Add NSS (and its dependency NSPR) to deps/third_party/nss.
This changelist contains the source files only. The
build and support files are in a separate changelist.

R=agl
BUG=28744
TEST=No build errors.

git-svn-id: http://src.chromium.org/svn/trunk/deps/third_party/nss@36871 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/README.chromium b/README.chromium
new file mode 100644
index 0000000..ce4e774
--- /dev/null
+++ b/README.chromium
@@ -0,0 +1,45 @@
+Network Security Services (NSS)
+
+URL: http://www.mozilla.org/projects/security/pki/nss/
+Version: NSS 3.12.6 pre-release with NSPR 4.8.4 pre-release
+License: MPL/LGPL/GPL tri-license
+License File: http://www.mozilla.org/MPL/
+
+Description:
+
+This copy of NSS has been customized for Chromium.  NSPR is also put here
+rather than in a separate directory to emphasize the fact that Chromium is
+using NSPR strictly as an NSS dependency.
+
+We took a subset of NSS, omitting the SSL and SMIME libraries and the
+built-in root CA certificates module.  This NSS subset satisfies the
+dependencies of the NSS SSL library in src/net/third_party/nss.  Do NOT use
+this copy of NSS on platforms that have NSS as system libraries, such as
+Linux.
+
+The source code was checked out from the mozilla.org CVS repository using
+the nspr-checkout.sh and nss-checkout.sh scripts in the scripts directory.
+The current source code was checked out with the date tag -D 2010-01-19.
+
+Local Modifications:
+
+We made the following local changes to NSPR.
+- patches/nspr-static.patch: to build NSPR as static libraries.  See NSPR
+  bug 533014 (https://bugzilla.mozilla.org/show_bug.cgi?id=533014).
+- patches/nspr-warnings.patch: to fix some (but not all) compiler warnings.
+  See NSPR bug 541222 (https://bugzilla.mozilla.org/show_bug.cgi?id=541222).
+- patches/prcpucfg.h: added to the mozilla/nsprpub/pr/include directory.
+
+We made the following local changes to NSS.
+- patches/nss-static.patch: to build NSS as static libraries and omit
+  libpkix (the new certification path validation library) and
+  softoken/legacydb (support for the old Berkeley DB databases).  See NSS
+  bug 534471 (https://bugzilla.mozilla.org/show_bug.cgi?id=534471).
+- patches/nss-secport.patch: to rewrite ancient code that uses NSPR as
+  shared libraries/DLLs.  See NSS bug 541228
+  (https://bugzilla.mozilla.org/show_bug.cgi?id=541228).
+- patches/nss-nssinit.patch: to remove two unnecessary header inclusions.
+  See NSS bug 541231 (https://bugzilla.mozilla.org/show_bug.cgi?id=541231).
+- patches/nss-dertime.patch: to fix some (but not all) compiler warnings.
+  See NSS bug 536023 comment 13
+  (https://bugzilla.mozilla.org/show_bug.cgi?id=536023#c13).
diff --git a/mozilla/nsprpub/lib/ds/plarena.c b/mozilla/nsprpub/lib/ds/plarena.c
new file mode 100644
index 0000000..2d27458
--- /dev/null
+++ b/mozilla/nsprpub/lib/ds/plarena.c
@@ -0,0 +1,433 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  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 *****
+ */
+
+/*
+ * Lifetime-based fast allocation, inspired by much prior art, including
+ * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
+ * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "plarena.h"
+#include "prmem.h"
+#include "prbit.h"
+#include "prlog.h"
+#include "prlock.h"
+#include "prinit.h"
+
+static PLArena *arena_freelist;
+
+#ifdef PL_ARENAMETER
+static PLArenaStats *arena_stats_list;
+
+#define COUNT(pool,what)  (pool)->stats.what++
+#else
+#define COUNT(pool,what)  /* nothing */
+#endif
+
+#define PL_ARENA_DEFAULT_ALIGN  sizeof(double)
+
+static PRLock    *arenaLock;
+static PRCallOnceType once;
+static const PRCallOnceType pristineCallOnce;
+
+/*
+** InitializeArenas() -- Initialize arena operations.
+**
+** InitializeArenas() is called exactly once and only once from 
+** LockArena(). This function creates the arena protection 
+** lock: arenaLock.
+**
+** Note: If the arenaLock cannot be created, InitializeArenas()
+** fails quietly, returning only PR_FAILURE. This percolates up
+** to the application using the Arena API. He gets no arena
+** from PL_ArenaAllocate(). It's up to him to fail gracefully
+** or recover.
+**
+*/
+static PRStatus InitializeArenas( void )
+{
+    PR_ASSERT( arenaLock == NULL );
+    arenaLock = PR_NewLock();
+    if ( arenaLock == NULL )
+        return PR_FAILURE;
+    else
+        return PR_SUCCESS;
+} /* end ArenaInitialize() */
+
+static PRStatus LockArena( void )
+{
+    PRStatus rc = PR_CallOnce( &once, InitializeArenas );
+
+    if ( PR_FAILURE != rc )
+        PR_Lock( arenaLock );
+    return(rc);
+} /* end LockArena() */
+
+static void UnlockArena( void )
+{
+    PR_Unlock( arenaLock );
+    return;
+} /* end UnlockArena() */
+
+PR_IMPLEMENT(void) PL_InitArenaPool(
+    PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align)
+{
+    /*
+     * Look-up table of PR_BITMASK(PR_CeilingLog2(align)) values for
+     * align = 1 to 32.
+     */
+    static const PRUint8 pmasks[33] = {
+         0,                                               /*  not used */
+         0, 1, 3, 3, 7, 7, 7, 7,15,15,15,15,15,15,15,15,  /*  1 ... 16 */
+        31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31}; /* 17 ... 32 */
+
+    if (align == 0)
+        align = PL_ARENA_DEFAULT_ALIGN;
+
+    if (align < sizeof(pmasks)/sizeof(pmasks[0]))
+        pool->mask = pmasks[align];
+    else
+        pool->mask = PR_BITMASK(PR_CeilingLog2(align));
+
+    pool->first.next = NULL;
+    pool->first.base = pool->first.avail = pool->first.limit =
+        (PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1);
+    pool->current = &pool->first;
+    pool->arenasize = size;                                  
+#ifdef PL_ARENAMETER
+    memset(&pool->stats, 0, sizeof pool->stats);
+    pool->stats.name = strdup(name);
+    pool->stats.next = arena_stats_list;
+    arena_stats_list = &pool->stats;
+#endif
+}
+
+
+/*
+** PL_ArenaAllocate() -- allocate space from an arena pool
+** 
+** Description: PL_ArenaAllocate() allocates space from an arena
+** pool. 
+**
+** First, try to satisfy the request from arenas starting at
+** pool->current.
+**
+** If there is not enough space in the arena pool->current, try
+** to claim an arena, on a first fit basis, from the global
+** freelist (arena_freelist).
+** 
+** If no arena in arena_freelist is suitable, then try to
+** allocate a new arena from the heap.
+**
+** Returns: pointer to allocated space or NULL
+** 
+** Notes: The original implementation had some difficult to
+** solve bugs; the code was difficult to read. Sometimes it's
+** just easier to rewrite it. I did that. larryh.
+**
+** See also: bugzilla: 45343.
+**
+*/
+
+PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
+{
+    PLArena *a;   
+    char *rp;     /* returned pointer */
+
+    PR_ASSERT((nb & pool->mask) == 0);
+    
+    nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */
+
+    /* attempt to allocate from arenas at pool->current */
+    {
+        a = pool->current;
+        do {
+            if ( a->avail +nb <= a->limit )  {
+                pool->current = a;
+                rp = (char *)a->avail;
+                a->avail += nb;
+                return rp;
+            }
+        } while( NULL != (a = a->next) );
+    }
+
+    /* attempt to allocate from arena_freelist */
+    {
+        PLArena *p; /* previous pointer, for unlinking from freelist */
+
+        /* lock the arena_freelist. Make access to the freelist MT-Safe */
+        if ( PR_FAILURE == LockArena())
+            return(0);
+
+        for ( a = arena_freelist, p = NULL; a != NULL ; p = a, a = a->next ) {
+            if ( a->base +nb <= a->limit )  {
+                if ( p == NULL )
+                    arena_freelist = a->next;
+                else
+                    p->next = a->next;
+                UnlockArena();
+                a->avail = a->base;
+                rp = (char *)a->avail;
+                a->avail += nb;
+                /* the newly allocated arena is linked after pool->current 
+                *  and becomes pool->current */
+                a->next = pool->current->next;
+                pool->current->next = a;
+                pool->current = a;
+                if ( NULL == pool->first.next )
+                    pool->first.next = a;
+                return(rp);
+            }
+        }
+        UnlockArena();
+    }
+
+    /* attempt to allocate from the heap */ 
+    {  
+        PRUint32 sz = PR_MAX(pool->arenasize, nb);
+        sz += sizeof *a + pool->mask;  /* header and alignment slop */
+        a = (PLArena*)PR_MALLOC(sz);
+        if ( NULL != a )  {
+            a->limit = (PRUword)a + sz;
+            a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
+            rp = (char *)a->avail;
+            a->avail += nb;
+            /* the newly allocated arena is linked after pool->current 
+            *  and becomes pool->current */
+            a->next = pool->current->next;
+            pool->current->next = a;
+            pool->current = a;
+            if ( NULL == pool->first.next )
+                pool->first.next = a;
+            PL_COUNT_ARENA(pool,++);
+            COUNT(pool, nmallocs);
+            return(rp);
+        }
+    }
+
+    /* we got to here, and there's no memory to allocate */
+    return(NULL);
+} /* --- end PL_ArenaAllocate() --- */
+
+PR_IMPLEMENT(void *) PL_ArenaGrow(
+    PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
+{
+    void *newp;
+
+    PL_ARENA_ALLOCATE(newp, pool, size + incr);
+    if (newp)
+        memcpy(newp, p, size);
+    return newp;
+}
+
+/*
+ * Free tail arenas linked after head, which may not be the true list head.
+ * Reset pool->current to point to head in case it pointed at a tail arena.
+ */
+static void FreeArenaList(PLArenaPool *pool, PLArena *head, PRBool reallyFree)
+{
+    PLArena **ap, *a;
+
+    ap = &head->next;
+    a = *ap;
+    if (!a)
+        return;
+
+#ifdef DEBUG
+    do {
+        PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+        a->avail = a->base;
+        PL_CLEAR_UNUSED(a);
+    } while ((a = a->next) != 0);
+    a = *ap;
+#endif
+
+    if (reallyFree) {
+        do {
+            *ap = a->next;
+            PL_CLEAR_ARENA(a);
+            PL_COUNT_ARENA(pool,--);
+            PR_DELETE(a);
+        } while ((a = *ap) != 0);
+    } else {
+        /* Insert the whole arena chain at the front of the freelist. */
+        do {
+            ap = &(*ap)->next;
+        } while (*ap);
+        LockArena();
+        *ap = arena_freelist;
+        arena_freelist = a;
+        head->next = 0;
+        UnlockArena();
+    }
+
+    pool->current = head;
+}
+
+PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
+{
+    PLArena *a;
+
+    for (a = pool->first.next; a; a = a->next) {
+        if (PR_UPTRDIFF(mark, a->base) < PR_UPTRDIFF(a->avail, a->base)) {
+            a->avail = (PRUword)PL_ARENA_ALIGN(pool, mark);
+            FreeArenaList(pool, a, PR_FALSE);
+            return;
+        }
+    }
+}
+
+PR_IMPLEMENT(void) PL_FreeArenaPool(PLArenaPool *pool)
+{
+    FreeArenaList(pool, &pool->first, PR_FALSE);
+    COUNT(pool, ndeallocs);
+}
+
+PR_IMPLEMENT(void) PL_FinishArenaPool(PLArenaPool *pool)
+{
+    FreeArenaList(pool, &pool->first, PR_TRUE);
+#ifdef PL_ARENAMETER
+    {
+        PLArenaStats *stats, **statsp;
+
+        if (pool->stats.name)
+            PR_DELETE(pool->stats.name);
+        for (statsp = &arena_stats_list; (stats = *statsp) != 0;
+             statsp = &stats->next) {
+            if (stats == &pool->stats) {
+                *statsp = stats->next;
+                return;
+            }
+        }
+    }
+#endif
+}
+
+PR_IMPLEMENT(void) PL_CompactArenaPool(PLArenaPool *ap)
+{
+}
+
+PR_IMPLEMENT(void) PL_ArenaFinish(void)
+{
+    PLArena *a, *next;
+
+    for (a = arena_freelist; a; a = next) {
+        next = a->next;
+        PR_DELETE(a);
+    }
+    arena_freelist = NULL;
+
+    if (arenaLock) {
+        PR_DestroyLock(arenaLock);
+        arenaLock = NULL;
+    }
+    once = pristineCallOnce;
+}
+
+#ifdef PL_ARENAMETER
+PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb)
+{
+    pool->stats.nallocs++;
+    pool->stats.nbytes += nb;
+    if (nb > pool->stats.maxalloc)
+        pool->stats.maxalloc = nb;
+    pool->stats.variance += nb * nb;
+}
+
+PR_IMPLEMENT(void) PL_ArenaCountInplaceGrowth(
+    PLArenaPool *pool, PRUint32 size, PRUint32 incr)
+{
+    pool->stats.ninplace++;
+}
+
+PR_IMPLEMENT(void) PL_ArenaCountGrowth(
+    PLArenaPool *pool, PRUint32 size, PRUint32 incr)
+{
+    pool->stats.ngrows++;
+    pool->stats.nbytes += incr;
+    pool->stats.variance -= size * size;
+    size += incr;
+    if (size > pool->stats.maxalloc)
+        pool->stats.maxalloc = size;
+    pool->stats.variance += size * size;
+}
+
+PR_IMPLEMENT(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark)
+{
+    pool->stats.nreleases++;
+}
+
+PR_IMPLEMENT(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark)
+{
+    pool->stats.nfastrels++;
+}
+
+#include <math.h>
+#include <stdio.h>
+
+PR_IMPLEMENT(void) PL_DumpArenaStats(FILE *fp)
+{
+    PLArenaStats *stats;
+    double mean, variance;
+
+    for (stats = arena_stats_list; stats; stats = stats->next) {
+        if (stats->nallocs != 0) {
+            mean = (double)stats->nbytes / stats->nallocs;
+            variance = fabs(stats->variance / stats->nallocs - mean * mean);
+        } else {
+            mean = variance = 0;
+        }
+
+        fprintf(fp, "\n%s allocation statistics:\n", stats->name);
+        fprintf(fp, "              number of arenas: %u\n", stats->narenas);
+        fprintf(fp, "         number of allocations: %u\n", stats->nallocs);
+        fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims);
+        fprintf(fp, "        number of malloc calls: %u\n", stats->nmallocs);
+        fprintf(fp, "       number of deallocations: %u\n", stats->ndeallocs);
+        fprintf(fp, "  number of allocation growths: %u\n", stats->ngrows);
+        fprintf(fp, "    number of in-place growths: %u\n", stats->ninplace);
+        fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
+        fprintf(fp, "       number of fast releases: %u\n", stats->nfastrels);
+        fprintf(fp, "         total bytes allocated: %u\n", stats->nbytes);
+        fprintf(fp, "          mean allocation size: %g\n", mean);
+        fprintf(fp, "            standard deviation: %g\n", sqrt(variance));
+        fprintf(fp, "       maximum allocation size: %u\n", stats->maxalloc);
+    }
+}
+#endif /* PL_ARENAMETER */
diff --git a/mozilla/nsprpub/lib/ds/plarena.h b/mozilla/nsprpub/lib/ds/plarena.h
new file mode 100644
index 0000000..38f3e39
--- /dev/null
+++ b/mozilla/nsprpub/lib/ds/plarena.h
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  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 *****
+ */
+
+#ifndef plarena_h___
+#define plarena_h___
+/*
+ * Lifetime-based fast allocation, inspired by much prior art, including
+ * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
+ * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
+ *
+ * Also supports LIFO allocation (PL_ARENA_MARK/PL_ARENA_RELEASE).
+ */
+#include "prtypes.h"
+#include "plarenas.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PLArena          PLArena;
+
+struct PLArena {
+    PLArena     *next;          /* next arena for this lifetime */
+    PRUword     base;           /* aligned base address, follows this header */
+    PRUword     limit;          /* one beyond last byte in arena */
+    PRUword     avail;          /* points to next available byte */
+};
+
+#ifdef PL_ARENAMETER
+typedef struct PLArenaStats PLArenaStats;
+
+struct PLArenaStats {
+    PLArenaStats  *next;        /* next in arenaStats list */
+    char          *name;        /* name for debugging */
+    PRUint32      narenas;      /* number of arenas in pool */
+    PRUint32      nallocs;      /* number of PL_ARENA_ALLOCATE() calls */
+    PRUint32      nreclaims;    /* number of reclaims from freeArenas */
+    PRUint32      nmallocs;     /* number of malloc() calls */
+    PRUint32      ndeallocs;    /* number of lifetime deallocations */
+    PRUint32      ngrows;       /* number of PL_ARENA_GROW() calls */
+    PRUint32      ninplace;     /* number of in-place growths */
+    PRUint32      nreleases;    /* number of PL_ARENA_RELEASE() calls */
+    PRUint32      nfastrels;    /* number of "fast path" releases */
+    PRUint32      nbytes;       /* total bytes allocated */
+    PRUint32      maxalloc;     /* maximum allocation size in bytes */
+    PRFloat64     variance;     /* size variance accumulator */
+};
+#endif
+
+struct PLArenaPool {
+    PLArena     first;          /* first arena in pool list */
+    PLArena     *current;       /* arena from which to allocate space */
+    PRUint32    arenasize;      /* net exact size of a new arena */
+    PRUword     mask;           /* alignment mask (power-of-2 - 1) */
+#ifdef PL_ARENAMETER
+    PLArenaStats stats;
+#endif
+};
+
+/*
+ * If the including .c file uses only one power-of-2 alignment, it may define
+ * PL_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions
+ * per ALLOCATE and GROW.
+ */
+#ifdef PL_ARENA_CONST_ALIGN_MASK
+#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + PL_ARENA_CONST_ALIGN_MASK) \
+                                & ~PL_ARENA_CONST_ALIGN_MASK)
+
+#define PL_INIT_ARENA_POOL(pool, name, size) \
+        PL_InitArenaPool(pool, name, size, PL_ARENA_CONST_ALIGN_MASK + 1)
+#else
+#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + (pool)->mask) & ~(pool)->mask)
+#endif
+
+#define PL_ARENA_ALLOCATE(p, pool, nb) \
+    PR_BEGIN_MACRO \
+        PLArena *_a = (pool)->current; \
+        PRUint32 _nb = PL_ARENA_ALIGN(pool, nb); \
+        PRUword _p = _a->avail; \
+        PRUword _q = _p + _nb; \
+        if (_q > _a->limit) \
+            _p = (PRUword)PL_ArenaAllocate(pool, _nb); \
+        else \
+            _a->avail = _q; \
+        p = (void *)_p; \
+        PL_ArenaCountAllocation(pool, nb); \
+    PR_END_MACRO
+
+#define PL_ARENA_GROW(p, pool, size, incr) \
+    PR_BEGIN_MACRO \
+        PLArena *_a = (pool)->current; \
+        PRUint32 _incr = PL_ARENA_ALIGN(pool, incr); \
+        PRUword _p = _a->avail; \
+        PRUword _q = _p + _incr; \
+        if (_p == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \
+            _q <= _a->limit) { \
+            _a->avail = _q; \
+            PL_ArenaCountInplaceGrowth(pool, size, incr); \
+        } else { \
+            p = PL_ArenaGrow(pool, p, size, incr); \
+        } \
+        PL_ArenaCountGrowth(pool, size, incr); \
+    PR_END_MACRO
+
+#define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail)
+#define PR_UPTRDIFF(p,q) ((PRUword)(p) - (PRUword)(q))
+
+#ifdef DEBUG
+#define PL_FREE_PATTERN 0xDA
+#define PL_CLEAR_UNUSED(a) (PR_ASSERT((a)->avail <= (a)->limit), \
+                           memset((void*)(a)->avail, PL_FREE_PATTERN, \
+                           (a)->limit - (a)->avail))
+#define PL_CLEAR_ARENA(a)  memset((void*)(a), PL_FREE_PATTERN, \
+                           (a)->limit - (PRUword)(a))
+#else
+#define PL_CLEAR_UNUSED(a)
+#define PL_CLEAR_ARENA(a)
+#endif
+
+#define PL_ARENA_RELEASE(pool, mark) \
+    PR_BEGIN_MACRO \
+        char *_m = (char *)(mark); \
+        PLArena *_a = (pool)->current; \
+        if (PR_UPTRDIFF(_m, _a->base) <= PR_UPTRDIFF(_a->avail, _a->base)) { \
+            _a->avail = (PRUword)PL_ARENA_ALIGN(pool, _m); \
+            PL_CLEAR_UNUSED(_a); \
+            PL_ArenaCountRetract(pool, _m); \
+        } else { \
+            PL_ArenaRelease(pool, _m); \
+        } \
+        PL_ArenaCountRelease(pool, _m); \
+    PR_END_MACRO
+
+#ifdef PL_ARENAMETER
+#define PL_COUNT_ARENA(pool,op) ((pool)->stats.narenas op)
+#else
+#define PL_COUNT_ARENA(pool,op)
+#endif
+
+#define PL_ARENA_DESTROY(pool, a, pnext) \
+    PR_BEGIN_MACRO \
+        PL_COUNT_ARENA(pool,--); \
+        if ((pool)->current == (a)) (pool)->current = &(pool)->first; \
+        *(pnext) = (a)->next; \
+        PL_CLEAR_ARENA(a); \
+        free(a); \
+        (a) = 0; \
+    PR_END_MACRO
+
+#ifdef PL_ARENAMETER
+
+#include <stdio.h>
+
+PR_EXTERN(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb);
+
+PR_EXTERN(void) PL_ArenaCountInplaceGrowth(
+    PLArenaPool *pool, PRUint32 size, PRUint32 incr);
+
+PR_EXTERN(void) PL_ArenaCountGrowth(
+    PLArenaPool *pool, PRUint32 size, PRUint32 incr);
+
+PR_EXTERN(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark);
+
+PR_EXTERN(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark);
+
+PR_EXTERN(void) PL_DumpArenaStats(FILE *fp);
+
+#else  /* !PL_ARENAMETER */
+
+#define PL_ArenaCountAllocation(ap, nb)                 /* nothing */
+#define PL_ArenaCountInplaceGrowth(ap, size, incr)      /* nothing */
+#define PL_ArenaCountGrowth(ap, size, incr)             /* nothing */
+#define PL_ArenaCountRelease(ap, mark)                  /* nothing */
+#define PL_ArenaCountRetract(ap, mark)                  /* nothing */
+
+#endif /* !PL_ARENAMETER */
+
+PR_END_EXTERN_C
+
+#endif /* plarena_h___ */
diff --git a/mozilla/nsprpub/lib/ds/plarenas.h b/mozilla/nsprpub/lib/ds/plarenas.h
new file mode 100644
index 0000000..e3eca35
--- /dev/null
+++ b/mozilla/nsprpub/lib/ds/plarenas.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#if defined(PLARENAS_H)
+#else  /* defined(PLARENAS_H) */
+#define PLARENAS_H
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PLArenaPool      PLArenaPool;
+
+/*
+** Allocate an arena pool as specified by the parameters.
+**
+** This is equivelant to allocating the space yourself and then
+** calling PL_InitArenaPool().
+**
+** This function may fail (and return a NULL) for a variety of
+** reasons. The reason for a particular failure can be discovered
+** by calling PR_GetError().
+*/
+#if 0  /* Not implemented */
+PR_EXTERN(PLArenaPool*) PL_AllocArenaPool(
+    const char *name, PRUint32 size, PRUint32 align);
+#endif
+
+/*
+** Destroy an arena pool previously allocated by PL_AllocArenaPool().
+**
+** This function may fail if the arena is not empty and the caller
+** wishes to check for empty upon descruction.
+*/
+#if 0  /* Not implemented */
+PR_EXTERN(PRStatus) PL_DestroyArenaPool(PLArenaPool *pool, PRBool checkEmpty);
+#endif
+
+
+/*
+** Initialize an arena pool with the given name for debugging and metering,
+** with a minimum size per arena of size bytes.
+**/
+PR_EXTERN(void) PL_InitArenaPool(
+    PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align);
+
+/*
+** Finish using arenas, freeing all memory associated with them.
+**/
+PR_EXTERN(void) PL_ArenaFinish(void);
+
+/*
+** Free the arenas in pool.  The user may continue to allocate from pool
+** after calling this function.  There is no need to call PL_InitArenaPool()
+** again unless PL_FinishArenaPool(pool) has been called.
+**/
+PR_EXTERN(void) PL_FreeArenaPool(PLArenaPool *pool);
+
+/*
+** Free the arenas in pool and finish using it altogether.
+**/
+PR_EXTERN(void) PL_FinishArenaPool(PLArenaPool *pool);
+
+/*
+** Compact all of the arenas in a pool so that no space is wasted.
+**/
+PR_EXTERN(void) PL_CompactArenaPool(PLArenaPool *pool);
+
+/*
+** Friend functions used by the PL_ARENA_*() macros.
+**/
+PR_EXTERN(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb);
+
+PR_EXTERN(void *) PL_ArenaGrow(
+    PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr);
+
+PR_EXTERN(void) PL_ArenaRelease(PLArenaPool *pool, char *mark);
+
+PR_END_EXTERN_C
+
+#endif /* defined(PLARENAS_H) */
+
+/* plarenas */
diff --git a/mozilla/nsprpub/lib/ds/plhash.c b/mozilla/nsprpub/lib/ds/plhash.c
new file mode 100644
index 0000000..4f69d04
--- /dev/null
+++ b/mozilla/nsprpub/lib/ds/plhash.c
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * PL hash table package.
+ */
+#include "plhash.h"
+#include "prbit.h"
+#include "prlog.h"
+#include "prmem.h"
+#include "prtypes.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Compute the number of buckets in ht */
+#define NBUCKETS(ht)    (1 << (PL_HASH_BITS - (ht)->shift))
+
+/* The smallest table has 16 buckets */
+#define MINBUCKETSLOG2  4
+#define MINBUCKETS      (1 << MINBUCKETSLOG2)
+
+/* Compute the maximum entries given n buckets that we will tolerate, ~90% */
+#define OVERLOADED(n)   ((n) - ((n) >> 3))
+
+/* Compute the number of entries below which we shrink the table by half */
+#define UNDERLOADED(n)  (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
+
+/*
+** Stubs for default hash allocator ops.
+*/
+static void * PR_CALLBACK
+DefaultAllocTable(void *pool, PRSize size)
+{
+    return PR_MALLOC(size);
+}
+
+static void PR_CALLBACK
+DefaultFreeTable(void *pool, void *item)
+{
+    PR_Free(item);
+}
+
+static PLHashEntry * PR_CALLBACK
+DefaultAllocEntry(void *pool, const void *key)
+{
+    return PR_NEW(PLHashEntry);
+}
+
+static void PR_CALLBACK
+DefaultFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+    if (flag == HT_FREE_ENTRY)
+        PR_Free(he);
+}
+
+static PLHashAllocOps defaultHashAllocOps = {
+    DefaultAllocTable, DefaultFreeTable,
+    DefaultAllocEntry, DefaultFreeEntry
+};
+
+PR_IMPLEMENT(PLHashTable *)
+PL_NewHashTable(PRUint32 n, PLHashFunction keyHash,
+                PLHashComparator keyCompare, PLHashComparator valueCompare,
+                const PLHashAllocOps *allocOps, void *allocPriv)
+{
+    PLHashTable *ht;
+    PRSize nb;
+
+    if (n <= MINBUCKETS) {
+        n = MINBUCKETSLOG2;
+    } else {
+        n = PR_CeilingLog2(n);
+        if ((PRInt32)n < 0)
+            return 0;
+    }
+
+    if (!allocOps) allocOps = &defaultHashAllocOps;
+
+    ht = (PLHashTable*)((*allocOps->allocTable)(allocPriv, sizeof *ht));
+    if (!ht)
+	return 0;
+    memset(ht, 0, sizeof *ht);
+    ht->shift = PL_HASH_BITS - n;
+    n = 1 << n;
+    nb = n * sizeof(PLHashEntry *);
+    ht->buckets = (PLHashEntry**)((*allocOps->allocTable)(allocPriv, nb));
+    if (!ht->buckets) {
+        (*allocOps->freeTable)(allocPriv, ht);
+        return 0;
+    }
+    memset(ht->buckets, 0, nb);
+
+    ht->keyHash = keyHash;
+    ht->keyCompare = keyCompare;
+    ht->valueCompare = valueCompare;
+    ht->allocOps = allocOps;
+    ht->allocPriv = allocPriv;
+    return ht;
+}
+
+PR_IMPLEMENT(void)
+PL_HashTableDestroy(PLHashTable *ht)
+{
+    PRUint32 i, n;
+    PLHashEntry *he, *next;
+    const PLHashAllocOps *allocOps = ht->allocOps;
+    void *allocPriv = ht->allocPriv;
+
+    n = NBUCKETS(ht);
+    for (i = 0; i < n; i++) {
+        for (he = ht->buckets[i]; he; he = next) {
+            next = he->next;
+            (*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY);
+        }
+    }
+#ifdef DEBUG
+    memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
+#endif
+    (*allocOps->freeTable)(allocPriv, ht->buckets);
+#ifdef DEBUG
+    memset(ht, 0xDB, sizeof *ht);
+#endif
+    (*allocOps->freeTable)(allocPriv, ht);
+}
+
+/*
+** Multiplicative hash, from Knuth 6.4.
+*/
+#define GOLDEN_RATIO    0x9E3779B9U  /* 2/(1+sqrt(5))*(2^32) */
+
+PR_IMPLEMENT(PLHashEntry **)
+PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key)
+{
+    PLHashEntry *he, **hep, **hep0;
+    PLHashNumber h;
+
+#ifdef HASHMETER
+    ht->nlookups++;
+#endif
+    h = keyHash * GOLDEN_RATIO;
+    h >>= ht->shift;
+    hep = hep0 = &ht->buckets[h];
+    while ((he = *hep) != 0) {
+        if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) {
+            /* Move to front of chain if not already there */
+            if (hep != hep0) {
+                *hep = he->next;
+                he->next = *hep0;
+                *hep0 = he;
+            }
+            return hep0;
+        }
+        hep = &he->next;
+#ifdef HASHMETER
+        ht->nsteps++;
+#endif
+    }
+    return hep;
+}
+
+/*
+** Same as PL_HashTableRawLookup but doesn't reorder the hash entries.
+*/
+PR_IMPLEMENT(PLHashEntry **)
+PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash,
+                           const void *key)
+{
+    PLHashEntry *he, **hep;
+    PLHashNumber h;
+
+#ifdef HASHMETER
+    ht->nlookups++;
+#endif
+    h = keyHash * GOLDEN_RATIO;
+    h >>= ht->shift;
+    hep = &ht->buckets[h];
+    while ((he = *hep) != 0) {
+        if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) {
+            break;
+        }
+        hep = &he->next;
+#ifdef HASHMETER
+        ht->nsteps++;
+#endif
+    }
+    return hep;
+}
+
+PR_IMPLEMENT(PLHashEntry *)
+PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep,
+                   PLHashNumber keyHash, const void *key, void *value)
+{
+    PRUint32 i, n;
+    PLHashEntry *he, *next, **oldbuckets;
+    PRSize nb;
+
+    /* Grow the table if it is overloaded */
+    n = NBUCKETS(ht);
+    if (ht->nentries >= OVERLOADED(n)) {
+        oldbuckets = ht->buckets;
+        nb = 2 * n * sizeof(PLHashEntry *);
+        ht->buckets = (PLHashEntry**)
+            ((*ht->allocOps->allocTable)(ht->allocPriv, nb));
+        if (!ht->buckets) {
+            ht->buckets = oldbuckets;
+            return 0;
+        }
+        memset(ht->buckets, 0, nb);
+#ifdef HASHMETER
+        ht->ngrows++;
+#endif
+        ht->shift--;
+
+        for (i = 0; i < n; i++) {
+            for (he = oldbuckets[i]; he; he = next) {
+                next = he->next;
+                hep = PL_HashTableRawLookup(ht, he->keyHash, he->key);
+                PR_ASSERT(*hep == 0);
+                he->next = 0;
+                *hep = he;
+            }
+        }
+#ifdef DEBUG
+        memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
+#endif
+        (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
+        hep = PL_HashTableRawLookup(ht, keyHash, key);
+    }
+
+    /* Make a new key value entry */
+    he = (*ht->allocOps->allocEntry)(ht->allocPriv, key);
+    if (!he)
+	return 0;
+    he->keyHash = keyHash;
+    he->key = key;
+    he->value = value;
+    he->next = *hep;
+    *hep = he;
+    ht->nentries++;
+    return he;
+}
+
+PR_IMPLEMENT(PLHashEntry *)
+PL_HashTableAdd(PLHashTable *ht, const void *key, void *value)
+{
+    PLHashNumber keyHash;
+    PLHashEntry *he, **hep;
+
+    keyHash = (*ht->keyHash)(key);
+    hep = PL_HashTableRawLookup(ht, keyHash, key);
+    if ((he = *hep) != 0) {
+        /* Hit; see if values match */
+        if ((*ht->valueCompare)(he->value, value)) {
+            /* key,value pair is already present in table */
+            return he;
+        }
+        if (he->value)
+            (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE);
+        he->value = value;
+        return he;
+    }
+    return PL_HashTableRawAdd(ht, hep, keyHash, key, value);
+}
+
+PR_IMPLEMENT(void)
+PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he)
+{
+    PRUint32 i, n;
+    PLHashEntry *next, **oldbuckets;
+    PRSize nb;
+
+    *hep = he->next;
+    (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY);
+
+    /* Shrink table if it's underloaded */
+    n = NBUCKETS(ht);
+    if (--ht->nentries < UNDERLOADED(n)) {
+        oldbuckets = ht->buckets;
+        nb = n * sizeof(PLHashEntry*) / 2;
+        ht->buckets = (PLHashEntry**)(
+            (*ht->allocOps->allocTable)(ht->allocPriv, nb));
+        if (!ht->buckets) {
+            ht->buckets = oldbuckets;
+            return;
+        }
+        memset(ht->buckets, 0, nb);
+#ifdef HASHMETER
+        ht->nshrinks++;
+#endif
+        ht->shift++;
+
+        for (i = 0; i < n; i++) {
+            for (he = oldbuckets[i]; he; he = next) {
+                next = he->next;
+                hep = PL_HashTableRawLookup(ht, he->keyHash, he->key);
+                PR_ASSERT(*hep == 0);
+                he->next = 0;
+                *hep = he;
+            }
+        }
+#ifdef DEBUG
+        memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
+#endif
+        (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
+    }
+}
+
+PR_IMPLEMENT(PRBool)
+PL_HashTableRemove(PLHashTable *ht, const void *key)
+{
+    PLHashNumber keyHash;
+    PLHashEntry *he, **hep;
+
+    keyHash = (*ht->keyHash)(key);
+    hep = PL_HashTableRawLookup(ht, keyHash, key);
+    if ((he = *hep) == 0)
+        return PR_FALSE;
+
+    /* Hit; remove element */
+    PL_HashTableRawRemove(ht, hep, he);
+    return PR_TRUE;
+}
+
+PR_IMPLEMENT(void *)
+PL_HashTableLookup(PLHashTable *ht, const void *key)
+{
+    PLHashNumber keyHash;
+    PLHashEntry *he, **hep;
+
+    keyHash = (*ht->keyHash)(key);
+    hep = PL_HashTableRawLookup(ht, keyHash, key);
+    if ((he = *hep) != 0) {
+        return he->value;
+    }
+    return 0;
+}
+
+/*
+** Same as PL_HashTableLookup but doesn't reorder the hash entries.
+*/
+PR_IMPLEMENT(void *)
+PL_HashTableLookupConst(PLHashTable *ht, const void *key)
+{
+    PLHashNumber keyHash;
+    PLHashEntry *he, **hep;
+
+    keyHash = (*ht->keyHash)(key);
+    hep = PL_HashTableRawLookupConst(ht, keyHash, key);
+    if ((he = *hep) != 0) {
+        return he->value;
+    }
+    return 0;
+}
+
+/*
+** Iterate over the entries in the hash table calling func for each
+** entry found. Stop if "f" says to (return value & PR_ENUMERATE_STOP).
+** Return a count of the number of elements scanned.
+*/
+PR_IMPLEMENT(int)
+PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg)
+{
+    PLHashEntry *he, **hep;
+    PRUint32 i, nbuckets;
+    int rv, n = 0;
+    PLHashEntry *todo = 0;
+
+    nbuckets = NBUCKETS(ht);
+    for (i = 0; i < nbuckets; i++) {
+        hep = &ht->buckets[i];
+        while ((he = *hep) != 0) {
+            rv = (*f)(he, n, arg);
+            n++;
+            if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) {
+                *hep = he->next;
+                if (rv & HT_ENUMERATE_REMOVE) {
+                    he->next = todo;
+                    todo = he;
+                }
+            } else {
+                hep = &he->next;
+            }
+            if (rv & HT_ENUMERATE_STOP) {
+                goto out;
+            }
+        }
+    }
+
+out:
+    hep = &todo;
+    while ((he = *hep) != 0) {
+        PL_HashTableRawRemove(ht, hep, he);
+    }
+    return n;
+}
+
+#ifdef HASHMETER
+#include <math.h>
+#include <stdio.h>
+
+PR_IMPLEMENT(void)
+PL_HashTableDumpMeter(PLHashTable *ht, PLHashEnumerator dump, FILE *fp)
+{
+    double mean, variance;
+    PRUint32 nchains, nbuckets;
+    PRUint32 i, n, maxChain, maxChainLen;
+    PLHashEntry *he;
+
+    variance = 0;
+    nchains = 0;
+    maxChainLen = 0;
+    nbuckets = NBUCKETS(ht);
+    for (i = 0; i < nbuckets; i++) {
+        he = ht->buckets[i];
+        if (!he)
+            continue;
+        nchains++;
+        for (n = 0; he; he = he->next)
+            n++;
+        variance += n * n;
+        if (n > maxChainLen) {
+            maxChainLen = n;
+            maxChain = i;
+        }
+    }
+    mean = (double)ht->nentries / nchains;
+    variance = fabs(variance / nchains - mean * mean);
+
+    fprintf(fp, "\nHash table statistics:\n");
+    fprintf(fp, "     number of lookups: %u\n", ht->nlookups);
+    fprintf(fp, "     number of entries: %u\n", ht->nentries);
+    fprintf(fp, "       number of grows: %u\n", ht->ngrows);
+    fprintf(fp, "     number of shrinks: %u\n", ht->nshrinks);
+    fprintf(fp, "   mean steps per hash: %g\n", (double)ht->nsteps
+                                                / ht->nlookups);
+    fprintf(fp, "mean hash chain length: %g\n", mean);
+    fprintf(fp, "    standard deviation: %g\n", sqrt(variance));
+    fprintf(fp, " max hash chain length: %u\n", maxChainLen);
+    fprintf(fp, "        max hash chain: [%u]\n", maxChain);
+
+    for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
+        if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT)
+            break;
+}
+#endif /* HASHMETER */
+
+PR_IMPLEMENT(int)
+PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp)
+{
+    int count;
+
+    count = PL_HashTableEnumerateEntries(ht, dump, fp);
+#ifdef HASHMETER
+    PL_HashTableDumpMeter(ht, dump, fp);
+#endif
+    return count;
+}
+
+PR_IMPLEMENT(PLHashNumber)
+PL_HashString(const void *key)
+{
+    PLHashNumber h;
+    const PRUint8 *s;
+
+    h = 0;
+    for (s = (const PRUint8*)key; *s; s++)
+        h = PR_ROTATE_LEFT32(h, 4) ^ *s;
+    return h;
+}
+
+PR_IMPLEMENT(int)
+PL_CompareStrings(const void *v1, const void *v2)
+{
+    return strcmp((const char*)v1, (const char*)v2) == 0;
+}
+
+PR_IMPLEMENT(int)
+PL_CompareValues(const void *v1, const void *v2)
+{
+    return v1 == v2;
+}
diff --git a/mozilla/nsprpub/lib/ds/plhash.h b/mozilla/nsprpub/lib/ds/plhash.h
new file mode 100644
index 0000000..d752d16
--- /dev/null
+++ b/mozilla/nsprpub/lib/ds/plhash.h
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef plhash_h___
+#define plhash_h___
+/*
+ * API to portable hash table code.
+ */
+#include <stdio.h>
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PLHashEntry  PLHashEntry;
+typedef struct PLHashTable  PLHashTable;
+typedef PRUint32 PLHashNumber;
+#define PL_HASH_BITS 32  /* Number of bits in PLHashNumber */
+typedef PLHashNumber (PR_CALLBACK *PLHashFunction)(const void *key);
+typedef PRIntn (PR_CALLBACK *PLHashComparator)(const void *v1, const void *v2);
+
+typedef PRIntn (PR_CALLBACK *PLHashEnumerator)(PLHashEntry *he, PRIntn i, void *arg);
+
+/* Flag bits in PLHashEnumerator's return value */
+#define HT_ENUMERATE_NEXT       0       /* continue enumerating entries */
+#define HT_ENUMERATE_STOP       1       /* stop enumerating entries */
+#define HT_ENUMERATE_REMOVE     2       /* remove and free the current entry */
+#define HT_ENUMERATE_UNHASH     4       /* just unhash the current entry */
+
+typedef struct PLHashAllocOps {
+    void *              (PR_CALLBACK *allocTable)(void *pool, PRSize size);
+    void                (PR_CALLBACK *freeTable)(void *pool, void *item);
+    PLHashEntry *       (PR_CALLBACK *allocEntry)(void *pool, const void *key);
+    void                (PR_CALLBACK *freeEntry)(void *pool, PLHashEntry *he, PRUintn flag);
+} PLHashAllocOps;
+
+#define HT_FREE_VALUE   0               /* just free the entry's value */
+#define HT_FREE_ENTRY   1               /* free value and entire entry */
+
+struct PLHashEntry {
+    PLHashEntry         *next;          /* hash chain linkage */
+    PLHashNumber        keyHash;        /* key hash function result */
+    const void          *key;           /* ptr to opaque key */
+    void                *value;         /* ptr to opaque value */
+};
+
+struct PLHashTable {
+    PLHashEntry         **buckets;      /* vector of hash buckets */
+    PRUint32              nentries;       /* number of entries in table */
+    PRUint32              shift;          /* multiplicative hash shift */
+    PLHashFunction      keyHash;        /* key hash function */
+    PLHashComparator    keyCompare;     /* key comparison function */
+    PLHashComparator    valueCompare;   /* value comparison function */
+    const PLHashAllocOps *allocOps;     /* allocation operations */
+    void                *allocPriv;     /* allocation private data */
+#ifdef HASHMETER
+    PRUint32              nlookups;       /* total number of lookups */
+    PRUint32              nsteps;         /* number of hash chains traversed */
+    PRUint32              ngrows;         /* number of table expansions */
+    PRUint32              nshrinks;       /* number of table contractions */
+#endif
+};
+
+/*
+ * Create a new hash table.
+ * If allocOps is null, use default allocator ops built on top of malloc().
+ */
+PR_EXTERN(PLHashTable *)
+PL_NewHashTable(PRUint32 numBuckets, PLHashFunction keyHash,
+                PLHashComparator keyCompare, PLHashComparator valueCompare,
+                const PLHashAllocOps *allocOps, void *allocPriv);
+
+PR_EXTERN(void)
+PL_HashTableDestroy(PLHashTable *ht);
+
+/* Higher level access methods */
+PR_EXTERN(PLHashEntry *)
+PL_HashTableAdd(PLHashTable *ht, const void *key, void *value);
+
+PR_EXTERN(PRBool)
+PL_HashTableRemove(PLHashTable *ht, const void *key);
+
+PR_EXTERN(void *)
+PL_HashTableLookup(PLHashTable *ht, const void *key);
+
+PR_EXTERN(void *)
+PL_HashTableLookupConst(PLHashTable *ht, const void *key);
+
+PR_EXTERN(PRIntn)
+PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg);
+
+/* General-purpose C string hash function. */
+PR_EXTERN(PLHashNumber)
+PL_HashString(const void *key);
+
+/* Compare strings using strcmp(), return true if equal. */
+PR_EXTERN(PRIntn)
+PL_CompareStrings(const void *v1, const void *v2);
+
+/* Stub function just returns v1 == v2 */
+PR_EXTERN(PRIntn)
+PL_CompareValues(const void *v1, const void *v2);
+
+/* Low level access methods */
+PR_EXTERN(PLHashEntry **)
+PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key);
+
+PR_EXTERN(PLHashEntry **)
+PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash,
+                           const void *key);
+
+PR_EXTERN(PLHashEntry *)
+PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep, PLHashNumber keyHash,
+                   const void *key, void *value);
+
+PR_EXTERN(void)
+PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he);
+
+/* This can be trivially implemented using PL_HashTableEnumerateEntries. */
+PR_EXTERN(PRIntn)
+PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp);
+
+PR_END_EXTERN_C
+
+#endif /* plhash_h___ */
diff --git a/mozilla/nsprpub/lib/libc/include/plbase64.h b/mozilla/nsprpub/lib/libc/include/plbase64.h
new file mode 100644
index 0000000..d21ff5d
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/include/plbase64.h
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef _plbase64_h
+#define _plbase64_h
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * PL_Base64Encode
+ *
+ * This routine encodes the data pointed to by the "src" parameter using the
+ * base64 algorithm, and returns a pointer to the result.  If the "srclen"
+ * parameter is not zero, it specifies the length of the source data.  If it
+ * is zero, the source data is assumed to be null-terminated, and PL_strlen
+ * is used to determine the source length.  If the "dest" parameter is not
+ * null, it is assumed to point to a buffer of sufficient size (which may be
+ * calculated: ((srclen + 2)/3)*4) into which the encoded data is placed 
+ * (without any termination).  If the "dest" parameter is null, a buffer is
+ * allocated from the heap to hold the encoded data, and the result *will*
+ * be terminated with an extra null character.  It is the caller's 
+ * responsibility to free the result when it is allocated.  A null is returned 
+ * if the allocation fails.
+ *
+ * NOTE: when calculating ((srclen + 2)/3)*4), first ensure that
+ *     srclen <= (PR_UINT32_MAX/4) * 3
+ * to avoid PRUint32 overflow.
+ */
+
+PR_EXTERN(char *)
+PL_Base64Encode
+(
+    const char *src,
+    PRUint32    srclen,
+    char       *dest
+);
+
+/*
+ * PL_Base64Decode
+ *
+ * This routine decodes the data pointed to by the "src" parameter using
+ * the base64 algorithm, and returns a pointer to the result.  The source
+ * may either include or exclude any trailing '=' characters.  If the
+ * "srclen" parameter is not zero, it specifies the length of the source
+ * data.  If it is zero, PL_strlen will be used to determine the source
+ * length.  If the "dest" parameter is not null, it is assumed to point to
+ * a buffer of sufficient size (which may be calculated: (srclen * 3)/4
+ * when srclen includes the '=' characters) into which the decoded data
+ * is placed (without any termination).  If the "dest" parameter is null,
+ * a buffer is allocated from the heap to hold the decoded data, and the
+ * result *will* be terminated with an extra null character.  It is the
+ * caller's responsibility to free the result when it is allocated.  A null
+ * is retuned if the allocation fails, or if the source is not well-coded.
+ *
+ * NOTE: when calculating (srclen * 3)/4, first ensure that 
+ *     srclen <= PR_UINT32_MAX/3
+ * to avoid PRUint32 overflow.  Alternatively, calculate
+ *     (srclen/4) * 3 + ((srclen%4) * 3)/4
+ * which is equivalent but doesn't overflow for any value of srclen.
+ */
+
+PR_EXTERN(char *)
+PL_Base64Decode
+(
+    const char *src,
+    PRUint32    srclen,
+    char       *dest
+);
+
+PR_END_EXTERN_C
+
+#endif /* _plbase64_h */
diff --git a/mozilla/nsprpub/lib/libc/include/plerror.h b/mozilla/nsprpub/lib/libc/include/plerror.h
new file mode 100644
index 0000000..a2b8d0b
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/include/plerror.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:        plerror.h
+** Description: Simple routine to print translate the calling thread's
+**              error numbers and print them.
+*/
+
+#if defined(PLERROR_H)
+#else
+#define PLERROR_H
+
+#include "prio.h"
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+/*
+** Print the messages to "syserr" prepending 'msg' if not NULL.
+*/
+PR_EXTERN(void) PL_PrintError(const char *msg);
+
+/*
+** Print the messages to specified output file prepending 'msg' if not NULL.
+*/
+PR_EXTERN(void) PL_FPrintError(PRFileDesc *output, const char *msg);
+
+PR_END_EXTERN_C
+
+#endif /* defined(PLERROR_H) */
+
+/* plerror.h */
diff --git a/mozilla/nsprpub/lib/libc/include/plgetopt.h b/mozilla/nsprpub/lib/libc/include/plgetopt.h
new file mode 100644
index 0000000..fcdf23b
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/include/plgetopt.h
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:          plgetopt.h
+** Description:   utilities to parse argc/argv
+*/
+
+#if defined(PLGETOPT_H_)
+#else
+#define PLGETOPT_H_
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PLOptionInternal PLOptionInternal; 
+
+typedef enum
+{
+        PL_OPT_OK,              /* all's well with the option */
+        PL_OPT_EOL,             /* end of options list */
+        PL_OPT_BAD              /* invalid option (and value) */
+} PLOptStatus;
+
+typedef struct PLLongOpt
+{
+    const char * longOptName;   /* long option name string                  */
+    PRIntn       longOption;    /* value put in PLOptState for this option. */
+    PRBool       valueRequired; /* If option name not followed by '=',      */
+                                /* value is the next argument from argv.    */
+} PLLongOpt;
+
+typedef struct PLOptState
+{
+    char option;                /* the name of the option */
+    const char *value;          /* the value of that option | NULL */
+
+    PLOptionInternal *internal; /* private processing state */
+
+    PRIntn   longOption;        /* value from PLLongOpt put here */
+    PRIntn   longOptIndex;      /* index into caller's array of PLLongOpts */
+} PLOptState;
+
+/*
+ * PL_CreateOptState
+ *
+ * The argument "options" points to a string of single-character option 
+ * names.  Option names that may have an option argument value must be 
+ * followed immediately by a ':' character.  
+ */
+PR_EXTERN(PLOptState*) PL_CreateOptState(
+        PRIntn argc, char **argv, const char *options);
+
+/* 
+ * PL_CreateLongOptState
+ *
+ * Alternative to PL_CreateOptState.  
+ * Allows caller to specify BOTH a string of single-character option names, 
+ * AND an array of structures describing "long" (keyword) option names.  
+ * The array is terminated by a structure in which longOptName is NULL.  
+ * Long option values (arguments) may always be given as "--name=value".
+ * If PLLongOpt.valueRequired is not PR_FALSE, and the option name was not 
+ * followed by '=' then the next argument from argv is taken as the value.  
+ */
+PR_EXTERN(PLOptState*) PL_CreateLongOptState(
+        PRIntn argc, char **argv, const char *options, 
+        const PLLongOpt *longOpts);
+/*
+ * PL_DestroyOptState
+ *
+ * Call this to destroy the PLOptState returned from PL_CreateOptState or
+ * PL_CreateLongOptState.
+ */
+PR_EXTERN(void) PL_DestroyOptState(PLOptState *opt);
+
+/*
+ * PL_GetNextOpt
+ *
+ * When this function returns PL_OPT_OK, 
+ * - opt->option will hold the single-character option name that was parsed, 
+ *   or zero.  
+ * When opt->option is zero, the token parsed was either a "long" (keyword) 
+ *   option or a positional parameter.  
+ * For a positional parameter, 
+ * - opt->longOptIndex will contain -1, and
+ * - opt->value will point to the positional parameter string.
+ * For a long option name, 
+ * - opt->longOptIndex will contain the non-negative index of the 
+ *   PLLongOpt structure in the caller's array of PLLongOpt structures 
+ 8   corresponding to the long option name, and 
+ * For a single-character or long option, 
+ * - opt->longOption will contain the value of the single-character option
+ *   name, or the value of the longOption from the PLLongOpt structure
+ *   for that long option.  See notes below.
+ * - opt->value will point to the argument option string, or will
+ *   be NULL if no argument option string was given.
+ * When opt->option is non-zero, 
+ * - opt->longOptIndex will be -1
+ * When this function returns PL_OPT_EOL, or PL_OPT_BAD, the contents of
+ *   opt are undefined.
+ *
+ * Notes: It is possible to ignore opt->option, and always look at 
+ *   opt->longOption instead.  opt->longOption will contain the same value
+ *   as opt->option for single-character option names, and will contain the
+ *   value of longOption from the PLLongOpt structure for long option names.
+ * This means that it is possible to equivalence long option names to 
+ *   single character names by giving the longOption in the PLLongOpt struct
+ *   the same value as the single-character option name.  
+ * For long options that are NOT intended to be equivalent to any single-
+ *   character option, the longOption value should be chosen to not match 
+ *   any possible single character name.  It might be advisable to choose
+ *   longOption values greater than 0xff for such long options.
+ */
+PR_EXTERN(PLOptStatus) PL_GetNextOpt(PLOptState *opt);
+
+PR_END_EXTERN_C
+
+#endif /* defined(PLGETOPT_H_) */
+
+/* plgetopt.h */
+
diff --git a/mozilla/nsprpub/lib/libc/include/plstr.h b/mozilla/nsprpub/lib/libc/include/plstr.h
new file mode 100644
index 0000000..4d21cc4
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/include/plstr.h
@@ -0,0 +1,470 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Roland Mainz <roland mainz@informatik.med.uni-giessen.de>
+ *
+ * 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 ***** */
+
+#ifndef _plstr_h
+#define _plstr_h
+
+/*
+ * plstr.h
+ *
+ * This header file exports the API to the NSPR portable library or string-
+ * handling functions.  
+ * 
+ * This API was not designed as an "optimal" or "ideal" string library; it 
+ * was based on the good ol' unix string.3 functions, and was written to
+ *
+ *  1) replace the libc functions, for cross-platform consistency, 
+ *  2) complete the API on platforms lacking common functions (e.g., 
+ *     strcase*), and
+ *  3) to implement some obvious "closure" functions that I've seen
+ *     people hacking around in our code.
+ *
+ * Point number three largely means that most functions have an "strn"
+ * limited-length version, and all comparison routines have a non-case-
+ * sensitive version available.
+ */
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+/*
+ * PL_strlen
+ *
+ * Returns the length of the provided string, not including the trailing '\0'.
+ */
+
+PR_EXTERN(PRUint32)
+PL_strlen(const char *str);
+
+/*
+ * PL_strnlen
+ *
+ * Returns the length of the provided string, not including the trailing '\0',
+ * up to the indicated maximum.  The string will not be examined beyond the
+ * maximum; if no terminating '\0' is found, the maximum will be returned.
+ */
+
+PR_EXTERN(PRUint32)
+PL_strnlen(const char *str, PRUint32 max);
+
+/*
+ * PL_strcpy
+ *
+ * Copies the source string, up to and including the trailing '\0', into the
+ * destination buffer.  It does not (can not) verify that the destination
+ * buffer is large enough.  It returns the "dest" argument.
+ */
+
+PR_EXTERN(char *)
+PL_strcpy(char *dest, const char *src);
+
+/*
+ * PL_strncpy
+ *
+ * Copies the source string into the destination buffer, up to and including
+ * the trailing '\0' or up to and including the max'th character, whichever
+ * comes first.  It does not (can not) verify that the destination buffer is
+ * large enough.  If the source string is longer than the maximum length,
+ * the result will *not* be null-terminated (JLRU).
+ */
+
+PR_EXTERN(char *)
+PL_strncpy(char *dest, const char *src, PRUint32 max);
+
+/*
+ * PL_strncpyz
+ *
+ * Copies the source string into the destination buffer, up to and including 
+ * the trailing '\0' or up but not including the max'th character, whichever 
+ * comes first.  It does not (can not) verify that the destination buffer is
+ * large enough.  The destination string is always terminated with a '\0',
+ * unlike the traditional libc implementation.  It returns the "dest" argument.
+ *
+ * NOTE: If you call this with a source "abcdefg" and a max of 5, the 
+ * destination will end up with "abcd\0" (i.e., its strlen length will be 4)!
+ *
+ * This means you can do this:
+ *
+ *     char buffer[ SOME_SIZE ];
+ *     PL_strncpyz(buffer, src, sizeof(buffer));
+ *
+ * and the result will be properly terminated.
+ */
+
+PR_EXTERN(char *)
+PL_strncpyz(char *dest, const char *src, PRUint32 max);
+
+/*
+ * PL_strdup
+ *
+ * Returns a pointer to a malloc'd extent of memory containing a duplicate
+ * of the argument string.  The size of the allocated extent is one greater
+ * than the length of the argument string, because of the terminator.  A
+ * null argument, like a zero-length argument, will result in a pointer to
+ * a one-byte extent containing the null value.  This routine returns null
+ * upon malloc failure.
+ */
+
+PR_EXTERN(char *)
+PL_strdup(const char *s);
+
+/*
+ * PL_strfree
+ *
+ * Free memory allocated by PL_strdup
+ */
+
+PR_EXTERN(void)
+PL_strfree(char *s);
+
+/*
+ * PL_strndup
+ *
+ * Returns a pointer to a malloc'd extent of memory containing a duplicate
+ * of the argument string, up to the maximum specified.  If the argument
+ * string has a length greater than the value of the specified maximum, the
+ * return value will be a pointer to an extent of memory of length one
+ * greater than the maximum specified.  A null string, a zero-length string,
+ * or a zero maximum will all result in a pointer to a one-byte extent
+ * containing the null value.  This routine returns null upon malloc failure.
+ */
+
+PR_EXTERN(char *)
+PL_strndup(const char *s, PRUint32 max);
+
+/*
+ * PL_strcat
+ *
+ * Appends a copy of the string pointed to by the second argument to the
+ * end of the string pointed to by the first.  The destination buffer is
+ * not (can not be) checked for sufficient size.  A null destination
+ * argument returns null; otherwise, the first argument is returned.
+ */
+
+PR_EXTERN(char *)
+PL_strcat(char *dst, const char *src);
+
+/*
+ * PL_strncat
+ *
+ * Appends a copy of the string pointed to by the second argument, up to
+ * the maximum size specified, to the end of the string pointed to by the
+ * first.  The destination buffer is not (can not be) checked for sufficient
+ * size.  A null destination argument returns null; otherwise, the first 
+ * argument is returned.  If the maximum size limits the copy, then the
+ * result will *not* be null-terminated (JLRU).  A null destination
+ * returns null; otherwise, the destination argument is returned.
+ */
+
+PR_EXTERN(char *)
+PL_strncat(char *dst, const char *src, PRUint32 max);
+
+/*
+ * PL_strcatn
+ *
+ * Appends a copy of the string pointed to by the third argument, to the
+ * end of the string pointed to by the first.  The second argument specifies
+ * the maximum size of the destination buffer, including the null termination.
+ * If the existing string in dst is longer than the max, no action is taken.
+ * The resulting string will be null-terminated.  A null destination returns
+ * null; otherwise, the destination argument is returned.
+ */
+
+PR_EXTERN(char *)
+PL_strcatn(char *dst, PRUint32 max, const char *src);
+
+/*
+ * PL_strcmp
+ *
+ * Returns an integer, the sign of which -- positive, zero, or negative --
+ * reflects the lexical sorting order of the two strings indicated.  The
+ * result is positive if the first string comes after the second.  The
+ * NSPR implementation is not i18n.
+ */
+
+PR_EXTERN(PRIntn)
+PL_strcmp(const char *a, const char *b);
+
+/*
+ * PL_strncmp
+ * 
+ * Returns an integer, the sign of which -- positive, zero, or negative --
+ * reflects the lexical sorting order of the two strings indicated, up to
+ * the maximum specified.  The result is positive if the first string comes 
+ * after the second.  The NSPR implementation is not i18n.  If the maximum
+ * is zero, only the existance or non-existance (pointer is null) of the
+ * strings is compared.
+ */
+
+PR_EXTERN(PRIntn)
+PL_strncmp(const char *a, const char *b, PRUint32 max);
+
+/*
+ * PL_strcasecmp
+ *
+ * Returns an integer, the sign of which -- positive, zero or negative --
+ * reflects the case-insensitive lexical sorting order of the two strings
+ * indicated.  The result is positive if the first string comes after the 
+ * second.  The NSPR implementation is not i18n.
+ */
+
+PR_EXTERN(PRIntn)
+PL_strcasecmp(const char *a, const char *b);
+
+/*
+ * PL_strncasecmp
+ *
+ * Returns an integer, the sign of which -- positive, zero or negative --
+ * reflects the case-insensitive lexical sorting order of the first n characters
+ * of the two strings indicated.  The result is positive if the first string comes 
+ * after the second.  The NSPR implementation is not i18n.
+ */
+
+PR_EXTERN(PRIntn)
+PL_strncasecmp(const char *a, const char *b, PRUint32 max);
+
+/*
+ * PL_strchr
+ *
+ * Returns a pointer to the first instance of the specified character in the
+ * provided string.  It returns null if the character is not found, or if the
+ * provided string is null.  The character may be the null character.
+ */
+
+PR_EXTERN(char *)
+PL_strchr(const char *s, char c);
+
+/*
+ * PL_strrchr
+ *
+ * Returns a pointer to the last instance of the specified character in the
+ * provided string.  It returns null if the character is not found, or if the
+ * provided string is null.  The character may be the null character.
+ */
+
+PR_EXTERN(char *)
+PL_strrchr(const char *s, char c);
+
+/*
+ * PL_strnchr
+ * 
+ * Returns a pointer to the first instance of the specified character within the
+ * first n characters of the provided string.  It returns null if the character
+ * is not found, or if the provided string is null.  The character may be the
+ * null character.
+ */
+
+PR_EXTERN(char *)
+PL_strnchr(const char *s, char c, PRUint32 n);
+
+/*
+ * PL_strnrchr
+ *
+ * Returns a pointer to the last instance of the specified character within the
+ * first n characters of the provided string.  It returns null if the character is
+ * not found, or if the provided string is null.  The character may be the null
+ * character.
+ */
+
+PR_EXTERN(char *)
+PL_strnrchr(const char *s, char c, PRUint32 n);
+
+/*
+ * NOTE: Looking for strcasechr, strcaserchr, strncasechr, or strncaserchr?
+ * Use strpbrk, strprbrk, strnpbrk or strnprbrk.
+ */
+
+/*
+ * PL_strpbrk
+ *
+ * Returns a pointer to the first instance in the first string of any character
+ * (not including the terminating null character) of the second string.  It returns
+ * null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strpbrk(const char *s, const char *list);
+
+/*
+ * PL_strprbrk
+ *
+ * Returns a pointer to the last instance in the first string of any character
+ * (not including the terminating null character) of the second string.  It returns
+ * null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strprbrk(const char *s, const char *list);
+
+/*
+ * PL_strnpbrk
+ *
+ * Returns a pointer to the first instance (within the first n characters) of any
+ * character (not including the terminating null character) of the second string.
+ * It returns null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strnpbrk(const char *s, const char *list, PRUint32 n);
+
+/*
+ * PL_strnprbrk
+ *
+ * Returns a pointer to the last instance (within the first n characters) of any
+ * character (not including the terminating null character) of the second string.
+ * It returns null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strnprbrk(const char *s, const char *list, PRUint32 n);
+
+/*
+ * PL_strstr
+ *
+ * Returns a pointer to the first instance of the little string within the
+ * big one.  It returns null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strstr(const char *big, const char *little);
+
+/*
+ * PL_strrstr
+ *
+ * Returns a pointer to the last instance of the little string within the big one.
+ * It returns null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strrstr(const char *big, const char *little);
+
+/*
+ * PL_strnstr
+ *
+ * Returns a pointer to the first instance of the little string within the first
+ * n characters of the big one.  It returns null if either string is null.  It
+ * returns null if the length of the little string is greater than n.
+ */
+
+PR_EXTERN(char *)
+PL_strnstr(const char *big, const char *little, PRUint32 n);
+
+/*
+ * PL_strnrstr
+ *
+ * Returns a pointer to the last instance of the little string within the first
+ * n characters of the big one.  It returns null if either string is null.  It
+ * returns null if the length of the little string is greater than n.
+ */
+
+PR_EXTERN(char *)
+PL_strnrstr(const char *big, const char *little, PRUint32 max);
+
+/*
+ * PL_strcasestr
+ *
+ * Returns a pointer to the first instance of the little string within the big one,
+ * ignoring case.  It returns null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strcasestr(const char *big, const char *little);
+
+/*
+ * PL_strcaserstr
+ *
+ * Returns a pointer to the last instance of the little string within the big one,
+ * ignoring case.  It returns null if either string is null.
+ */
+
+PR_EXTERN(char *)
+PL_strcaserstr(const char *big, const char *little);
+
+/*
+ * PL_strncasestr
+ *
+ * Returns a pointer to the first instance of the little string within the first
+ * n characters of the big one, ignoring case.  It returns null if either string is 
+ * null.  It returns null if the length of the little string is greater than n.
+ */
+
+PR_EXTERN(char *)
+PL_strncasestr(const char *big, const char *little, PRUint32 max);
+
+/*
+ * PL_strncaserstr
+ *
+ * Returns a pointer to the last instance of the little string within the first
+ * n characters of the big one, ignoring case.  It returns null if either string is
+ * null.  It returns null if the length of the little string is greater than n.
+ */
+
+PR_EXTERN(char *)
+PL_strncaserstr(const char *big, const char *little, PRUint32 max);
+
+/*
+ * PL_strtok_r
+ *
+ * Splits the string s1 into tokens, separated by one or more characters
+ * from the separator string s2.  The argument lasts points to a
+ * user-supplied char * pointer in which PL_strtok_r stores information
+ * for it to continue scanning the same string.
+ *
+ * In the first call to PL_strtok_r, s1 points to a string and the value
+ * of *lasts is ignored.  PL_strtok_r returns a pointer to the first
+ * token, writes '\0' into the character following the first token, and
+ * updates *lasts.
+ *
+ * In subsequent calls, s1 is null and lasts must stay unchanged from the
+ * previous call.  The separator string s2 may be different from call to
+ * call.  PL_strtok_r returns a pointer to the next token in s1.  When no
+ * token remains in s1, PL_strtok_r returns null.
+ */
+
+PR_EXTERN(char *)
+PL_strtok_r(char *s1, const char *s2, char **lasts);
+
+/*
+ * Things not (yet?) included: strspn/strcspn, strsep.
+ * memchr, memcmp, memcpy, memccpy, index, rindex, bcmp, bcopy, bzero.
+ * Any and all i18n/l10n stuff.
+ */
+
+PR_END_EXTERN_C
+
+#endif /* _plstr_h */
diff --git a/mozilla/nsprpub/lib/libc/src/base64.c b/mozilla/nsprpub/lib/libc/src/base64.c
new file mode 100644
index 0000000..e3fd80d
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/base64.c
@@ -0,0 +1,448 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plbase64.h"
+#include "prlog.h" /* For PR_NOT_REACHED */
+#include "prmem.h" /* for malloc / PR_MALLOC */
+
+#include <string.h> /* for strlen */
+
+static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static void
+encode3to4
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32 = (PRUint32)0;
+    PRIntn i, j = 18;
+
+    for( i = 0; i < 3; i++ )
+    {
+        b32 <<= 8;
+        b32 |= (PRUint32)src[i];
+    }
+
+    for( i = 0; i < 4; i++ )
+    {
+        dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ];
+        j -= 6;
+    }
+
+    return;
+}
+
+static void
+encode2to4
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
+    dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ];
+    dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ];
+    dest[3] = (unsigned char)'=';
+    return;
+}
+
+static void
+encode1to4
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
+    dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ];
+    dest[2] = (unsigned char)'=';
+    dest[3] = (unsigned char)'=';
+    return;
+}
+
+static void
+encode
+(
+    const unsigned char    *src,
+    PRUint32                srclen,
+    unsigned char          *dest
+)
+{
+    while( srclen >= 3 )
+    {
+        encode3to4(src, dest);
+        src += 3;
+        dest += 4;
+        srclen -= 3;
+    }
+
+    switch( srclen )
+    {
+        case 2:
+            encode2to4(src, dest);
+            break;
+        case 1:
+            encode1to4(src, dest);
+            break;
+        case 0:
+            break;
+        default:
+            PR_NOT_REACHED("coding error");
+    }
+
+    return;
+}
+
+/*
+ * PL_Base64Encode
+ *
+ * If the destination argument is NULL, a return buffer is 
+ * allocated, and the data therein will be null-terminated.  
+ * If the destination argument is not NULL, it is assumed to
+ * be of sufficient size, and the contents will not be null-
+ * terminated by this routine.
+ *
+ * Returns null if the allocation fails.
+ */
+
+PR_IMPLEMENT(char *)
+PL_Base64Encode
+(
+    const char *src,
+    PRUint32    srclen,
+    char       *dest
+)
+{
+    if( 0 == srclen )
+    {
+        size_t len = strlen(src);
+        srclen = len;
+        /* Detect truncation. */
+        if( srclen != len )
+        {
+            return (char *)0;
+        }
+    }
+
+    if( (char *)0 == dest )
+    {
+        PRUint32 destlen;
+        /* Ensure all PRUint32 values stay within range. */
+        if( srclen > (PR_UINT32_MAX/4) * 3 )
+        {
+            return (char *)0;
+        }
+        destlen = ((srclen + 2)/3) * 4;
+        dest = (char *)PR_MALLOC(destlen + 1);
+        if( (char *)0 == dest )
+        {
+            return (char *)0;
+        }
+        dest[ destlen ] = (char)0; /* null terminate */
+    }
+
+    encode((const unsigned char *)src, srclen, (unsigned char *)dest);
+    return dest;
+}
+
+static PRInt32
+codetovalue
+(
+    unsigned char c
+)
+{
+    if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') )
+    {
+        return (PRInt32)(c - (unsigned char)'A');
+    }
+    else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') )
+    {
+        return ((PRInt32)(c - (unsigned char)'a') +26);
+    }
+    else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') )
+    {
+        return ((PRInt32)(c - (unsigned char)'0') +52);
+    }
+    else if( (unsigned char)'+' == c )
+    {
+        return (PRInt32)62;
+    }
+    else if( (unsigned char)'/' == c )
+    {
+        return (PRInt32)63;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+static PRStatus
+decode4to3
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32 = (PRUint32)0;
+    PRInt32 bits;
+    PRIntn i;
+
+    for( i = 0; i < 4; i++ )
+    {
+        bits = codetovalue(src[i]);
+        if( bits < 0 )
+        {
+            return PR_FAILURE;
+        }
+
+        b32 <<= 6;
+        b32 |= bits;
+    }
+
+    dest[0] = (unsigned char)((b32 >> 16) & 0xFF);
+    dest[1] = (unsigned char)((b32 >>  8) & 0xFF);
+    dest[2] = (unsigned char)((b32      ) & 0xFF);
+
+    return PR_SUCCESS;
+}
+
+static PRStatus
+decode3to2
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32 = (PRUint32)0;
+    PRInt32 bits;
+    PRUint32 ubits;
+
+    bits = codetovalue(src[0]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    b32 = (PRUint32)bits;
+    b32 <<= 6;
+
+    bits = codetovalue(src[1]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    b32 |= (PRUint32)bits;
+    b32 <<= 4;
+
+    bits = codetovalue(src[2]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    ubits = (PRUint32)bits;
+    b32 |= (ubits >> 2);
+
+    dest[0] = (unsigned char)((b32 >> 8) & 0xFF);
+    dest[1] = (unsigned char)((b32     ) & 0xFF);
+
+    return PR_SUCCESS;
+}
+
+static PRStatus
+decode2to1
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32;
+    PRUint32 ubits;
+    PRInt32 bits;
+
+    bits = codetovalue(src[0]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    ubits = (PRUint32)bits;
+    b32 = (ubits << 2);
+
+    bits = codetovalue(src[1]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    ubits = (PRUint32)bits;
+    b32 |= (ubits >> 4);
+
+    dest[0] = (unsigned char)b32;
+
+    return PR_SUCCESS;
+}
+
+static PRStatus
+decode
+(
+    const unsigned char    *src,
+    PRUint32                srclen,
+    unsigned char          *dest
+)
+{
+    PRStatus rv;
+
+    while( srclen >= 4 )
+    {
+        rv = decode4to3(src, dest);
+        if( PR_SUCCESS != rv )
+        {
+            return PR_FAILURE;
+        }
+
+        src += 4;
+        dest += 3;
+        srclen -= 4;
+    }
+
+    switch( srclen )
+    {
+        case 3:
+            rv = decode3to2(src, dest);
+            break;
+        case 2:
+            rv = decode2to1(src, dest);
+            break;
+        case 1:
+            rv = PR_FAILURE;
+            break;
+        case 0:
+            rv = PR_SUCCESS;
+            break;
+        default:
+            PR_NOT_REACHED("coding error");
+    }
+
+    return rv;
+}
+
+/*
+ * PL_Base64Decode
+ *
+ * If the destination argument is NULL, a return buffer is
+ * allocated and the data therein will be null-terminated.
+ * If the destination argument is not null, it is assumed
+ * to be of sufficient size, and the data will not be null-
+ * terminated by this routine.
+ * 
+ * Returns null if the allocation fails, or if the source string is 
+ * not well-formed.
+ */
+
+PR_IMPLEMENT(char *)
+PL_Base64Decode
+(
+    const char *src,
+    PRUint32    srclen,
+    char       *dest
+)
+{
+    PRStatus status;
+    PRBool allocated = PR_FALSE;
+
+    if( (char *)0 == src )
+    {
+        return (char *)0;
+    }
+
+    if( 0 == srclen )
+    {
+        size_t len = strlen(src);
+        srclen = len;
+        /* Detect truncation. */
+        if( srclen != len )
+        {
+            return (char *)0;
+        }
+    }
+
+    if( srclen && (0 == (srclen & 3)) )
+    {
+        if( (char)'=' == src[ srclen-1 ] )
+        {
+            if( (char)'=' == src[ srclen-2 ] )
+            {
+                srclen -= 2;
+            }
+            else
+            {
+                srclen -= 1;
+            }
+        }
+    }
+
+    if( (char *)0 == dest )
+    {
+        /* The following computes ((srclen * 3) / 4) without overflow. */
+        PRUint32 destlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4;
+        dest = (char *)PR_MALLOC(destlen + 1);
+        if( (char *)0 == dest )
+        {
+            return (char *)0;
+        }
+        dest[ destlen ] = (char)0; /* null terminate */
+        allocated = PR_TRUE;
+    }
+
+    status = decode((const unsigned char *)src, srclen, (unsigned char *)dest);
+    if( PR_SUCCESS != status )
+    {
+        if( PR_TRUE == allocated )
+        {
+            PR_DELETE(dest);
+        }
+
+        return (char *)0;
+    }
+
+    return dest;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/plerror.c b/mozilla/nsprpub/lib/libc/src/plerror.c
new file mode 100644
index 0000000..90b713a
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/plerror.c
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:plerror.c
+** Description: Simple routine to print translate the calling thread's
+**  error numbers and print them to "syserr".
+*/
+
+#include "plerror.h"
+
+#include "prprf.h"
+#include "prerror.h"
+
+PR_IMPLEMENT(void) PL_FPrintError(PRFileDesc *fd, const char *msg)
+{
+PRErrorCode error = PR_GetError();
+PRInt32 oserror = PR_GetOSError();
+const char *name = PR_ErrorToName(error);
+
+	if (NULL != msg) PR_fprintf(fd, "%s: ", msg);
+    if (NULL == name)
+        PR_fprintf(
+			fd, " (%d)OUT OF RANGE, oserror = %d\n", error, oserror);
+    else
+        PR_fprintf(
+            fd, "%s(%d), oserror = %d\n",
+            name, error, oserror);
+}  /* PL_FPrintError */
+
+PR_IMPLEMENT(void) PL_PrintError(const char *msg)
+{
+	static PRFileDesc *fd = NULL;
+	if (NULL == fd) fd = PR_GetSpecialFD(PR_StandardError);
+	PL_FPrintError(fd, msg);
+}  /* PL_PrintError */
+
+/* plerror.c */
diff --git a/mozilla/nsprpub/lib/libc/src/plgetopt.c b/mozilla/nsprpub/lib/libc/src/plgetopt.c
new file mode 100644
index 0000000..0fe4faf
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/plgetopt.c
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:          plgetopt.c
+** Description:   utilities to parse argc/argv
+*/
+
+#include "prmem.h"
+#include "prlog.h"
+#include "prerror.h"
+#include "plstr.h"
+#include "plgetopt.h"
+
+#include <string.h>
+
+static char static_Nul = 0;
+
+struct PLOptionInternal
+{
+    const char *options;        /* client options list specification */
+    PRIntn argc;                /* original number of arguments */
+    char **argv;                /* vector of pointers to arguments */
+    PRIntn xargc;               /* which one we're processing now */
+    const char *xargv;          /* where within *argv[xargc] */
+    PRIntn minus;               /* do we already have the '-'? */
+    const PLLongOpt *longOpts;  /* Caller's array */
+    PRBool endOfOpts;           /* have reached a "--" argument */
+    PRIntn optionsLen;          /* is strlen(options) */
+};
+
+/*
+** Create the state in which to parse the tokens.
+**
+** argc        the sum of the number of options and their values
+** argv        the options and their values
+** options    vector of single character options w/ | w/o ':
+*/
+PR_IMPLEMENT(PLOptState*) PL_CreateOptState(
+    PRIntn argc, char **argv, const char *options)
+{
+    return PL_CreateLongOptState( argc, argv, options, NULL);
+}  /* PL_CreateOptState */
+
+PR_IMPLEMENT(PLOptState*) PL_CreateLongOptState(
+    PRIntn argc, char **argv, const char *options, 
+    const PLLongOpt *longOpts)
+{
+    PLOptState *opt = NULL;
+    PLOptionInternal *internal;
+
+    if (NULL == options) 
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return opt;
+    }
+
+    opt = PR_NEWZAP(PLOptState);
+    if (NULL == opt) 
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return opt;
+    }
+
+    internal = PR_NEW(PLOptionInternal);
+    if (NULL == internal)
+    {
+        PR_DELETE(opt);
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+
+    opt->option = 0;
+    opt->value = NULL;
+    opt->internal = internal;
+    opt->longOption   =  0;
+    opt->longOptIndex = -1;
+
+    internal->argc = argc;
+    internal->argv = argv;
+    internal->xargc = 0;
+    internal->xargv = &static_Nul;
+    internal->minus = 0;
+    internal->options = options;
+    internal->longOpts = longOpts;
+    internal->endOfOpts = PR_FALSE;
+    internal->optionsLen = PL_strlen(options);
+
+    return opt;
+}  /* PL_CreateLongOptState */
+
+/*
+** Destroy object created by CreateOptState()
+*/
+PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt)
+{
+    PR_DELETE(opt->internal);
+    PR_DELETE(opt);
+}  /* PL_DestroyOptState */
+
+PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt)
+{
+    PLOptionInternal *internal = opt->internal;
+
+    opt->longOption   =  0;
+    opt->longOptIndex = -1;
+    /*
+    ** If the current xarg points to nul, advance to the next
+    ** element of the argv vector. If the vector index is equal
+    ** to argc, we're out of arguments, so return an EOL.
+    ** Note whether the first character of the new argument is
+    ** a '-' and skip by it if it is.
+    */
+    while (0 == *internal->xargv)
+    {
+        internal->xargc += 1;
+        if (internal->xargc >= internal->argc)
+        {
+            opt->option = 0;
+            opt->value = NULL;
+            return PL_OPT_EOL;
+        }
+        internal->xargv = internal->argv[internal->xargc];
+        internal->minus = 0;
+        if (!internal->endOfOpts && ('-' == *internal->xargv)) 
+        {
+            internal->minus++;
+            internal->xargv++;  /* and consume */
+            if ('-' == *internal->xargv && internal->longOpts) 
+            {
+                internal->minus++;
+                internal->xargv++;
+                if (0 == *internal->xargv) 
+                {
+                    internal->endOfOpts = PR_TRUE;
+                }
+            }
+        }
+    }
+
+    /*
+    ** If we already have a '-' or '--' in hand, xargv points to the next
+    ** option. See if we can find a match in the list of possible
+    ** options supplied.
+    */
+
+    if (internal->minus == 2) 
+    {
+        char * foundEqual = strchr(internal->xargv,'=');
+        PRIntn optNameLen = foundEqual ? (foundEqual - internal->xargv) :
+                            strlen(internal->xargv);
+        const PLLongOpt *longOpt = internal->longOpts;
+
+        opt->option = 0;
+        opt->value  = NULL;
+
+        for (; longOpt->longOptName; ++longOpt) 
+        {
+            if (strncmp(longOpt->longOptName, internal->xargv, optNameLen))
+                continue;  /* not a possible match */
+            if (strlen(longOpt->longOptName) != optNameLen)
+                continue;  /* not a match */
+            /* option name match */
+            opt->longOptIndex = longOpt - internal->longOpts;
+            opt->longOption   = longOpt->longOption;
+            if (foundEqual) 
+            {
+                opt->value = foundEqual[1] ? foundEqual + 1 : NULL;
+            }
+            else if (longOpt->valueRequired)
+            {
+                opt->value = internal->argv[++(internal->xargc)];
+            }
+            internal->xargv = &static_Nul; /* consume this */
+            return PL_OPT_OK;
+        }
+        internal->xargv = &static_Nul; /* consume this */
+        return PL_OPT_BAD;
+    }
+    if (internal->minus)
+    {
+        PRIntn cop;
+        PRIntn eoo = internal->optionsLen;
+        for (cop = 0; cop < eoo; ++cop)
+        {
+            if (internal->options[cop] == *internal->xargv)
+            {
+                opt->option = *internal->xargv++;
+                opt->longOption = opt->option & 0xff;
+                /*
+                ** if options indicates that there's an associated
+                ** value, this argv is finished and the next is the
+                ** option's value.
+                */
+                if (':' == internal->options[cop + 1])
+                {
+                    if (0 != *internal->xargv) 
+                        return PL_OPT_BAD;
+                    opt->value = internal->argv[++(internal->xargc)];
+                    internal->xargv = &static_Nul;
+                    internal->minus = 0;
+                }
+                else 
+                    opt->value = NULL; 
+                return PL_OPT_OK;
+            }
+        }
+        internal->xargv += 1;  /* consume that option */
+        return PL_OPT_BAD;
+    }
+    /*
+    ** No '-', so it must be a standalone value. The option is nul.
+    */
+    opt->value = internal->argv[internal->xargc];
+    internal->xargv = &static_Nul;
+    opt->option = 0;
+    return PL_OPT_OK;
+}  /* PL_GetNextOpt */
+
+/* plgetopt.c */
diff --git a/mozilla/nsprpub/lib/libc/src/strcase.c b/mozilla/nsprpub/lib/libc/src/strcase.c
new file mode 100644
index 0000000..7e280aa
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strcase.c
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include <string.h>
+
+static const unsigned char uc[] =
+{
+    '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+    '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+    '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+    '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+    ' ',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
+    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+    '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
+    '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177',
+    0200,   0201,   0202,   0203,   0204,   0205,   0206,   0207,
+    0210,   0211,   0212,   0213,   0214,   0215,   0216,   0217,
+    0220,   0221,   0222,   0223,   0224,   0225,   0226,   0227,
+    0230,   0231,   0232,   0233,   0234,   0235,   0236,   0237,
+    0240,   0241,   0242,   0243,   0244,   0245,   0246,   0247,
+    0250,   0251,   0252,   0253,   0254,   0255,   0256,   0257,
+    0260,   0261,   0262,   0263,   0264,   0265,   0266,   0267,
+    0270,   0271,   0272,   0273,   0274,   0275,   0276,   0277,
+    0300,   0301,   0302,   0303,   0304,   0305,   0306,   0307,
+    0310,   0311,   0312,   0313,   0314,   0315,   0316,   0317,
+    0320,   0321,   0322,   0323,   0324,   0325,   0326,   0327,
+    0330,   0331,   0332,   0333,   0334,   0335,   0336,   0337,
+    0340,   0341,   0342,   0343,   0344,   0345,   0346,   0347,
+    0350,   0351,   0352,   0353,   0354,   0355,   0356,   0357,
+    0360,   0361,   0362,   0363,   0364,   0365,   0366,   0367,
+    0370,   0371,   0372,   0373,   0374,   0375,   0376,   0377
+};
+
+PR_IMPLEMENT(PRIntn)
+PL_strcasecmp(const char *a, const char *b)
+{
+    const unsigned char *ua = (const unsigned char *)a;
+    const unsigned char *ub = (const unsigned char *)b;
+
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
+    {
+        a++;
+        ua++;
+        ub++;
+    }
+
+    return (PRIntn)(uc[*ua] - uc[*ub]);
+}
+
+PR_IMPLEMENT(PRIntn)
+PL_strncasecmp(const char *a, const char *b, PRUint32 max)
+{
+    const unsigned char *ua = (const unsigned char *)a;
+    const unsigned char *ub = (const unsigned char *)b;
+
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( max && (uc[*ua] == uc[*ub]) && ('\0' != *a) )
+    {
+        a++;
+        ua++;
+        ub++;
+        max--;
+    }
+
+    if( 0 == max ) return (PRIntn)0;
+
+    return (PRIntn)(uc[*ua] - uc[*ub]);
+}
+
+PR_IMPLEMENT(char *)
+PL_strcasestr(const char *big, const char *little)
+{
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = strlen(little);
+
+    for( ; *big; big++ )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(big, little, ll) )
+                return (char *)big;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strcaserstr(const char *big, const char *little)
+{
+    const char *p;
+    PRUint32 bl, ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    bl = strlen(big);
+    ll = strlen(little);
+    if( bl < ll ) return (char *)0;
+    p = &big[ bl - ll ];
+
+    for( ; p >= big; p-- )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncasestr(const char *big, const char *little, PRUint32 max)
+{
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = strlen(little);
+    if( ll > max ) return (char *)0;
+    max -= ll;
+    max++;
+
+    for( ; max && *big; big++, max-- )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(big, little, ll) )
+                return (char *)big;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncaserstr(const char *big, const char *little, PRUint32 max)
+{
+    const char *p;
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = strlen(little);
+
+    for( p = big; max && *p; p++, max-- )
+        ;
+
+    p -= ll;
+    if( p < big ) return (char *)0;
+
+    for( ; p >= big; p-- )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strcat.c b/mozilla/nsprpub/lib/libc/src/strcat.c
new file mode 100644
index 0000000..f71b097
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strcat.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include <string.h>
+
+PR_IMPLEMENT(char *)
+PL_strcat(char *dest, const char *src)
+{
+    if( ((char *)0 == dest) || ((const char *)0 == src) )
+        return dest;
+
+    return strcat(dest, src);
+}
+
+PR_IMPLEMENT(char *)
+PL_strncat(char *dest, const char *src, PRUint32 max)
+{
+    char *rv;
+
+    if( ((char *)0 == dest) || ((const char *)0 == src) || (0 == max) )
+        return dest;
+
+    for( rv = dest; *dest; dest++ )
+        ;
+
+    (void)PL_strncpy(dest, src, max);
+    return rv;
+}
+
+PR_IMPLEMENT(char *)
+PL_strcatn(char *dest, PRUint32 max, const char *src)
+{
+    char *rv;
+    PRUint32 dl;
+
+    if( ((char *)0 == dest) || ((const char *)0 == src) )
+        return dest;
+
+    for( rv = dest, dl = 0; *dest; dest++, dl++ )
+        ;
+
+    if( max <= dl ) return rv;
+    (void)PL_strncpyz(dest, src, max-dl);
+
+    return rv;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strchr.c b/mozilla/nsprpub/lib/libc/src/strchr.c
new file mode 100644
index 0000000..35ccedc
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strchr.c
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include <string.h>
+
+PR_IMPLEMENT(char *)
+PL_strchr(const char *s, char c)
+{
+    if( (const char *)0 == s ) return (char *)0;
+
+    return strchr(s, c);
+}
+
+PR_IMPLEMENT(char *)
+PL_strrchr(const char *s, char c)
+{
+    if( (const char *)0 == s ) return (char *)0;
+
+    return strrchr(s, c);
+}
+
+PR_IMPLEMENT(char *)
+PL_strnchr(const char *s, char c, PRUint32 n)
+{
+    if( (const char *)0 == s ) return (char *)0;
+
+    for( ; n && *s; s++, n-- )
+        if( *s == c )
+            return (char *)s;
+
+    if( ((char)0 == c) && (n > 0) && ((char)0 == *s) ) return (char *)s;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnrchr(const char *s, char c, PRUint32 n)
+{
+    const char *p;
+
+    if( (const char *)0 == s ) return (char *)0;
+
+    for( p = s; n && *p; p++, n-- )
+        ;
+
+    if( ((char)0 == c) && (n > 0) && ((char)0 == *p) ) return (char *)p;
+
+    for( p--; p >= s; p-- )
+        if( *p == c )
+            return (char *)p;
+
+    return (char *)0;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strcmp.c b/mozilla/nsprpub/lib/libc/src/strcmp.c
new file mode 100644
index 0000000..095e178
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strcmp.c
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include <string.h>
+
+PR_IMPLEMENT(PRIntn)
+PL_strcmp(const char *a, const char *b)
+{
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    return (PRIntn)strcmp(a, b);
+}
+
+PR_IMPLEMENT(PRIntn)
+PL_strncmp(const char *a, const char *b, PRUint32 max)
+{
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    return (PRIntn)strncmp(a, b, (size_t)max);
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strcpy.c b/mozilla/nsprpub/lib/libc/src/strcpy.c
new file mode 100644
index 0000000..b576b67
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strcpy.c
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include <string.h>
+
+PR_IMPLEMENT(char *)
+PL_strcpy(char *dest, const char *src)
+{
+    if( ((char *)0 == dest) || ((const char *)0 == src) ) return (char *)0;
+
+    return strcpy(dest, src);
+}
+
+PR_IMPLEMENT(char *)
+PL_strncpy(char *dest, const char *src, PRUint32 max)
+{
+    char *rv;
+    
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return (char *)0;
+
+    for( rv = dest; max && ((*dest = *src) != 0); dest++, src++, max-- )
+        ;
+
+#ifdef JLRU
+    /* XXX I (wtc) think the -- and ++ operators should be postfix. */
+    while( --max )
+        *++dest = '\0';
+#endif /* JLRU */
+
+    return rv;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncpyz(char *dest, const char *src, PRUint32 max)
+{
+    char *rv;
+    
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return (char *)0;
+    if( 0 == max ) return (char *)0;
+
+    for( rv = dest, max--; max && ((*dest = *src) != 0); dest++, src++, max-- )
+        ;
+
+    *dest = '\0';
+
+    return rv;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strdup.c b/mozilla/nsprpub/lib/libc/src/strdup.c
new file mode 100644
index 0000000..27a553c
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strdup.c
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include "prmem.h"
+#include <string.h>
+
+PR_IMPLEMENT(char *)
+PL_strdup(const char *s)
+{
+    char *rv;
+    size_t n;
+
+    if( (const char *)0 == s )
+        s = "";
+
+    n = strlen(s) + 1;
+
+    rv = (char *)malloc(n);
+    if( (char *)0 == rv ) return rv;
+
+    (void)memcpy(rv, s, n);
+
+    return rv;
+}
+
+PR_IMPLEMENT(void)
+PL_strfree(char *s)
+{
+    free(s);
+}
+
+PR_IMPLEMENT(char *)
+PL_strndup(const char *s, PRUint32 max)
+{
+    char *rv;
+    size_t l;
+
+    if( (const char *)0 == s )
+        s = "";
+
+    l = PL_strnlen(s, max);
+
+    rv = (char *)malloc(l+1);
+    if( (char *)0 == rv ) return rv;
+
+    (void)memcpy(rv, s, l);
+    rv[l] = '\0';
+
+    return rv;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strlen.c b/mozilla/nsprpub/lib/libc/src/strlen.c
new file mode 100644
index 0000000..e03f7d2
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strlen.c
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include "prtypes.h"
+#include "prlog.h"
+#include <string.h>
+
+PR_IMPLEMENT(PRUint32)
+PL_strlen(const char *str)
+{
+    size_t l;
+
+    if( (const char *)0 == str ) return 0;
+
+    l = strlen(str);
+
+    /* error checking in case we have a 64-bit platform -- make sure
+     * we don't have ultra long strings that overflow an int32
+     */ 
+    if( sizeof(PRUint32) < sizeof(size_t) )
+    {
+        if( l > PR_INT32_MAX )
+            PR_Assert("l <= PR_INT32_MAX", __FILE__, __LINE__);
+    }
+
+    return (PRUint32)l;
+}
+
+PR_IMPLEMENT(PRUint32)
+PL_strnlen(const char *str, PRUint32 max)
+{
+    register const char *s;
+
+    if( (const char *)0 == str ) return 0;
+    for( s = str; max && *s; s++, max-- )
+        ;
+
+    return (PRUint32)(s - str);
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strpbrk.c b/mozilla/nsprpub/lib/libc/src/strpbrk.c
new file mode 100644
index 0000000..afcb4f5
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strpbrk.c
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include <string.h>
+
+PR_IMPLEMENT(char *)
+PL_strpbrk(const char *s, const char *list)
+{
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    return strpbrk(s, list);
+}
+
+PR_IMPLEMENT(char *)
+PL_strprbrk(const char *s, const char *list)
+{
+    const char *p;
+    const char *r;
+
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    for( r = s; *r; r++ )
+        ;
+
+    for( r--; r >= s; r-- )
+        for( p = list; *p; p++ )
+            if( *r == *p )
+                return (char *)r;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnpbrk(const char *s, const char *list, PRUint32 max)
+{
+    const char *p;
+
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    for( ; max && *s; s++, max-- )
+        for( p = list; *p; p++ )
+            if( *s == *p )
+                return (char *)s;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnprbrk(const char *s, const char *list, PRUint32 max)
+{
+    const char *p;
+    const char *r;
+
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    for( r = s; max && *r; r++, max-- )
+        ;
+
+    for( r--; r >= s; r-- )
+        for( p = list; *p; p++ )
+            if( *r == *p )
+                return (char *)r;
+
+    return (char *)0;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strstr.c b/mozilla/nsprpub/lib/libc/src/strstr.c
new file mode 100644
index 0000000..6bc03d3
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strstr.c
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "plstr.h"
+#include <string.h>
+
+PR_IMPLEMENT(char *)
+PL_strstr(const char *big, const char *little)
+{
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    return strstr(big, little);
+}
+
+PR_IMPLEMENT(char *)
+PL_strrstr(const char *big, const char *little)
+{
+    const char *p;
+    size_t ll;
+    size_t bl;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = strlen(little);
+    bl = strlen(big);
+    if( bl < ll ) return (char *)0;
+    p = &big[ bl - ll ];
+
+    for( ; p >= big; p-- )
+        if( *little == *p )
+            if( 0 == strncmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnstr(const char *big, const char *little, PRUint32 max)
+{
+    size_t ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = strlen(little);
+    if( ll > (size_t)max ) return (char *)0;
+    max -= (PRUint32)ll;
+    max++;
+
+    for( ; max && *big; big++, max-- )
+        if( *little == *big )
+            if( 0 == strncmp(big, little, ll) )
+                return (char *)big;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnrstr(const char *big, const char *little, PRUint32 max)
+{
+    const char *p;
+    size_t ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = strlen(little);
+
+    for( p = big; max && *p; p++, max-- )
+        ;
+
+    p -= ll;
+    if( p < big ) return (char *)0;
+
+    for( ; p >= big; p-- )
+        if( *little == *p )
+            if( 0 == strncmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
diff --git a/mozilla/nsprpub/lib/libc/src/strtok.c b/mozilla/nsprpub/lib/libc/src/strtok.c
new file mode 100644
index 0000000..400e9a4
--- /dev/null
+++ b/mozilla/nsprpub/lib/libc/src/strtok.c
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Roland Mainz <roland mainz@informatik.med.uni-giessen.de>
+ *
+ * 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 "plstr.h"
+
+PR_IMPLEMENT(char *)
+PL_strtok_r(char *s1, const char *s2, char **lasts)
+{
+    const char *sepp;
+    int         c, sc;
+    char       *tok;
+
+    if( s1 == NULL )
+    {
+        if( *lasts == NULL )
+            return NULL;
+
+        s1 = *lasts;
+    }
+  
+    for( ; (c = *s1) != 0; s1++ )
+    {
+        for( sepp = s2 ; (sc = *sepp) != 0 ; sepp++ )
+        {
+            if( c == sc )
+                break;
+        }
+        if( sc == 0 )
+            break; 
+    }
+
+    if( c == 0 )
+    {
+        *lasts = NULL;
+        return NULL;
+    }
+  
+    tok = s1++;
+
+    for( ; (c = *s1) != 0; s1++ )
+    {
+        for( sepp = s2; (sc = *sepp) != 0; sepp++ )
+        {
+            if( c == sc )
+            {
+                *s1++ = '\0';
+                *lasts = s1;
+                return tok;
+            }
+        }
+    }
+    *lasts = NULL;
+    return tok;
+}
diff --git a/mozilla/nsprpub/pr/include/md/_darwin.cfg b/mozilla/nsprpub/pr/include/md/_darwin.cfg
new file mode 100644
index 0000000..60bea8e
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_darwin.cfg
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#define PR_AF_INET6 30  /* same as AF_INET6 */
+
+#ifdef __LITTLE_ENDIAN__
+#undef IS_BIG_ENDIAN
+#define  IS_LITTLE_ENDIAN 1
+#else
+#undef IS_LITTLE_ENDIAN
+#define  IS_BIG_ENDIAN 1
+#endif
+
+#ifdef __x86_64__
+#define IS_64
+#endif
+
+#ifndef HAVE_LONG_LONG
+#define	HAVE_LONG_LONG
+#endif
+#undef	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS 1
+
+#ifdef IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+#define PR_BITS_PER_DWORD   64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+#define PR_BITS_PER_DWORD_LOG2  6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+#define PR_ALIGN_OF_DWORD   8
+
+#else /* IS_64 */
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+#define PR_BITS_PER_DWORD   64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#endif /* IS_64 */
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
+
diff --git a/mozilla/nsprpub/pr/include/md/_darwin.h b/mozilla/nsprpub/pr/include/md/_darwin.h
new file mode 100644
index 0000000..fc37798
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_darwin.h
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef nspr_darwin_defs_h___
+#define nspr_darwin_defs_h___
+
+#include "prthread.h"
+
+#include <sys/syscall.h>
+
+#ifdef XP_MACOSX
+#include <AvailabilityMacros.h>
+#endif
+
+#define PR_LINKER_ARCH	"darwin"
+#define _PR_SI_SYSNAME  "DARWIN"
+#ifdef __i386__
+#define _PR_SI_ARCHITECTURE "x86"
+#elif defined(__x86_64__)
+#define _PR_SI_ARCHITECTURE "x86-64"
+#elif defined(__ppc__)
+#define _PR_SI_ARCHITECTURE "ppc"
+#endif
+#define PR_DLL_SUFFIX		".dylib"
+
+#define _PR_VMBASE              0x30000000
+#define _PR_STACK_VMBASE	0x50000000
+#define _MD_DEFAULT_STACK_SIZE	65536L
+#define _MD_MMAP_FLAGS          MAP_PRIVATE
+
+#undef  HAVE_STACK_GROWING_UP
+#define HAVE_DLL
+#ifdef __x86_64__
+#define USE_DLFCN
+#else
+#define USE_MACH_DYLD
+#endif
+#define _PR_HAVE_SOCKADDR_LEN  
+#define _PR_STAT_HAS_ST_ATIMESPEC
+#define _PR_HAVE_LARGE_OFF_T
+#define _PR_HAVE_SYSV_SEMAPHORES
+#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+
+#define _PR_INET6
+/*
+ * I'd prefer to use getipnodebyname and getipnodebyaddr but the
+ * getipnodebyname(3) man page on Mac OS X 10.2 says they are not
+ * thread-safe.  AI_V4MAPPED|AI_ADDRCONFIG doesn't work either.
+ */
+#define _PR_HAVE_GETHOSTBYNAME2
+#define _PR_HAVE_GETADDRINFO
+/*
+ * On Mac OS X 10.2, gethostbyaddr fails with h_errno=NO_RECOVERY
+ * if you pass an IPv4-mapped IPv6 address to it.
+ */
+#define _PR_GHBA_DISALLOW_V4MAPPED
+#ifdef XP_MACOSX
+#if !defined(MAC_OS_X_VERSION_10_3) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3
+/*
+ * socket(AF_INET6) fails with EPROTONOSUPPORT on Mac OS X 10.1.
+ * IPv6 under OS X 10.2 and below is not complete (see bug 222031).
+ */
+#define _PR_INET6_PROBE
+#endif /* DT < 10.3 */
+#if defined(MAC_OS_X_VERSION_10_2) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_2
+/* Mac OS X 10.2 has inet_ntop and inet_pton. */
+#define _PR_HAVE_INET_NTOP
+#endif /* DT >= 10.2 */
+#endif /* XP_MACOSX */
+#define _PR_IPV6_V6ONLY_PROBE
+/* The IPV6_V6ONLY socket option is not defined on Mac OS X 10.1. */
+#ifndef IPV6_V6ONLY
+#define IPV6_V6ONLY 27
+#endif
+
+#ifdef __ppc__
+#define _PR_HAVE_ATOMIC_OPS
+#define _MD_INIT_ATOMIC()
+extern PRInt32 _PR_DarwinPPC_AtomicIncrement(PRInt32 *val);
+#define _MD_ATOMIC_INCREMENT(val)   _PR_DarwinPPC_AtomicIncrement(val)
+extern PRInt32 _PR_DarwinPPC_AtomicDecrement(PRInt32 *val);
+#define _MD_ATOMIC_DECREMENT(val)   _PR_DarwinPPC_AtomicDecrement(val)
+extern PRInt32 _PR_DarwinPPC_AtomicSet(PRInt32 *val, PRInt32 newval);
+#define _MD_ATOMIC_SET(val, newval) _PR_DarwinPPC_AtomicSet(val, newval)
+extern PRInt32 _PR_DarwinPPC_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+#define _MD_ATOMIC_ADD(ptr, val)    _PR_DarwinPPC_AtomicAdd(ptr, val)
+#endif /* __ppc__ */
+
+#ifdef __i386__
+#define _PR_HAVE_ATOMIC_OPS
+#define _MD_INIT_ATOMIC()
+extern PRInt32 _PR_Darwin_x86_AtomicIncrement(PRInt32 *val);
+#define _MD_ATOMIC_INCREMENT(val)   _PR_Darwin_x86_AtomicIncrement(val)
+extern PRInt32 _PR_Darwin_x86_AtomicDecrement(PRInt32 *val);
+#define _MD_ATOMIC_DECREMENT(val)   _PR_Darwin_x86_AtomicDecrement(val)
+extern PRInt32 _PR_Darwin_x86_AtomicSet(PRInt32 *val, PRInt32 newval);
+#define _MD_ATOMIC_SET(val, newval) _PR_Darwin_x86_AtomicSet(val, newval)
+extern PRInt32 _PR_Darwin_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+#define _MD_ATOMIC_ADD(ptr, val)    _PR_Darwin_x86_AtomicAdd(ptr, val)
+#endif /* __i386__ */
+
+#ifdef __x86_64__
+#define _PR_HAVE_ATOMIC_OPS
+#define _MD_INIT_ATOMIC()
+extern PRInt32 _PR_Darwin_x86_64_AtomicIncrement(PRInt32 *val);
+#define _MD_ATOMIC_INCREMENT(val)   _PR_Darwin_x86_64_AtomicIncrement(val)
+extern PRInt32 _PR_Darwin_x86_64_AtomicDecrement(PRInt32 *val);
+#define _MD_ATOMIC_DECREMENT(val)   _PR_Darwin_x86_64_AtomicDecrement(val)
+extern PRInt32 _PR_Darwin_x86_64_AtomicSet(PRInt32 *val, PRInt32 newval);
+#define _MD_ATOMIC_SET(val, newval) _PR_Darwin_x86_64_AtomicSet(val, newval)
+extern PRInt32 _PR_Darwin_x86_64_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+#define _MD_ATOMIC_ADD(ptr, val)    _PR_Darwin_x86_64_AtomicAdd(ptr, val)
+#endif /* __x86_64__ */
+
+#define USE_SETJMP
+
+#if !defined(_PR_PTHREADS)
+
+#include <setjmp.h>
+
+#define PR_CONTEXT_TYPE	jmp_buf
+
+#define CONTEXT(_th)       ((_th)->md.context)
+#define _MD_GET_SP(_th)    (((struct sigcontext *) (_th)->md.context)->sc_onstack)
+#define PR_NUM_GCREGS	    _JBLEN
+
+/*
+** Initialize a thread context to run "_main()" when started
+*/
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status)  \
+{  \
+    *status = PR_TRUE;  \
+    if (setjmp(CONTEXT(_thread))) {  \
+        _main();  \
+    }  \
+    _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \
+}
+
+#define _MD_SWITCH_CONTEXT(_thread)  \
+    if (!setjmp(CONTEXT(_thread))) {  \
+	(_thread)->md.errcode = errno;  \
+	_PR_Schedule();  \
+    }
+
+/*
+** Restore a thread context, saved by _MD_SWITCH_CONTEXT
+*/
+#define _MD_RESTORE_CONTEXT(_thread) \
+{   \
+    errno = (_thread)->md.errcode;  \
+    _MD_SET_CURRENT_THREAD(_thread);  \
+    longjmp(CONTEXT(_thread), 1);  \
+}
+
+/* Machine-dependent (MD) data structures */
+
+struct _MDThread {
+    PR_CONTEXT_TYPE context;
+    int id;
+    int errcode;
+};
+
+struct _MDThreadStack {
+    PRInt8 notused;
+};
+
+struct _MDLock {
+    PRInt8 notused;
+};
+
+struct _MDSemaphore {
+    PRInt8 notused;
+};
+
+struct _MDCVar {
+    PRInt8 notused;
+};
+
+struct _MDSegment {
+    PRInt8 notused;
+};
+
+/*
+ * md-specific cpu structure field
+ */
+#define _PR_MD_MAX_OSFD FD_SETSIZE
+
+struct _MDCPU_Unix {
+    PRCList ioQ;
+    PRUint32 ioq_timeout;
+    PRInt32 ioq_max_osfd;
+    PRInt32 ioq_osfd_cnt;
+#ifndef _PR_USE_POLL
+    fd_set fd_read_set, fd_write_set, fd_exception_set;
+    PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD],
+				fd_exception_cnt[_PR_MD_MAX_OSFD];
+#else
+	struct pollfd *ioq_pollfds;
+	int ioq_pollfds_size;
+#endif	/* _PR_USE_POLL */
+};
+
+#define _PR_IOQ(_cpu)			((_cpu)->md.md_unix.ioQ)
+#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu))
+#define _PR_FD_READ_SET(_cpu)		((_cpu)->md.md_unix.fd_read_set)
+#define _PR_FD_READ_CNT(_cpu)		((_cpu)->md.md_unix.fd_read_cnt)
+#define _PR_FD_WRITE_SET(_cpu)		((_cpu)->md.md_unix.fd_write_set)
+#define _PR_FD_WRITE_CNT(_cpu)		((_cpu)->md.md_unix.fd_write_cnt)
+#define _PR_FD_EXCEPTION_SET(_cpu)	((_cpu)->md.md_unix.fd_exception_set)
+#define _PR_FD_EXCEPTION_CNT(_cpu)	((_cpu)->md.md_unix.fd_exception_cnt)
+#define _PR_IOQ_TIMEOUT(_cpu)		((_cpu)->md.md_unix.ioq_timeout)
+#define _PR_IOQ_MAX_OSFD(_cpu)		((_cpu)->md.md_unix.ioq_max_osfd)
+#define _PR_IOQ_OSFD_CNT(_cpu)		((_cpu)->md.md_unix.ioq_osfd_cnt)
+#define _PR_IOQ_POLLFDS(_cpu)		((_cpu)->md.md_unix.ioq_pollfds)
+#define _PR_IOQ_POLLFDS_SIZE(_cpu)	((_cpu)->md.md_unix.ioq_pollfds_size)
+
+#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu)	32
+
+struct _MDCPU {
+	struct _MDCPU_Unix md_unix;
+};
+
+#define _MD_INIT_LOCKS()
+#define _MD_NEW_LOCK(lock) PR_SUCCESS
+#define _MD_FREE_LOCK(lock)
+#define _MD_LOCK(lock)
+#define _MD_UNLOCK(lock)
+#define _MD_INIT_IO()
+#define _MD_IOQ_LOCK()
+#define _MD_IOQ_UNLOCK()
+
+extern PRStatus _MD_InitializeThread(PRThread *thread);
+
+#define _MD_INIT_RUNNING_CPU(cpu)       _MD_unix_init_running_cpu(cpu)
+#define _MD_INIT_THREAD                 _MD_InitializeThread
+#define _MD_EXIT_THREAD(thread)
+#define _MD_SUSPEND_THREAD(thread)      _MD_suspend_thread
+#define _MD_RESUME_THREAD(thread)       _MD_resume_thread
+#define _MD_CLEAN_THREAD(_thread)
+
+extern PRStatus _MD_CREATE_THREAD(
+    PRThread *thread,
+    void (*start) (void *),
+    PRThreadPriority priority,
+    PRThreadScope scope,
+    PRThreadState state,
+    PRUint32 stackSize);
+extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri);
+extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout);
+extern PRStatus _MD_WAKEUP_WAITER(PRThread *);
+extern void _MD_YIELD(void);
+
+#endif /* ! _PR_PTHREADS */
+
+#define _MD_EARLY_INIT          _MD_EarlyInit
+#define _MD_FINAL_INIT			_PR_UnixInit
+#define _MD_GET_INTERVAL        _PR_UNIX_GetInterval
+#define _MD_INTERVAL_PER_SEC    _PR_UNIX_TicksPerSecond
+
+extern void             _MD_EarlyInit(void);
+extern PRIntervalTime   _PR_UNIX_GetInterval(void);
+extern PRIntervalTime   _PR_UNIX_TicksPerSecond(void);
+
+/*
+ * We wrapped the select() call.  _MD_SELECT refers to the built-in,
+ * unwrapped version.
+ */
+#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv)
+
+/* For writev() */
+#include <sys/uio.h>
+
+#endif /* nspr_darwin_defs_h___ */
diff --git a/mozilla/nsprpub/pr/include/md/_pcos.h b/mozilla/nsprpub/pr/include/md/_pcos.h
new file mode 100644
index 0000000..59e8e2c
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_pcos.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prpcos_h___
+#define prpcos_h___
+
+#define PR_DLL_SUFFIX		".dll"
+
+#include <stdlib.h>
+
+#define DIRECTORY_SEPARATOR         '\\'
+#define DIRECTORY_SEPARATOR_STR     "\\"
+#define PATH_SEPARATOR              ';'
+
+/*
+** Routines for processing command line arguments
+*/
+PR_BEGIN_EXTERN_C
+#ifndef XP_OS2
+extern char *optarg;
+extern int optind;
+extern int getopt(int argc, char **argv, char *spec);
+#endif
+PR_END_EXTERN_C
+
+
+/*
+** Definitions of directory structures amd functions
+** These definitions are from:
+**      <dirent.h>
+*/
+#ifdef XP_OS2
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+#include <io.h>
+#include <fcntl.h>          /* O_BINARY */
+
+#ifdef OS2
+extern PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen);
+#define _MD_GETHOSTNAME _MD_OS2GetHostName
+#else
+extern PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen);
+#define _MD_GETHOSTNAME _MD_WindowsGetHostName
+extern PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen);
+#define _MD_GETSYSINFO _MD_WindowsGetSysInfo
+#endif
+
+#endif /* prpcos_h___ */
diff --git a/mozilla/nsprpub/pr/include/md/_pth.h b/mozilla/nsprpub/pr/include/md/_pth.h
new file mode 100644
index 0000000..c4cb30a
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_pth.h
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef nspr_pth_defs_h_
+#define nspr_pth_defs_h_
+
+/*
+** Appropriate definitions of entry points not used in a pthreads world
+*/
+#define _PR_MD_BLOCK_CLOCK_INTERRUPTS()
+#define _PR_MD_UNBLOCK_CLOCK_INTERRUPTS()
+#define _PR_MD_DISABLE_CLOCK_INTERRUPTS()
+#define _PR_MD_ENABLE_CLOCK_INTERRUPTS()
+
+/* In good standards fashion, the DCE threads (based on posix-4) are not
+ * quite the same as newer posix implementations.  These are mostly name
+ * changes and small differences, so macros usually do the trick
+ */
+#ifdef _PR_DCETHREADS
+#define _PT_PTHREAD_MUTEXATTR_INIT        pthread_mutexattr_create
+#define _PT_PTHREAD_MUTEXATTR_DESTROY     pthread_mutexattr_delete
+#define _PT_PTHREAD_MUTEX_INIT(m, a)      pthread_mutex_init(&(m), a)
+#define _PT_PTHREAD_MUTEX_IS_LOCKED(m)    (0 == pthread_mutex_trylock(&(m)))
+#define _PT_PTHREAD_CONDATTR_INIT         pthread_condattr_create
+#define _PT_PTHREAD_COND_INIT(m, a)       pthread_cond_init(&(m), a)
+#define _PT_PTHREAD_CONDATTR_DESTROY      pthread_condattr_delete
+
+/* Notes about differences between DCE threads and pthreads 10:
+ *   1. pthread_mutex_trylock returns 1 when it locks the mutex
+ *      0 when it does not.  The latest pthreads has a set of errno-like
+ *      return values.
+ *   2. return values from pthread_cond_timedwait are different.
+ *
+ *
+ *
+ */
+#elif defined(BSDI)
+/*
+ * Mutex and condition attributes are not supported.  The attr
+ * argument to pthread_mutex_init() and pthread_cond_init() must
+ * be passed as NULL.
+ *
+ * The memset calls in _PT_PTHREAD_MUTEX_INIT and _PT_PTHREAD_COND_INIT
+ * are to work around BSDI's using a single bit to indicate a mutex
+ * or condition variable is initialized.  This entire BSDI section
+ * will go away when BSDI releases updated threads libraries for
+ * BSD/OS 3.1 and 4.0.
+ */
+#define _PT_PTHREAD_MUTEXATTR_INIT(x)     0
+#define _PT_PTHREAD_MUTEXATTR_DESTROY(x)  /* */
+#define _PT_PTHREAD_MUTEX_INIT(m, a)      (memset(&(m), 0, sizeof(m)), \
+                                      pthread_mutex_init(&(m), NULL))
+#define _PT_PTHREAD_MUTEX_IS_LOCKED(m)    (EBUSY == pthread_mutex_trylock(&(m)))
+#define _PT_PTHREAD_CONDATTR_INIT(x)      0
+#define _PT_PTHREAD_CONDATTR_DESTROY(x)   /* */
+#define _PT_PTHREAD_COND_INIT(m, a)       (memset(&(m), 0, sizeof(m)), \
+                                      pthread_cond_init(&(m), NULL))
+#else
+#define _PT_PTHREAD_MUTEXATTR_INIT        pthread_mutexattr_init
+#define _PT_PTHREAD_MUTEXATTR_DESTROY     pthread_mutexattr_destroy
+#define _PT_PTHREAD_MUTEX_INIT(m, a)      pthread_mutex_init(&(m), &(a))
+#if defined(FREEBSD)
+#define _PT_PTHREAD_MUTEX_IS_LOCKED(m)    pt_pthread_mutex_is_locked(&(m))
+#else
+#define _PT_PTHREAD_MUTEX_IS_LOCKED(m)    (EBUSY == pthread_mutex_trylock(&(m)))
+#endif
+#define _PT_PTHREAD_CONDATTR_INIT         pthread_condattr_init
+#define _PT_PTHREAD_CONDATTR_DESTROY      pthread_condattr_destroy
+#define _PT_PTHREAD_COND_INIT(m, a)       pthread_cond_init(&(m), &(a))
+#endif
+
+/* The pthreads standard does not specify an invalid value for the
+ * pthread_t handle.  (0 is usually an invalid pthread identifier
+ * but there are exceptions, for example, DG/UX.)  These macros
+ * define a way to set the handle to or compare the handle with an
+ * invalid identifier.  These macros are not portable and may be
+ * more of a problem as we adapt to more pthreads implementations.
+ * They are only used in the PRMonitor functions.  Do not use them
+ * in new code.
+ *
+ * Unfortunately some of our clients depend on certain properties
+ * of our PRMonitor implementation, preventing us from replacing
+ * it by a portable implementation.
+ * - High-performance servers like the fact that PR_EnterMonitor
+ *   only calls PR_Lock and PR_ExitMonitor only calls PR_Unlock.
+ *   (A portable implementation would use a PRLock and a PRCondVar
+ *   to implement the recursive lock in a monitor and call both
+ *   PR_Lock and PR_Unlock in PR_EnterMonitor and PR_ExitMonitor.)
+ *   Unfortunately this forces us to read the monitor owner field
+ *   without holding a lock.
+ * - One way to make it safe to read the monitor owner field
+ *   without holding a lock is to make that field a PRThread*
+ *   (one should be able to read a pointer with a single machine
+ *   instruction).  However, PR_GetCurrentThread calls calloc if
+ *   it is called by a thread that was not created by NSPR.  The
+ *   malloc tracing tools in the Mozilla client use PRMonitor for
+ *   locking in their malloc, calloc, and free functions.  If
+ *   PR_EnterMonitor calls any of these functions, infinite
+ *   recursion ensues.
+ */
+#if defined(_PR_DCETHREADS)
+#define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) \
+	memset(&(t), 0, sizeof(pthread_t))
+#define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) \
+	(!memcmp(&(t), &pt_zero_tid, sizeof(pthread_t)))
+#define _PT_PTHREAD_COPY_THR_HANDLE(st, dt)   (dt) = (st)
+#elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(SOLARIS) \
+	|| defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
+	|| defined(HPUX) || defined(FREEBSD) \
+	|| defined(NETBSD) || defined(OPENBSD) || defined(BSDI) \
+	|| defined(NTO) || defined(DARWIN) \
+	|| defined(UNIXWARE) || defined(RISCOS)	|| defined(SYMBIAN)
+#ifdef __GNU__
+/* Hurd pthreads don't have an invalid value for pthread_t. -- rmh */
+#error Using Hurd pthreads
+#endif
+#define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t)  (t) = 0
+#define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t)  (t) == 0
+#define _PT_PTHREAD_COPY_THR_HANDLE(st, dt)   (dt) = (st)
+#else 
+#error "pthreads is not supported for this architecture"
+#endif
+
+#if defined(_PR_DCETHREADS)
+#define _PT_PTHREAD_ATTR_INIT            pthread_attr_create
+#define _PT_PTHREAD_ATTR_DESTROY         pthread_attr_delete
+#define _PT_PTHREAD_CREATE(t, a, f, r)   pthread_create(t, a, f, r) 
+#define _PT_PTHREAD_KEY_CREATE           pthread_keycreate
+#define _PT_PTHREAD_ATTR_SETSCHEDPOLICY  pthread_attr_setsched
+#define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) \
+                                     (*(s) = pthread_attr_getstacksize(*(a)), 0)
+#define _PT_PTHREAD_GETSPECIFIC(k, r) \
+		pthread_getspecific((k), (pthread_addr_t *) &(r))
+#elif defined(_PR_PTHREADS)
+#define _PT_PTHREAD_ATTR_INIT            pthread_attr_init
+#define _PT_PTHREAD_ATTR_DESTROY         pthread_attr_destroy
+#define _PT_PTHREAD_CREATE(t, a, f, r)   pthread_create(t, &a, f, r) 
+#define _PT_PTHREAD_KEY_CREATE           pthread_key_create
+#define _PT_PTHREAD_ATTR_SETSCHEDPOLICY  pthread_attr_setschedpolicy
+#define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) pthread_attr_getstacksize(a, s)
+#define _PT_PTHREAD_GETSPECIFIC(k, r)    (r) = pthread_getspecific(k)
+#else
+#error "Cannot determine pthread strategy"
+#endif
+
+#if defined(_PR_DCETHREADS)
+#define _PT_PTHREAD_EXPLICIT_SCHED      _PT_PTHREAD_DEFAULT_SCHED
+#endif
+
+/*
+ * pthread_mutex_trylock returns different values in DCE threads and
+ * pthreads.
+ */
+#if defined(_PR_DCETHREADS)
+#define PT_TRYLOCK_SUCCESS 1
+#define PT_TRYLOCK_BUSY    0
+#else
+#define PT_TRYLOCK_SUCCESS 0
+#define PT_TRYLOCK_BUSY    EBUSY
+#endif
+
+/*
+ * These platforms don't have sigtimedwait()
+ */
+#if (defined(AIX) && !defined(AIX4_3_PLUS)) \
+	|| defined(LINUX) || defined(__GNU__)|| defined(__GLIBC__) \
+	|| defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
+	|| defined(BSDI) || defined(UNIXWARE) \
+	|| defined(DARWIN) || defined(SYMBIAN)
+#define PT_NO_SIGTIMEDWAIT
+#endif
+
+#if defined(OSF1)
+#define PT_PRIO_MIN            PRI_OTHER_MIN
+#define PT_PRIO_MAX            PRI_OTHER_MAX
+#elif defined(IRIX)
+#include <sys/sched.h>
+#define PT_PRIO_MIN            PX_PRIO_MIN
+#define PT_PRIO_MAX            PX_PRIO_MAX
+#elif defined(AIX)
+#include <sys/priv.h>
+#include <sys/sched.h>
+#ifndef PTHREAD_CREATE_JOINABLE
+#define PTHREAD_CREATE_JOINABLE     PTHREAD_CREATE_UNDETACHED
+#endif
+#define PT_PRIO_MIN            DEFAULT_PRIO
+#define PT_PRIO_MAX            DEFAULT_PRIO
+#elif defined(HPUX)
+
+#if defined(_PR_DCETHREADS)
+#define PT_PRIO_MIN            PRI_OTHER_MIN
+#define PT_PRIO_MAX            PRI_OTHER_MAX
+#else /* defined(_PR_DCETHREADS) */
+#include <sys/sched.h>
+#define PT_PRIO_MIN            sched_get_priority_min(SCHED_OTHER)
+#define PT_PRIO_MAX            sched_get_priority_max(SCHED_OTHER)
+#endif /* defined(_PR_DCETHREADS) */
+
+#elif defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
+	|| defined(FREEBSD) || defined(SYMBIAN)
+#define PT_PRIO_MIN            sched_get_priority_min(SCHED_OTHER)
+#define PT_PRIO_MAX            sched_get_priority_max(SCHED_OTHER)
+#elif defined(NTO)
+/*
+ * Neutrino has functions that return the priority range but
+ * they return invalid numbers, so I just hard coded these here
+ * for now.  Jerry.Kirk@Nexarecorp.com
+ */
+#define PT_PRIO_MIN            0
+#define PT_PRIO_MAX            30
+#elif defined(SOLARIS)
+/*
+ * Solaris doesn't seem to have macros for the min/max priorities.
+ * The range of 0-127 is mentioned in the pthread_setschedparam(3T)
+ * man pages, and pthread_setschedparam indeed allows 0-127.  However,
+ * pthread_attr_setschedparam does not allow 0; it allows 1-127.
+ */
+#define PT_PRIO_MIN            1
+#define PT_PRIO_MAX            127
+#elif defined(OPENBSD)
+#define PT_PRIO_MIN            0
+#define PT_PRIO_MAX            31
+#elif defined(NETBSD) \
+	|| defined(BSDI) || defined(DARWIN) || defined(UNIXWARE) \
+	|| defined(RISCOS) /* XXX */
+#define PT_PRIO_MIN            0
+#define PT_PRIO_MAX            126
+#else
+#error "pthreads is not supported for this architecture"
+#endif
+
+/*
+ * The _PT_PTHREAD_YIELD function is called from a signal handler.
+ * Needed for garbage collection -- Look at PR_Suspend/PR_Resume
+ * implementation.
+ */
+#if defined(_PR_DCETHREADS)
+#define _PT_PTHREAD_YIELD()            	pthread_yield()
+#elif defined(OSF1)
+/*
+ * sched_yield can't be called from a signal handler.  Must use
+ * the _np version.
+ */
+#define _PT_PTHREAD_YIELD()            	pthread_yield_np()
+#elif defined(AIX)
+extern int (*_PT_aix_yield_fcn)();
+#define _PT_PTHREAD_YIELD()			(*_PT_aix_yield_fcn)()
+#elif defined(IRIX)
+#include <time.h>
+#define _PT_PTHREAD_YIELD() \
+    PR_BEGIN_MACRO               				\
+		struct timespec onemillisec = {0};		\
+		onemillisec.tv_nsec = 1000000L;			\
+        nanosleep(&onemillisec,NULL);			\
+    PR_END_MACRO
+#elif defined(HPUX) || defined(SOLARIS) \
+	|| defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
+	|| defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
+	|| defined(BSDI) || defined(NTO) || defined(DARWIN) \
+	|| defined(UNIXWARE) || defined(RISCOS) || defined(SYMBIAN)
+#define _PT_PTHREAD_YIELD()            	sched_yield()
+#else
+#error "Need to define _PT_PTHREAD_YIELD for this platform"
+#endif
+
+#endif /* nspr_pth_defs_h_ */
diff --git a/mozilla/nsprpub/pr/include/md/_unix_errors.h b/mozilla/nsprpub/pr/include/md/_unix_errors.h
new file mode 100644
index 0000000..a44cbb3
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_unix_errors.h
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prunixerrors_h___
+#define prunixerrors_h___
+
+#include <unistd.h>
+#include <stddef.h>
+
+PR_BEGIN_EXTERN_C
+
+extern void _MD_unix_map_default_error(int err);
+#define	_PR_MD_MAP_DEFAULT_ERROR	_MD_unix_map_default_error
+
+extern void _MD_unix_map_opendir_error(int err);
+#define	_PR_MD_MAP_OPENDIR_ERROR	_MD_unix_map_opendir_error
+
+extern void _MD_unix_map_closedir_error(int err);
+#define	_PR_MD_MAP_CLOSEDIR_ERROR	_MD_unix_map_closedir_error
+
+extern void _MD_unix_readdir_error(int err);
+#define	_PR_MD_MAP_READDIR_ERROR	_MD_unix_readdir_error
+
+extern void _MD_unix_map_unlink_error(int err);
+#define	_PR_MD_MAP_UNLINK_ERROR	_MD_unix_map_unlink_error
+
+extern void _MD_unix_map_stat_error(int err);
+#define	_PR_MD_MAP_STAT_ERROR	_MD_unix_map_stat_error
+
+extern void _MD_unix_map_fstat_error(int err);
+#define	_PR_MD_MAP_FSTAT_ERROR	_MD_unix_map_fstat_error
+
+extern void _MD_unix_map_rename_error(int err);
+#define	_PR_MD_MAP_RENAME_ERROR	_MD_unix_map_rename_error
+
+extern void _MD_unix_map_access_error(int err);
+#define	_PR_MD_MAP_ACCESS_ERROR	_MD_unix_map_access_error
+
+extern void _MD_unix_map_mkdir_error(int err);
+#define	_PR_MD_MAP_MKDIR_ERROR	_MD_unix_map_mkdir_error
+
+extern void _MD_unix_map_rmdir_error(int err);
+#define	_PR_MD_MAP_RMDIR_ERROR	_MD_unix_map_rmdir_error
+
+extern void _MD_unix_map_read_error(int err);
+#define	_PR_MD_MAP_READ_ERROR	_MD_unix_map_read_error
+
+extern void _MD_unix_map_write_error(int err);
+#define	_PR_MD_MAP_WRITE_ERROR	_MD_unix_map_write_error
+
+extern void _MD_unix_map_lseek_error(int err);
+#define	_PR_MD_MAP_LSEEK_ERROR	_MD_unix_map_lseek_error
+
+extern void _MD_unix_map_fsync_error(int err);
+#define	_PR_MD_MAP_FSYNC_ERROR	_MD_unix_map_fsync_error
+
+extern void _MD_unix_map_close_error(int err);
+#define	_PR_MD_MAP_CLOSE_ERROR	_MD_unix_map_close_error
+
+extern void _MD_unix_map_socket_error(int err);
+#define	_PR_MD_MAP_SOCKET_ERROR	_MD_unix_map_socket_error
+
+extern void _MD_unix_map_socketavailable_error(int err);
+#define	_PR_MD_MAP_SOCKETAVAILABLE_ERROR	_MD_unix_map_socketavailable_error
+
+extern void _MD_unix_map_recv_error(int err);
+#define	_PR_MD_MAP_RECV_ERROR	_MD_unix_map_recv_error
+
+extern void _MD_unix_map_recvfrom_error(int err);
+#define	_PR_MD_MAP_RECVFROM_ERROR	_MD_unix_map_recvfrom_error
+
+extern void _MD_unix_map_send_error(int err);
+#define	_PR_MD_MAP_SEND_ERROR	_MD_unix_map_send_error
+
+extern void _MD_unix_map_sendto_error(int err);
+#define	_PR_MD_MAP_SENDTO_ERROR	_MD_unix_map_sendto_error
+
+extern void _MD_unix_map_writev_error(int err);
+#define	_PR_MD_MAP_WRITEV_ERROR	_MD_unix_map_writev_error
+
+extern void _MD_unix_map_accept_error(int err);
+#define	_PR_MD_MAP_ACCEPT_ERROR	_MD_unix_map_accept_error
+
+extern void _MD_unix_map_connect_error(int err);
+#define	_PR_MD_MAP_CONNECT_ERROR	_MD_unix_map_connect_error
+
+extern void _MD_unix_map_bind_error(int err);
+#define	_PR_MD_MAP_BIND_ERROR	_MD_unix_map_bind_error
+
+extern void _MD_unix_map_listen_error(int err);
+#define	_PR_MD_MAP_LISTEN_ERROR	_MD_unix_map_listen_error
+
+extern void _MD_unix_map_shutdown_error(int err);
+#define	_PR_MD_MAP_SHUTDOWN_ERROR	_MD_unix_map_shutdown_error
+
+extern void _MD_unix_map_socketpair_error(int err);
+#define	_PR_MD_MAP_SOCKETPAIR_ERROR	_MD_unix_map_socketpair_error
+
+extern void _MD_unix_map_getsockname_error(int err);
+#define	_PR_MD_MAP_GETSOCKNAME_ERROR	_MD_unix_map_getsockname_error
+
+extern void _MD_unix_map_getpeername_error(int err);
+#define	_PR_MD_MAP_GETPEERNAME_ERROR	_MD_unix_map_getpeername_error
+
+extern void _MD_unix_map_getsockopt_error(int err);
+#define	_PR_MD_MAP_GETSOCKOPT_ERROR	_MD_unix_map_getsockopt_error
+
+extern void _MD_unix_map_setsockopt_error(int err);
+#define	_PR_MD_MAP_SETSOCKOPT_ERROR	_MD_unix_map_setsockopt_error
+
+extern void _MD_unix_map_open_error(int err);
+#define	_PR_MD_MAP_OPEN_ERROR	_MD_unix_map_open_error
+
+extern void _MD_unix_map_mmap_error(int err);
+#define	_PR_MD_MAP_MMAP_ERROR	_MD_unix_map_mmap_error
+
+extern void _MD_unix_map_gethostname_error(int err);
+#define	_PR_MD_MAP_GETHOSTNAME_ERROR	_MD_unix_map_gethostname_error
+
+extern void _MD_unix_map_select_error(int err);
+#define	_PR_MD_MAP_SELECT_ERROR	_MD_unix_map_select_error
+
+extern void _MD_unix_map_poll_error(int err);
+#define _PR_MD_MAP_POLL_ERROR _MD_unix_map_poll_error
+
+extern void _MD_unix_map_poll_revents_error(int err);
+#define _PR_MD_MAP_POLL_REVENTS_ERROR _MD_unix_map_poll_revents_error
+
+extern void _MD_unix_map_flock_error(int err);
+#define	_PR_MD_MAP_FLOCK_ERROR	_MD_unix_map_flock_error
+
+extern void _MD_unix_map_lockf_error(int err);
+#define	_PR_MD_MAP_LOCKF_ERROR	_MD_unix_map_lockf_error
+
+PR_END_EXTERN_C
+
+#endif /* prunixerrors_h___ */
diff --git a/mozilla/nsprpub/pr/include/md/_unixos.h b/mozilla/nsprpub/pr/include/md/_unixos.h
new file mode 100644
index 0000000..bc31f42
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_unixos.h
@@ -0,0 +1,634 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prunixos_h___
+#define prunixos_h___
+
+/*
+ * If FD_SETSIZE is not defined on the command line, set the default value
+ * before include select.h
+ */
+/*
+ * Linux: FD_SETSIZE is defined in /usr/include/sys/select.h and should
+ * not be redefined.
+ */
+#if !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__) \
+    && !defined(DARWIN) && !defined(NEXTSTEP)
+#ifndef FD_SETSIZE
+#define FD_SETSIZE  4096
+#endif
+#endif
+
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "prio.h"
+#include "prmem.h"
+#include "prclist.h"
+
+/*
+ * For select(), fd_set, and struct timeval.
+ *
+ * In The Single UNIX(R) Specification, Version 2,
+ * the header file for select() is <sys/time.h>.
+ * In Version 3, the header file for select() is
+ * changed to <sys/select.h>.
+ *
+ * fd_set is defined in <sys/types.h>.  Usually
+ * <sys/time.h> includes <sys/types.h>, but on some
+ * older systems <sys/time.h> does not include
+ * <sys/types.h>, so we include it explicitly.
+ */
+#include <sys/time.h>
+#include <sys/types.h>
+#if defined(AIX) || defined(SYMBIAN)
+#include <sys/select.h>
+#endif
+
+#ifndef SYMBIAN
+#define HAVE_NETINET_TCP_H
+#endif
+
+#define _PR_HAVE_O_APPEND
+
+#define PR_DIRECTORY_SEPARATOR		'/'
+#define PR_DIRECTORY_SEPARATOR_STR	"/"
+#define PR_PATH_SEPARATOR		':'
+#define PR_PATH_SEPARATOR_STR		":"
+typedef int (*FARPROC)();
+
+/*
+ * intervals at which GLOBAL threads wakeup to check for pending interrupt
+ */
+#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
+extern PRIntervalTime intr_timeout_ticks;
+
+/*
+ * The bit flags for the in_flags and out_flags fields
+ * of _PR_UnixPollDesc
+ */
+#ifdef _PR_USE_POLL
+#define _PR_UNIX_POLL_READ    POLLIN
+#define _PR_UNIX_POLL_WRITE   POLLOUT
+#define _PR_UNIX_POLL_EXCEPT  POLLPRI
+#define _PR_UNIX_POLL_ERR     POLLERR
+#define _PR_UNIX_POLL_NVAL    POLLNVAL
+#define _PR_UNIX_POLL_HUP     POLLHUP
+#else /* _PR_USE_POLL */
+#define _PR_UNIX_POLL_READ    0x1
+#define _PR_UNIX_POLL_WRITE   0x2
+#define _PR_UNIX_POLL_EXCEPT  0x4
+#define _PR_UNIX_POLL_ERR     0x8
+#define _PR_UNIX_POLL_NVAL    0x10
+#define _PR_UNIX_POLL_HUP     0x20
+#endif /* _PR_USE_POLL */
+
+typedef struct _PRUnixPollDesc {
+	PRInt32 osfd;
+	PRInt16 in_flags;
+	PRInt16 out_flags;
+} _PRUnixPollDesc;
+
+typedef struct PRPollQueue {
+    PRCList links;        /* for linking PRPollQueue's together */
+    _PRUnixPollDesc *pds;        /* array of poll descriptors */
+    PRUintn npds;            /* length of the array */
+    PRPackedBool on_ioq;    /* is this on the async i/o work q? */
+    PRIntervalTime timeout;        /* timeout, in ticks */
+    struct PRThread *thr;
+} PRPollQueue;
+
+#define _PR_POLLQUEUE_PTR(_qp) \
+    ((PRPollQueue*) ((char*) (_qp) - offsetof(PRPollQueue,links)))
+
+
+extern PRInt32 _PR_WaitForMultipleFDs(
+    _PRUnixPollDesc *unixpds,
+    PRInt32 pdcnt,
+    PRIntervalTime timeout);
+extern void _PR_Unblock_IO_Wait(struct PRThread *thr);
+
+#if defined(_PR_LOCAL_THREADS_ONLY) || defined(_PR_GLOBAL_THREADS_ONLY)
+#define _MD_CHECK_FOR_EXIT()
+#endif
+
+extern fd_set _pr_md_read_set, _pr_md_write_set, _pr_md_exception_set;
+extern PRInt16 _pr_md_read_cnt[], _pr_md_write_cnt[], _pr_md_exception_cnt[];
+extern PRInt32 _pr_md_ioq_max_osfd;
+extern PRUint32 _pr_md_ioq_timeout;
+
+struct _MDFileDesc {
+    int osfd;
+#if defined(LINUX) && defined(_PR_PTHREADS)
+    int tcp_nodelay;  /* used by pt_LinuxSendFile */
+#endif
+};
+
+struct _MDDir {
+	DIR *d;
+};
+
+struct _PRCPU;
+extern void _MD_unix_init_running_cpu(struct _PRCPU *cpu);
+
+/*
+** Make a redzone at both ends of the stack segment. Disallow access
+** to those pages of memory. It's ok if the mprotect call's don't
+** work - it just means that we don't really have a functional
+** redzone.
+*/
+#include <sys/mman.h>
+#ifndef PROT_NONE
+#define PROT_NONE 0x0
+#endif
+
+#if defined(DEBUG) && !defined(DARWIN) && !defined(NEXTSTEP)
+#if !defined(SOLARIS)	
+#include <string.h>  /* for memset() */
+#define _MD_INIT_STACK(ts,REDZONE)					\
+    PR_BEGIN_MACRO                 					\
+	(void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_NONE);	\
+	(void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\
+			REDZONE, PROT_NONE);				\
+    /*									\
+    ** Fill stack memory with something that turns into an illegal	\
+    ** pointer value. This will sometimes find runtime references to	\
+    ** uninitialized pointers. We don't do this for solaris because we	\
+    ** can use purify instead.						\
+    */									\
+    if (_pr_debugStacks) {						\
+	memset(ts->allocBase + REDZONE, 0xf7, ts->stackSize);		\
+    }									\
+    PR_END_MACRO
+#else	/* !SOLARIS	*/
+#define _MD_INIT_STACK(ts,REDZONE)					\
+    PR_BEGIN_MACRO                 					\
+	(void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_NONE);	\
+	(void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\
+			REDZONE, PROT_NONE);				\
+    PR_END_MACRO
+#endif	/* !SOLARIS	*/
+
+/*
+ * _MD_CLEAR_STACK
+ *	Allow access to the redzone pages; the access was turned off in
+ *	_MD_INIT_STACK.
+ */
+#define _MD_CLEAR_STACK(ts)						\
+    PR_BEGIN_MACRO                 					\
+	(void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_READ|PROT_WRITE);\
+	(void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\
+			REDZONE, PROT_READ|PROT_WRITE);			\
+    PR_END_MACRO
+
+#else	/* DEBUG */
+
+#define _MD_INIT_STACK(ts,REDZONE)
+#define _MD_CLEAR_STACK(ts)
+
+#endif	/* DEBUG */
+
+#if !defined(SOLARIS) 
+
+#define PR_SET_INTSOFF(newval)
+
+#endif
+
+/************************************************************************/
+
+extern void _PR_UnixInit(void);
+
+/************************************************************************/
+
+struct _MDProcess {
+    pid_t pid;
+};
+
+struct PRProcess;
+struct PRProcessAttr;
+
+/* Create a new process (fork() + exec()) */
+#define _MD_CREATE_PROCESS _MD_CreateUnixProcess
+extern struct PRProcess * _MD_CreateUnixProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const struct PRProcessAttr *attr
+);
+
+#define _MD_DETACH_PROCESS _MD_DetachUnixProcess
+extern PRStatus _MD_DetachUnixProcess(struct PRProcess *process);
+
+/* Wait for a child process to terminate */
+#define _MD_WAIT_PROCESS _MD_WaitUnixProcess
+extern PRStatus _MD_WaitUnixProcess(struct PRProcess *process,
+    PRInt32 *exitCode);
+
+#define _MD_KILL_PROCESS _MD_KillUnixProcess
+extern PRStatus _MD_KillUnixProcess(struct PRProcess *process);
+
+/************************************************************************/
+
+extern void _MD_EnableClockInterrupts(void);
+extern void _MD_DisableClockInterrupts(void);
+
+#define _MD_START_INTERRUPTS			_MD_StartInterrupts
+#define _MD_STOP_INTERRUPTS				_MD_StopInterrupts
+#define _MD_DISABLE_CLOCK_INTERRUPTS	_MD_DisableClockInterrupts
+#define _MD_ENABLE_CLOCK_INTERRUPTS		_MD_EnableClockInterrupts
+#define _MD_BLOCK_CLOCK_INTERRUPTS		_MD_BlockClockInterrupts
+#define _MD_UNBLOCK_CLOCK_INTERRUPTS	_MD_UnblockClockInterrupts
+
+/************************************************************************/
+
+extern void		_MD_InitCPUS(void);
+#define _MD_INIT_CPUS           _MD_InitCPUS
+
+extern void		_MD_Wakeup_CPUs(void);
+#define _MD_WAKEUP_CPUS _MD_Wakeup_CPUs
+
+#define _MD_PAUSE_CPU			_MD_PauseCPU
+
+#if defined(_PR_LOCAL_THREADS_ONLY) || defined(_PR_GLOBAL_THREADS_ONLY)
+#define _MD_CLEANUP_BEFORE_EXIT()
+#endif
+
+#ifndef IRIX
+#define _MD_EXIT(status)		_exit(status)
+#endif
+
+/************************************************************************/
+
+#define _MD_GET_ENV				getenv
+#define _MD_PUT_ENV				putenv
+
+/************************************************************************/
+
+#define _MD_INIT_FILEDESC(fd)
+
+extern void		_MD_MakeNonblock(PRFileDesc *fd);
+#define _MD_MAKE_NONBLOCK			_MD_MakeNonblock		
+
+/************************************************************************/
+
+#if !defined(_PR_PTHREADS)
+
+extern void		_MD_InitSegs(void);
+extern PRStatus	_MD_AllocSegment(PRSegment *seg, PRUint32 size,
+				void *vaddr);
+extern void		_MD_FreeSegment(PRSegment *seg);
+
+#define _MD_INIT_SEGS			_MD_InitSegs
+#define _MD_ALLOC_SEGMENT		_MD_AllocSegment
+#define _MD_FREE_SEGMENT		_MD_FreeSegment
+
+#endif /* !defined(_PR_PTHREADS) */
+
+/************************************************************************/
+
+#if !defined(HPUX_LW_TIMER)
+#define _MD_INTERVAL_INIT()
+#endif
+#define _MD_INTERVAL_PER_MILLISEC()	(_PR_MD_INTERVAL_PER_SEC() / 1000)
+#define _MD_INTERVAL_PER_MICROSEC()	(_PR_MD_INTERVAL_PER_SEC() / 1000000)
+
+/************************************************************************/
+
+#define _MD_ERRNO()             	(errno)
+#define _MD_GET_SOCKET_ERROR()		(errno)
+
+/************************************************************************/
+
+extern PRInt32 _MD_AvailableSocket(PRInt32 osfd);
+
+extern void _MD_StartInterrupts(void);
+extern void _MD_StopInterrupts(void);
+extern void _MD_DisableClockInterrupts(void);
+extern void _MD_BlockClockInterrupts(void);
+extern void _MD_UnblockClockInterrupts(void);
+extern void _MD_PauseCPU(PRIntervalTime timeout);
+
+extern PRStatus _MD_open_dir(struct _MDDir *, const char *);
+extern PRInt32  _MD_close_dir(struct _MDDir *);
+extern char *   _MD_read_dir(struct _MDDir *, PRIntn);
+extern PRInt32  _MD_open(const char *name, PRIntn osflags, PRIntn mode);
+extern PRInt32	_MD_delete(const char *name);
+extern PRInt32	_MD_getfileinfo(const char *fn, PRFileInfo *info);
+extern PRInt32  _MD_getfileinfo64(const char *fn, PRFileInfo64 *info);
+extern PRInt32  _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info);
+extern PRInt32  _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info);
+extern PRInt32	_MD_rename(const char *from, const char *to);
+extern PRInt32	_MD_access(const char *name, PRAccessHow how);
+extern PRInt32	_MD_mkdir(const char *name, PRIntn mode);
+extern PRInt32	_MD_rmdir(const char *name);
+extern PRInt32	_MD_accept_read(PRInt32 sock, PRInt32 *newSock,
+				PRNetAddr **raddr, void *buf, PRInt32 amount);
+extern PRInt32 	_PR_UnixSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+			PRTransmitFileFlags flags, PRIntervalTime timeout);
+
+extern PRStatus _MD_LockFile(PRInt32 osfd);
+extern PRStatus _MD_TLockFile(PRInt32 osfd);
+extern PRStatus _MD_UnlockFile(PRInt32 osfd);
+
+#define _MD_OPEN_DIR(dir, name)		    _MD_open_dir(dir, name)
+#define _MD_CLOSE_DIR(dir)		        _MD_close_dir(dir)
+#define _MD_READ_DIR(dir, flags)	    _MD_read_dir(dir, flags)
+#define _MD_OPEN(name, osflags, mode)	_MD_open(name, osflags, mode)
+#define _MD_OPEN_FILE(name, osflags, mode)	_MD_open(name, osflags, mode)
+extern PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount);
+#define _MD_READ(fd,buf,amount)		    _MD_read(fd,buf,amount)
+extern PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount);
+#define _MD_WRITE(fd,buf,amount)	    _MD_write(fd,buf,amount)
+#define _MD_DELETE(name)		        _MD_delete(name)
+#define _MD_GETFILEINFO(fn, info)	    _MD_getfileinfo(fn, info)
+#define _MD_GETFILEINFO64(fn, info)	    _MD_getfileinfo64(fn, info)
+#define _MD_GETOPENFILEINFO(fd, info)	_MD_getopenfileinfo(fd, info)
+#define _MD_GETOPENFILEINFO64(fd, info)	_MD_getopenfileinfo64(fd, info)
+#define _MD_RENAME(from, to)		    _MD_rename(from, to)
+#define _MD_ACCESS(name, how)		    _MD_access(name, how)
+#define _MD_MKDIR(name, mode)		    _MD_mkdir(name, mode)
+#define _MD_MAKE_DIR(name, mode)		_MD_mkdir(name, mode)
+#define _MD_RMDIR(name)			        _MD_rmdir(name)
+#define _MD_ACCEPT_READ(sock, newSock, raddr, buf, amount)	_MD_accept_read(sock, newSock, raddr, buf, amount)
+
+#define _MD_LOCKFILE _MD_LockFile
+#define _MD_TLOCKFILE _MD_TLockFile
+#define _MD_UNLOCKFILE _MD_UnlockFile
+
+
+extern PRInt32		_MD_socket(int af, int type, int flags);
+#define _MD_SOCKET	_MD_socket
+extern PRInt32		_MD_connect(PRFileDesc *fd, const PRNetAddr *addr,
+								PRUint32 addrlen, PRIntervalTime timeout);
+#define _MD_CONNECT	_MD_connect
+extern PRInt32		_MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen,
+													PRIntervalTime timeout);
+#define _MD_ACCEPT	_MD_accept
+extern PRInt32		_MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen);
+#define _MD_BIND	_MD_bind
+extern PRInt32		_MD_listen(PRFileDesc *fd, PRIntn backlog);
+#define _MD_LISTEN	_MD_listen
+extern PRInt32		_MD_shutdown(PRFileDesc *fd, PRIntn how);
+#define _MD_SHUTDOWN	_MD_shutdown
+
+extern PRInt32		_MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, 
+                               PRIntn flags, PRIntervalTime timeout);
+#define _MD_RECV	_MD_recv
+extern PRInt32		_MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+									PRIntn flags, PRIntervalTime timeout);
+#define _MD_SEND	_MD_send
+extern PRInt32		_MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+						PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
+											PRIntervalTime timeout);
+#define _MD_RECVFROM	_MD_recvfrom
+extern PRInt32 _MD_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
+							PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen,
+												PRIntervalTime timeout);
+#define _MD_SENDTO	_MD_sendto
+extern PRInt32		_MD_writev(PRFileDesc *fd, const struct PRIOVec *iov,
+								PRInt32 iov_size, PRIntervalTime timeout);
+#define _MD_WRITEV	_MD_writev
+
+extern PRInt32		_MD_socketavailable(PRFileDesc *fd);
+#define	_MD_SOCKETAVAILABLE		_MD_socketavailable
+extern PRInt64		_MD_socketavailable64(PRFileDesc *fd);
+#define	_MD_SOCKETAVAILABLE64		_MD_socketavailable64
+
+#define	_MD_PIPEAVAILABLE		_MD_socketavailable
+
+extern PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds,
+												PRIntervalTime timeout);
+#define _MD_PR_POLL		_MD_pr_poll
+
+extern PRInt32		_MD_close(PRInt32 osfd);
+#define _MD_CLOSE_FILE	_MD_close
+extern PRInt32		_MD_lseek(PRFileDesc*, PRInt32, PRSeekWhence);
+#define _MD_LSEEK	_MD_lseek
+extern PRInt64		_MD_lseek64(PRFileDesc*, PRInt64, PRSeekWhence);
+#define _MD_LSEEK64	_MD_lseek64
+extern PRInt32		_MD_fsync(PRFileDesc *fd);
+#define _MD_FSYNC	_MD_fsync
+
+extern PRInt32 _MD_socketpair(int af, int type, int flags, PRInt32 *osfd);
+#define _MD_SOCKETPAIR		_MD_socketpair
+
+#define _MD_CLOSE_SOCKET	_MD_close
+
+#ifndef NO_NSPR_10_SUPPORT
+#define _MD_STAT	stat
+#endif
+
+extern PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr,
+											PRUint32 *addrlen);
+#define _MD_GETPEERNAME _MD_getpeername
+extern PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr,
+											PRUint32 *addrlen);
+#define _MD_GETSOCKNAME _MD_getsockname
+
+extern PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level,
+						PRInt32 optname, char* optval, PRInt32* optlen);
+#define _MD_GETSOCKOPT		_MD_getsockopt
+extern PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level,
+					PRInt32 optname, const char* optval, PRInt32 optlen);
+#define _MD_SETSOCKOPT		_MD_setsockopt
+
+extern PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable);
+#define _MD_SET_FD_INHERITABLE _MD_set_fd_inheritable
+
+extern void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported);
+#define _MD_INIT_FD_INHERITABLE _MD_init_fd_inheritable
+
+extern void _MD_query_fd_inheritable(PRFileDesc *fd);
+#define _MD_QUERY_FD_INHERITABLE _MD_query_fd_inheritable
+
+extern PRStatus _MD_gethostname(char *name, PRUint32 namelen);
+#define _MD_GETHOSTNAME		_MD_gethostname
+
+extern PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen);
+#define _MD_GETSYSINFO		_MD_getsysinfo
+
+extern int _MD_unix_get_nonblocking_connect_error(int osfd);
+
+/* Memory-mapped files */
+
+struct _MDFileMap {
+    PRIntn prot;
+    PRIntn flags;
+    PRBool isAnonFM; /* when true, PR_CloseFileMap() must close the related fd */
+};
+
+extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size);
+#define _MD_CREATE_FILE_MAP _MD_CreateFileMap
+
+#define _MD_GET_MEM_MAP_ALIGNMENT() PR_GetPageSize()
+
+extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset,
+        PRUint32 len);
+#define _MD_MEM_MAP _MD_MemMap
+
+extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size);
+#define _MD_MEM_UNMAP _MD_MemUnmap
+
+extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap);
+#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap
+
+/*
+ * The standard (XPG4) gettimeofday() (from BSD) takes two arguments.
+ * On some SVR4 derivatives, gettimeofday() takes only one argument.
+ * The GETTIMEOFDAY macro is intended to hide this difference.
+ */
+#ifdef HAVE_SVID_GETTOD
+#define GETTIMEOFDAY(tp) gettimeofday(tp)
+#else
+#define GETTIMEOFDAY(tp) gettimeofday((tp), NULL)
+#endif
+
+#if defined(_PR_PTHREADS) && !defined(_PR_POLL_AVAILABLE)
+#define _PR_NEED_FAKE_POLL
+#endif
+
+#if defined(_PR_NEED_FAKE_POLL)
+
+/*
+ * Some platforms don't have poll(), but our pthreads code calls poll().
+ * As a temporary measure, I implemented a fake poll() using select().
+ * Here are the struct and macro definitions copied from sys/poll.h
+ * on Solaris 2.5.
+ */
+
+struct pollfd {
+    int fd;
+    short events;
+    short revents;
+};
+
+/* poll events */
+
+#define	POLLIN		0x0001		/* fd is readable */
+#define	POLLPRI		0x0002		/* high priority info at fd */
+#define	POLLOUT		0x0004		/* fd is writeable (won't block) */
+#define	POLLRDNORM	0x0040		/* normal data is readable */
+#define	POLLWRNORM	POLLOUT
+#define	POLLRDBAND	0x0080		/* out-of-band data is readable */
+#define	POLLWRBAND	0x0100		/* out-of-band data is writeable */
+
+#define	POLLNORM	POLLRDNORM
+
+#define	POLLERR		0x0008		/* fd has error condition */
+#define	POLLHUP		0x0010		/* fd has been hung up on */
+#define	POLLNVAL	0x0020		/* invalid pollfd entry */
+
+extern int poll(struct pollfd *, unsigned long, int);
+
+#endif /* _PR_NEED_FAKE_POLL */
+
+/*
+** A vector of the UNIX I/O calls we use. These are here to smooth over
+** the rough edges needed for large files. All of NSPR's implmentaions
+** go through this vector using syntax of the form
+**      result = _md_iovector.xxx64(args);
+*/
+
+#if defined(SOLARIS2_5)
+/*
+** Special case: Solaris 2.5.1
+** Solaris starts to have 64-bit file I/O in 2.6.  We build on Solaris
+** 2.5.1 so that we can use the same binaries on both Solaris 2.5.1 and
+** 2.6.  At run time, we detect whether 64-bit file I/O is available by
+** looking up the 64-bit file function symbols in libc.  At build time,
+** we need to define the 64-bit file I/O datatypes that are compatible
+** with their definitions on Solaris 2.6.
+*/
+typedef PRInt64 off64_t;
+typedef PRUint64 ino64_t;
+typedef PRInt64 blkcnt64_t;
+struct stat64 {
+    dev_t st_dev;
+    long st_pad1[3];
+    ino64_t st_ino;
+    mode_t st_mode;
+    nlink_t st_nlink;
+    uid_t st_uid;
+    gid_t st_gid;
+    dev_t st_rdev;
+    long t_pad2[2];
+    off64_t st_size;
+    timestruc_t st_atim;
+    timestruc_t st_mtim;
+    timestruc_t st_ctim;
+    long st_blksize;
+    blkcnt64_t st_blocks;
+    char st_fstype[_ST_FSTYPSZ];
+    long st_pad4[8];
+};
+typedef struct stat64 _MDStat64;
+typedef off64_t _MDOff64_t;
+
+#elif defined(_PR_HAVE_OFF64_T)
+typedef struct stat64 _MDStat64;
+typedef off64_t _MDOff64_t;
+#elif defined(_PR_HAVE_LARGE_OFF_T)
+typedef struct stat _MDStat64;
+typedef off_t _MDOff64_t;
+#elif defined(_PR_NO_LARGE_FILES)
+typedef struct stat _MDStat64;
+typedef PRInt64 _MDOff64_t;
+#else
+#error "I don't know yet"
+#endif
+
+typedef PRIntn (*_MD_Fstat64)(PRIntn osfd, _MDStat64 *buf);
+typedef PRIntn (*_MD_Open64)(const char *path, int oflag, ...);
+typedef PRIntn (*_MD_Stat64)(const char *path, _MDStat64 *buf);
+typedef _MDOff64_t (*_MD_Lseek64)(PRIntn osfd, _MDOff64_t, PRIntn whence);
+typedef void* (*_MD_Mmap64)(
+    void *addr, PRSize len, PRIntn prot, PRIntn flags,
+    PRIntn fildes, _MDOff64_t offset);
+struct _MD_IOVector
+{
+    _MD_Open64 _open64;
+    _MD_Mmap64 _mmap64;
+    _MD_Stat64 _stat64;
+    _MD_Fstat64 _fstat64;
+    _MD_Lseek64 _lseek64;
+};
+extern struct _MD_IOVector _md_iovector;
+
+#endif /* prunixos_h___ */
diff --git a/mozilla/nsprpub/pr/include/md/_win32_errors.h b/mozilla/nsprpub/pr/include/md/_win32_errors.h
new file mode 100644
index 0000000..d5d8b71
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_win32_errors.h
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef nspr_win32_errors_h___
+#define nspr_win32_errors_h___
+
+#include <windows.h>
+#include <winsock.h>
+#include <errno.h>
+
+
+extern void _MD_win32_map_default_error(PRInt32 err);
+#define _PR_MD_MAP_DEFAULT_ERROR	_MD_win32_map_default_error
+
+extern void _MD_win32_map_opendir_error(PRInt32 err);
+#define	_PR_MD_MAP_OPENDIR_ERROR	_MD_win32_map_opendir_error
+
+extern void _MD_win32_map_closedir_error(PRInt32 err);
+#define	_PR_MD_MAP_CLOSEDIR_ERROR	_MD_win32_map_closedir_error
+
+extern void _MD_unix_readdir_error(PRInt32 err);
+#define	_PR_MD_MAP_READDIR_ERROR	_MD_unix_readdir_error
+
+extern void _MD_win32_map_delete_error(PRInt32 err);
+#define	_PR_MD_MAP_DELETE_ERROR	_MD_win32_map_delete_error
+
+extern void _MD_win32_map_stat_error(PRInt32 err);
+#define	_PR_MD_MAP_STAT_ERROR	_MD_win32_map_stat_error
+
+extern void _MD_win32_map_fstat_error(PRInt32 err);
+#define	_PR_MD_MAP_FSTAT_ERROR	_MD_win32_map_fstat_error
+
+extern void _MD_win32_map_rename_error(PRInt32 err);
+#define	_PR_MD_MAP_RENAME_ERROR	_MD_win32_map_rename_error
+
+extern void _MD_win32_map_access_error(PRInt32 err);
+#define	_PR_MD_MAP_ACCESS_ERROR	_MD_win32_map_access_error
+
+extern void _MD_win32_map_mkdir_error(PRInt32 err);
+#define	_PR_MD_MAP_MKDIR_ERROR	_MD_win32_map_mkdir_error
+
+extern void _MD_win32_map_rmdir_error(PRInt32 err);
+#define	_PR_MD_MAP_RMDIR_ERROR	_MD_win32_map_rmdir_error
+
+extern void _MD_win32_map_read_error(PRInt32 err);
+#define	_PR_MD_MAP_READ_ERROR	_MD_win32_map_read_error
+
+extern void _MD_win32_map_transmitfile_error(PRInt32 err);
+#define	_PR_MD_MAP_TRANSMITFILE_ERROR	_MD_win32_map_transmitfile_error
+
+extern void _MD_win32_map_write_error(PRInt32 err);
+#define	_PR_MD_MAP_WRITE_ERROR	_MD_win32_map_write_error
+
+extern void _MD_win32_map_lseek_error(PRInt32 err);
+#define	_PR_MD_MAP_LSEEK_ERROR	_MD_win32_map_lseek_error
+
+extern void _MD_win32_map_fsync_error(PRInt32 err);
+#define	_PR_MD_MAP_FSYNC_ERROR	_MD_win32_map_fsync_error
+
+extern void _MD_win32_map_close_error(PRInt32 err);
+#define	_PR_MD_MAP_CLOSE_ERROR	_MD_win32_map_close_error
+
+extern void _MD_win32_map_socket_error(PRInt32 err);
+#define	_PR_MD_MAP_SOCKET_ERROR	_MD_win32_map_socket_error
+
+extern void _MD_win32_map_recv_error(PRInt32 err);
+#define	_PR_MD_MAP_RECV_ERROR	_MD_win32_map_recv_error
+
+extern void _MD_win32_map_recvfrom_error(PRInt32 err);
+#define	_PR_MD_MAP_RECVFROM_ERROR	_MD_win32_map_recvfrom_error
+
+extern void _MD_win32_map_send_error(PRInt32 err);
+#define	_PR_MD_MAP_SEND_ERROR	_MD_win32_map_send_error
+
+extern void _MD_win32_map_sendto_error(PRInt32 err);
+#define	_PR_MD_MAP_SENDTO_ERROR	_MD_win32_map_sendto_error
+
+extern void _MD_win32_map_accept_error(PRInt32 err);
+#define	_PR_MD_MAP_ACCEPT_ERROR	_MD_win32_map_accept_error
+
+extern void _MD_win32_map_acceptex_error(PRInt32 err);
+#define	_PR_MD_MAP_ACCEPTEX_ERROR	_MD_win32_map_acceptex_error
+
+extern PRInt32 _MD_win32_map_connect_error(PRInt32 err);
+#define	_PR_MD_MAP_CONNECT_ERROR	_MD_win32_map_connect_error
+
+extern void _MD_win32_map_bind_error(PRInt32 err);
+#define	_PR_MD_MAP_BIND_ERROR	_MD_win32_map_bind_error
+
+extern void _MD_win32_map_listen_error(PRInt32 err);
+#define	_PR_MD_MAP_LISTEN_ERROR	_MD_win32_map_listen_error
+
+extern void _MD_win32_map_shutdown_error(PRInt32 err);
+#define	_PR_MD_MAP_SHUTDOWN_ERROR	_MD_win32_map_shutdown_error
+
+extern void _MD_win32_map_getsockname_error(PRInt32 err);
+#define	_PR_MD_MAP_GETSOCKNAME_ERROR	_MD_win32_map_getsockname_error
+
+extern void _MD_win32_map_getpeername_error(PRInt32 err);
+#define	_PR_MD_MAP_GETPEERNAME_ERROR	_MD_win32_map_getpeername_error
+
+extern void _MD_win32_map_getsockopt_error(PRInt32 err);
+#define	_PR_MD_MAP_GETSOCKOPT_ERROR	_MD_win32_map_getsockopt_error
+
+extern void _MD_win32_map_setsockopt_error(PRInt32 err);
+#define	_PR_MD_MAP_SETSOCKOPT_ERROR	_MD_win32_map_setsockopt_error
+
+extern void _MD_win32_map_open_error(PRInt32 err);
+#define	_PR_MD_MAP_OPEN_ERROR	_MD_win32_map_open_error
+
+extern void _MD_win32_map_gethostname_error(PRInt32 err);
+#define	_PR_MD_MAP_GETHOSTNAME_ERROR	_MD_win32_map_gethostname_error
+
+extern void _MD_win32_map_select_error(PRInt32 err);
+#define	_PR_MD_MAP_SELECT_ERROR	_MD_win32_map_select_error
+
+extern void _MD_win32_map_lockf_error(int err);
+#define _PR_MD_MAP_LOCKF_ERROR  _MD_win32_map_lockf_error
+
+#endif /* nspr_win32_errors_h___ */
diff --git a/mozilla/nsprpub/pr/include/md/_win95.cfg b/mozilla/nsprpub/pr/include/md/_win95.cfg
new file mode 100644
index 0000000..4a85281
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_win95.cfg
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_PC
+#define XP_PC
+#endif
+
+#ifndef WIN32
+#define WIN32
+#endif
+
+#ifdef _WIN32_WCE
+#ifndef WINCE
+#define WINCE
+#endif
+#else
+#ifndef WIN95
+#define WIN95
+#endif
+#endif
+
+#define PR_AF_INET6 23  /* same as AF_INET6 */
+
+#if defined(_M_IX86) || defined(_X86_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD	4
+#define PR_BYTES_PER_DWORD	8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD	32
+#define PR_BITS_PER_DWORD	64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2	5
+#define PR_BITS_PER_DWORD_LOG2	6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD	4
+#define PR_ALIGN_OF_DWORD	8
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+
+#define PR_BYTES_PER_WORD_LOG2	2
+#define PR_BYTES_PER_DWORD_LOG2	3
+
+#elif defined(_ALPHA_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_BYTES_PER_WORD_LOG2  2
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+
+#elif defined(_AMD64_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD	8
+#define PR_BYTES_PER_DWORD	8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD	64
+#define PR_BITS_PER_DWORD	64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2	6
+#define PR_BITS_PER_DWORD_LOG2	6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD	8
+#define PR_ALIGN_OF_DWORD	8
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#define PR_BYTES_PER_WORD_LOG2	3
+#define PR_BYTES_PER_DWORD_LOG2	3
+
+#elif defined(_IA64_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD	8
+#define PR_BYTES_PER_DWORD	8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD	64
+#define PR_BITS_PER_DWORD	64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2	6
+#define PR_BITS_PER_DWORD_LOG2	6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD	8
+#define PR_ALIGN_OF_DWORD	8
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#define PR_BYTES_PER_WORD_LOG2	3
+#define PR_BYTES_PER_DWORD_LOG2	3
+
+#elif defined(_ARM_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD    32
+#define PR_BITS_PER_DWORD   64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2   5
+#define PR_BITS_PER_DWORD_LOG2  6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD    4
+#define PR_ALIGN_OF_DWORD   8
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+
+#define PR_BYTES_PER_WORD_LOG2  2
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#else /* defined(_M_IX86) || defined(_X86_) */
+
+#error unknown processor architecture
+
+#endif /* defined(_M_IX86) || defined(_X86_) */
+
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE      PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT     PR_BYTES_PER_SHORT
+#define BYTES_PER_INT       PR_BYTES_PER_INT
+#define BYTES_PER_INT64     PR_BYTES_PER_INT64
+#define BYTES_PER_LONG      PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT     PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE    PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD      PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD     PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE       PR_BITS_PER_BYTE
+#define BITS_PER_SHORT      PR_BITS_PER_SHORT
+#define BITS_PER_INT        PR_BITS_PER_INT
+#define BITS_PER_INT64      PR_BITS_PER_INT64
+#define BITS_PER_LONG       PR_BITS_PER_LONG
+#define BITS_PER_FLOAT      PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE     PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD       PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2  PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2   PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2  PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2    PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2  PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT      PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT        PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG       PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64      PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT      PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE     PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER    PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD       PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2		PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2    PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2    PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/mozilla/nsprpub/pr/include/md/_win95.h b/mozilla/nsprpub/pr/include/md/_win95.h
new file mode 100644
index 0000000..af8497d
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/_win95.h
@@ -0,0 +1,569 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef nspr_win95_defs_h___
+#define nspr_win95_defs_h___
+
+#include "prio.h"
+
+#include <windows.h>
+#include <winsock.h>
+#include <errno.h>
+
+/*
+ * Internal configuration macros
+ */
+
+#define PR_LINKER_ARCH      "win32"
+#define _PR_SI_SYSNAME        "WIN95"
+#if defined(_M_IX86) || defined(_X86_)
+#define _PR_SI_ARCHITECTURE   "x86"
+#elif defined(_AMD64_)
+#define _PR_SI_ARCHITECTURE   "x86-64"
+#elif defined(_IA64_)
+#define _PR_SI_ARCHITECTURE   "ia64"
+#elif defined(_ARM_)
+#define _PR_SI_ARCHITECTURE   "arm"
+#else
+#error unknown processor architecture
+#endif
+
+#define HAVE_DLL
+#undef  HAVE_THREAD_AFFINITY
+#define _PR_HAVE_GETADDRINFO
+#define _PR_INET6_PROBE
+#ifndef _PR_INET6
+#define AF_INET6 23
+/* newer ws2tcpip.h provides these */
+#ifndef AI_CANONNAME
+#define AI_CANONNAME 0x2
+#define AI_NUMERICHOST 0x4
+#define NI_NUMERICHOST 0x02
+struct addrinfo {
+    int ai_flags;
+    int ai_family;
+    int ai_socktype;
+    int ai_protocol;
+    size_t ai_addrlen;
+    char *ai_canonname;
+    struct sockaddr *ai_addr;
+    struct addrinfo *ai_next;
+};
+#endif
+#define _PR_HAVE_MD_SOCKADDR_IN6
+/* isomorphic to struct in6_addr on Windows */
+struct _md_in6_addr {
+    union {
+        PRUint8  _S6_u8[16];
+        PRUint16 _S6_u16[8];
+    } _S6_un;
+};
+/* isomorphic to struct sockaddr_in6 on Windows */
+struct _md_sockaddr_in6 {
+    PRInt16 sin6_family;
+    PRUint16 sin6_port;
+    PRUint32 sin6_flowinfo;
+    struct _md_in6_addr sin6_addr;
+    PRUint32 sin6_scope_id;
+};
+#endif
+#define _PR_HAVE_THREADSAFE_GETHOST
+#define _PR_HAVE_ATOMIC_OPS
+#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY
+
+/* --- Common User-Thread/Native-Thread Definitions --------------------- */
+
+/* --- Globals --- */
+extern struct PRLock                      *_pr_schedLock;
+
+/* --- Typedefs --- */
+typedef void (*FiberFunc)(void *);
+
+#define PR_NUM_GCREGS           8
+typedef PRInt32	                PR_CONTEXT_TYPE[PR_NUM_GCREGS];
+#define GC_VMBASE               0x40000000
+#define GC_VMLIMIT              0x00FFFFFF
+
+#define _MD_MAGIC_THREAD	0x22222222
+#define _MD_MAGIC_THREADSTACK	0x33333333
+#define _MD_MAGIC_SEGMENT	0x44444444
+#define _MD_MAGIC_DIR		0x55555555
+#define _MD_MAGIC_CV        0x66666666
+
+struct _MDCPU {
+    int              unused;
+};
+
+struct _MDThread {
+    HANDLE           blocked_sema;      /* Threads block on this when waiting
+                                         * for IO or CondVar.
+                                         */
+    PRBool           inCVWaitQueue;     /* PR_TRUE if the thread is in the
+                                         * wait queue of some cond var.
+                                         * PR_FALSE otherwise.  */
+    HANDLE           handle;            /* Win32 thread handle */
+    PRUint32         id;
+    void            *sp;                /* only valid when suspended */
+    PRUint32         magic;             /* for debugging */
+    PR_CONTEXT_TYPE  gcContext;         /* Thread context for GC */
+    struct PRThread *prev, *next;       /* used by the cvar wait queue to
+                                         * chain the PRThread structures
+                                         * together */
+    void (*start)(void *);              /* used by _PR_MD_CREATE_THREAD to
+                                         * pass its 'start' argument to
+                                         * pr_root. */
+};
+
+struct _MDThreadStack {
+    PRUint32           magic;          /* for debugging */
+};
+
+struct _MDSegment {
+    PRUint32           magic;          /* for debugging */
+};
+
+#undef PROFILE_LOCKS
+
+struct _MDDir {
+    HANDLE           d_hdl;
+    WIN32_FIND_DATAA d_entry;
+    PRBool           firstEntry;     /* Is this the entry returned
+                                      * by FindFirstFile()? */
+    PRUint32         magic;          /* for debugging */
+};
+
+#ifdef MOZ_UNICODE
+struct _MDDirUTF16 {
+    HANDLE           d_hdl;
+    WIN32_FIND_DATAW d_entry;
+    PRBool           firstEntry;     /* Is this the entry returned
+                                      * by FindFirstFileW()? */
+    PRUint32         magic;          /* for debugging */
+};
+#endif /* MOZ_UNICODE */
+
+struct _MDCVar {
+    PRUint32 magic;
+    struct PRThread *waitHead, *waitTail;  /* the wait queue: a doubly-
+                                            * linked list of threads
+                                            * waiting on this condition
+                                            * variable */
+    PRIntn nwait;                          /* number of threads in the
+                                            * wait queue */
+};
+
+#define _MD_CV_NOTIFIED_LENGTH 6
+typedef struct _MDNotified _MDNotified;
+struct _MDNotified {
+    PRIntn length;                     /* # of used entries in this
+                                        * structure */
+    struct {
+        struct _MDCVar *cv;            /* the condition variable notified */
+        PRIntn times;                  /* and the number of times notified */
+        struct PRThread *notifyHead;   /* list of threads to wake up */
+    } cv[_MD_CV_NOTIFIED_LENGTH];
+    _MDNotified *link;                 /* link to another of these, or NULL */
+};
+
+struct _MDLock {
+    CRITICAL_SECTION mutex;          /* this is recursive on NT */
+
+    /*
+     * When notifying cvars, there is no point in actually
+     * waking up the threads waiting on the cvars until we've
+     * released the lock.  So, we temporarily record the cvars.
+     * When doing an unlock, we'll then wake up the waiting threads.
+     */
+    struct _MDNotified notified;     /* array of conditions notified */
+#ifdef PROFILE_LOCKS
+    PRInt32 hitcount;
+    PRInt32 misscount;
+#endif
+};
+
+struct _MDSemaphore {
+    HANDLE           sem;
+};
+
+struct _MDFileDesc {
+    PROsfd osfd;     /* The osfd can come from one of three spaces:
+                      * - For stdin, stdout, and stderr, we are using
+                      *   the libc file handle (0, 1, 2), which is an int.
+                      * - For files and pipes, we are using Win32 HANDLE,
+                      *   which is a void*.
+                      * - For sockets, we are using Winsock SOCKET, which
+                      *   is a u_int.
+                      */
+};
+
+struct _MDProcess {
+    HANDLE handle;
+    DWORD id;
+};
+
+/* --- Misc stuff --- */
+#define _MD_GET_SP(thread)            (thread)->md.gcContext[6]
+
+/* --- NT security stuff --- */
+
+extern void _PR_NT_InitSids(void);
+extern void _PR_NT_FreeSids(void);
+extern PRStatus _PR_NT_MakeSecurityDescriptorACL(
+    PRIntn mode,
+    DWORD accessTable[],
+    PSECURITY_DESCRIPTOR *resultSD,
+    PACL *resultACL
+);
+extern void _PR_NT_FreeSecurityDescriptorACL(
+    PSECURITY_DESCRIPTOR pSD, PACL pACL);
+
+/* --- IO stuff --- */
+
+#define _MD_OPEN                      _PR_MD_OPEN
+#define _MD_OPEN_FILE                 _PR_MD_OPEN_FILE
+#define _MD_READ                      _PR_MD_READ
+#define _MD_WRITE                     _PR_MD_WRITE
+#define _MD_WRITEV                    _PR_MD_WRITEV
+#define _MD_LSEEK                     _PR_MD_LSEEK
+#define _MD_LSEEK64                   _PR_MD_LSEEK64
+extern PRInt32 _MD_CloseFile(PROsfd osfd);
+#define _MD_CLOSE_FILE                _MD_CloseFile
+#define _MD_GETFILEINFO               _PR_MD_GETFILEINFO
+#define _MD_GETFILEINFO64             _PR_MD_GETFILEINFO64
+#define _MD_GETOPENFILEINFO           _PR_MD_GETOPENFILEINFO
+#define _MD_GETOPENFILEINFO64         _PR_MD_GETOPENFILEINFO64
+#define _MD_STAT                      _PR_MD_STAT
+#define _MD_RENAME                    _PR_MD_RENAME     
+#define _MD_ACCESS                    _PR_MD_ACCESS     
+#define _MD_DELETE                    _PR_MD_DELETE     
+#define _MD_MKDIR                     _PR_MD_MKDIR      
+#define _MD_MAKE_DIR                  _PR_MD_MAKE_DIR
+#define _MD_RMDIR                     _PR_MD_RMDIR      
+#define _MD_LOCKFILE                  _PR_MD_LOCKFILE
+#define _MD_TLOCKFILE                 _PR_MD_TLOCKFILE
+#define _MD_UNLOCKFILE                _PR_MD_UNLOCKFILE
+
+/* --- UTF16 IO stuff --- */
+extern PRBool _pr_useUnicode;
+#ifdef MOZ_UNICODE
+#define _MD_OPEN_FILE_UTF16           _PR_MD_OPEN_FILE_UTF16
+#define _MD_OPEN_DIR_UTF16            _PR_MD_OPEN_DIR_UTF16
+#define _MD_READ_DIR_UTF16            _PR_MD_READ_DIR_UTF16
+#define _MD_CLOSE_DIR_UTF16           _PR_MD_CLOSE_DIR_UTF16
+#define _MD_GETFILEINFO64_UTF16       _PR_MD_GETFILEINFO64_UTF16
+#endif /* MOZ_UNICODE */
+
+/* --- Socket IO stuff --- */
+extern void _PR_MD_InitSockets(void);
+extern void _PR_MD_CleanupSockets(void);
+#define _MD_EACCES                WSAEACCES
+#define _MD_EADDRINUSE            WSAEADDRINUSE
+#define _MD_EADDRNOTAVAIL         WSAEADDRNOTAVAIL
+#define _MD_EAFNOSUPPORT          WSAEAFNOSUPPORT
+#define _MD_EAGAIN                WSAEWOULDBLOCK
+#define _MD_EALREADY              WSAEALREADY
+#define _MD_EBADF                 WSAEBADF
+#define _MD_ECONNREFUSED          WSAECONNREFUSED
+#define _MD_ECONNRESET            WSAECONNRESET
+#define _MD_EFAULT                WSAEFAULT
+#define _MD_EINPROGRESS           WSAEINPROGRESS
+#define _MD_EINTR                 WSAEINTR
+#define _MD_EINVAL                EINVAL
+#define _MD_EISCONN               WSAEISCONN
+#define _MD_ENETUNREACH           WSAENETUNREACH
+#define _MD_ENOENT                ENOENT
+#define _MD_ENOTCONN              WSAENOTCONN
+#define _MD_ENOTSOCK              WSAENOTSOCK
+#define _MD_EOPNOTSUPP            WSAEOPNOTSUPP
+#define _MD_EWOULDBLOCK           WSAEWOULDBLOCK
+#define _MD_GET_SOCKET_ERROR()    WSAGetLastError()
+#define _MD_SET_SOCKET_ERROR(_err) WSASetLastError(_err)
+
+#define _MD_INIT_FILEDESC(fd)
+extern void _MD_MakeNonblock(PRFileDesc *f);
+#define _MD_MAKE_NONBLOCK             _MD_MakeNonblock
+#define _MD_INIT_FD_INHERITABLE       _PR_MD_INIT_FD_INHERITABLE
+#define _MD_QUERY_FD_INHERITABLE      _PR_MD_QUERY_FD_INHERITABLE
+#define _MD_SHUTDOWN                  _PR_MD_SHUTDOWN
+#define _MD_LISTEN                    _PR_MD_LISTEN
+extern PRInt32 _MD_CloseSocket(PROsfd osfd);
+#define _MD_CLOSE_SOCKET              _MD_CloseSocket
+#define _MD_SENDTO                    _PR_MD_SENDTO
+#define _MD_RECVFROM                  _PR_MD_RECVFROM
+#define _MD_SOCKETPAIR(s, type, proto, sv) -1
+#define _MD_GETSOCKNAME               _PR_MD_GETSOCKNAME
+#define _MD_GETPEERNAME               _PR_MD_GETPEERNAME
+#define _MD_GETSOCKOPT                _PR_MD_GETSOCKOPT
+#define _MD_SETSOCKOPT                _PR_MD_SETSOCKOPT
+#define _MD_SET_FD_INHERITABLE        _PR_MD_SET_FD_INHERITABLE
+#define _MD_SELECT                    select
+#define _MD_FSYNC                     _PR_MD_FSYNC
+#define READ_FD                       1
+#define WRITE_FD                      2
+
+#define _MD_INIT_ATOMIC()
+#if defined(_M_IX86) || defined(_X86_)
+#define _MD_ATOMIC_INCREMENT          _PR_MD_ATOMIC_INCREMENT
+#define _MD_ATOMIC_ADD          	  _PR_MD_ATOMIC_ADD
+#define _MD_ATOMIC_DECREMENT          _PR_MD_ATOMIC_DECREMENT
+#else /* non-x86 processors */
+#define _MD_ATOMIC_INCREMENT(x)       InterlockedIncrement((PLONG)x)
+#define _MD_ATOMIC_ADD(ptr,val)    (InterlockedExchangeAdd((PLONG)ptr, (LONG)val) + val)
+#define _MD_ATOMIC_DECREMENT(x)       InterlockedDecrement((PLONG)x)
+#endif /* x86 */
+#define _MD_ATOMIC_SET(x,y)           InterlockedExchange((PLONG)x, (LONG)y)
+
+#define _MD_INIT_IO                   _PR_MD_INIT_IO
+
+
+/* win95 doesn't have async IO */
+#define _MD_SOCKET                    _PR_MD_SOCKET
+extern PRInt32 _MD_SocketAvailable(PRFileDesc *fd);
+#define _MD_SOCKETAVAILABLE           _MD_SocketAvailable
+#define _MD_PIPEAVAILABLE             _PR_MD_PIPEAVAILABLE
+#define _MD_CONNECT                   _PR_MD_CONNECT
+extern PROsfd _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen,
+        PRIntervalTime timeout);
+#define _MD_ACCEPT                    _MD_Accept
+#define _MD_BIND                      _PR_MD_BIND
+#define _MD_RECV                      _PR_MD_RECV
+#define _MD_SEND                      _PR_MD_SEND
+#define _MD_PR_POLL                   _PR_MD_PR_POLL
+
+/* --- Scheduler stuff --- */
+// #define _MD_PAUSE_CPU                 _PR_MD_PAUSE_CPU
+#define _MD_PAUSE_CPU
+
+/* --- DIR stuff --- */
+#define PR_DIRECTORY_SEPARATOR        '\\'
+#define PR_DIRECTORY_SEPARATOR_STR    "\\"
+#define PR_PATH_SEPARATOR		';'
+#define PR_PATH_SEPARATOR_STR		";"
+#define _MD_ERRNO()                   GetLastError()
+#define _MD_OPEN_DIR                  _PR_MD_OPEN_DIR
+#define _MD_CLOSE_DIR                 _PR_MD_CLOSE_DIR
+#define _MD_READ_DIR                  _PR_MD_READ_DIR
+
+/* --- Segment stuff --- */
+#define _MD_INIT_SEGS()
+#define _MD_ALLOC_SEGMENT(seg, size, vaddr)   0
+#define _MD_FREE_SEGMENT(seg)
+
+/* --- Environment Stuff --- */
+#define _MD_GET_ENV                 _PR_MD_GET_ENV
+#define _MD_PUT_ENV                 _PR_MD_PUT_ENV
+
+/* --- Threading Stuff --- */
+#define _MD_DEFAULT_STACK_SIZE            0
+#define _MD_INIT_THREAD             _PR_MD_INIT_THREAD
+#define _MD_INIT_ATTACHED_THREAD    _PR_MD_INIT_THREAD
+#define _MD_CREATE_THREAD           _PR_MD_CREATE_THREAD
+#define _MD_YIELD                   _PR_MD_YIELD
+#define _MD_SET_PRIORITY            _PR_MD_SET_PRIORITY
+#define _MD_CLEAN_THREAD            _PR_MD_CLEAN_THREAD
+#define _MD_SETTHREADAFFINITYMASK   _PR_MD_SETTHREADAFFINITYMASK
+#define _MD_GETTHREADAFFINITYMASK   _PR_MD_GETTHREADAFFINITYMASK
+#define _MD_EXIT_THREAD             _PR_MD_EXIT_THREAD
+#define _MD_EXIT                    _PR_MD_EXIT
+#define _MD_SUSPEND_THREAD          _PR_MD_SUSPEND_THREAD
+#define _MD_RESUME_THREAD           _PR_MD_RESUME_THREAD
+#define _MD_SUSPEND_CPU             _PR_MD_SUSPEND_CPU
+#define _MD_RESUME_CPU              _PR_MD_RESUME_CPU
+#define _MD_BEGIN_SUSPEND_ALL()
+#define _MD_BEGIN_RESUME_ALL()
+#define _MD_END_SUSPEND_ALL()
+#define _MD_END_RESUME_ALL()
+
+/* --- Lock stuff --- */
+#define _PR_LOCK                      _MD_LOCK
+#define _PR_UNLOCK					  _MD_UNLOCK
+
+#define _MD_NEW_LOCK(lock)            (InitializeCriticalSection(&((lock)->mutex)),(lock)->notified.length=0,(lock)->notified.link=NULL,PR_SUCCESS)
+#define _MD_FREE_LOCK(lock)           DeleteCriticalSection(&((lock)->mutex))
+#define _MD_LOCK(lock)                EnterCriticalSection(&((lock)->mutex))
+#define _MD_TEST_AND_LOCK(lock)       (EnterCriticalSection(&((lock)->mutex)),0)
+#define _MD_UNLOCK                    _PR_MD_UNLOCK
+
+/* --- lock and cv waiting --- */
+#define _MD_WAIT                      _PR_MD_WAIT
+#define _MD_WAKEUP_WAITER             _PR_MD_WAKEUP_WAITER
+
+/* --- CVar ------------------- */
+#define _MD_WAIT_CV					  _PR_MD_WAIT_CV
+#define _MD_NEW_CV					  _PR_MD_NEW_CV
+#define _MD_FREE_CV					  _PR_MD_FREE_CV
+#define _MD_NOTIFY_CV				  _PR_MD_NOTIFY_CV	
+#define _MD_NOTIFYALL_CV			  _PR_MD_NOTIFYALL_CV
+
+   /* XXXMB- the IOQ stuff is certainly not working correctly yet. */
+// extern  struct _MDLock              _pr_ioq_lock;
+#define _MD_IOQ_LOCK()                
+#define _MD_IOQ_UNLOCK()              
+
+
+/* --- Initialization stuff --- */
+#define _MD_START_INTERRUPTS()
+#define _MD_STOP_INTERRUPTS()
+#define _MD_DISABLE_CLOCK_INTERRUPTS()
+#define _MD_ENABLE_CLOCK_INTERRUPTS()
+#define _MD_BLOCK_CLOCK_INTERRUPTS()
+#define _MD_UNBLOCK_CLOCK_INTERRUPTS()
+#define _MD_EARLY_INIT                _PR_MD_EARLY_INIT
+#define _MD_FINAL_INIT()
+#define _MD_INIT_CPUS()
+#define _MD_INIT_RUNNING_CPU(cpu)
+
+struct PRProcess;
+struct PRProcessAttr;
+
+#define _MD_CREATE_PROCESS _PR_CreateWindowsProcess
+extern struct PRProcess * _PR_CreateWindowsProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const struct PRProcessAttr *attr
+);
+
+#define _MD_DETACH_PROCESS _PR_DetachWindowsProcess
+extern PRStatus _PR_DetachWindowsProcess(struct PRProcess *process);
+
+/* --- Wait for a child process to terminate --- */
+#define _MD_WAIT_PROCESS _PR_WaitWindowsProcess
+extern PRStatus _PR_WaitWindowsProcess(struct PRProcess *process, 
+    PRInt32 *exitCode);
+
+#define _MD_KILL_PROCESS _PR_KillWindowsProcess
+extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process);
+
+#define _MD_CLEANUP_BEFORE_EXIT           _PR_MD_CLEANUP_BEFORE_EXIT
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \
+    PR_BEGIN_MACRO \
+    *status = PR_TRUE; \
+    PR_END_MACRO
+#define _MD_SWITCH_CONTEXT
+#define _MD_RESTORE_CONTEXT
+
+/* --- Intervals --- */
+#define _MD_INTERVAL_INIT                 _PR_MD_INTERVAL_INIT
+#define _MD_GET_INTERVAL                  _PR_MD_GET_INTERVAL
+#define _MD_INTERVAL_PER_SEC              _PR_MD_INTERVAL_PER_SEC
+#define _MD_INTERVAL_PER_MILLISEC()       (_PR_MD_INTERVAL_PER_SEC() / 1000)
+#define _MD_INTERVAL_PER_MICROSEC()       (_PR_MD_INTERVAL_PER_SEC() / 1000000)
+
+/* --- Time --- */
+extern void _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm);
+
+#ifdef WINCE
+extern void _MD_InitTime(void);
+extern void _MD_CleanupTime(void);
+#endif
+
+/* --- Native-Thread Specific Definitions ------------------------------- */
+
+extern struct PRThread * _MD_CURRENT_THREAD(void);
+
+#ifdef _PR_USE_STATIC_TLS
+extern __declspec(thread) struct PRThread *_pr_currentThread;
+#define _MD_GET_ATTACHED_THREAD() _pr_currentThread
+#define _MD_SET_CURRENT_THREAD(_thread) (_pr_currentThread = (_thread))
+
+extern __declspec(thread) struct PRThread *_pr_thread_last_run;
+#define _MD_LAST_THREAD() _pr_thread_last_run
+#define _MD_SET_LAST_THREAD(_thread) (_pr_thread_last_run = 0)
+
+extern __declspec(thread) struct _PRCPU *_pr_currentCPU;
+#define _MD_CURRENT_CPU() _pr_currentCPU
+#define _MD_SET_CURRENT_CPU(_cpu) (_pr_currentCPU = 0)
+#else /* _PR_USE_STATIC_TLS */
+extern DWORD _pr_currentThreadIndex;
+#define _MD_GET_ATTACHED_THREAD() ((PRThread *) TlsGetValue(_pr_currentThreadIndex))
+#define _MD_SET_CURRENT_THREAD(_thread) TlsSetValue(_pr_currentThreadIndex, (_thread))
+
+extern DWORD _pr_lastThreadIndex;
+#define _MD_LAST_THREAD() ((PRThread *) TlsGetValue(_pr_lastThreadIndex))
+#define _MD_SET_LAST_THREAD(_thread) TlsSetValue(_pr_lastThreadIndex, 0)
+
+extern DWORD _pr_currentCPUIndex;
+#define _MD_CURRENT_CPU() ((struct _PRCPU *) TlsGetValue(_pr_currentCPUIndex))
+#define _MD_SET_CURRENT_CPU(_cpu) TlsSetValue(_pr_currentCPUIndex, 0)
+#endif /* _PR_USE_STATIC_TLS */
+
+/* --- Scheduler stuff --- */
+#define LOCK_SCHEDULER()                 0
+#define UNLOCK_SCHEDULER()               0
+#define _PR_LockSched()                	 0
+#define _PR_UnlockSched()                0
+
+/* --- Initialization stuff --- */
+#define _MD_INIT_LOCKS()
+
+/* --- Stack stuff --- */
+#define _MD_INIT_STACK(stack, redzone)
+#define _MD_CLEAR_STACK(stack)
+
+/* --- Memory-mapped files stuff --- */
+
+struct _MDFileMap {
+    HANDLE hFileMap;
+    DWORD dwAccess;
+};
+
+extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size);
+#define _MD_CREATE_FILE_MAP _MD_CreateFileMap
+
+extern PRInt32 _MD_GetMemMapAlignment(void);
+#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment
+
+extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset,
+        PRUint32 len);
+#define _MD_MEM_MAP _MD_MemMap
+
+extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size);
+#define _MD_MEM_UNMAP _MD_MemUnmap
+
+extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap);
+#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap
+
+/* --- Named semaphores stuff --- */
+#define _PR_HAVE_NAMED_SEMAPHORES
+#define _MD_OPEN_SEMAPHORE            _PR_MD_OPEN_SEMAPHORE
+#define _MD_WAIT_SEMAPHORE            _PR_MD_WAIT_SEMAPHORE
+#define _MD_POST_SEMAPHORE            _PR_MD_POST_SEMAPHORE
+#define _MD_CLOSE_SEMAPHORE           _PR_MD_CLOSE_SEMAPHORE
+#define _MD_DELETE_SEMAPHORE(name)    PR_SUCCESS  /* no op */
+
+#endif /* nspr_win32_defs_h___ */
diff --git a/mozilla/nsprpub/pr/include/md/prosdep.h b/mozilla/nsprpub/pr/include/md/prosdep.h
new file mode 100644
index 0000000..7e20ab4
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/md/prosdep.h
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prosdep_h___
+#define prosdep_h___
+
+/*
+** Get OS specific header information
+*/
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+#ifdef XP_PC
+
+#include "md/_pcos.h"
+#ifdef WINNT
+#include "md/_winnt.h"
+#include "md/_win32_errors.h"
+#elif defined(WIN95) || defined(WINCE)
+#include "md/_win95.h"
+#include "md/_win32_errors.h"
+#elif defined(OS2)
+#include "md/_os2.h"
+#include "md/_os2_errors.h"
+#else
+#error unknown Windows platform
+#endif
+
+#elif defined(XP_UNIX)
+
+#if defined(AIX)
+#include "md/_aix.h"
+
+#elif defined(FREEBSD)
+#include "md/_freebsd.h"
+
+#elif defined(NETBSD)
+#include "md/_netbsd.h"
+
+#elif defined(OPENBSD)
+#include "md/_openbsd.h"
+
+#elif defined(BSDI)
+#include "md/_bsdi.h"
+
+#elif defined(HPUX)
+#include "md/_hpux.h"
+
+#elif defined(IRIX)
+#include "md/_irix.h"
+
+#elif defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)
+#include "md/_linux.h"
+
+#elif defined(OSF1)
+#include "md/_osf1.h"
+
+#elif defined(DARWIN)
+#include "md/_darwin.h"
+
+#elif defined(NEXTSTEP)
+#include "md/_nextstep.h"
+
+#elif defined(SOLARIS)
+#include "md/_solaris.h"
+
+#elif defined(SUNOS4)
+#include "md/_sunos4.h"
+
+#elif defined(SNI)
+#include "md/_reliantunix.h"
+
+#elif defined(SONY)
+#include "md/_sony.h"
+
+#elif defined(NEC)
+#include "md/_nec.h"
+
+#elif defined(SCO)
+#include "md/_scoos.h"
+
+#elif defined(UNIXWARE)
+#include "md/_unixware.h"
+
+#elif defined(NCR)
+#include "md/_ncr.h"
+
+#elif defined(DGUX)
+#include "md/_dgux.h"
+
+#elif defined(QNX)
+#include "md/_qnx.h"
+
+#elif defined(NTO)
+#include "md/_nto.h"
+
+#elif defined(RISCOS)
+#include "md/_riscos.h"
+
+#elif defined(SYMBIAN)
+#include "md/_symbian.h"
+
+#else
+#error unknown Unix flavor
+
+#endif
+
+#include "md/_unixos.h"
+#include "md/_unix_errors.h"
+
+#elif defined(XP_BEOS)
+
+#include "md/_beos.h"
+#include "md/_unix_errors.h"
+
+#else
+
+#error "The platform is not BeOS, Unix, Windows, or Mac"
+
+#endif
+
+#ifdef _PR_PTHREADS
+#include "md/_pth.h"
+#endif
+
+PR_END_EXTERN_C
+
+#endif /* prosdep_h___ */
diff --git a/mozilla/nsprpub/pr/include/nspr.h b/mozilla/nsprpub/pr/include/nspr.h
new file mode 100644
index 0000000..cf3bfad
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/nspr.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef nspr_h___
+#define nspr_h___
+
+#include "pratom.h"
+#include "prbit.h"
+#include "prclist.h"
+#include "prcmon.h"
+#include "prcvar.h"
+#include "prdtoa.h"
+#include "prenv.h"
+#include "prerror.h"
+#include "prinet.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prio.h"
+#include "pripcsem.h"
+#include "prlink.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prlong.h"
+#include "prmem.h"
+#include "prmon.h"
+#include "prmwait.h"
+#include "prnetdb.h"
+#include "prprf.h"
+#include "prproces.h"
+#include "prrng.h"
+#include "prrwlock.h"
+#include "prshm.h"
+#include "prshma.h"
+#include "prsystem.h"
+#include "prthread.h"
+#include "prtime.h"
+#include "prtpool.h"
+#include "prtrace.h"
+#include "prtypes.h"
+
+#endif /* nspr_h___ */
diff --git a/mozilla/nsprpub/pr/include/obsolete/pralarm.h b/mozilla/nsprpub/pr/include/obsolete/pralarm.h
new file mode 100644
index 0000000..20476e4
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/obsolete/pralarm.h
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:		pralarm.h
+** Description:	API to periodic alarms.
+**
+**
+** Alarms are defined to invoke some client specified function at 
+** a time in the future. The notification may be a one time event
+** or repeated at a fixed interval. The interval at which the next
+** notification takes place may be modified by the client code only
+** during the respective notification.
+**
+** The notification is delivered on a thread that is part of the
+** alarm context (PRAlarm). The thread will inherit the priority
+** of the Alarm creator.
+**
+** Any number of periodic alarms (PRAlarmID) may be created within
+** the context of a single alarm (PRAlarm). The notifications will be
+** scheduled as close to the desired time as possible.
+**
+** Repeating periodic notifies are expected to run at a fixed rate.
+** That rate is expressed as some number of notifies per period where
+** the period is much larger than a PRIntervalTime (see prinrval.h).
+*/
+
+#if !defined(pralarm_h)
+#define pralarm_h
+
+#include "prtypes.h"
+#include "prinrval.h"
+
+
+PR_BEGIN_EXTERN_C
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+typedef struct PRAlarm PRAlarm;
+typedef struct PRAlarmID PRAlarmID;
+
+typedef PRBool (PR_CALLBACK *PRPeriodicAlarmFn)(
+    PRAlarmID *id, void *clientData, PRUint32 late);
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+/***********************************************************************
+** FUNCTION:    PR_CreateAlarm
+** DESCRIPTION:
+**  Create an alarm context.
+** INPUTS:      void
+** OUTPUTS:     None
+** RETURN:      PRAlarm*
+**  
+** SIDE EFFECTS:
+**  This creates an alarm context, which is an object used for subsequent
+**  notification creations. It also creates a thread that will be used to
+** deliver the notifications that are expected to be defined. The client
+** is resposible for destroying the context when appropriate.
+** RESTRICTIONS:
+**  None. 
+** MEMORY:      The object (PRAlarm) and a thread to support notifications.
+** ALGORITHM:   N/A
+***********************************************************************/
+NSPR_API(PRAlarm*) PR_CreateAlarm(void);
+
+/***********************************************************************
+** FUNCTION:    PR_DestroyAlarm
+** DESCRIPTION:
+**  Destroys the context created by PR_CreateAlarm().
+** INPUTS:      PRAlarm*
+** OUTPUTS:     None
+** RETURN:      PRStatus
+**  
+** SIDE EFFECTS:
+**  This destroys the context that was created by PR_CreateAlarm().
+**  If there are any active alarms (PRAlarmID), they will be cancelled.
+**  Once that is done, the thread that was used to deliver the alarms
+**  will be joined. 
+** RESTRICTIONS:
+**  None. 
+** MEMORY:      N/A
+** ALGORITHM:   N/A
+***********************************************************************/
+NSPR_API(PRStatus) PR_DestroyAlarm(PRAlarm *alarm);
+
+/***********************************************************************
+** FUNCTION:    PR_SetAlarm
+** DESCRIPTION:
+**  Creates a periodic notifier that is to be delivered to a specified
+**  function at some fixed interval.
+** INPUTS:      PRAlarm *alarm              Parent alarm context
+**              PRIntervalTime period       Interval over which the notifies
+**                                          are delivered.
+**              PRUint32 rate               The rate within the interval that
+**                                          the notifies will be delivered.
+**              PRPeriodicAlarmFn function  Entry point where the notifies
+**                                          will be delivered.
+** OUTPUTS:     None
+** RETURN:      PRAlarmID*                  Handle to the notifier just created
+**                                          or NULL if the request failed.
+**  
+** SIDE EFFECTS:
+**  A periodic notifier is created. The notifications will be delivered
+**  by the alarm's internal thread at a fixed interval whose rate is the
+**  number of interrupts per interval specified. The first notification
+**  will be delivered as soon as possible, and they will continue until
+**  the notifier routine indicates that they should cease of the alarm
+**  context is destroyed (PR_DestroyAlarm).
+** RESTRICTIONS:
+**  None. 
+** MEMORY:      Memory for the notifier object.
+** ALGORITHM:   The rate at which notifications are delivered are stated
+**              to be "'rate' notifies per 'interval'". The exact time of
+**              the notification is computed based on a epoch established
+**              when the notifier was set. Each notification is delivered
+**              not ealier than the epoch plus the fixed rate times the
+**              notification sequence number. Such notifications have the
+**              potential to be late by not more than 'interval'/'rate'.
+**              The amount of lateness of one notification is taken into
+**              account on the next in an attempt to avoid long term slew.  
+***********************************************************************/
+NSPR_API(PRAlarmID*) PR_SetAlarm(
+    PRAlarm *alarm, PRIntervalTime period, PRUint32 rate,
+    PRPeriodicAlarmFn function, void *clientData);
+
+/***********************************************************************
+** FUNCTION:    PR_ResetAlarm
+** DESCRIPTION:
+**  Resets an existing alarm.
+** INPUTS:      PRAlarmID *id               Identify of the notifier.
+**              PRIntervalTime period       Interval over which the notifies
+**                                          are delivered.
+**              PRUint32 rate               The rate within the interval that
+**                                          the notifies will be delivered.
+** OUTPUTS:     None
+** RETURN:      PRStatus                    Indication of completion.
+**  
+** SIDE EFFECTS:
+**  An existing alarm may have its period and rate redefined. The
+**  additional side effect is that the notifier's epoch is recomputed.
+**  The first notification delivered by the newly refreshed alarm is
+**  defined to be 'interval'/'rate' from the time of the reset.
+** RESTRICTIONS:
+**  This function may only be called in the notifier for that alarm.
+** MEMORY:      N/A.
+** ALGORITHM:   See PR_SetAlarm().  
+***********************************************************************/
+NSPR_API(PRStatus) PR_ResetAlarm(
+	PRAlarmID *id, PRIntervalTime period, PRUint32 rate);
+
+PR_END_EXTERN_C
+
+#endif /* !defined(pralarm_h) */
+
+/* prinrval.h */
diff --git a/mozilla/nsprpub/pr/include/obsolete/probslet.h b/mozilla/nsprpub/pr/include/obsolete/probslet.h
new file mode 100644
index 0000000..bad5947
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/obsolete/probslet.h
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** A collection of things thought to be obsolete
+*/
+
+#if defined(PROBSLET_H)
+#else
+#define PROBSLET_H
+
+#include "prio.h"
+#include "private/pprio.h"  /* for PROsfd */
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Yield the current thread.  The proper function to use in place of
+** PR_Yield() is PR_Sleep() with an argument of PR_INTERVAL_NO_WAIT.
+*/
+NSPR_API(PRStatus) PR_Yield(void);
+
+/************************************************************************/
+/************* The following definitions are for select *****************/
+/************************************************************************/
+
+/*
+** The following is obsolete and will be deleted in the next release!
+** These are provided for compatibility, but are GUARANTEED to be slow.
+**
+** Override PR_MAX_SELECT_DESC if you need more space in the select set.
+*/
+#ifndef PR_MAX_SELECT_DESC
+#define PR_MAX_SELECT_DESC 1024
+#endif
+typedef struct PR_fd_set {
+    PRUint32      hsize;
+    PRFileDesc   *harray[PR_MAX_SELECT_DESC];
+    PRUint32      nsize;
+    PROsfd        narray[PR_MAX_SELECT_DESC];
+} PR_fd_set;
+
+/*
+*************************************************************************
+** FUNCTION:    PR_Select
+** DESCRIPTION:
+**
+** The call returns as soon as I/O is ready on one or more of the underlying
+** file/socket descriptors or an exceptional condition is pending. A count of the 
+** number of ready descriptors is returned unless a timeout occurs in which case 
+** zero is returned.  On return, PR_Select replaces the given descriptor sets with 
+** subsets consisting of those descriptors that are ready for the requested condition.
+** The total number of ready descriptors in all the sets is the return value.
+**
+** INPUTS:
+**   PRInt32 num             
+**       This argument is unused but is provided for select(unix) interface
+**       compatability.  All input PR_fd_set arguments are self-describing
+**       with its own maximum number of elements in the set.
+**                               
+**   PR_fd_set *readfds
+**       A set describing the io descriptors for which ready for reading
+**       condition is of interest.  
+**                               
+**   PR_fd_set *writefds
+**       A set describing the io descriptors for which ready for writing
+**       condition is of interest.  
+**                               
+**   PR_fd_set *exceptfds
+**       A set describing the io descriptors for which exception pending
+**       condition is of interest.  
+**
+**   Any of the above readfds, writefds or exceptfds may be given as NULL 
+**   pointers if no descriptors are of interest for that particular condition.                          
+**   
+**   PRIntervalTime timeout  
+**       Amount of time the call will block waiting for I/O to become ready. 
+**       If this time expires without any I/O becoming ready, the result will
+**       be zero.
+**
+** OUTPUTS:    
+**   PR_fd_set *readfds
+**       A set describing the io descriptors which are ready for reading.
+**                               
+**   PR_fd_set *writefds
+**       A set describing the io descriptors which are ready for writing.
+**                               
+**   PR_fd_set *exceptfds
+**       A set describing the io descriptors which have pending exception.
+**
+** RETURN:PRInt32
+**   Number of io descriptors with asked for conditions or zero if the function
+**   timed out or -1 on failure.  The reason for the failure is obtained by 
+**   calling PR_GetError().
+** XXX can we implement this on windoze and mac?
+**************************************************************************
+*/
+NSPR_API(PRInt32) PR_Select(
+    PRInt32 num, PR_fd_set *readfds, PR_fd_set *writefds,
+    PR_fd_set *exceptfds, PRIntervalTime timeout);
+
+/* 
+** The following are not thread safe for two threads operating on them at the
+** same time.
+**
+** The following routines are provided for manipulating io descriptor sets.
+** PR_FD_ZERO(&fdset) initializes a descriptor set fdset to the null set.
+** PR_FD_SET(fd, &fdset) includes a particular file descriptor fd in fdset.
+** PR_FD_CLR(fd, &fdset) removes a file descriptor fd from fdset.  
+** PR_FD_ISSET(fd, &fdset) is nonzero if file descriptor fd is a member of 
+** fdset, zero otherwise.
+**
+** PR_FD_NSET(osfd, &fdset) includes a particular native file descriptor osfd
+** in fdset.
+** PR_FD_NCLR(osfd, &fdset) removes a native file descriptor osfd from fdset.  
+** PR_FD_NISSET(osfd, &fdset) is nonzero if native file descriptor osfd is a member of 
+** fdset, zero otherwise.
+*/
+
+NSPR_API(void)        PR_FD_ZERO(PR_fd_set *set);
+NSPR_API(void)        PR_FD_SET(PRFileDesc *fd, PR_fd_set *set);
+NSPR_API(void)        PR_FD_CLR(PRFileDesc *fd, PR_fd_set *set);
+NSPR_API(PRInt32)     PR_FD_ISSET(PRFileDesc *fd, PR_fd_set *set);
+NSPR_API(void)        PR_FD_NSET(PROsfd osfd, PR_fd_set *set);
+NSPR_API(void)        PR_FD_NCLR(PROsfd osfd, PR_fd_set *set);
+NSPR_API(PRInt32)     PR_FD_NISSET(PROsfd osfd, PR_fd_set *set);
+
+/*
+** The next two entry points should not be in the API, but they are
+** declared here for historical reasons.
+*/
+
+NSPR_API(PRInt32) PR_GetSysfdTableMax(void);
+
+NSPR_API(PRInt32) PR_SetSysfdTableSize(PRIntn table_size);
+
+#ifndef NO_NSPR_10_SUPPORT
+#include <sys/stat.h>
+
+NSPR_API(PRInt32) PR_Stat(const char *path, struct stat *buf);
+#endif /* NO_NSPR_10_SUPPORT */
+
+PR_END_EXTERN_C
+
+#endif /* defined(PROBSLET_H) */
+
+/* probslet.h */
diff --git a/mozilla/nsprpub/pr/include/obsolete/protypes.h b/mozilla/nsprpub/pr/include/obsolete/protypes.h
new file mode 100644
index 0000000..d8e947a
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/obsolete/protypes.h
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * This header typedefs the old 'native' types to the new PR<type>s.
+ * These definitions are scheduled to be eliminated at the earliest
+ * possible time. The NSPR API is implemented and documented using
+ * the new definitions.
+ */
+
+#if !defined(PROTYPES_H)
+#define PROTYPES_H
+
+typedef PRUintn uintn;
+#ifndef _XP_Core_
+typedef PRIntn intn;
+#endif
+
+/*
+ * It is trickier to define uint, int8, uint8, int16, uint16,
+ * int32, uint32, int64, and uint64 because some of these int
+ * types are defined by standard header files on some platforms.
+ * Our strategy here is to include all such standard headers
+ * first, and then define these int types only if they are not
+ * defined by those standard headers.
+ */
+
+/*
+ * BeOS defines all the int types below in its standard header
+ * file SupportDefs.h.
+ */
+#ifdef XP_BEOS
+#include <support/SupportDefs.h>
+#endif
+
+/*
+ * SVR4 typedef of uint is commonly found on UNIX machines.
+ *
+ * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h)
+ * defines the types int8, int16, int32, and int64.
+ *
+ * On OS/2, sys/types.h defines uint.
+ */
+#if defined(XP_UNIX) || defined(XP_OS2)
+#include <sys/types.h>
+#endif
+
+/* model.h on HP-UX defines int8, int16, and int32. */
+#ifdef HPUX
+#include <model.h>
+#endif
+
+/*
+ * uint
+ */
+
+#if !defined(XP_BEOS) && !defined(XP_OS2) && !defined(XP_UNIX) || defined(NTO)
+typedef PRUintn uint;
+#endif
+
+/*
+ * uint64
+ */
+
+#if !defined(XP_BEOS)
+typedef PRUint64 uint64;
+#endif
+
+/*
+ * uint32
+ */
+
+#if !defined(XP_BEOS)
+#if !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO)
+typedef PRUint32 uint32;
+#else
+typedef unsigned long uint32;
+#endif
+#endif
+
+/*
+ * uint16
+ */
+
+#if !defined(XP_BEOS)
+typedef PRUint16 uint16;
+#endif
+
+/*
+ * uint8
+ */
+
+#if !defined(XP_BEOS)
+typedef PRUint8 uint8;
+#endif
+
+/*
+ * int64
+ */
+
+#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES)
+typedef PRInt64 int64;
+#endif
+
+/*
+ * int32
+ */
+
+#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \
+    && !defined(HPUX)
+#if !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO)
+typedef PRInt32 int32;
+#else
+typedef long int32;
+#endif
+#endif
+
+/*
+ * int16
+ */
+
+#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \
+    && !defined(HPUX)
+typedef PRInt16 int16;
+#endif
+
+/*
+ * int8
+ */
+
+#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \
+    && !defined(HPUX)
+typedef PRInt8 int8;
+#endif
+
+typedef PRFloat64 float64;
+typedef PRUptrdiff uptrdiff_t;
+typedef PRUword uprword_t;
+typedef PRWord prword_t;
+
+
+/* Re: prbit.h */
+#define TEST_BIT	PR_TEST_BIT
+#define SET_BIT		PR_SET_BIT
+#define CLEAR_BIT	PR_CLEAR_BIT
+
+/* Re: prarena.h->plarena.h */
+#define PRArena PLArena
+#define PRArenaPool PLArenaPool
+#define PRArenaStats PLArenaStats
+#define PR_ARENA_ALIGN PL_ARENA_ALIGN
+#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL
+#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE
+#define PR_ARENA_GROW PL_ARENA_GROW
+#define PR_ARENA_MARK PL_ARENA_MARK
+#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED
+#define PR_CLEAR_ARENA PL_CLEAR_ARENA
+#define PR_ARENA_RELEASE PL_ARENA_RELEASE
+#define PR_COUNT_ARENA PL_COUNT_ARENA
+#define PR_ARENA_DESTROY PL_ARENA_DESTROY
+#define PR_InitArenaPool PL_InitArenaPool
+#define PR_FreeArenaPool PL_FreeArenaPool
+#define PR_FinishArenaPool PL_FinishArenaPool
+#define PR_CompactArenaPool PL_CompactArenaPool
+#define PR_ArenaFinish PL_ArenaFinish
+#define PR_ArenaAllocate PL_ArenaAllocate
+#define PR_ArenaGrow PL_ArenaGrow
+#define PR_ArenaRelease PL_ArenaRelease
+#define PR_ArenaCountAllocation PL_ArenaCountAllocation
+#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth
+#define PR_ArenaCountGrowth PL_ArenaCountGrowth
+#define PR_ArenaCountRelease PL_ArenaCountRelease
+#define PR_ArenaCountRetract PL_ArenaCountRetract
+
+/* Re: prhash.h->plhash.h */
+#define PRHashEntry PLHashEntry
+#define PRHashTable PLHashTable
+#define PRHashNumber PLHashNumber
+#define PRHashFunction PLHashFunction
+#define PRHashComparator PLHashComparator
+#define PRHashEnumerator PLHashEnumerator
+#define PRHashAllocOps PLHashAllocOps
+#define PR_NewHashTable PL_NewHashTable
+#define PR_HashTableDestroy PL_HashTableDestroy
+#define PR_HashTableRawLookup PL_HashTableRawLookup
+#define PR_HashTableRawAdd PL_HashTableRawAdd
+#define PR_HashTableRawRemove PL_HashTableRawRemove
+#define PR_HashTableAdd PL_HashTableAdd
+#define PR_HashTableRemove PL_HashTableRemove
+#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries
+#define PR_HashTableLookup PL_HashTableLookup
+#define PR_HashTableDump PL_HashTableDump
+#define PR_HashString PL_HashString
+#define PR_CompareStrings PL_CompareStrings
+#define PR_CompareValues PL_CompareValues
+
+#endif /* !defined(PROTYPES_H) */
diff --git a/mozilla/nsprpub/pr/include/obsolete/prsem.h b/mozilla/nsprpub/pr/include/obsolete/prsem.h
new file mode 100644
index 0000000..fd0863a
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/obsolete/prsem.h
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prsem_h___
+#define prsem_h___
+
+/*
+** API for counting semaphores. Semaphores are counting synchronizing 
+** variables based on a lock and a condition variable.  They are lightweight 
+** contention control for a given count of resources.
+*/
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PRSemaphore PRSemaphore;
+
+/*
+** Create a new semaphore object.
+*/
+NSPR_API(PRSemaphore*) PR_NewSem(PRUintn value);
+
+/*
+** Destroy the given semaphore object.
+**
+*/
+NSPR_API(void) PR_DestroySem(PRSemaphore *sem);
+
+/*
+** Wait on a Semaphore.
+** 
+** This routine allows a calling thread to wait or proceed depending upon the 
+** state of the semahore sem. The thread can proceed only if the counter value 
+** of the semaphore sem is currently greater than 0. If the value of semaphore 
+** sem is positive, it is decremented by one and the routine returns immediately 
+** allowing the calling thread to continue. If the value of semaphore sem is 0, 
+** the calling thread blocks awaiting the semaphore to be released by another 
+** thread.
+** 
+** This routine can return PR_PENDING_INTERRUPT if the waiting thread 
+** has been interrupted.
+*/
+NSPR_API(PRStatus) PR_WaitSem(PRSemaphore *sem);
+
+/*
+** This routine increments the counter value of the semaphore. If other threads 
+** are blocked for the semaphore, then the scheduler will determine which ONE 
+** thread will be unblocked.
+*/
+NSPR_API(void) PR_PostSem(PRSemaphore *sem);
+
+/*
+** Returns the value of the semaphore referenced by sem without affecting
+** the state of the semaphore.  The value represents the semaphore vaule
+F** at the time of the call, but may not be the actual value when the
+** caller inspects it.
+*/
+NSPR_API(PRUintn) PR_GetValueSem(PRSemaphore *sem);
+
+PR_END_EXTERN_C
+
+#endif /* prsem_h___ */
diff --git a/mozilla/nsprpub/pr/include/pratom.h b/mozilla/nsprpub/pr/include/pratom.h
new file mode 100644
index 0000000..1c18a9f
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/pratom.h
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/* GLOBAL FUNCTIONS:
+** DESCRIPTION:
+**     PR Atomic operations
+*/
+
+#ifndef pratom_h___
+#define pratom_h___
+
+#include "prtypes.h"
+#include "prlock.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** FUNCTION: PR_AtomicIncrement
+** DESCRIPTION:
+**    Atomically increment a 32 bit value.
+** INPUTS:
+**    val:  a pointer to the value to increment
+** RETURN:
+**    the returned value is the result of the increment
+*/
+NSPR_API(PRInt32)	PR_AtomicIncrement(PRInt32 *val);
+
+/*
+** FUNCTION: PR_AtomicDecrement
+** DESCRIPTION:
+**    Atomically decrement a 32 bit value.
+** INPUTS:
+**    val:  a pointer to the value to decrement
+** RETURN:
+**    the returned value is the result of the decrement
+*/
+NSPR_API(PRInt32)	PR_AtomicDecrement(PRInt32 *val);
+
+/*
+** FUNCTION: PR_AtomicSet
+** DESCRIPTION:
+**    Atomically set a 32 bit value.
+** INPUTS:
+**    val: A pointer to a 32 bit value to be set
+**    newval: The newvalue to assign to val
+** RETURN:
+**    Returns the prior value
+*/
+NSPR_API(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval);
+
+/*
+** FUNCTION: PR_AtomicAdd
+** DESCRIPTION:
+**    Atomically add a 32 bit value.
+** INPUTS:
+**    ptr:  a pointer to the value to increment
+**	  val:  value to be added
+** RETURN:
+**    the returned value is the result of the addition
+*/
+NSPR_API(PRInt32)	PR_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+
+/*
+** MACRO: PR_ATOMIC_INCREMENT
+** MACRO: PR_ATOMIC_DECREMENT
+** MACRO: PR_ATOMIC_SET
+** MACRO: PR_ATOMIC_ADD
+** DESCRIPTION:
+**    Macro versions of the atomic operations.  They may be implemented
+**    as compiler intrinsics.
+**
+** IMPORTANT NOTE TO NSPR MAINTAINERS:
+**    Implement these macros with compiler intrinsics only on platforms
+**    where the PR_AtomicXXX functions are truly atomic (i.e., where the
+**    configuration macro _PR_HAVE_ATOMIC_OPS is defined).  Otherwise,
+**    the macros and functions won't be compatible and can't be used
+**    interchangeably.
+*/
+#if defined(_WIN32) && !defined(_WIN32_WCE) && \
+    defined(_MSC_VER) && (_MSC_VER >= 1310)
+
+long __cdecl _InterlockedIncrement(long volatile *Addend);
+#pragma intrinsic(_InterlockedIncrement)
+
+long __cdecl _InterlockedDecrement(long volatile *Addend);
+#pragma intrinsic(_InterlockedDecrement)
+
+long __cdecl _InterlockedExchange(long volatile *Target, long Value);
+#pragma intrinsic(_InterlockedExchange)
+
+long __cdecl _InterlockedExchangeAdd(long volatile *Addend, long Value);
+#pragma intrinsic(_InterlockedExchangeAdd)
+
+#define PR_ATOMIC_INCREMENT(val) _InterlockedIncrement(val)
+#define PR_ATOMIC_DECREMENT(val) _InterlockedDecrement(val)
+#define PR_ATOMIC_SET(val, newval) _InterlockedExchange(val, newval)
+#define PR_ATOMIC_ADD(ptr, val) (_InterlockedExchangeAdd(ptr, val) + (val))
+
+#elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \
+      ((defined(DARWIN) && \
+           (defined(__ppc__) || defined(__i386__))) || \
+       (defined(LINUX) && \
+           (defined(__i386__) || defined(__ia64__) || defined(__x86_64__) || \
+           (defined(__powerpc__) && !defined(__powerpc64__)) || \
+           defined(__alpha))))
+
+/*
+ * Because the GCC manual warns that some processors may support
+ * reduced functionality of __sync_lock_test_and_set, we test for the
+ * processors that we believe support a full atomic exchange operation.
+ */
+
+#define PR_ATOMIC_INCREMENT(val) __sync_add_and_fetch(val, 1)
+#define PR_ATOMIC_DECREMENT(val) __sync_sub_and_fetch(val, 1)
+#define PR_ATOMIC_SET(val, newval) __sync_lock_test_and_set(val, newval)
+#define PR_ATOMIC_ADD(ptr, val) __sync_add_and_fetch(ptr, val)
+
+#else
+
+#define PR_ATOMIC_INCREMENT(val) PR_AtomicIncrement(val)
+#define PR_ATOMIC_DECREMENT(val) PR_AtomicDecrement(val)
+#define PR_ATOMIC_SET(val, newval) PR_AtomicSet(val, newval)
+#define PR_ATOMIC_ADD(ptr, val) PR_AtomicAdd(ptr, val)
+
+#endif
+
+/*
+** LIFO linked-list (stack)
+*/
+typedef struct PRStackElemStr PRStackElem;
+
+struct PRStackElemStr {
+    PRStackElem	*prstk_elem_next;	/* next pointer MUST be at offset 0;
+									  assembly language code relies on this */
+};
+
+typedef struct PRStackStr PRStack;
+
+/*
+** FUNCTION: PR_CreateStack
+** DESCRIPTION:
+**    Create a stack, a LIFO linked list
+** INPUTS:
+**    stack_name:  a pointer to string containing the name of the stack
+** RETURN:
+**    A pointer to the created stack, if successful, else NULL.
+*/
+NSPR_API(PRStack *)	PR_CreateStack(const char *stack_name);
+
+/*
+** FUNCTION: PR_StackPush
+** DESCRIPTION:
+**    Push an element on the top of the stack
+** INPUTS:
+**    stack:		pointer to the stack
+**    stack_elem:	pointer to the stack element
+** RETURN:
+**    None
+*/
+NSPR_API(void)			PR_StackPush(PRStack *stack, PRStackElem *stack_elem);
+
+/*
+** FUNCTION: PR_StackPop
+** DESCRIPTION:
+**    Remove the element on the top of the stack
+** INPUTS:
+**    stack:		pointer to the stack
+** RETURN:
+**    A pointer to the stack element removed from the top of the stack,
+**	  if non-empty,
+**    else NULL
+*/
+NSPR_API(PRStackElem *)	PR_StackPop(PRStack *stack);
+
+/*
+** FUNCTION: PR_DestroyStack
+** DESCRIPTION:
+**    Destroy the stack
+** INPUTS:
+**    stack:		pointer to the stack
+** RETURN:
+**    PR_SUCCESS - if successfully deleted
+**	  PR_FAILURE - if the stack is not empty
+**					PR_GetError will return
+**						PR_INVALID_STATE_ERROR - stack is not empty
+*/
+NSPR_API(PRStatus)		PR_DestroyStack(PRStack *stack);
+
+PR_END_EXTERN_C
+
+#endif /* pratom_h___ */
diff --git a/mozilla/nsprpub/pr/include/prbit.h b/mozilla/nsprpub/pr/include/prbit.h
new file mode 100644
index 0000000..1f4fc84
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prbit.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prbit_h___
+#define prbit_h___
+
+#include "prtypes.h"
+PR_BEGIN_EXTERN_C
+
+/*
+** A prbitmap_t is a long integer that can be used for bitmaps
+*/
+typedef unsigned long prbitmap_t;
+
+#define PR_TEST_BIT(_map,_bit) \
+    ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] & (1L << ((_bit) & (PR_BITS_PER_LONG-1))))
+#define PR_SET_BIT(_map,_bit) \
+    ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] |= (1L << ((_bit) & (PR_BITS_PER_LONG-1))))
+#define PR_CLEAR_BIT(_map,_bit) \
+    ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] &= ~(1L << ((_bit) & (PR_BITS_PER_LONG-1))))
+
+/*
+** Compute the log of the least power of 2 greater than or equal to n
+*/
+NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i); 
+
+/*
+** Compute the log of the greatest power of 2 less than or equal to n
+*/
+NSPR_API(PRIntn) PR_FloorLog2(PRUint32 i); 
+
+/*
+** Macro version of PR_CeilingLog2: Compute the log of the least power of
+** 2 greater than or equal to _n. The result is returned in _log2.
+*/
+#define PR_CEILING_LOG2(_log2,_n)   \
+  PR_BEGIN_MACRO                    \
+    PRUint32 j_ = (PRUint32)(_n); 	\
+    (_log2) = 0;                    \
+    if ((j_) & ((j_)-1))            \
+	(_log2) += 1;               \
+    if ((j_) >> 16)                 \
+	(_log2) += 16, (j_) >>= 16; \
+    if ((j_) >> 8)                  \
+	(_log2) += 8, (j_) >>= 8;   \
+    if ((j_) >> 4)                  \
+	(_log2) += 4, (j_) >>= 4;   \
+    if ((j_) >> 2)                  \
+	(_log2) += 2, (j_) >>= 2;   \
+    if ((j_) >> 1)                  \
+	(_log2) += 1;               \
+  PR_END_MACRO
+
+/*
+** Macro version of PR_FloorLog2: Compute the log of the greatest power of
+** 2 less than or equal to _n. The result is returned in _log2.
+**
+** This is equivalent to finding the highest set bit in the word.
+*/
+#define PR_FLOOR_LOG2(_log2,_n)   \
+  PR_BEGIN_MACRO                    \
+    PRUint32 j_ = (PRUint32)(_n); 	\
+    (_log2) = 0;                    \
+    if ((j_) >> 16)                 \
+	(_log2) += 16, (j_) >>= 16; \
+    if ((j_) >> 8)                  \
+	(_log2) += 8, (j_) >>= 8;   \
+    if ((j_) >> 4)                  \
+	(_log2) += 4, (j_) >>= 4;   \
+    if ((j_) >> 2)                  \
+	(_log2) += 2, (j_) >>= 2;   \
+    if ((j_) >> 1)                  \
+	(_log2) += 1;               \
+  PR_END_MACRO
+
+/*
+** Macros for rotate left and right. The argument 'a' must be an unsigned
+** 32-bit integer type such as PRUint32.
+**
+** There is no rotate operation in the C Language, so the construct
+** (a << 4) | (a >> 28) is frequently used instead. Most compilers convert
+** this to a rotate instruction, but MSVC doesn't without a little help.
+** To get MSVC to generate a rotate instruction, we have to use the _rotl
+** or _rotr intrinsic and use a pragma to make it inline.
+**
+** Note: MSVC in VS2005 will do an inline rotate instruction on the above
+** construct.
+*/
+
+#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \
+    defined(_M_X64))
+#include <stdlib.h>
+#pragma intrinsic(_rotl, _rotr)
+#define PR_ROTATE_LEFT32(a, bits) _rotl(a, bits)
+#define PR_ROTATE_RIGHT32(a, bits) _rotr(a, bits)
+#else
+#define PR_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits))))
+#define PR_ROTATE_RIGHT32(a, bits) (((a) >> (bits)) | ((a) << (32 - (bits))))
+#endif
+
+PR_END_EXTERN_C
+#endif /* prbit_h___ */
diff --git a/mozilla/nsprpub/pr/include/prclist.h b/mozilla/nsprpub/pr/include/prclist.h
new file mode 100644
index 0000000..1680ac1
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prclist.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prclist_h___
+#define prclist_h___
+
+#include "prtypes.h"
+
+typedef struct PRCListStr PRCList;
+
+/*
+** Circular linked list
+*/
+struct PRCListStr {
+    PRCList	*next;
+    PRCList	*prev;
+};
+
+/*
+** Insert element "_e" into the list, before "_l".
+*/
+#define PR_INSERT_BEFORE(_e,_l)	 \
+    PR_BEGIN_MACRO		 \
+	(_e)->next = (_l);	 \
+	(_e)->prev = (_l)->prev; \
+	(_l)->prev->next = (_e); \
+	(_l)->prev = (_e);	 \
+    PR_END_MACRO
+
+/*
+** Insert element "_e" into the list, after "_l".
+*/
+#define PR_INSERT_AFTER(_e,_l)	 \
+    PR_BEGIN_MACRO		 \
+	(_e)->next = (_l)->next; \
+	(_e)->prev = (_l);	 \
+	(_l)->next->prev = (_e); \
+	(_l)->next = (_e);	 \
+    PR_END_MACRO
+
+/*
+** Return the element following element "_e"
+*/
+#define PR_NEXT_LINK(_e)	 \
+    	((_e)->next)
+/*
+** Return the element preceding element "_e"
+*/
+#define PR_PREV_LINK(_e)	 \
+    	((_e)->prev)
+
+/*
+** Append an element "_e" to the end of the list "_l"
+*/
+#define PR_APPEND_LINK(_e,_l) PR_INSERT_BEFORE(_e,_l)
+
+/*
+** Insert an element "_e" at the head of the list "_l"
+*/
+#define PR_INSERT_LINK(_e,_l) PR_INSERT_AFTER(_e,_l)
+
+/* Return the head/tail of the list */
+#define PR_LIST_HEAD(_l) (_l)->next
+#define PR_LIST_TAIL(_l) (_l)->prev
+
+/*
+** Remove the element "_e" from it's circular list.
+*/
+#define PR_REMOVE_LINK(_e)	       \
+    PR_BEGIN_MACRO		       \
+	(_e)->prev->next = (_e)->next; \
+	(_e)->next->prev = (_e)->prev; \
+    PR_END_MACRO
+
+/*
+** Remove the element "_e" from it's circular list. Also initializes the
+** linkage.
+*/
+#define PR_REMOVE_AND_INIT_LINK(_e)    \
+    PR_BEGIN_MACRO		       \
+	(_e)->prev->next = (_e)->next; \
+	(_e)->next->prev = (_e)->prev; \
+	(_e)->next = (_e);	       \
+	(_e)->prev = (_e);	       \
+    PR_END_MACRO
+
+/*
+** Return non-zero if the given circular list "_l" is empty, zero if the
+** circular list is not empty
+*/
+#define PR_CLIST_IS_EMPTY(_l) \
+    ((_l)->next == (_l))
+
+/*
+** Initialize a circular list
+*/
+#define PR_INIT_CLIST(_l)  \
+    PR_BEGIN_MACRO	   \
+	(_l)->next = (_l); \
+	(_l)->prev = (_l); \
+    PR_END_MACRO
+
+#define PR_INIT_STATIC_CLIST(_l) \
+    {(_l), (_l)}
+
+#endif /* prclist_h___ */
diff --git a/mozilla/nsprpub/pr/include/prcmon.h b/mozilla/nsprpub/pr/include/prcmon.h
new file mode 100644
index 0000000..f61cf56
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prcmon.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prcmon_h___
+#define prcmon_h___
+
+/*
+** Interface to cached monitors. Cached monitors use an address to find a
+** given PR monitor. In this way a monitor can be associated with another
+** object without preallocating a monitor for all objects.
+**
+** A hash table is used to quickly map addresses to individual monitors
+** and the system automatically grows the hash table as needed.
+**
+** Cache monitors are about 5 times slower to use than uncached monitors.
+*/
+#include "prmon.h"
+#include "prinrval.h"
+
+PR_BEGIN_EXTERN_C
+
+/**
+** Like PR_EnterMonitor except use the "address" to find a monitor in the
+** monitor cache. If successful, returns the PRMonitor now associated
+** with "address". Note that you must PR_CExitMonitor the address to
+** release the monitor cache entry (otherwise the monitor cache will fill
+** up). This call will return NULL if the monitor cache needs to be
+** expanded and the system is out of memory.
+*/
+NSPR_API(PRMonitor*) PR_CEnterMonitor(void *address);
+
+/*
+** Like PR_ExitMonitor except use the "address" to find a monitor in the
+** monitor cache.
+*/
+NSPR_API(PRStatus) PR_CExitMonitor(void *address);
+
+/*
+** Like PR_Wait except use the "address" to find a monitor in the
+** monitor cache.
+*/
+NSPR_API(PRStatus) PR_CWait(void *address, PRIntervalTime timeout);
+
+/*
+** Like PR_Notify except use the "address" to find a monitor in the
+** monitor cache.
+*/
+NSPR_API(PRStatus) PR_CNotify(void *address);
+
+/*
+** Like PR_NotifyAll except use the "address" to find a monitor in the
+** monitor cache.
+*/
+NSPR_API(PRStatus) PR_CNotifyAll(void *address);
+
+/*
+** Set a callback to be invoked each time a monitor is recycled from the cache
+** freelist, with the monitor's cache-key passed in address.
+*/
+NSPR_API(void) PR_CSetOnMonitorRecycle(void (PR_CALLBACK *callback)(void *address));
+
+PR_END_EXTERN_C
+
+#endif /* prcmon_h___ */
diff --git a/mozilla/nsprpub/pr/include/prcountr.h b/mozilla/nsprpub/pr/include/prcountr.h
new file mode 100644
index 0000000..4b197e9
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prcountr.h
@@ -0,0 +1,557 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prcountr_h___
+#define prcountr_h___
+
+/*----------------------------------------------------------------------------
+** prcountr.h -- NSPR Instrumentation counters
+**
+** The NSPR Counter Feature provides a means to "count
+** something." Counters can be dynamically defined, incremented,
+** decremented, set, and deleted under application program
+** control.
+** 																                   
+** The Counter Feature is intended to be used as instrumentation,                  
+** not as operational data. If you need a counter for operational                  
+** data, use native integral types.                                                
+** 																                   
+** Counters are 32bit unsigned intergers. On overflow, a counter                   
+** will wrap. No exception is recognized or reported.                              
+**                                                                                 
+** A counter can be dynamically created using a two level naming
+** convention. A "handle" is returned when the counter is
+** created. The counter can subsequently be addressed by its
+** handle. An API is provided to get an existing counter's handle
+** given the names with  which it was originally created. 
+** Similarly, a counter's name can be retrieved given its handle.
+** 
+** The counter naming convention is a two-level hierarchy. The
+** QName is the higher level of the hierarchy; RName is the
+** lower level. RNames can be thought of as existing within a
+** QName. The same RName can exist within multiple QNames. QNames
+** are unique. The NSPR Counter is not a near-zero overhead
+** feature. Application designers should be aware of 
+** serialization issues when using the Counter API. Creating a
+** counter locks a large asset, potentially causing a stall. This
+** suggest that applications should create counters at component
+** initialization, for example, and not create and destroy them
+** willy-nilly. ... You have been warned.
+** 
+** Incrementing and Adding to counters uses atomic operations.
+** The performance of these operations will vary from platform
+** to platform. On platforms where atomic operations are not
+** supported the overhead may be substantial.
+** 
+** When traversing the counter database with FindNext functions,
+** the instantaneous values of any given counter is that at the
+** moment of extraction. The state of the entire counter database
+** may not be viewed as atomic.
+** 
+** The counter interface may be disabled (No-Op'd) at compile
+** time. When DEBUG is defined at compile time, the Counter
+** Feature is compiled into NSPR and applications invoking it.
+** When DEBUG is not defined, the counter macros compile to
+** nothing. To force the Counter Feature to be compiled into an
+** optimized build, define FORCE_NSPR_COUNTERS at compile time
+** for both NSPR and the application intending to use it.
+** 
+** Application designers should use the macro form of the Counter
+** Feature methods to minimize performance impact in optimized
+** builds. The macros normally compile to nothing on optimized
+** builds.
+** 
+** Application designers should be aware of the effects of
+** debug and optimized build differences when using result of the
+** Counter Feature macros in expressions.
+** 
+** The Counter Feature is thread-safe and SMP safe.
+** 
+** /lth. 09-Jun-1998.
+*/
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Opaque counter handle type.
+** ... don't even think of looking in here.
+**
+*/
+typedef void *  PRCounterHandle;
+
+#define PRCOUNTER_NAME_MAX 31
+#define PRCOUNTER_DESC_MAX 255
+
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_DEFINE_COUNTER() -- Define a PRCounterHandle
+** 
+** DESCRIPTION: PR_DEFINE_COUNTER() is used to define a counter
+** handle.
+** 
+*/
+#define PR_DEFINE_COUNTER(name) PRCounterHandle name
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_INIT_COUNTER_HANDLE() -- Set the value of a PRCounterHandle
+** 
+** DESCRIPTION: 
+** PR_INIT_COUNTER_HANDLE() sets the value of a PRCounterHandle
+** to value.
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_INIT_COUNTER_HANDLE(handle,value)\
+    (handle) = (PRCounterHandle)(value)
+#else
+#define PR_INIT_COUNTER_HANDLE(handle,value)
+#endif
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_CreateCounter() -- Create a counter
+** 
+** DESCRIPTION: PR_CreateCounter() creates a counter object and
+** initializes it to zero.
+** 
+** The macro form takes as its first argument the name of the
+** PRCounterHandle to receive the handle returned from
+** PR_CreateCounter().
+** 
+** INPUTS:
+**  qName: The QName for the counter object. The maximum length
+** of qName is defined by PRCOUNTER_NAME_MAX
+** 
+**  rName: The RName for the counter object. The maximum length
+** of qName is defined by PRCOUNTER_NAME_MAX
+** 
+**  descrioption: The description of the counter object. The
+** maximum length of description is defined by
+** PRCOUNTER_DESC_MAX.
+** 
+** OUTPUTS:
+** 
+** RETURNS:
+**  PRCounterHandle.
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_CREATE_COUNTER(handle,qName,rName,description)\
+   (handle) = PR_CreateCounter((qName),(rName),(description))
+#else
+#define PR_CREATE_COUNTER(handle,qName,rName,description)
+#endif
+
+NSPR_API(PRCounterHandle) 
+	PR_CreateCounter( 
+		const char *qName, 
+    	const char *rName, 
+        const char *description 
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_DestroyCounter() -- Destroy a counter object.
+** 
+** DESCRIPTION: PR_DestroyCounter() removes a counter and
+** unregisters its handle from the counter database.
+** 
+** INPUTS:
+**  handle: the PRCounterHandle of the counter to be destroyed.
+** 
+** OUTPUTS: 
+**  The counter is destroyed.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_DESTROY_COUNTER(handle) PR_DestroyCounter((handle))
+#else
+#define PR_DESTROY_COUNTER(handle)
+#endif
+
+NSPR_API(void) 
+	PR_DestroyCounter( 
+		PRCounterHandle handle 
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_GetCounterHandleFromName() -- Retreive a
+** counter's handle give its name.
+** 
+** DESCRIPTION: PR_GetCounterHandleFromName() retreives a
+** counter's handle from the counter database, given the name
+** the counter was originally created with.
+** 
+** INPUTS:
+**  qName: Counter's original QName.
+**  rName: Counter's original RName.
+** 
+** OUTPUTS:
+** 
+** RETURNS: 
+**  PRCounterHandle or PRCounterError.
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName)\
+    (handle) = PR_GetCounterHandleFromName((qName),(rName))
+#else
+#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName)
+#endif
+
+NSPR_API(PRCounterHandle) 
+	PR_GetCounterHandleFromName( 
+    	const char *qName, 
+    	const char *rName 
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_GetCounterNameFromHandle() -- Retreive a
+** counter's name, given its handle.
+** 
+** DESCRIPTION: PR_GetCounterNameFromHandle() retreives a
+** counter's name given its handle.
+** 
+** INPUTS:
+**  qName: Where to store a pointer to qName.
+**  rName: Where to store a pointer to rName.
+**  description: Where to store a pointer to description.
+** 
+** OUTPUTS: Pointers to the Counter Feature's copies of the names
+** used when the counters were created.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description)\
+    PR_GetCounterNameFromHandle((handle),(qName),(rName),(description))
+#else
+#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description )
+#endif
+
+NSPR_API(void) 
+	PR_GetCounterNameFromHandle( 
+    	PRCounterHandle handle,  
+	    const char **qName, 
+	    const char **rName, 
+		const char **description 
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_IncrementCounter() -- Add one to the referenced
+** counter.
+** 
+** DESCRIPTION: Add one to the referenced counter.
+** 
+** INPUTS:
+**  handle: The PRCounterHandle of the counter to be incremented
+** 
+** OUTPUTS: The counter is incrementd.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_INCREMENT_COUNTER(handle) PR_IncrementCounter(handle)
+#else
+#define PR_INCREMENT_COUNTER(handle)
+#endif
+
+NSPR_API(void) 
+	PR_IncrementCounter( 
+		PRCounterHandle handle
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_DecrementCounter() -- Subtract one from the
+** referenced counter
+** 
+** DESCRIPTION: Subtract one from the referenced counter.
+** 
+** INPUTS: 
+**  handle: The PRCounterHandle of the coutner to be
+** decremented.
+** 
+** OUTPUTS: the counter is decremented.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_DECREMENT_COUNTER(handle) PR_DecrementCounter(handle)
+#else
+#define PR_DECREMENT_COUNTER(handle)
+#endif
+
+NSPR_API(void) 
+	PR_DecrementCounter( 
+		PRCounterHandle handle
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_AddToCounter() -- Add a value to a counter.
+** 
+** DESCRIPTION: Add value to the counter referenced by handle.
+** 
+** INPUTS:
+**  handle: the PRCounterHandle of the counter to be added to.
+** 
+**  value: the value to be added to the counter.
+** 
+** OUTPUTS: new value for counter.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_ADD_TO_COUNTER(handle,value)\
+    PR_AddToCounter((handle),(value))
+#else
+#define PR_ADD_TO_COUNTER(handle,value)
+#endif
+
+NSPR_API(void) 
+	PR_AddToCounter( 
+    	PRCounterHandle handle, 
+	    PRUint32 value 
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_SubtractFromCounter() -- A value is subtracted
+** from a counter.
+** 
+** DESCRIPTION:
+** Subtract a value from a counter.
+** 
+** INPUTS:
+**  handle: the PRCounterHandle of the counter to be subtracted
+** from.
+** 
+**  value: the value to be subtracted from the counter.
+** 
+** OUTPUTS: new value for counter
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_SUBTRACT_FROM_COUNTER(handle,value)\
+    PR_SubtractFromCounter((handle),(value))
+#else
+#define PR_SUBTRACT_FROM_COUNTER(handle,value)
+#endif
+
+NSPR_API(void) 
+	PR_SubtractFromCounter( 
+    	PRCounterHandle handle, 
+	    PRUint32 value 
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_GetCounter() -- Retreive the value of a counter
+** 
+** DESCRIPTION:
+** Retreive the value of a counter.
+** 
+** INPUTS:
+**  handle: the PR_CounterHandle of the counter to be retreived
+** 
+** OUTPUTS:
+** 
+** RETURNS: The value of the referenced counter
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_GET_COUNTER(counter,handle)\
+    (counter) = PR_GetCounter((handle))
+#else
+#define PR_GET_COUNTER(counter,handle) 0
+#endif
+
+NSPR_API(PRUint32) 
+	PR_GetCounter( 
+		PRCounterHandle handle 
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_SetCounter() -- Replace the content of counter
+** with value.
+** 
+** DESCRIPTION: The contents of the referenced counter are
+** replaced by value.
+** 
+** INPUTS:
+**  handle: the PRCounterHandle of the counter whose contents
+** are to be replaced.
+** 
+**  value: the new value of the counter.
+** 
+** OUTPUTS:
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_SET_COUNTER(handle,value) PR_SetCounter((handle),(value))
+#else
+#define PR_SET_COUNTER(handle,value)
+#endif
+
+NSPR_API(void) 
+	PR_SetCounter( 
+		PRCounterHandle handle, 
+		PRUint32 value 
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_FindNextCounterQname() -- Retreive the next QName counter
+** handle iterator
+** 
+** DESCRIPTION:
+** PR_FindNextCounterQname() retreives the first or next Qname
+** the counter data base, depending on the value of handle. When
+** handle is NULL, the function attempts to retreive the first
+** QName handle in the database. When handle is a handle previosly
+** retreived QName handle, then the function attempts to retreive
+** the next QName handle.
+** 
+** INPUTS: 
+**  handle: PRCounterHandle or NULL.
+** 
+** OUTPUTS: returned
+** 
+** RETURNS: PRCounterHandle or NULL when no more QName counter
+** handles are present.
+** 
+** RESTRICTIONS:
+**  A concurrent PR_CreateCounter() or PR_DestroyCounter() may
+** cause unpredictable results.
+** 
+** A PRCounterHandle returned from this function may only be used
+** in another PR_FindNextCounterQname() function call; other
+** operations may cause unpredictable results.
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_FIND_NEXT_COUNTER_QNAME(next,handle)\
+    (next) = PR_FindNextCounterQname((handle))
+#else
+#define PR_FIND_NEXT_COUNTER_QNAME(next,handle) NULL
+#endif
+
+NSPR_API(PRCounterHandle) 
+	PR_FindNextCounterQname( 
+        PRCounterHandle handle
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_FindNextCounterRname() -- Retreive the next RName counter
+** handle iterator
+** 
+** DESCRIPTION:
+** PR_FindNextCounterRname() retreives the first or next RNname
+** handle from the counter data base, depending on the
+** value of handle. When handle is NULL, the function attempts to
+** retreive the first RName handle in the database. When handle is
+** a handle previosly retreived RName handle, then the function
+** attempts to retreive the next RName handle.
+** 
+** INPUTS:
+**  handle: PRCounterHandle or NULL.
+**  qhandle: PRCounterHandle of a previously aquired via
+** PR_FIND_NEXT_QNAME_HANDLE()
+** 
+** OUTPUTS: returned
+** 
+** RETURNS: PRCounterHandle or NULL when no more RName counter
+** handles are present.
+** 
+** RESTRICTIONS:
+**  A concurrent PR_CreateCounter() or PR_DestroyCounter() may
+** cause unpredictable results.
+** 
+** A PRCounterHandle returned from this function may only be used
+** in another PR_FindNextCounterRname() function call; other
+** operations may cause unpredictable results.
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)
+#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle)\
+    (next) = PR_FindNextCounterRname((rhandle),(qhandle))
+#else
+#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle)
+#endif
+
+NSPR_API(PRCounterHandle) 
+	PR_FindNextCounterRname( 
+        PRCounterHandle rhandle,
+        PRCounterHandle qhandle
+);
+
+PR_END_EXTERN_C
+
+#endif /* prcountr_h___ */
diff --git a/mozilla/nsprpub/pr/include/prcpucfg.h b/mozilla/nsprpub/pr/include/prcpucfg.h
new file mode 100644
index 0000000..dbd0203
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prcpucfg.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#if defined(_WIN32)
+#include "md/_win95.cfg"
+#elif defined(__APPLE__)
+#include "md/_darwin.cfg"
+#else
+#error Add a case for your platform
+#endif
diff --git a/mozilla/nsprpub/pr/include/prcvar.h b/mozilla/nsprpub/pr/include/prcvar.h
new file mode 100644
index 0000000..c668493
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prcvar.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prcvar_h___
+#define prcvar_h___
+
+#include "prlock.h"
+#include "prinrval.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PRCondVar PRCondVar;
+
+/*
+** Create a new condition variable.
+**
+** 	"lock" is the lock used to protect the condition variable.
+**
+** Condition variables are synchronization objects that threads can use
+** to wait for some condition to occur.
+**
+** This may fail if memory is tight or if some operating system resource
+** is low. In such cases, a NULL will be returned.
+*/
+NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock);
+
+/*
+** Destroy a condition variable. There must be no thread
+** waiting on the condvar. The caller is responsible for guaranteeing
+** that the condvar is no longer in use.
+**
+*/
+NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar);
+
+/*
+** The thread that waits on a condition is blocked in a "waiting on
+** condition" state until another thread notifies the condition or a
+** caller specified amount of time expires. The lock associated with
+** the condition variable will be released, which must have be held
+** prior to the call to wait.
+**
+** Logically a notified thread is moved from the "waiting on condition"
+** state and made "ready." When scheduled, it will attempt to reacquire
+** the lock that it held when wait was called.
+**
+** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and
+** PR_INTERVAL_NO_WAIT. The former value requires that a condition be
+** notified (or the thread interrupted) before it will resume from the
+** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect
+** is to release the lock, possibly causing a rescheduling within the
+** runtime, then immediately attempting to reacquire the lock and resume.
+**
+** Any other value for timeout will cause the thread to be rescheduled
+** either due to explicit notification or an expired interval. The latter
+** must be determined by treating time as one part of the monitored data
+** being protected by the lock and tested explicitly for an expired
+** interval.
+**
+** Returns PR_FAILURE if the caller has not locked the lock associated
+** with the condition variable or the thread was interrupted (PR_Interrupt()).
+** The particular reason can be extracted with PR_GetError().
+*/
+NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout);
+
+/*
+** Notify ONE thread that is currently waiting on 'cvar'. Which thread is
+** dependent on the implementation of the runtime. Common sense would dictate
+** that all threads waiting on a single condition have identical semantics,
+** therefore which one gets notified is not significant. 
+**
+** The calling thead must hold the lock that protects the condition, as
+** well as the invariants that are tightly bound to the condition, when
+** notify is called.
+**
+** Returns PR_FAILURE if the caller has not locked the lock associated
+** with the condition variable.
+*/
+NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar);
+
+/*
+** Notify all of the threads waiting on the condition variable. The order
+** that the threads are notified is indeterminant. The lock that protects
+** the condition must be held.
+**
+** Returns PR_FAILURE if the caller has not locked the lock associated
+** with the condition variable.
+*/
+NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar);
+
+PR_END_EXTERN_C
+
+#endif /* prcvar_h___ */
diff --git a/mozilla/nsprpub/pr/include/prdtoa.h b/mozilla/nsprpub/pr/include/prdtoa.h
new file mode 100644
index 0000000..c71725a
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prdtoa.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prdtoa_h___
+#define prdtoa_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** PR_strtod() returns as a double-precision floating-point number
+** the  value represented by the character string pointed to by
+** s00. The string is scanned up to the first unrecognized
+** character.
+**a
+** If the value of se is not (char **)NULL, a  pointer  to
+** the  character terminating the scan is returned in the location pointed
+** to by se. If no number can be formed, se is set to s00, and
+** zero is returned.
+*/
+NSPR_API(PRFloat64)
+PR_strtod(const char *s00, char **se);
+
+/*
+** PR_cnvtf()
+** conversion routines for floating point
+** prcsn - number of digits of precision to generate floating
+** point value.
+*/
+NSPR_API(void) PR_cnvtf(char *buf, PRIntn bufsz, PRIntn prcsn, PRFloat64 fval);
+
+/*
+** PR_dtoa() converts double to a string.
+**
+** ARGUMENTS:
+** If rve is not null, *rve is set to point to the end of the return value.
+** If d is +-Infinity or NaN, then *decpt is set to 9999.
+**
+** mode:
+**     0 ==> shortest string that yields d when read in
+**           and rounded to nearest.
+*/
+NSPR_API(PRStatus) PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits,
+	PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize);
+
+PR_END_EXTERN_C
+
+#endif /* prdtoa_h___ */
diff --git a/mozilla/nsprpub/pr/include/prenv.h b/mozilla/nsprpub/pr/include/prenv.h
new file mode 100644
index 0000000..c73fffc
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prenv.h
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prenv_h___
+#define prenv_h___
+
+#include "prtypes.h"
+
+/*******************************************************************************/
+/*******************************************************************************/
+/****************** THESE FUNCTIONS MAY NOT BE THREAD SAFE *********************/
+/*******************************************************************************/
+/*******************************************************************************/
+
+PR_BEGIN_EXTERN_C
+
+/*
+** PR_GetEnv() -- Retrieve value of environment variable
+** 
+** Description:
+** PR_GetEnv() is modeled on Unix getenv().
+** 
+** 
+** Inputs: 
+**   var -- The name of the environment variable
+** 
+** Returns:
+**   The value of the environment variable 'var' or NULL if
+** the variable is undefined.
+** 
+** Restrictions:
+**   You'd think that a POSIX getenv(), putenv() would be
+**   consistently implemented everywhere. Surprise! It is not. On
+**   some platforms, a putenv() where the argument is of
+**   the form "name"  causes the named environment variable to
+**   be un-set; that is: a subsequent getenv() returns NULL. On
+**   other platforms, the putenv() fails, on others, it is a
+**   no-op. Similarly, a putenv() where the argument is of the
+**   form "name=" causes the named environment variable to be
+**   un-set; a subsequent call to getenv() returns NULL. On
+**   other platforms, a subsequent call to getenv() returns a
+**   pointer to a null-string (a byte of zero).
+** 
+**   PR_GetEnv(), PR_SetEnv() provide a consistent behavior 
+**   across all supported platforms. There are, however, some
+**   restrictions and some practices you must use to achieve
+**   consistent results everywhere.
+** 
+**   When manipulating the environment there is no way to un-set
+**   an environment variable across all platforms. We suggest
+**   you interpret the return of a pointer to null-string to
+**   mean the same as a return of NULL from PR_GetEnv().
+** 
+**   A call to PR_SetEnv() where the parameter is of the form
+**   "name" will return PR_FAILURE; the environment remains
+**   unchanged. A call to PR_SetEnv() where the parameter is
+**   of the form "name=" may un-set the envrionment variable on
+**   some platforms; on others it may set the value of the
+**   environment variable to the null-string.
+** 
+**   For example, to test for NULL return or return of the
+**   null-string from PR_GetEnv(), use the following code
+**   fragment:
+** 
+**      char *val = PR_GetEnv("foo");
+**      if ((NULL == val) || ('\0' == *val)) { 
+**          ... interpret this as un-set ... 
+**      }
+** 
+**   The caller must ensure that the string passed
+**   to PR_SetEnv() is persistent. That is: The string should
+**   not be on the stack, where it can be overwritten
+**   on return from the function calling PR_SetEnv().
+**   Similarly, the string passed to PR_SetEnv() must not be
+**   overwritten by other actions of the process. ... Some
+**   platforms use the string by reference rather than copying
+**   it into the environment space. ... You have been warned!
+** 
+**   Use of platform-native functions that manipulate the
+**   environment (getenv(), putenv(), 
+**   SetEnvironmentVariable(), etc.) must not be used with
+**   NSPR's similar functions. The platform-native functions
+**   may not be thread safe and/or may operate on different
+**   conceptual environment space than that operated upon by
+**   NSPR's functions or other environment manipulating
+**   functions on the same platform. (!)
+** 
+*/
+NSPR_API(char*) PR_GetEnv(const char *var);
+
+/*
+** PR_SetEnv() -- set, unset or change an environment variable
+** 
+** Description:
+** PR_SetEnv() is modeled on the Unix putenv() function.
+** 
+** Inputs: 
+**   string -- pointer to a caller supplied
+**   constant, persistent string of the form name=value. Where
+**   name is the name of the environment variable to be set or
+**   changed; value is the value assigned to the variable.
+**
+** Returns: 
+**   PRStatus.
+** 
+** Restrictions: 
+**   See the Restrictions documented in the description of
+**   PR_GetEnv() in this header file.
+** 
+** 
+*/
+NSPR_API(PRStatus) PR_SetEnv(const char *string);
+
+PR_END_EXTERN_C
+
+#endif /* prenv_h___ */
diff --git a/mozilla/nsprpub/pr/include/prerr.h b/mozilla/nsprpub/pr/include/prerr.h
new file mode 100644
index 0000000..eba68f1
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prerr.h
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prerr_h___
+#define prerr_h___
+
+/*
+ *
+ * prerr.h
+ * This file is automatically generated; please do not edit it.
+ */
+
+/* Memory allocation attempt failed */
+#define PR_OUT_OF_MEMORY_ERROR                   (-6000L)
+
+/* Invalid file descriptor */
+#define PR_BAD_DESCRIPTOR_ERROR                  (-5999L)
+
+/* The operation would have blocked */
+#define PR_WOULD_BLOCK_ERROR                     (-5998L)
+
+/* Invalid memory address argument */
+#define PR_ACCESS_FAULT_ERROR                    (-5997L)
+
+/* Invalid function for file type */
+#define PR_INVALID_METHOD_ERROR                  (-5996L)
+
+/* Invalid memory address argument */
+#define PR_ILLEGAL_ACCESS_ERROR                  (-5995L)
+
+/* Some unknown error has occurred */
+#define PR_UNKNOWN_ERROR                         (-5994L)
+
+/* Operation interrupted by another thread */
+#define PR_PENDING_INTERRUPT_ERROR               (-5993L)
+
+/* function not implemented */
+#define PR_NOT_IMPLEMENTED_ERROR                 (-5992L)
+
+/* I/O function error */
+#define PR_IO_ERROR                              (-5991L)
+
+/* I/O operation timed out */
+#define PR_IO_TIMEOUT_ERROR                      (-5990L)
+
+/* I/O operation on busy file descriptor */
+#define PR_IO_PENDING_ERROR                      (-5989L)
+
+/* The directory could not be opened */
+#define PR_DIRECTORY_OPEN_ERROR                  (-5988L)
+
+/* Invalid function argument */
+#define PR_INVALID_ARGUMENT_ERROR                (-5987L)
+
+/* Network address not available (in use?) */
+#define PR_ADDRESS_NOT_AVAILABLE_ERROR           (-5986L)
+
+/* Network address type not supported */
+#define PR_ADDRESS_NOT_SUPPORTED_ERROR           (-5985L)
+
+/* Already connected */
+#define PR_IS_CONNECTED_ERROR                    (-5984L)
+
+/* Network address is invalid */
+#define PR_BAD_ADDRESS_ERROR                     (-5983L)
+
+/* Local Network address is in use */
+#define PR_ADDRESS_IN_USE_ERROR                  (-5982L)
+
+/* Connection refused by peer */
+#define PR_CONNECT_REFUSED_ERROR                 (-5981L)
+
+/* Network address is presently unreachable */
+#define PR_NETWORK_UNREACHABLE_ERROR             (-5980L)
+
+/* Connection attempt timed out */
+#define PR_CONNECT_TIMEOUT_ERROR                 (-5979L)
+
+/* Network file descriptor is not connected */
+#define PR_NOT_CONNECTED_ERROR                   (-5978L)
+
+/* Failure to load dynamic library */
+#define PR_LOAD_LIBRARY_ERROR                    (-5977L)
+
+/* Failure to unload dynamic library */
+#define PR_UNLOAD_LIBRARY_ERROR                  (-5976L)
+
+/* Symbol not found in any of the loaded dynamic libraries */
+#define PR_FIND_SYMBOL_ERROR                     (-5975L)
+
+/* Insufficient system resources */
+#define PR_INSUFFICIENT_RESOURCES_ERROR          (-5974L)
+
+/* A directory lookup on a network address has failed */
+#define PR_DIRECTORY_LOOKUP_ERROR                (-5973L)
+
+/* Attempt to access a TPD key that is out of range */
+#define PR_TPD_RANGE_ERROR                       (-5972L)
+
+/* Process open FD table is full */
+#define PR_PROC_DESC_TABLE_FULL_ERROR            (-5971L)
+
+/* System open FD table is full */
+#define PR_SYS_DESC_TABLE_FULL_ERROR             (-5970L)
+
+/* Network operation attempted on non-network file descriptor */
+#define PR_NOT_SOCKET_ERROR                      (-5969L)
+
+/* TCP-specific function attempted on a non-TCP file descriptor */
+#define PR_NOT_TCP_SOCKET_ERROR                  (-5968L)
+
+/* TCP file descriptor is already bound */
+#define PR_SOCKET_ADDRESS_IS_BOUND_ERROR         (-5967L)
+
+/* Access Denied */
+#define PR_NO_ACCESS_RIGHTS_ERROR                (-5966L)
+
+/* The requested operation is not supported by the platform */
+#define PR_OPERATION_NOT_SUPPORTED_ERROR         (-5965L)
+
+/* The host operating system does not support the protocol requested */
+#define PR_PROTOCOL_NOT_SUPPORTED_ERROR          (-5964L)
+
+/* Access to the remote file has been severed */
+#define PR_REMOTE_FILE_ERROR                     (-5963L)
+
+/* The value requested is too large to be stored in the data buffer provided */
+#define PR_BUFFER_OVERFLOW_ERROR                 (-5962L)
+
+/* TCP connection reset by peer */
+#define PR_CONNECT_RESET_ERROR                   (-5961L)
+
+/* Unused */
+#define PR_RANGE_ERROR                           (-5960L)
+
+/* The operation would have deadlocked */
+#define PR_DEADLOCK_ERROR                        (-5959L)
+
+/* The file is already locked */
+#define PR_FILE_IS_LOCKED_ERROR                  (-5958L)
+
+/* Write would result in file larger than the system allows */
+#define PR_FILE_TOO_BIG_ERROR                    (-5957L)
+
+/* The device for storing the file is full */
+#define PR_NO_DEVICE_SPACE_ERROR                 (-5956L)
+
+/* Unused */
+#define PR_PIPE_ERROR                            (-5955L)
+
+/* Unused */
+#define PR_NO_SEEK_DEVICE_ERROR                  (-5954L)
+
+/* Cannot perform a normal file operation on a directory */
+#define PR_IS_DIRECTORY_ERROR                    (-5953L)
+
+/* Symbolic link loop */
+#define PR_LOOP_ERROR                            (-5952L)
+
+/* File name is too long */
+#define PR_NAME_TOO_LONG_ERROR                   (-5951L)
+
+/* File not found */
+#define PR_FILE_NOT_FOUND_ERROR                  (-5950L)
+
+/* Cannot perform directory operation on a normal file */
+#define PR_NOT_DIRECTORY_ERROR                   (-5949L)
+
+/* Cannot write to a read-only file system */
+#define PR_READ_ONLY_FILESYSTEM_ERROR            (-5948L)
+
+/* Cannot delete a directory that is not empty */
+#define PR_DIRECTORY_NOT_EMPTY_ERROR             (-5947L)
+
+/* Cannot delete or rename a file object while the file system is busy */
+#define PR_FILESYSTEM_MOUNTED_ERROR              (-5946L)
+
+/* Cannot rename a file to a file system on another device */
+#define PR_NOT_SAME_DEVICE_ERROR                 (-5945L)
+
+/* The directory object in the file system is corrupted */
+#define PR_DIRECTORY_CORRUPTED_ERROR             (-5944L)
+
+/* Cannot create or rename a filename that already exists */
+#define PR_FILE_EXISTS_ERROR                     (-5943L)
+
+/* Directory is full.  No additional filenames may be added */
+#define PR_MAX_DIRECTORY_ENTRIES_ERROR           (-5942L)
+
+/* The required device was in an invalid state */
+#define PR_INVALID_DEVICE_STATE_ERROR            (-5941L)
+
+/* The device is locked */
+#define PR_DEVICE_IS_LOCKED_ERROR                (-5940L)
+
+/* No more entries in the directory */
+#define PR_NO_MORE_FILES_ERROR                   (-5939L)
+
+/* Encountered end of file */
+#define PR_END_OF_FILE_ERROR                     (-5938L)
+
+/* Seek error */
+#define PR_FILE_SEEK_ERROR                       (-5937L)
+
+/* The file is busy */
+#define PR_FILE_IS_BUSY_ERROR                    (-5936L)
+
+/* The I/O operation was aborted */
+#define PR_OPERATION_ABORTED_ERROR               (-5935L)
+
+/* Operation is still in progress (probably a non-blocking connect) */
+#define PR_IN_PROGRESS_ERROR                     (-5934L)
+
+/* Operation has already been initiated (probably a non-blocking connect) */
+#define PR_ALREADY_INITIATED_ERROR               (-5933L)
+
+/* The wait group is empty */
+#define PR_GROUP_EMPTY_ERROR                     (-5932L)
+
+/* Object state improper for request */
+#define PR_INVALID_STATE_ERROR                   (-5931L)
+
+/* Network is down */
+#define PR_NETWORK_DOWN_ERROR                    (-5930L)
+
+/* Socket shutdown */
+#define PR_SOCKET_SHUTDOWN_ERROR                 (-5929L)
+
+/* Connection aborted */
+#define PR_CONNECT_ABORTED_ERROR                 (-5928L)
+
+/* Host is unreachable */
+#define PR_HOST_UNREACHABLE_ERROR                (-5927L)
+
+/* The library is not loaded */
+#define PR_LIBRARY_NOT_LOADED_ERROR              (-5926L)
+
+/* The one-time function was previously called and failed. Its error code is no longer available */
+#define PR_CALL_ONCE_ERROR                       (-5925L)
+
+/* Placeholder for the end of the list */
+#define PR_MAX_ERROR                             (-5924L)
+
+extern void nspr_InitializePRErrorTable(void);
+#define ERROR_TABLE_BASE_nspr (-6000L)
+
+#endif /* prerr_h___ */
diff --git a/mozilla/nsprpub/pr/include/prerror.h b/mozilla/nsprpub/pr/include/prerror.h
new file mode 100644
index 0000000..cf94872
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prerror.h
@@ -0,0 +1,326 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prerror_h___
+#define prerror_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef PRInt32 PRErrorCode;
+
+#define PR_NSPR_ERROR_BASE -6000
+
+#include "prerr.h"
+
+/*
+** Set error will preserve an error condition within a thread context.
+** The values stored are the NSPR (platform independent) translation of
+** the error. Also, if available, the platform specific oserror is stored.
+** If there is no appropriate OS error number, a zero my be supplied.
+*/
+NSPR_API(void) PR_SetError(PRErrorCode errorCode, PRInt32 oserr);
+
+/*
+** The text value specified may be NULL. If it is not NULL and the text length
+** is zero, the string is assumed to be a null terminated C string. Otherwise
+** the text is assumed to be the length specified and possibly include NULL
+** characters (e.g., a multi-national string).
+**
+** The text will be copied into to thread structure and remain there
+** until the next call to PR_SetError.
+*/
+NSPR_API(void) PR_SetErrorText(
+    PRIntn textLength, const char *text);
+
+/*
+** Return the current threads last set error code.
+*/
+NSPR_API(PRErrorCode) PR_GetError(void);
+
+/*
+** Return the current threads last set os error code. This is used for
+** machine specific code that desires the underlying os error.
+*/
+NSPR_API(PRInt32) PR_GetOSError(void);
+
+/*
+** Get the length of the error text. If a zero is returned, then there
+** is no text. Otherwise, the value returned is sufficient to contain
+** the error text currently available.
+*/
+NSPR_API(PRInt32) PR_GetErrorTextLength(void);
+
+/*
+** Copy the current threads current error text. Then actual number of bytes
+** copied is returned as the result. If the result is zero, the 'text' area
+** is unaffected.
+*/
+NSPR_API(PRInt32) PR_GetErrorText(char *text);
+
+
+/*
+Copyright (C) 1987, 1988 Student Information Processing Board of the
+Massachusetts Institute of Technology.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.  M.I.T. and the M.I.T. S.I.P.B.
+make no representations about the suitability of this software for any
+purpose.  It is provided "as is" without express or implied warranty.
+*/
+
+
+/*
+ * NOTE:
+ *		The interfaces for error-code-translation described in the rest of
+ *		this file are preliminary in the 3.1 release of nspr and are subject 
+ *		to change in future releases.
+ */
+
+/*
+** Description:	Localizable error code to string function.
+**
+**
+** NSPR provides a mechanism for converting an error code to a
+** descriptive string, in a caller-specified language.
+**
+** Error codes themselves are 32 bit (signed) integers.  Typically,
+** the high order 24 bits are an identifier of which error table the
+** error code is from, and the low order 8 bits are a sequential error
+** number within the table.  NSPR supports error tables whose first
+** error code is not a multiple of 256, such error code assignments
+** should be avoided when possible.
+**
+** Error table 0 is defined to match the UNIX system call error table
+** (sys_errlist); this allows errno values to be used directly in the
+** library.  Other error table numbers are typically formed by
+** compacting together the first four characters of the error table
+** name.  The mapping between characters in the name and numeric
+** values in the error code are defined in a system-independent
+** fashion, so that two systems that can pass integral values between
+** them can reliably pass error codes without loss of meaning; this
+** should work even if the character sets used are not the
+** same. (However, if this is to be done, error table 0 should be
+** avoided, since the local system call error tables may differ.)
+**
+** Libraries defining error codes need only provide a table mapping
+** error code numbers to names and default English descriptions,
+** calling a routine to install the table, making it ``known'' to NSPR
+** library.  Once installed, a table may not be removed.  Any error
+** code the library generates can be converted to the corresponding
+** error message.  There is also a default format for error codes
+** accidentally returned before making the table known, which is of
+** the form "unknown code foo 32", where "foo" would be the name of
+** the table.
+**
+** Normally, the error code conversion routine only supports the
+** languages "i-default" and "en", returning the error-table-provided
+** English description for both languages.  The application may
+** provide a localization plugin, allowing support for additional
+** languages.
+**
+**/
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+/*
+ * PRLanguageCode --
+ *
+ *    NSPR represents a language code as a non-negative integer.
+ *    Languages 0 is always "i-default" the language you get without
+ *    explicit negotiation.  Language 1 is always "en", English
+ *    which has been explicitly negotiated.  Additional language
+ *    codes are defined by an application-provided localization plugin.
+ */
+typedef PRUint32 PRLanguageCode;
+#define PR_LANGUAGE_I_DEFAULT 0 /* i-default, the default language */
+#define PR_LANGUAGE_EN 1 /* English, explicitly negotiated */
+
+/*
+ * struct PRErrorMessage --
+ *
+ *    An error message in an error table.
+ */
+struct PRErrorMessage {
+    const char * name;    /* Macro name for error */
+    const char * en_text; /* Default English text */
+};
+
+/*
+ * struct PRErrorTable --
+ *
+ *    An error table, provided by a library.
+ */
+struct PRErrorTable {
+    const struct PRErrorMessage * msgs; /* Array of error information */
+    const char *name; /* Name of error table source */
+    PRErrorCode base; /* Error code for first error in table */
+    int n_msgs; /* Number of codes in table */
+};
+
+/*
+ * struct PRErrorCallbackPrivate --
+ *
+ *    A private structure for the localization plugin 
+ */
+struct PRErrorCallbackPrivate;
+
+/*
+ * struct PRErrorCallbackTablePrivate --
+ *
+ *    A data structure under which the localization plugin may store information,
+ *    associated with an error table, that is private to itself.
+ */
+struct PRErrorCallbackTablePrivate;
+
+/*
+ * PRErrorCallbackLookupFn --
+ *
+ *    A function of PRErrorCallbackLookupFn type is a localization
+ *    plugin callback which converts an error code into a description
+ *    in the requested language.  The callback is provided the
+ *    appropriate error table, private data for the plugin and the table.
+ *    The callback returns the appropriate UTF-8 encoded description, or NULL
+ *    if no description can be found.
+ */
+typedef const char *
+PRErrorCallbackLookupFn(PRErrorCode code, PRLanguageCode language, 
+		   const struct PRErrorTable *table,
+		   struct PRErrorCallbackPrivate *cb_private,
+		   struct PRErrorCallbackTablePrivate *table_private);
+
+/*
+ * PRErrorCallbackNewTableFn --
+ *
+ *    A function PRErrorCallbackNewTableFn type is a localization plugin
+ *    callback which is called once with each error table registered
+ *    with NSPR.  The callback is provided with the error table and
+ *    the plugin's private structure.  The callback returns any table private
+ *    data it wishes to associate with the error table.  Does not need to be thread
+ *    safe.
+ */
+typedef struct PRErrorCallbackTablePrivate *
+PRErrorCallbackNewTableFn(const struct PRErrorTable *table,
+			struct PRErrorCallbackPrivate *cb_private);
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+/***********************************************************************
+** FUNCTION:    PR_ErrorToString
+** DESCRIPTION:
+**  Returns the UTF-8 message for an error code in
+**  the requested language.  May return the message
+**  in the default language if a translation in the requested
+**  language is not available.  The returned string is
+**  valid for the duration of the process.  Never returns NULL.
+**
+***********************************************************************/
+NSPR_API(const char *) PR_ErrorToString(PRErrorCode code,
+    PRLanguageCode language);
+
+
+/***********************************************************************
+** FUNCTION:    PR_ErrorToName
+** DESCRIPTION:
+**  Returns the macro name for an error code, or NULL
+**  if the error code is not known.  The returned string is
+**  valid for the duration of the process.
+**
+**  Does not work for error table 0, the system error codes.
+**
+***********************************************************************/
+NSPR_API(const char *) PR_ErrorToName(PRErrorCode code);
+
+
+/***********************************************************************
+** FUNCTION:    PR_ErrorLanguages
+** DESCRIPTION:
+**  Returns the RFC 1766 language tags for the language
+**  codes PR_ErrorToString() supports.  The returned array is valid
+**  for the duration of the process.  Never returns NULL.  The first
+**  item in the returned array is the language tag for PRLanguageCode 0,
+**  the second is for PRLanguageCode 1, and so on.  The array is terminated
+**  with a null pointer.
+**
+***********************************************************************/
+NSPR_API(const char * const *) PR_ErrorLanguages(void);
+
+
+/***********************************************************************
+** FUNCTION:    PR_ErrorInstallTable
+** DESCRIPTION:
+**  Registers an error table with NSPR.  Must be done exactly once per
+**  table.  Memory pointed to by `table' must remain valid for the life
+**  of the process.
+**
+**  NOT THREAD SAFE!
+**  
+***********************************************************************/
+NSPR_API(PRErrorCode) PR_ErrorInstallTable(const struct PRErrorTable *table);
+
+
+/***********************************************************************
+** FUNCTION:    PR_ErrorInstallCallback
+** DESCRIPTION:
+**  Registers an error localization plugin with NSPR.  May be called
+**  at most one time.  `languages' contains the language codes supported
+**  by this plugin.  Languages 0 and 1 must be "i-default" and "en"
+**  respectively.  `lookup' and `newtable' contain pointers to
+**  the plugin callback functions.  `cb_private' contains any information
+**  private to the plugin functions.
+**
+**  NOT THREAD SAFE!
+**
+***********************************************************************/
+NSPR_API(void) PR_ErrorInstallCallback(const char * const * languages,
+			      PRErrorCallbackLookupFn *lookup, 
+			      PRErrorCallbackNewTableFn *newtable,
+			      struct PRErrorCallbackPrivate *cb_private);
+
+PR_END_EXTERN_C
+
+#endif /* prerror_h___ */
diff --git a/mozilla/nsprpub/pr/include/prinet.h b/mozilla/nsprpub/pr/include/prinet.h
new file mode 100644
index 0000000..7c3f4bd
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prinet.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * File:		prinet.h
+ * Description:
+ *     Header file used to find the system header files for socket support[1].
+ *     This file serves the following purposes:
+ *     - A cross-platform, "get-everything" socket header file.  On
+ *       Unix, socket support is scattered in several header files,
+ *       while Windows has a "get-everything" socket header file[2].
+ *     - NSPR needs the following macro definitions and function
+ *       prototype declarations from these header files:
+ *           AF_INET
+ *           INADDR_ANY, INADDR_LOOPBACK, INADDR_BROADCAST
+ *           ntohl(), ntohs(), htonl(), ntons().
+ *       NSPR does not define its own versions of these macros and
+ *       functions.  It simply uses the native versions, which have
+ *       the same names on all supported platforms.
+ *     This file is intended to be included by NSPR public header
+ *     files, such as prio.h.  One should not include this file directly.
+ *
+ * Notes:
+ *     1. This file should have been an internal header.  Please do not
+ *        depend on it to pull in the system header files you need.
+ *     2. WARNING: This file is no longer cross-platform as it is a no-op
+ *        for WIN32!  See the comment in the WIN32 section for details.
+ */
+
+#ifndef prinet_h__
+#define prinet_h__
+
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+#include <sys/types.h>
+#include <sys/socket.h>		/* AF_INET */
+#include <netinet/in.h>         /* INADDR_ANY, ..., ntohl(), ... */
+#ifdef XP_OS2
+#include <sys/ioctl.h>
+#endif
+#ifdef XP_UNIX
+#ifdef AIX
+/*
+ * On AIX 4.3, the header <arpa/inet.h> refers to struct
+ * ether_addr and struct sockaddr_dl that are not declared.
+ * The following struct declarations eliminate the compiler
+ * warnings.
+ */
+struct ether_addr;
+struct sockaddr_dl;
+#endif /* AIX */
+#include <arpa/inet.h>
+#endif /* XP_UNIX */
+#include <netdb.h>
+
+#if defined(FREEBSD) || defined(BSDI) || defined(QNX)
+#include <rpc/types.h> /* the only place that defines INADDR_LOOPBACK */
+#endif
+
+/*
+ * OS/2 hack.  For some reason INADDR_LOOPBACK is not defined in the
+ * socket headers.
+ */
+#if defined(OS2) && !defined(INADDR_LOOPBACK)
+#define INADDR_LOOPBACK 0x7f000001
+#endif
+
+/*
+ * Prototypes of ntohl() etc. are declared in <machine/endian.h>
+ * on these platforms.
+ */
+#if defined(BSDI) || defined(OSF1)
+#include <machine/endian.h>
+#endif
+
+#elif defined(WIN32)
+
+/*
+ * Do not include any system header files.
+ *
+ * Originally we were including <windows.h>.  It slowed down the
+ * compilation of files that included NSPR headers, so we removed
+ * the <windows.h> inclusion at customer's request, which created
+ * an unfortunate inconsistency with other platforms.
+ */
+
+#else
+
+#error Unknown platform
+
+#endif
+
+#endif /* prinet_h__ */
diff --git a/mozilla/nsprpub/pr/include/prinit.h b/mozilla/nsprpub/pr/include/prinit.h
new file mode 100644
index 0000000..0d115de
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prinit.h
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prinit_h___
+#define prinit_h___
+
+#include "prthread.h"
+#include "prtypes.h"
+#include "prwin16.h"
+#include <stdio.h>
+
+PR_BEGIN_EXTERN_C
+
+/************************************************************************/
+/**************************IDENTITY AND VERSIONING***********************/
+/************************************************************************/
+
+/*
+** NSPR's name, this should persist until at least the turn of the
+** century.
+*/
+#define PR_NAME     "NSPR"
+
+/*
+** NSPR's version is used to determine the likelihood that the version you
+** used to build your component is anywhere close to being compatible with
+** what is in the underlying library.
+**
+** The format of the version string is
+**     "<major version>.<minor version>[.<patch level>] [<Beta>]"
+*/
+#define PR_VERSION  "4.8.4 Beta"
+#define PR_VMAJOR   4
+#define PR_VMINOR   8
+#define PR_VPATCH   4
+#define PR_BETA     PR_TRUE
+
+/*
+** PRVersionCheck
+**
+** The basic signature of the function that is called to provide version
+** checking. The result will be a boolean that indicates the likelihood
+** that the underling library will perform as the caller expects.
+**
+** The only argument is a string, which should be the verson identifier
+** of the library in question. That string will be compared against an
+** equivalent string that represents the actual build version of the
+** exporting library.
+**
+** The result will be the logical union of the directly called library
+** and all dependent libraries.
+*/
+
+typedef PRBool (*PRVersionCheck)(const char*);
+
+/*
+** PR_VersionCheck
+**
+** NSPR's existance proof of the version check function.
+**
+** Note that NSPR has no cooperating dependencies.
+*/
+
+NSPR_API(PRBool) PR_VersionCheck(const char *importedVersion);
+
+
+/************************************************************************/
+/*******************************INITIALIZATION***************************/
+/************************************************************************/
+
+/*
+** Initialize the runtime. Attach a thread object to the currently
+** executing native thread of type "type".
+**
+** The specificaiton of 'maxPTDs' is ignored.
+*/
+NSPR_API(void) PR_Init(
+    PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs);
+
+/*
+** And alternate form of initialization, one that may become the default if
+** not the only mechanism, provides a method to get the NSPR runtime init-
+** ialized and place NSPR between the caller and the runtime library. This
+** allows main() to be treated as any other thread root function, signalling
+** its compeletion by returning and allowing the runtime to coordinate the
+** completion of the other threads of the runtime.
+**
+** The priority of the main (or primordial) thread will be PR_PRIORITY_NORMAL.
+** The thread may adjust its own priority by using PR_SetPriority(), though
+** at this time the support for priorities is somewhat weak.
+**
+** The specificaiton of 'maxPTDs' is ignored.
+**
+** The value returned by PR_Initialize is the value returned from the root
+** function, 'prmain'.
+*/
+
+typedef PRIntn (PR_CALLBACK *PRPrimordialFn)(PRIntn argc, char **argv);
+
+NSPR_API(PRIntn) PR_Initialize(
+    PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs);
+
+/*
+** Return PR_TRUE if PR_Init has already been called.
+*/
+NSPR_API(PRBool) PR_Initialized(void);
+
+/*
+ * Perform a graceful shutdown of NSPR.  PR_Cleanup() may be called by
+ * the primordial thread near the end of the main() function.
+ *
+ * PR_Cleanup() attempts to synchronize the natural termination of
+ * process.  It does that by blocking the caller, if and only if it is
+ * the primordial thread, until the number of user threads has dropped
+ * to zero.  When the primordial thread returns from main(), the process
+ * will immediately and silently exit.  That is, it will (if necessary)
+ * forcibly terminate any existing threads and exit without significant
+ * blocking and there will be no error messages or core files.
+ *
+ * PR_Cleanup() returns PR_SUCCESS if NSPR is successfully shutdown,
+ * or PR_FAILURE if the calling thread of this function is not the
+ * primordial thread.
+ */
+NSPR_API(PRStatus) PR_Cleanup(void);
+
+/*
+** Disable Interrupts
+**		Disables timer signals used for pre-emptive scheduling.
+*/
+NSPR_API(void) PR_DisableClockInterrupts(void);
+
+/*
+** Enables Interrupts
+**		Enables timer signals used for pre-emptive scheduling.
+*/
+NSPR_API(void) PR_EnableClockInterrupts(void);
+
+/*
+** Block Interrupts
+**		Blocks the timer signal used for pre-emptive scheduling
+*/
+NSPR_API(void) PR_BlockClockInterrupts(void);
+
+/*
+** Unblock Interrupts
+**		Unblocks the timer signal used for pre-emptive scheduling
+*/
+NSPR_API(void) PR_UnblockClockInterrupts(void);
+
+/*
+** Create extra virtual processor threads. Generally used with MP systems.
+*/
+NSPR_API(void) PR_SetConcurrency(PRUintn numCPUs);
+
+/*
+** Control the method and size of the file descriptor (PRFileDesc*)
+** cache used by the runtime. Setting 'high' to zero is for performance,
+** any other value probably for debugging (see memo on FD caching).
+*/
+NSPR_API(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high);
+
+/*
+ * Cause an immediate, nongraceful, forced termination of the process.
+ * It takes a PRIntn argument, which is the exit status code of the
+ * process.
+ */
+NSPR_API(void) PR_ProcessExit(PRIntn status);
+
+/*
+** Abort the process in a non-graceful manner. This will cause a core file,
+** call to the debugger or other moral equivalent as well as causing the
+** entire process to stop.
+*/
+NSPR_API(void) PR_Abort(void);
+
+/*
+ ****************************************************************
+ *
+ * Module initialization:
+ *
+ ****************************************************************
+ */
+
+typedef struct PRCallOnceType {
+    PRIntn initialized;
+    PRInt32 inProgress;
+    PRStatus status;
+} PRCallOnceType;
+
+typedef PRStatus (PR_CALLBACK *PRCallOnceFN)(void);
+
+typedef PRStatus (PR_CALLBACK *PRCallOnceWithArgFN)(void *arg);
+
+NSPR_API(PRStatus) PR_CallOnce(
+    PRCallOnceType *once,
+    PRCallOnceFN    func
+);
+
+NSPR_API(PRStatus) PR_CallOnceWithArg(
+    PRCallOnceType      *once,
+    PRCallOnceWithArgFN  func,
+    void                *arg
+);
+
+
+PR_END_EXTERN_C
+
+#endif /* prinit_h___ */
diff --git a/mozilla/nsprpub/pr/include/prinrval.h b/mozilla/nsprpub/pr/include/prinrval.h
new file mode 100644
index 0000000..67d2f42
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prinrval.h
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:		prinrval.h
+** Description:	API to interval timing functions of NSPR.
+**
+**
+** NSPR provides interval times that are independent of network time
+** of day values. Interval times are (in theory) accurate regardless
+** of host processing requirements and also very cheap to acquire. It
+** is expected that getting an interval time while in a synchronized
+** function (holding one's lock).
+**/
+
+#if !defined(prinrval_h)
+#define prinrval_h
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+typedef PRUint32 PRIntervalTime;
+
+/***********************************************************************
+** DEFINES:     PR_INTERVAL_MIN
+**              PR_INTERVAL_MAX
+** DESCRIPTION:
+**  These two constants define the range (in ticks / second) of the
+**  platform dependent type, PRIntervalTime. These constants bound both
+**  the period and the resolution of a PRIntervalTime. 
+***********************************************************************/
+#define PR_INTERVAL_MIN 1000UL
+#define PR_INTERVAL_MAX 100000UL
+
+/***********************************************************************
+** DEFINES:     PR_INTERVAL_NO_WAIT
+**              PR_INTERVAL_NO_TIMEOUT
+** DESCRIPTION:
+**  Two reserved constants are defined in the PRIntervalTime namespace.
+**  They are used to indicate that the process should wait no time (return
+**  immediately) or wait forever (never time out), respectively.
+**  Note: PR_INTERVAL_NO_TIMEOUT passed as input to PR_Connect is 
+**  interpreted as use the OS's connect timeout.
+**  
+***********************************************************************/
+#define PR_INTERVAL_NO_WAIT 0UL
+#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+/***********************************************************************
+** FUNCTION:    PR_IntervalNow
+** DESCRIPTION:
+**  Return the value of NSPR's free running interval timer. That timer
+**  can be used to establish epochs and determine intervals (be computing
+**  the difference between two times).
+** INPUTS:      void
+** OUTPUTS:     void
+** RETURN:      PRIntervalTime
+**  
+** SIDE EFFECTS:
+**  None
+** RESTRICTIONS:
+**  The units of PRIntervalTime are platform dependent. They are chosen
+**  such that they are appropriate for the host OS, yet provide sufficient
+**  resolution and period to be useful to clients. 
+** MEMORY:      N/A
+** ALGORITHM:   Platform dependent
+***********************************************************************/
+NSPR_API(PRIntervalTime) PR_IntervalNow(void);
+
+/***********************************************************************
+** FUNCTION:    PR_TicksPerSecond
+** DESCRIPTION:
+**  Return the number of ticks per second for PR_IntervalNow's clock.
+**  The value will be in the range [PR_INTERVAL_MIN..PR_INTERVAL_MAX].
+** INPUTS:      void
+** OUTPUTS:     void
+** RETURN:      PRUint32
+**  
+** SIDE EFFECTS:
+**  None
+** RESTRICTIONS:
+**  None
+** MEMORY:      N/A
+** ALGORITHM:   N/A
+***********************************************************************/
+NSPR_API(PRUint32) PR_TicksPerSecond(void);
+
+/***********************************************************************
+** FUNCTION:    PR_SecondsToInterval
+**              PR_MillisecondsToInterval
+**              PR_MicrosecondsToInterval
+** DESCRIPTION:
+**  Convert standard clock units to platform dependent intervals.
+** INPUTS:      PRUint32
+** OUTPUTS:     void
+** RETURN:      PRIntervalTime
+**  
+** SIDE EFFECTS:
+**  None
+** RESTRICTIONS:
+**  Conversion may cause overflow, which is not reported.
+** MEMORY:      N/A
+** ALGORITHM:   N/A
+***********************************************************************/
+NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds);
+NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli);
+NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro);
+
+/***********************************************************************
+** FUNCTION:    PR_IntervalToSeconds
+**              PR_IntervalToMilliseconds
+**              PR_IntervalToMicroseconds
+** DESCRIPTION:
+**  Convert platform dependent intervals to standard clock units.
+** INPUTS:      PRIntervalTime
+** OUTPUTS:     void
+** RETURN:      PRUint32
+**  
+** SIDE EFFECTS:
+**  None
+** RESTRICTIONS:
+**  Conversion may cause overflow, which is not reported.
+** MEMORY:      N/A
+** ALGORITHM:   N/A
+***********************************************************************/
+NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks);
+NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks);
+NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks);
+
+PR_END_EXTERN_C
+
+
+#endif /* !defined(prinrval_h) */
+
+/* prinrval.h */
diff --git a/mozilla/nsprpub/pr/include/prio.h b/mozilla/nsprpub/pr/include/prio.h
new file mode 100644
index 0000000..7ec3045
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prio.h
@@ -0,0 +1,2034 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * File:     prio.h
+ *
+ * Description:    PR i/o related stuff, such as file system access, file
+ *         i/o, socket i/o, etc.
+ */
+
+#ifndef prio_h___
+#define prio_h___
+
+#include "prlong.h"
+#include "prtime.h"
+#include "prinrval.h"
+#include "prinet.h"
+
+PR_BEGIN_EXTERN_C
+
+/* Typedefs */
+typedef struct PRDir            PRDir;
+typedef struct PRDirEntry       PRDirEntry;
+#ifdef MOZ_UNICODE
+typedef struct PRDirUTF16       PRDirUTF16;
+typedef struct PRDirEntryUTF16  PRDirEntryUTF16;
+#endif /* MOZ_UNICODE */
+typedef struct PRFileDesc       PRFileDesc;
+typedef struct PRFileInfo       PRFileInfo;
+typedef struct PRFileInfo64     PRFileInfo64;
+typedef union  PRNetAddr        PRNetAddr;
+typedef struct PRIOMethods      PRIOMethods;
+typedef struct PRPollDesc       PRPollDesc;
+typedef struct PRFilePrivate    PRFilePrivate;
+typedef struct PRSendFileData   PRSendFileData;
+
+/*
+***************************************************************************
+** The file descriptor.
+** This is the primary structure to represent any active open socket,
+** whether it be a normal file or a network connection. Such objects
+** are stackable (or layerable). Each layer may have its own set of
+** method pointers and context private to that layer. All each layer
+** knows about its neighbors is how to get to their method table.
+***************************************************************************
+*/
+
+typedef PRIntn PRDescIdentity;          /* see: Layering file descriptors */
+
+struct PRFileDesc {
+    const PRIOMethods *methods;         /* the I/O methods table */
+    PRFilePrivate *secret;              /* layer dependent data */
+    PRFileDesc *lower, *higher;         /* pointers to adjacent layers */
+    void (PR_CALLBACK *dtor)(PRFileDesc *fd);
+                                        /* A destructor function for layer */
+    PRDescIdentity identity;            /* Identity of this particular layer  */
+};
+
+/*
+***************************************************************************
+** PRTransmitFileFlags
+**
+** Flags for PR_TransmitFile.  Pass PR_TRANSMITFILE_CLOSE_SOCKET to
+** PR_TransmitFile if the connection should be closed after the file
+** is transmitted.
+***************************************************************************
+*/
+typedef enum PRTransmitFileFlags {
+    PR_TRANSMITFILE_KEEP_OPEN = 0,    /* socket is left open after file
+                                       * is transmitted. */
+    PR_TRANSMITFILE_CLOSE_SOCKET = 1  /* socket is closed after file
+                                       * is transmitted. */
+} PRTransmitFileFlags;
+
+/*
+**************************************************************************
+** Macros for PRNetAddr
+**
+** Address families: PR_AF_INET, PR_AF_INET6, PR_AF_LOCAL
+** IP addresses: PR_INADDR_ANY, PR_INADDR_LOOPBACK, PR_INADDR_BROADCAST
+**************************************************************************
+*/
+
+#ifdef WIN32
+
+#define PR_AF_INET 2
+#define PR_AF_LOCAL 1
+#define PR_INADDR_ANY (unsigned long)0x00000000
+#define PR_INADDR_LOOPBACK 0x7f000001
+#define PR_INADDR_BROADCAST (unsigned long)0xffffffff
+
+#else /* WIN32 */
+
+#define PR_AF_INET AF_INET
+#define PR_AF_LOCAL AF_UNIX
+#define PR_INADDR_ANY INADDR_ANY
+#define PR_INADDR_LOOPBACK INADDR_LOOPBACK
+#define PR_INADDR_BROADCAST INADDR_BROADCAST
+
+#endif /* WIN32 */
+
+/*
+** Define PR_AF_INET6 in prcpucfg.h with the same
+** value as AF_INET6 on platforms with IPv6 support.
+** Otherwise define it here.
+*/
+#ifndef PR_AF_INET6
+#define PR_AF_INET6 100
+#endif
+
+#ifndef PR_AF_UNSPEC
+#define PR_AF_UNSPEC 0
+#endif
+
+/*
+**************************************************************************
+** A network address
+**
+** Only Internet Protocol (IPv4 and IPv6) addresses are supported.
+** The address family must always represent IPv4 (AF_INET, probably == 2)
+** or IPv6 (AF_INET6).
+**************************************************************************
+*************************************************************************/
+
+struct PRIPv6Addr {
+	union {
+		PRUint8  _S6_u8[16];
+		PRUint16 _S6_u16[8];
+		PRUint32 _S6_u32[4];
+		PRUint64 _S6_u64[2];
+	} _S6_un;
+};
+#define pr_s6_addr		_S6_un._S6_u8
+#define pr_s6_addr16	_S6_un._S6_u16
+#define pr_s6_addr32	_S6_un._S6_u32
+#define pr_s6_addr64 	_S6_un._S6_u64
+
+typedef struct PRIPv6Addr PRIPv6Addr;
+
+union PRNetAddr {
+    struct {
+        PRUint16 family;                /* address family (0x00ff maskable) */
+#ifdef XP_BEOS
+        char data[10];                  /* Be has a smaller structure */
+#else
+        char data[14];                  /* raw address data */
+#endif
+    } raw;
+    struct {
+        PRUint16 family;                /* address family (AF_INET) */
+        PRUint16 port;                  /* port number */
+        PRUint32 ip;                    /* The actual 32 bits of address */
+#ifdef XP_BEOS
+        char pad[4];                    /* Be has a smaller structure */
+#else
+        char pad[8];
+#endif
+    } inet;
+    struct {
+        PRUint16 family;                /* address family (AF_INET6) */
+        PRUint16 port;                  /* port number */
+        PRUint32 flowinfo;              /* routing information */
+        PRIPv6Addr ip;                  /* the actual 128 bits of address */
+        PRUint32 scope_id;              /* set of interfaces for a scope */
+    } ipv6;
+#if defined(XP_UNIX) || defined(XP_OS2)
+    struct {                            /* Unix domain socket address */
+        PRUint16 family;                /* address family (AF_UNIX) */
+#ifdef XP_OS2
+        char path[108];                 /* null-terminated pathname */
+                                        /* bind fails if size is not 108. */
+#else
+        char path[104];                 /* null-terminated pathname */
+#endif
+    } local;
+#endif
+};
+
+/*
+***************************************************************************
+** PRSockOption
+**
+** The file descriptors can have predefined options set after they file
+** descriptor is created to change their behavior. Only the options in
+** the following enumeration are supported.
+***************************************************************************
+*/
+typedef enum PRSockOption
+{
+    PR_SockOpt_Nonblocking,     /* nonblocking io */
+    PR_SockOpt_Linger,          /* linger on close if data present */
+    PR_SockOpt_Reuseaddr,       /* allow local address reuse */
+    PR_SockOpt_Keepalive,       /* keep connections alive */
+    PR_SockOpt_RecvBufferSize,  /* send buffer size */
+    PR_SockOpt_SendBufferSize,  /* receive buffer size */
+
+    PR_SockOpt_IpTimeToLive,    /* time to live */
+    PR_SockOpt_IpTypeOfService, /* type of service and precedence */
+
+    PR_SockOpt_AddMember,       /* add an IP group membership */
+    PR_SockOpt_DropMember,      /* drop an IP group membership */
+    PR_SockOpt_McastInterface,  /* multicast interface address */
+    PR_SockOpt_McastTimeToLive, /* multicast timetolive */
+    PR_SockOpt_McastLoopback,   /* multicast loopback */
+
+    PR_SockOpt_NoDelay,         /* don't delay send to coalesce packets */
+    PR_SockOpt_MaxSegment,      /* maximum segment size */
+    PR_SockOpt_Broadcast,       /* enable broadcast */
+    PR_SockOpt_Last
+} PRSockOption;
+
+typedef struct PRLinger {
+	PRBool polarity;		    /* Polarity of the option's setting */
+	PRIntervalTime linger;	    /* Time to linger before closing */
+} PRLinger;
+
+typedef struct PRMcastRequest {
+	PRNetAddr mcaddr;			/* IP multicast address of group */
+	PRNetAddr ifaddr;			/* local IP address of interface */
+} PRMcastRequest;
+
+typedef struct PRSocketOptionData
+{
+    PRSockOption option;
+    union
+    {
+        PRUintn ip_ttl;             /* IP time to live */
+        PRUintn mcast_ttl;          /* IP multicast time to live */
+        PRUintn tos;                /* IP type of service and precedence */
+        PRBool non_blocking;        /* Non-blocking (network) I/O */
+        PRBool reuse_addr;          /* Allow local address reuse */
+        PRBool keep_alive;          /* Keep connections alive */
+        PRBool mcast_loopback;      /* IP multicast loopback */
+        PRBool no_delay;            /* Don't delay send to coalesce packets */
+        PRBool broadcast;           /* Enable broadcast */
+        PRSize max_segment;         /* Maximum segment size */
+        PRSize recv_buffer_size;    /* Receive buffer size */
+        PRSize send_buffer_size;    /* Send buffer size */
+        PRLinger linger;            /* Time to linger on close if data present */
+        PRMcastRequest add_member;  /* add an IP group membership */
+        PRMcastRequest drop_member; /* Drop an IP group membership */
+        PRNetAddr mcast_if;         /* multicast interface address */
+    } value;
+} PRSocketOptionData;
+
+/*
+***************************************************************************
+** PRIOVec
+**
+** The I/O vector is used by the write vector method to describe the areas
+** that are affected by the ouput operation.
+***************************************************************************
+*/
+typedef struct PRIOVec {
+    char *iov_base;
+    int iov_len;
+} PRIOVec;
+
+/*
+***************************************************************************
+** Discover what type of socket is being described by the file descriptor.
+***************************************************************************
+*/
+typedef enum PRDescType
+{
+    PR_DESC_FILE = 1,
+    PR_DESC_SOCKET_TCP = 2,
+    PR_DESC_SOCKET_UDP = 3,
+    PR_DESC_LAYERED = 4,
+    PR_DESC_PIPE = 5
+} PRDescType;
+
+typedef enum PRSeekWhence {
+    PR_SEEK_SET = 0,
+    PR_SEEK_CUR = 1,
+    PR_SEEK_END = 2
+} PRSeekWhence;
+
+NSPR_API(PRDescType) PR_GetDescType(PRFileDesc *file);
+
+/*
+***************************************************************************
+** PRIOMethods
+**
+** The I/O methods table provides procedural access to the functions of
+** the file descriptor. It is the responsibility of a layer implementor
+** to provide suitable functions at every entry point. If a layer provides
+** no functionality, it should call the next lower(higher) function of the
+** same name (e.g., return fd->lower->method->close(fd->lower));
+**
+** Not all functions are implemented for all types of files. In cases where
+** that is true, the function will return a error indication with an error
+** code of PR_INVALID_METHOD_ERROR.
+***************************************************************************
+*/
+
+typedef PRStatus (PR_CALLBACK *PRCloseFN)(PRFileDesc *fd);
+typedef PRInt32 (PR_CALLBACK *PRReadFN)(PRFileDesc *fd, void *buf, PRInt32 amount);
+typedef PRInt32 (PR_CALLBACK *PRWriteFN)(PRFileDesc *fd, const void *buf, PRInt32 amount);
+typedef PRInt32 (PR_CALLBACK *PRAvailableFN)(PRFileDesc *fd);
+typedef PRInt64 (PR_CALLBACK *PRAvailable64FN)(PRFileDesc *fd);
+typedef PRStatus (PR_CALLBACK *PRFsyncFN)(PRFileDesc *fd);
+typedef PROffset32 (PR_CALLBACK *PRSeekFN)(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how);
+typedef PROffset64 (PR_CALLBACK *PRSeek64FN)(PRFileDesc *fd, PROffset64 offset, PRSeekWhence how);
+typedef PRStatus (PR_CALLBACK *PRFileInfoFN)(PRFileDesc *fd, PRFileInfo *info);
+typedef PRStatus (PR_CALLBACK *PRFileInfo64FN)(PRFileDesc *fd, PRFileInfo64 *info);
+typedef PRInt32 (PR_CALLBACK *PRWritevFN)(
+    PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size,
+    PRIntervalTime timeout);
+typedef PRStatus (PR_CALLBACK *PRConnectFN)(
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout);
+typedef PRFileDesc* (PR_CALLBACK *PRAcceptFN) (
+    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout);
+typedef PRStatus (PR_CALLBACK *PRBindFN)(PRFileDesc *fd, const PRNetAddr *addr);
+typedef PRStatus (PR_CALLBACK *PRListenFN)(PRFileDesc *fd, PRIntn backlog);
+typedef PRStatus (PR_CALLBACK *PRShutdownFN)(PRFileDesc *fd, PRIntn how);
+typedef PRInt32 (PR_CALLBACK *PRRecvFN)(
+    PRFileDesc *fd, void *buf, PRInt32 amount,
+    PRIntn flags, PRIntervalTime timeout);
+typedef PRInt32 (PR_CALLBACK *PRSendFN) (
+    PRFileDesc *fd, const void *buf, PRInt32 amount,
+    PRIntn flags, PRIntervalTime timeout);
+typedef PRInt32 (PR_CALLBACK *PRRecvfromFN)(
+    PRFileDesc *fd, void *buf, PRInt32 amount,
+    PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout);
+typedef PRInt32 (PR_CALLBACK *PRSendtoFN)(
+    PRFileDesc *fd, const void *buf, PRInt32 amount,
+    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout);
+typedef PRInt16 (PR_CALLBACK *PRPollFN)(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags);
+typedef PRInt32 (PR_CALLBACK *PRAcceptreadFN)(
+    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
+    void *buf, PRInt32 amount, PRIntervalTime t);
+typedef PRInt32 (PR_CALLBACK *PRTransmitfileFN)(
+     PRFileDesc *sd, PRFileDesc *fd, const void *headers,
+     PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime t);
+typedef PRStatus (PR_CALLBACK *PRGetsocknameFN)(PRFileDesc *fd, PRNetAddr *addr);
+typedef PRStatus (PR_CALLBACK *PRGetpeernameFN)(PRFileDesc *fd, PRNetAddr *addr);
+typedef PRStatus (PR_CALLBACK *PRGetsocketoptionFN)(
+    PRFileDesc *fd, PRSocketOptionData *data);
+typedef PRStatus (PR_CALLBACK *PRSetsocketoptionFN)(
+    PRFileDesc *fd, const PRSocketOptionData *data);
+typedef PRInt32 (PR_CALLBACK *PRSendfileFN)(
+	PRFileDesc *networkSocket, PRSendFileData *sendData,
+	PRTransmitFileFlags flags, PRIntervalTime timeout);
+typedef PRStatus (PR_CALLBACK *PRConnectcontinueFN)(
+    PRFileDesc *fd, PRInt16 out_flags);
+typedef PRIntn (PR_CALLBACK *PRReservedFN)(PRFileDesc *fd);
+
+struct PRIOMethods {
+    PRDescType file_type;           /* Type of file represented (tos)           */
+    PRCloseFN close;                /* close file and destroy descriptor        */
+    PRReadFN read;                  /* read up to specified bytes into buffer   */
+    PRWriteFN write;                /* write specified bytes from buffer        */
+    PRAvailableFN available;        /* determine number of bytes available      */
+    PRAvailable64FN available64;    /*          ditto, 64 bit                   */
+    PRFsyncFN fsync;                /* flush all buffers to permanent store     */
+    PRSeekFN seek;                  /* position the file to the desired place   */
+    PRSeek64FN seek64;              /*           ditto, 64 bit                  */
+    PRFileInfoFN fileInfo;          /* Get information about an open file       */
+    PRFileInfo64FN fileInfo64;      /*           ditto, 64 bit                  */
+    PRWritevFN writev;              /* Write segments as described by iovector  */
+    PRConnectFN connect;            /* Connect to the specified (net) address   */
+    PRAcceptFN accept;              /* Accept a connection for a (net) peer     */
+    PRBindFN bind;                  /* Associate a (net) address with the fd    */
+    PRListenFN listen;              /* Prepare to listen for (net) connections  */
+    PRShutdownFN shutdown;          /* Shutdown a (net) connection              */
+    PRRecvFN recv;                  /* Solicit up the the specified bytes       */
+    PRSendFN send;                  /* Send all the bytes specified             */
+    PRRecvfromFN recvfrom;          /* Solicit (net) bytes and report source    */
+    PRSendtoFN sendto;              /* Send bytes to (net) address specified    */
+    PRPollFN poll;                  /* Test the fd to see if it is ready        */
+    PRAcceptreadFN acceptread;      /* Accept and read on a new (net) fd        */
+    PRTransmitfileFN transmitfile;  /* Transmit at entire file                  */
+    PRGetsocknameFN getsockname;    /* Get (net) address associated with fd     */
+    PRGetpeernameFN getpeername;    /* Get peer's (net) address                 */
+    PRReservedFN reserved_fn_6;     /* reserved for future use */
+    PRReservedFN reserved_fn_5;     /* reserved for future use */
+    PRGetsocketoptionFN getsocketoption;
+                                    /* Get current setting of specified option  */
+    PRSetsocketoptionFN setsocketoption;
+                                    /* Set value of specified option            */
+    PRSendfileFN sendfile;			/* Send a (partial) file with header/trailer*/
+    PRConnectcontinueFN connectcontinue;
+                                    /* Continue a nonblocking connect */
+    PRReservedFN reserved_fn_3;		/* reserved for future use */
+    PRReservedFN reserved_fn_2;		/* reserved for future use */
+    PRReservedFN reserved_fn_1;		/* reserved for future use */
+    PRReservedFN reserved_fn_0;		/* reserved for future use */
+};
+
+/*
+ **************************************************************************
+ * FUNCTION: PR_GetSpecialFD
+ * DESCRIPTION: Get the file descriptor that represents the standard input,
+ *              output, or error stream.
+ * INPUTS:
+ *     PRSpecialFD id
+ *         A value indicating the type of stream desired:
+ *             PR_StandardInput: standard input
+ *             PR_StandardOuput: standard output
+ *             PR_StandardError: standard error
+ * OUTPUTS: none
+ * RETURNS: PRFileDesc *
+ *     If the argument is valid, PR_GetSpecialFD returns a file descriptor
+ *     that represents the corresponding standard I/O stream.  Otherwise,
+ *     PR_GetSpecialFD returns NULL and sets error PR_INVALID_ARGUMENT_ERROR.
+ **************************************************************************
+ */
+
+typedef enum PRSpecialFD
+{
+    PR_StandardInput,          /* standard input */
+    PR_StandardOutput,         /* standard output */
+    PR_StandardError           /* standard error */
+} PRSpecialFD;
+
+NSPR_API(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD id);
+
+#define PR_STDIN	PR_GetSpecialFD(PR_StandardInput)
+#define PR_STDOUT	PR_GetSpecialFD(PR_StandardOutput)
+#define PR_STDERR	PR_GetSpecialFD(PR_StandardError)
+
+/*
+ **************************************************************************
+ * Layering file descriptors
+ *
+ * File descriptors may be layered. Each layer has it's own identity.
+ * Identities are allocated by the runtime and are to be associated
+ * (by the layer implementor) with all layers that are of that type.
+ * It is then possible to scan the chain of layers and find a layer
+ * that one recongizes and therefore predict that it will implement
+ * a desired protocol.
+ *
+ * There are three well-known identities:
+ *      PR_INVALID_IO_LAYER => an invalid layer identity, for error return
+ *      PR_TOP_IO_LAYER     => the identity of the top of the stack
+ *      PR_NSPR_IO_LAYER    => the identity used by NSPR proper
+ * PR_TOP_IO_LAYER may be used as a shorthand for identifying the topmost
+ * layer of an existing stack. Ie., the following two constructs are
+ * equivalent.
+ *
+ *      rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, my_layer);
+ *      rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), my_layer)
+ *
+ * A string may be associated with the creation of the identity. It
+ * will be copied by the runtime. If queried the runtime will return
+ * a reference to that copied string (not yet another copy). There
+ * is no facility for deleting an identity.
+ **************************************************************************
+ */
+
+#define PR_IO_LAYER_HEAD (PRDescIdentity)-3
+#define PR_INVALID_IO_LAYER (PRDescIdentity)-1
+#define PR_TOP_IO_LAYER (PRDescIdentity)-2
+#define PR_NSPR_IO_LAYER (PRDescIdentity)0
+
+NSPR_API(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name);
+NSPR_API(const char*) PR_GetNameForIdentity(PRDescIdentity ident);
+NSPR_API(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd);
+NSPR_API(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd_stack, PRDescIdentity id);
+
+/*
+ **************************************************************************
+ * PR_GetDefaultIOMethods: Accessing the default methods table.
+ * You may get a pointer to the default methods table by calling this function.
+ * You may then select any elements from that table with which to build your
+ * layer's methods table. You may NOT modify the table directly.
+ **************************************************************************
+ */
+NSPR_API(const PRIOMethods *) PR_GetDefaultIOMethods(void);
+
+/*
+ **************************************************************************
+ * Creating a layer
+ *
+ * A new layer may be allocated by calling PR_CreateIOLayerStub(). The
+ * file descriptor returned will contain the pointer to the methods table
+ * provided. The runtime will not modify the table nor test its correctness.
+ **************************************************************************
+ */
+NSPR_API(PRFileDesc*) PR_CreateIOLayerStub(
+    PRDescIdentity ident, const PRIOMethods *methods);
+
+/*
+ **************************************************************************
+ * Creating a layer
+ *
+ * A new stack may be created by calling PR_CreateIOLayer(). The
+ * file descriptor returned will point to the top of the stack, which has
+ * the layer 'fd' as the topmost layer.
+ * 
+ * NOTE: This function creates a new style stack, which has a fixed, dummy
+ * header. The old style stack, created by a call to PR_PushIOLayer,
+ * results in modifying contents of the top layer of the stack, when
+ * pushing and popping layers of the stack.
+ **************************************************************************
+ */
+NSPR_API(PRFileDesc*) PR_CreateIOLayer(PRFileDesc* fd);
+
+/*
+ **************************************************************************
+ * Pushing a layer
+ *
+ * A file descriptor (perhaps allocated using PR_CreateIOLayerStub()) may
+ * be pushed into an existing stack of file descriptors at any point the
+ * caller deems appropriate. The new layer will be inserted into the stack
+ * just above the layer with the indicated identity.
+ *
+ * Note: Even if the identity parameter indicates the top-most layer of
+ * the stack, the value of the file descriptor describing the original
+ * stack will not change.
+ **************************************************************************
+ */
+NSPR_API(PRStatus) PR_PushIOLayer(
+    PRFileDesc *fd_stack, PRDescIdentity id, PRFileDesc *layer);
+
+/*
+ **************************************************************************
+ * Popping a layer
+ *
+ * A layer may be popped from a stack by indicating the identity of the
+ * layer to be removed. If found, a pointer to the removed object will
+ * be returned to the caller. The object then becomes the responsibility
+ * of the caller.
+ *
+ * Note: Even if the identity indicates the top layer of the stack, the
+ * reference returned will not be the file descriptor for the stack and
+ * that file descriptor will remain valid.
+ **************************************************************************
+ */
+NSPR_API(PRFileDesc*) PR_PopIOLayer(PRFileDesc *fd_stack, PRDescIdentity id);
+
+/*
+ **************************************************************************
+ * FUNCTION:    PR_Open
+ * DESCRIPTION:    Open a file for reading, writing, or both.
+ * INPUTS:
+ *     const char *name
+ *         The path name of the file to be opened
+ *     PRIntn flags
+ *         The file status flags.
+ *         It is a bitwise OR of the following bit flags (only one of
+ *         the first three flags below may be used):
+ *		PR_RDONLY        Open for reading only.
+ *		PR_WRONLY        Open for writing only.
+ *		PR_RDWR          Open for reading and writing.
+ *		PR_CREATE_FILE   If the file does not exist, the file is created
+ *                              If the file exists, this flag has no effect.
+ *      PR_SYNC          If set, each write will wait for both the file data
+ *                              and file status to be physically updated.
+ *		PR_APPEND        The file pointer is set to the end of
+ *                              the file prior to each write.
+ *		PR_TRUNCATE      If the file exists, its length is truncated to 0.
+ *      PR_EXCL          With PR_CREATE_FILE, if the file does not exist,
+ *                              the file is created. If the file already 
+ *                              exists, no action and NULL is returned
+ *
+ *     PRIntn mode
+ *         The access permission bits of the file mode, if the file is
+ *         created when PR_CREATE_FILE is on.
+ * OUTPUTS:    None
+ * RETURNS:    PRFileDesc *
+ *     If the file is successfully opened,
+ *     returns a pointer to the PRFileDesc
+ *     created for the newly opened file.
+ *     Returns a NULL pointer if the open
+ *     failed.
+ * SIDE EFFECTS:
+ * RESTRICTIONS:
+ * MEMORY:
+ *     The return value, if not NULL, points to a dynamically allocated
+ *     PRFileDesc object.
+ * ALGORITHM:
+ **************************************************************************
+ */
+
+/* Open flags */
+#define PR_RDONLY       0x01
+#define PR_WRONLY       0x02
+#define PR_RDWR         0x04
+#define PR_CREATE_FILE  0x08
+#define PR_APPEND       0x10
+#define PR_TRUNCATE     0x20
+#define PR_SYNC         0x40
+#define PR_EXCL         0x80
+
+/*
+** File modes ....
+**
+** CAVEAT: 'mode' is currently only applicable on UNIX platforms.
+** The 'mode' argument may be ignored by PR_Open on other platforms.
+**
+**   00400   Read by owner.
+**   00200   Write by owner.
+**   00100   Execute (search if a directory) by owner.
+**   00040   Read by group.
+**   00020   Write by group.
+**   00010   Execute by group.
+**   00004   Read by others.
+**   00002   Write by others
+**   00001   Execute by others.
+**
+*/
+
+NSPR_API(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode);
+
+/*
+ **************************************************************************
+ * FUNCTION: PR_OpenFile
+ * DESCRIPTION:
+ *     Open a file for reading, writing, or both.
+ *     PR_OpenFile has the same prototype as PR_Open but implements
+ *     the specified file mode where possible.
+ **************************************************************************
+ */
+
+/* File mode bits */
+#define PR_IRWXU 00700  /* read, write, execute/search by owner */
+#define PR_IRUSR 00400  /* read permission, owner */
+#define PR_IWUSR 00200  /* write permission, owner */
+#define PR_IXUSR 00100  /* execute/search permission, owner */
+#define PR_IRWXG 00070  /* read, write, execute/search by group */
+#define PR_IRGRP 00040  /* read permission, group */
+#define PR_IWGRP 00020  /* write permission, group */
+#define PR_IXGRP 00010  /* execute/search permission, group */
+#define PR_IRWXO 00007  /* read, write, execute/search by others */
+#define PR_IROTH 00004  /* read permission, others */
+#define PR_IWOTH 00002  /* write permission, others */
+#define PR_IXOTH 00001  /* execute/search permission, others */
+
+NSPR_API(PRFileDesc*) PR_OpenFile(
+    const char *name, PRIntn flags, PRIntn mode);
+
+#ifdef MOZ_UNICODE
+/*
+ * EXPERIMENTAL: This function may be removed in a future release.
+ */
+NSPR_API(PRFileDesc*) PR_OpenFileUTF16(
+    const PRUnichar *name, PRIntn flags, PRIntn mode);
+#endif /* MOZ_UNICODE */
+
+/*
+ **************************************************************************
+ * FUNCTION: PR_Close
+ * DESCRIPTION:
+ *     Close a file or socket.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         a pointer to a PRFileDesc.
+ * OUTPUTS:
+ *     None.
+ * RETURN:
+ *     PRStatus
+ * SIDE EFFECTS:
+ * RESTRICTIONS:
+ *     None.
+ * MEMORY:
+ *     The dynamic memory pointed to by the argument fd is freed.
+ **************************************************************************
+ */
+
+NSPR_API(PRStatus)    PR_Close(PRFileDesc *fd);
+
+/*
+ **************************************************************************
+ * FUNCTION: PR_Read
+ * DESCRIPTION:
+ *     Read bytes from a file or socket.
+ *     The operation will block until either an end of stream indication is
+ *     encountered, some positive number of bytes are transferred, or there
+ *     is an error. No more than 'amount' bytes will be transferred.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         pointer to the PRFileDesc object for the file or socket
+ *     void *buf
+ *         pointer to a buffer to hold the data read in.
+ *     PRInt32 amount
+ *         the size of 'buf' (in bytes)
+ * OUTPUTS:
+ * RETURN:
+ *     PRInt32
+ *         a positive number indicates the number of bytes actually read in.
+ *         0 means end of file is reached or the network connection is closed.
+ *         -1 indicates a failure. The reason for the failure is obtained
+ *         by calling PR_GetError().
+ * SIDE EFFECTS:
+ *     data is written into the buffer pointed to by 'buf'.
+ * RESTRICTIONS:
+ *     None.
+ * MEMORY:
+ *     N/A
+ * ALGORITHM:
+ *     N/A
+ **************************************************************************
+ */
+
+NSPR_API(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount);
+
+/*
+ ***************************************************************************
+ * FUNCTION: PR_Write
+ * DESCRIPTION:
+ *     Write a specified number of bytes to a file or socket.  The thread
+ *     invoking this function blocks until all the data is written.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         pointer to a PRFileDesc object that refers to a file or socket
+ *     const void *buf
+ *         pointer to the buffer holding the data
+ *     PRInt32 amount
+ *         amount of data in bytes to be written from the buffer
+ * OUTPUTS:
+ *     None.
+ * RETURN: PRInt32
+ *     A positive number indicates the number of bytes successfully written.
+ *     A -1 is an indication that the operation failed. The reason
+ *     for the failure is obtained by calling PR_GetError().
+ ***************************************************************************
+ */
+
+NSPR_API(PRInt32) PR_Write(PRFileDesc *fd,const void *buf,PRInt32 amount);
+
+/*
+ ***************************************************************************
+ * FUNCTION: PR_Writev
+ * DESCRIPTION:
+ *     Write data to a socket.  The data is organized in a PRIOVec array. The
+ *     operation will block until all the data is written or the operation
+ *     fails.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         Pointer that points to a PRFileDesc object for a socket.
+ *     const PRIOVec *iov
+ *         An array of PRIOVec.  PRIOVec is a struct with the following
+ *         two fields:
+ *             char *iov_base;
+ *             int iov_len;
+ *     PRInt32 iov_size
+ *         Number of elements in the iov array. The value of this
+ *         argument must not be greater than PR_MAX_IOVECTOR_SIZE.
+ *         If it is, the method will fail (PR_BUFFER_OVERFLOW_ERROR).
+ *     PRIntervalTime timeout
+ *       Time limit for completion of the entire write operation.
+ * OUTPUTS:
+ *     None
+ * RETURN:
+ *     A positive number indicates the number of bytes successfully written.
+ *     A -1 is an indication that the operation failed. The reason
+ *     for the failure is obtained by calling PR_GetError().
+ ***************************************************************************
+ */
+
+#define PR_MAX_IOVECTOR_SIZE 16   /* 'iov_size' must be <= */
+
+NSPR_API(PRInt32) PR_Writev(
+    PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size,
+    PRIntervalTime timeout);
+
+/*
+ ***************************************************************************
+ * FUNCTION: PR_Delete
+ * DESCRIPTION:
+ *     Delete a file from the filesystem. The operation may fail if the
+ *     file is open.
+ * INPUTS:
+ *     const char *name
+ *         Path name of the file to be deleted.
+ * OUTPUTS:
+ *     None.
+ * RETURN: PRStatus
+ *     The function returns PR_SUCCESS if the file is successfully
+ *     deleted, otherwise it returns PR_FAILURE.
+ ***************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_Delete(const char *name);
+
+/**************************************************************************/
+
+typedef enum PRFileType
+{
+    PR_FILE_FILE = 1,
+    PR_FILE_DIRECTORY = 2,
+    PR_FILE_OTHER = 3
+} PRFileType;
+
+struct PRFileInfo {
+    PRFileType type;        /* Type of file */
+    PROffset32 size;        /* Size, in bytes, of file's contents */
+    PRTime creationTime;    /* Creation time per definition of PRTime */
+    PRTime modifyTime;      /* Last modification time per definition of PRTime */
+};
+
+struct PRFileInfo64 {
+    PRFileType type;        /* Type of file */
+    PROffset64 size;        /* Size, in bytes, of file's contents */
+    PRTime creationTime;    /* Creation time per definition of PRTime */
+    PRTime modifyTime;      /* Last modification time per definition of PRTime */
+};
+
+/****************************************************************************
+ * FUNCTION: PR_GetFileInfo, PR_GetFileInfo64
+ * DESCRIPTION:
+ *     Get the information about the file with the given path name. This is
+ *     applicable only to NSFileDesc describing 'file' types (see
+ * INPUTS:
+ *     const char *fn
+ *         path name of the file
+ * OUTPUTS:
+ *     PRFileInfo *info
+ *         Information about the given file is written into the file
+ *         information object pointer to by 'info'.
+ * RETURN: PRStatus
+ *     PR_GetFileInfo returns PR_SUCCESS if file information is successfully
+ *     obtained, otherwise it returns PR_FAILURE.
+ ***************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info);
+NSPR_API(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info);
+
+#ifdef MOZ_UNICODE
+/*
+ * EXPERIMENTAL: This function may be removed in a future release.
+ */
+NSPR_API(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info);
+#endif /* MOZ_UNICODE */
+
+/*
+ **************************************************************************
+ * FUNCTION: PR_GetOpenFileInfo, PR_GetOpenFileInfo64
+ * DESCRIPTION:
+ *     Get information about an open file referred to by the
+ *     given PRFileDesc object.
+ * INPUTS:
+ *     const PRFileDesc *fd
+ *          A reference to a valid, open file.
+ * OUTPUTS:
+ *     Same as PR_GetFileInfo, PR_GetFileInfo64
+ * RETURN: PRStatus
+ *     PR_GetFileInfo returns PR_SUCCESS if file information is successfully
+ *     obtained, otherwise it returns PR_FAILURE.
+ ***************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info);
+NSPR_API(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info);
+
+/*
+ **************************************************************************
+ * FUNCTION: PR_Rename
+ * DESCRIPTION:
+ *     Rename a file from the old name 'from' to the new name 'to'.
+ * INPUTS:
+ *     const char *from
+ *         The old name of the file to be renamed.
+ *     const char *to
+ *         The new name of the file.
+ * OUTPUTS:
+ *     None.
+ * RETURN: PRStatus
+ **************************************************************************
+ */
+
+NSPR_API(PRStatus)    PR_Rename(const char *from, const char *to);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Access
+ * DESCRIPTION:
+ *     Determine accessibility of a file.
+ * INPUTS:
+ *     const char *name
+ *         path name of the file
+ *     PRAccessHow how
+ *         specifies which access permission to check for.
+ *         It can be one of the following values:
+ *             PR_ACCESS_READ_OK       Test for read permission
+ *             PR_ACCESS_WRITE_OK      Test for write permission
+ *             PR_ACCESS_EXISTS        Check existence of file
+ * OUTPUTS:
+ *     None.
+ * RETURN: PRStatus
+ *     PR_SUCCESS is returned if the requested access is permitted.
+ *     Otherwise, PR_FAILURE is returned. Additional information
+ *     regarding the reason for the failure may be retrieved from
+ *     PR_GetError().
+ *************************************************************************
+ */
+
+typedef enum PRAccessHow {
+    PR_ACCESS_EXISTS = 1,
+    PR_ACCESS_WRITE_OK = 2,
+    PR_ACCESS_READ_OK = 3
+} PRAccessHow;
+
+NSPR_API(PRStatus) PR_Access(const char *name, PRAccessHow how);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Seek, PR_Seek64
+ * DESCRIPTION:
+ *     Moves read-write file offset
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         Pointer to a PRFileDesc object.
+ *     PROffset32, PROffset64 offset
+ *         Specifies a value, in bytes, that is used in conjunction
+ *         with the 'whence' parameter to set the file pointer.  A
+ *         negative value causes seeking in the reverse direction.
+ *     PRSeekWhence whence
+ *         Specifies how to interpret the 'offset' parameter in setting
+ *         the file pointer associated with the 'fd' parameter.
+ *         Values for the 'whence' parameter are:
+ *             PR_SEEK_SET  Sets the file pointer to the value of the
+ *                          'offset' parameter
+ *             PR_SEEK_CUR  Sets the file pointer to its current location
+ *                          plus the value of the offset parameter.
+ *             PR_SEEK_END  Sets the file pointer to the size of the
+ *                          file plus the value of the offset parameter.
+ * OUTPUTS:
+ *     None.
+ * RETURN: PROffset32, PROffset64
+ *     Upon successful completion, the resulting pointer location,
+ *     measured in bytes from the beginning of the file, is returned.
+ *     If the PR_Seek() function fails, the file offset remains
+ *     unchanged, and the returned value is -1. The error code can
+ *     then be retrieved via PR_GetError().
+ *************************************************************************
+ */
+
+NSPR_API(PROffset32) PR_Seek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence);
+NSPR_API(PROffset64) PR_Seek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence);
+
+/*
+ ************************************************************************
+ * FUNCTION: PR_Available
+ * DESCRIPTION:
+ *     Determine the amount of data in bytes available for reading
+ *     in the given file or socket.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         Pointer to a PRFileDesc object that refers to a file or
+ *         socket.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRInt32, PRInt64
+ *     Upon successful completion, PR_Available returns the number of
+ *     bytes beyond the current read pointer that is available for
+ *     reading.  Otherwise, it returns a -1 and the reason for the
+ *     failure can be retrieved via PR_GetError().
+ ************************************************************************
+ */
+
+NSPR_API(PRInt32) PR_Available(PRFileDesc *fd);
+NSPR_API(PRInt64) PR_Available64(PRFileDesc *fd);
+
+/*
+ ************************************************************************
+ * FUNCTION: PR_Sync
+ * DESCRIPTION:
+ *     Sync any buffered data for a fd to its backing device (disk).
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         Pointer to a PRFileDesc object that refers to a file or
+ *         socket
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *     PR_SUCCESS is returned if the requested access is permitted.
+ *     Otherwise, PR_FAILURE is returned.
+ ************************************************************************
+ */
+
+NSPR_API(PRStatus)	PR_Sync(PRFileDesc *fd);
+
+/************************************************************************/
+
+struct PRDirEntry {
+    const char *name;        /* name of entry, relative to directory name */
+};
+
+#ifdef MOZ_UNICODE
+struct PRDirEntryUTF16 {
+    const PRUnichar *name;   /* name of entry in UTF16, relative to
+                              * directory name */
+};
+#endif /* MOZ_UNICODE */
+
+#if !defined(NO_NSPR_10_SUPPORT)
+#define PR_DirName(dirEntry)	(dirEntry->name)
+#endif
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_OpenDir
+ * DESCRIPTION:
+ *     Open the directory by the given name
+ * INPUTS:
+ *     const char *name
+ *         path name of the directory to be opened
+ * OUTPUTS:
+ *     None
+ * RETURN: PRDir *
+ *     If the directory is sucessfully opened, a PRDir object is
+ *     dynamically allocated and a pointer to it is returned.
+ *     If the directory cannot be opened, a NULL pointer is returned.
+ * MEMORY:
+ *     Upon successful completion, the return value points to
+ *     dynamically allocated memory.
+ *************************************************************************
+ */
+
+NSPR_API(PRDir*) PR_OpenDir(const char *name);
+
+#ifdef MOZ_UNICODE
+/*
+ * EXPERIMENTAL: This function may be removed in a future release.
+ */
+NSPR_API(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name);
+#endif /* MOZ_UNICODE */
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_ReadDir
+ * DESCRIPTION:
+ * INPUTS:
+ *     PRDir *dir
+ *         pointer to a PRDir object that designates an open directory
+ *     PRDirFlags flags
+ *           PR_SKIP_NONE     Do not skip any files
+ *           PR_SKIP_DOT      Skip the directory entry "." that
+ *                            represents the current directory
+ *           PR_SKIP_DOT_DOT  Skip the directory entry ".." that
+ *                            represents the parent directory.
+ *           PR_SKIP_BOTH     Skip both '.' and '..'
+ *           PR_SKIP_HIDDEN   Skip hidden files
+ * OUTPUTS:
+ * RETURN: PRDirEntry*
+ *     Returns a pointer to the next entry in the directory.  Returns
+ *     a NULL pointer upon reaching the end of the directory or when an
+ *     error occurs. The actual reason can be retrieved via PR_GetError().
+ *************************************************************************
+ */
+
+typedef enum PRDirFlags {
+    PR_SKIP_NONE = 0x0,
+    PR_SKIP_DOT = 0x1,
+    PR_SKIP_DOT_DOT = 0x2,
+    PR_SKIP_BOTH = 0x3,
+    PR_SKIP_HIDDEN = 0x4
+} PRDirFlags;
+
+NSPR_API(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags);
+
+#ifdef MOZ_UNICODE
+/*
+ * EXPERIMENTAL: This function may be removed in a future release.
+ */
+NSPR_API(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags);
+#endif /* MOZ_UNICODE */
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_CloseDir
+ * DESCRIPTION:
+ *     Close the specified directory.
+ * INPUTS:
+ *     PRDir *dir
+ *        The directory to be closed.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *        If successful, will return a status of PR_SUCCESS. Otherwise
+ *        a value of PR_FAILURE. The reason for the failure may be re-
+ *        trieved using PR_GetError().
+ *************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_CloseDir(PRDir *dir);
+
+#ifdef MOZ_UNICODE
+/*
+ * EXPERIMENTAL: This function may be removed in a future release.
+ */
+NSPR_API(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir);
+#endif /* MOZ_UNICODE */
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_MkDir
+ * DESCRIPTION:
+ *     Create a new directory with the given name and access mode.
+ * INPUTS:
+ *     const char *name
+ *        The name of the directory to be created. All the path components
+ *        up to but not including the leaf component must already exist.
+ *     PRIntn mode
+ *        See 'mode' definiton in PR_Open().
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *        If successful, will return a status of PR_SUCCESS. Otherwise
+ *        a value of PR_FAILURE. The reason for the failure may be re-
+ *        trieved using PR_GetError().
+ *************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_MkDir(const char *name, PRIntn mode);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_MakeDir
+ * DESCRIPTION:
+ *     Create a new directory with the given name and access mode.
+ *     PR_MakeDir has the same prototype as PR_MkDir but implements
+ *     the specified access mode where possible.
+ *************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_MakeDir(const char *name, PRIntn mode);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_RmDir
+ * DESCRIPTION:
+ *     Remove a directory by the given name.
+ * INPUTS:
+ *     const char *name
+ *        The name of the directory to be removed. All the path components
+ *        must already exist. Only the leaf component will be removed.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *        If successful, will return a status of PR_SUCCESS. Otherwise
+ *        a value of PR_FAILURE. The reason for the failure may be re-
+ *        trieved using PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_RmDir(const char *name);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_NewUDPSocket
+ * DESCRIPTION:
+ *     Create a new UDP socket.
+ * INPUTS:
+ *     None
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_NewUDPSocket returns a pointer
+ *     to the PRFileDesc created for the newly opened UDP socket.
+ *     Returns a NULL pointer if the creation of a new UDP socket failed.
+ *
+ **************************************************************************
+ */
+
+NSPR_API(PRFileDesc*)    PR_NewUDPSocket(void);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_NewTCPSocket
+ * DESCRIPTION:
+ *     Create a new TCP socket.
+ * INPUTS:
+ *     None
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_NewTCPSocket returns a pointer
+ *     to the PRFileDesc created for the newly opened TCP socket.
+ *     Returns a NULL pointer if the creation of a new TCP socket failed.
+ *
+ **************************************************************************
+ */
+
+NSPR_API(PRFileDesc*)    PR_NewTCPSocket(void);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_OpenUDPSocket
+ * DESCRIPTION:
+ *     Create a new UDP socket of the specified address family.
+ * INPUTS:
+ *     PRIntn af
+ *       Address family
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_OpenUDPSocket returns a pointer
+ *     to the PRFileDesc created for the newly opened UDP socket.
+ *     Returns a NULL pointer if the creation of a new UDP socket failed.
+ *
+ **************************************************************************
+ */
+
+NSPR_API(PRFileDesc*)    PR_OpenUDPSocket(PRIntn af);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_OpenTCPSocket
+ * DESCRIPTION:
+ *     Create a new TCP socket of the specified address family.
+ * INPUTS:
+ *     PRIntn af
+ *       Address family
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_NewTCPSocket returns a pointer
+ *     to the PRFileDesc created for the newly opened TCP socket.
+ *     Returns a NULL pointer if the creation of a new TCP socket failed.
+ *
+ **************************************************************************
+ */
+
+NSPR_API(PRFileDesc*)    PR_OpenTCPSocket(PRIntn af);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Connect
+ * DESCRIPTION:
+ *     Initiate a connection on a socket.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       Points to a PRFileDesc object representing a socket
+ *     PRNetAddr *addr
+ *       Specifies the address of the socket in its own communication
+ *       space.
+ *     PRIntervalTime timeout
+ *       The function uses the lesser of the provided timeout and
+ *       the OS's connect timeout.  In particular, if you specify
+ *       PR_INTERVAL_NO_TIMEOUT as the timeout, the OS's connection
+ *       time limit will be used.
+ *
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *     Upon successful completion of connection initiation, PR_Connect
+ *     returns PR_SUCCESS.  Otherwise, it returns PR_FAILURE.  Further
+ *     failure information can be obtained by calling PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_Connect(
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_ConnectContinue
+ * DESCRIPTION:
+ *     Continue a nonblocking connect.  After a nonblocking connect
+ *     is initiated with PR_Connect() (which fails with
+ *     PR_IN_PROGRESS_ERROR), one should call PR_Poll() on the socket,
+ *     with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT.  When
+ *     PR_Poll() returns, one calls PR_ConnectContinue() on the
+ *     socket to determine whether the nonblocking connect has
+ *     completed or is still in progress.  Repeat the PR_Poll(),
+ *     PR_ConnectContinue() sequence until the nonblocking connect
+ *     has completed.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *         the file descriptor representing a socket
+ *     PRInt16 out_flags
+ *         the out_flags field of the poll descriptor returned by
+ *         PR_Poll()
+ * RETURN: PRStatus
+ *     If the nonblocking connect has successfully completed,
+ *     PR_ConnectContinue returns PR_SUCCESS.  If PR_ConnectContinue()
+ *     returns PR_FAILURE, call PR_GetError():
+ *     - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in
+ *       progress and has not completed yet.  The caller should poll
+ *       on the file descriptor for the in_flags
+ *       PR_POLL_WRITE|PR_POLL_EXCEPT and retry PR_ConnectContinue
+ *       later when PR_Poll() returns.
+ *     - Other errors: the nonblocking connect has failed with this
+ *       error code.
+ */
+
+NSPR_API(PRStatus)    PR_ConnectContinue(PRFileDesc *fd, PRInt16 out_flags);
+
+/*
+ *************************************************************************
+ * THIS FUNCTION IS DEPRECATED.  USE PR_ConnectContinue INSTEAD.
+ *
+ * FUNCTION: PR_GetConnectStatus
+ * DESCRIPTION:
+ *     Get the completion status of a nonblocking connect.  After
+ *     a nonblocking connect is initiated with PR_Connect() (which
+ *     fails with PR_IN_PROGRESS_ERROR), one should call PR_Poll()
+ *     on the socket, with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT.
+ *     When PR_Poll() returns, one calls PR_GetConnectStatus on the
+ *     PRPollDesc structure to determine whether the nonblocking
+ *     connect has succeeded or failed.
+ * INPUTS:
+ *     const PRPollDesc *pd
+ *         Pointer to a PRPollDesc whose fd member is the socket,
+ *         and in_flags must contain PR_POLL_WRITE and PR_POLL_EXCEPT.
+ *         PR_Poll() should have been called and set the out_flags.
+ * RETURN: PRStatus
+ *     If the nonblocking connect has successfully completed,
+ *     PR_GetConnectStatus returns PR_SUCCESS.  If PR_GetConnectStatus()
+ *     returns PR_FAILURE, call PR_GetError():
+ *     - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in
+ *       progress and has not completed yet.
+ *     - Other errors: the nonblocking connect has failed with this
+ *       error code.
+ */
+
+NSPR_API(PRStatus)    PR_GetConnectStatus(const PRPollDesc *pd);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Accept
+ * DESCRIPTION:
+ *     Accept a connection on a socket.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       Points to a PRFileDesc object representing the rendezvous socket
+ *       on which the caller is willing to accept new connections.
+ *     PRIntervalTime timeout
+ *       Time limit for completion of the accept operation.
+ * OUTPUTS:
+ *     PRNetAddr *addr
+ *       Returns the address of the connecting entity in its own
+ *       communication space. It may be NULL.
+ * RETURN: PRFileDesc*
+ *     Upon successful acceptance of a connection, PR_Accept
+ *     returns a valid file descriptor. Otherwise, it returns NULL.
+ *     Further failure information can be obtained by calling PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRFileDesc*) PR_Accept(
+    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Bind
+ * DESCRIPTION:
+ *    Bind an address to a socket.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       Points to a PRFileDesc object representing a socket.
+ *     PRNetAddr *addr
+ *       Specifies the address to which the socket will be bound.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *     Upon successful binding of an address to a socket, PR_Bind
+ *     returns PR_SUCCESS.  Otherwise, it returns PR_FAILURE.  Further
+ *     failure information can be obtained by calling PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Listen
+ * DESCRIPTION:
+ *    Listen for connections on a socket.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       Points to a PRFileDesc object representing a socket that will be
+ *       used to listen for new connections.
+ *     PRIntn backlog
+ *       Specifies the maximum length of the queue of pending connections.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *     Upon successful completion of listen request, PR_Listen
+ *     returns PR_SUCCESS.  Otherwise, it returns PR_FAILURE.  Further
+ *     failure information can be obtained by calling PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Shutdown
+ * DESCRIPTION:
+ *    Shut down part of a full-duplex connection on a socket.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       Points to a PRFileDesc object representing a connected socket.
+ *     PRIntn how
+ *       Specifies the kind of disallowed operations on the socket.
+ *           PR_SHUTDOWN_RCV - Further receives will be disallowed
+ *           PR_SHUTDOWN_SEND - Further sends will be disallowed
+ *           PR_SHUTDOWN_BOTH - Further sends and receives will be disallowed
+ * OUTPUTS:
+ *     None
+ * RETURN: PRStatus
+ *     Upon successful completion of shutdown request, PR_Shutdown
+ *     returns PR_SUCCESS.  Otherwise, it returns PR_FAILURE.  Further
+ *     failure information can be obtained by calling PR_GetError().
+ **************************************************************************
+ */
+
+typedef enum PRShutdownHow
+{
+    PR_SHUTDOWN_RCV = 0,      /* disallow further receives */
+    PR_SHUTDOWN_SEND = 1,     /* disallow further sends */
+    PR_SHUTDOWN_BOTH = 2      /* disallow further receives and sends */
+} PRShutdownHow;
+
+NSPR_API(PRStatus)    PR_Shutdown(PRFileDesc *fd, PRShutdownHow how);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Recv
+ * DESCRIPTION:
+ *    Receive a specified number of bytes from a connected socket.
+ *     The operation will block until some positive number of bytes are 
+ *     transferred, a time out has occurred, or there is an error. 
+ *     No more than 'amount' bytes will be transferred.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       points to a PRFileDesc object representing a socket.
+ *     void *buf
+ *       pointer to a buffer to hold the data received.
+ *     PRInt32 amount
+ *       the size of 'buf' (in bytes)
+ *     PRIntn flags
+ *       must be zero or PR_MSG_PEEK.
+ *     PRIntervalTime timeout
+ *       Time limit for completion of the receive operation.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRInt32
+ *         a positive number indicates the number of bytes actually received.
+ *         0 means the network connection is closed.
+ *         -1 indicates a failure. The reason for the failure is obtained
+ *         by calling PR_GetError().
+ **************************************************************************
+ */
+
+#define PR_MSG_PEEK 0x2
+
+NSPR_API(PRInt32)    PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+                PRIntn flags, PRIntervalTime timeout);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_Send
+ * DESCRIPTION:
+ *    Send a specified number of bytes from a connected socket.
+ *     The operation will block until all bytes are 
+ *     processed, a time out has occurred, or there is an error. 
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       points to a PRFileDesc object representing a socket.
+ *     void *buf
+ *       pointer to a buffer from where the data is sent.
+ *     PRInt32 amount
+ *       the size of 'buf' (in bytes)
+ *     PRIntn flags
+ *        (OBSOLETE - must always be zero)
+ *     PRIntervalTime timeout
+ *       Time limit for completion of the send operation.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRInt32
+ *     A positive number indicates the number of bytes successfully processed.
+ *     This number must always equal 'amount'. A -1 is an indication that the
+ *     operation failed. The reason for the failure is obtained by calling
+ *     PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRInt32)    PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+                                PRIntn flags, PRIntervalTime timeout);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_RecvFrom
+ * DESCRIPTION:
+ *     Receive up to a specified number of bytes from socket which may
+ *     or may not be connected.
+ *     The operation will block until one or more bytes are 
+ *     transferred, a time out has occurred, or there is an error. 
+ *     No more than 'amount' bytes will be transferred.
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       points to a PRFileDesc object representing a socket.
+ *     void *buf
+ *       pointer to a buffer to hold the data received.
+ *     PRInt32 amount
+ *       the size of 'buf' (in bytes)
+ *     PRIntn flags
+ *        (OBSOLETE - must always be zero)
+ *     PRNetAddr *addr
+ *       Specifies the address of the sending peer. It may be NULL.
+ *     PRIntervalTime timeout
+ *       Time limit for completion of the receive operation.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRInt32
+ *         a positive number indicates the number of bytes actually received.
+ *         0 means the network connection is closed.
+ *         -1 indicates a failure. The reason for the failure is obtained
+ *         by calling PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRInt32) PR_RecvFrom(
+    PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+    PRNetAddr *addr, PRIntervalTime timeout);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_SendTo
+ * DESCRIPTION:
+ *    Send a specified number of bytes from an unconnected socket.
+ *    The operation will block until all bytes are 
+ *    sent, a time out has occurred, or there is an error. 
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       points to a PRFileDesc object representing an unconnected socket.
+ *     void *buf
+ *       pointer to a buffer from where the data is sent.
+ *     PRInt32 amount
+ *       the size of 'buf' (in bytes)
+ *     PRIntn flags
+ *        (OBSOLETE - must always be zero)
+ *     PRNetAddr *addr
+ *       Specifies the address of the peer.
+.*     PRIntervalTime timeout
+ *       Time limit for completion of the send operation.
+ * OUTPUTS:
+ *     None
+ * RETURN: PRInt32
+ *     A positive number indicates the number of bytes successfully sent.
+ *     -1 indicates a failure. The reason for the failure is obtained
+ *     by calling PR_GetError().
+ **************************************************************************
+ */
+
+NSPR_API(PRInt32) PR_SendTo(
+    PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+    const PRNetAddr *addr, PRIntervalTime timeout);
+
+/*
+*************************************************************************
+** FUNCTION: PR_TransmitFile
+** DESCRIPTION:
+**    Transmitfile sends a complete file (sourceFile) across a socket 
+**    (networkSocket).  If headers is non-NULL, the headers will be sent across
+**    the socket prior to sending the file.
+** 
+**    Optionally, the PR_TRANSMITFILE_CLOSE_SOCKET flag may be passed to
+**    transmitfile.  This flag specifies that transmitfile should close the
+**    socket after sending the data.
+**
+** INPUTS:
+**    PRFileDesc *networkSocket
+**        The socket to send data over
+**    PRFileDesc *sourceFile
+**        The file to send
+**    const void *headers
+**        A pointer to headers to be sent before sending data
+**    PRInt32       hlen
+**        length of header buffers in bytes.
+**    PRTransmitFileFlags       flags
+**        If the flags indicate that the connection should be closed,
+**        it will be done immediately after transferring the file, unless
+**        the operation is unsuccessful. 
+.*     PRIntervalTime timeout
+ *        Time limit for completion of the transmit operation.
+**
+** RETURNS:
+**    Returns the number of bytes written or -1 if the operation failed.
+**    If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_
+**    SOCKET flag is ignored. The reason for the failure is obtained
+**    by calling PR_GetError().
+**************************************************************************
+*/
+
+NSPR_API(PRInt32) PR_TransmitFile(
+    PRFileDesc *networkSocket, PRFileDesc *sourceFile,
+    const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
+    PRIntervalTime timeout);
+
+/*
+*************************************************************************
+** FUNCTION: PR_SendFile
+** DESCRIPTION:
+**    PR_SendFile sends data from a file (sendData->fd) across a socket 
+**    (networkSocket).  If specified, a header and/or trailer buffer are sent
+**	  before and after the file, respectively. The file offset, number of bytes
+** 	  of file data to send, the header and trailer buffers are specified in the
+**	  sendData argument.
+** 
+**    Optionally, if the PR_TRANSMITFILE_CLOSE_SOCKET flag is passed, the
+**    socket is closed after successfully sending the data.
+**
+** INPUTS:
+**    PRFileDesc *networkSocket
+**        The socket to send data over
+**    PRSendFileData *sendData
+**        Contains the FD, file offset and length, header and trailer
+**		  buffer specifications.
+**    PRTransmitFileFlags       flags
+**        If the flags indicate that the connection should be closed,
+**        it will be done immediately after transferring the file, unless
+**        the operation is unsuccessful. 
+.*     PRIntervalTime timeout
+ *        Time limit for completion of the send operation.
+**
+** RETURNS:
+**    Returns the number of bytes written or -1 if the operation failed.
+**    If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_
+**    SOCKET flag is ignored. The reason for the failure is obtained
+**    by calling PR_GetError().
+**************************************************************************
+*/
+
+struct PRSendFileData {
+	PRFileDesc	*fd;			/* file to send							*/
+	PRUint32	file_offset;	/* file offset							*/
+	PRSize		file_nbytes;	/* number of bytes of file data to send	*/
+								/* if 0, send data from file_offset to	*/
+								/* end-of-file.							*/
+	const void	*header;		/* header buffer						*/
+	PRInt32		hlen;			/* header len							*/
+	const void	*trailer;		/* trailer buffer						*/
+	PRInt32		tlen;			/* trailer len							*/
+};
+
+
+NSPR_API(PRInt32) PR_SendFile(
+    PRFileDesc *networkSocket, PRSendFileData *sendData,
+	PRTransmitFileFlags flags, PRIntervalTime timeout);
+
+/*
+*************************************************************************
+** FUNCTION: PR_AcceptRead
+** DESCRIPTION:
+**    AcceptRead accepts a new connection, returns the newly created
+**    socket's descriptor and also returns the connecting peer's address.
+**    AcceptRead, as its name suggests, also receives the first block of data 
+**    sent by the peer.
+**
+** INPUTS:
+**    PRFileDesc *listenSock
+**        A socket descriptor that has been called with the PR_Listen() 
+**        function, also known as the rendezvous socket.
+**    void *buf
+**        A pointer to a buffer to receive data sent by the client.  This 
+**        buffer must be large enough to receive <amount> bytes of data
+**        and two PRNetAddr structures, plus an extra 32 bytes. See:
+**        PR_ACCEPT_READ_BUF_OVERHEAD.
+**    PRInt32 amount
+**        The number of bytes of client data to receive.  Does not include
+**        the size of the PRNetAddr structures.  If 0, no data will be read
+**        from the client.
+**    PRIntervalTime timeout
+**        The timeout interval only applies to the read portion of the 
+**        operation.  PR_AcceptRead will block indefinitely until the 
+**        connection is accepted; the read will timeout after the timeout 
+**        interval elapses.
+** OUTPUTS:
+**    PRFileDesc **acceptedSock
+**        The file descriptor for the newly connected socket.  This parameter
+**        will only be valid if the function return does not indicate failure.
+**    PRNetAddr  **peerAddr,
+**        The address of the remote socket.  This parameter will only be
+**        valid if the function return does not indicate failure.  The
+**        returned address is not guaranteed to be properly aligned.
+** 
+** RETURNS:
+**     The number of bytes read from the client or -1 on failure.  The reason 
+**     for the failure is obtained by calling PR_GetError().
+**************************************************************************
+**/       
+/* define buffer overhead constant. Add this value to the user's 
+** data length when allocating a buffer to accept data.
+**    Example:
+**    #define USER_DATA_SIZE 10
+**    char buf[USER_DATA_SIZE + PR_ACCEPT_READ_BUF_OVERHEAD];
+**    bytesRead = PR_AcceptRead( s, fd, &a, &p, USER_DATA_SIZE, ...);
+*/
+#define PR_ACCEPT_READ_BUF_OVERHEAD (32+(2*sizeof(PRNetAddr)))
+
+NSPR_API(PRInt32) PR_AcceptRead(
+    PRFileDesc *listenSock, PRFileDesc **acceptedSock,
+    PRNetAddr **peerAddr, void *buf, PRInt32 amount, PRIntervalTime timeout);
+
+/*
+*************************************************************************
+** FUNCTION: PR_NewTCPSocketPair
+** DESCRIPTION:
+**    Create a new TCP socket pair. The returned descriptors can be used
+**    interchangeably; they are interconnected full-duplex descriptors: data
+**    written to one can be read from the other and vice-versa.
+**
+** INPUTS:
+**    None
+** OUTPUTS:
+**    PRFileDesc *fds[2]
+**        The file descriptor pair for the newly created TCP sockets.
+** RETURN: PRStatus
+**     Upon successful completion of TCP socket pair, PR_NewTCPSocketPair 
+**     returns PR_SUCCESS.  Otherwise, it returns PR_FAILURE.  Further
+**     failure information can be obtained by calling PR_GetError().
+** XXX can we implement this on windoze and mac?
+**************************************************************************
+**/
+NSPR_API(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2]);
+
+/*
+*************************************************************************
+** FUNCTION: PR_GetSockName
+** DESCRIPTION:
+**    Get socket name.  Return the network address for this socket.
+**
+** INPUTS:
+**     PRFileDesc *fd
+**       Points to a PRFileDesc object representing the socket.
+** OUTPUTS:
+**     PRNetAddr *addr
+**       Returns the address of the socket in its own communication space.
+** RETURN: PRStatus
+**     Upon successful completion, PR_GetSockName returns PR_SUCCESS.  
+**     Otherwise, it returns PR_FAILURE.  Further failure information can 
+**     be obtained by calling PR_GetError().
+**************************************************************************
+**/
+NSPR_API(PRStatus)	PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr);
+
+/*
+*************************************************************************
+** FUNCTION: PR_GetPeerName
+** DESCRIPTION:
+**    Get name of the connected peer.  Return the network address for the 
+**    connected peer socket.
+**
+** INPUTS:
+**     PRFileDesc *fd
+**       Points to a PRFileDesc object representing the connected peer.
+** OUTPUTS:
+**     PRNetAddr *addr
+**       Returns the address of the connected peer in its own communication
+**       space.
+** RETURN: PRStatus
+**     Upon successful completion, PR_GetPeerName returns PR_SUCCESS.  
+**     Otherwise, it returns PR_FAILURE.  Further failure information can 
+**     be obtained by calling PR_GetError().
+**************************************************************************
+**/
+NSPR_API(PRStatus)	PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr);
+
+NSPR_API(PRStatus)	PR_GetSocketOption(
+    PRFileDesc *fd, PRSocketOptionData *data);
+
+NSPR_API(PRStatus)	PR_SetSocketOption(
+    PRFileDesc *fd, const PRSocketOptionData *data);
+
+/*
+ *********************************************************************
+ *
+ * File descriptor inheritance
+ *
+ *********************************************************************
+ */
+
+/*
+ ************************************************************************
+ * FUNCTION: PR_SetFDInheritable
+ * DESCRIPTION:
+ *    Set the inheritance attribute of a file descriptor.
+ *
+ * INPUTS:
+ *     PRFileDesc *fd
+ *       Points to a PRFileDesc object.
+ *     PRBool inheritable
+ *       If PR_TRUE, the file descriptor fd is set to be inheritable
+ *       by a child process.  If PR_FALSE, the file descriptor is set
+ *       to be not inheritable by a child process.
+ * RETURN: PRStatus
+ *     Upon successful completion, PR_SetFDInheritable returns PR_SUCCESS.  
+ *     Otherwise, it returns PR_FAILURE.  Further failure information can 
+ *     be obtained by calling PR_GetError().
+ *************************************************************************
+ */
+NSPR_API(PRStatus) PR_SetFDInheritable(
+    PRFileDesc *fd,
+    PRBool inheritable);
+
+/*
+ ************************************************************************
+ * FUNCTION: PR_GetInheritedFD
+ * DESCRIPTION:
+ *    Get an inherited file descriptor with the specified name.
+ *
+ * INPUTS:
+ *     const char *name
+ *       The name of the inherited file descriptor.
+ * RETURN: PRFileDesc *
+ *     Upon successful completion, PR_GetInheritedFD returns the
+ *     inherited file descriptor with the specified name.  Otherwise,  
+ *     it returns NULL.  Further failure information can be obtained
+ *     by calling PR_GetError().
+ *************************************************************************
+ */
+NSPR_API(PRFileDesc *) PR_GetInheritedFD(const char *name);
+
+/*
+ *********************************************************************
+ *
+ * Memory-mapped files
+ *
+ *********************************************************************
+ */
+
+typedef struct PRFileMap PRFileMap;
+
+/*
+ * protection options for read and write accesses of a file mapping
+ */
+typedef enum PRFileMapProtect {
+    PR_PROT_READONLY,     /* read only */
+    PR_PROT_READWRITE,    /* readable, and write is shared */
+    PR_PROT_WRITECOPY     /* readable, and write is private (copy-on-write) */
+} PRFileMapProtect;
+
+NSPR_API(PRFileMap *) PR_CreateFileMap(
+    PRFileDesc *fd,
+    PRInt64 size,
+    PRFileMapProtect prot);
+
+/*
+ * return the alignment (in bytes) of the offset argument to PR_MemMap
+ */
+NSPR_API(PRInt32) PR_GetMemMapAlignment(void);
+
+NSPR_API(void *) PR_MemMap(
+    PRFileMap *fmap,
+    PROffset64 offset,  /* must be aligned and sized according to the
+                         * return value of PR_GetMemMapAlignment() */
+    PRUint32 len);
+
+NSPR_API(PRStatus) PR_MemUnmap(void *addr, PRUint32 len);
+
+NSPR_API(PRStatus) PR_CloseFileMap(PRFileMap *fmap);
+
+/*
+ ******************************************************************
+ *
+ * Interprocess communication
+ *
+ ******************************************************************
+ */
+
+/*
+ * Creates an anonymous pipe and returns file descriptors for the
+ * read and write ends of the pipe.
+ */
+
+NSPR_API(PRStatus) PR_CreatePipe(
+    PRFileDesc **readPipe,
+    PRFileDesc **writePipe
+);
+
+/************************************************************************/
+/************** The following definitions are for poll ******************/
+/************************************************************************/
+
+struct PRPollDesc {
+    PRFileDesc* fd;
+    PRInt16 in_flags;
+    PRInt16 out_flags;
+};
+
+/*
+** Bit values for PRPollDesc.in_flags or PRPollDesc.out_flags. Binary-or
+** these together to produce the desired poll request.
+*/
+
+#if defined(_PR_POLL_BACKCOMPAT)
+
+#include <poll.h>
+#define PR_POLL_READ    POLLIN
+#define PR_POLL_WRITE   POLLOUT
+#define PR_POLL_EXCEPT  POLLPRI
+#define PR_POLL_ERR     POLLERR     /* only in out_flags */
+#define PR_POLL_NVAL    POLLNVAL    /* only in out_flags when fd is bad */
+#define PR_POLL_HUP     POLLHUP     /* only in out_flags */
+
+#else  /* _PR_POLL_BACKCOMPAT */
+
+#define PR_POLL_READ    0x1
+#define PR_POLL_WRITE   0x2
+#define PR_POLL_EXCEPT  0x4
+#define PR_POLL_ERR     0x8         /* only in out_flags */
+#define PR_POLL_NVAL    0x10        /* only in out_flags when fd is bad */
+#define PR_POLL_HUP     0x20        /* only in out_flags */
+
+#endif  /* _PR_POLL_BACKCOMPAT */
+
+/*
+*************************************************************************
+** FUNCTION:    PR_Poll
+** DESCRIPTION:
+**
+** The call returns as soon as I/O is ready on one or more of the underlying
+** socket objects. A count of the number of ready descriptors is
+** returned unless a timeout occurs in which case zero is returned.
+**
+** PRPollDesc.fd should be set to a pointer to a PRFileDesc object
+** representing a socket. This field can be set to NULL to indicate to
+** PR_Poll that this PRFileDesc object should be ignored.
+** PRPollDesc.in_flags should be set to the desired request
+** (read/write/except or some combination). Upon successful return from
+** this call PRPollDesc.out_flags will be set to indicate what kind of
+** i/o can be performed on the respective descriptor. PR_Poll() uses the
+** out_flags fields as scratch variables during the call. If PR_Poll()
+** returns 0 or -1, the out_flags fields do not contain meaningful values
+** and must not be used.
+**
+** INPUTS:
+**      PRPollDesc *pds         A pointer to an array of PRPollDesc
+**
+**      PRIntn npds             The number of elements in the array
+**                              If this argument is zero PR_Poll is
+**                              equivalent to a PR_Sleep(timeout).
+**
+**      PRIntervalTime timeout  Amount of time the call will block waiting
+**                              for I/O to become ready. If this time expires
+**                              w/o any I/O becoming ready, the result will
+**                              be zero.
+**
+** OUTPUTS:    None
+** RETURN:
+**      PRInt32                 Number of PRPollDesc's with events or zero
+**                              if the function timed out or -1 on failure.
+**                              The reason for the failure is obtained by
+**                              calling PR_GetError().
+**************************************************************************
+*/
+NSPR_API(PRInt32) PR_Poll(
+    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout);
+
+/*
+**************************************************************************
+**
+** Pollable events
+**
+** A pollable event is a special kind of file descriptor.
+** The only I/O operation you can perform on a pollable event
+** is to poll it with the PR_POLL_READ flag.  You can't
+** read from or write to a pollable event.
+**
+** The purpose of a pollable event is to combine event waiting
+** with I/O waiting in a single PR_Poll call.  Pollable events
+** are implemented using a pipe or a pair of TCP sockets
+** connected via the loopback address, therefore setting and
+** waiting for pollable events are expensive operating system
+** calls.  Do not use pollable events for general thread
+** synchronization. Use condition variables instead.
+**
+** A pollable event has two states: set and unset.  Events
+** are not queued, so there is no notion of an event count.
+** A pollable event is either set or unset.
+**
+** A new pollable event is created by a PR_NewPollableEvent
+** call and is initially in the unset state.
+**
+** PR_WaitForPollableEvent blocks the calling thread until
+** the pollable event is set, and then it atomically unsets
+** the pollable event before it returns.
+**
+** To set a pollable event, call PR_SetPollableEvent.
+**
+** One can call PR_Poll with the PR_POLL_READ flag on a pollable
+** event.  When the pollable event is set, PR_Poll returns with
+** the PR_POLL_READ flag set in the out_flags.
+**
+** To close a pollable event, call PR_DestroyPollableEvent
+** (not PR_Close).
+**
+**************************************************************************
+*/
+
+NSPR_API(PRFileDesc *) PR_NewPollableEvent(void);
+
+NSPR_API(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event);
+
+NSPR_API(PRStatus) PR_SetPollableEvent(PRFileDesc *event);
+
+NSPR_API(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event);
+
+PR_END_EXTERN_C
+
+#endif /* prio_h___ */
diff --git a/mozilla/nsprpub/pr/include/pripcsem.h b/mozilla/nsprpub/pr/include/pripcsem.h
new file mode 100644
index 0000000..5a96be5
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/pripcsem.h
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+/*
+ * File: pripcsem.h
+ *
+ * Description: named semaphores for interprocess
+ * synchronization
+ *
+ * Unrelated processes obtain access to a shared semaphore
+ * by specifying its name.
+ *
+ * Our goal is to support named semaphores on at least
+ * Unix and Win32 platforms.  The implementation will use
+ * one of the three native semaphore APIs: POSIX, System V,
+ * and Win32.
+ *
+ * Because POSIX named semaphores have kernel persistence,
+ * we are forced to have a delete function in this API.
+ */
+
+#ifndef pripcsem_h___
+#define pripcsem_h___
+
+#include "prtypes.h"
+#include "prio.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * PRSem is an opaque structure that represents a named
+ * semaphore.
+ */
+typedef struct PRSem PRSem;
+
+/*
+ * PR_OpenSemaphore --
+ *
+ * Create or open a named semaphore with the specified name.
+ * A handle to the semaphore is returned.
+ *
+ * If the named semaphore doesn't exist and the PR_SEM_CREATE
+ * flag is specified, the named semaphore is created.  The
+ * created semaphore needs to be removed from the system with
+ * a PR_DeleteSemaphore call.
+ *
+ * If PR_SEM_CREATE is specified, the third argument is the
+ * access permission bits of the new semaphore (same
+ * interpretation as the mode argument to PR_Open) and the
+ * fourth argument is the initial value of the new semaphore.
+ * If PR_SEM_CREATE is not specified, the third and fourth
+ * arguments are ignored.
+ */
+
+#define PR_SEM_CREATE 0x1  /* create if not exist */
+#define PR_SEM_EXCL   0x2  /* fail if already exists */
+
+NSPR_API(PRSem *) PR_OpenSemaphore(
+    const char *name, PRIntn flags, PRIntn mode, PRUintn value);
+
+/*
+ * PR_WaitSemaphore --
+ *
+ * If the value of the semaphore is > 0, decrement the value and return.
+ * If the value is 0, sleep until the value becomes > 0, then decrement
+ * the value and return.
+ *
+ * The "test and decrement" operation is performed atomically.
+ */
+
+NSPR_API(PRStatus) PR_WaitSemaphore(PRSem *sem);
+
+/*
+ * PR_PostSemaphore --
+ *
+ * Increment the value of the named semaphore by 1.
+ */
+
+NSPR_API(PRStatus) PR_PostSemaphore(PRSem *sem);
+
+/*
+ * PR_CloseSemaphore --
+ *
+ * Close a named semaphore handle.
+ */
+
+NSPR_API(PRStatus) PR_CloseSemaphore(PRSem *sem);
+
+/*
+ * PR_DeleteSemaphore --
+ *
+ * Remove a named semaphore from the system.
+ */
+
+NSPR_API(PRStatus) PR_DeleteSemaphore(const char *name);
+
+PR_END_EXTERN_C
+
+#endif /* pripcsem_h___ */
diff --git a/mozilla/nsprpub/pr/include/private/pprio.h b/mozilla/nsprpub/pr/include/private/pprio.h
new file mode 100644
index 0000000..8f29657
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/private/pprio.h
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:	pprio.h
+**
+** Description:	Private definitions for I/O related structures
+*/
+
+#ifndef pprio_h___
+#define pprio_h___
+
+#include "prtypes.h"
+#include "prio.h"
+
+PR_BEGIN_EXTERN_C
+
+/************************************************************************/
+/************************************************************************/
+
+#ifdef _WIN64
+typedef __int64 PROsfd;
+#else
+typedef PRInt32 PROsfd;
+#endif
+
+/* Return the method tables for files, tcp sockets and udp sockets */
+NSPR_API(const PRIOMethods*)    PR_GetFileMethods(void);
+NSPR_API(const PRIOMethods*)    PR_GetTCPMethods(void);
+NSPR_API(const PRIOMethods*)    PR_GetUDPMethods(void);
+NSPR_API(const PRIOMethods*)    PR_GetPipeMethods(void);
+
+/*
+** Convert a NSPR socket handle to a native socket handle.
+**
+** Using this function makes your code depend on the properties of the
+** current NSPR implementation, which may change (although extremely
+** unlikely because of NSPR's backward compatibility requirement).  Avoid
+** using it if you can.
+**
+** If you use this function, you need to understand what NSPR does to
+** the native handle.  For example, NSPR puts native socket handles in
+** non-blocking mode or associates them with an I/O completion port (the
+** WINNT build configuration only).  Your use of the native handle should
+** not interfere with NSPR's use of the native handle.  If your code
+** changes the configuration of the native handle, (e.g., changes it to
+** blocking or closes it), NSPR will not work correctly.
+*/
+NSPR_API(PROsfd)       PR_FileDesc2NativeHandle(PRFileDesc *);
+NSPR_API(void)         PR_ChangeFileDescNativeHandle(PRFileDesc *, PROsfd);
+NSPR_API(PRFileDesc*)  PR_AllocFileDesc(PROsfd osfd,
+                                         const PRIOMethods *methods);
+NSPR_API(void)         PR_FreeFileDesc(PRFileDesc *fd);
+/*
+** Import an existing OS file to NSPR. 
+*/
+NSPR_API(PRFileDesc*)  PR_ImportFile(PROsfd osfd);
+NSPR_API(PRFileDesc*)  PR_ImportPipe(PROsfd osfd);
+NSPR_API(PRFileDesc*)  PR_ImportTCPSocket(PROsfd osfd);
+NSPR_API(PRFileDesc*)  PR_ImportUDPSocket(PROsfd osfd);
+
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_CreateSocketPollFd
+ * DESCRIPTION:
+ *     Create a PRFileDesc wrapper for a native socket handle, for use with
+ *	   PR_Poll only
+ * INPUTS:
+ *     None
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_CreateSocketPollFd returns a pointer
+ *     to the PRFileDesc created for the native socket handle
+ *     Returns a NULL pointer if the create of a new PRFileDesc failed
+ *
+ **************************************************************************
+ */
+
+NSPR_API(PRFileDesc*)	PR_CreateSocketPollFd(PROsfd osfd);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_DestroySocketPollFd
+ * DESCRIPTION:
+ *     Destroy the PRFileDesc wrapper created by PR_CreateSocketPollFd
+ * INPUTS:
+ *     None
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_DestroySocketPollFd returns
+ *	   PR_SUCCESS, else PR_FAILURE
+ *
+ **************************************************************************
+ */
+
+NSPR_API(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd);
+
+
+/*
+** Macros for PR_Socket
+**
+** Socket types: PR_SOCK_STREAM, PR_SOCK_DGRAM
+*/
+
+#ifdef WIN32
+
+#define PR_SOCK_STREAM 1
+#define PR_SOCK_DGRAM 2
+
+#else /* WIN32 */
+
+#define PR_SOCK_STREAM SOCK_STREAM
+#define PR_SOCK_DGRAM SOCK_DGRAM
+
+#endif /* WIN32 */
+
+/*
+** Create a new Socket; this function is obsolete.
+*/
+NSPR_API(PRFileDesc*)	PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto);
+
+/* FUNCTION: PR_LockFile
+** DESCRIPTION:
+**    Lock a file for exclusive access.
+** RETURNS:
+**    PR_SUCCESS when the lock is held
+**    PR_FAILURE otherwise
+*/
+NSPR_API(PRStatus) PR_LockFile(PRFileDesc *fd);
+
+/* FUNCTION: PR_TLockFile
+** DESCRIPTION:
+**    Test and Lock a file for exclusive access.  Do not block if the
+**    file cannot be locked immediately.
+** RETURNS:
+**    PR_SUCCESS when the lock is held
+**    PR_FAILURE otherwise
+*/
+NSPR_API(PRStatus) PR_TLockFile(PRFileDesc *fd);
+
+/* FUNCTION: PR_UnlockFile
+** DESCRIPTION:
+**    Unlock a file which has been previously locked successfully by this
+**    process.
+** RETURNS:
+**    PR_SUCCESS when the lock is released
+**    PR_FAILURE otherwise
+*/
+NSPR_API(PRStatus) PR_UnlockFile(PRFileDesc *fd);
+
+/*
+** Emulate acceptread by accept and recv.
+*/
+NSPR_API(PRInt32) PR_EmulateAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
+    PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout);
+
+/*
+** Emulate sendfile by reading from the file and writing to the socket.
+** The file is memory-mapped if memory-mapped files are supported.
+*/
+NSPR_API(PRInt32) PR_EmulateSendFile(
+    PRFileDesc *networkSocket, PRSendFileData *sendData,
+    PRTransmitFileFlags flags, PRIntervalTime timeout);
+
+#ifdef WIN32
+/* FUNCTION: PR_NTFast_AcceptRead
+** DESCRIPTION:
+**    NT has the notion of an "accept context", which is only needed in
+**    order to make certain calls.  By default, a socket connected via
+**    AcceptEx can only do a limited number of things without updating
+**    the acceptcontext.  The generic version of PR_AcceptRead always
+**    updates the accept context.  This version does not.
+**/
+NSPR_API(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
+              PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime t);
+
+typedef void (*_PR_AcceptTimeoutCallback)(void *);
+
+/* FUNCTION: PR_NTFast_AcceptRead_WithTimeoutCallback
+** DESCRIPTION:
+**    The AcceptEx call combines the accept with the read function.  However,
+**    our daemon threads need to be able to wakeup and reliably flush their
+**    log buffers if the Accept times out.  However, with the current blocking
+**    interface to AcceptRead, there is no way for us to timeout the Accept;
+**    this is because when we timeout the Read, we can close the newly 
+**    socket and continue; but when we timeout the accept itself, there is no
+**    new socket to timeout.  So instead, this version of the function is
+**    provided.  After the initial timeout period elapses on the accept()
+**    portion of the function, it will call the callback routine and then
+**    continue the accept.   If the timeout occurs on the read, it will 
+**    close the connection and return error.
+*/
+NSPR_API(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
+              PRFileDesc *sd, 
+              PRFileDesc **nd,
+              PRNetAddr **raddr, 
+              void *buf, 
+              PRInt32 amount, 
+              PRIntervalTime t,
+              _PR_AcceptTimeoutCallback callback, 
+              void *callback_arg);
+
+/* FUNCTION: PR_NTFast_Accept
+** DESCRIPTION:
+**    NT has the notion of an "accept context", which is only needed in
+**    order to make certain calls.  By default, a socket connected via
+**    AcceptEx can only do a limited number of things without updating
+**    the acceptcontext.  The generic version of PR_Accept always
+**    updates the accept context.  This version does not.
+**/
+NSPR_API(PRFileDesc*)	PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
+                                                PRIntervalTime timeout);
+
+/* FUNCTION: PR_NTFast_Update
+** DESCRIPTION:
+**    For sockets accepted with PR_NTFast_Accept or PR_NTFastAcceptRead,
+**    this function will update the accept context for those sockets,
+**    so that the socket can make general purpose socket calls.
+**    Without calling this, the only operations supported on the socket
+**    Are PR_Read, PR_Write, PR_Transmitfile, and PR_Close.
+*/
+NSPR_API(void) PR_NTFast_UpdateAcceptContext(PRFileDesc *acceptSock, 
+                                        PRFileDesc *listenSock);
+
+
+/* FUNCTION: PR_NT_CancelIo
+** DESCRIPTION:
+**    Cancel IO operations on fd.
+*/
+NSPR_API(PRStatus) PR_NT_CancelIo(PRFileDesc *fd);
+
+
+#endif /* WIN32 */
+
+PR_END_EXTERN_C
+
+#endif /* pprio_h___ */
diff --git a/mozilla/nsprpub/pr/include/private/pprmwait.h b/mozilla/nsprpub/pr/include/private/pprmwait.h
new file mode 100644
index 0000000..d116a8b
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/private/pprmwait.h
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#if defined(_PPRMWAIT_H)
+#else
+#define _PPRMWAIT_H
+
+#include "prlock.h"
+#include "prcvar.h"
+#include "prclist.h"
+#include "prthread.h"
+
+#define MAX_POLLING_INTERVAL 100
+#define _PR_POLL_COUNT_FUDGE 64
+#define _PR_DEFAULT_HASH_LENGTH 59
+
+/*
+ * Our hash table resolves collisions by open addressing with
+ * double hashing.  See Cormen, Leiserson, and Rivest,
+ * Introduction to Algorithms, p. 232, The MIT Press, 1990.
+ */
+
+#define _MW_HASH(a, m) ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m))
+#define _MW_HASH2(a, m) (1 + ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m - 2)))
+#define _MW_ABORTED(_rv) \
+    ((PR_FAILURE == (_rv)) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))
+
+typedef enum {_prmw_success, _prmw_rehash, _prmw_error} _PR_HashStory;
+
+typedef struct _PRWaiterHash
+{
+    PRUint16 count;             /* current number in hash table */
+    PRUint16 length;            /* current size of the hash table */
+    PRRecvWait *recv_wait;      /* hash table of receive wait objects */
+} _PRWaiterHash;
+
+typedef enum {_prmw_running, _prmw_stopping, _prmw_stopped} PRMWGroupState;
+
+struct PRWaitGroup
+{
+    PRCList group_link;         /* all groups are linked to each other */
+    PRCList io_ready;           /* list of I/O requests that are ready */
+    PRMWGroupState state;       /* state of this group (so we can shut down) */
+
+    PRLock *ml;                 /* lock for synchronizing this wait group */
+    PRCondVar *io_taken;        /* calling threads notify when they take I/O */
+    PRCondVar *io_complete;     /* calling threads wait here for completions */
+    PRCondVar *new_business;    /* polling thread waits here more work */
+    PRCondVar *mw_manage;       /* used to manage group lists */
+    PRThread* poller;           /* thread that's actually doing the poll() */
+    PRUint16 waiting_threads;   /* number of threads waiting for recv */
+    PRUint16 polling_count;     /* number of elements in the polling list */
+    PRUint32 p_timestamp;       /* pseudo-time group had element removed */
+    PRPollDesc *polling_list;   /* list poller builds for polling */
+    PRIntervalTime last_poll;   /* last time we polled */
+    _PRWaiterHash *waiter;      /* pointer to hash table of wait receive objects */
+
+#ifdef WINNT
+    /*
+     * On NT, idle threads are responsible for getting completed i/o.
+     * They need to add completed i/o to the io_ready list.  Since
+     * idle threads cannot use nspr locks, we have to use an md lock
+     * to protect the io_ready list.
+     */
+    _MDLock mdlock;             /* protect io_ready, waiter, and wait_list */
+    PRCList wait_list;          /* used in place of io_complete.  reuse
+                                 * waitQLinks in the PRThread structure. */
+#endif /* WINNT */
+};
+
+/**********************************************************************
+***********************************************************************
+******************** Wait group enumerations **************************
+***********************************************************************
+**********************************************************************/
+typedef struct _PRGlobalState
+{
+    PRCList group_list;         /* master of the group list */
+    PRWaitGroup *group;         /* the default (NULL) group */
+} _PRGlobalState;
+
+#ifdef WINNT
+extern PRStatus NT_HashRemoveInternal(PRWaitGroup *group, PRFileDesc *fd);
+#endif
+
+typedef enum {_PR_ENUM_UNSEALED=0, _PR_ENUM_SEALED=0x0eadface} _PREnumSeal;
+
+struct PRMWaitEnumerator
+{
+    PRWaitGroup *group;       /* group this enumerator is bound to */
+    PRThread *thread;               /* thread in midst of an enumeration */
+    _PREnumSeal seal;               /* trying to detect deleted objects */
+    PRUint32 p_timestamp;           /* when enumeration was (re)started */
+    PRRecvWait **waiter;            /* pointer into hash table */
+    PRUintn index;                  /* position in hash table */
+    void *pad[4];                   /* some room to grow */
+};
+
+#endif /* defined(_PPRMWAIT_H) */
+
+/* pprmwait.h */
diff --git a/mozilla/nsprpub/pr/include/private/pprthred.h b/mozilla/nsprpub/pr/include/private/pprthred.h
new file mode 100644
index 0000000..fe8ae50
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/private/pprthred.h
@@ -0,0 +1,363 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef pprthred_h___
+#define pprthred_h___
+
+/*
+** API for PR private functions.  These calls are to be used by internal
+** developers only.
+*/
+#include "nspr.h"
+
+#if defined(XP_OS2)
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_WIN
+#include <os2.h>
+#endif
+
+PR_BEGIN_EXTERN_C
+
+/*---------------------------------------------------------------------------
+** THREAD PRIVATE FUNCTIONS
+---------------------------------------------------------------------------*/
+
+/*
+** Associate a thread object with an existing native thread.
+** 	"type" is the type of thread object to attach
+** 	"priority" is the priority to assign to the thread
+** 	"stack" defines the shape of the threads stack
+**
+** This can return NULL if some kind of error occurs, or if memory is
+** tight. This call invokes "start(obj,arg)" and returns when the
+** function returns. The thread object is automatically destroyed.
+**
+** This call is not normally needed unless you create your own native
+** thread. PR_Init does this automatically for the primordial thread.
+*/
+NSPR_API(PRThread*) PR_AttachThread(PRThreadType type,
+                                     PRThreadPriority priority,
+				     PRThreadStack *stack);
+
+/*
+** Detach the nspr thread from the currently executing native thread.
+** The thread object will be destroyed and all related data attached
+** to it. The exit procs will be invoked.
+**
+** This call is not normally needed unless you create your own native
+** thread. PR_Exit will automatially detach the nspr thread object
+** created by PR_Init for the primordial thread.
+**
+** This call returns after the nspr thread object is destroyed.
+*/
+NSPR_API(void) PR_DetachThread(void);
+
+/*
+** Get the id of the named thread. Each thread is assigned a unique id
+** when it is created or attached.
+*/
+NSPR_API(PRUint32) PR_GetThreadID(PRThread *thread);
+
+/*
+** Set the procedure that is called when a thread is dumped. The procedure
+** will be applied to the argument, arg, when called. Setting the procedure
+** to NULL effectively removes it.
+*/
+typedef void (*PRThreadDumpProc)(PRFileDesc *fd, PRThread *t, void *arg);
+NSPR_API(void) PR_SetThreadDumpProc(
+    PRThread* thread, PRThreadDumpProc dump, void *arg);
+
+/*
+** Get this thread's affinity mask.  The affinity mask is a 32 bit quantity
+** marking a bit for each processor this process is allowed to run on.
+** The processor mask is returned in the mask argument.
+** The least-significant-bit represents processor 0.
+**
+** Returns 0 on success, -1 on failure.
+*/
+NSPR_API(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask);
+
+/*
+** Set this thread's affinity mask.  
+**
+** Returns 0 on success, -1 on failure.
+*/
+NSPR_API(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask );
+
+/*
+** Set the default CPU Affinity mask.
+**
+*/
+NSPR_API(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask);
+
+/*
+** Show status of all threads to standard error output.
+*/
+NSPR_API(void) PR_ShowStatus(void);
+
+/*
+** Set thread recycle mode to on (1) or off (0)
+*/
+NSPR_API(void) PR_SetThreadRecycleMode(PRUint32 flag);
+
+
+/*---------------------------------------------------------------------------
+** THREAD PRIVATE FUNCTIONS FOR GARBAGE COLLECTIBLE THREADS           
+---------------------------------------------------------------------------*/
+
+/* 
+** Only Garbage collectible threads participate in resume all, suspend all and 
+** enumeration operations.  They are also different during creation when
+** platform specific action may be needed (For example, all Solaris GC able
+** threads are bound threads).
+*/
+
+/*
+** Same as PR_CreateThread except that the thread is marked as garbage
+** collectible.
+*/
+NSPR_API(PRThread*) PR_CreateThreadGCAble(PRThreadType type,
+				     void (*start)(void *arg),
+				     void *arg,
+				     PRThreadPriority priority,
+				     PRThreadScope scope,
+				     PRThreadState state,
+				     PRUint32 stackSize);
+
+/*
+** Same as PR_AttachThread except that the thread being attached is marked as 
+** garbage collectible.
+*/
+NSPR_API(PRThread*) PR_AttachThreadGCAble(PRThreadType type,
+					PRThreadPriority priority,
+					PRThreadStack *stack);
+
+/*
+** Mark the thread as garbage collectible.
+*/
+NSPR_API(void) PR_SetThreadGCAble(void);
+
+/*
+** Unmark the thread as garbage collectible.
+*/
+NSPR_API(void) PR_ClearThreadGCAble(void);
+
+/*
+** This routine prevents all other GC able threads from running. This call is needed by 
+** the garbage collector.
+*/
+NSPR_API(void) PR_SuspendAll(void);
+
+/*
+** This routine unblocks all other GC able threads that were suspended from running by 
+** PR_SuspendAll(). This call is needed by the garbage collector.
+*/
+NSPR_API(void) PR_ResumeAll(void);
+
+/*
+** Return the thread stack pointer of the given thread. 
+** Needed by the garbage collector.
+*/
+NSPR_API(void *) PR_GetSP(PRThread *thread);
+
+/*
+** Save the registers that the GC would find interesting into the thread
+** "t". isCurrent will be non-zero if the thread state that is being
+** saved is the currently executing thread. Return the address of the
+** first register to be scanned as well as the number of registers to
+** scan in "np".
+**
+** If "isCurrent" is non-zero then it is allowed for the thread context
+** area to be used as scratch storage to hold just the registers
+** necessary for scanning.
+**
+** This function simply calls the internal function _MD_HomeGCRegisters().
+*/
+NSPR_API(PRWord *) PR_GetGCRegisters(PRThread *t, int isCurrent, int *np);
+
+/*
+** (Get|Set)ExecutionEnvironent
+**
+** Used by Java to associate it's execution environment so garbage collector
+** can find it. If return is NULL, then it's probably not a collectable thread.
+**
+** There's no locking required around these calls.
+*/
+NSPR_API(void*) GetExecutionEnvironment(PRThread *thread);
+NSPR_API(void) SetExecutionEnvironment(PRThread* thread, void *environment);
+
+/*
+** Enumeration function that applies "func(thread,i,arg)" to each active
+** thread in the process. The enumerator returns PR_SUCCESS if the enumeration
+** should continue, any other value is considered failure, and enumeration
+** stops, returning the failure value from PR_EnumerateThreads.
+** Needed by the garbage collector.
+*/
+typedef PRStatus (PR_CALLBACK *PREnumerator)(PRThread *t, int i, void *arg);
+NSPR_API(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg);
+
+/* 
+** Signature of a thread stack scanning function. It is applied to every
+** contiguous group of potential pointers within a thread. Count denotes the
+** number of pointers. 
+*/
+typedef PRStatus 
+(PR_CALLBACK *PRScanStackFun)(PRThread* t,
+			      void** baseAddr, PRUword count, void* closure);
+
+/*
+** Applies scanFun to all contiguous groups of potential pointers 
+** within a thread. This includes the stack, registers, and thread-local
+** data. If scanFun returns a status value other than PR_SUCCESS the scan
+** is aborted, and the status value is returned. 
+*/
+NSPR_API(PRStatus)
+PR_ThreadScanStackPointers(PRThread* t,
+                           PRScanStackFun scanFun, void* scanClosure);
+
+/* 
+** Calls PR_ThreadScanStackPointers for every thread.
+*/
+NSPR_API(PRStatus)
+PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure);
+
+/*
+** Returns a conservative estimate on the amount of stack space left
+** on a thread in bytes, sufficient for making decisions about whether 
+** to continue recursing or not.
+*/
+NSPR_API(PRUword)
+PR_GetStackSpaceLeft(PRThread* t);
+
+/*---------------------------------------------------------------------------
+** THREAD CPU PRIVATE FUNCTIONS             
+---------------------------------------------------------------------------*/
+
+/*
+** Get a pointer to the primordial CPU.
+*/
+NSPR_API(struct _PRCPU *) _PR_GetPrimordialCPU(void);
+
+/*---------------------------------------------------------------------------
+** THREAD SYNCHRONIZATION PRIVATE FUNCTIONS
+---------------------------------------------------------------------------*/
+
+/*
+** Create a new named monitor (named for debugging purposes).
+**  Monitors are re-entrant locks with a built-in condition variable.
+**
+** This may fail if memory is tight or if some operating system resource
+** is low.
+*/
+NSPR_API(PRMonitor*) PR_NewNamedMonitor(const char* name);
+
+/*
+** Test and then lock the lock if it's not already locked by some other
+** thread. Return PR_FALSE if some other thread owned the lock at the
+** time of the call.
+*/
+NSPR_API(PRBool) PR_TestAndLock(PRLock *lock);
+
+/*
+** Test and then enter the mutex associated with the monitor if it's not
+** already entered by some other thread. Return PR_FALSE if some other
+** thread owned the mutex at the time of the call.
+*/
+NSPR_API(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon);
+
+/*
+** Return the number of times that the current thread has entered the
+** mutex. Returns zero if the current thread has not entered the mutex.
+*/
+NSPR_API(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon);
+
+/*
+** Just like PR_CEnterMonitor except that if the monitor is owned by
+** another thread NULL is returned.
+*/
+NSPR_API(PRMonitor*) PR_CTestAndEnterMonitor(void *address);
+
+/*---------------------------------------------------------------------------
+** PLATFORM-SPECIFIC INITIALIZATION FUNCTIONS
+---------------------------------------------------------------------------*/
+#if defined(IRIX)
+/*
+** Irix specific initialization funtion to be called before PR_Init
+** is called by the application. Sets the CONF_INITUSERS and CONF_INITSIZE
+** attributes of the shared arena set up by nspr.
+**
+** The environment variables _NSPR_IRIX_INITUSERS and _NSPR_IRIX_INITSIZE
+** can also be used to set these arena attributes. If _NSPR_IRIX_INITUSERS
+** is set, but not _NSPR_IRIX_INITSIZE, the value of the CONF_INITSIZE
+** attribute of the nspr arena is scaled as a function of the
+** _NSPR_IRIX_INITUSERS value.
+** 
+** If the _PR_Irix_Set_Arena_Params() is called in addition to setting the
+** environment variables, the values of the environment variables are used.
+** 
+*/
+NSPR_API(void) _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize);
+
+#endif /* IRIX */
+
+#if defined(XP_OS2)
+/*
+** These functions need to be called at the start and end of a thread.
+** An EXCEPTIONREGISTRATIONRECORD must be declared on the stack and its
+** address passed to the two functions.
+*/
+NSPR_API(void) PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e);
+NSPR_API(void) PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e);
+#endif /* XP_OS2 */
+
+/* I think PR_GetMonitorEntryCount is useless. All you really want is this... */
+#define PR_InMonitor(m)		(PR_GetMonitorEntryCount(m) > 0)
+
+/*---------------------------------------------------------------------------
+** Special X-Lock hack for client
+---------------------------------------------------------------------------*/
+
+#ifdef XP_UNIX
+extern void PR_XLock(void);
+extern void PR_XUnlock(void);
+extern PRBool PR_XIsLocked(void);
+#endif /* XP_UNIX */
+
+PR_END_EXTERN_C
+
+#endif /* pprthred_h___ */
diff --git a/mozilla/nsprpub/pr/include/private/primpl.h b/mozilla/nsprpub/pr/include/private/primpl.h
new file mode 100644
index 0000000..15971bc
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/private/primpl.h
@@ -0,0 +1,2138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef primpl_h___
+#define primpl_h___
+
+/*
+ * HP-UX 10.10's pthread.h (DCE threads) includes dce/cma.h, which
+ * has:
+ *     #define sigaction _sigaction_sys
+ * This macro causes chaos if signal.h gets included before pthread.h.
+ * To be safe, we include pthread.h first.
+ */
+
+#if defined(_PR_PTHREADS)
+#include <pthread.h>
+#endif
+
+#if defined(_PR_BTHREADS)
+#include <kernel/OS.h>
+#endif
+
+#ifdef WIN32
+/*
+ * Allow use of functions and symbols first defined in Win2k.
+ */
+#if !defined(WINVER) || (WINVER < 0x0500)
+#undef WINVER
+#define WINVER 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#endif /* WIN32 */
+
+#include "nspr.h"
+#include "prpriv.h"
+
+typedef struct PRSegment PRSegment;
+
+#include "md/prosdep.h"
+#include "obsolete/probslet.h"
+
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#include <semaphore.h>
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+#include <sys/sem.h>
+#endif
+
+/*************************************************************************
+*****  A Word about Model Dependent Function Naming Convention ***********
+*************************************************************************/
+
+/*
+NSPR 2.0 must implement its function across a range of platforms 
+including: MAC, Windows/16, Windows/95, Windows/NT, and several
+variants of Unix. Each implementation shares common code as well 
+as having platform dependent portions. This standard describes how
+the model dependent portions are to be implemented.
+
+In header file pr/include/primpl.h, each publicly declared 
+platform dependent function is declared as:
+
+NSPR_API void _PR_MD_FUNCTION( long arg1, long arg2 );
+#define _PR_MD_FUNCTION _MD_FUNCTION
+
+In header file pr/include/md/<platform>/_<platform>.h, 
+each #define'd macro is redefined as one of:
+
+#define _MD_FUNCTION <blanks>
+#define _MD_FUNCTION <expanded macro>
+#define _MD_FUNCTION <osFunction>
+#define _MD_FUNCTION <_MD_Function>
+
+Where:
+
+<blanks> is no definition at all. In this case, the function is not implemented 
+and is never called for this platform. 
+For example: 
+#define _MD_INIT_CPUS()
+
+<expanded macro> is a C language macro expansion. 
+For example: 
+#define        _MD_CLEAN_THREAD(_thread) \
+    PR_BEGIN_MACRO \
+        PR_DestroyCondVar(_thread->md.asyncIOCVar); \
+        PR_DestroyLock(_thread->md.asyncIOLock); \
+    PR_END_MACRO
+
+<osFunction> is some function implemented by the host operating system. 
+For example: 
+#define _MD_EXIT        exit
+
+<_MD_function> is the name of a function implemented for this platform in 
+pr/src/md/<platform>/<soruce>.c file. 
+For example: 
+#define        _MD_GETFILEINFO         _MD_GetFileInfo
+
+In <source>.c, the implementation is:
+PR_IMPLEMENT(PRInt32) _MD_GetFileInfo(const char *fn, PRFileInfo *info);
+*/
+
+PR_BEGIN_EXTERN_C
+
+typedef struct _MDLock _MDLock;
+typedef struct _MDCVar _MDCVar;
+typedef struct _MDSegment _MDSegment;
+typedef struct _MDThread _MDThread;
+typedef struct _MDThreadStack _MDThreadStack;
+typedef struct _MDSemaphore _MDSemaphore;
+typedef struct _MDDir _MDDir;
+#ifdef MOZ_UNICODE
+typedef struct _MDDirUTF16 _MDDirUTF16;
+#endif /* MOZ_UNICODE */
+typedef struct _MDFileDesc _MDFileDesc;
+typedef struct _MDProcess _MDProcess;
+typedef struct _MDFileMap _MDFileMap;
+
+#if defined(_PR_PTHREADS)
+
+/*
+** The following definitions are unique to implementing NSPR using pthreads.
+** Since pthreads defines most of the thread and thread synchronization
+** stuff, this is a pretty small set.
+*/
+
+#define PT_CV_NOTIFIED_LENGTH 6
+typedef struct _PT_Notified _PT_Notified;
+struct _PT_Notified
+{
+    PRIntn length;              /* # of used entries in this structure */
+    struct
+    {
+        PRCondVar *cv;          /* the condition variable notified */
+        PRIntn times;           /* and the number of times notified */
+    } cv[PT_CV_NOTIFIED_LENGTH];
+    _PT_Notified *link;         /* link to another of these | NULL */
+};
+
+/*
+ * bits defined for pthreads 'state' field 
+ */
+#define PT_THREAD_DETACHED  0x01    /* thread can't be joined */
+#define PT_THREAD_GLOBAL    0x02    /* a global thread (unlikely) */
+#define PT_THREAD_SYSTEM    0x04    /* system (not user) thread */
+#define PT_THREAD_PRIMORD   0x08    /* this is the primordial thread */
+#define PT_THREAD_ABORTED   0x10    /* thread has been interrupted */
+#define PT_THREAD_GCABLE    0x20    /* thread is garbage collectible */
+#define PT_THREAD_SUSPENDED 0x40    /* thread has been suspended */
+#define PT_THREAD_FOREIGN   0x80    /* thread is not one of ours */
+#define PT_THREAD_BOUND     0x100    /* a bound-global thread */
+
+#define _PT_THREAD_INTERRUPTED(thr)					\
+		(!(thr->interrupt_blocked) && (thr->state & PT_THREAD_ABORTED))
+#define _PT_THREAD_BLOCK_INTERRUPT(thr)				\
+		(thr->interrupt_blocked = 1)
+#define _PT_THREAD_UNBLOCK_INTERRUPT(thr)			\
+		(thr->interrupt_blocked = 0)
+
+#ifdef GC_LEAK_DETECTOR
+/* All threads are GCable. */
+#define _PT_IS_GCABLE_THREAD(thr) 1
+#else
+#define _PT_IS_GCABLE_THREAD(thr) ((thr)->state & PT_THREAD_GCABLE)
+#endif /* GC_LEAK_DETECTOR */
+
+/* 
+** Possible values for thread's suspend field
+** Note that the first two can be the same as they are really mutually exclusive,
+** i.e. both cannot be happening at the same time. We have two symbolic names
+** just as a mnemonic.
+**/
+#define PT_THREAD_RESUMED   0x80    /* thread has been resumed */
+#define PT_THREAD_SETGCABLE 0x100   /* set the GCAble flag */
+
+#if defined(DEBUG)
+
+typedef struct PTDebug
+{
+    PRTime timeStarted;
+    PRUintn locks_created, locks_destroyed;
+    PRUintn locks_acquired, locks_released;
+    PRUintn cvars_created, cvars_destroyed;
+    PRUintn cvars_notified, delayed_cv_deletes;
+} PTDebug;
+
+#endif /* defined(DEBUG) */
+
+NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg);
+
+#else /* defined(_PR_PTHREADS) */
+
+NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg);
+
+/*
+** This section is contains those parts needed to implement NSPR on
+** platforms in general. One would assume that the pthreads implementation
+** included lots of the same types, at least conceptually.
+*/
+
+/*
+ * Local threads only.  No multiple CPU support and hence all the
+ * following routines are no-op.
+ */
+#ifdef _PR_LOCAL_THREADS_ONLY
+
+#define        _PR_MD_SUSPEND_THREAD(thread)        
+#define        _PR_MD_RESUME_THREAD(thread)        
+#define        _PR_MD_SUSPEND_CPU(cpu)        
+#define        _PR_MD_RESUME_CPU(cpu)        
+#define        _PR_MD_BEGIN_SUSPEND_ALL()        
+#define        _PR_MD_END_SUSPEND_ALL()        
+#define        _PR_MD_BEGIN_RESUME_ALL()        
+#define        _PR_MD_END_RESUME_ALL()
+#define _PR_MD_INIT_ATTACHED_THREAD(thread) PR_FAILURE
+
+#endif
+
+typedef struct _PRCPUQueue _PRCPUQueue;
+typedef struct _PRCPU _PRCPU;
+typedef struct _MDCPU _MDCPU;
+
+struct _PRCPUQueue {
+    _MDLock  runQLock;          /* lock for the run + wait queues */
+    _MDLock  sleepQLock;        /* lock for the run + wait queues */
+    _MDLock  miscQLock;         /* lock for the run + wait queues */
+
+    PRCList runQ[PR_PRIORITY_LAST + 1]; /* run queue for this CPU */
+    PRUint32  runQReadyMask;
+    PRCList sleepQ;
+    PRIntervalTime sleepQmax;
+    PRCList pauseQ;
+    PRCList suspendQ;
+    PRCList waitingToJoinQ;
+
+    PRUintn   numCPUs;          /* number of CPUs using this Q */
+};
+
+struct _PRCPU {
+    PRCList links;              /* link list of CPUs */
+    PRUint32 id;                /* id for this CPU */
+
+    union {
+        PRInt32 bits;
+        PRUint8 missed[4];
+    } u;
+    PRIntn where;               /* index into u.missed */
+    PRPackedBool paused;        /* cpu is paused */
+    PRPackedBool exit;          /* cpu should exit */
+
+    PRThread *thread;           /* native thread for this CPUThread */
+    PRThread *idle_thread;      /* user-level idle thread for this CPUThread */
+
+    PRIntervalTime last_clock;  /* the last time we went into 
+                                 * _PR_ClockInterrupt() on this CPU
+                                 */
+
+    _PRCPUQueue *queue;
+
+    _MDCPU md;
+};
+
+typedef struct _PRInterruptTable {
+    const char *name;
+    PRUintn missed_bit;
+    void (*handler)(void);
+} _PRInterruptTable;
+
+#define _PR_CPU_PTR(_qp) \
+    ((_PRCPU*) ((char*) (_qp) - offsetof(_PRCPU,links)))
+
+#if !defined(IRIX) && !defined(WIN32) && !defined(XP_OS2) \
+        && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY))
+#define _MD_GET_ATTACHED_THREAD()        (_PR_MD_CURRENT_THREAD())
+#endif
+
+#ifdef _PR_LOCAL_THREADS_ONLY 
+
+NSPR_API(struct _PRCPU *)              _pr_currentCPU;
+NSPR_API(PRThread *)                   _pr_currentThread;
+NSPR_API(PRThread *)                   _pr_lastThread;
+NSPR_API(PRInt32)                      _pr_intsOff;
+
+#define _MD_CURRENT_CPU()               (_pr_currentCPU)
+#define _MD_SET_CURRENT_CPU(_cpu)       (_pr_currentCPU = (_cpu))
+#define _MD_CURRENT_THREAD()            (_pr_currentThread)
+#define _MD_SET_CURRENT_THREAD(_thread) (_pr_currentThread = (_thread))
+#define _MD_LAST_THREAD()               (_pr_lastThread)
+#define _MD_SET_LAST_THREAD(t)          (_pr_lastThread = t)
+
+#define _MD_GET_INTSOFF()               (_pr_intsOff)
+#define _MD_SET_INTSOFF(_val)           (_pr_intsOff = _val)
+
+
+/* The unbalanced curly braces in these two macros are intentional */
+#define _PR_LOCK_HEAP() { PRIntn _is; if (_pr_currentCPU) _PR_INTSOFF(_is);
+#define _PR_UNLOCK_HEAP() if (_pr_currentCPU) _PR_INTSON(_is); }
+
+#endif /* _PR_LOCAL_THREADS_ONLY */
+
+extern PRInt32                  _native_threads_only;
+
+#if defined(_PR_GLOBAL_THREADS_ONLY)
+
+#define _MD_GET_INTSOFF() 0
+#define _MD_SET_INTSOFF(_val)
+#define _PR_INTSOFF(_is)
+#define _PR_FAST_INTSON(_is)
+#define _PR_INTSON(_is)
+#define _PR_THREAD_LOCK(_thread)
+#define _PR_THREAD_UNLOCK(_thread)
+#define _PR_RUNQ_LOCK(cpu)
+#define _PR_RUNQ_UNLOCK(cpu)
+#define _PR_SLEEPQ_LOCK(thread)
+#define _PR_SLEEPQ_UNLOCK(thread)
+#define _PR_MISCQ_LOCK(thread)
+#define _PR_MISCQ_UNLOCK(thread)
+#define _PR_CPU_LIST_LOCK()
+#define _PR_CPU_LIST_UNLOCK()
+
+#define _PR_ADD_RUNQ(_thread, _cpu, _pri)
+#define _PR_DEL_RUNQ(_thread)
+#define _PR_ADD_SLEEPQ(_thread, _timeout)
+#define _PR_DEL_SLEEPQ(_thread, _propogate)
+#define _PR_ADD_JOINQ(_thread, _cpu)
+#define _PR_DEL_JOINQ(_thread)
+#define _PR_ADD_SUSPENDQ(_thread, _cpu)
+#define _PR_DEL_SUSPENDQ(_thread)
+
+#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU)
+
+#define _PR_IS_NATIVE_THREAD(thread) 1
+#define _PR_IS_NATIVE_THREAD_SUPPORTED() 1
+
+#else
+
+#define _PR_INTSOFF(_is) \
+    PR_BEGIN_MACRO \
+        (_is) = _PR_MD_GET_INTSOFF(); \
+        _PR_MD_SET_INTSOFF(1); \
+    PR_END_MACRO
+
+#define _PR_FAST_INTSON(_is) \
+    PR_BEGIN_MACRO \
+        _PR_MD_SET_INTSOFF(_is); \
+    PR_END_MACRO
+
+#define _PR_INTSON(_is) \
+    PR_BEGIN_MACRO \
+        if ((_is == 0) && (_PR_MD_CURRENT_CPU())->u.bits) \
+                _PR_IntsOn((_PR_MD_CURRENT_CPU())); \
+        _PR_MD_SET_INTSOFF(_is); \
+    PR_END_MACRO
+
+#ifdef _PR_LOCAL_THREADS_ONLY 
+
+#define _PR_IS_NATIVE_THREAD(thread) 0
+#define _PR_THREAD_LOCK(_thread)
+#define _PR_THREAD_UNLOCK(_thread)
+#define _PR_RUNQ_LOCK(cpu)
+#define _PR_RUNQ_UNLOCK(cpu)
+#define _PR_SLEEPQ_LOCK(thread)
+#define _PR_SLEEPQ_UNLOCK(thread)
+#define _PR_MISCQ_LOCK(thread)
+#define _PR_MISCQ_UNLOCK(thread)
+#define _PR_CPU_LIST_LOCK()
+#define _PR_CPU_LIST_UNLOCK()
+
+#define _PR_ADD_RUNQ(_thread, _cpu, _pri) \
+    PR_BEGIN_MACRO \
+    PR_APPEND_LINK(&(_thread)->links, &_PR_RUNQ(_cpu)[_pri]); \
+    _PR_RUNQREADYMASK(_cpu) |= (1L << _pri); \
+    PR_END_MACRO
+
+#define _PR_DEL_RUNQ(_thread) \
+    PR_BEGIN_MACRO \
+    _PRCPU *_cpu = _thread->cpu; \
+    PRInt32 _pri = _thread->priority; \
+    PR_REMOVE_LINK(&(_thread)->links); \
+    if (PR_CLIST_IS_EMPTY(&_PR_RUNQ(_cpu)[_pri])) \
+        _PR_RUNQREADYMASK(_cpu) &= ~(1L << _pri); \
+    PR_END_MACRO
+
+#define _PR_ADD_SLEEPQ(_thread, _timeout) \
+    _PR_AddSleepQ(_thread, _timeout);   
+
+#define _PR_DEL_SLEEPQ(_thread, _propogate) \
+    _PR_DelSleepQ(_thread, _propogate);  
+
+#define _PR_ADD_JOINQ(_thread, _cpu) \
+    PR_APPEND_LINK(&(_thread)->links, &_PR_WAITINGTOJOINQ(_cpu));
+
+#define _PR_DEL_JOINQ(_thread) \
+    PR_REMOVE_LINK(&(_thread)->links);
+
+#define _PR_ADD_SUSPENDQ(_thread, _cpu) \
+    PR_APPEND_LINK(&(_thread)->links, &_PR_SUSPENDQ(_cpu));
+
+#define _PR_DEL_SUSPENDQ(_thread) \
+    PR_REMOVE_LINK(&(_thread)->links);
+
+#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU)
+
+#define _PR_IS_NATIVE_THREAD_SUPPORTED() 0
+
+#else        /* _PR_LOCAL_THREADS_ONLY */
+
+/* These are for the "combined" thread model */
+
+#define _PR_THREAD_LOCK(_thread) \
+    _PR_MD_LOCK(&(_thread)->threadLock);
+
+#define _PR_THREAD_UNLOCK(_thread) \
+    _PR_MD_UNLOCK(&(_thread)->threadLock);
+
+#define _PR_RUNQ_LOCK(_cpu) \
+    PR_BEGIN_MACRO \
+    _PR_MD_LOCK(&(_cpu)->queue->runQLock );\
+    PR_END_MACRO
+    
+#define _PR_RUNQ_UNLOCK(_cpu) \
+    PR_BEGIN_MACRO \
+    _PR_MD_UNLOCK(&(_cpu)->queue->runQLock );\
+    PR_END_MACRO
+
+#define _PR_SLEEPQ_LOCK(_cpu) \
+    _PR_MD_LOCK(&(_cpu)->queue->sleepQLock );
+
+#define _PR_SLEEPQ_UNLOCK(_cpu) \
+    _PR_MD_UNLOCK(&(_cpu)->queue->sleepQLock );
+
+#define _PR_MISCQ_LOCK(_cpu) \
+    _PR_MD_LOCK(&(_cpu)->queue->miscQLock );
+
+#define _PR_MISCQ_UNLOCK(_cpu) \
+    _PR_MD_UNLOCK(&(_cpu)->queue->miscQLock );
+
+#define _PR_CPU_LIST_LOCK()                 _PR_MD_LOCK(&_pr_cpuLock)
+#define _PR_CPU_LIST_UNLOCK()               _PR_MD_UNLOCK(&_pr_cpuLock)
+
+#define QUEUE_RUN           0x1
+#define QUEUE_SLEEP         0x2
+#define QUEUE_JOIN          0x4
+#define QUEUE_SUSPEND       0x8
+#define QUEUE_LOCK          0x10
+
+#define _PR_ADD_RUNQ(_thread, _cpu, _pri) \
+    PR_BEGIN_MACRO \
+    PR_APPEND_LINK(&(_thread)->links, &_PR_RUNQ(_cpu)[_pri]); \
+    _PR_RUNQREADYMASK(_cpu) |= (1L << _pri); \
+    PR_ASSERT((_thread)->queueCount == 0); \
+    (_thread)->queueCount = QUEUE_RUN; \
+    PR_END_MACRO
+
+#define _PR_DEL_RUNQ(_thread) \
+    PR_BEGIN_MACRO \
+    _PRCPU *_cpu = _thread->cpu; \
+    PRInt32 _pri = _thread->priority; \
+    PR_REMOVE_LINK(&(_thread)->links); \
+    if (PR_CLIST_IS_EMPTY(&_PR_RUNQ(_cpu)[_pri])) \
+        _PR_RUNQREADYMASK(_cpu) &= ~(1L << _pri); \
+    PR_ASSERT((_thread)->queueCount == QUEUE_RUN);\
+    (_thread)->queueCount = 0; \
+    PR_END_MACRO
+
+#define _PR_ADD_SLEEPQ(_thread, _timeout) \
+    PR_ASSERT((_thread)->queueCount == 0); \
+    (_thread)->queueCount = QUEUE_SLEEP; \
+    _PR_AddSleepQ(_thread, _timeout);  
+
+#define _PR_DEL_SLEEPQ(_thread, _propogate) \
+    PR_ASSERT((_thread)->queueCount == QUEUE_SLEEP);\
+    (_thread)->queueCount = 0; \
+    _PR_DelSleepQ(_thread, _propogate);  
+
+#define _PR_ADD_JOINQ(_thread, _cpu) \
+    PR_ASSERT((_thread)->queueCount == 0); \
+    (_thread)->queueCount = QUEUE_JOIN; \
+    PR_APPEND_LINK(&(_thread)->links, &_PR_WAITINGTOJOINQ(_cpu));
+
+#define _PR_DEL_JOINQ(_thread) \
+    PR_ASSERT((_thread)->queueCount == QUEUE_JOIN);\
+    (_thread)->queueCount = 0; \
+    PR_REMOVE_LINK(&(_thread)->links);
+
+#define _PR_ADD_SUSPENDQ(_thread, _cpu) \
+    PR_ASSERT((_thread)->queueCount == 0); \
+    (_thread)->queueCount = QUEUE_SUSPEND; \
+    PR_APPEND_LINK(&(_thread)->links, &_PR_SUSPENDQ(_cpu));
+
+#define _PR_DEL_SUSPENDQ(_thread) \
+    PR_ASSERT((_thread)->queueCount == QUEUE_SUSPEND);\
+    (_thread)->queueCount = 0; \
+    PR_REMOVE_LINK(&(_thread)->links);
+
+#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU) \
+    (_thread)->cpu = (_newCPU);
+
+#define _PR_IS_NATIVE_THREAD(thread) (thread->flags & _PR_GLOBAL_SCOPE)
+#define _PR_IS_NATIVE_THREAD_SUPPORTED() 1
+
+#endif /* _PR_LOCAL_THREADS_ONLY */
+
+#endif /* _PR_GLOBAL_THREADS_ONLY */
+
+#define _PR_SET_RESCHED_FLAG() _PR_MD_CURRENT_CPU()->u.missed[3] = 1
+#define _PR_CLEAR_RESCHED_FLAG() _PR_MD_CURRENT_CPU()->u.missed[3] = 0
+
+extern _PRInterruptTable _pr_interruptTable[];
+
+/* Bits for _pr_interruptState.u.missed[0,1] */
+#define _PR_MISSED_CLOCK    0x1
+#define _PR_MISSED_IO        0x2
+#define _PR_MISSED_CHILD    0x4
+
+extern void _PR_IntsOn(_PRCPU *cpu);
+
+NSPR_API(void) _PR_WakeupCPU(void);
+NSPR_API(void) _PR_PauseCPU(void);
+
+/************************************************************************/
+
+#define _PR_LOCK_LOCK(_lock) \
+    _PR_MD_LOCK(&(_lock)->ilock);
+#define _PR_LOCK_UNLOCK(_lock) \
+    _PR_MD_UNLOCK(&(_lock)->ilock);
+    
+extern void _PR_UnblockLockWaiter(PRLock *lock);
+
+#define _PR_LOCK_PTR(_qp) \
+    ((PRLock*) ((char*) (_qp) - offsetof(PRLock,links)))
+
+/************************************************************************/
+
+#define _PR_CVAR_LOCK(_cvar) \
+    _PR_MD_LOCK(&(_cvar)->ilock); 
+#define _PR_CVAR_UNLOCK(_cvar) \
+    _PR_MD_UNLOCK(&(_cvar)->ilock);
+
+extern PRStatus _PR_WaitCondVar(
+    PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout);
+extern PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen);
+
+NSPR_API(void) _PR_Notify(PRMonitor *mon, PRBool all, PRBool sticky);
+
+/* PRThread.flags */
+#define _PR_SYSTEM          0x01
+#define _PR_INTERRUPT       0x02
+#define _PR_ATTACHED        0x04        /* created via PR_AttachThread */
+#define _PR_PRIMORDIAL      0x08        /* the thread that called PR_Init */
+#define _PR_ON_SLEEPQ       0x10        /* thread is on the sleepQ */
+#define _PR_ON_PAUSEQ       0x20        /* thread is on the pauseQ */
+#define _PR_SUSPENDING      0x40        /* thread wants to suspend */
+#define _PR_GLOBAL_SCOPE    0x80        /* thread is global scope */
+#define _PR_IDLE_THREAD     0x200       /* this is an idle thread        */
+#define _PR_GCABLE_THREAD   0x400       /* this is a collectable thread */
+#define _PR_BOUND_THREAD    0x800       /* a bound thread */
+#define _PR_INTERRUPT_BLOCKED	0x1000	/* interrupts blocked */
+
+/* PRThread.state */
+#define _PR_UNBORN       0
+#define _PR_RUNNABLE     1
+#define _PR_RUNNING      2
+#define _PR_LOCK_WAIT    3
+#define _PR_COND_WAIT    4
+#define _PR_JOIN_WAIT    5
+#define _PR_IO_WAIT      6
+#define _PR_SUSPENDED    7
+#define _PR_DEAD_STATE   8  /* for debugging */
+
+/* PRThreadStack.flags */
+#define _PR_STACK_VM            0x1    /* using vm instead of malloc */
+#define _PR_STACK_MAPPED        0x2    /* vm is mapped */
+#define _PR_STACK_PRIMORDIAL    0x4    /* stack for primordial thread */
+
+/* 
+** If the default stcksize from the client is zero, we need to pick a machine
+** dependent value.  This is only for standard user threads.  For custom threads,
+** 0 has a special meaning.
+** Adjust stackSize. Round up to a page boundary.
+*/
+
+#ifndef _MD_MINIMUM_STACK_SIZE
+#define _MD_MINIMUM_STACK_SIZE	0
+#endif
+
+#if (!defined(HAVE_CUSTOM_USER_THREADS))
+#define        _PR_ADJUST_STACKSIZE(stackSize) \
+        PR_BEGIN_MACRO \
+    if (stackSize == 0) \
+                stackSize = _MD_DEFAULT_STACK_SIZE; \
+    if (stackSize < _MD_MINIMUM_STACK_SIZE) \
+                stackSize = _MD_MINIMUM_STACK_SIZE; \
+    stackSize = (stackSize + (1 << _pr_pageShift) - 1) >> _pr_pageShift; \
+    stackSize <<= _pr_pageShift; \
+        PR_END_MACRO
+#else
+#define        _PR_ADJUST_STACKSIZE(stackSize)
+#endif
+
+#ifdef GC_LEAK_DETECTOR
+/* All threads are GCable. */
+#define _PR_IS_GCABLE_THREAD(thr) 1
+#else
+#define _PR_IS_GCABLE_THREAD(thr) ((thr)->flags & _PR_GCABLE_THREAD)
+#endif /* GC_LEAK_DETECTOR */
+
+#define _PR_PENDING_INTERRUPT(thr)					\
+		(!((thr)->flags & _PR_INTERRUPT_BLOCKED) && ((thr)->flags & _PR_INTERRUPT))
+#define _PR_THREAD_BLOCK_INTERRUPT(thr)			\
+		(thr->flags |= _PR_INTERRUPT_BLOCKED)
+#define _PR_THREAD_UNBLOCK_INTERRUPT(thr)			\
+		(thr->flags &= ~_PR_INTERRUPT_BLOCKED)
+
+#define _PR_THREAD_PTR(_qp) \
+    ((PRThread*) ((char*) (_qp) - offsetof(PRThread,links)))
+
+#define _PR_ACTIVE_THREAD_PTR(_qp) \
+    ((PRThread*) ((char*) (_qp) - offsetof(PRThread,active)))
+
+#define _PR_THREAD_CONDQ_PTR(_qp) \
+    ((PRThread*) ((char*) (_qp) - offsetof(PRThread,waitQLinks)))
+
+#define _PR_THREAD_MD_TO_PTR(_md) \
+    ((PRThread*) ((char*) (_md) - offsetof(PRThread,md)))
+
+#define _PR_THREAD_STACK_TO_PTR(_stack) \
+    ((PRThread*) (_stack->thr))
+
+extern PRCList _pr_active_local_threadQ;
+extern PRCList _pr_active_global_threadQ;
+extern PRCList _pr_cpuQ;
+extern _MDLock  _pr_cpuLock;
+extern PRInt32 _pr_md_idle_cpus;
+
+#define _PR_ACTIVE_LOCAL_THREADQ()          _pr_active_local_threadQ
+#define _PR_ACTIVE_GLOBAL_THREADQ()         _pr_active_global_threadQ
+#define _PR_CPUQ()                          _pr_cpuQ
+#define _PR_RUNQ(_cpu)                      ((_cpu)->queue->runQ)
+#define _PR_RUNQREADYMASK(_cpu)             ((_cpu)->queue->runQReadyMask)
+#define _PR_SLEEPQ(_cpu)                    ((_cpu)->queue->sleepQ)
+#define _PR_SLEEPQMAX(_cpu)                 ((_cpu)->queue->sleepQmax)
+#define _PR_PAUSEQ(_cpu)                    ((_cpu)->queue->pauseQ)
+#define _PR_SUSPENDQ(_cpu)                  ((_cpu)->queue->suspendQ)
+#define _PR_WAITINGTOJOINQ(_cpu)            ((_cpu)->queue->waitingToJoinQ)
+
+extern PRUint32 _pr_recycleThreads;   /* Flag for behavior on thread cleanup */
+extern PRLock *_pr_deadQLock;
+extern PRUint32 _pr_numNativeDead;
+extern PRUint32 _pr_numUserDead;
+extern PRCList _pr_deadNativeQ;
+extern PRCList _pr_deadUserQ;
+#define _PR_DEADNATIVEQ     _pr_deadNativeQ
+#define _PR_DEADUSERQ       _pr_deadUserQ
+#define _PR_DEADQ_LOCK      PR_Lock(_pr_deadQLock);
+#define _PR_DEADQ_UNLOCK    PR_Unlock(_pr_deadQLock);
+#define _PR_INC_DEADNATIVE  (_pr_numNativeDead++)
+#define _PR_DEC_DEADNATIVE  (_pr_numNativeDead--)
+#define _PR_NUM_DEADNATIVE  (_pr_numNativeDead)
+#define _PR_INC_DEADUSER    (_pr_numUserDead++)
+#define _PR_DEC_DEADUSER    (_pr_numUserDead--)
+#define _PR_NUM_DEADUSER    (_pr_numUserDead)
+
+extern PRUint32 _pr_utid;
+
+extern struct _PRCPU  *_pr_primordialCPU;
+
+extern PRLock *_pr_activeLock;          /* lock for userActive and systemActive */
+extern PRInt32 _pr_userActive;          /* number of active user threads */
+extern PRInt32 _pr_systemActive;        /* number of active system threads */
+extern PRInt32 _pr_primordialExitCount; /* number of user threads left
+                                         * before the primordial thread
+                                         * can exit.  */
+extern PRCondVar *_pr_primordialExitCVar; /* the condition variable for
+                                           * notifying the primordial thread
+                                           * when all other user threads
+                                           * have terminated.  */
+
+extern PRUintn _pr_maxPTDs;
+
+extern PRLock *_pr_terminationCVLock;
+
+/*************************************************************************
+* Internal routines either called by PR itself or from machine-dependent *
+* code.                                                                  *
+*************************************************************************/
+
+extern void _PR_ClockInterrupt(void);
+
+extern void _PR_Schedule(void);
+extern void _PR_SetThreadPriority(
+    PRThread* thread, PRThreadPriority priority);
+
+/***********************************************************************
+** FUNCTION:	_PR_NewSegment()
+** DESCRIPTION:
+**   Allocate a memory segment. The "size" value is rounded up to the
+**   native system page size and a page aligned portion of memory is
+**   returned.  This memory is not part of the malloc heap. If "vaddr" is
+**   not NULL then PR tries to allocate the segment at the desired virtual
+**   address.
+** INPUTS:	size:  size of the desired memory segment
+**          vaddr:  address at which the newly aquired segment is to be
+**                  mapped into memory.
+** OUTPUTS:	a memory segment is allocated, a PRSegment is allocated
+** RETURN:	pointer to PRSegment
+***********************************************************************/
+extern PRSegment* _PR_NewSegment(PRUint32 size, void *vaddr);
+
+/***********************************************************************
+** FUNCTION:	_PR_DestroySegment()
+** DESCRIPTION:
+**   The memory segment and the PRSegment are freed
+** INPUTS:	seg:  pointer to PRSegment to be freed
+** OUTPUTS:	the the PRSegment and its associated memory segment are freed
+** RETURN:	void
+***********************************************************************/
+extern void _PR_DestroySegment(PRSegment *seg);
+
+extern PRThreadStack * _PR_NewStack(PRUint32 stackSize);
+extern void _PR_FreeStack(PRThreadStack *stack);
+extern PRBool _PR_NotifyThread (PRThread *thread, PRThread *me);
+extern void _PR_NotifyLockedThread (PRThread *thread);
+
+NSPR_API(void) _PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout);
+NSPR_API(void) _PR_DelSleepQ(PRThread *thread, PRBool propogate_time);
+
+extern void _PR_AddThreadToRunQ(PRThread *me, PRThread *thread);
+
+NSPR_API(PRThread*) _PR_CreateThread(PRThreadType type,
+                                     void (*start)(void *arg),
+                                     void *arg,
+                                     PRThreadPriority priority,
+                                     PRThreadScope scope,
+                                     PRThreadState state,
+                                     PRUint32 stackSize,
+                     PRUint32 flags);
+
+extern void _PR_NativeDestroyThread(PRThread *thread);
+extern void _PR_UserDestroyThread(PRThread *thread);
+
+extern PRThread* _PRI_AttachThread(
+    PRThreadType type, PRThreadPriority priority,
+    PRThreadStack *stack, PRUint32 flags);
+
+extern void _PRI_DetachThread(void);
+
+
+#define _PR_IO_PENDING(_thread) ((_thread)->io_pending)
+
+NSPR_API(void) _PR_MD_INIT_CPUS();
+#define    _PR_MD_INIT_CPUS _MD_INIT_CPUS
+
+NSPR_API(void) _PR_MD_WAKEUP_CPUS();
+#define    _PR_MD_WAKEUP_CPUS _MD_WAKEUP_CPUS
+
+/* Interrupts related */
+
+NSPR_API(void) _PR_MD_START_INTERRUPTS(void);
+#define    _PR_MD_START_INTERRUPTS _MD_START_INTERRUPTS
+
+NSPR_API(void) _PR_MD_STOP_INTERRUPTS(void);
+#define    _PR_MD_STOP_INTERRUPTS _MD_STOP_INTERRUPTS
+
+NSPR_API(void) _PR_MD_ENABLE_CLOCK_INTERRUPTS(void);
+#define    _PR_MD_ENABLE_CLOCK_INTERRUPTS _MD_ENABLE_CLOCK_INTERRUPTS
+
+NSPR_API(void) _PR_MD_DISABLE_CLOCK_INTERRUPTS(void);
+#define    _PR_MD_DISABLE_CLOCK_INTERRUPTS _MD_DISABLE_CLOCK_INTERRUPTS
+
+NSPR_API(void) _PR_MD_BLOCK_CLOCK_INTERRUPTS(void);
+#define    _PR_MD_BLOCK_CLOCK_INTERRUPTS _MD_BLOCK_CLOCK_INTERRUPTS
+
+NSPR_API(void) _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(void);
+#define    _PR_MD_UNBLOCK_CLOCK_INTERRUPTS _MD_UNBLOCK_CLOCK_INTERRUPTS
+
+/* The _PR_MD_WAIT_LOCK and _PR_MD_WAKEUP_WAITER functions put to sleep and
+ * awaken a thread which is waiting on a lock or cvar.
+ */
+extern PRStatus _PR_MD_WAIT(PRThread *, PRIntervalTime timeout);
+#define    _PR_MD_WAIT _MD_WAIT
+
+extern PRStatus _PR_MD_WAKEUP_WAITER(PRThread *);
+#define    _PR_MD_WAKEUP_WAITER _MD_WAKEUP_WAITER
+
+#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */
+NSPR_API(void) _PR_MD_CLOCK_INTERRUPT(void);
+#define    _PR_MD_CLOCK_INTERRUPT _MD_CLOCK_INTERRUPT
+#endif
+
+/* Stack debugging */
+NSPR_API(void) _PR_MD_INIT_STACK(PRThreadStack *ts, PRIntn redzone);
+#define    _PR_MD_INIT_STACK _MD_INIT_STACK
+
+NSPR_API(void) _PR_MD_CLEAR_STACK(PRThreadStack* ts);
+#define    _PR_MD_CLEAR_STACK _MD_CLEAR_STACK
+
+/* CPU related */
+NSPR_API(PRInt32) _PR_MD_GET_INTSOFF(void);
+#define    _PR_MD_GET_INTSOFF _MD_GET_INTSOFF
+
+NSPR_API(void) _PR_MD_SET_INTSOFF(PRInt32 _val);
+#define    _PR_MD_SET_INTSOFF _MD_SET_INTSOFF
+
+NSPR_API(_PRCPU*) _PR_MD_CURRENT_CPU(void);
+#define    _PR_MD_CURRENT_CPU _MD_CURRENT_CPU
+
+NSPR_API(void) _PR_MD_SET_CURRENT_CPU(_PRCPU *cpu);
+#define    _PR_MD_SET_CURRENT_CPU _MD_SET_CURRENT_CPU
+
+NSPR_API(void) _PR_MD_INIT_RUNNING_CPU(_PRCPU *cpu);
+#define    _PR_MD_INIT_RUNNING_CPU _MD_INIT_RUNNING_CPU
+
+/*
+ * Returns the number of threads awoken or 0 if a timeout occurred;
+ */
+extern PRInt32 _PR_MD_PAUSE_CPU(PRIntervalTime timeout);
+#define    _PR_MD_PAUSE_CPU _MD_PAUSE_CPU
+
+extern void _PR_MD_CLEANUP_BEFORE_EXIT(void);
+#define _PR_MD_CLEANUP_BEFORE_EXIT _MD_CLEANUP_BEFORE_EXIT
+
+extern void _PR_MD_EXIT(PRIntn status);
+#define    _PR_MD_EXIT _MD_EXIT
+
+/* Locks related */
+
+NSPR_API(void) _PR_MD_INIT_LOCKS(void);
+#define    _PR_MD_INIT_LOCKS _MD_INIT_LOCKS
+
+NSPR_API(PRStatus) _PR_MD_NEW_LOCK(_MDLock *md);
+#define    _PR_MD_NEW_LOCK _MD_NEW_LOCK
+
+NSPR_API(void) _PR_MD_FREE_LOCK(_MDLock *md);
+#define    _PR_MD_FREE_LOCK _MD_FREE_LOCK
+
+NSPR_API(void) _PR_MD_LOCK(_MDLock *md);
+#define    _PR_MD_LOCK _MD_LOCK
+
+/* Return 0 on success, a nonzero value on failure. */
+NSPR_API(PRIntn) _PR_MD_TEST_AND_LOCK(_MDLock *md);
+#define    _PR_MD_TEST_AND_LOCK _MD_TEST_AND_LOCK
+
+NSPR_API(void) _PR_MD_UNLOCK(_MDLock *md);
+#define    _PR_MD_UNLOCK _MD_UNLOCK
+
+NSPR_API(void) _PR_MD_IOQ_LOCK(void);
+#define    _PR_MD_IOQ_LOCK _MD_IOQ_LOCK
+
+NSPR_API(void) _PR_MD_IOQ_UNLOCK(void);
+#define    _PR_MD_IOQ_UNLOCK _MD_IOQ_UNLOCK
+
+#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */
+/* Semaphore related -- only for native threads */
+#ifdef HAVE_CVAR_BUILT_ON_SEM
+NSPR_API(void) _PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value);
+#define _PR_MD_NEW_SEM _MD_NEW_SEM
+
+NSPR_API(void) _PR_MD_DESTROY_SEM(_MDSemaphore *md);
+#define _PR_MD_DESTROY_SEM _MD_DESTROY_SEM
+
+NSPR_API(PRStatus) _PR_MD_TIMED_WAIT_SEM(
+    _MDSemaphore *md, PRIntervalTime timeout);
+#define _PR_MD_TIMED_WAIT_SEM _MD_TIMED_WAIT_SEM
+
+NSPR_API(PRStatus) _PR_MD_WAIT_SEM(_MDSemaphore *md);
+#define _PR_MD_WAIT_SEM _MD_WAIT_SEM
+
+NSPR_API(void) _PR_MD_POST_SEM(_MDSemaphore *md);
+#define _PR_MD_POST_SEM _MD_POST_SEM
+#endif /* HAVE_CVAR_BUILT_ON_SEM */
+
+#endif
+
+/* Condition Variables related -- only for native threads */
+
+#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */
+NSPR_API(PRInt32) _PR_MD_NEW_CV(_MDCVar *md);
+#define    _PR_MD_NEW_CV _MD_NEW_CV
+
+NSPR_API(void) _PR_MD_FREE_CV(_MDCVar *md);
+#define    _PR_MD_FREE_CV _MD_FREE_CV
+
+NSPR_API(void) _PR_MD_WAIT_CV(
+    _MDCVar *mdCVar,_MDLock *mdLock,PRIntervalTime timeout);
+#define    _PR_MD_WAIT_CV _MD_WAIT_CV
+
+NSPR_API(void) _PR_MD_NOTIFY_CV(_MDCVar *md, _MDLock *lock);
+#define    _PR_MD_NOTIFY_CV _MD_NOTIFY_CV
+
+NSPR_API(void) _PR_MD_NOTIFYALL_CV(_MDCVar *md, _MDLock *lock);
+#define    _PR_MD_NOTIFYALL_CV _MD_NOTIFYALL_CV
+#endif /* _PR_LOCAL_THREADS_ONLY */
+
+/* Threads related */
+NSPR_API(PRThread*) _PR_MD_CURRENT_THREAD(void);
+#define    _PR_MD_CURRENT_THREAD _MD_CURRENT_THREAD
+
+NSPR_API(PRThread*) _PR_MD_GET_ATTACHED_THREAD(void);
+#define    _PR_MD_GET_ATTACHED_THREAD _MD_GET_ATTACHED_THREAD
+
+NSPR_API(PRThread*) _PR_MD_LAST_THREAD(void);
+#define    _PR_MD_LAST_THREAD _MD_LAST_THREAD
+
+NSPR_API(void) _PR_MD_SET_CURRENT_THREAD(PRThread *thread);
+#define    _PR_MD_SET_CURRENT_THREAD _MD_SET_CURRENT_THREAD
+
+NSPR_API(void) _PR_MD_SET_LAST_THREAD(PRThread *thread);
+#define    _PR_MD_SET_LAST_THREAD _MD_SET_LAST_THREAD
+
+extern PRStatus _PR_MD_INIT_THREAD(PRThread *thread);
+#define    _PR_MD_INIT_THREAD _MD_INIT_THREAD
+
+extern void _PR_MD_EXIT_THREAD(PRThread *thread);
+#define    _PR_MD_EXIT_THREAD _MD_EXIT_THREAD
+
+#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */
+
+NSPR_API(PRStatus) _PR_MD_INIT_ATTACHED_THREAD(PRThread *thread);
+#define    _PR_MD_INIT_ATTACHED_THREAD _MD_INIT_ATTACHED_THREAD
+
+extern void _PR_MD_SUSPEND_THREAD(PRThread *thread);
+#define    _PR_MD_SUSPEND_THREAD _MD_SUSPEND_THREAD
+
+extern void _PR_MD_RESUME_THREAD(PRThread *thread);
+#define    _PR_MD_RESUME_THREAD _MD_RESUME_THREAD
+
+extern void _PR_MD_SUSPEND_CPU(_PRCPU  *cpu);
+#define    _PR_MD_SUSPEND_CPU _MD_SUSPEND_CPU
+
+extern void _PR_MD_RESUME_CPU(_PRCPU  *cpu);
+#define    _PR_MD_RESUME_CPU _MD_RESUME_CPU
+
+extern void _PR_MD_BEGIN_SUSPEND_ALL(void);
+#define    _PR_MD_BEGIN_SUSPEND_ALL _MD_BEGIN_SUSPEND_ALL
+
+extern void _PR_MD_END_SUSPEND_ALL(void);
+#define    _PR_MD_END_SUSPEND_ALL _MD_END_SUSPEND_ALL
+
+extern void _PR_MD_BEGIN_RESUME_ALL(void);
+#define    _PR_MD_BEGIN_RESUME_ALL _MD_BEGIN_RESUME_ALL
+
+extern void _PR_MD_END_RESUME_ALL(void);
+#define    _PR_MD_END_RESUME_ALL _MD_END_RESUME_ALL
+
+#if defined(IRIX) 
+NSPR_API(void) _PR_IRIX_CHILD_PROCESS(void);
+#endif        /* IRIX */
+
+#endif        /* !_PR_LOCAL_THREADS_ONLY */
+
+extern void _PR_MD_CLEAN_THREAD(PRThread *thread);
+#define    _PR_MD_CLEAN_THREAD _MD_CLEAN_THREAD
+
+#ifdef HAVE_CUSTOM_USER_THREADS
+extern void _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread *);
+#define    _PR_MD_CREATE_PRIMORDIAL_USER_THREAD _MD_CREATE_PRIMORDIAL_USER_THREAD
+
+extern PRThread* _PR_MD_CREATE_USER_THREAD(
+                        PRUint32 stacksize,
+                        void (*start)(void *),
+                        void *arg);
+#define    _PR_MD_CREATE_USER_THREAD _MD_CREATE_USER_THREAD
+#endif
+
+extern PRStatus _PR_MD_CREATE_THREAD(
+                        PRThread *thread, 
+                        void (*start) (void *), 
+                        PRThreadPriority priority,                      
+                        PRThreadScope scope,
+                        PRThreadState state,
+                        PRUint32 stackSize);
+#define    _PR_MD_CREATE_THREAD _MD_CREATE_THREAD
+
+extern void _PR_MD_JOIN_THREAD(_MDThread *md);
+#define    _PR_MD_JOIN_THREAD _MD_JOIN_THREAD
+
+extern void _PR_MD_END_THREAD(void);
+#define    _PR_MD_END_THREAD _MD_END_THREAD
+
+extern void _PR_MD_YIELD(void);
+#define    _PR_MD_YIELD _MD_YIELD
+
+extern void _PR_MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri);
+#define    _PR_MD_SET_PRIORITY _MD_SET_PRIORITY
+
+NSPR_API(void) _PR_MD_SUSPENDALL(void);
+#define    _PR_MD_SUSPENDALL _MD_SUSPENDALL
+
+NSPR_API(void) _PR_MD_RESUMEALL(void);
+#define    _PR_MD_RESUMEALL _MD_RESUMEALL
+
+extern void _PR_MD_INIT_CONTEXT(
+    PRThread *thread, char *top, void (*start) (void), PRBool *status);
+#define    _PR_MD_INIT_CONTEXT _MD_INIT_CONTEXT
+
+extern void _PR_MD_SWITCH_CONTEXT(PRThread *thread);
+#define    _PR_MD_SWITCH_CONTEXT _MD_SWITCH_CONTEXT
+
+extern void _PR_MD_RESTORE_CONTEXT(PRThread *thread);
+#define    _PR_MD_RESTORE_CONTEXT _MD_RESTORE_CONTEXT
+
+/* Segment related */
+extern void _PR_MD_INIT_SEGS(void);
+#define    _PR_MD_INIT_SEGS _MD_INIT_SEGS
+
+extern PRStatus _PR_MD_ALLOC_SEGMENT(PRSegment *seg, PRUint32 size, void *vaddr);
+#define    _PR_MD_ALLOC_SEGMENT _MD_ALLOC_SEGMENT
+
+extern void _PR_MD_FREE_SEGMENT(PRSegment *seg);
+#define    _PR_MD_FREE_SEGMENT _MD_FREE_SEGMENT
+
+/* Directory enumeration related */
+extern PRStatus _PR_MD_OPEN_DIR(_MDDir *md,const char *name);
+#define    _PR_MD_OPEN_DIR _MD_OPEN_DIR
+
+extern char * _PR_MD_READ_DIR(_MDDir *md, PRIntn flags);
+#define    _PR_MD_READ_DIR _MD_READ_DIR
+
+extern PRInt32 _PR_MD_CLOSE_DIR(_MDDir *md);
+#define    _PR_MD_CLOSE_DIR _MD_CLOSE_DIR
+
+/* Named semaphores related */
+extern PRSem * _PR_MD_OPEN_SEMAPHORE(
+    const char *osname, PRIntn flags, PRIntn mode, PRUintn value);
+#define    _PR_MD_OPEN_SEMAPHORE _MD_OPEN_SEMAPHORE
+
+extern PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem);
+#define    _PR_MD_WAIT_SEMAPHORE _MD_WAIT_SEMAPHORE
+
+extern PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem);
+#define    _PR_MD_POST_SEMAPHORE _MD_POST_SEMAPHORE
+
+extern PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem);
+#define    _PR_MD_CLOSE_SEMAPHORE _MD_CLOSE_SEMAPHORE
+
+extern PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname);
+#define    _PR_MD_DELETE_SEMAPHORE _MD_DELETE_SEMAPHORE
+
+/* I/O related */
+extern void _PR_MD_INIT_FILEDESC(PRFileDesc *fd);
+#define    _PR_MD_INIT_FILEDESC _MD_INIT_FILEDESC
+
+extern void _PR_MD_MAKE_NONBLOCK(PRFileDesc *fd);
+#define    _PR_MD_MAKE_NONBLOCK _MD_MAKE_NONBLOCK
+
+/* File I/O related */
+extern PROsfd _PR_MD_OPEN(const char *name, PRIntn osflags, PRIntn mode);
+#define    _PR_MD_OPEN _MD_OPEN
+
+extern PROsfd _PR_MD_OPEN_FILE(const char *name, PRIntn osflags, PRIntn mode);
+#define    _PR_MD_OPEN_FILE _MD_OPEN_FILE
+
+extern PRInt32 _PR_MD_CLOSE_FILE(PROsfd osfd);
+#define    _PR_MD_CLOSE_FILE _MD_CLOSE_FILE
+
+extern PRInt32 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 amount);
+#define    _PR_MD_READ _MD_READ
+
+extern PRInt32 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 amount);
+#define    _PR_MD_WRITE _MD_WRITE
+
+extern PRInt32 _PR_MD_WRITEV(
+    PRFileDesc *fd, const struct PRIOVec *iov,
+    PRInt32 iov_size, PRIntervalTime timeout);
+#define    _PR_MD_WRITEV _MD_WRITEV
+
+extern PRInt32 _PR_MD_FSYNC(PRFileDesc *fd);
+#define    _PR_MD_FSYNC _MD_FSYNC
+
+extern PRInt32 _PR_MD_DELETE(const char *name);
+#define        _PR_MD_DELETE _MD_DELETE
+
+extern PRInt32 _PR_MD_RENAME(const char *from, const char *to);
+#define _PR_MD_RENAME _MD_RENAME
+
+extern PRInt32 _PR_MD_ACCESS(const char *name, PRAccessHow how);
+#define _PR_MD_ACCESS _MD_ACCESS
+
+extern PRInt32 _PR_MD_STAT(const char *name, struct stat *buf);
+#define _PR_MD_STAT _MD_STAT
+
+extern PRInt32 _PR_MD_MKDIR(const char *name, PRIntn mode);
+#define _PR_MD_MKDIR _MD_MKDIR
+
+extern PRInt32 _PR_MD_MAKE_DIR(const char *name, PRIntn mode);
+#define _PR_MD_MAKE_DIR _MD_MAKE_DIR
+
+extern PRInt32 _PR_MD_RMDIR(const char *name);
+#define _PR_MD_RMDIR _MD_RMDIR
+
+#ifdef MOZ_UNICODE
+/* UTF16 File I/O related */
+extern PRStatus _PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *md, const PRUnichar *name);
+#define    _PR_MD_OPEN_DIR_UTF16 _MD_OPEN_DIR_UTF16
+
+extern PROsfd _PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, PRIntn mode);
+#define    _PR_MD_OPEN_FILE_UTF16 _MD_OPEN_FILE_UTF16
+
+extern PRUnichar * _PR_MD_READ_DIR_UTF16(_MDDirUTF16 *md, PRIntn flags);
+#define    _PR_MD_READ_DIR_UTF16 _MD_READ_DIR_UTF16
+
+extern PRInt32 _PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *md);
+#define    _PR_MD_CLOSE_DIR_UTF16 _MD_CLOSE_DIR_UTF16
+
+extern PRInt32 _PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info);
+#define _PR_MD_GETFILEINFO64_UTF16 _MD_GETFILEINFO64_UTF16
+#endif /* MOZ_UNICODE */
+
+/* Socket I/O related */
+extern void _PR_MD_INIT_IO(void);
+#define    _PR_MD_INIT_IO _MD_INIT_IO
+
+extern PRInt32 _PR_MD_CLOSE_SOCKET(PROsfd osfd);
+#define    _PR_MD_CLOSE_SOCKET _MD_CLOSE_SOCKET
+
+extern PRInt32 _PR_MD_CONNECT(
+    PRFileDesc *fd, const PRNetAddr *addr,
+    PRUint32 addrlen, PRIntervalTime timeout);
+#define    _PR_MD_CONNECT _MD_CONNECT
+
+extern PROsfd _PR_MD_ACCEPT(
+    PRFileDesc *fd, PRNetAddr *addr,
+    PRUint32 *addrlen, PRIntervalTime timeout);
+#define    _PR_MD_ACCEPT _MD_ACCEPT
+
+extern PRInt32 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen);
+#define    _PR_MD_BIND _MD_BIND
+
+extern PRInt32 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog);
+#define    _PR_MD_LISTEN _MD_LISTEN
+
+extern PRInt32 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how);
+#define    _PR_MD_SHUTDOWN _MD_SHUTDOWN
+
+extern PRInt32 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, 
+                               PRIntn flags, PRIntervalTime timeout);
+#define    _PR_MD_RECV _MD_RECV
+
+extern PRInt32 _PR_MD_SEND(
+    PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, 
+    PRIntervalTime timeout);
+#define    _PR_MD_SEND _MD_SEND
+
+extern PRInt32 _PR_MD_ACCEPT_READ(PRFileDesc *sd, PROsfd *newSock, 
+                                PRNetAddr **raddr, void *buf, PRInt32 amount,
+                                PRIntervalTime timeout);
+#define _PR_MD_ACCEPT_READ _MD_ACCEPT_READ
+
+#ifdef WIN32
+extern PROsfd _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *addr, 
+                                PRUint32 *addrlen, PRIntervalTime timeout,
+                                PRBool fast,
+                                _PR_AcceptTimeoutCallback callback,
+                                void *callbackArg);
+
+extern PRInt32 _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PROsfd *newSock, 
+                                PRNetAddr **raddr, void *buf, PRInt32 amount,
+                                PRIntervalTime timeout, PRBool fast,
+                                _PR_AcceptTimeoutCallback callback,
+                                void *callbackArg);
+
+extern void _PR_MD_UPDATE_ACCEPT_CONTEXT(PROsfd s, PROsfd ls);
+#define _PR_MD_UPDATE_ACCEPT_CONTEXT _MD_UPDATE_ACCEPT_CONTEXT
+/*
+ * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
+ * We store the value in a PRTime variable for convenience.
+ * This constant is used by _PR_FileTimeToPRTime().
+ * This is defined in ntmisc.c
+ */
+extern const PRTime _pr_filetime_offset;
+#endif /* WIN32 */
+
+extern PRInt32 _PR_MD_SENDFILE(
+    PRFileDesc *sock, PRSendFileData *sfd, 
+	PRInt32 flags, PRIntervalTime timeout);
+#define _PR_MD_SENDFILE _MD_SENDFILE
+
+extern PRStatus _PR_MD_GETSOCKNAME(
+    PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
+#define    _PR_MD_GETSOCKNAME _MD_GETSOCKNAME
+
+extern PRStatus _PR_MD_GETPEERNAME(
+    PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
+#define    _PR_MD_GETPEERNAME _MD_GETPEERNAME
+
+extern PRStatus _PR_MD_GETSOCKOPT(
+    PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen);
+#define    _PR_MD_GETSOCKOPT _MD_GETSOCKOPT
+
+extern PRStatus _PR_MD_SETSOCKOPT(
+    PRFileDesc *fd, PRInt32 level, PRInt32 optname,
+    const char* optval, PRInt32 optlen);
+#define    _PR_MD_SETSOCKOPT _MD_SETSOCKOPT
+
+extern PRStatus PR_CALLBACK _PR_SocketGetSocketOption(
+    PRFileDesc *fd, PRSocketOptionData *data);
+
+extern PRStatus PR_CALLBACK _PR_SocketSetSocketOption(
+    PRFileDesc *fd, const PRSocketOptionData *data);
+
+extern PRInt32 _PR_MD_RECVFROM(
+    PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+    PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout);
+#define    _PR_MD_RECVFROM _MD_RECVFROM
+
+extern PRInt32 _PR_MD_SENDTO(
+    PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+    const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout);
+#define    _PR_MD_SENDTO _MD_SENDTO
+
+extern PRInt32 _PR_MD_SOCKETPAIR(int af, int type, int flags, PROsfd *osfd);
+#define    _PR_MD_SOCKETPAIR _MD_SOCKETPAIR
+
+extern PROsfd _PR_MD_SOCKET(int af, int type, int flags);
+#define    _PR_MD_SOCKET _MD_SOCKET
+
+extern PRInt32 _PR_MD_SOCKETAVAILABLE(PRFileDesc *fd);
+#define    _PR_MD_SOCKETAVAILABLE _MD_SOCKETAVAILABLE
+
+extern PRInt32 _PR_MD_PIPEAVAILABLE(PRFileDesc *fd);
+#define    _PR_MD_PIPEAVAILABLE _MD_PIPEAVAILABLE
+
+extern PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds,
+                                                                                        PRIntervalTime timeout);
+#define    _PR_MD_PR_POLL _MD_PR_POLL
+
+/*
+ * Initialize fd->secret->inheritable for a newly created fd.
+ * If 'imported' is false, the osfd (i.e., fd->secret->md.osfd)
+ * was created by NSPR and hence has the OS-dependent default
+ * inheritable attribute.  If 'imported' is true, the osfd was
+ * not created by NSPR and hence a system call is required to
+ * query its inheritable attribute.  Since we may never need to
+ * know the inheritable attribute of a fd, a platform may choose
+ * to initialize fd->secret->inheritable of an imported fd to
+ * _PR_TRI_UNKNOWN and only pay the cost of the system call
+ * (in _PR_MD_QUERY_FD_INHERITABLE) when necessary.
+ */
+extern void _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported);
+#define    _PR_MD_INIT_FD_INHERITABLE _MD_INIT_FD_INHERITABLE
+
+extern PRStatus _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable);
+#define    _PR_MD_SET_FD_INHERITABLE _MD_SET_FD_INHERITABLE
+
+
+#define _PR_PROCESS_TIMEOUT_INTERRUPT_ERRORS(me) \
+        if (_PR_PENDING_INTERRUPT(me)) { \
+                me->flags &= ~_PR_INTERRUPT; \
+                PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); \
+        } else { \
+                PR_SetError(PR_IO_TIMEOUT_ERROR, 0); \
+        }                                                        
+                
+extern void *_PR_MD_GET_SP(PRThread *thread);
+#define    _PR_MD_GET_SP _MD_GET_SP
+
+#endif /* defined(_PR_PTHREADS) */
+
+/************************************************************************/
+/*************************************************************************
+** The remainder of the definitions are shared by pthreads and the classic
+** NSPR code. These too may be conditionalized.
+*************************************************************************/
+/************************************************************************/
+
+extern PROffset32 _PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence);
+#define    _PR_MD_LSEEK _MD_LSEEK
+
+extern PROffset64 _PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence);
+#define    _PR_MD_LSEEK64 _MD_LSEEK64
+
+extern PRInt32 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info);
+#define _PR_MD_GETFILEINFO _MD_GETFILEINFO
+
+extern PRInt32 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info);
+#define _PR_MD_GETFILEINFO64 _MD_GETFILEINFO64
+
+extern PRInt32 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info);
+#define _PR_MD_GETOPENFILEINFO _MD_GETOPENFILEINFO
+
+extern PRInt32 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info);
+#define _PR_MD_GETOPENFILEINFO64 _MD_GETOPENFILEINFO64
+
+
+/*****************************************************************************/
+/************************** File descriptor caching **************************/
+/*****************************************************************************/
+extern void _PR_InitFdCache(void);
+extern void _PR_CleanupFdCache(void);
+extern PRFileDesc *_PR_Getfd(void);
+extern void _PR_Putfd(PRFileDesc *fd);
+
+/*
+ * These flags are used by NSPR temporarily in the poll
+ * descriptor's out_flags field to record the mapping of
+ * NSPR's poll flags to the system poll flags.
+ *
+ * If _PR_POLL_READ_SYS_WRITE bit is set, it means the
+ * PR_POLL_READ flag specified by the topmost layer is
+ * mapped to the WRITE flag at the system layer.  Similarly
+ * for the other three _PR_POLL_XXX_SYS_YYY flags.  It is
+ * assumed that the PR_POLL_EXCEPT flag doesn't get mapped
+ * to other flags.
+ */
+#define _PR_POLL_READ_SYS_READ     0x1
+#define _PR_POLL_READ_SYS_WRITE    0x2
+#define _PR_POLL_WRITE_SYS_READ    0x4
+#define _PR_POLL_WRITE_SYS_WRITE   0x8
+
+/*
+** These methods are coerced into file descriptor methods table
+** when the intended service is inappropriate for the particular
+** type of file descriptor.
+*/
+extern PRIntn _PR_InvalidInt(void);
+extern PRInt16 _PR_InvalidInt16(void);
+extern PRInt64 _PR_InvalidInt64(void);
+extern PRStatus _PR_InvalidStatus(void);
+extern PRFileDesc *_PR_InvalidDesc(void);
+
+extern PRIOMethods _pr_faulty_methods;
+
+/*
+** The PR_NETADDR_SIZE macro can only be called on a PRNetAddr union
+** whose 'family' field is set.  It returns the size of the union
+** member corresponding to the specified address family.
+*/
+
+extern PRUintn _PR_NetAddrSize(const PRNetAddr* addr);
+
+#if defined(_PR_INET6)
+
+#define PR_NETADDR_SIZE(_addr) _PR_NetAddrSize(_addr)
+
+#elif defined(_PR_HAVE_MD_SOCKADDR_IN6)
+
+/*
+** Under the following conditions:
+** 1. _PR_INET6 is not defined;
+** 2. _PR_INET6_PROBE is defined;
+** 3. struct sockaddr_in6 has nonstandard fields at the end
+**    (e.g., on Solaris 8),
+** (_addr)->ipv6 is smaller than struct sockaddr_in6, and
+** hence we can't pass sizeof((_addr)->ipv6) to socket
+** functions such as connect because they would fail with
+** EINVAL.
+**
+** To pass the correct socket address length to socket
+** functions, define the macro _PR_HAVE_MD_SOCKADDR_IN6 and
+** define struct _md_sockaddr_in6 to be isomorphic to
+** struct sockaddr_in6.
+*/
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+#define PR_NETADDR_SIZE(_addr) 					\
+        ((_addr)->raw.family == PR_AF_INET		\
+        ? sizeof((_addr)->inet)					\
+        : ((_addr)->raw.family == PR_AF_INET6	\
+        ? sizeof(struct _md_sockaddr_in6)		\
+        : sizeof((_addr)->local)))
+#else
+#define PR_NETADDR_SIZE(_addr) 					\
+        ((_addr)->raw.family == PR_AF_INET		\
+        ? sizeof((_addr)->inet)					\
+        : sizeof(struct _md_sockaddr_in6))
+#endif /* defined(XP_UNIX) */
+
+#else
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+#define PR_NETADDR_SIZE(_addr) 					\
+        ((_addr)->raw.family == PR_AF_INET		\
+        ? sizeof((_addr)->inet)					\
+        : ((_addr)->raw.family == PR_AF_INET6	\
+        ? sizeof((_addr)->ipv6)					\
+        : sizeof((_addr)->local)))
+#else
+#define PR_NETADDR_SIZE(_addr) 					\
+        ((_addr)->raw.family == PR_AF_INET		\
+        ? sizeof((_addr)->inet)					\
+        : sizeof((_addr)->ipv6))
+#endif /* defined(XP_UNIX) */
+
+#endif /* defined(_PR_INET6) */
+
+extern PRStatus _PR_MapOptionName(
+    PRSockOption optname, PRInt32 *level, PRInt32 *name);
+extern void _PR_InitThreads(
+    PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs);
+
+struct PRLock {
+#if defined(_PR_PTHREADS)
+    pthread_mutex_t mutex;          /* the underlying lock */
+    _PT_Notified notified;          /* array of conditions notified */
+    PRBool locked;                  /* whether the mutex is locked */
+    pthread_t owner;                /* if locked, current lock owner */
+#elif defined(_PR_BTHREADS)
+    sem_id	semaphoreID;	    /* the underlying lock */
+    int32	benaphoreCount;	    /* number of people in lock */
+    thread_id	owner;		    /* current lock owner */
+#else /* not pthreads or Be threads */
+    PRCList links;                  /* linkage for PRThread.lockList */
+    struct PRThread *owner;         /* current lock owner */
+    PRCList waitQ;                  /* list of threads waiting for lock */
+    PRThreadPriority priority;      /* priority of lock */ 
+    PRThreadPriority boostPriority; /* boosted priority of lock owner */
+    _MDLock ilock;                  /* Internal Lock to protect user-level fields */
+#endif
+};
+
+extern void _PR_InitLocks(void);
+
+struct PRCondVar {
+    PRLock *lock;               /* associated lock that protects the condition */
+#if defined(_PR_PTHREADS)
+    pthread_cond_t cv;          /* underlying pthreads condition */
+    PRInt32 notify_pending;     /* CV has destroy pending notification */
+#elif defined(_PR_BTHREADS)
+    sem_id    sem;              /* the underlying lock */
+    sem_id    handshakeSem;     /* the lock for 'notify'-threads waiting for confirmation */
+    sem_id    signalSem;        /* the lock for threads waiting for someone to notify */
+    volatile int32    nw;       /* the number waiting */
+    volatile int32    ns;       /* the number signalling */
+    long signalBenCount;        /* the number waiting on the underlying sem */
+#else /* not pthreads or Be threads */
+    PRCList condQ;              /* Condition variable wait Q */
+    _MDLock ilock;              /* Internal Lock to protect condQ */
+    _MDCVar md;
+#endif
+};
+
+/************************************************************************/
+
+struct PRMonitor {
+    const char* name;           /* monitor name for debugging */
+#if defined(_PR_PTHREADS)
+    PRLock lock;                /* the lock structure */
+    pthread_t owner;            /* the owner of the lock or invalid */
+    PRCondVar *cvar;            /* condition variable queue */
+#else  /* defined(_PR_PTHREADS) */
+    PRCondVar *cvar;            /* associated lock and condition variable queue */
+#endif /* defined(_PR_PTHREADS) */
+    PRUint32 entryCount;        /* # of times re-entered */
+};
+
+/************************************************************************/
+
+struct PRSemaphore {
+#if defined(_PR_BTHREADS)
+    sem_id  sem;
+    int32   benaphoreCount;
+#else
+    PRCondVar *cvar;        /* associated lock and condition variable queue */
+    PRUintn count;            /* the value of the counting semaphore */
+    PRUint32 waiters;            /* threads waiting on the semaphore */
+#if defined(_PR_PTHREADS)
+#else  /* defined(_PR_PTHREADS) */
+    _MDSemaphore md;
+#endif /* defined(_PR_PTHREADS) */
+#endif /* defined(_PR_BTHREADS) */
+};
+
+NSPR_API(void) _PR_InitSem(void);
+
+/*************************************************************************/
+
+struct PRSem {
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+    sem_t *sem;
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+    int semid;
+#elif defined(WIN32)
+    HANDLE sem;
+#else
+    PRInt8 notused;
+#endif
+};
+
+/*************************************************************************/
+
+struct PRStackStr {
+    /* head MUST be at offset 0; assembly language code relies on this */
+#if defined(AIX)
+    volatile PRStackElem prstk_head;
+#else
+    PRStackElem prstk_head;
+#endif
+
+    PRLock *prstk_lock;
+    char *prstk_name;
+};
+
+/************************************************************************/
+
+/* XXX this needs to be exported (sigh) */
+struct PRThreadStack {
+    PRCList links;
+    PRUintn flags;
+
+    char *allocBase;            /* base of stack's allocated memory */
+    PRUint32 allocSize;         /* size of stack's allocated memory */
+    char *stackBottom;          /* bottom of stack from C's point of view */
+    char *stackTop;             /* top of stack from C's point of view */
+    PRUint32 stackSize;         /* size of usable portion of the stack */
+
+    PRSegment *seg;
+        PRThread* thr;          /* back pointer to thread owning this stack */
+
+#if defined(_PR_PTHREADS)
+#else /* defined(_PR_PTHREADS) */
+    _MDThreadStack md;
+#endif /* defined(_PR_PTHREADS) */
+};
+
+extern void _PR_DestroyThreadPrivate(PRThread*);
+
+typedef void (PR_CALLBACK *_PRStartFn)(void *);
+
+struct PRThread {
+    PRUint32 state;                 /* thread's creation state */
+    PRThreadPriority priority;      /* apparent priority, loosly defined */
+
+    void *arg;                      /* argument to the client's entry point */
+    _PRStartFn startFunc;           /* the root of the client's thread */
+
+    PRThreadStack *stack;           /* info about thread's stack (for GC) */
+    void *environment;              /* pointer to execution environment */
+
+    PRThreadDumpProc dump;          /* dump thread info out */
+    void *dumpArg;                  /* argument for the dump function */
+
+    /*
+    ** Per thread private data
+    */
+    PRUint32 tpdLength;             /* thread's current vector length */
+    void **privateData;             /* private data vector or NULL */
+    PRErrorCode errorCode;          /* current NSPR error code | zero */
+    PRInt32 osErrorCode;            /* mapping of errorCode | zero */
+    PRIntn  errorStringLength;      /* textLength from last call to PR_SetErrorText() */
+    PRInt32 errorStringSize;        /* malloc()'d size of buffer | zero */
+    char *errorString;              /* current error string | NULL */
+
+#if defined(_PR_PTHREADS)
+    pthread_t id;                   /* pthread identifier for the thread */
+    PRBool okToDelete;              /* ok to delete the PRThread struct? */
+    PRCondVar *waiting;             /* where the thread is waiting | NULL */
+    void *sp;                       /* recorded sp for garbage collection */
+    PRThread *next, *prev;          /* simple linked list of all threads */
+    PRUint32 suspend;               /* used to store suspend and resume flags */
+#ifdef PT_NO_SIGTIMEDWAIT
+    pthread_mutex_t suspendResumeMutex;
+    pthread_cond_t suspendResumeCV;
+#endif
+    PRUint32 interrupt_blocked;     /* interrupt blocked */
+    struct pollfd *syspoll_list;    /* Unix polling list used by PR_Poll */
+    PRUint32 syspoll_count;         /* number of elements in syspoll_list */
+#if defined(_PR_POLL_WITH_SELECT)
+    int *selectfd_list;             /* Unix fd's that PR_Poll selects on */
+    PRUint32 selectfd_count;        /* number of elements in selectfd_list */
+#endif
+#elif defined(_PR_BTHREADS)
+    PRUint32 flags;
+    _MDThread md;
+    PRBool io_pending;
+    PRInt32 io_fd;
+    PRBool io_suspended;
+#else /* not pthreads or Be threads */
+    _MDLock threadLock;             /* Lock to protect thread state variables.
+                                     * Protects the following fields:
+                                     *     state
+                                     *     priority
+                                     *     links
+                                     *     wait
+                                     *     cpu
+                                     */
+    PRUint32 queueCount;
+    PRUint32 waitCount;
+
+    PRCList active;                 /* on list of all active threads        */
+    PRCList links;
+    PRCList waitQLinks;             /* when thread is PR_Wait'ing */
+    PRCList lockList;               /* list of locks currently holding */
+    PRIntervalTime sleep;           /* sleep time when thread is sleeping */
+    struct _wait {
+        struct PRLock *lock;
+        struct PRCondVar *cvar;
+    } wait;
+
+    PRUint32 id;
+    PRUint32 flags;
+    PRUint32 no_sched;              /* Don't schedule the thread to run.
+                                     * This flag has relevance only when
+                                     * multiple NSPR CPUs are created.
+                                     * When a thread is de-scheduled, there
+                                     * is a narrow window of time in which
+                                     * the thread is put on the run queue
+                                     * but the scheduler is actually using
+                                     * the stack of this thread.  It is safe
+                                     * to run this thread on a different CPU
+                                     * only when its stack is not in use on
+                                     * any other CPU.  The no_sched flag is
+                                     * set during this interval to prevent
+                                     * the thread from being scheduled on a
+                                     * different CPU.
+                                     */
+
+    /* thread termination condition variable for join */
+    PRCondVar *term;
+
+    _PRCPU *cpu;                    /* cpu to which this thread is bound    */
+    PRUint32 threadAllocatedOnStack;/* boolean */
+
+    /* When an async IO is in progress and a second async IO cannot be 
+     * initiated, the io_pending flag is set to true.  Some platforms will
+     * not use the io_pending flag.  If the io_pending flag is true, then
+     * io_fd is the OS-file descriptor on which IO is pending.
+     */
+    PRBool io_pending;
+    PRInt32 io_fd;
+ 
+    /* If a timeout occurs or if an outstanding IO is interrupted and the
+     * OS doesn't support a real cancellation (NT or MAC), then the 
+     * io_suspended flag will be set to true.  The thread will be resumed
+     * but may run into trouble issuing additional IOs until the io_pending
+     * flag can be cleared 
+     */
+    PRBool io_suspended;
+
+    _MDThread md;
+#endif
+};
+
+struct PRProcessAttr {
+    PRFileDesc *stdinFd;
+    PRFileDesc *stdoutFd;
+    PRFileDesc *stderrFd;
+    char *currentDirectory;
+    char *fdInheritBuffer;
+    PRSize fdInheritBufferSize;
+    PRSize fdInheritBufferUsed;
+};
+
+struct PRProcess {
+    _MDProcess md;
+};
+
+struct PRFileMap {
+    PRFileDesc *fd;
+    PRFileMapProtect prot;
+    _MDFileMap md;
+};
+
+/************************************************************************/
+
+/*
+** File descriptors of the NSPR layer can be in one of the
+** following states (stored in the 'state' field of struct
+** PRFilePrivate):
+** - _PR_FILEDESC_OPEN: The OS fd is open.
+** - _PR_FILEDESC_CLOSED: The OS fd is closed.  The PRFileDesc
+**   is still open but is unusable.  The only operation allowed
+**   on the PRFileDesc is PR_Close().
+** - _PR_FILEDESC_FREED: The OS fd is closed and the PRFileDesc
+**   structure is freed.
+*/
+
+#define _PR_FILEDESC_OPEN       0xaaaaaaaa    /* 1010101... */
+#define _PR_FILEDESC_CLOSED     0x55555555    /* 0101010... */
+#define _PR_FILEDESC_FREED      0x11111111
+
+/*
+** A boolean type with an additional "unknown" state
+*/
+
+typedef enum {
+    _PR_TRI_TRUE = 1,
+    _PR_TRI_FALSE = 0,
+    _PR_TRI_UNKNOWN = -1
+} _PRTriStateBool;
+
+struct PRFilePrivate {
+    PRInt32 state;
+    PRBool nonblocking;
+    _PRTriStateBool inheritable;
+    PRFileDesc *next;
+    PRIntn lockCount;   /*   0: not locked
+                         *  -1: a native lockfile call is in progress
+                         * > 0: # times the file is locked */
+#ifdef _PR_HAVE_PEEK_BUFFER
+    char *peekBuffer;
+    PRInt32 peekBufSize;
+    PRInt32 peekBytes;
+#endif
+#if !defined(_PR_HAVE_O_APPEND)
+    PRBool  appendMode; /* Some platforms don't have O_APPEND or its
+                         * equivalent, so they have to seek to end of
+                         * file on write if the file was opened in
+                         * append mode.  See Bugzilla 4090, 276330. */
+#endif
+    _MDFileDesc md;
+#ifdef _PR_NEED_SECRET_AF
+    PRUint16 af;        /* If the platform's implementation of accept()
+                         * requires knowing the address family of the 
+			 * socket, we save the address family here. */
+#endif
+};
+
+#ifdef _WIN64
+#define PR_PRIdOSFD "lld"       /* for printing PROsfd */
+#define PR_PRIxOSFD "llx"
+#define PR_SCNdOSFD "lld"       /* for scanning PROsfd */
+#define PR_SCNxOSFD "llx"
+#else
+#define PR_PRIdOSFD "ld"        /* for printing PROsfd */
+#define PR_PRIxOSFD "lx"
+#define PR_SCNdOSFD "ld"        /* for scanning PROsfd */
+#define PR_SCNxOSFD "lx"
+#endif
+
+struct PRDir {
+    PRDirEntry d;
+    _MDDir md;
+};
+
+#ifdef MOZ_UNICODE
+struct PRDirUTF16 { 
+    PRDirEntry d; 
+    _MDDirUTF16 md; 
+}; 
+#endif /* MOZ_UNICODE */
+
+extern void _PR_InitSegs(void);
+extern void _PR_InitStacks(void);
+extern void _PR_InitTPD(void);
+extern void _PR_InitMem(void);
+extern void _PR_InitEnv(void);
+extern void _PR_InitCMon(void);
+extern void _PR_InitIO(void);
+extern void _PR_InitLog(void);
+extern void _PR_InitNet(void);
+extern void _PR_InitClock(void);
+extern void _PR_InitLinker(void);
+extern void _PR_InitAtomic(void);
+extern void _PR_InitCPUs(void);
+extern void _PR_InitDtoa(void);
+extern void _PR_InitTime(void);
+extern void _PR_InitMW(void);
+extern void _PR_InitRWLocks(void);
+extern void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me);
+extern void _PR_CleanupThread(PRThread *thread);
+extern void _PR_CleanupCallOnce(void);
+extern void _PR_CleanupMW(void);
+extern void _PR_CleanupTime(void);
+extern void _PR_CleanupDtoa(void);
+extern void _PR_ShutdownLinker(void);
+extern void _PR_CleanupEnv(void);
+extern void _PR_CleanupIO(void);
+extern void _PR_CleanupCMon(void);
+extern void _PR_CleanupNet(void);
+extern void _PR_CleanupLayerCache(void);
+extern void _PR_CleanupStacks(void);
+#ifdef WINNT
+extern void _PR_CleanupCPUs(void);
+#endif
+extern void _PR_CleanupThreads(void);
+extern void _PR_CleanupTPD(void);
+extern void _PR_Cleanup(void);
+extern void _PR_LogCleanup(void);
+extern void _PR_InitLayerCache(void);
+#ifdef GC_LEAK_DETECTOR
+extern void _PR_InitGarbageCollector(void);
+#endif
+
+extern PRBool _pr_initialized;
+extern void _PR_ImplicitInitialization(void);
+extern PRBool _PR_Obsolete(const char *obsolete, const char *preferred);
+
+/************************************************************************/
+
+struct PRSegment {
+    void *vaddr;
+    PRUint32 size;
+    PRUintn flags;
+#if defined(_PR_PTHREADS)
+#else  /* defined(_PR_PTHREADS) */
+    _MDSegment md;
+#endif /* defined(_PR_PTHREADS) */
+};
+
+/* PRSegment.flags */
+#define _PR_SEG_VM    0x1
+
+/************************************************************************/
+
+extern PRInt32 _pr_pageSize;
+extern PRInt32 _pr_pageShift;
+
+extern PRLogModuleInfo *_pr_clock_lm;
+extern PRLogModuleInfo *_pr_cmon_lm;
+extern PRLogModuleInfo *_pr_io_lm;
+extern PRLogModuleInfo *_pr_cvar_lm;
+extern PRLogModuleInfo *_pr_mon_lm;
+extern PRLogModuleInfo *_pr_linker_lm;
+extern PRLogModuleInfo *_pr_sched_lm;
+extern PRLogModuleInfo *_pr_thread_lm;
+extern PRLogModuleInfo *_pr_gc_lm;
+
+extern PRFileDesc *_pr_stdin;
+extern PRFileDesc *_pr_stdout;
+extern PRFileDesc *_pr_stderr;
+
+/* Zone allocator */
+/*
+** The zone allocator code has hardcoded pthread types and
+** functions, so it can only be used in the pthreads version.
+** This can be fixed by replacing the hardcoded pthread types
+** and functions with macros that expand to the native thread
+** types and functions on each platform.
+*/
+#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
+#define _PR_ZONE_ALLOCATOR
+#endif
+
+#ifdef _PR_ZONE_ALLOCATOR
+extern void _PR_InitZones(void);
+extern void _PR_DestroyZones(void);
+#endif
+
+/* Overriding malloc, free, etc. */
+#if !defined(_PR_NO_PREEMPT) && defined(XP_UNIX) \
+        && !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY) \
+        && !defined(PURIFY) \
+        && !defined(DARWIN) \
+        && !defined(NEXTSTEP) \
+        && !defined(QNX) \
+        && !(defined (UNIXWARE) && defined (USE_SVR4_THREADS))
+#define _PR_OVERRIDE_MALLOC
+#endif
+
+/*************************************************************************
+* External machine-dependent code provided by each OS.                     *                                                                     *
+*************************************************************************/
+
+/* Initialization related */
+extern void _PR_MD_EARLY_INIT(void);
+#define    _PR_MD_EARLY_INIT _MD_EARLY_INIT
+
+extern void _PR_MD_INTERVAL_INIT(void);
+#define    _PR_MD_INTERVAL_INIT _MD_INTERVAL_INIT
+
+NSPR_API(void) _PR_MD_FINAL_INIT(void);
+#define    _PR_MD_FINAL_INIT _MD_FINAL_INIT
+
+/* Process control */
+
+extern PRProcess * _PR_MD_CREATE_PROCESS(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr);
+#define    _PR_MD_CREATE_PROCESS _MD_CREATE_PROCESS
+
+extern PRStatus _PR_MD_DETACH_PROCESS(PRProcess *process);
+#define    _PR_MD_DETACH_PROCESS _MD_DETACH_PROCESS
+
+extern PRStatus _PR_MD_WAIT_PROCESS(PRProcess *process, PRInt32 *exitCode);
+#define    _PR_MD_WAIT_PROCESS _MD_WAIT_PROCESS
+
+extern PRStatus _PR_MD_KILL_PROCESS(PRProcess *process);
+#define    _PR_MD_KILL_PROCESS _MD_KILL_PROCESS        
+
+/* Current Time */
+NSPR_API(PRTime) _PR_MD_NOW(void);
+#define    _PR_MD_NOW _MD_NOW
+
+/* Environment related */
+extern char* _PR_MD_GET_ENV(const char *name);
+#define    _PR_MD_GET_ENV _MD_GET_ENV
+
+extern PRIntn _PR_MD_PUT_ENV(const char *name);
+#define    _PR_MD_PUT_ENV _MD_PUT_ENV
+
+/* Atomic operations */
+
+extern void _PR_MD_INIT_ATOMIC(void);
+#define    _PR_MD_INIT_ATOMIC _MD_INIT_ATOMIC
+
+extern PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *);
+#define    _PR_MD_ATOMIC_INCREMENT _MD_ATOMIC_INCREMENT
+
+extern PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *, PRInt32);
+#define    _PR_MD_ATOMIC_ADD _MD_ATOMIC_ADD
+
+extern PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *);
+#define    _PR_MD_ATOMIC_DECREMENT _MD_ATOMIC_DECREMENT
+
+extern PRInt32 _PR_MD_ATOMIC_SET(PRInt32 *, PRInt32);
+#define    _PR_MD_ATOMIC_SET _MD_ATOMIC_SET
+
+/* Garbage collection */
+
+/*
+** Save the registers that the GC would find interesting into the thread
+** "t". isCurrent will be non-zero if the thread state that is being
+** saved is the currently executing thread. Return the address of the
+** first register to be scanned as well as the number of registers to
+** scan in "np".
+**
+** If "isCurrent" is non-zero then it is allowed for the thread context
+** area to be used as scratch storage to hold just the registers
+** necessary for scanning.
+*/
+extern PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np);
+
+/* Time intervals */
+
+extern PRIntervalTime _PR_MD_GET_INTERVAL(void);
+#define _PR_MD_GET_INTERVAL _MD_GET_INTERVAL
+
+extern PRIntervalTime _PR_MD_INTERVAL_PER_SEC(void);
+#define _PR_MD_INTERVAL_PER_SEC _MD_INTERVAL_PER_SEC
+
+/* Affinity masks */
+
+extern PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask );
+#define _PR_MD_SETTHREADAFFINITYMASK _MD_SETTHREADAFFINITYMASK
+
+extern PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask);
+#define _PR_MD_GETTHREADAFFINITYMASK _MD_GETTHREADAFFINITYMASK
+
+/* File locking */
+
+extern PRStatus _PR_MD_LOCKFILE(PROsfd osfd);
+#define    _PR_MD_LOCKFILE _MD_LOCKFILE
+
+extern PRStatus _PR_MD_TLOCKFILE(PROsfd osfd);
+#define    _PR_MD_TLOCKFILE _MD_TLOCKFILE
+
+extern PRStatus _PR_MD_UNLOCKFILE(PROsfd osfd);
+#define    _PR_MD_UNLOCKFILE _MD_UNLOCKFILE
+
+/* Memory-mapped files */
+
+extern PRStatus _PR_MD_CREATE_FILE_MAP(PRFileMap *fmap, PRInt64 size);
+#define _PR_MD_CREATE_FILE_MAP _MD_CREATE_FILE_MAP
+
+extern PRInt32 _PR_MD_GET_MEM_MAP_ALIGNMENT(void);
+#define _PR_MD_GET_MEM_MAP_ALIGNMENT _MD_GET_MEM_MAP_ALIGNMENT
+
+extern void * _PR_MD_MEM_MAP(
+    PRFileMap *fmap,
+    PROffset64 offset,
+    PRUint32 len);
+#define _PR_MD_MEM_MAP _MD_MEM_MAP
+
+extern PRStatus _PR_MD_MEM_UNMAP(void *addr, PRUint32 size);
+#define _PR_MD_MEM_UNMAP _MD_MEM_UNMAP
+
+extern PRStatus _PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap);
+#define _PR_MD_CLOSE_FILE_MAP _MD_CLOSE_FILE_MAP
+
+/* Named Shared Memory */
+
+/*
+** Declare PRSharedMemory.
+*/
+struct PRSharedMemory 
+{
+    char        *ipcname; /* after conversion to native */
+    PRSize      size;  /* from open */
+    PRIntn      mode;  /* from open */
+    PRIntn      flags; /* from open */
+#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY)
+    int         id;
+#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY)
+    int         id;
+#elif defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
+    HANDLE      handle;
+#else
+    PRUint32    nothing; /* placeholder, nothing behind here */
+#endif
+    PRUint32    ident; /* guard word at end of struct */
+#define _PR_SHM_IDENT 0xdeadbad
+};
+                                                      
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+    const char *name,
+    PRSize      size,
+    PRIntn      flags,
+    PRIntn      mode
+);
+#define _PR_MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags );
+#define _PR_MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr );
+#define _PR_MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm );
+#define _PR_MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name );
+#define _PR_MD_DELETE_SHARED_MEMORY  _MD_DeleteSharedMemory
+
+extern PRFileMap* _md_OpenAnonFileMap( 
+    const char *dirName,
+    PRSize      size,
+    PRFileMapProtect prot
+);
+#define _PR_MD_OPEN_ANON_FILE_MAP _md_OpenAnonFileMap
+
+extern PRStatus _md_ExportFileMapAsString(
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+);
+#define _PR_MD_EXPORT_FILE_MAP_AS_STRING _md_ExportFileMapAsString
+
+extern PRFileMap * _md_ImportFileMapFromString(
+    const char *fmstring
+);
+#define _PR_MD_IMPORT_FILE_MAP_FROM_STRING _md_ImportFileMapFromString
+
+
+
+/* Interprocess communications (IPC) */
+
+/*
+ * The maximum length of an NSPR IPC name, including the
+ * terminating null byte.
+ */
+#define PR_IPC_NAME_SIZE 1024
+
+/*
+ * Types of NSPR IPC objects
+ */
+typedef enum {
+    _PRIPCSem,  /* semaphores */
+    _PRIPCShm   /* shared memory segments */
+} _PRIPCType;
+
+/*
+ * Make a native IPC name from an NSPR IPC name.
+ */
+extern PRStatus _PR_MakeNativeIPCName(
+    const char *name,  /* NSPR IPC name */
+    char *result,      /* result buffer */
+    PRIntn size,       /* size of result buffer */
+    _PRIPCType type    /* type of IPC object */
+);
+
+/* Socket call error code */
+
+NSPR_API(PRInt32) _PR_MD_GET_SOCKET_ERROR(void);
+#define    _PR_MD_GET_SOCKET_ERROR _MD_GET_SOCKET_ERROR
+
+/* Get name of current host */
+extern PRStatus _PR_MD_GETHOSTNAME(char *name, PRUint32 namelen);
+#define    _PR_MD_GETHOSTNAME _MD_GETHOSTNAME
+
+extern PRStatus _PR_MD_GETSYSINFO(PRSysInfo cmd, char *name, PRUint32 namelen);
+#define    _PR_MD_GETSYSINFO _MD_GETSYSINFO
+
+/* File descriptor inheritance */
+
+/*
+ * If fd->secret->inheritable is _PR_TRI_UNKNOWN and we need to
+ * know the inheritable attribute of the fd, call this function
+ * to find that out.  This typically requires a system call.
+ */
+extern void _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd);
+#define    _PR_MD_QUERY_FD_INHERITABLE _MD_QUERY_FD_INHERITABLE
+
+/* --- PR_GetRandomNoise() related things --- */
+
+extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size );
+#define _PR_MD_GET_RANDOM_NOISE(buf,size) _PR_MD_GetRandomNoise((buf),(size))
+extern PRSize _pr_CopyLowBits( void *dest, PRSize dstlen, void *src, PRSize srclen );
+
+/* end PR_GetRandomNoise() related */
+
+#ifdef XP_BEOS
+
+extern PRLock *_connectLock;
+
+typedef struct _ConnectListNode {
+	PRInt32		osfd;
+	PRNetAddr	addr;
+	PRUint32	addrlen;
+	PRIntervalTime	timeout;
+} ConnectListNode;
+
+extern ConnectListNode connectList[64];
+
+extern PRUint32 connectCount;
+
+#endif /* XP_BEOS */
+
+PR_END_EXTERN_C
+
+#endif /* primpl_h___ */
diff --git a/mozilla/nsprpub/pr/include/private/prpriv.h b/mozilla/nsprpub/pr/include/private/prpriv.h
new file mode 100644
index 0000000..12a2cd6
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/private/prpriv.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prpriv_h___
+#define prpriv_h___
+
+/*
+ * NSPR 2.0 Private API
+ */
+
+#include "private/pprio.h"
+#include "private/pprthred.h"
+
+#endif /* prpriv_h___ */
diff --git a/mozilla/nsprpub/pr/include/prlink.h b/mozilla/nsprpub/pr/include/prlink.h
new file mode 100644
index 0000000..8cbcc4d
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prlink.h
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prlink_h___
+#define prlink_h___
+
+/*
+** API to static and dynamic linking.
+*/
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PRLibrary PRLibrary;
+
+typedef struct PRStaticLinkTable {
+    const char *name;
+    void (*fp)();
+} PRStaticLinkTable;
+
+/*
+** Change the default library path to the given string. The string is
+** copied. This call will fail if it runs out of memory.
+**
+** The string provided as 'path' is copied. The caller can do whatever is
+** convenient with the argument when the function is complete.
+*/
+NSPR_API(PRStatus) PR_SetLibraryPath(const char *path);
+
+/*
+** Return a character string which contains the path used to search for
+** dynamically loadable libraries.
+**
+** The returned value is basically a copy of a PR_SetLibraryPath().
+** The storage is allocated by the runtime and becomes the responsibilty
+** of the caller.
+*/
+NSPR_API(char*) PR_GetLibraryPath(void);
+
+/*
+** Given a directory name "dir" and a library name "lib" construct a full
+** path name that will refer to the actual dynamically loaded
+** library. This does not test for existance of said file, it just
+** constructs the full filename. The name constructed is system dependent
+** and prepared for PR_LoadLibrary. The result must be free'd when the
+** caller is done with it.
+**
+** The storage for the result is allocated by the runtime and becomes the
+** responsibility of the caller.
+*/
+NSPR_API(char*) PR_GetLibraryName(const char *dir, const char *lib);
+
+/*
+**
+** Free the memory allocated, for the caller, by PR_GetLibraryName
+*/
+NSPR_API(void) PR_FreeLibraryName(char *mem);
+
+/*
+** Given a library "name" try to load the library. The argument "name"
+** is a machine-dependent name for the library, such as the full pathname
+** returned by PR_GetLibraryName.  If the library is already loaded,
+** this function will avoid loading the library twice.
+**
+** If the library is loaded successfully, then a pointer to the PRLibrary
+** structure representing the library is returned.  Otherwise, NULL is
+** returned.
+**
+** This increments the reference count of the library.
+*/
+NSPR_API(PRLibrary*) PR_LoadLibrary(const char *name);
+
+/*
+** Each operating system has its preferred way of specifying
+** a file in the file system.  Most operating systems use
+** a pathname.  Mac OS Classic, on the other hand, uses the FSSpec
+** structure to specify a file. PRLibSpec allows NSPR clients
+** to use the type of file specification that is most efficient
+** for a particular platform.
+**
+** On some operating systems such as Mac OS Classic, a shared library
+** may contain code fragments that can be individually loaded.
+** PRLibSpec also allows NSPR clients to identify a code fragment
+** in a library, if code fragments are supported by the OS.
+** A code fragment can be specified by name or by an integer index.
+**
+** Right now PRLibSpec supports four types of library specification:
+** a pathname in the native character encoding, a Mac code fragment
+** by name, a Mac code fragment by index, and a UTF-16 pathname.
+*/
+
+typedef enum PRLibSpecType {
+    PR_LibSpec_Pathname,
+    PR_LibSpec_MacNamedFragment,   /* obsolete (for Mac OS Classic) */
+    PR_LibSpec_MacIndexedFragment, /* obsolete (for Mac OS Classic) */
+    PR_LibSpec_PathnameU           /* supported only on Win32 */ 
+} PRLibSpecType;
+
+struct FSSpec; /* Mac OS Classic FSSpec */
+
+typedef struct PRLibSpec {
+    PRLibSpecType type;
+    union {
+        /* if type is PR_LibSpec_Pathname */
+        const char *pathname;
+
+        /* if type is PR_LibSpec_MacNamedFragment */
+        struct {
+            const struct FSSpec *fsspec;
+            const char *name;
+        } mac_named_fragment;      /* obsolete (for Mac OS Classic) */
+
+        /* if type is PR_LibSpec_MacIndexedFragment */
+        struct {
+            const struct FSSpec *fsspec;
+            PRUint32 index;
+        } mac_indexed_fragment;    /* obsolete (for Mac OS Classic) */
+
+        /* if type is PR_LibSpec_PathnameU */
+        const PRUnichar *pathname_u; /* supported only on Win32 */
+    } value;
+} PRLibSpec;
+
+/*
+** The following bit flags may be or'd together and passed
+** as the 'flags' argument to PR_LoadLibraryWithFlags.
+** Flags not supported by the underlying OS are ignored.
+*/
+
+#define PR_LD_LAZY   0x1  /* equivalent to RTLD_LAZY on Unix */
+#define PR_LD_NOW    0x2  /* equivalent to RTLD_NOW on Unix */
+#define PR_LD_GLOBAL 0x4  /* equivalent to RTLD_GLOBAL on Unix */
+#define PR_LD_LOCAL  0x8  /* equivalent to RTLD_LOCAL on Unix */
+/* The following is equivalent to LOAD_WITH_ALTERED_SEARCH_PATH on Windows */
+#define PR_LD_ALT_SEARCH_PATH  0x10  
+/*                0x8000     reserved for NSPR internal use */
+
+/*
+** Load the specified library, in the manner specified by 'flags'.
+*/
+
+NSPR_API(PRLibrary *)
+PR_LoadLibraryWithFlags(
+    PRLibSpec libSpec,    /* the shared library */
+    PRIntn flags          /* flags that affect the loading */
+);
+
+/*
+** Unload a previously loaded library. If the library was a static
+** library then the static link table will no longer be referenced. The
+** associated PRLibrary object is freed.
+**
+** PR_FAILURE is returned if the library cannot be unloaded.
+**
+** This function decrements the reference count of the library.
+*/
+NSPR_API(PRStatus) PR_UnloadLibrary(PRLibrary *lib);
+
+/*
+** Given the name of a procedure, return the address of the function that
+** implements the procedure, or NULL if no such function can be
+** found. This does not find symbols in the main program (the ".exe");
+** use PR_LoadStaticLibrary to register symbols in the main program.
+**
+** This function does not modify the reference count of the library.
+*/
+NSPR_API(void*) PR_FindSymbol(PRLibrary *lib, const char *name);
+
+/*
+** Similar to PR_FindSymbol, except that the return value is a pointer to
+** a function, and not a pointer to void. Casting between a data pointer
+** and a function pointer is not portable according to the C standard.
+** Any function pointer can be cast to any other function pointer.
+**
+** This function does not modify the reference count of the library.
+*/
+typedef void (*PRFuncPtr)();
+NSPR_API(PRFuncPtr) PR_FindFunctionSymbol(PRLibrary *lib, const char *name);
+
+/*
+** Finds a symbol in one of the currently loaded libraries. Given the
+** name of a procedure, return the address of the function that
+** implements the procedure, and return the library that contains that
+** symbol, or NULL if no such function can be found. This does not find
+** symbols in the main program (the ".exe"); use PR_AddStaticLibrary to
+** register symbols in the main program.  
+**
+** This increments the reference count of the library.
+*/
+NSPR_API(void*) PR_FindSymbolAndLibrary(const char *name,
+						      PRLibrary* *lib);
+
+/*
+** Similar to PR_FindSymbolAndLibrary, except that the return value is
+** a pointer to a function, and not a pointer to void. Casting between a
+** data pointer and a function pointer is not portable according to the C
+** standard. Any function pointer can be cast to any other function pointer.
+**
+** This increments the reference count of the library.
+*/
+NSPR_API(PRFuncPtr) PR_FindFunctionSymbolAndLibrary(const char *name,
+						      PRLibrary* *lib);
+
+/*
+** Register a static link table with the runtime under the name
+** "name". The symbols present in the static link table will be made
+** available to PR_FindSymbol. If "name" is null then the symbols will be
+** made available to the library which represents the executable. The
+** tables are not copied.
+**
+** Returns the library object if successful, null otherwise.
+**
+** This increments the reference count of the library.
+*/
+NSPR_API(PRLibrary*) PR_LoadStaticLibrary(
+    const char *name, const PRStaticLinkTable *table);
+
+/*
+** Return the pathname of the file that the library "name" was loaded
+** from. "addr" is the address of a function defined in the library.
+**
+** The caller is responsible for freeing the result with PR_Free.
+*/
+NSPR_API(char *) PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr);
+
+PR_END_EXTERN_C
+
+#endif /* prlink_h___ */
diff --git a/mozilla/nsprpub/pr/include/prlock.h b/mozilla/nsprpub/pr/include/prlock.h
new file mode 100644
index 0000000..b270aac
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prlock.h
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:		prlock.h
+** Description:	API to basic locking functions of NSPR.
+**
+**
+** NSPR provides basic locking mechanisms for thread synchronization.  Locks 
+** are lightweight resource contention controls that prevent multiple threads 
+** from accessing something (code/data) simultaneously.
+**/
+
+#ifndef prlock_h___
+#define prlock_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+/*
+ * PRLock --
+ *
+ *     NSPR represents the lock as an opaque entity to the client of the
+ *	   API.  All routines operate on a pointer to this opaque entity.
+ */
+
+typedef struct PRLock PRLock;
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+/***********************************************************************
+** FUNCTION:    PR_NewLock
+** DESCRIPTION:
+**  Returns a pointer to a newly created opaque lock object.
+** INPUTS:      void
+** OUTPUTS:     void
+** RETURN:      PRLock*
+**   If the lock can not be created because of resource constraints, NULL
+**   is returned.
+**  
+***********************************************************************/
+NSPR_API(PRLock*) PR_NewLock(void);
+
+/***********************************************************************
+** FUNCTION:    PR_DestroyLock
+** DESCRIPTION:
+**  Destroys a given opaque lock object.
+** INPUTS:      PRLock *lock
+**              Lock to be freed.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+NSPR_API(void) PR_DestroyLock(PRLock *lock);
+
+/***********************************************************************
+** FUNCTION:    PR_Lock
+** DESCRIPTION:
+**  Lock a lock.
+** INPUTS:      PRLock *lock
+**              Lock to locked.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+NSPR_API(void) PR_Lock(PRLock *lock);
+
+/***********************************************************************
+** FUNCTION:    PR_Unlock
+** DESCRIPTION:
+**  Unlock a lock.  Unlocking an unlocked lock has undefined results.
+** INPUTS:      PRLock *lock
+**              Lock to unlocked.
+** OUTPUTS:     void
+** RETURN:      PR_STATUS
+**              Returns PR_FAILURE if the caller does not own the lock.
+***********************************************************************/
+NSPR_API(PRStatus) PR_Unlock(PRLock *lock);
+
+/***********************************************************************
+** MACRO:    PR_ASSERT_CURRENT_THREAD_OWNS_LOCK
+** DESCRIPTION:
+**  If the current thread owns |lock|, this assertion is guaranteed to
+**  succeed.  Otherwise, the behavior of this function is undefined.
+** INPUTS:      PRLock *lock
+**              Lock to assert ownership of.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
+#define PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(/* PrLock* */ lock) \
+    PR_AssertCurrentThreadOwnsLock(lock)
+#else
+#define PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(/* PrLock* */ lock)
+#endif
+
+/* Don't call this function directly. */
+NSPR_API(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock);
+
+PR_END_EXTERN_C
+
+#endif /* prlock_h___ */
diff --git a/mozilla/nsprpub/pr/include/prlog.h b/mozilla/nsprpub/pr/include/prlog.h
new file mode 100644
index 0000000..c5f6c62
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prlog.h
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prlog_h___
+#define prlog_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** prlog.h -- Declare interfaces to NSPR's Logging service
+**
+** NSPR provides a logging service that is used by NSPR itself and is
+** available to client programs.
+**
+** To use the service from a client program, you should create a
+** PRLogModuleInfo structure by calling PR_NewLogModule(). After
+** creating the LogModule, you can write to the log using the PR_LOG()
+** macro.
+**
+** Initialization of the log service is handled by NSPR initialization.
+**
+** At execution time, you must enable the log service. To enable the
+** log service, set the environment variable: NSPR_LOG_MODULES
+** variable.
+**
+** NSPR_LOG_MODULES variable has the form:
+**
+**     <moduleName>:<value>[, <moduleName>:<value>]*
+**
+** Where:
+**  <moduleName> is the name passed to PR_NewLogModule().
+**  <value> is a numeric constant, e.g. 5. This value is the maximum
+** value of a log event, enumerated by PRLogModuleLevel, that you want
+** written to the log.
+** 
+** For example: to record all events of greater value than or equal to
+** PR_LOG_ERROR for a LogModule names "gizmo", say:
+** 
+** set NSPR_LOG_MODULES=gizmo:2
+** 
+** Note that you must specify the numeric value of PR_LOG_ERROR.
+** 
+** Special LogModule names are provided for controlling NSPR's log
+** service at execution time. These controls should be set in the
+** NSPR_LOG_MODULES environment variable at execution time to affect
+** NSPR's log service for your application.
+** 
+** The special LogModule "all" enables all LogModules. To enable all
+** LogModule calls to PR_LOG(), say:
+** 
+** set NSPR_LOG_MODULES=all:5
+** 
+** The special LogModule name "sync" tells the NSPR log service to do
+** unbuffered logging.
+** 
+** The special LogModule name "bufsize:<size>" tells NSPR to set the
+** log buffer to <size>.
+**
+** The environment variable NSPR_LOG_FILE specifies the log file to use
+** unless the default of "stderr" is acceptable. For MS Windows
+** systems, NSPR_LOG_FILE can be set to a special value: "WinDebug"
+** (case sensitive). This value causes PR_LOG() output to be written
+** using the Windows API OutputDebugString(). OutputDebugString()
+** writes to the debugger window; some people find this helpful.
+** 
+**
+** To put log messages in your programs, use the PR_LOG macro:
+**
+**     PR_LOG(<module>, <level>, (<printfString>, <args>*));
+**
+** Where <module> is the address of a PRLogModuleInfo structure, and
+** <level> is one of the levels defined by the enumeration:
+** PRLogModuleLevel. <args> is a printf() style of argument list. That
+** is: (fmtstring, ...).
+**
+** Example:
+** 
+** main() {
+**    PRIntn one = 1;
+**    PRLogModuleInfo * myLm = PR_NewLogModule("gizmo");
+**    PR_LOG( myLm, PR_LOG_ALWAYS, ("Log this! %d\n", one)); 
+**    return; 
+** }
+** 
+** Note the use of printf() style arguments as the third agrument(s) to
+** PR_LOG().
+** 
+** After compiling and linking you application, set the environment:
+** 
+** set NSPR_LOG_MODULES=gizmo:5
+** set NSPR_LOG_FILE=logfile.txt
+** 
+** When you execute your application, the string "Log this! 1" will be
+** written to the file "logfile.txt".
+** 
+** Note to NSPR engineers: a number of PRLogModuleInfo structures are
+** defined and initialized in prinit.c. See this module for ideas on
+** what to log where.
+** 
+*/
+
+typedef enum PRLogModuleLevel {
+    PR_LOG_NONE = 0,                /* nothing */
+    PR_LOG_ALWAYS = 1,              /* always printed */
+    PR_LOG_ERROR = 2,               /* error messages */
+    PR_LOG_WARNING = 3,             /* warning messages */
+    PR_LOG_DEBUG = 4,               /* debug messages */
+
+    PR_LOG_NOTICE = PR_LOG_DEBUG,   /* notice messages */
+    PR_LOG_WARN = PR_LOG_WARNING,   /* warning messages */
+    PR_LOG_MIN = PR_LOG_DEBUG,      /* minimal debugging messages */
+    PR_LOG_MAX = PR_LOG_DEBUG       /* maximal debugging messages */
+} PRLogModuleLevel;
+
+/*
+** One of these structures is created for each module that uses logging.
+**    "name" is the name of the module
+**    "level" is the debugging level selected for that module
+*/
+typedef struct PRLogModuleInfo {
+    const char *name;
+    PRLogModuleLevel level;
+    struct PRLogModuleInfo *next;
+} PRLogModuleInfo;
+
+/*
+** Create a new log module.
+*/
+NSPR_API(PRLogModuleInfo*) PR_NewLogModule(const char *name);
+
+/*
+** Set the file to use for logging. Returns PR_FALSE if the file cannot
+** be created
+*/
+NSPR_API(PRBool) PR_SetLogFile(const char *name);
+
+/*
+** Set the size of the logging buffer. If "buffer_size" is zero then the
+** logging becomes "synchronous" (or unbuffered).
+*/
+NSPR_API(void) PR_SetLogBuffering(PRIntn buffer_size);
+
+/*
+** Print a string to the log. "fmt" is a PR_snprintf format type. All
+** messages printed to the log are preceeded by the name of the thread
+** and a time stamp. Also, the routine provides a missing newline if one
+** is not provided.
+*/
+NSPR_API(void) PR_LogPrint(const char *fmt, ...);
+
+/*
+** Flush the log to its file.
+*/
+NSPR_API(void) PR_LogFlush(void);
+
+NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln);
+
+#if defined(DEBUG) || defined(FORCE_PR_LOG)
+#define PR_LOGGING 1
+
+#define PR_LOG_TEST(_module,_level) \
+    ((_module)->level >= (_level))
+
+/*
+** Log something.
+**    "module" is the address of a PRLogModuleInfo structure
+**    "level" is the desired logging level
+**    "args" is a variable length list of arguments to print, in the following
+**       format:  ("printf style format string", ...)
+*/
+#define PR_LOG(_module,_level,_args)     \
+    PR_BEGIN_MACRO             \
+      if (PR_LOG_TEST(_module,_level)) { \
+      PR_LogPrint _args;         \
+      }                     \
+    PR_END_MACRO
+
+#else /* defined(DEBUG) || defined(FORCE_PR_LOG) */
+
+#undef PR_LOGGING
+#define PR_LOG_TEST(module,level) 0
+#define PR_LOG(module,level,args)
+
+#endif /* defined(DEBUG) || defined(FORCE_PR_LOG) */
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#ifdef PR_LOGGING
+#define PR_LOG_BEGIN    PR_LOG
+#define PR_LOG_END      PR_LOG
+#define PR_LOG_DEFINE   PR_NewLogModule
+#else
+#define PR_LOG_BEGIN(module,level,args)
+#define PR_LOG_END(module,level,args)
+#define PR_LOG_DEFINE(_name)    NULL
+#endif /* PR_LOGGING */
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
+
+#define PR_ASSERT(_expr) \
+    ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__))
+
+#define PR_NOT_REACHED(_reasonStr) \
+    PR_Assert(_reasonStr,__FILE__,__LINE__)
+
+#else
+
+#define PR_ASSERT(expr) ((void) 0)
+#define PR_NOT_REACHED(reasonStr)
+
+#endif /* defined(DEBUG) || defined(FORCE_PR_ASSERT) */
+
+/*
+** Compile-time assert. "condition" must be a constant expression.
+** The macro can be used only in places where an "extern" declaration is
+** allowed.
+*/
+#define PR_STATIC_ASSERT(condition) \
+    extern void pr_static_assert(int arg[(condition) ? 1 : -1])
+
+PR_END_EXTERN_C
+
+#endif /* prlog_h___ */
diff --git a/mozilla/nsprpub/pr/include/prlong.h b/mozilla/nsprpub/pr/include/prlong.h
new file mode 100644
index 0000000..9523d30
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prlong.h
@@ -0,0 +1,435 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:                prlong.h
+** Description: Portable access to 64 bit numerics
+**
+** Long-long (64-bit signed integer type) support. Some C compilers
+** don't support 64 bit integers yet, so we use these macros to
+** support both machines that do and don't.
+**/
+#ifndef prlong_h___
+#define prlong_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/***********************************************************************
+** DEFINES:     LL_MaxInt
+**              LL_MinInt
+**              LL_Zero
+**              LL_MaxUint
+** DESCRIPTION:
+**      Various interesting constants and static variable
+**      initializer
+***********************************************************************/
+NSPR_API(PRInt64) LL_MaxInt(void);
+NSPR_API(PRInt64) LL_MinInt(void);
+NSPR_API(PRInt64) LL_Zero(void);
+NSPR_API(PRUint64) LL_MaxUint(void);
+
+#if defined(HAVE_LONG_LONG)
+
+/* Keep this in sync with prtypes.h. */
+#if PR_BYTES_PER_LONG == 8 && !defined(__APPLE__)
+#define LL_MAXINT   9223372036854775807L
+#define LL_MININT   (-LL_MAXINT - 1L)
+#define LL_ZERO     0L
+#define LL_MAXUINT  18446744073709551615UL
+#define LL_INIT(hi, lo)  ((hi ## L << 32) + lo ## L)
+#elif defined(WIN32) && !defined(__GNUC__)
+#define LL_MAXINT   9223372036854775807i64
+#define LL_MININT   (-LL_MAXINT - 1i64)
+#define LL_ZERO     0i64
+#define LL_MAXUINT  18446744073709551615ui64
+#define LL_INIT(hi, lo)  ((hi ## i64 << 32) + lo ## i64)
+#else
+#define LL_MAXINT   9223372036854775807LL
+#define LL_MININT   (-LL_MAXINT - 1LL)
+#define LL_ZERO     0LL
+#define LL_MAXUINT  18446744073709551615ULL
+#define LL_INIT(hi, lo)  ((hi ## LL << 32) + lo ## LL)
+#endif
+
+/***********************************************************************
+** MACROS:      LL_*
+** DESCRIPTION:
+**      The following macros define portable access to the 64 bit
+**      math facilities.
+**
+***********************************************************************/
+
+/***********************************************************************
+** MACROS:      LL_<relational operators>
+**
+**  LL_IS_ZERO        Test for zero
+**  LL_EQ             Test for equality
+**  LL_NE             Test for inequality
+**  LL_GE_ZERO        Test for zero or positive
+**  LL_CMP            Compare two values
+***********************************************************************/
+#define LL_IS_ZERO(a)       ((a) == 0)
+#define LL_EQ(a, b)         ((a) == (b))
+#define LL_NE(a, b)         ((a) != (b))
+#define LL_GE_ZERO(a)       ((a) >= 0)
+#define LL_CMP(a, op, b)    ((PRInt64)(a) op (PRInt64)(b))
+#define LL_UCMP(a, op, b)   ((PRUint64)(a) op (PRUint64)(b))
+
+/***********************************************************************
+** MACROS:      LL_<logical operators>
+**
+**  LL_AND            Logical and
+**  LL_OR             Logical or
+**  LL_XOR            Logical exclusion
+**  LL_OR2            A disgusting deviation
+**  LL_NOT            Negation (one's complement)
+***********************************************************************/
+#define LL_AND(r, a, b)        ((r) = (a) & (b))
+#define LL_OR(r, a, b)        ((r) = (a) | (b))
+#define LL_XOR(r, a, b)        ((r) = (a) ^ (b))
+#define LL_OR2(r, a)        ((r) = (r) | (a))
+#define LL_NOT(r, a)        ((r) = ~(a))
+
+/***********************************************************************
+** MACROS:      LL_<mathematical operators>
+**
+**  LL_NEG            Negation (two's complement)
+**  LL_ADD            Summation (two's complement)
+**  LL_SUB            Difference (two's complement)
+***********************************************************************/
+#define LL_NEG(r, a)        ((r) = -(a))
+#define LL_ADD(r, a, b)     ((r) = (a) + (b))
+#define LL_SUB(r, a, b)     ((r) = (a) - (b))
+
+/***********************************************************************
+** MACROS:      LL_<mathematical operators>
+**
+**  LL_MUL            Product (two's complement)
+**  LL_DIV            Quotient (two's complement)
+**  LL_MOD            Modulus (two's complement)
+***********************************************************************/
+#define LL_MUL(r, a, b)        ((r) = (a) * (b))
+#define LL_DIV(r, a, b)        ((r) = (a) / (b))
+#define LL_MOD(r, a, b)        ((r) = (a) % (b))
+
+/***********************************************************************
+** MACROS:      LL_<shifting operators>
+**
+**  LL_SHL            Shift left [0..64] bits
+**  LL_SHR            Shift right [0..64] bits with sign extension
+**  LL_USHR           Unsigned shift right [0..64] bits
+**  LL_ISHL           Signed shift left [0..64] bits
+***********************************************************************/
+#define LL_SHL(r, a, b)     ((r) = (PRInt64)(a) << (b))
+#define LL_SHR(r, a, b)     ((r) = (PRInt64)(a) >> (b))
+#define LL_USHR(r, a, b)    ((r) = (PRUint64)(a) >> (b))
+#define LL_ISHL(r, a, b)    ((r) = (PRInt64)(a) << (b))
+
+/***********************************************************************
+** MACROS:      LL_<conversion operators>
+**
+**  LL_L2I            Convert to signed 32 bit
+**  LL_L2UI           Convert to unsigned 32 bit
+**  LL_L2F            Convert to floating point
+**  LL_L2D            Convert to floating point
+**  LL_I2L            Convert signed to 64 bit
+**  LL_UI2L           Convert unsigned to 64 bit
+**  LL_F2L            Convert float to 64 bit
+**  LL_D2L            Convert float to 64 bit
+***********************************************************************/
+#define LL_L2I(i, l)        ((i) = (PRInt32)(l))
+#define LL_L2UI(ui, l)        ((ui) = (PRUint32)(l))
+#define LL_L2F(f, l)        ((f) = (PRFloat64)(l))
+#define LL_L2D(d, l)        ((d) = (PRFloat64)(l))
+
+#define LL_I2L(l, i)        ((l) = (PRInt64)(i))
+#define LL_UI2L(l, ui)        ((l) = (PRInt64)(ui))
+#define LL_F2L(l, f)        ((l) = (PRInt64)(f))
+#define LL_D2L(l, d)        ((l) = (PRInt64)(d))
+
+/***********************************************************************
+** MACROS:      LL_UDIVMOD
+** DESCRIPTION:
+**  Produce both a quotient and a remainder given an unsigned 
+** INPUTS:      PRUint64 a: The dividend of the operation
+**              PRUint64 b: The quotient of the operation
+** OUTPUTS:     PRUint64 *qp: pointer to quotient
+**              PRUint64 *rp: pointer to remainder
+***********************************************************************/
+#define LL_UDIVMOD(qp, rp, a, b) \
+    (*(qp) = ((PRUint64)(a) / (b)), \
+     *(rp) = ((PRUint64)(a) % (b)))
+
+#else  /* !HAVE_LONG_LONG */
+
+#define LL_MAXINT   LL_MaxInt()
+#define LL_MININT   LL_MinInt()
+#define LL_ZERO     LL_Zero()
+#define LL_MAXUINT  LL_MaxUint()
+
+#ifdef IS_LITTLE_ENDIAN
+#define LL_INIT(hi, lo) {PR_UINT32(lo), PR_UINT32(hi)}
+#else
+#define LL_INIT(hi, lo) {PR_UINT32(hi), PR_UINT32(lo)}
+#endif
+
+#define LL_IS_ZERO(a)        (((a).hi == 0) && ((a).lo == 0))
+#define LL_EQ(a, b)        (((a).hi == (b).hi) && ((a).lo == (b).lo))
+#define LL_NE(a, b)        (((a).hi != (b).hi) || ((a).lo != (b).lo))
+#define LL_GE_ZERO(a)        (((a).hi >> 31) == 0)
+
+#define LL_CMP(a, op, b)    (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \
+                 ((PRInt32)(a).hi op (PRInt32)(b).hi))
+#define LL_UCMP(a, op, b)    (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \
+                 ((a).hi op (b).hi))
+
+#define LL_AND(r, a, b)        ((r).lo = (a).lo & (b).lo, \
+                 (r).hi = (a).hi & (b).hi)
+#define LL_OR(r, a, b)        ((r).lo = (a).lo | (b).lo, \
+                 (r).hi = (a).hi | (b).hi)
+#define LL_XOR(r, a, b)        ((r).lo = (a).lo ^ (b).lo, \
+                 (r).hi = (a).hi ^ (b).hi)
+#define LL_OR2(r, a)        ((r).lo = (r).lo | (a).lo, \
+                 (r).hi = (r).hi | (a).hi)
+#define LL_NOT(r, a)        ((r).lo = ~(a).lo, \
+                 (r).hi = ~(a).hi)
+
+#define LL_NEG(r, a)        ((r).lo = -(PRInt32)(a).lo, \
+                 (r).hi = -(PRInt32)(a).hi - ((r).lo != 0))
+#define LL_ADD(r, a, b) { \
+    PRInt64 _a, _b; \
+    _a = a; _b = b; \
+    (r).lo = _a.lo + _b.lo; \
+    (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \
+}
+
+#define LL_SUB(r, a, b) { \
+    PRInt64 _a, _b; \
+    _a = a; _b = b; \
+    (r).lo = _a.lo - _b.lo; \
+    (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \
+}
+
+#define LL_MUL(r, a, b) { \
+    PRInt64 _a, _b; \
+    _a = a; _b = b; \
+    LL_MUL32(r, _a.lo, _b.lo); \
+    (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \
+}
+
+#define _lo16(a)        ((a) & PR_BITMASK(16))
+#define _hi16(a)        ((a) >> 16)
+
+#define LL_MUL32(r, a, b) { \
+     PRUint32 _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \
+     _a1 = _hi16(a), _a0 = _lo16(a); \
+     _b1 = _hi16(b), _b0 = _lo16(b); \
+     _y0 = _a0 * _b0; \
+     _y1 = _a0 * _b1; \
+     _y2 = _a1 * _b0; \
+     _y3 = _a1 * _b1; \
+     _y1 += _hi16(_y0);                         /* can't carry */ \
+     _y1 += _y2;                                /* might carry */ \
+     if (_y1 < _y2)    \
+        _y3 += (PRUint32)(PR_BIT(16));  /* propagate */ \
+     (r).lo = (_lo16(_y1) << 16) + _lo16(_y0); \
+     (r).hi = _y3 + _hi16(_y1); \
+}
+
+#define LL_UDIVMOD(qp, rp, a, b)    ll_udivmod(qp, rp, a, b)
+
+NSPR_API(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b);
+
+#define LL_DIV(r, a, b) { \
+    PRInt64 _a, _b; \
+    PRUint32 _negative = (PRInt32)(a).hi < 0; \
+    if (_negative) { \
+    LL_NEG(_a, a); \
+    } else { \
+    _a = a; \
+    } \
+    if ((PRInt32)(b).hi < 0) { \
+    _negative ^= 1; \
+    LL_NEG(_b, b); \
+    } else { \
+    _b = b; \
+    } \
+    LL_UDIVMOD(&(r), 0, _a, _b); \
+    if (_negative) \
+    LL_NEG(r, r); \
+}
+
+#define LL_MOD(r, a, b) { \
+    PRInt64 _a, _b; \
+    PRUint32 _negative = (PRInt32)(a).hi < 0; \
+    if (_negative) { \
+    LL_NEG(_a, a); \
+    } else { \
+    _a = a; \
+    } \
+    if ((PRInt32)(b).hi < 0) { \
+    LL_NEG(_b, b); \
+    } else { \
+    _b = b; \
+    } \
+    LL_UDIVMOD(0, &(r), _a, _b); \
+    if (_negative) \
+    LL_NEG(r, r); \
+}
+
+#define LL_SHL(r, a, b) { \
+    if (b) { \
+    PRInt64 _a; \
+        _a = a; \
+        if ((b) < 32) { \
+        (r).lo = _a.lo << ((b) & 31); \
+        (r).hi = (_a.hi << ((b) & 31)) | (_a.lo >> (32 - (b))); \
+    } else { \
+        (r).lo = 0; \
+        (r).hi = _a.lo << ((b) & 31); \
+    } \
+    } else { \
+    (r) = (a); \
+    } \
+}
+
+/* a is an PRInt32, b is PRInt32, r is PRInt64 */
+#define LL_ISHL(r, a, b) { \
+    if (b) { \
+    PRInt64 _a; \
+    _a.lo = (a); \
+    _a.hi = 0; \
+        if ((b) < 32) { \
+        (r).lo = (a) << ((b) & 31); \
+        (r).hi = ((a) >> (32 - (b))); \
+    } else { \
+        (r).lo = 0; \
+        (r).hi = (a) << ((b) & 31); \
+    } \
+    } else { \
+    (r).lo = (a); \
+    (r).hi = 0; \
+    } \
+}
+
+#define LL_SHR(r, a, b) { \
+    if (b) { \
+    PRInt64 _a; \
+        _a = a; \
+    if ((b) < 32) { \
+        (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \
+        (r).hi = (PRInt32)_a.hi >> ((b) & 31); \
+    } else { \
+        (r).lo = (PRInt32)_a.hi >> ((b) & 31); \
+        (r).hi = (PRInt32)_a.hi >> 31; \
+    } \
+    } else { \
+    (r) = (a); \
+    } \
+}
+
+#define LL_USHR(r, a, b) { \
+    if (b) { \
+    PRInt64 _a; \
+        _a = a; \
+    if ((b) < 32) { \
+        (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \
+        (r).hi = _a.hi >> ((b) & 31); \
+    } else { \
+        (r).lo = _a.hi >> ((b) & 31); \
+        (r).hi = 0; \
+    } \
+    } else { \
+    (r) = (a); \
+    } \
+}
+
+#define LL_L2I(i, l)        ((i) = (l).lo)
+#define LL_L2UI(ui, l)        ((ui) = (l).lo)
+#define LL_L2F(f, l)        { double _d; LL_L2D(_d, l); (f) = (PRFloat64)_d; }
+
+#define LL_L2D(d, l) { \
+    int _negative; \
+    PRInt64 _absval; \
+ \
+    _negative = (l).hi >> 31; \
+    if (_negative) { \
+    LL_NEG(_absval, l); \
+    } else { \
+    _absval = l; \
+    } \
+    (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \
+    if (_negative) \
+    (d) = -(d); \
+}
+
+#define LL_I2L(l, i)        { PRInt32 _i = ((PRInt32)(i)) >> 31; (l).lo = (i); (l).hi = _i; }
+#define LL_UI2L(l, ui)      ((l).lo = (ui), (l).hi = 0)
+#define LL_F2L(l, f)        { double _d = (double)f; LL_D2L(l, _d); }
+
+#define LL_D2L(l, d) { \
+    int _negative; \
+    double _absval, _d_hi; \
+    PRInt64 _lo_d; \
+ \
+    _negative = ((d) < 0); \
+    _absval = _negative ? -(d) : (d); \
+ \
+    (l).hi = _absval / 4.294967296e9; \
+    (l).lo = 0; \
+    LL_L2D(_d_hi, l); \
+    _absval -= _d_hi; \
+    _lo_d.hi = 0; \
+    if (_absval < 0) { \
+    _lo_d.lo = -_absval; \
+    LL_SUB(l, l, _lo_d); \
+    } else { \
+    _lo_d.lo = _absval; \
+    LL_ADD(l, l, _lo_d); \
+    } \
+ \
+    if (_negative) \
+    LL_NEG(l, l); \
+}
+
+#endif /* !HAVE_LONG_LONG */
+
+PR_END_EXTERN_C
+
+#endif /* prlong_h___ */
diff --git a/mozilla/nsprpub/pr/include/prmem.h b/mozilla/nsprpub/pr/include/prmem.h
new file mode 100644
index 0000000..1cf0949
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prmem.h
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File: prmem.h
+** Description: API to NSPR memory management functions
+**
+*/
+#ifndef prmem_h___
+#define prmem_h___
+
+#include "prtypes.h"
+#include <stdlib.h>
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Thread safe memory allocation.
+**
+** NOTE: pr wraps up malloc, free, calloc, realloc so they are already
+** thread safe (and are not declared here - look in stdlib.h).
+*/
+
+/*
+** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free have the same signatures
+** as their libc equivalent malloc, calloc, realloc, and free, and have
+** the same semantics.  (Note that the argument type size_t is replaced
+** by PRUint32.)  Memory allocated by PR_Malloc, PR_Calloc, or PR_Realloc
+** must be freed by PR_Free.
+*/
+
+NSPR_API(void *) PR_Malloc(PRUint32 size);
+
+NSPR_API(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize);
+
+NSPR_API(void *) PR_Realloc(void *ptr, PRUint32 size);
+
+NSPR_API(void) PR_Free(void *ptr);
+
+/*
+** The following are some convenience macros defined in terms of
+** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free.
+*/
+
+/***********************************************************************
+** FUNCTION:	PR_MALLOC()
+** DESCRIPTION:
+**   PR_NEW() allocates an untyped item of size _size from the heap.
+** INPUTS:  _size: size in bytes of item to be allocated
+** OUTPUTS:	untyped pointer to the node allocated
+** RETURN:	pointer to node or error returned from malloc().
+***********************************************************************/
+#define PR_MALLOC(_bytes) (PR_Malloc((_bytes)))
+
+/***********************************************************************
+** FUNCTION:	PR_NEW()
+** DESCRIPTION:
+**   PR_NEW() allocates an item of type _struct from the heap.
+** INPUTS:  _struct: a data type
+** OUTPUTS:	pointer to _struct
+** RETURN:	pointer to _struct or error returns from malloc().
+***********************************************************************/
+#define PR_NEW(_struct) ((_struct *) PR_MALLOC(sizeof(_struct)))
+
+/***********************************************************************
+** FUNCTION:	PR_REALLOC()
+** DESCRIPTION:
+**   PR_REALLOC() re-allocates _ptr bytes from the heap as a _size
+**   untyped item.
+** INPUTS:	_ptr: pointer to node to reallocate
+**          _size: size of node to allocate
+** OUTPUTS:	pointer to node allocated
+** RETURN:	pointer to node allocated
+***********************************************************************/
+#define PR_REALLOC(_ptr, _size) (PR_Realloc((_ptr), (_size)))
+
+/***********************************************************************
+** FUNCTION:	PR_CALLOC()
+** DESCRIPTION:
+**   PR_CALLOC() allocates a _size bytes untyped item from the heap
+**   and sets the allocated memory to all 0x00.
+** INPUTS:	_size: size of node to allocate
+** OUTPUTS:	pointer to node allocated
+** RETURN:	pointer to node allocated
+***********************************************************************/
+#define PR_CALLOC(_size) (PR_Calloc(1, (_size)))
+
+/***********************************************************************
+** FUNCTION:	PR_NEWZAP()
+** DESCRIPTION:
+**   PR_NEWZAP() allocates an item of type _struct from the heap
+**   and sets the allocated memory to all 0x00.
+** INPUTS:	_struct: a data type
+** OUTPUTS:	pointer to _struct
+** RETURN:	pointer to _struct
+***********************************************************************/
+#define PR_NEWZAP(_struct) ((_struct*)PR_Calloc(1, sizeof(_struct)))
+
+/***********************************************************************
+** FUNCTION:	PR_DELETE()
+** DESCRIPTION:
+**   PR_DELETE() unallocates an object previosly allocated via PR_NEW()
+**   or PR_NEWZAP() to the heap.
+** INPUTS:	pointer to previously allocated object
+** OUTPUTS:	the referenced object is returned to the heap
+** RETURN:	void
+***********************************************************************/
+#define PR_DELETE(_ptr) { PR_Free(_ptr); (_ptr) = NULL; }
+
+/***********************************************************************
+** FUNCTION:	PR_FREEIF()
+** DESCRIPTION:
+**   PR_FREEIF() conditionally unallocates an object previously allocated
+**   vial PR_NEW() or PR_NEWZAP(). If the pointer to the object is
+**   equal to zero (0), the object is not released.
+** INPUTS:	pointer to previously allocated object
+** OUTPUTS:	the referenced object is conditionally returned to the heap
+** RETURN:	void
+***********************************************************************/
+#define PR_FREEIF(_ptr)	if (_ptr) PR_DELETE(_ptr)
+
+PR_END_EXTERN_C
+
+#endif /* prmem_h___ */
diff --git a/mozilla/nsprpub/pr/include/prmon.h b/mozilla/nsprpub/pr/include/prmon.h
new file mode 100644
index 0000000..0fe18dc
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prmon.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prmon_h___
+#define prmon_h___
+
+#include "prtypes.h"
+#include "prinrval.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PRMonitor PRMonitor;
+
+/*
+** Create a new monitor. Monitors are re-entrant locks with a single built-in
+** condition variable.
+**
+** This may fail if memory is tight or if some operating system resource
+** is low.
+*/
+NSPR_API(PRMonitor*) PR_NewMonitor(void);
+
+/*
+** Destroy a monitor. The caller is responsible for guaranteeing that the
+** monitor is no longer in use. There must be no thread waiting on the monitor's
+** condition variable and that the lock is not held.
+**
+*/
+NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon);
+
+/*
+** Enter the lock associated with the monitor. If the calling thread currently
+** is in the monitor, the call to enter will silently succeed. In either case,
+** it will increment the entry count by one.
+*/
+NSPR_API(void) PR_EnterMonitor(PRMonitor *mon);
+
+/*
+** Decrement the entry count associated with the monitor. If the decremented
+** entry count is zero, the monitor is exited. Returns PR_FAILURE if the
+** calling thread has not entered the monitor.
+*/
+NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon);
+
+/*
+** Wait for a notify on the monitor's condition variable. Sleep for "ticks"
+** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is
+** indefinite).
+**
+** While the thread is waiting it exits the monitor (as if it called
+** PR_ExitMonitor as many times as it had called PR_EnterMonitor).  When
+** the wait has finished the thread regains control of the monitors lock
+** with the same entry count as before the wait began.
+**
+** The thread waiting on the monitor will be resumed when the monitor is
+** notified (assuming the thread is the next in line to receive the
+** notify) or when the "ticks" timeout elapses.
+**
+** Returns PR_FAILURE if the caller has not entered the monitor.
+*/
+NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks);
+
+/*
+** Notify a thread waiting on the monitor's condition variable. If a thread
+** is waiting on the condition variable (using PR_Wait) then it is awakened
+** and attempts to reenter the monitor.
+*/
+NSPR_API(PRStatus) PR_Notify(PRMonitor *mon);
+
+/*
+** Notify all of the threads waiting on the monitor's condition variable.
+** All of threads waiting on the condition are scheduled to reenter the
+** monitor.
+*/
+NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon);
+
+/*
+** PR_ASSERT_CURRENT_THREAD_IN_MONITOR
+** If the current thread is in |mon|, this assertion is guaranteed to
+** succeed.  Otherwise, the behavior of this function is undefined.
+*/
+#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
+#define PR_ASSERT_CURRENT_THREAD_IN_MONITOR(/* PRMonitor* */ mon) \
+    PR_AssertCurrentThreadInMonitor(mon)
+#else
+#define PR_ASSERT_CURRENT_THREAD_IN_MONITOR(/* PRMonitor* */ mon)
+#endif
+
+/* Don't call this function directly. */
+NSPR_API(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon);
+
+PR_END_EXTERN_C
+
+#endif /* prmon_h___ */
diff --git a/mozilla/nsprpub/pr/include/prmwait.h b/mozilla/nsprpub/pr/include/prmwait.h
new file mode 100644
index 0000000..e4cabda
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prmwait.h
@@ -0,0 +1,412 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#if defined(_PRMWAIT_H)
+#else
+#define _PRMWAIT_H
+
+#include "prio.h"
+#include "prtypes.h"
+#include "prclist.h"
+
+PR_BEGIN_EXTERN_C
+
+/********************************************************************************/
+/********************************************************************************/
+/********************************************************************************/
+/******************************       WARNING        ****************************/
+/********************************************************************************/
+/**************************** This is work in progress. *************************/
+/************************** Do not make any assumptions *************************/
+/************************** about the stability of this *************************/
+/************************** API or the underlying imple- ************************/
+/************************** mentation.                   ************************/
+/********************************************************************************/
+/********************************************************************************/
+
+/*
+** STRUCTURE:   PRWaitGroup
+** DESCRIPTION:
+**      The client may define several wait groups in order to semantically
+**      tie a collection of file descriptors for a single purpose. This allows
+**      easier dispatching of threads that returned with active file descriptors
+**      from the wait function.
+*/
+typedef struct PRWaitGroup PRWaitGroup;
+
+/*
+** ENUMERATION: PRMWStatus
+** DESCRIPTION:
+**      This enumeration is used to indicate the completion status of
+**      a receive wait object. Generally stated, a positive value indicates
+**      that the operation is not yet complete. A zero value indicates
+**      success (similar to PR_SUCCESS) and any negative value is an
+**      indication of failure. The reason for the failure can be retrieved
+**      by calling PR_GetError().
+**
+**  PR_MW_PENDING       The operation is still pending. None of the other
+**                      fields of the object are currently valid.
+**  PR_MW_SUCCESS       The operation is complete and it was successful.
+**  PR_MW_FAILURE       The operation failed. The reason for the failure
+**                      can be retrieved by calling PR_GetError().
+**  PR_MW_TIMEOUT       The amount of time allowed for by the object's
+**                      'timeout' field has expired w/o the operation
+**                      otherwise coming to closure.
+**  PR_MW_INTERRUPT     The operation was cancelled, either by the client
+**                      calling PR_CancelWaitFileDesc() or destroying the
+**                      entire wait group (PR_DestroyWaitGroup()).
+*/
+typedef enum PRMWStatus
+{
+    PR_MW_PENDING = 1,
+    PR_MW_SUCCESS = 0,
+    PR_MW_FAILURE = -1,
+    PR_MW_TIMEOUT = -2,
+    PR_MW_INTERRUPT = -3
+} PRMWStatus;
+
+/*
+** STRUCTURE:   PRMemoryDescriptor
+** DESCRIPTION:
+**      THis is a descriptor for an interval of memory. It contains a
+**      pointer to the first byte of that memory and the length (in
+**      bytes) of the interval.
+*/
+typedef struct PRMemoryDescriptor
+{
+    void *start;                /* pointer to first byte of memory */
+    PRSize length;              /* length (in bytes) of memory interval */
+} PRMemoryDescriptor;
+
+/*
+** STRUCTURE:   PRMWaitClientData
+** DESCRIPTION:
+**      An opague stucture for which a client MAY give provide a concrete
+**      definition and associate with a receive descriptor. The NSPR runtime
+**      does not manage this field. It is completely up to the client.
+*/
+typedef struct PRMWaitClientData PRMWaitClientData;
+
+/*
+** STRUCTURE:   PRRecvWait
+** DESCRIPTION:
+**      A receive wait object contains the file descriptor that is subject
+**      to the wait and the amount of time (beginning epoch established
+**      when the object is presented to the runtime) the the channel should
+**      block before abandoning the process.
+**
+**      The success of the wait operation will be noted in the object's
+**      'outcome' field. The fields are not valid when the NSPR runtime
+**      is in possession of the object.
+**
+**      The memory descriptor describes an interval of writable memory
+**      in the caller's address space where data from an initial read
+**      can be placed. The description may indicate a null interval.
+*/
+typedef struct PRRecvWait 
+{
+    PRCList internal;           /* internal runtime linkages */
+
+    PRFileDesc *fd;             /* file descriptor associated w/ object */
+    PRMWStatus outcome;         /* outcome of the current/last operation */
+    PRIntervalTime timeout;     /* time allowed for entire operation */
+
+    PRInt32 bytesRecv;          /* number of bytes transferred into buffer */
+    PRMemoryDescriptor buffer;  /* where to store first segment of input data */
+    PRMWaitClientData *client;  /* pointer to arbitrary client defined data */
+} PRRecvWait;
+
+/*
+** STRUCTURE:   PRMWaitEnumerator
+** DESCRIPTION:
+**      An enumeration object is used to store the state of an existing
+**      enumeration over a wait group. The opaque object must be allocated
+**      by the client and the reference presented on each call to the
+**      pseudo-stateless enumerator. The enumeration objects are sharable
+**      only in serial fashion.
+*/
+typedef struct PRMWaitEnumerator PRMWaitEnumerator;
+
+
+/*
+** FUNCTION:    PR_AddWaitFileDesc
+** DESCRIPTION:
+**      This function will effectively add a file descriptor to the
+**      list of those waiting for network receive. The new descriptor
+**      will be semantically tied to the wait group specified.
+**
+**      The ownership for the storage pointed to by 'desc' is temporarily
+**      passed over the the NSPR runtime. It will be handed back by the
+**      function PR_WaitRecvReady().
+**
+**  INPUTS
+**      group       A reference to a PRWaitGroup or NULL. Wait groups are
+**                  created by calling PR_CreateWaitGroup() and are used
+**                  to semantically group various file descriptors by the
+**                  client's application.
+**      desc        A reference to a valid PRRecvWait. The object of the
+**                  reference must be preserved and not be modified
+**                  until its ownership is returned to the client.
+**  RETURN
+**      PRStatus    An indication of success. If equal to PR_FAILUE details
+**                  of the failure are avaiable via PR_GetError().
+**
+**  ERRORS
+**      PR_INVALID_ARGUMENT_ERROR
+**                  Invalid 'group' identifier or duplicate 'desc' object.
+**      PR_OUT_OF_MEMORY_ERROR
+**                  Insuffient memory for internal data structures.
+**      PR_INVALID_STATE_ERROR
+**                  The group is being destroyed.
+*/
+NSPR_API(PRStatus) PR_AddWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc);
+
+/*
+** FUNCTION:    PR_WaitRecvReady
+** DESCRIPTION:
+**      PR_WaitRecvReady will block the calling thread until one of the
+**      file descriptors that have been added via PR_AddWaitFileDesc is
+**      available for input I/O.
+**  INPUT
+**      group       A pointer to a valid PRWaitGroup or NULL (the null
+**                  group. The function will block the caller until a
+**                  channel from the wait group becomes ready for receive
+**                  or there is some sort of error.
+**  RETURN
+**      PRReciveWait
+**                  When the caller is resumed it is either returned a
+**                  valid pointer to a previously added receive wait or
+**                  a NULL. If the latter, the function has terminated
+**                  for a reason that can be determined by calling
+**                  PR_GetError().
+**                  If a valid pointer is returned, the reference is to the
+**                  file descriptor contained in the receive wait object.
+**                  The outcome of the wait operation may still fail, and
+**                  if it has, that fact will be noted in the object's
+**                  outcome field. Details can be retrieved from PR_GetError().
+**
+**  ERRORS
+**      PR_INVALID_ARGUMENT_ERROR
+**                  The 'group' is not known by the runtime.
+**      PR_PENDING_INTERRUPT_ERROR
+                    The thread was interrupted.
+**      PR_INVALID_STATE_ERROR
+**                  The group is being destroyed.
+*/
+NSPR_API(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group);
+
+/*
+** FUNCTION:    PR_CancelWaitFileDesc
+** DESCRIPTION:
+**      PR_CancelWaitFileDesc is provided as a means for cancelling operations
+**      on objects previously submitted by use of PR_AddWaitFileDesc(). If
+**      the runtime knows of the object, it will be marked as having failed
+**      because it was interrupted (similar to PR_Interrupt()). The first
+**      available thread waiting on the group will be made to return the
+**      PRRecvWait object with the outcome noted.
+**
+**  INPUTS
+**      group       The wait group under which the wait receive object was
+**                  added.
+**      desc        A pointer to the wait receive object that is to be
+**                  cancelled.
+**  RETURN
+**      PRStatus    If the wait receive object was located and associated
+**                  with the specified wait group, the status returned will
+**                  be PR_SUCCESS. There is still a race condition that would
+**                  permit the offected object to complete normally, but it
+**                  is assured that it will complete in the near future.
+**                  If the receive object or wait group are invalid, the
+**                  function will return with a status of PR_FAILURE.
+**
+**  ERRORS
+**      PR_INVALID_ARGUMENT_ERROR
+**                  The 'group' argument is not recognized as a valid group.
+**      PR_COLLECTION_EMPTY_ERROR
+**                  There are no more receive wait objects in the group's
+**                  collection.
+**      PR_INVALID_STATE_ERROR
+**                  The group is being destroyed.
+*/
+NSPR_API(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc);
+
+/*
+** FUNCTION:    PR_CancelWaitGroup
+** DESCRIPTION:
+**      PR_CancelWaitGroup is provided as a means for cancelling operations
+**      on objects previously submitted by use of PR_AddWaitFileDesc(). Each
+**      successive call will return a pointer to a PRRecvWait object that
+**      was previously registered via PR_AddWaitFileDesc(). If no wait
+**      objects are associated with the wait group, a NULL will be returned.
+**      This function should be called in a loop until a NULL is returned
+**      to reclaim all the wait objects prior to calling PR_DestroyWaitGroup().
+**
+**  INPUTS
+**      group       The wait group under which the wait receive object was
+**                  added.
+**  RETURN
+**      PRRecvWait* If the wait group is valid and at least one receive wait
+**                  object is present in the group, that object will be
+**                  marked as PR_MW_INTERRUPT'd and removed from the group's
+**                  queues. Otherwise a NULL will be returned and the reason
+**                  for the NULL may be retrieved by calling PR_GetError().
+**
+**  ERRORS
+**      PR_INVALID_ARGUMENT_ERROR
+**      PR_GROUP_EMPTY_ERROR
+*/
+NSPR_API(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group);
+
+/*
+** FUNCTION:    PR_CreateWaitGroup
+** DESCRIPTION:
+**      A wait group is an opaque object that a client may create in order
+**      to semantically group various wait requests. Each wait group is
+**      unique, including the default wait group (NULL). A wait request
+**      that was added under a wait group will only be serviced by a caller
+**      that specified the same wait group.
+**
+**  INPUT
+**      size        The size of the hash table to be used to contain the
+**                  receive wait objects. This is just the initial size.
+**                  It will grow as it needs to, but to avoid that hassle
+**                  one can suggest a suitable size initially. It should
+**                  be ~30% larger than the maximum number of receive wait
+**                  objects expected.
+**  RETURN
+**      PRWaitGroup If successful, the function will return a pointer to an
+**                  object that was allocated by and owned by the runtime.
+**                  The reference remains valid until it is explicitly destroyed
+**                  by calling PR_DestroyWaitGroup().
+**
+**  ERRORS
+**      PR_OUT_OF_MEMORY_ERROR
+*/
+NSPR_API(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size);
+
+/*
+** FUNCTION:    PR_DestroyWaitGroup
+** DESCRIPTION:
+**      Undo the effects of PR_CreateWaitGroup(). Any receive wait operations
+**      on the group will be treated as if the each had been the target of a
+**      PR_CancelWaitFileDesc().
+**
+**  INPUT
+**      group       Reference to a wait group previously allocated using
+**                  PR_CreateWaitGroup().
+**  RETURN
+**      PRStatus    Will be PR_SUCCESS if the wait group was valid and there
+**                  are no receive wait objects in that group. Otherwise
+**                  will indicate PR_FAILURE.
+**
+**  ERRORS
+**      PR_INVALID_ARGUMENT_ERROR
+**                  The 'group' argument does not reference a known object.
+**      PR_INVALID_STATE_ERROR
+**                  The group still contains receive wait objects.
+*/
+NSPR_API(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group);
+
+/*
+** FUNCTION:    PR_CreateMWaitEnumerator
+** DESCRIPTION:
+**      The PR_CreateMWaitEnumerator() function returns a reference to an
+**      opaque PRMWaitEnumerator object. The enumerator object is required
+**      as an argument for each successive call in the stateless enumeration
+**      of the indicated wait group.
+**
+**      group       The wait group that the enumeration is intended to
+**                  process. It may be be the default wait group (NULL).
+** RETURN
+**      PRMWaitEnumerator* group
+**                  A reference to an object that will be used to store
+**                  intermediate state of enumerations.
+** ERRORS
+**      Errors are indicated by the function returning a NULL.
+**      PR_INVALID_ARGUMENT_ERROR
+**                  The 'group' argument does not reference a known object.
+**      PR_OUT_OF_MEMORY_ERROR
+*/
+NSPR_API(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group);
+
+/*
+** FUNCTION:    PR_DestroyMWaitEnumerator
+** DESCRIPTION:
+**      Destroys the object created by PR_CreateMWaitEnumerator(). The reference
+**      used as an argument becomes invalid.
+**
+** INPUT
+**      PRMWaitEnumerator* enumerator
+**          The PRMWaitEnumerator object to destroy.
+** RETURN
+**      PRStatus
+**          PR_SUCCESS if successful, PR_FAILURE otherwise.
+** ERRORS
+**      PR_INVALID_ARGUMENT_ERROR
+**                  The enumerator is invalid.
+*/
+NSPR_API(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator);
+
+/*
+** FUNCTION:    PR_EnumerateWaitGroup
+** DESCRIPTION:
+**      PR_EnumerateWaitGroup is a thread safe enumerator over a wait group.
+**      Each call to the enumerator must present a valid PRMWaitEnumerator
+**      rererence and a pointer to the "previous" element returned from the
+**      enumeration process or a NULL.
+**
+**      An enumeration is started by passing a NULL as the "previous" value.
+**      Subsequent calls to the enumerator must pass in the result of the
+**      previous call. The enumeration end is signaled by the runtime returning
+**      a NULL as the result.
+**
+**      Modifications to the content of the wait group are allowed during
+**      an enumeration. The effect is that the enumeration may have to be
+**      "reset" and that may result in duplicates being returned from the
+**      enumeration.
+**
+**      An enumeration may be abandoned at any time. The runtime is not
+**      keeping any state, so there are no issues in that regard.
+*/
+NSPR_API(PRRecvWait*) PR_EnumerateWaitGroup(
+    PRMWaitEnumerator *enumerator, const PRRecvWait *previous);
+   
+PR_END_EXTERN_C
+
+#endif /* defined(_PRMWAIT_H) */
+
+/* prmwait.h */
diff --git a/mozilla/nsprpub/pr/include/prnetdb.h b/mozilla/nsprpub/pr/include/prnetdb.h
new file mode 100644
index 0000000..f1b7ddc
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prnetdb.h
@@ -0,0 +1,499 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prnetdb_h___
+#define prnetdb_h___
+
+#include "prtypes.h"
+#include "prio.h"
+
+PR_BEGIN_EXTERN_C
+
+
+/*
+ *********************************************************************
+ *  Translate an Internet address to/from a character string
+ *********************************************************************
+ */
+NSPR_API(PRStatus) PR_StringToNetAddr(
+    const char *string, PRNetAddr *addr);
+
+NSPR_API(PRStatus) PR_NetAddrToString(
+    const PRNetAddr *addr, char *string, PRUint32 size);
+
+/*
+** Structures returned by network data base library.  All addresses are
+** supplied in host order, and returned in network order (suitable for
+** use in system calls).
+*/
+/*
+** Beware that WINSOCK.H defines h_addrtype and h_length as short.
+** Client code does direct struct copies of hostent to PRHostEnt and
+** hence the ifdef.
+*/
+typedef struct PRHostEnt {
+    char *h_name;       /* official name of host */
+    char **h_aliases;   /* alias list */
+#ifdef WIN32
+    PRInt16 h_addrtype; /* host address type */
+    PRInt16 h_length;   /* length of address */
+#else
+    PRInt32 h_addrtype; /* host address type */
+    PRInt32 h_length;   /* length of address */
+#endif
+    char **h_addr_list; /* list of addresses from name server */
+} PRHostEnt;
+
+/* A safe size to use that will mostly work... */
+#if (defined(AIX) && defined(_THREAD_SAFE)) || defined(OSF1)
+#define PR_NETDB_BUF_SIZE sizeof(struct protoent_data)
+#else
+#define PR_NETDB_BUF_SIZE 1024
+#endif
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_GetHostByName()
+** Lookup a host by name.
+**
+** INPUTS:
+**  char *hostname      Character string defining the host name of interest
+**  char *buf           A scratch buffer for the runtime to return result.
+**                      This buffer is allocated by the caller.
+**  PRIntn bufsize      Number of bytes in 'buf'. A recommnded value to
+**                      use is PR_NETDB_BUF_SIZE.
+** OUTPUTS:
+**  PRHostEnt *hostentry
+**                      This structure is filled in by the runtime if
+**                      the function returns PR_SUCCESS. This structure
+**                      is allocated by the caller.
+** RETURN:
+**  PRStatus            PR_SUCCESS if the lookup succeeds. If it fails
+**                      the result will be PR_FAILURE and the reason
+**                      for the failure can be retrieved by PR_GetError().
+***********************************************************************/
+NSPR_API(PRStatus) PR_GetHostByName(
+    const char *hostname, char *buf, PRIntn bufsize, PRHostEnt *hostentry);
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_GetIPNodeByName()
+** Lookup a host by name. Equivalent to getipnodebyname(AI_DEFAULT)
+** of RFC 2553.
+**
+** INPUTS:
+**  char *hostname      Character string defining the host name of interest
+**  PRUint16 af         Address family (either PR_AF_INET or PR_AF_INET6)
+**  PRIntn flags        Specifies the types of addresses that are searched
+**                      for and the types of addresses that are returned.
+**                      The only supported flag is PR_AI_DEFAULT.
+**  char *buf           A scratch buffer for the runtime to return result.
+**                      This buffer is allocated by the caller.
+**  PRIntn bufsize      Number of bytes in 'buf'. A recommnded value to
+**                      use is PR_NETDB_BUF_SIZE.
+** OUTPUTS:
+**  PRHostEnt *hostentry
+**                      This structure is filled in by the runtime if
+**                      the function returns PR_SUCCESS. This structure
+**                      is allocated by the caller.
+** RETURN:
+**  PRStatus            PR_SUCCESS if the lookup succeeds. If it fails
+**                      the result will be PR_FAILURE and the reason
+**                      for the failure can be retrieved by PR_GetError().
+***********************************************************************/
+
+
+#define PR_AI_ALL         0x08
+#define PR_AI_V4MAPPED    0x10
+#define PR_AI_ADDRCONFIG  0x20
+#define PR_AI_NOCANONNAME 0x8000
+#define PR_AI_DEFAULT     (PR_AI_V4MAPPED | PR_AI_ADDRCONFIG)
+
+NSPR_API(PRStatus) PR_GetIPNodeByName(
+    const char *hostname,
+    PRUint16 af,
+    PRIntn flags,
+    char *buf,
+    PRIntn bufsize,
+    PRHostEnt *hostentry);
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_GetHostByAddr()
+** Lookup a host entry by its network address.
+**
+** INPUTS:
+**  char *hostaddr      IP address of host in question
+**  char *buf           A scratch buffer for the runtime to return result.
+**                      This buffer is allocated by the caller.
+**  PRIntn bufsize      Number of bytes in 'buf'. A recommnded value to
+**                      use is PR_NETDB_BUF_SIZE.
+** OUTPUTS:
+**  PRHostEnt *hostentry
+**                      This structure is filled in by the runtime if
+**                      the function returns PR_SUCCESS. This structure
+**                      is allocated by the caller.
+** RETURN:
+**  PRStatus            PR_SUCCESS if the lookup succeeds. If it fails
+**                      the result will be PR_FAILURE and the reason
+**                      for the failure can be retrieved by PR_GetError().
+***********************************************************************/
+NSPR_API(PRStatus) PR_GetHostByAddr(
+    const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry);
+
+/***********************************************************************
+** FUNCTION:	PR_EnumerateHostEnt()	
+** DESCRIPTION:
+**  A stateless enumerator over a PRHostEnt structure acquired from
+**  PR_GetHostByName() PR_GetHostByAddr() to evaluate the possible
+**  network addresses.
+**
+** INPUTS:
+**  PRIntn  enumIndex   Index of the enumeration. The enumeration starts
+**                      and ends with a value of zero.
+**
+**  PRHostEnt *hostEnt  A pointer to a host entry struct that was
+**                      previously returned by PR_GetHostByName() or
+**                      PR_GetHostByAddr().
+**
+**  PRUint16 port       The port number to be assigned as part of the
+**                      PRNetAddr.
+**
+** OUTPUTS:
+**  PRNetAddr *address  A pointer to an address structure that will be
+**                      filled in by the call to the enumeration if the
+**                      result of the call is greater than zero.
+**
+** RETURN:
+**  PRIntn              The value that should be used for the next call
+**                      of the enumerator ('enumIndex'). The enumeration
+**                      is ended if this value is returned zero.
+**                      If a value of -1 is returned, the enumeration
+**                      has failed. The reason for the failure can be
+**                      retrieved by calling PR_GetError().
+***********************************************************************/
+NSPR_API(PRIntn) PR_EnumerateHostEnt(
+    PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address);
+
+/***********************************************************************
+** FUNCTION: PR_InitializeNetAddr(), 
+** DESCRIPTION:
+**  Initialize the fields of a PRNetAddr, assigning well known values as
+**  appropriate.
+**
+** INPUTS
+**  PRNetAddrValue val  The value to be assigned to the IP Address portion
+**                      of the network address. This can only specify the
+**                      special well known values that are equivalent to
+**                      INADDR_ANY and INADDR_LOOPBACK.
+**
+**  PRUint16 port       The port number to be assigned in the structure.
+**
+** OUTPUTS:
+**  PRNetAddr *addr     The address to be manipulated.
+**
+** RETURN:
+**  PRStatus            To indicate success or failure. If the latter, the
+**                      reason for the failure can be retrieved by calling
+**                      PR_GetError();
+***********************************************************************/
+typedef enum PRNetAddrValue
+{
+    PR_IpAddrNull,      /* do NOT overwrite the IP address */
+    PR_IpAddrAny,       /* assign logical INADDR_ANY to IP address */
+    PR_IpAddrLoopback,  /* assign logical INADDR_LOOPBACK  */
+    PR_IpAddrV4Mapped   /* IPv4 mapped address */
+} PRNetAddrValue;
+
+NSPR_API(PRStatus) PR_InitializeNetAddr(
+    PRNetAddrValue val, PRUint16 port, PRNetAddr *addr);
+
+/***********************************************************************
+** FUNCTION: PR_SetNetAddr(), 
+** DESCRIPTION:
+**  Set the fields of a PRNetAddr, assigning well known values as
+**  appropriate. This function is similar to PR_InitializeNetAddr
+**  but differs in that the address family is specified.
+**
+** INPUTS
+**  PRNetAddrValue val  The value to be assigned to the IP Address portion
+**                      of the network address. This can only specify the
+**                      special well known values that are equivalent to
+**                      INADDR_ANY and INADDR_LOOPBACK.
+**
+**  PRUint16 af         The address family (either PR_AF_INET or PR_AF_INET6)
+**
+**  PRUint16 port       The port number to be assigned in the structure.
+**
+** OUTPUTS:
+**  PRNetAddr *addr     The address to be manipulated.
+**
+** RETURN:
+**  PRStatus            To indicate success or failure. If the latter, the
+**                      reason for the failure can be retrieved by calling
+**                      PR_GetError();
+***********************************************************************/
+NSPR_API(PRStatus) PR_SetNetAddr(
+    PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr);
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_IsNetAddrType()
+** Determine if the network address is of the specified type.
+**
+** INPUTS:
+**  const PRNetAddr *addr   A network address.
+**  PRNetAddrValue          The type of network address 
+**
+** RETURN:
+**  PRBool                  PR_TRUE if the network address is of the
+**                          specified type, else PR_FALSE.
+***********************************************************************/
+NSPR_API(PRBool) PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val);
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_ConvertIPv4AddrToIPv6()
+** Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr
+**
+** INPUTS:
+**  PRUint32 	v4addr		IPv4 address
+**
+** OUTPUTS:
+**  PRIPv6Addr *v6addr      The converted IPv6 address
+**
+** RETURN:
+**  void
+**                       
+***********************************************************************/
+NSPR_API(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr);
+
+/***********************************************************************
+** MACRO:	
+** DESCRIPTION:	PR_NetAddrFamily()
+** Get the 'family' field of a PRNetAddr union.
+**
+** INPUTS:
+**  const PRNetAddr *addr   A network address.
+**
+** RETURN:
+**  PRUint16                The 'family' field of 'addr'.
+***********************************************************************/
+#define PR_NetAddrFamily(addr) ((addr)->raw.family)
+
+/***********************************************************************
+** MACRO:	
+** DESCRIPTION:	PR_NetAddrInetPort()
+** Get the 'port' field of a PRNetAddr union.
+**
+** INPUTS:
+**  const PRNetAddr *addr   A network address.
+**
+** RETURN:
+**  PRUint16                The 'port' field of 'addr'.
+***********************************************************************/
+#define PR_NetAddrInetPort(addr) \
+    ((addr)->raw.family == PR_AF_INET6 ? (addr)->ipv6.port : (addr)->inet.port)
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_GetProtoByName()
+** Lookup a protocol entry based on protocol's name
+**
+** INPUTS:
+**  char *protocolname  Character string of the protocol's name.
+**  char *buf           A scratch buffer for the runtime to return result.
+**                      This buffer is allocated by the caller.
+**  PRIntn bufsize      Number of bytes in 'buf'. A recommnded value to
+**                      use is PR_NETDB_BUF_SIZE.
+** OUTPUTS:
+**  PRHostEnt *PRProtoEnt
+**                      This structure is filled in by the runtime if
+**                      the function returns PR_SUCCESS. This structure
+**                      is allocated by the caller.
+** RETURN:
+**  PRStatus            PR_SUCCESS if the lookup succeeds. If it fails
+**                      the result will be PR_FAILURE and the reason
+**                      for the failure can be retrieved by PR_GetError().
+***********************************************************************/
+
+typedef struct PRProtoEnt {
+    char *p_name;       /* official protocol name */
+    char **p_aliases;   /* alias list */
+#ifdef WIN32
+    PRInt16 p_num;      /* protocol # */
+#else
+    PRInt32 p_num;      /* protocol # */
+#endif
+} PRProtoEnt;
+
+NSPR_API(PRStatus) PR_GetProtoByName(
+    const char* protocolname, char* buffer, PRInt32 bufsize, PRProtoEnt* result);
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_GetProtoByNumber()
+** Lookup a protocol entry based on protocol's number
+**
+** INPUTS:
+**  PRInt32 protocolnumber
+**                      Number assigned to the protocol.
+**  char *buf           A scratch buffer for the runtime to return result.
+**                      This buffer is allocated by the caller.
+**  PRIntn bufsize      Number of bytes in 'buf'. A recommnded value to
+**                      use is PR_NETDB_BUF_SIZE.
+** OUTPUTS:
+**  PRHostEnt *PRProtoEnt
+**                      This structure is filled in by the runtime if
+**                      the function returns PR_SUCCESS. This structure
+**                      is allocated by the caller.
+** RETURN:
+**  PRStatus            PR_SUCCESS if the lookup succeeds. If it fails
+**                      the result will be PR_FAILURE and the reason
+**                      for the failure can be retrieved by PR_GetError().
+***********************************************************************/
+NSPR_API(PRStatus) PR_GetProtoByNumber(
+    PRInt32 protocolnumber, char* buffer, PRInt32 bufsize, PRProtoEnt* result);
+
+/***********************************************************************
+** FUNCTION:
+** DESCRIPTION: PR_GetAddrInfoByName()
+**  Look up a host by name. Equivalent to getaddrinfo(host, NULL, ...) of
+**  RFC 3493.
+**
+** INPUTS:
+**  char *hostname      Character string defining the host name of interest
+**  PRUint16 af         May be PR_AF_UNSPEC or PR_AF_INET.
+**  PRIntn flags        May be either PR_AI_ADDRCONFIG or
+**                      PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME. Include
+**                      PR_AI_NOCANONNAME to suppress the determination of
+**                      the canonical name corresponding to hostname.
+** RETURN:
+**  PRAddrInfo*         Handle to a data structure containing the results
+**                      of the host lookup. Use PR_EnumerateAddrInfo to
+**                      inspect the PRNetAddr values stored in this object.
+**                      When no longer needed, this handle must be destroyed
+**                      with a call to PR_FreeAddrInfo.  If a lookup error
+**                      occurs, then NULL will be returned.
+***********************************************************************/
+typedef struct PRAddrInfo PRAddrInfo;
+
+NSPR_API(PRAddrInfo*) PR_GetAddrInfoByName(
+    const char *hostname, PRUint16 af, PRIntn flags);
+
+/***********************************************************************
+** FUNCTION:
+** DESCRIPTION: PR_FreeAddrInfo()
+**  Destroy the PRAddrInfo handle allocated by PR_GetAddrInfoByName().
+**
+** INPUTS:
+**  PRAddrInfo *addrInfo
+**                      The handle resulting from a successful call to
+**                      PR_GetAddrInfoByName().
+** RETURN:
+**  void
+***********************************************************************/
+NSPR_API(void) PR_FreeAddrInfo(PRAddrInfo *addrInfo);
+
+/***********************************************************************
+** FUNCTION:
+** DESCRIPTION: PR_EnumerateAddrInfo()
+**  A stateless enumerator over a PRAddrInfo handle acquired from
+**  PR_GetAddrInfoByName() to inspect the possible network addresses.
+**
+** INPUTS:
+**  void *enumPtr       Index pointer of the enumeration. The enumeration
+**                      starts and ends with a value of NULL.
+**  const PRAddrInfo *addrInfo
+**                      The PRAddrInfo handle returned by a successful
+**                      call to PR_GetAddrInfoByName().
+**  PRUint16 port       The port number to be assigned as part of the
+**                      PRNetAddr.
+** OUTPUTS:
+**  PRNetAddr *result   A pointer to an address structure that will be
+**                      filled in by the call to the enumeration if the
+**                      result of the call is not NULL.
+** RETURN:
+**  void*               The value that should be used for the next call
+**                      of the enumerator ('enumPtr'). The enumeration
+**                      is ended if this value is NULL.
+***********************************************************************/
+NSPR_API(void *) PR_EnumerateAddrInfo(
+    void *enumPtr, const PRAddrInfo *addrInfo, PRUint16 port, PRNetAddr *result);
+
+/***********************************************************************
+** FUNCTION:
+** DESCRIPTION: PR_GetCanonNameFromAddrInfo()
+**  Extracts the canonical name of the hostname passed to
+**  PR_GetAddrInfoByName().
+**
+** INPUTS:
+**  const PRAddrInfo *addrInfo 
+**                      The PRAddrInfo handle returned by a successful
+**                      call to PR_GetAddrInfoByName().
+** RETURN:
+**  const char *        A const pointer to the canonical hostname stored
+**                      in the given PRAddrInfo handle. This pointer is
+**                      invalidated once the PRAddrInfo handle is destroyed
+**                      by a call to PR_FreeAddrInfo().
+***********************************************************************/
+NSPR_API(const char *) PR_GetCanonNameFromAddrInfo(
+    const PRAddrInfo *addrInfo);
+
+/***********************************************************************
+** FUNCTIONS: PR_ntohs, PR_ntohl, PR_ntohll, PR_htons, PR_htonl, PR_htonll
+**
+** DESCRIPTION: API entries for the common byte ordering routines.
+**
+**      PR_ntohs        16 bit conversion from network to host
+**      PR_ntohl        32 bit conversion from network to host
+**      PR_ntohll       64 bit conversion from network to host
+**      PR_htons        16 bit conversion from host to network
+**      PR_htonl        32 bit conversion from host to network
+**      PR_ntonll       64 bit conversion from host to network
+**
+***********************************************************************/
+NSPR_API(PRUint16) PR_ntohs(PRUint16);
+NSPR_API(PRUint32) PR_ntohl(PRUint32);
+NSPR_API(PRUint64) PR_ntohll(PRUint64);
+NSPR_API(PRUint16) PR_htons(PRUint16);
+NSPR_API(PRUint32) PR_htonl(PRUint32);
+NSPR_API(PRUint64) PR_htonll(PRUint64);
+
+PR_END_EXTERN_C
+
+#endif /* prnetdb_h___ */
diff --git a/mozilla/nsprpub/pr/include/prolock.h b/mozilla/nsprpub/pr/include/prolock.h
new file mode 100644
index 0000000..d8aece9
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prolock.h
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prolock_h___
+#define prolock_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** A locking mechanism, built on the existing PRLock definiion,
+** is provided that will permit applications to define a Lock
+** Hierarchy (or Lock Ordering) schema. An application designed
+** using the Ordered Lock functions will terminate with a
+** diagnostic message when a lock inversion condition is
+** detected. 
+** 
+** The lock ordering detection is complile-time enabled only. in
+** optimized builds of NSPR, the Ordered Lock functions map
+** directly to PRLock functions, providing no lock order
+** detection.
+** 
+** The Ordered Lock Facility is compiled in when DEBUG is defined at
+** compile time. Ordered Lock can be forced on in optimized builds by
+** defining FORCE_NSPR_ORDERED_LOCK at compile time. Both the
+** application using Ordered Lock and NSPR must be compiled with the
+** facility enabled to achieve the desired results.
+** 
+** Application designers should use the macro interfaces to the Ordered
+** Lock facility to ensure that it is compiled out in optimized builds.
+**
+** Application designers are responsible for defining their own
+** lock hierarchy. 
+**
+** Ordered Lock is thread-safe and SMP safe.
+**
+** See Also: prlock.h
+**
+** /lth. 10-Jun-1998.
+**
+*/
+
+/*
+** Opaque type for ordered lock.
+** ... Don't even think of looking in here.
+**
+*/
+
+#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS)
+typedef void * PROrderedLock;
+#else
+/*
+** Map PROrderedLock and methods onto PRLock when ordered locking
+** is not compiled in.
+**  
+*/
+#include "prlock.h"
+
+typedef PRLock PROrderedLock;
+#endif
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_CreateOrderedLock() -- Create an Ordered Lock
+** 
+** DESCRIPTION: PR_CreateOrderedLock() creates an ordered lock.
+** 
+** INPUTS:
+**  order: user defined order of this lock.
+**  name: name of the lock. For debugging purposes.
+** 
+** OUTPUTS: returned
+** 
+** RETURNS: PR_OrderedLock pointer
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS)
+#define PR_CREATE_ORDERED_LOCK(order,name)\
+    PR_CreateOrderedLock((order),(name))
+#else
+#define PR_CREATE_ORDERED_LOCK(order) PR_NewLock()
+#endif
+
+NSPR_API(PROrderedLock *) 
+    PR_CreateOrderedLock( 
+        PRInt32 order,
+        const char *name
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_DestroyOrderedLock() -- Destroy an Ordered Lock
+** 
+** DESCRIPTION: PR_DestroyOrderedLock() destroys the ordered lock
+** referenced by lock.
+** 
+** INPUTS: lock: pointer to a PROrderedLock
+** 
+** OUTPUTS: the lock is destroyed
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS)
+#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyOrderedLock((lock))
+#else
+#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyLock((lock))
+#endif
+
+NSPR_API(void) 
+    PR_DestroyOrderedLock( 
+        PROrderedLock *lock 
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_LockOrderedLock() -- Lock an ordered lock
+** 
+** DESCRIPTION: PR_LockOrderedLock() locks the ordered lock
+** referenced by lock. If the order of lock is less than or equal
+** to the order of the highest lock held by the locking thread,
+** the function asserts.
+** 
+** INPUTS: lock: a pointer to a PROrderedLock
+** 
+** OUTPUTS: The lock is held or the function asserts.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS)
+#define PR_LOCK_ORDERED_LOCK(lock) PR_LockOrderedLock((lock))
+#else
+#define PR_LOCK_ORDERED_LOCK(lock) PR_Lock((lock))
+#endif
+
+NSPR_API(void) 
+    PR_LockOrderedLock( 
+        PROrderedLock *lock 
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_UnlockOrderedLock() -- unlock and Ordered Lock
+** 
+** DESCRIPTION: PR_UnlockOrderedLock() unlocks the lock referenced
+** by lock.
+** 
+** INPUTS: lock: a pointer to a PROrderedLock
+** 
+** OUTPUTS: the lock is unlocked
+** 
+** RETURNS:
+**  PR_SUCCESS
+**  PR_FAILURE
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS)
+#define PR_UNLOCK_ORDERED_LOCK(lock) PR_UnlockOrderedLock((lock))
+#else
+#define PR_UNLOCK_ORDERED_LOCK(lock) PR_Unlock((lock))
+#endif
+
+NSPR_API(PRStatus) 
+    PR_UnlockOrderedLock( 
+        PROrderedLock *lock 
+);
+
+PR_END_EXTERN_C
+
+#endif /* prolock_h___ */
diff --git a/mozilla/nsprpub/pr/include/prpdce.h b/mozilla/nsprpub/pr/include/prpdce.h
new file mode 100644
index 0000000..ebd595a
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prpdce.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * File:		prpdce.h
+ * Description:	This file is the API defined to allow for DCE (aka POSIX)
+ *				thread emulation in an NSPR environment. It is not the
+ *				intent that this be a fully supported API.
+ */
+
+#if !defined(PRPDCE_H)
+#define PRPDCE_H
+
+#include "prlock.h"
+#include "prcvar.h"
+#include "prtypes.h"
+#include "prinrval.h"
+
+PR_BEGIN_EXTERN_C
+
+#define _PR_NAKED_CV_LOCK (PRLock*)0xdce1dce1
+
+/*
+** Test and acquire a lock.
+**
+** If the lock is acquired by the calling thread, the
+** return value will be PR_SUCCESS. If the lock is
+** already held, by another thread or this thread, the
+** result will be PR_FAILURE.
+*/
+NSPR_API(PRStatus) PRP_TryLock(PRLock *lock);
+
+/*
+** Create a naked condition variable
+**
+** A "naked" condition variable is one that is not created bound
+** to a lock. The CV created with this function is the only type
+** that may be used in the subsequent "naked" condition variable
+** operations (see PRP_NakedWait, PRP_NakedNotify, PRP_NakedBroadcast);
+*/
+NSPR_API(PRCondVar*) PRP_NewNakedCondVar(void);
+
+/*
+** Destroy a naked condition variable
+**
+** Destroy the condition variable created by PR_NewNakedCondVar.
+*/
+NSPR_API(void) PRP_DestroyNakedCondVar(PRCondVar *cvar);
+
+/*
+** Wait on a condition
+**
+** Wait on the condition variable 'cvar'. It is asserted that
+** the lock protecting the condition 'lock' is held by the
+** calling thread. If more time expires than that declared in
+** 'timeout' the condition will be notified. Waits can be
+** interrupted by another thread.
+**
+** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar.
+*/
+NSPR_API(PRStatus) PRP_NakedWait(
+	PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout);
+
+/*
+** Notify a thread waiting on a condition
+**
+** Notify the condition specified 'cvar'.
+**
+** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar.
+*/
+NSPR_API(PRStatus) PRP_NakedNotify(PRCondVar *cvar);
+
+/*
+** Notify all threads waiting on a condition
+**
+** Notify the condition specified 'cvar'.
+**
+** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar.
+*/
+NSPR_API(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar);
+
+PR_END_EXTERN_C
+
+#endif /* PRPDCE_H */
diff --git a/mozilla/nsprpub/pr/include/prprf.h b/mozilla/nsprpub/pr/include/prprf.h
new file mode 100644
index 0000000..7336d97
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prprf.h
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prprf_h___
+#define prprf_h___
+
+/*
+** API for PR printf like routines. Supports the following formats
+**	%d - decimal
+**	%u - unsigned decimal
+**	%x - unsigned hex
+**	%X - unsigned uppercase hex
+**	%o - unsigned octal
+**	%hd, %hu, %hx, %hX, %ho - 16-bit versions of above
+**	%ld, %lu, %lx, %lX, %lo - 32-bit versions of above
+**	%lld, %llu, %llx, %llX, %llo - 64 bit versions of above
+**	%s - string
+**	%c - character
+**	%p - pointer (deals with machine dependent pointer size)
+**	%f - float
+**	%g - float
+*/
+#include "prtypes.h"
+#include "prio.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+PR_BEGIN_EXTERN_C
+
+/*
+** sprintf into a fixed size buffer. Guarantees that a NUL is at the end
+** of the buffer. Returns the length of the written output, NOT including
+** the NUL, or (PRUint32)-1 if an error occurs.
+*/
+NSPR_API(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...);
+
+/*
+** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd
+** buffer on success, NULL on failure. Call "PR_smprintf_free" to release
+** the memory returned.
+*/
+NSPR_API(char*) PR_smprintf(const char *fmt, ...);
+
+/*
+** Free the memory allocated, for the caller, by PR_smprintf
+*/
+NSPR_API(void) PR_smprintf_free(char *mem);
+
+/*
+** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of
+** the PR_MALLOC'd buffer. sprintf will append data to the end of last,
+** growing it as necessary using realloc. If last is NULL, PR_sprintf_append
+** will allocate the initial string. The return value is the new value of
+** last for subsequent calls, or NULL if there is a malloc failure.
+*/
+NSPR_API(char*) PR_sprintf_append(char *last, const char *fmt, ...);
+
+/*
+** sprintf into a function. The function "f" is called with a string to
+** place into the output. "arg" is an opaque pointer used by the stuff
+** function to hold any state needed to do the storage of the output
+** data. The return value is a count of the number of characters fed to
+** the stuff function, or (PRUint32)-1 if an error occurs.
+*/
+typedef PRIntn (*PRStuffFunc)(void *arg, const char *s, PRUint32 slen);
+
+NSPR_API(PRUint32) PR_sxprintf(PRStuffFunc f, void *arg, const char *fmt, ...);
+
+/*
+** fprintf to a PRFileDesc
+*/
+NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...);
+
+/*
+** va_list forms of the above.
+*/
+NSPR_API(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen, const char *fmt, va_list ap);
+NSPR_API(char*) PR_vsmprintf(const char *fmt, va_list ap);
+NSPR_API(char*) PR_vsprintf_append(char *last, const char *fmt, va_list ap);
+NSPR_API(PRUint32) PR_vsxprintf(PRStuffFunc f, void *arg, const char *fmt, va_list ap);
+NSPR_API(PRUint32) PR_vfprintf(struct PRFileDesc* fd, const char *fmt, va_list ap);
+
+/*
+***************************************************************************
+** FUNCTION: PR_sscanf
+** DESCRIPTION:
+**     PR_sscanf() scans the input character string, performs data
+**     conversions, and stores the converted values in the data objects
+**     pointed to by its arguments according to the format control
+**     string.
+**
+**     PR_sscanf() behaves the same way as the sscanf() function in the
+**     Standard C Library (stdio.h), with the following exceptions:
+**     - PR_sscanf() handles the NSPR integer and floating point types,
+**       such as PRInt16, PRInt32, PRInt64, and PRFloat64, whereas
+**       sscanf() handles the standard C types like short, int, long,
+**       and double.
+**     - PR_sscanf() has no multibyte character support, while sscanf()
+**       does.
+** INPUTS:
+**     const char *buf
+**         a character string holding the input to scan
+**     const char *fmt
+**         the format control string for the conversions
+**     ...
+**         variable number of arguments, each of them is a pointer to
+**         a data object in which the converted value will be stored
+** OUTPUTS: none
+** RETURNS: PRInt32
+**     The number of values converted and stored.
+** RESTRICTIONS:
+**    Multibyte characters in 'buf' or 'fmt' are not allowed.
+***************************************************************************
+*/
+
+NSPR_API(PRInt32) PR_sscanf(const char *buf, const char *fmt, ...);
+
+PR_END_EXTERN_C
+
+#endif /* prprf_h___ */
diff --git a/mozilla/nsprpub/pr/include/prproces.h b/mozilla/nsprpub/pr/include/prproces.h
new file mode 100644
index 0000000..0c1e8a6
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prproces.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prproces_h___
+#define prproces_h___
+
+#include "prtypes.h"
+#include "prio.h"
+
+PR_BEGIN_EXTERN_C
+
+/************************************************************************/
+/*****************************PROCESS OPERATIONS*************************/
+/************************************************************************/
+
+typedef struct PRProcess PRProcess;
+typedef struct PRProcessAttr PRProcessAttr;
+
+NSPR_API(PRProcessAttr *) PR_NewProcessAttr(void);
+
+NSPR_API(void) PR_ResetProcessAttr(PRProcessAttr *attr);
+
+NSPR_API(void) PR_DestroyProcessAttr(PRProcessAttr *attr);
+
+NSPR_API(void) PR_ProcessAttrSetStdioRedirect(
+    PRProcessAttr *attr,
+    PRSpecialFD stdioFd,
+    PRFileDesc *redirectFd
+);
+
+/*
+ * OBSOLETE -- use PR_ProcessAttrSetStdioRedirect instead.
+ */
+NSPR_API(void) PR_SetStdioRedirect(
+    PRProcessAttr *attr,
+    PRSpecialFD stdioFd,
+    PRFileDesc *redirectFd
+);
+
+NSPR_API(PRStatus) PR_ProcessAttrSetCurrentDirectory(
+    PRProcessAttr *attr,
+    const char *dir
+);
+
+NSPR_API(PRStatus) PR_ProcessAttrSetInheritableFD(
+    PRProcessAttr *attr,
+    PRFileDesc *fd,
+    const char *name
+);
+
+/*
+** Create a new process
+**
+** Create a new process executing the file specified as 'path' and with
+** the supplied arguments and environment.
+**
+** This function may fail because of illegal access (permissions),
+** invalid arguments or insufficient resources.
+**
+** A process may be created such that the creator can later synchronize its
+** termination using PR_WaitProcess(). 
+*/
+
+NSPR_API(PRProcess*) PR_CreateProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr);
+
+NSPR_API(PRStatus) PR_CreateProcessDetached(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr);
+
+NSPR_API(PRStatus) PR_DetachProcess(PRProcess *process);
+
+NSPR_API(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode);
+
+NSPR_API(PRStatus) PR_KillProcess(PRProcess *process);
+
+PR_END_EXTERN_C
+
+#endif /* prproces_h___ */
diff --git a/mozilla/nsprpub/pr/include/prrng.h b/mozilla/nsprpub/pr/include/prrng.h
new file mode 100644
index 0000000..e94b806
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prrng.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+
+/*
+** prrng.h -- NSPR Random Number Generator
+** 
+**
+** lth. 29-Oct-1999.
+*/
+
+#ifndef prrng_h___ 
+#define prrng_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** PR_GetRandomNoise() -- Get random noise from the host platform
+**
+** Description:
+** PR_GetRandomNoise() provides, depending on platform, a random value.
+** The length of the random value is dependent on platform and the
+** platform's ability to provide a random value at that moment.
+**
+** The intent of PR_GetRandomNoise() is to provide a "seed" value for a
+** another random number generator that may be suitable for
+** cryptographic operations. This implies that the random value
+** provided may not be, by itself, cryptographically secure. The value
+** generated by PR_GetRandomNoise() is at best, extremely difficult to
+** predict and is as non-deterministic as the underlying platfrom can
+** provide.
+**
+** Inputs:
+**   buf -- pointer to a caller supplied buffer to contain the
+**          generated random number. buf must be at least as large as
+**          is specified in the 'size' argument.
+**
+**   size -- the requested size of the generated random number
+**
+** Outputs:
+**   a random number provided in 'buf'.
+**
+** Returns:
+**   PRSize value equal to the size of the random number actually
+**   generated, or zero. The generated size may be less than the size
+**   requested. A return value of zero means that PR_GetRandomNoise() is
+**   not implemented on this platform, or there is no available noise
+**   available to be returned at the time of the call.
+**
+** Restrictions:
+**   Calls to PR_GetRandomNoise() may use a lot of CPU on some platforms.
+**   Some platforms may block for up to a few seconds while they
+**   accumulate some noise. Busy machines generate lots of noise, but
+**   care is advised when using PR_GetRandomNoise() frequently in your
+**   application.
+**
+** History:
+**   Parts of the model dependent implementation for PR_GetRandomNoise()
+**   were taken in whole or part from code previously in Netscape's NSS
+**   component.
+**
+*/
+NSPR_API(PRSize) PR_GetRandomNoise( 
+    void    *buf,
+    PRSize  size
+);
+
+PR_END_EXTERN_C
+
+#endif /* prrng_h___ */
+/* end prrng.h */
diff --git a/mozilla/nsprpub/pr/include/prrwlock.h b/mozilla/nsprpub/pr/include/prrwlock.h
new file mode 100644
index 0000000..945e5f8
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prrwlock.h
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:		prrwlock.h
+** Description:	API to basic reader-writer lock functions of NSPR.
+**
+**/
+
+#ifndef prrwlock_h___
+#define prrwlock_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * PRRWLock --
+ *
+ *	The reader writer lock, PRRWLock, is an opaque object to the clients
+ *	of NSPR.  All routines operate on a pointer to this opaque entity.
+ */
+
+
+typedef struct PRRWLock PRRWLock;
+
+#define	PR_RWLOCK_RANK_NONE	0
+
+
+/***********************************************************************
+** FUNCTION:    PR_NewRWLock
+** DESCRIPTION:
+**  Returns a pointer to a newly created reader-writer lock object.
+** INPUTS:      Lock rank
+**				Lock name
+** OUTPUTS:     void
+** RETURN:      PRRWLock*
+**   If the lock cannot be created because of resource constraints, NULL
+**   is returned.
+**  
+***********************************************************************/
+NSPR_API(PRRWLock*) PR_NewRWLock(PRUint32 lock_rank, const char *lock_name);
+
+/***********************************************************************
+** FUNCTION:    PR_DestroyRWLock
+** DESCRIPTION:
+**  Destroys a given RW lock object.
+** INPUTS:      PRRWLock *lock - Lock to be freed.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+NSPR_API(void) PR_DestroyRWLock(PRRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    PR_RWLock_Rlock
+** DESCRIPTION:
+**  Apply a read lock (non-exclusive) on a RWLock
+** INPUTS:      PRRWLock *lock - Lock to be read-locked.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+NSPR_API(void) PR_RWLock_Rlock(PRRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    PR_RWLock_Wlock
+** DESCRIPTION:
+**  Apply a write lock (exclusive) on a RWLock
+** INPUTS:      PRRWLock *lock - Lock to write-locked.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+NSPR_API(void) PR_RWLock_Wlock(PRRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    PR_RWLock_Unlock
+** DESCRIPTION:
+**  Release a RW lock. Unlocking an unlocked lock has undefined results.
+** INPUTS:      PRRWLock *lock - Lock to unlocked.
+** OUTPUTS:     void
+** RETURN:      void
+***********************************************************************/
+NSPR_API(void) PR_RWLock_Unlock(PRRWLock *lock);
+
+PR_END_EXTERN_C
+
+#endif /* prrwlock_h___ */
diff --git a/mozilla/nsprpub/pr/include/prshm.h b/mozilla/nsprpub/pr/include/prshm.h
new file mode 100644
index 0000000..098566e
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prshm.h
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+/*
+** prshm.h -- NSPR Shared Memory
+**
+** NSPR Named Shared Memory API provides a cross-platform named
+** shared-memory interface. NSPR Named Shared Memory is modeled on
+** similar constructs in Unix and Windows operating systems. Shared
+** memory allows multiple processes to access one or more common shared
+** memory regions, using it as an inter-process communication channel.
+**
+** Notes on Platform Independence:
+**   NSPR Named Shared Memory is built on the native services offered
+**   by most platforms. The NSPR Named Shared Memory API tries to
+**   provide a least common denominator interface so that it works
+**   across all supported platforms. To ensure that it works everywhere,
+**   some platform considerations must be accomodated and the protocol
+**   for using NSPR Shared Memory API must be observed.
+**
+** Protocol:
+**   Multiple shared memories can be created using NSPR's Shared Memory
+**   feature. For each named shared memory, as defined by the name
+**   given in the PR_OpenSharedMemory() call, a protocol for using the
+**   shared memory API is required to ensure desired behavior. Failing
+**   to follow the protocol may yield unpredictable results.
+**   
+**   PR_OpenSharedMemory() will create the shared memory segment, if it
+**   does not already exist, or open a connection that the existing
+**   shared memory segment if it already exists.
+**   
+**   PR_AttachSharedMemory() should be called following
+**   PR_OpenSharedMemory() to map the memory segment to an address in
+**   the application's address space.
+**   
+**   PR_AttachSharedMemory() may be called to re-map a shared memory
+**   segment after detaching the same PRSharedMemory object. Be
+**   sure to detach it when done.
+**   
+**   PR_DetachSharedMemory() should be called to un-map the shared
+**   memory segment from the application's address space.
+**   
+**   PR_CloseSharedMemory() should be called when no further use of the
+**   PRSharedMemory object is required within a process. Following a
+**   call to  PR_CloseSharedMemory() the PRSharedMemory object is
+**   invalid and cannot be reused.
+**   
+**   PR_DeleteSharedMemory() should be called before process
+**   termination. After calling PR_DeleteSharedMemory() any further use
+**   of the shared memory associated with the name may cause
+**   unpredictable results.
+**   
+** Files:
+**   The name passed to PR_OpenSharedMemory() should be a valid filename
+**   for a unix platform. PR_OpenSharedMemory() creates file using the
+**   name passed in. Some platforms may mangle the name before creating
+**   the file and the shared memory.
+**   
+**   The unix implementation may use SysV IPC shared memory, Posix
+**   shared memory, or memory mapped files; the filename may used to
+**   define the namespace. On Windows, the name is significant, but
+**   there is no file associated with name.
+**   
+**   No assumptions about the persistence of data in the named file
+**   should be made. Depending on platform, the shared memory may be
+**   mapped onto system paging space and be discarded at process
+**   termination.
+**   
+**   All names provided to PR_OpenSharedMemory() should be valid
+**   filename syntax or name syntax for shared memory for the target
+**   platform. Referenced directories should have permissions 
+**   appropriate for writing.
+**
+** Limits:
+**   Different platforms have limits on both the number and size of
+**   shared memory resources. The default system limits on some
+**   platforms may be smaller than your requirements. These limits may
+**   be adjusted on some platforms either via boot-time options or by
+**   setting the size of the system paging space to accomodate more
+**   and/or larger shared memory segment(s).
+**
+** Security:
+**   On unix platforms, depending on implementation, contents of the
+**   backing store for the shared memory can be exposed via the file
+**   system. Set permissions and or access controls at create and attach
+**   time to ensure you get the desired security.
+**
+**   On windows platforms, no special security measures are provided.
+**
+** Example:
+**   The test case pr/tests/nameshm1.c provides an example of use as
+**   well as testing the operation of NSPR's Named Shared Memory.
+**
+** lth. 18-Aug-1999.
+*/
+
+#ifndef prshm_h___
+#define prshm_h___
+
+#include "prtypes.h"
+#include "prio.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Declare opaque type PRSharedMemory.
+*/
+typedef struct PRSharedMemory PRSharedMemory;
+
+/*
+** FUNCTION: PR_OpenSharedMemory()
+**
+** DESCRIPTION:
+**   PR_OpenSharedMemory() creates a new shared-memory segment or
+**   associates a previously created memory segment with name.
+**
+**   When parameter create is (PR_SHM_EXCL | PR_SHM_CREATE) and the
+**   shared memory already exists, the function returns NULL with the
+**   error set to PR_FILE_EXISTS_ERROR.
+**
+**   When parameter create is PR_SHM_CREATE and the shared memory
+**   already exists, a handle to that memory segment is returned. If
+**   the segment does not exist, it is created and a pointer to the
+**   related PRSharedMemory structure is returned.
+**
+**   When parameter create is 0, and the shared memory exists, a
+**   pointer to a PRSharedMemory is returned. If the shared memory does
+**   not exist, NULL is returned with the error set to
+**   PR_FILE_NOT_FOUND_ERROR.
+**
+** INPUTS:
+**   name -- the name the shared-memory segment is known as.
+**   size -- the size of the shared memory segment. 
+**   flags -- Options for creating the shared memory
+**   mode -- Same as is passed to PR_Open()
+**
+** OUTPUTS: 
+**   The shared memory is allocated.
+**
+** RETURNS: Pointer to opaque structure PRSharedMemory or NULL.
+**   NULL is returned on error. The reason for the error can be
+**   retrieved via PR_GetError() and PR_GetOSError();
+**
+*/
+NSPR_API( PRSharedMemory * )
+    PR_OpenSharedMemory(
+        const char *name,
+        PRSize      size,
+        PRIntn      flags,
+        PRIntn      mode
+);
+/* Define values for PR_OpenShareMemory(...,create) */
+#define PR_SHM_CREATE 0x1  /* create if not exist */
+#define PR_SHM_EXCL   0x2  /* fail if already exists */
+
+/*
+** FUNCTION: PR_AttachSharedMemory()
+**
+** DESCRIPTION:
+** PR_AttachSharedMemory() maps the shared-memory described by
+** shm to the current process. 
+**
+** INPUTS: 
+**   shm -- The handle returned from PR_OpenSharedMemory().
+**   flags -- options for mapping the shared memory.
+**   PR_SHM_READONLY causes the memory to be attached 
+**   read-only.
+**
+** OUTPUTS:
+**   On success, the shared memory segment represented by shm is mapped
+**   into the process' address space.
+**
+** RETURNS: Address where shared memory is mapped, or NULL.
+**   NULL is returned on error. The reason for the error can be
+**   retrieved via PR_GetError() and PR_GetOSError();
+**
+**
+*/
+NSPR_API( void * )
+    PR_AttachSharedMemory(
+        PRSharedMemory *shm,
+        PRIntn  flags
+);
+/* Define values for PR_AttachSharedMemory(...,flags) */ 
+#define PR_SHM_READONLY 0x01
+
+/*
+** FUNCTION: PR_DetachSharedMemory()
+**
+** DESCRIPTION:
+**   PR_DetachSharedMemory() detaches the shared-memory described
+**   by shm. 
+**
+** INPUTS: 
+**   shm -- The handle returned from PR_OpenSharedMemory().
+**   addr -- The address at which the memory was attached.
+**
+** OUTPUTS:
+**   The shared memory mapped to an address via a previous call to
+**   PR_AttachSharedMemory() is unmapped.
+**
+** RETURNS: PRStatus
+**
+*/
+NSPR_API( PRStatus )
+    PR_DetachSharedMemory(
+        PRSharedMemory *shm,
+        void  *addr
+);
+
+/*
+** FUNCTION: PR_CloseSharedMemory()
+**
+** DESCRIPTION:
+**   PR_CloseSharedMemory() closes the shared-memory described by
+**   shm.
+** 
+** INPUTS:
+**   shm -- The handle returned from PR_OpenSharedMemory().
+**
+** OUTPUTS:
+**   the shared memory represented by shm is closed
+**
+** RETURNS: PRStatus
+**
+*/
+NSPR_API( PRStatus )
+    PR_CloseSharedMemory(
+        PRSharedMemory *shm
+);
+
+/*
+** FUNCTION: PR_DeleteSharedMemory()
+**
+** DESCRIPTION:
+**   The shared memory resource represented by name is released.
+**
+** INPUTS:
+**   name -- the name the shared-memory segment
+**
+** OUTPUTS:
+**   depending on platform, resources may be returned to the underlying
+**   operating system.
+**
+** RETURNS: PRStatus
+**
+*/
+NSPR_API( PRStatus )
+    PR_DeleteSharedMemory( 
+        const char *name
+);
+
+PR_END_EXTERN_C
+
+#endif /* prshm_h___ */
diff --git a/mozilla/nsprpub/pr/include/prshma.h b/mozilla/nsprpub/pr/include/prshma.h
new file mode 100644
index 0000000..e72ee85
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prshma.h
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+/*
+** prshma.h -- NSPR Anonymous Shared Memory
+**
+** NSPR provides an anonymous shared memory based on NSPR's PRFileMap
+** type. The anonymous file-mapped shared memory provides an inheritable
+** shared memory, as in: the child process inherits the shared memory.
+** Compare the file-mapped anonymous shared memory to to a named shared
+** memory described in prshm.h. The intent is to provide a shared
+** memory that is accessable only by parent and child processes. ...
+** It's a security thing.
+** 
+** Depending on the underlying platform, the file-mapped shared memory
+** may be backed by a file. ... surprise! ... On some platforms, no
+** real file backs the shared memory. On platforms where the shared
+** memory is backed by a file, the file's name in the filesystem is
+** visible to other processes for only the duration of the creation of
+** the file, hopefully a very short time. This restricts processess
+** that do not inherit the shared memory from opening the file and
+** reading or writing its contents. Further, when all processes
+** using an anonymous shared memory terminate, the backing file is
+** deleted. ... If you are not paranoid, you're not paying attention.
+** 
+** The file-mapped shared memory requires a protocol for the parent
+** process and child process to share the memory. NSPR provides two
+** protocols. Use one or the other; don't mix and match.
+** 
+** In the first protocol, the job of passing the inheritable shared
+** memory is done via helper-functions with PR_CreateProcess(). In the
+** second protocol, the parent process is responsible for creating the
+** child process; the parent and child are mutually responsible for
+** passing a FileMap string. NSPR provides helper functions for
+** extracting data from the PRFileMap object. ... See the examples
+** below.
+** 
+** Both sides should adhere strictly to the protocol for proper
+** operation. The pseudo-code below shows the use of a file-mapped
+** shared memory by a parent and child processes. In the examples, the
+** server creates the file-mapped shared memory, the client attaches to
+** it.
+**
+** First protocol.
+** Server:
+**
+**   fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); 
+**   addr = PR_MemMap(fm); 
+**   attr = PR_NewProcessAttr();
+**   PR_ProcessAttrSetInheritableFileMap( attr, fm, shmname );
+**   PR_CreateProcess(Client); 
+**   PR_DestroyProcessAttr(attr);
+**   ... yadda ...
+**   PR_MemUnmap( addr );
+**   PR_CloseFileMap(fm);
+**
+**
+** Client: 
+**   ... started by server via PR_CreateProcess()
+**   fm = PR_GetInheritedFileMap( shmname );
+**   addr = PR_MemMap(fm);
+**   ... yadda ...
+**   PR_MemUnmap(addr);
+**   PR_CloseFileMap(fm);
+**
+**
+** Second Protocol:
+** Server:
+**
+**   fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); 
+**   fmstring = PR_ExportFileMapAsString( fm );
+**   addr = PR_MemMap(fm); 
+**    ... application specific technique to pass fmstring to child
+**    ... yadda ... Server uses his own magic to create child
+**   PR_MemUnmap( addr );
+**   PR_CloseFileMap(fm);
+**
+**
+** Client: 
+**   ... started by server via his own magic
+**   ... application specific technique to find fmstring from parent
+**   fm = PR_ImportFileMapFromString( fmstring )
+**   addr = PR_MemMap(fm);
+**   ... yadda ...
+**   PR_MemUnmap(addr);
+**   PR_CloseFileMap(fm);
+**
+**
+** lth. 2-Jul-1999.
+**
+** Note: The second protocol was requested by NelsonB (7/1999); this is
+** to accomodate servers which already create their own child processes
+** using platform native methods.
+** 
+*/
+
+#ifndef prshma_h___
+#define prshma_h___
+
+#include "prtypes.h"
+#include "prio.h"
+#include "prproces.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory
+**
+** Description:
+** PR_OpenAnonFileMap() creates an anonymous shared memory. If the
+** shared memory already exists, a handle is returned to that shared
+** memory object.
+**
+** On Unix platforms, PR_OpenAnonFileMap() uses 'dirName' as a
+** directory name, without the trailing '/', to contain the anonymous
+** file. A filename is generated for the name.
+**
+** On Windows platforms, dirName is ignored.
+**
+** Inputs:
+**   dirName -- A directory name to contain the anonymous file.
+**   size -- The size of the shared memory
+**   prot -- How the shared memory is mapped. See prio.h
+**   
+** Outputs:
+**   PRFileMap *
+**
+** Returns:
+**   Pointer to PRFileMap or NULL on error.
+**
+*/
+NSPR_API( PRFileMap *)
+PR_OpenAnonFileMap(
+    const char *dirName,
+    PRSize      size, 
+    PRFileMapProtect prot
+);  
+
+/*
+** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export  
+**   to my children processes via PR_CreateProcess()
+**
+** Description:
+** PR_ProcessAttrSetInheritableFileMap() connects the PRFileMap to
+** PRProcessAttr with shmname. A subsequent call to PR_CreateProcess()
+** makes the PRFileMap importable by the child process.
+**
+** Inputs:
+**   attr -- PRProcessAttr, used to pass data to PR_CreateProcess()
+**   fm -- PRFileMap structure to be passed to the child process
+**   shmname -- The name for the PRFileMap; used by child.
+**
+** Outputs:
+**   PRFileMap *
+**
+** Returns:
+**   PRStatus
+**
+*/
+NSPR_API(PRStatus) 
+PR_ProcessAttrSetInheritableFileMap( 
+    PRProcessAttr   *attr,
+    PRFileMap       *fm, 
+    const char      *shmname
+);
+
+/*
+** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported
+**   by my parent process via PR_CreateProcess()
+**
+** Description:
+** PR_GetInheritedFileMap() retrieves a PRFileMap object exported from
+** its parent process via PR_CreateProcess().
+**
+** Inputs:
+**    shmname -- The name provided to PR_ProcessAttrSetInheritableFileMap()
+** 
+** Outputs:
+**   PRFileMap *
+**
+** Returns:
+**   PRFileMap pointer or NULL.
+**
+*/
+NSPR_API( PRFileMap *)
+PR_GetInheritedFileMap( 
+    const char *shmname 
+);
+
+/*
+** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap
+**
+** Description:
+** Creates an identifier, as a string, from a PRFileMap object
+** previously created with PR_OpenAnonFileMap().
+**
+** Inputs:
+**   fm -- PRFileMap pointer to be represented as a string.
+**   bufsize -- sizeof(buf)
+**   buf -- a buffer of length PR_FILEMAP_STRING_BUFSIZE
+**
+** Outputs:
+**   buf contains the stringized PRFileMap identifier
+**
+** Returns:
+**   PRStatus
+**
+*/
+NSPR_API( PRStatus )
+PR_ExportFileMapAsString( 
+    PRFileMap *fm,
+    PRSize    bufsize,
+    char      *buf
+);
+#define PR_FILEMAP_STRING_BUFSIZE 128
+
+/*
+** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string
+**
+** Description:
+** PR_ImportFileMapFromString() creates a PRFileMap object from a
+** string previously created by PR_ExportFileMapAsString().
+**
+** Inputs:
+**   fmstring -- string created by PR_ExportFileMapAsString()
+**
+** Returns:
+**   PRFileMap pointer or NULL.
+**
+*/
+NSPR_API( PRFileMap * )
+PR_ImportFileMapFromString( 
+    const char *fmstring
+);
+
+PR_END_EXTERN_C
+#endif /* prshma_h___ */
diff --git a/mozilla/nsprpub/pr/include/prsystem.h b/mozilla/nsprpub/pr/include/prsystem.h
new file mode 100644
index 0000000..13cf8ba
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prsystem.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prsystem_h___
+#define prsystem_h___
+
+/*
+** API to NSPR functions returning system info.
+*/
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Get the host' directory separator.
+**  Pathnames are then assumed to be of the form:
+**      [<sep><root_component><sep>]*(<component><sep>)<leaf_name>
+*/
+
+NSPR_API(char) PR_GetDirectorySeparator(void);
+
+/*
+** OBSOLETE -- the function name is misspelled.
+** Use PR_GetDirectorySeparator instead.
+*/
+
+NSPR_API(char) PR_GetDirectorySepartor(void);
+
+/*
+** Get the host' path separator.
+**  Paths are assumed to be of the form:
+**      <directory>[<sep><directory>]*
+*/
+
+NSPR_API(char) PR_GetPathSeparator(void);
+
+/* Types of information available via PR_GetSystemInfo(...) */
+typedef enum {
+    PR_SI_HOSTNAME,  /* the hostname with the domain name (if any)
+                      * removed */
+    PR_SI_SYSNAME,
+    PR_SI_RELEASE,
+    PR_SI_ARCHITECTURE,
+    PR_SI_HOSTNAME_UNTRUNCATED  /* the hostname exactly as configured
+                                 * on the system */
+} PRSysInfo;
+
+
+/*
+** If successful returns a null termintated string in 'buf' for
+** the information indicated in 'cmd'. If unseccussful the reason for
+** the failure can be retrieved from PR_GetError().
+**
+** The buffer is allocated by the caller and should be at least
+** SYS_INFO_BUFFER_LENGTH bytes in length.
+*/
+
+#define SYS_INFO_BUFFER_LENGTH 256
+
+NSPR_API(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen);
+
+/*
+** Return the number of bytes in a page
+*/
+NSPR_API(PRInt32) PR_GetPageSize(void);
+
+/*
+** Return log2 of the size of a page
+*/
+NSPR_API(PRInt32) PR_GetPageShift(void);
+
+/*
+** PR_GetNumberOfProcessors() -- returns the number of CPUs
+**
+** Description:
+** PR_GetNumberOfProcessors() extracts the number of processors
+** (CPUs available in an SMP system) and returns the number.
+** 
+** Parameters:
+**   none
+**
+** Returns:
+**   The number of available processors or -1 on error
+** 
+*/
+NSPR_API(PRInt32) PR_GetNumberOfProcessors( void );
+
+/*
+** PR_GetPhysicalMemorySize() -- returns the amount of system RAM
+**
+** Description:
+** PR_GetPhysicalMemorySize() determines the amount of physical RAM
+** in the system and returns the size in bytes.
+**
+** Parameters:
+**   none
+**
+** Returns:
+**   The amount of system RAM, or 0 on failure.
+**
+*/
+NSPR_API(PRUint64) PR_GetPhysicalMemorySize(void);
+
+PR_END_EXTERN_C
+
+#endif /* prsystem_h___ */
diff --git a/mozilla/nsprpub/pr/include/prthread.h b/mozilla/nsprpub/pr/include/prthread.h
new file mode 100644
index 0000000..bb93cbf
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prthread.h
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prthread_h___
+#define prthread_h___
+
+/*
+** API for NSPR threads. On some architectures (Mac OS Classic
+** notably) pre-emptibility is not guaranteed. Hard priority scheduling
+** is not guaranteed, so programming using priority based synchronization
+** is a no-no.
+**
+** NSPR threads are scheduled based loosely on their client set priority.
+** In general, a thread of a higher priority has a statistically better
+** chance of running relative to threads of lower priority. However,
+** NSPR uses multiple strategies to provide execution vehicles for thread
+** abstraction of various host platforms. As it turns out, there is little
+** NSPR can do to affect the scheduling attributes of "GLOBAL" threads.
+** However, a semblance of GLOBAL threads is used to implement "LOCAL"
+** threads. An arbitrary number of such LOCAL threads can be assigned to
+** a single GLOBAL thread.
+**
+** For scheduling, NSPR will attempt to run the highest priority LOCAL
+** thread associated with a given GLOBAL thread. It is further assumed
+** that the host OS will apply some form of "fair" scheduling on the
+** GLOBAL threads.
+**
+** Threads have a "system flag" which when set indicates the thread
+** doesn't count for determining when the process should exit (the
+** process exits when the last user thread exits).
+**
+** Threads also have a "scope flag" which controls whether the threads
+** are scheduled in the local scope or scheduled by the OS globally. This 
+** indicates whether a thread is permanently bound to a native OS thread. 
+** An unbound thread competes for scheduling resources in the same process.
+**
+** Another flag is "state flag" which control whether the thread is joinable.
+** It allows other threads to wait for the created thread to reach completion.
+**
+** Threads can have "per-thread-data" attached to them. Each thread has a
+** per-thread error number and error string which are updated when NSPR
+** operations fail.
+*/
+#include "prtypes.h"
+#include "prinrval.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PRThread PRThread;
+typedef struct PRThreadStack PRThreadStack;
+
+typedef enum PRThreadType {
+    PR_USER_THREAD,
+    PR_SYSTEM_THREAD
+} PRThreadType;
+
+typedef enum PRThreadScope {
+    PR_LOCAL_THREAD,
+    PR_GLOBAL_THREAD,
+    PR_GLOBAL_BOUND_THREAD
+} PRThreadScope;
+
+typedef enum PRThreadState {
+    PR_JOINABLE_THREAD,
+    PR_UNJOINABLE_THREAD
+} PRThreadState;
+
+typedef enum PRThreadPriority
+{
+    PR_PRIORITY_FIRST = 0,      /* just a placeholder */
+    PR_PRIORITY_LOW = 0,        /* the lowest possible priority */
+    PR_PRIORITY_NORMAL = 1,     /* most common expected priority */
+    PR_PRIORITY_HIGH = 2,       /* slightly more aggressive scheduling */
+    PR_PRIORITY_URGENT = 3,     /* it does little good to have more than one */
+    PR_PRIORITY_LAST = 3        /* this is just a placeholder */
+} PRThreadPriority;
+
+/*
+** Create a new thread:
+**     "type" is the type of thread to create
+**     "start(arg)" will be invoked as the threads "main"
+**     "priority" will be created thread's priority
+**     "scope" will specify whether the thread is local or global
+**     "state" will specify whether the thread is joinable or not
+**     "stackSize" the size of the stack, in bytes. The value can be zero
+**        and then a machine specific stack size will be chosen.
+**
+** This can return NULL if some kind of error occurs, such as if memory is
+** tight.
+**
+** If you want the thread to start up waiting for the creator to do
+** something, enter a lock before creating the thread and then have the
+** threads start routine enter and exit the same lock. When you are ready
+** for the thread to run, exit the lock.
+**
+** If you want to detect the completion of the created thread, the thread
+** should be created joinable.  Then, use PR_JoinThread to synchrnoize the
+** termination of another thread.
+**
+** When the start function returns the thread exits. If it is the last
+** PR_USER_THREAD to exit then the process exits.
+*/
+NSPR_API(PRThread*) PR_CreateThread(PRThreadType type,
+                     void (PR_CALLBACK *start)(void *arg),
+                     void *arg,
+                     PRThreadPriority priority,
+                     PRThreadScope scope,
+                     PRThreadState state,
+                     PRUint32 stackSize);
+
+/*
+** Wait for thread termination:
+**     "thread" is the target thread 
+**
+** This can return PR_FAILURE if no joinable thread could be found 
+** corresponding to the specified target thread.
+**
+** The calling thread is blocked until the target thread completes.
+** Several threads cannot wait for the same thread to complete; one thread
+** will operate successfully and others will terminate with an error PR_FAILURE.
+** The calling thread will not be blocked if the target thread has already
+** terminated.
+*/
+NSPR_API(PRStatus) PR_JoinThread(PRThread *thread);
+
+/*
+** Return the current thread object for the currently running code.
+** Never returns NULL.
+*/
+NSPR_API(PRThread*) PR_GetCurrentThread(void);
+#ifndef NO_NSPR_10_SUPPORT
+#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */
+#endif /* NO_NSPR_10_SUPPORT */
+
+/*
+** Get the priority of "thread".
+*/
+NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread);
+
+/*
+** Change the priority of the "thread" to "priority".
+*/
+NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority);
+
+/*
+** This routine returns a new index for per-thread-private data table. 
+** The index is visible to all threads within a process. This index can 
+** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 
+** to save and retrieve data associated with the index for a thread.
+**
+** Each index is associationed with a destructor function ('dtor'). The function
+** may be specified as NULL when the index is created. If it is not NULL, the
+** function will be called when:
+**      - the thread exits and the private data for the associated index
+**        is not NULL,
+**      - new thread private data is set and the current private data is
+**        not NULL.
+**
+** The index independently maintains specific values for each binding thread. 
+** A thread can only get access to its own thread-specific-data.
+**
+** Upon a new index return the value associated with the index for all threads
+** is NULL, and upon thread creation the value associated with all indices for 
+** that thread is NULL. 
+**
+** Returns PR_FAILURE if the total number of indices will exceed the maximun 
+** allowed.
+*/
+typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv);
+
+NSPR_API(PRStatus) PR_NewThreadPrivateIndex(
+    PRUintn *newIndex, PRThreadPrivateDTOR destructor);
+
+/*
+** Define some per-thread-private data.
+**     "tpdIndex" is an index into the per-thread private data table
+**     "priv" is the per-thread-private data 
+**
+** If the per-thread private data table has a previously registered
+** destructor function and a non-NULL per-thread-private data value,
+** the destructor function is invoked.
+**
+** This can return PR_FAILURE if the index is invalid.
+*/
+NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv);
+
+/*
+** Recover the per-thread-private data for the current thread. "tpdIndex" is
+** the index into the per-thread private data table. 
+**
+** The returned value may be NULL which is indistinguishable from an error 
+** condition.
+**
+** A thread can only get access to its own thread-specific-data.
+*/
+NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex);
+
+/*
+** This routine sets the interrupt request for a target thread. The interrupt
+** request remains in the thread's state until it is delivered exactly once
+** or explicitly canceled.
+**
+** A thread that has been interrupted will fail all NSPR blocking operations
+** that return a PRStatus (I/O, waiting on a condition, etc).
+**
+** PR_Interrupt may itself fail if the target thread is invalid.
+*/
+NSPR_API(PRStatus) PR_Interrupt(PRThread *thread);
+
+/*
+** Clear the interrupt request for the calling thread. If no such request
+** is pending, this operation is a noop.
+*/
+NSPR_API(void) PR_ClearInterrupt(void);
+
+/*
+** Block the interrupt for the calling thread.
+*/
+NSPR_API(void) PR_BlockInterrupt(void);
+
+/*
+** Unblock the interrupt for the calling thread.
+*/
+NSPR_API(void) PR_UnblockInterrupt(void);
+
+/*
+** Make the current thread sleep until "ticks" time amount of time
+** has expired. If "ticks" is PR_INTERVAL_NO_WAIT then the call is
+** equivalent to calling PR_Yield. Calling PR_Sleep with an argument
+** equivalent to PR_INTERVAL_NO_TIMEOUT is an error and will result
+** in a PR_FAILURE error return.
+*/
+NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks);
+
+/*
+** Get the scoping of this thread.
+*/
+NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread);
+
+/*
+** Get the type of this thread.
+*/
+NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread);
+
+/*
+** Get the join state of this thread.
+*/
+NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread);
+
+PR_END_EXTERN_C
+
+#endif /* prthread_h___ */
diff --git a/mozilla/nsprpub/pr/include/prtime.h b/mozilla/nsprpub/pr/include/prtime.h
new file mode 100644
index 0000000..7f00f67
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prtime.h
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * prtime.h --
+ *
+ *     NSPR date and time functions
+ *
+ *-----------------------------------------------------------------------
+ */
+
+#ifndef prtime_h___
+#define prtime_h___
+
+#include "prlong.h"
+
+PR_BEGIN_EXTERN_C
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+#define PR_MSEC_PER_SEC		1000UL
+#define PR_USEC_PER_SEC		1000000UL
+#define PR_NSEC_PER_SEC		1000000000UL
+#define PR_USEC_PER_MSEC	1000UL
+#define PR_NSEC_PER_MSEC	1000000UL
+
+/*
+ * PRTime --
+ *
+ *     NSPR represents basic time as 64-bit signed integers relative
+ *     to midnight (00:00:00), January 1, 1970 Greenwich Mean Time (GMT).
+ *     (GMT is also known as Coordinated Universal Time, UTC.)
+ *     The units of time are in microseconds. Negative times are allowed
+ *     to represent times prior to the January 1970 epoch. Such values are
+ *     intended to be exported to other systems or converted to human
+ *     readable form.
+ *
+ *     Notes on porting: PRTime corresponds to time_t in ANSI C.  NSPR 1.0
+ *     simply uses PRInt64.
+ */
+
+typedef PRInt64 PRTime;
+
+/*
+ * Time zone and daylight saving time corrections applied to GMT to
+ * obtain the local time of some geographic location
+ */
+
+typedef struct PRTimeParameters {
+    PRInt32 tp_gmt_offset;     /* the offset from GMT in seconds */
+    PRInt32 tp_dst_offset;     /* contribution of DST in seconds */
+} PRTimeParameters;
+
+/*
+ * PRExplodedTime --
+ *
+ *     Time broken down into human-readable components such as year, month,
+ *     day, hour, minute, second, and microsecond.  Time zone and daylight
+ *     saving time corrections may be applied.  If they are applied, the
+ *     offsets from the GMT must be saved in the 'tm_params' field so that
+ *     all the information is available to reconstruct GMT.
+ *
+ *     Notes on porting: PRExplodedTime corrresponds to struct tm in
+ *     ANSI C, with the following differences:
+ *       - an additional field tm_usec;
+ *       - replacing tm_isdst by tm_params;
+ *       - the month field is spelled tm_month, not tm_mon;
+ *       - we use absolute year, AD, not the year since 1900.
+ *     The corresponding type in NSPR 1.0 is called PRTime.  Below is
+ *     a table of date/time type correspondence in the three APIs:
+ *         API          time since epoch          time in components
+ *       ANSI C             time_t                  struct tm
+ *       NSPR 1.0           PRInt64                   PRTime
+ *       NSPR 2.0           PRTime                  PRExplodedTime
+ */
+
+typedef struct PRExplodedTime {
+    PRInt32 tm_usec;		    /* microseconds past tm_sec (0-99999)  */
+    PRInt32 tm_sec;             /* seconds past tm_min (0-61, accomodating
+                                   up to two leap seconds) */
+    PRInt32 tm_min;             /* minutes past tm_hour (0-59) */
+    PRInt32 tm_hour;            /* hours past tm_day (0-23) */
+    PRInt32 tm_mday;            /* days past tm_mon (1-31, note that it
+				                starts from 1) */
+    PRInt32 tm_month;           /* months past tm_year (0-11, Jan = 0) */
+    PRInt16 tm_year;            /* absolute year, AD (note that we do not
+				                count from 1900) */
+
+    PRInt8 tm_wday;		        /* calculated day of the week
+				                (0-6, Sun = 0) */
+    PRInt16 tm_yday;            /* calculated day of the year
+				                (0-365, Jan 1 = 0) */
+
+    PRTimeParameters tm_params;  /* time parameters used by conversion */
+} PRExplodedTime;
+
+/*
+ * PRTimeParamFn --
+ *
+ *     A function of PRTimeParamFn type returns the time zone and
+ *     daylight saving time corrections for some geographic location,
+ *     given the current time in GMT.  The input argument gmt should
+ *     point to a PRExplodedTime that is in GMT, i.e., whose
+ *     tm_params contains all 0's.
+ *
+ *     For any time zone other than GMT, the computation is intended to
+ *     consist of two steps:
+ *       - Figure out the time zone correction, tp_gmt_offset.  This number
+ *         usually depends on the geographic location only.  But it may
+ *         also depend on the current time.  For example, all of China
+ *         is one time zone right now.  But this situation may change
+ *         in the future.
+ *       - Figure out the daylight saving time correction, tp_dst_offset.
+ *         This number depends on both the geographic location and the
+ *         current time.  Most of the DST rules are expressed in local
+ *         current time.  If so, one should apply the time zone correction
+ *         to GMT before applying the DST rules.
+ */
+
+typedef PRTimeParameters (PR_CALLBACK *PRTimeParamFn)(const PRExplodedTime *gmt);
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+/*
+ * The PR_Now routine returns the current time relative to the
+ * epoch, midnight, January 1, 1970 UTC. The units of the returned
+ * value are microseconds since the epoch.
+ *
+ * The values returned are not guaranteed to advance in a linear fashion
+ * due to the application of time correction protocols which synchronize
+ * computer clocks to some external time source. Consequently it should
+ * not be depended on for interval timing.
+ *
+ * The implementation is machine dependent.
+ * Cf. time_t time(time_t *tp) in ANSI C.
+ */
+NSPR_API(PRTime)
+PR_Now(void);
+
+/*
+ * Expand time binding it to time parameters provided by PRTimeParamFn.
+ * The calculation is envisoned to proceed in the following steps:
+ *   - From given PRTime, calculate PRExplodedTime in GMT
+ *   - Apply the given PRTimeParamFn to the GMT that we just calculated
+ *     to obtain PRTimeParameters.
+ *   - Add the PRTimeParameters offsets to GMT to get the local time
+ *     as PRExplodedTime.
+ */
+
+NSPR_API(void) PR_ExplodeTime(
+    PRTime usecs, PRTimeParamFn params, PRExplodedTime *exploded);
+
+/* Reverse operation of PR_ExplodeTime */
+NSPR_API(PRTime)
+PR_ImplodeTime(const PRExplodedTime *exploded);
+
+/*
+ * Adjust exploded time to normalize field overflows after manipulation.
+ * Note that the following fields of PRExplodedTime should not be
+ * manipulated:
+ *   - tm_month and tm_year: because the number of days in a month and
+ *     number of days in a year are not constant, it is ambiguous to
+ *     manipulate the month and year fields, although one may be tempted
+ *     to.  For example, what does "a month from January 31st" mean?
+ *   - tm_wday and tm_yday: these fields are calculated by NSPR.  Users
+ *     should treat them as "read-only".
+ */
+
+NSPR_API(void) PR_NormalizeTime(
+    PRExplodedTime *exploded, PRTimeParamFn params);
+
+/**********************************************************************/
+/*********************** TIME PARAMETER FUNCTIONS *********************/
+/**********************************************************************/
+
+/* Time parameters that suit current host machine */
+NSPR_API(PRTimeParameters) PR_LocalTimeParameters(const PRExplodedTime *gmt);
+
+/* Time parameters that represent Greenwich Mean Time */
+NSPR_API(PRTimeParameters) PR_GMTParameters(const PRExplodedTime *gmt);
+
+/*
+ * Time parameters that represent the US Pacific Time Zone, with the
+ * current daylight saving time rules (for testing only)
+ */
+NSPR_API(PRTimeParameters) PR_USPacificTimeParameters(const PRExplodedTime *gmt);
+
+/*
+ * This parses a time/date string into a PRExplodedTime
+ * struct. It populates all fields but it can't split
+ * the offset from UTC into tp_gmt_offset and tp_dst_offset in
+ * most cases (exceptions: PST/PDT, MST/MDT, CST/CDT, EST/EDT, GMT/BST).
+ * In those cases tp_gmt_offset will be the sum of these two and
+ * tp_dst_offset will be 0.
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ *
+ * Many formats are handled, including:
+ *
+ *   14 Apr 89 03:20:12
+ *   14 Apr 89 03:20 GMT
+ *   Fri, 17 Mar 89 4:01:33
+ *   Fri, 17 Mar 89 4:01 GMT
+ *   Mon Jan 16 16:12 PDT 1989
+ *   Mon Jan 16 16:12 +0130 1989
+ *   6 May 1992 16:41-JST (Wednesday)
+ *   22-AUG-1993 10:59:12.82
+ *   22-AUG-1993 10:59pm
+ *   22-AUG-1993 12:59am
+ *   22-AUG-1993 12:59 PM
+ *   Friday, August 04, 1995 3:54 PM
+ *   06/21/95 04:24:34 PM
+ *   20/06/95 21:07
+ *   95-06-08 19:32:48 EDT
+ *
+ * If the input string doesn't contain a description of the timezone,
+ * we consult the `default_to_gmt' to decide whether the string should
+ * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
+ * The correct value for this argument depends on what standard specified
+ * the time string which you are parsing.
+ */
+
+NSPR_API(PRStatus) PR_ParseTimeStringToExplodedTime (
+        const char *string,
+        PRBool default_to_gmt,
+        PRExplodedTime *result);
+
+/*
+ * This uses PR_ParseTimeStringToExplodedTime to parse
+ * a time/date string and PR_ImplodeTime to transform it into
+ * a PRTime (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ */
+
+NSPR_API(PRStatus) PR_ParseTimeString (
+	const char *string,
+	PRBool default_to_gmt,
+	PRTime *result);
+
+/*
+ * FIXME: should we also have a formatting function, such as asctime, ctime,
+ * and strftime in standard C library?  But this would involve
+ * internationalization issues.  Might want to provide a US English version.
+ */
+
+/**********************************************************************/
+/*********************** OLD COMPATIBILITYFUNCTIONS *******************/
+/**********************************************************************/
+#ifndef NO_NSPR_10_SUPPORT
+
+/* Format a time value into a buffer. Same semantics as strftime() */
+NSPR_API(PRUint32) PR_FormatTime(char *buf, int buflen, const char *fmt,
+                                           const PRExplodedTime *tm);
+
+/* Format a time value into a buffer. Time is always in US English format, regardless
+ * of locale setting.
+ */
+NSPR_API(PRUint32)
+PR_FormatTimeUSEnglish( char* buf, PRUint32 bufSize,
+                        const char* format, const PRExplodedTime* tm );
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+PR_END_EXTERN_C
+
+#endif /* prtime_h___ */
diff --git a/mozilla/nsprpub/pr/include/prtpool.h b/mozilla/nsprpub/pr/include/prtpool.h
new file mode 100644
index 0000000..2e1f6dd
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prtpool.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+#ifndef prtpool_h___
+#define prtpool_h___
+
+#include "prtypes.h"
+#include "prthread.h"
+#include "prio.h"
+#include "prerror.h"
+
+/*
+ * NOTE:
+ *		THIS API IS A PRELIMINARY VERSION IN NSPR 4.0 AND IS SUBJECT TO
+ *		CHANGE
+ */
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PRJobIoDesc {
+    PRFileDesc *socket;
+    PRErrorCode error;
+    PRIntervalTime timeout;
+} PRJobIoDesc;
+
+typedef struct PRThreadPool PRThreadPool;
+typedef struct PRJob PRJob;
+typedef void (PR_CALLBACK *PRJobFn) (void *arg);
+
+/* Create thread pool */
+NSPR_API(PRThreadPool *)
+PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads,
+                          PRUint32 stacksize);
+
+/* queue a job */
+NSPR_API(PRJob *)
+PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable);
+
+/* queue a job, when a socket is readable */
+NSPR_API(PRJob *)
+PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod,
+							PRJobFn fn, void * arg, PRBool joinable);
+
+/* queue a job, when a socket is writeable */
+NSPR_API(PRJob *)
+PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod,
+								PRJobFn fn, void * arg, PRBool joinable);
+
+/* queue a job, when a socket has a pending connection */
+NSPR_API(PRJob *)
+PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod,
+									PRJobFn fn, void * arg, PRBool joinable);
+
+/* queue a job, when the socket connection to addr succeeds or fails */
+NSPR_API(PRJob *)
+PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod,
+			const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable);
+
+/* queue a job, when a timer exipres */
+NSPR_API(PRJob *)
+PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout,
+								PRJobFn fn, void * arg, PRBool joinable);
+/* cancel a job */
+NSPR_API(PRStatus)
+PR_CancelJob(PRJob *job);
+
+/* join a job */
+NSPR_API(PRStatus)
+PR_JoinJob(PRJob *job);
+
+/* shutdown pool */
+NSPR_API(PRStatus)
+PR_ShutdownThreadPool(PRThreadPool *tpool);
+
+/* join pool, wait for exit of all threads */
+NSPR_API(PRStatus)
+PR_JoinThreadPool(PRThreadPool *tpool);
+
+PR_END_EXTERN_C
+
+#endif /* prtpool_h___ */
diff --git a/mozilla/nsprpub/pr/include/prtrace.h b/mozilla/nsprpub/pr/include/prtrace.h
new file mode 100644
index 0000000..42f88e9
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prtrace.h
@@ -0,0 +1,678 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prtrace_h___
+#define prtrace_h___
+/*
+** prtrace.h -- NSPR's Trace Facility.  		           
+**                                                               		           
+** The Trace Facility provides a means to trace application				           
+** program events within a process. When implementing an         		           
+** application program an engineer may insert a "Trace" function 		           
+** call, passing arguments to be traced. The "Trace" function     		           
+** combines the user trace data with identifying data and        		           
+** writes this data in time ordered sequence into a circular     		           
+** in-memory buffer; when the buffer fills, it wraps.
+**                                                               		           
+** Functions are provided to set and/or re-configure the size of		           
+** the trace buffer, control what events are recorded in the			           
+** buffer, enable and disable tracing based on specific user			           
+** supplied data and other control functions. Methods are provided		           
+** to record the trace entries in the in-memory trace buffer to
+** a file.
+**                                                               		           
+** Tracing may cause a performance degredation to the application		           
+** depending on the number and placement of calls to the tracing		           
+** facility. When tracing is compiled in and all tracing is				           
+** disabled via the runtime controls, the overhead should be			           
+** minimal. ... Famous last words, eh?									           
+** 																                   
+** When DEBUG is defined at compile time, the Trace Facility is                    
+** compiled as part of NSPR and any application using NSPR's                       
+** header files will have tracing compiled in. When DEBUG is not                   
+** defined, the Trace Facility is not compiled into NSPR nor                       
+** exported in its header files.  If the Trace Facility is                         
+** desired in a non-debug build, then FORCE_NSPR_TRACE may be                      
+** defined at compile time for both the optimized build of NSPR                    
+** and the application. NSPR and any application using  NSPR's                     
+** Trace Facility must be compiled with the same level of trace                    
+** conditioning or unresolved references may be realized at link                   
+** time.                                                                           
+**                                                                                 
+** For any of the Trace Facility methods that requires a trace                     
+** handle as an input argument, the caller must ensure that the                    
+** trace handle argument is valid. An invalid trace handle                         
+** argument may cause unpredictable results.                                       
+**                                                                                 
+** Trace Facility methods are thread-safe and SMP safe.                            
+**                                                                                 
+** Users of the Trace Facility should use the defined macros to                     
+** invoke trace methods, not the function calls directly. e.g.                      
+** PR_TRACE( h1,0,1,2, ...); not PR_Trace(h1,0,1,2, ...);
+**                                                                                  
+** Application designers should be aware of the effects of
+** debug and optimized build differences when using result of the
+** Trace Facility macros in expressions.
+** 
+** See Also: prcountr.h                                                                                 
+**                                                                                  
+** /lth. 08-Jun-1998.                                                                                  
+*/
+
+#include "prtypes.h"
+#include "prthread.h"
+#include "prtime.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Opaque type for the trace handle 
+** ... Don't even think about looking in here.
+**
+*/
+typedef void *  PRTraceHandle;
+
+/*
+** PRTraceEntry -- A trace entry in the in-memory trace buffer
+** looks like this.
+**
+*/
+typedef struct PRTraceEntry
+{
+    PRThread        *thread;        /* The thread creating the trace entry */
+    PRTraceHandle   handle;         /* PRTraceHandle creating the trace entry */
+    PRTime          time;           /* Value of PR_Now() at time of trace entry */
+    PRUint32        userData[8];    /* user supplied trace data */
+} PRTraceEntry;
+
+/*
+** PRTraceOption -- command operands to
+** PR_[Set|Get]TraceOption(). See descriptive meanings there.
+**
+*/
+typedef enum PRTraceOption
+{
+    PRTraceBufSize,
+    PRTraceEnable,              
+    PRTraceDisable,
+    PRTraceSuspend,
+    PRTraceResume,
+    PRTraceSuspendRecording,
+    PRTraceResumeRecording,
+    PRTraceLockHandles,
+    PRTraceUnLockHandles,
+    PRTraceStopRecording
+} PRTraceOption;
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_DEFINE_TRACE() -- Define a PRTraceHandle
+** 
+** DESCRIPTION: PR_DEFINE_TRACE() is used to define a trace
+** handle.
+** 
+*/
+#define PR_DEFINE_TRACE(name) PRTraceHandle name
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_INIT_TRACE_HANDLE() -- Set the value of a PRTraceHandle
+** 
+** DESCRIPTION: 
+** PR_INIT_TRACE_HANDLE() sets the value of a PRTraceHandle
+** to value. e.g. PR_INIT_TRACE_HANDLE( myHandle, NULL );
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_INIT_TRACE_HANDLE(handle,value)\
+    (handle) = (PRCounterHandle)(value)
+#else
+#define PR_INIT_TRACE_HANDLE(handle,value)
+#endif
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_CreateTrace() -- Create a trace handle
+** 
+** DESCRIPTION:
+**  PR_CreateTrace() creates a new trace handle. Tracing is
+**  enabled for this handle when it is created. The trace handle
+**  is intended for use in other Trace Facility calls.
+**  
+**  PR_CreateTrace() registers the QName, RName and description
+**  data so that this data can be retrieved later.
+** 
+** INPUTS: 
+**  qName: pointer to string. QName for this trace handle. 
+** 
+**  rName: pointer to string. RName for this trace handle. 
+** 
+**  description: pointer to string. Descriptive data about this
+**  trace handle.
+**
+** OUTPUTS:
+**  Creates the trace handle. 
+**  Registers the QName and RName with the trace facility.
+** 
+** RETURNS: 
+**  PRTraceHandle
+** 
+** RESTRICTIONS:
+**  qName is limited to 31 characters.
+**  rName is limited to 31 characters.
+**  description is limited to 255 characters.
+** 
+*/
+#define PRTRACE_NAME_MAX 31
+#define PRTRACE_DESC_MAX 255
+
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_CREATE_TRACE(handle,qName,rName,description)\
+    (handle) = PR_CreateTrace((qName),(rName),(description))
+#else
+#define PR_CREATE_TRACE(handle,qName,rName,description)
+#endif
+
+NSPR_API(PRTraceHandle)
+	PR_CreateTrace( 
+    	const char *qName,          /* QName for this trace handle */
+	    const char *rName,          /* RName for this trace handle */
+	    const char *description     /* description for this trace handle */
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_DestroyTrace() -- Destroy a trace handle
+** 
+** DESCRIPTION: 
+**  PR_DestroyTrace() removes the referenced trace handle and
+** associated QName, RName and description data from the Trace
+** Facility.
+** 
+** INPUTS: handle. A PRTraceHandle
+** 
+** OUTPUTS: 
+**  The trace handle is unregistered.
+**  The QName, RName and description are removed.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_DESTROY_TRACE(handle)\
+    PR_DestroyTrace((handle))
+#else
+#define PR_DESTROY_TRACE(handle)
+#endif
+
+NSPR_API(void) 
+	PR_DestroyTrace( 
+		PRTraceHandle handle    /* Handle to be destroyed */
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_Trace() -- Make a trace entry in the in-memory trace
+** 
+** DESCRIPTION:
+** PR_Trace() makes an entry in the in-memory trace buffer for
+** the referenced trace handle. The next logically available
+** PRTraceEntry is used; when the next trace entry would overflow
+** the trace table, the table wraps.
+**
+** PR_Trace() for a specific trace handle may be disabled by
+** calling PR_SetTraceOption() specifying PRTraceDisable for the
+** trace handle to be disabled.
+** 
+** INPUTS:
+** handle: PRTraceHandle. The trace handle for this trace.
+** 
+** userData[0..7]: unsigned 32bit integers. user supplied data
+** that is copied into the PRTraceEntry
+** 
+** OUTPUTS:
+**  A PRTraceEntry is (conditionally) formatted in the in-memory
+** trace buffer.
+** 
+** RETURNS: void.
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7)\
+    PR_Trace((handle),(ud0),(ud1),(ud2),(ud3),(ud4),(ud5),(ud6),(ud7))
+#else
+#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7)
+#endif
+
+NSPR_API(void) 
+	PR_Trace( 
+    	PRTraceHandle handle,       /* use this trace handle */
+	    PRUint32    userData0,      /* User supplied data word 0 */
+	    PRUint32    userData1,      /* User supplied data word 1 */
+	    PRUint32    userData2,      /* User supplied data word 2 */
+	    PRUint32    userData3,      /* User supplied data word 3 */
+	    PRUint32    userData4,      /* User supplied data word 4 */
+	    PRUint32    userData5,      /* User supplied data word 5 */
+	    PRUint32    userData6,      /* User supplied data word 6 */
+	    PRUint32    userData7       /* User supplied data word 7 */
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_SetTraceOption() -- Control the Trace Facility
+** 
+** DESCRIPTION:
+** PR_SetTraceOption() controls the Trace Facility. Depending on
+** command and value, attributes of the Trace Facility may be
+** changed.
+** 
+** INPUTS:
+**  command: An enumerated value in the set of PRTraceOption.
+**  value: pointer to the data to be set. Type of the data is
+**  dependent on command; for each value of command, the type
+**  and meaning of dereferenced value is shown.
+**
+**  PRTraceBufSize: unsigned long: the size of the trace buffer,
+** in bytes.
+** 
+**  PRTraceEnable: PRTraceHandle. The trace handle to be
+** enabled.
+** 
+**  PRTraceDisable: PRTraceHandle. The trace handle to be
+** disabled.
+** 
+**  PRTraceSuspend: void. value must be NULL. All tracing is
+** suspended.
+** 
+**  PRTraceResume: void. value must be NULL. Tracing for all
+** previously enabled, prior to a PRTraceSuspend, is resumed.
+** 
+**  PRTraceStopRecording: void. value must be NULL. If recording
+** (see: ** PR_RecordTraceEntries()) is being done, 
+** PRTraceStopRecording causes PR_RecordTraceEntries() to return
+** to its caller. If recording is not being done, this function
+** has no effect.
+** 
+**  PRTraceSuspendRecording: void. Must be NULL. If recording is
+** being done, PRTraceSuspendRecording causes further writes to
+** the trace file to be suspended. Data in the in-memory
+** trace buffer that would ordinarily be written to the
+** trace file will not be written. Trace entries will continue
+** to be entered in the in-memory buffer. If the Trace Facility
+** recording is already in a suspended state, the call has no
+** effect.
+** 
+**  PRTraceResumeRecording: void. value must be NULL. If
+** recording for the Trace Facility has been previously been
+** suspended, this causes recording to resume. Recording resumes
+** with the next in-memory buffer segment that would be written
+** if trace recording had not been suspended. If recording is
+** not currently suspended, the call has no effect.
+** 
+**  PRTraceLockHandles: void. value must be NULL. Locks the
+** trace handle lock. While the trace handle lock is held,
+** calls to PR_CreateTrace() will block until the lock is
+** released.
+** 
+**  PRTraceUnlockHandles: void. value must be NULL. Unlocks the
+** trace handle lock.
+** 
+** OUTPUTS:
+**  The operation of the Trace Facility may be changed.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_SET_TRACE_OPTION(command,value)\
+    PR_SetTraceOption((command),(value))
+#else
+#define PR_SET_TRACE_OPTION(command,value)
+#endif
+
+NSPR_API(void) 
+	PR_SetTraceOption( 
+	    PRTraceOption command,  /* One of the enumerated values */
+	    void *value             /* command value or NULL */
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_GetTraceOption() -- Retrieve settings from the Trace Facility
+** 
+** DESCRIPTION:
+** PR_GetTraceOption() retrieves the current setting of the
+** Trace Facility control depending on command.
+** 
+** 
+**  PRTraceBufSize: unsigned long: the size of the trace buffer,
+** in bytes.
+** 
+** 
+** INPUTS:
+**  command: one of the enumerated values in PRTraceOptions
+** valid for PR_GetTraceOption().
+** 
+** OUTPUTS:
+**  dependent on command.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_GET_TRACE_OPTION(command,value)\
+    PR_GetTraceOption((command),(value))
+#else
+#define PR_GET_TRACE_OPTION(command,value)
+#endif
+
+NSPR_API(void) 
+	PR_GetTraceOption( 
+    	PRTraceOption command,  /* One of the enumerated values */
+	    void *value             /* command value or NULL */
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_GetTraceHandleFromName() -- Retrieve an existing
+** handle by name.
+** 
+** DESCRIPTION:
+** PR_GetTraceHandleFromName() retreives an existing tracehandle
+** using the name specified by qName and rName.
+** 
+** INPUTS:
+**  qName: pointer to string. QName for this trace handle. 
+** 
+**  rName: pointer to string. RName for this trace handle. 
+** 
+** 
+** OUTPUTS: returned.
+** 
+** RETURNS: 
+**  PRTraceHandle associated with qName and rName or NULL when
+** there is no match.
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName)\
+    (handle) = PR_GetTraceHandleFromName((qName),(rName))
+#else
+#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName)
+#endif
+
+NSPR_API(PRTraceHandle) 
+	PR_GetTraceHandleFromName( 
+    	const char *qName,      /* QName search argument */
+        const char *rName       /* RName search argument */
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_GetTraceNameFromHandle() -- Retreive trace name
+** by bandle.
+** 
+** DESCRIPTION:
+** PR_GetTraceNameFromHandle() retreives the existing qName,
+** rName, and description for the referenced trace handle.
+** 
+** INPUTS: handle: PRTraceHandle.
+** 
+** OUTPUTS: pointers to the Trace Facility's copy of qName,
+** rName and description. ... Don't mess with these values.
+** They're mine.
+** 
+** RETURNS: void
+** 
+** RESTRICTIONS:
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description)\
+    PR_GetTraceNameFromHandle((handle),(qName),(rName),(description))
+#else
+#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description)
+#endif
+
+NSPR_API(void) 
+	PR_GetTraceNameFromHandle( 
+    	PRTraceHandle handle,       /* handle as search argument */
+	    const char **qName,         /* pointer to associated QName */
+	    const char **rName,         /* pointer to associated RName */
+    	const char **description    /* pointer to associated description */
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_FindNextTraceQname() -- Retrieive a QName handle
+** iterator.
+** 
+** DESCRIPTION:
+** PR_FindNextTraceQname() retreives the first or next trace
+** QName handle, depending on the value of handle, from the trace
+** database. The PRTraceHandle returned can be used as an
+** iterator to traverse the QName handles in the Trace database.
+** 
+** INPUTS:
+**  handle: When NULL, PR_FindNextQname() returns the first QName
+** handle. When a handle is a valid PRTraceHandle previously
+** retreived using PR_FindNextQname() the next QName handle is
+** retreived.
+** 
+** OUTPUTS: returned.
+** 
+** RETURNS: 
+**  PRTraceHandle or NULL when there are no trace handles.
+** 
+** RESTRICTIONS:
+**  Iterating thru the trace handles via FindFirst/FindNext
+** should be done under protection of the trace handle lock.
+** See: PR_SetTraceOption( PRLockTraceHandles ).
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_FIND_NEXT_TRACE_QNAME(next,handle)\
+    (next) = PR_FindNextTraceQname((handle))
+#else
+#define PR_FIND_NEXT_TRACE_QNAME(next,handle)
+#endif
+
+NSPR_API(PRTraceHandle) 
+	PR_FindNextTraceQname( 
+        PRTraceHandle handle
+);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_FindNextTraceRname() -- Retrieive an RName handle
+** iterator.
+** 
+** DESCRIPTION:
+** PR_FindNextTraceRname() retreives the first or next trace
+** RName handle, depending on the value of handle, from the trace
+** database. The PRTraceHandle returned can be used as an
+** iterator to traverse the RName handles in the Trace database.
+** 
+** INPUTS:
+**  rhandle: When NULL, PR_FindNextRname() returns the first
+** RName handle. When a handle is a valid PRTraceHandle
+** previously retreived using PR_FindNextRname() the next RName
+** handle is retreived.
+**  qhandle: A valid PRTraceHandle retruned from a previous call
+** to PR_FIND_NEXT_TRACE_QNAME().
+** 
+** OUTPUTS: returned.
+** 
+** RETURNS: 
+**  PRTraceHandle or NULL when there are no trace handles.
+** 
+** RESTRICTIONS:
+**  Iterating thru the trace handles via FindNext should be done
+** under protection of the trace handle lock. See: (
+** PR_SetTraceOption( PRLockTraceHandles ).
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle)\
+    (next) = PR_FindNextTraceRname((rhandle),(qhandle))
+#else
+#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle)
+#endif
+
+NSPR_API(PRTraceHandle) 
+	PR_FindNextTraceRname( 
+        PRTraceHandle rhandle,
+        PRTraceHandle qhandle
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_RecordTraceEntries() -- Write trace entries to external media
+** 
+** DESCRIPTION:
+** PR_RecordTraceEntries() causes entries in the in-memory trace
+** buffer to be written to external media.
+**
+** When PR_RecordTraceEntries() is called from an application
+** thread, the function appears to block until another thread
+** calls PR_SetTraceOption() with the PRTraceStopRecording
+** option. This suggests that PR_RecordTraceEntries() should be
+** called from a user supplied thread whose only job is to
+** record trace entries. 
+** 
+** The environment variable NSPR_TRACE_LOG controls the operation
+** of this function. When NSPR_TRACE_LOG is not defined in the
+** environment, no recording of trace entries occurs. When
+** NSPR_TRACE_LOG is defined, the value of its definition must be
+** the filename of the file to receive the trace entry buffer.
+**
+** PR_RecordTraceEntries() attempts to record the in-memory
+** buffer to a file, subject to the setting of the environment
+** variable NSPR_TRACE_LOG. It is possible because of system
+** load, the thread priority of the recording thread, number of
+** active trace records being written over time, and other
+** variables that some trace records can be lost. ... In other
+** words: don't bet the farm on getting everything.
+** 
+** INPUTS: none
+** 
+** OUTPUTS: none
+** 
+** RETURNS: PR_STATUS
+**    PR_SUCCESS no errors were found.
+**    PR_FAILURE errors were found.
+** 
+** RESTRICTIONS:
+** Only one thread can call PR_RecordTraceEntries() within a
+** process.
+** 
+** On error, PR_RecordTraceEntries() may return prematurely.
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_RECORD_TRACE_ENTRIES()\
+	PR_RecordTraceEntries()
+#else
+#define PR_RECORD_TRACE_ENTRIES()
+#endif
+    
+NSPR_API(void)
+	PR_RecordTraceEntries(
+        void 
+);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PR_GetTraceEntries() -- Retreive trace entries from
+** the Trace Facility
+** 
+** DESCRIPTION:
+** PR_GetTraceEntries() retreives trace entries from the Trace
+** Facility. Up to count trace entries are copied from the Trace
+** Facility into buffer. Only those trace entries that have not
+** been copied via a previous call to PR_GetTraceEntries() are
+** copied. The actual number copied is placed in the PRInt32
+** variable pointed to by found.
+**
+** If more than count trace entries have entered the Trace
+** Facility since the last call to PR_GetTraceEntries() 
+** a lost data condition is returned. In this case, the most
+** recent count trace entries are copied into buffer and found is
+** set to count.
+** 
+** INPUTS:
+**  count. The number of trace entries to be copied into buffer.
+** 
+** 
+** OUTPUTS:
+**  buffer. An array of PRTraceEntries. The buffer is supplied
+** by the caller.
+** 
+** found: 32bit signed integer. The number of PRTraceEntries
+** actually copied. found is always less than or equal to count.
+** 
+** RETURNS: 
+**  zero when there is no lost data.
+**  non-zero when some PRTraceEntries have been lost.
+** 
+** RESTRICTIONS:
+** This is a real performance pig. The copy out operation is bad
+** enough, but depending on then frequency of calls to the
+** function, serious performance impact to the operating
+** application may be realized. ... YMMV.
+** 
+*/
+#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)
+#define PR_GET_TRACE_ENTRIES(buffer,count,found)\
+        PR_GetTraceEntries((buffer),(count),(found))
+#else
+#define PR_GET_TRACE_ENTRIES(buffer,count,found)
+#endif
+
+NSPR_API(PRIntn)
+    PR_GetTraceEntries(
+        PRTraceEntry    *buffer,    /* where to write output */
+        PRInt32         count,      /* number to get */
+        PRInt32         *found      /* number you got */
+);
+
+PR_END_EXTERN_C
+
+#endif /* prtrace_h___ */
+
diff --git a/mozilla/nsprpub/pr/include/prtypes.h b/mozilla/nsprpub/pr/include/prtypes.h
new file mode 100644
index 0000000..85805a9
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prtypes.h
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:                prtypes.h
+** Description: Definitions of NSPR's basic types
+**
+** Prototypes and macros used to make up for deficiencies that we have found
+** in ANSI environments.
+**
+** Since we do not wrap <stdlib.h> and all the other standard headers, authors
+** of portable code will not know in general that they need these definitions.
+** Instead of requiring these authors to find the dependent uses in their code
+** and take the following steps only in those C files, we take steps once here
+** for all C files.
+**/
+
+#ifndef prtypes_h___
+#define prtypes_h___
+
+#ifdef MDCPUCFG
+#include MDCPUCFG
+#else
+#include "prcpucfg.h"
+#endif
+
+#include <stddef.h>
+
+/***********************************************************************
+** MACROS:      PR_EXTERN
+**              PR_IMPLEMENT
+** DESCRIPTION:
+**      These are only for externally visible routines and globals.  For
+**      internal routines, just use "extern" for type checking and that
+**      will not export internal cross-file or forward-declared symbols.
+**      Define a macro for declaring procedures return types. We use this to
+**      deal with windoze specific type hackery for DLL definitions. Use
+**      PR_EXTERN when the prototype for the method is declared. Use
+**      PR_IMPLEMENT for the implementation of the method.
+**
+** Example:
+**   in dowhim.h
+**     PR_EXTERN( void ) DoWhatIMean( void );
+**   in dowhim.c
+**     PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; }
+**
+**
+***********************************************************************/
+#if 1  /* STATIC LIBRARIES */
+
+#define PR_EXPORT(__type) extern __type
+#define PR_EXPORT_DATA(__type) extern __type
+#define PR_IMPORT(__type) extern __type
+#define PR_IMPORT_DATA(__type) extern __type
+
+#define PR_EXTERN(__type) extern __type
+#define PR_IMPLEMENT(__type) __type
+#define PR_EXTERN_DATA(__type) extern __type
+#define PR_IMPLEMENT_DATA(__type) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(WIN32)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) __declspec(dllimport) __type
+#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(XP_BEOS)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(XP_OS2) && defined(__declspec)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) extern  __declspec(dllimport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(SYMBIAN)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#ifdef __WINS__
+#define PR_IMPORT(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type
+#else
+#define PR_IMPORT(__type) extern __declspec(dllimport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type
+#endif
+
+#define PR_EXTERN(__type) extern __type
+#define PR_IMPLEMENT(__type) __type
+#define PR_EXTERN_DATA(__type) extern __type
+#define PR_IMPLEMENT_DATA(__type) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#else /* Unix */
+
+/* GCC 3.3 and later support the visibility attribute. */
+#if (__GNUC__ >= 4) || \
+    (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default")))
+#else
+#define PR_VISIBILITY_DEFAULT
+#endif
+
+#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+
+#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type
+#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#endif
+
+#if defined(_NSPR_BUILD_)
+#define NSPR_API(__type) PR_EXPORT(__type)
+#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type)
+#else
+#define NSPR_API(__type) PR_IMPORT(__type)
+#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type)
+#endif
+
+/***********************************************************************
+** MACROS:      PR_BEGIN_MACRO
+**              PR_END_MACRO
+** DESCRIPTION:
+**      Macro body brackets so that macros with compound statement definitions
+**      behave syntactically more like functions when called.
+***********************************************************************/
+#define PR_BEGIN_MACRO  do {
+#define PR_END_MACRO    } while (0)
+
+/***********************************************************************
+** MACROS:      PR_BEGIN_EXTERN_C
+**              PR_END_EXTERN_C
+** DESCRIPTION:
+**      Macro shorthands for conditional C++ extern block delimiters.
+***********************************************************************/
+#ifdef __cplusplus
+#define PR_BEGIN_EXTERN_C       extern "C" {
+#define PR_END_EXTERN_C         }
+#else
+#define PR_BEGIN_EXTERN_C
+#define PR_END_EXTERN_C
+#endif
+
+/***********************************************************************
+** MACROS:      PR_BIT
+**              PR_BITMASK
+** DESCRIPTION:
+** Bit masking macros.  XXX n must be <= 31 to be portable
+***********************************************************************/
+#define PR_BIT(n)       ((PRUint32)1 << (n))
+#define PR_BITMASK(n)   (PR_BIT(n) - 1)
+
+/***********************************************************************
+** MACROS:      PR_ROUNDUP
+**              PR_MIN
+**              PR_MAX
+**              PR_ABS
+** DESCRIPTION:
+**      Commonly used macros for operations on compatible types.
+***********************************************************************/
+#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y))
+#define PR_MIN(x,y)     ((x)<(y)?(x):(y))
+#define PR_MAX(x,y)     ((x)>(y)?(x):(y))
+#define PR_ABS(x)       ((x)<0?-(x):(x))
+
+PR_BEGIN_EXTERN_C
+
+/************************************************************************
+** TYPES:       PRUint8
+**              PRInt8
+** DESCRIPTION:
+**  The int8 types are known to be 8 bits each. There is no type that
+**      is equivalent to a plain "char". 
+************************************************************************/
+#if PR_BYTES_PER_BYTE == 1
+typedef unsigned char PRUint8;
+/*
+** Some cfront-based C++ compilers do not like 'signed char' and
+** issue the warning message:
+**     warning: "signed" not implemented (ignored)
+** For these compilers, we have to define PRInt8 as plain 'char'.
+** Make sure that plain 'char' is indeed signed under these compilers.
+*/
+#if (defined(HPUX) && defined(__cplusplus) \
+        && !defined(__GNUC__) && __cplusplus < 199707L) \
+    || (defined(SCO) && defined(__cplusplus) \
+        && !defined(__GNUC__) && __cplusplus == 1L)
+typedef char PRInt8;
+#else
+typedef signed char PRInt8;
+#endif
+#else
+#error No suitable type for PRInt8/PRUint8
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT8_MAX
+ *              PR_INT8_MIN
+ *              PR_UINT8_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt8 or PRUint8.
+************************************************************************/
+
+#define PR_INT8_MAX 127
+#define PR_INT8_MIN (-128)
+#define PR_UINT8_MAX 255U
+
+/************************************************************************
+** TYPES:       PRUint16
+**              PRInt16
+** DESCRIPTION:
+**  The int16 types are known to be 16 bits each. 
+************************************************************************/
+#if PR_BYTES_PER_SHORT == 2
+typedef unsigned short PRUint16;
+typedef short PRInt16;
+#else
+#error No suitable type for PRInt16/PRUint16
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT16_MAX
+ *              PR_INT16_MIN
+ *              PR_UINT16_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt16 or PRUint16.
+************************************************************************/
+
+#define PR_INT16_MAX 32767
+#define PR_INT16_MIN (-32768)
+#define PR_UINT16_MAX 65535U
+
+/************************************************************************
+** TYPES:       PRUint32
+**              PRInt32
+** DESCRIPTION:
+**  The int32 types are known to be 32 bits each. 
+************************************************************************/
+#if PR_BYTES_PER_INT == 4
+typedef unsigned int PRUint32;
+typedef int PRInt32;
+#define PR_INT32(x)  x
+#define PR_UINT32(x) x ## U
+#elif PR_BYTES_PER_LONG == 4
+typedef unsigned long PRUint32;
+typedef long PRInt32;
+#define PR_INT32(x)  x ## L
+#define PR_UINT32(x) x ## UL
+#else
+#error No suitable type for PRInt32/PRUint32
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT32_MAX
+ *              PR_INT32_MIN
+ *              PR_UINT32_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt32 or PRUint32.
+************************************************************************/
+
+#define PR_INT32_MAX PR_INT32(2147483647)
+#define PR_INT32_MIN (-PR_INT32_MAX - 1)
+#define PR_UINT32_MAX PR_UINT32(4294967295)
+
+/************************************************************************
+** TYPES:       PRUint64
+**              PRInt64
+** DESCRIPTION:
+**  The int64 types are known to be 64 bits each. Care must be used when
+**      declaring variables of type PRUint64 or PRInt64. Different hardware
+**      architectures and even different compilers have varying support for
+**      64 bit values. The only guaranteed portability requires the use of
+**      the LL_ macros (see prlong.h).
+************************************************************************/
+#ifdef HAVE_LONG_LONG
+/* Keep this in sync with prlong.h. */
+/*
+ * On 64-bit Mac OS X, uint64 needs to be defined as unsigned long long to
+ * match uint64_t, otherwise our uint64 typedef conflicts with the uint64
+ * typedef in cssmconfig.h, which CoreServices.h includes indirectly.
+ */
+#if PR_BYTES_PER_LONG == 8 && !defined(__APPLE__)
+typedef long PRInt64;
+typedef unsigned long PRUint64;
+#elif defined(WIN32) && !defined(__GNUC__)
+typedef __int64  PRInt64;
+typedef unsigned __int64 PRUint64;
+#else
+typedef long long PRInt64;
+typedef unsigned long long PRUint64;
+#endif /* PR_BYTES_PER_LONG == 8 */
+#else  /* !HAVE_LONG_LONG */
+typedef struct {
+#ifdef IS_LITTLE_ENDIAN
+    PRUint32 lo, hi;
+#else
+    PRUint32 hi, lo;
+#endif
+} PRInt64;
+typedef PRInt64 PRUint64;
+#endif /* !HAVE_LONG_LONG */
+
+/************************************************************************
+** TYPES:       PRUintn
+**              PRIntn
+** DESCRIPTION:
+**  The PRIntn types are most appropriate for automatic variables. They are
+**      guaranteed to be at least 16 bits, though various architectures may
+**      define them to be wider (e.g., 32 or even 64 bits). These types are
+**      never valid for fields of a structure. 
+************************************************************************/
+#if PR_BYTES_PER_INT >= 2
+typedef int PRIntn;
+typedef unsigned int PRUintn;
+#else
+#error 'sizeof(int)' not sufficient for platform use
+#endif
+
+/************************************************************************
+** TYPES:       PRFloat64
+** DESCRIPTION:
+**  NSPR's floating point type is always 64 bits. 
+************************************************************************/
+typedef double          PRFloat64;
+
+/************************************************************************
+** TYPES:       PRSize
+** DESCRIPTION:
+**  A type for representing the size of objects. 
+************************************************************************/
+typedef size_t PRSize;
+
+
+/************************************************************************
+** TYPES:       PROffset32, PROffset64
+** DESCRIPTION:
+**  A type for representing byte offsets from some location. 
+************************************************************************/
+typedef PRInt32 PROffset32;
+typedef PRInt64 PROffset64;
+
+/************************************************************************
+** TYPES:       PRPtrDiff
+** DESCRIPTION:
+**  A type for pointer difference. Variables of this type are suitable
+**      for storing a pointer or pointer subtraction. 
+************************************************************************/
+typedef ptrdiff_t PRPtrdiff;
+
+/************************************************************************
+** TYPES:       PRUptrdiff
+** DESCRIPTION:
+**  A type for pointer difference. Variables of this type are suitable
+**      for storing a pointer or pointer sutraction. 
+************************************************************************/
+#ifdef _WIN64
+typedef unsigned __int64 PRUptrdiff;
+#else
+typedef unsigned long PRUptrdiff;
+#endif
+
+/************************************************************************
+** TYPES:       PRBool
+** DESCRIPTION:
+**  Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE
+**      for clarity of target type in assignments and actual arguments. Use
+**      'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans
+**      just as you would C int-valued conditions. 
+************************************************************************/
+typedef PRIntn PRBool;
+#define PR_TRUE 1
+#define PR_FALSE 0
+
+/************************************************************************
+** TYPES:       PRPackedBool
+** DESCRIPTION:
+**  Use PRPackedBool within structs where bitfields are not desirable
+**      but minimum and consistant overhead matters.
+************************************************************************/
+typedef PRUint8 PRPackedBool;
+
+/*
+** Status code used by some routines that have a single point of failure or 
+** special status return.
+*/
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+#ifndef __PRUNICHAR__
+#define __PRUNICHAR__
+#ifdef WIN32
+typedef wchar_t PRUnichar;
+#else
+typedef PRUint16 PRUnichar;
+#endif
+#endif
+
+/*
+** WARNING: The undocumented data types PRWord and PRUword are
+** only used in the garbage collection and arena code.  Do not
+** use PRWord and PRUword in new code.
+**
+** A PRWord is an integer that is the same size as a void*.
+** It implements the notion of a "word" in the Java Virtual
+** Machine.  (See Sec. 3.4 "Words", The Java Virtual Machine
+** Specification, Addison-Wesley, September 1996.
+** http://java.sun.com/docs/books/vmspec/index.html.)
+*/
+#ifdef _WIN64
+typedef __int64 PRWord;
+typedef unsigned __int64 PRUword;
+#else
+typedef long PRWord;
+typedef unsigned long PRUword;
+#endif
+
+#if defined(NO_NSPR_10_SUPPORT)
+#else
+/********* ???????????????? FIX ME       ??????????????????????????? *****/
+/********************** Some old definitions until pr=>ds transition is done ***/
+/********************** Also, we are still using NSPR 1.0. GC ******************/
+/*
+** Fundamental NSPR macros, used nearly everywhere.
+*/
+
+#define PR_PUBLIC_API		PR_IMPLEMENT
+
+/*
+** Macro body brackets so that macros with compound statement definitions
+** behave syntactically more like functions when called.
+*/
+#define NSPR_BEGIN_MACRO        do {
+#define NSPR_END_MACRO          } while (0)
+
+/*
+** Macro shorthands for conditional C++ extern block delimiters.
+*/
+#ifdef NSPR_BEGIN_EXTERN_C
+#undef NSPR_BEGIN_EXTERN_C
+#endif
+#ifdef NSPR_END_EXTERN_C
+#undef NSPR_END_EXTERN_C
+#endif
+
+#ifdef __cplusplus
+#define NSPR_BEGIN_EXTERN_C     extern "C" {
+#define NSPR_END_EXTERN_C       }
+#else
+#define NSPR_BEGIN_EXTERN_C
+#define NSPR_END_EXTERN_C
+#endif
+
+#include "obsolete/protypes.h"
+
+/********* ????????????? End Fix me ?????????????????????????????? *****/
+#endif /* NO_NSPR_10_SUPPORT */
+
+PR_END_EXTERN_C
+
+#endif /* prtypes_h___ */
+
diff --git a/mozilla/nsprpub/pr/include/prvrsion.h b/mozilla/nsprpub/pr/include/prvrsion.h
new file mode 100644
index 0000000..eb8e1e6
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prvrsion.h
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+
+/* author: jstewart */
+
+#if defined(_PRVERSION_H)
+#else
+#define _PRVERSION_H
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/* All components participating in the PR version protocol must expose
+ * a structure and a function. The structure is defined below and named
+ * according to the naming conventions outlined further below.  The function
+ * is called libVersionPoint and returns a pointer to this structure.
+ */
+
+/* on NT, always pack the structure the same. */
+#ifdef _WIN32
+#pragma pack(push, 8)
+#endif
+
+typedef struct {
+    /*
+     * The first field defines which version of this structure is in use.
+     * At this time, only version 2 is specified. If this value is not 
+     * 2, you must read no further into the structure.
+     */
+    PRInt32    version; 
+  
+    /* for Version 2, this is the body format. */
+    PRInt64         buildTime;      /* 64 bits - usecs since midnight, 1/1/1970 */
+    char *          buildTimeString;/* a human readable version of the time */
+  
+    PRUint8   vMajor;               /* Major version of this component */
+    PRUint8   vMinor;               /* Minor version of this component */
+    PRUint8   vPatch;               /* Patch level of this component */
+  
+    PRBool          beta;           /* true if this is a beta component */
+    PRBool          debug;          /* true if this is a debug component */
+    PRBool          special;        /* true if this component is a special build */
+  
+    char *          filename;       /* The original filename */
+    char *          description;    /* description of this component */
+    char *          security;       /* level of security in this component */
+    char *          copyright;      /* The copyright for this file */
+    char *          comment;        /* free form field for misc usage */
+    char *          specialString;  /* the special variant for this build */
+} PRVersionDescription;
+
+/* on NT, restore the previous packing */
+#ifdef _WIN32
+#pragma pack(pop)
+#endif
+
+/*
+ * All components must define an entrypoint named libVersionPoint which
+ * is of type versionEntryPointType.
+ *
+ * For example, for a library named libfoo, we would have:
+ *
+ *   PRVersionDescription prVersionDescription_libfoo =
+ *   {
+ *       ...
+ *   };
+ *
+ *   PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void)
+ *   {
+ *       return &prVersionDescription_libfoo;
+ *   }
+ */
+typedef const PRVersionDescription *(*versionEntryPointType)(void);
+
+/* 
+ * Where you declare your libVersionPoint, do it like this: 
+ * PR_IMPLEMENT(const PRVersionDescription *) libVersionPoint(void) {
+ *  fill it in...
+ * }
+ */
+
+/*
+ * NAMING CONVENTION FOR struct
+ *
+ * all components should also expose a static PRVersionDescription
+ * The name of the struct should be calculated as follows:
+ * Take the value of filename. (If filename is not specified, calculate
+ * a short, unique string.)  Convert all non-alphanumeric characters
+ * to '_'.  To this, prepend "PRVersionDescription_".  Thus for libfoo.so,
+ * the symbol name is "PRVersionDescription_libfoo_so".
+ * so the file should have
+ * PRVersionDescription PRVersionDescription_libfoo_so { fill it in };
+ * on NT, this file should be declspec export.
+ */
+
+PR_END_EXTERN_C
+
+#endif  /* defined(_PRVERSION_H) */
+
+/* prvrsion.h */
+
diff --git a/mozilla/nsprpub/pr/include/prwin16.h b/mozilla/nsprpub/pr/include/prwin16.h
new file mode 100644
index 0000000..215b051
--- /dev/null
+++ b/mozilla/nsprpub/pr/include/prwin16.h
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#ifndef prwin16_h___
+#define prwin16_h___
+
+/*
+** Condition use of this header on platform.
+*/
+#if (defined(XP_PC) && !defined(_WIN32) && !defined(XP_OS2) && defined(MOZILLA_CLIENT)) || defined(WIN16)
+#include <stdio.h>
+
+PR_BEGIN_EXTERN_C
+/* 
+** Win16 stdio special case.
+** To get stdio to work for Win16, all calls to printf() and related
+** things must be called from the environment of the .EXE; calls to
+** printf() from the .DLL send output to the bit-bucket.
+**
+** To make sure that PR_fprintf(), and related functions, work correctly,
+** the actual stream I/O to stdout, stderr, stdin must be done in the
+** .EXE. To do this, a hack is placed in _MD_Write() such that the
+** fd for stdio handles results in a call to the .EXE.
+**
+** file w16stdio.c contains the functions that get called from NSPR
+** to do the actual I/O. w16stdio.o must be statically linked with
+** any application needing stdio for Win16.
+**
+** The address of these functions must be made available to the .DLL
+** so he can call back to the .EXE. To do this, function 
+** PR_MD_RegisterW16StdioCallbacks() is called from the .EXE.
+** The arguments are the functions defined in w16stdio.c
+** At runtime, MD_Write() calls the registered functions, if any
+** were registered.
+**
+** prinit.h contains a macro PR_STDIO_INIT() that calls the registration
+** function for Win16; For other platforms, the macro is a No-Op.
+**
+** Note that stdio is not operational at all on Win16 GUI applications.
+** This special case exists to provide stdio capability from the NSPR
+** .DLL for command line applications only. NSPR's test cases are
+** almost exclusively command line applications.
+**
+** See also: w16io.c, w16stdio.c
+*/
+typedef PRInt32 (PR_CALLBACK *PRStdinRead)( void *buf, PRInt32 amount);
+typedef PRInt32 (PR_CALLBACK *PRStdoutWrite)( void *buf, PRInt32 amount);
+typedef PRInt32 (PR_CALLBACK *PRStderrWrite)( void *buf, PRInt32 amount);
+
+NSPR_API(PRStatus)
+PR_MD_RegisterW16StdioCallbacks( 
+    PRStdinRead inReadf,            /* i: function pointer for stdin read       */
+    PRStdoutWrite outWritef,        /* i: function pointer for stdout write     */
+    PRStderrWrite errWritef         /* i: function pointer for stderr write     */
+    );
+
+NSPR_API(PRInt32)
+_PL_W16StdioWrite( void *buf, PRInt32 amount );
+
+NSPR_API(PRInt32)
+_PL_W16StdioRead( void *buf, PRInt32 amount );
+
+#define PR_STDIO_INIT() PR_MD_RegisterW16StdioCallbacks( \
+    _PL_W16StdioRead, _PL_W16StdioWrite, _PL_W16StdioWrite ); \
+    PR_INIT_CALLBACKS();
+
+/*
+** Win16 hackery.
+**
+*/
+struct PRMethodCallbackStr {
+    int     (PR_CALLBACK *auxOutput)(const char *outputString);
+    size_t  (PR_CALLBACK *strftime)(char *s, size_t len, const char *fmt, const struct tm *p);
+    void *  (PR_CALLBACK *malloc)( size_t size );
+    void *  (PR_CALLBACK *calloc)(size_t n, size_t size );
+    void *  (PR_CALLBACK *realloc)( void* old_blk, size_t size );
+    void    (PR_CALLBACK *free)( void *ptr );
+    void *  (PR_CALLBACK *getenv)( const char *name);
+    int     (PR_CALLBACK *putenv)( const char *assoc);
+/*    void *  (PR_CALLBACK *perror)( const char *prefix ); */
+};
+
+NSPR_API(void) PR_MDRegisterCallbacks(struct PRMethodCallbackStr *);
+
+int PR_CALLBACK _PL_W16CallBackPuts( const char *outputString );
+size_t PR_CALLBACK _PL_W16CallBackStrftime( 
+    char *s, 
+    size_t len, 
+    const char *fmt,
+    const struct tm *p );
+void * PR_CALLBACK _PL_W16CallBackMalloc( size_t size );
+void * PR_CALLBACK _PL_W16CallBackCalloc( size_t n, size_t size );
+void * PR_CALLBACK _PL_W16CallBackRealloc( 
+    void *old_blk, 
+    size_t size );
+void   PR_CALLBACK _PL_W16CallBackFree( void *ptr );
+void * PR_CALLBACK _PL_W16CallBackGetenv( const char *name );
+int PR_CALLBACK _PL_W16CallBackPutenv( const char *assoc );
+
+/*
+** Hackery! 
+**
+** These functions are provided as static link points.
+** This is to satisfy the quick port of Gromit to NSPR 2.0
+** ... Don't do this! ... alas, It may never go away.
+** 
+*/
+NSPR_API(int)     PR_MD_printf(const char *, ...);
+NSPR_API(void)    PR_MD_exit(int);
+NSPR_API(size_t)  PR_MD_strftime(char *, size_t, const char *, const struct tm *); 
+NSPR_API(int)     PR_MD_sscanf(const char *, const char *, ...);
+NSPR_API(void*)   PR_MD_malloc( size_t size );
+NSPR_API(void*)   PR_MD_calloc( size_t n, size_t size );
+NSPR_API(void*)   PR_MD_realloc( void* old_blk, size_t size );
+NSPR_API(void)    PR_MD_free( void *ptr );
+NSPR_API(char*)   PR_MD_getenv( const char *name );
+NSPR_API(int)     PR_MD_putenv( const char *assoc );
+NSPR_API(int)     PR_MD_fprintf(FILE *fPtr, const char *fmt, ...);
+
+#define PR_INIT_CALLBACKS()                         \
+    {                                               \
+        static struct PRMethodCallbackStr cbf = {   \
+            _PL_W16CallBackPuts,                    \
+            _PL_W16CallBackStrftime,                \
+            _PL_W16CallBackMalloc,                  \
+            _PL_W16CallBackCalloc,                  \
+            _PL_W16CallBackRealloc,                 \
+            _PL_W16CallBackFree,                    \
+            _PL_W16CallBackGetenv,                  \
+            _PL_W16CallBackPutenv,                  \
+        };                                          \
+        PR_MDRegisterCallbacks( &cbf );             \
+    }
+
+
+/*
+** Get the exception context for Win16 MFC applications threads
+*/
+NSPR_API(void *) PR_W16GetExceptionContext(void);
+/*
+** Set the exception context for Win16 MFC applications threads
+*/
+NSPR_API(void) PR_W16SetExceptionContext(void *context);
+
+PR_END_EXTERN_C
+#else
+/*
+** For platforms other than Win16, define
+** PR_STDIO_INIT() as a No-Op.
+*/
+#define PR_STDIO_INIT()
+#endif /* WIN16 || MOZILLA_CLIENT */
+
+#endif /* prwin16_h___ */
+
+
+
+
+
+
+
+
diff --git a/mozilla/nsprpub/pr/src/io/prdir.c b/mozilla/nsprpub/pr/src/io/prdir.c
new file mode 100644
index 0000000..8679c9d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prdir.c
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Roy Yokoyama <yokoyama@netscape.com>
+ *
+ * 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 "primpl.h"
+
+PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
+{
+    PRDir *dir;
+    PRStatus sts;
+
+    dir = PR_NEW(PRDir);
+    if (dir) {
+        sts = _PR_MD_OPEN_DIR(&dir->md,name);
+        if (sts != PR_SUCCESS) {
+            PR_DELETE(dir);
+            return NULL;
+        }
+    } else {
+		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	}
+    return dir;
+}
+
+PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
+{
+    /* _MD_READ_DIR return a char* to the name; allocation in machine-dependent code */
+    char* name = _PR_MD_READ_DIR(&dir->md, flags);
+    dir->d.name = name;
+    return name ? &dir->d : NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
+{
+PRInt32 rv;
+
+    if (dir) {
+        rv = _PR_MD_CLOSE_DIR(&dir->md);
+		PR_DELETE(dir);
+		if (rv < 0) {
+			return PR_FAILURE;
+		} else
+			return PR_SUCCESS;
+    }
+	return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
+{
+PRInt32 rv;
+
+	rv = _PR_MD_MKDIR(name, mode);
+	if (rv < 0) {
+		return PR_FAILURE;
+	} else
+		return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
+{
+PRInt32 rv;
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+	rv = _PR_MD_MAKE_DIR(name, mode);
+	if (rv < 0) {
+		return PR_FAILURE;
+	} else
+		return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
+{
+PRInt32 rv;
+
+	rv = _PR_MD_RMDIR(name);
+	if (rv < 0) {
+		return PR_FAILURE;
+	} else
+		return PR_SUCCESS;
+}
+
+#ifdef MOZ_UNICODE
+/*
+ *  UTF16 Interface
+ */
+PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
+{ 
+    PRDirUTF16 *dir;
+    PRStatus sts;
+
+    dir = PR_NEW(PRDirUTF16);
+    if (dir) {
+        sts = _PR_MD_OPEN_DIR_UTF16(&dir->md,name);
+        if (sts != PR_SUCCESS) {
+            PR_DELETE(dir);
+            return NULL;
+        }
+    } else {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    }
+    return dir;
+}  
+ 
+PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
+{ 
+    /*
+     * _MD_READ_DIR_UTF16 return a PRUnichar* to the name; allocation in
+     * machine-dependent code
+     */
+    PRUnichar* name = _PR_MD_READ_DIR_UTF16(&dir->md, flags);
+    dir->d.name = name;
+    return name ? &dir->d : NULL;
+} 
+ 
+PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir)
+{ 
+    PRInt32 rv; 
+
+    if (dir) {
+        rv = _PR_MD_CLOSE_DIR_UTF16(&dir->md);
+        PR_DELETE(dir);
+        if (rv < 0)
+	    return PR_FAILURE;
+        else
+	    return PR_SUCCESS;
+    } 
+    return PR_SUCCESS;
+}
+
+#endif /* MOZ_UNICODE */
diff --git a/mozilla/nsprpub/pr/src/io/prfdcach.c b/mozilla/nsprpub/pr/src/io/prfdcach.c
new file mode 100644
index 0000000..ca09cb4
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prfdcach.c
@@ -0,0 +1,324 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+
+/*****************************************************************************/
+/*****************************************************************************/
+/************************** File descriptor caching **************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+/*
+** This code is built into debuggable versions of NSPR to assist in
+** finding misused file descriptors. Since file descritors (PRFileDesc)
+** are identified by a pointer to their structure, they can be the
+** target of dangling references. Furthermore, NSPR caches and tries
+** to aggressively reuse file descriptors, leading to more ambiguity.
+** The following code will allow a debugging client to set environment
+** variables and control the number of file descriptors that will be
+** preserved before they are recycled. The environment variables are
+** NSPR_FD_CACHE_SIZE_LOW and NSPR_FD_CACHE_SIZE_HIGH. The former sets
+** the number of descriptors NSPR will allocate before beginning to
+** recycle. The latter is the maximum number permitted in the cache
+** (exclusive of those in use) at a time.
+*/
+typedef struct _PR_Fd_Cache
+{
+    PRLock *ml;
+    PRIntn count;
+    PRStack *stack;
+    PRFileDesc *head, *tail;
+    PRIntn limit_low, limit_high;
+} _PR_Fd_Cache;
+
+static _PR_Fd_Cache _pr_fd_cache;
+static PRFileDesc **stack2fd = &(((PRFileDesc*)NULL)->higher);
+
+
+/*
+** Get a FileDescriptor from the cache if one exists. If not allocate
+** a new one from the heap.
+*/
+PRFileDesc *_PR_Getfd(void)
+{
+    PRFileDesc *fd;
+    /*
+    ** $$$
+    ** This may look a little wasteful. We'll see. Right now I want to
+    ** be able to toggle between caching and not at runtime to measure
+    ** the differences. If it isn't too annoying, I'll leave it in.
+    ** $$$$
+    **
+    ** The test is against _pr_fd_cache.limit_high. If that's zero,
+    ** we're not doing the extended cache but going for performance.
+    */
+    if (0 == _pr_fd_cache.limit_high)
+    {
+        PRStackElem *pop;
+        PR_ASSERT(NULL != _pr_fd_cache.stack);
+        pop = PR_StackPop(_pr_fd_cache.stack);
+        if (NULL == pop) goto allocate;
+        fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
+    }
+    else
+    {
+        do
+        {
+            if (NULL == _pr_fd_cache.head) goto allocate;  /* nothing there */
+            if (_pr_fd_cache.count < _pr_fd_cache.limit_low) goto allocate;
+
+            /* we "should" be able to extract an fd from the cache */
+            PR_Lock(_pr_fd_cache.ml);  /* need the lock to do this safely */
+            fd = _pr_fd_cache.head;  /* protected extraction */
+            if (NULL == fd)  /* unexpected, but not fatal */
+            {
+                PR_ASSERT(0 == _pr_fd_cache.count);
+                PR_ASSERT(NULL == _pr_fd_cache.tail);
+            }
+            else
+            {
+                _pr_fd_cache.count -= 1;
+                _pr_fd_cache.head = fd->higher;
+                if (NULL == _pr_fd_cache.head)
+                {
+                    PR_ASSERT(0 == _pr_fd_cache.count);
+                    _pr_fd_cache.tail = NULL;
+                }
+                PR_ASSERT(&_pr_faulty_methods == fd->methods);
+                PR_ASSERT(PR_INVALID_IO_LAYER == fd->identity);
+                PR_ASSERT(_PR_FILEDESC_FREED == fd->secret->state);
+            }
+            PR_Unlock(_pr_fd_cache.ml);
+
+        } while (NULL == fd);  /* then go around and allocate a new one */
+    }
+
+finished:
+    fd->dtor = NULL;
+    fd->lower = fd->higher = NULL;
+    fd->identity = PR_NSPR_IO_LAYER;
+    memset(fd->secret, 0, sizeof(PRFilePrivate));
+    return fd;
+
+allocate:
+    fd = PR_NEW(PRFileDesc);
+    if (NULL != fd)
+    {
+        fd->secret = PR_NEW(PRFilePrivate);
+        if (NULL == fd->secret) PR_DELETE(fd);
+    }
+    if (NULL != fd) goto finished;
+    else return NULL;
+
+}  /* _PR_Getfd */
+
+/*
+** Return a file descriptor to the cache unless there are too many in
+** there already. If put in cache, clear the fields first.
+*/
+void _PR_Putfd(PRFileDesc *fd)
+{
+    PR_ASSERT(PR_NSPR_IO_LAYER == fd->identity);
+    fd->methods = &_pr_faulty_methods;
+    fd->identity = PR_INVALID_IO_LAYER;
+    fd->secret->state = _PR_FILEDESC_FREED;
+
+    if (0 == _pr_fd_cache.limit_high)
+    {
+        PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
+    }
+    else
+    {
+        if (_pr_fd_cache.count > _pr_fd_cache.limit_high)
+        {
+            PR_Free(fd->secret);
+            PR_Free(fd);
+        }
+        else
+        {
+            PR_Lock(_pr_fd_cache.ml);
+            if (NULL == _pr_fd_cache.tail)
+            {
+                PR_ASSERT(0 == _pr_fd_cache.count);
+                PR_ASSERT(NULL == _pr_fd_cache.head);
+                _pr_fd_cache.head = _pr_fd_cache.tail = fd;
+            }
+            else
+            {
+                PR_ASSERT(NULL == _pr_fd_cache.tail->higher);
+                _pr_fd_cache.tail->higher = fd;
+                _pr_fd_cache.tail = fd;  /* new value */
+            }
+            fd->higher = NULL;  /* always so */
+            _pr_fd_cache.count += 1;  /* count the new entry */
+            PR_Unlock(_pr_fd_cache.ml);
+        }
+    }
+}  /* _PR_Putfd */
+
+PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high)
+{
+    /*
+    ** This can be called at any time, may adjust the cache sizes,
+    ** turn the caches off, or turn them on. It is not dependent
+    ** on the compilation setting of DEBUG.
+    */
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (low > high) low = high;  /* sanity check the params */
+    
+    PR_Lock(_pr_fd_cache.ml);
+    if (0 == high)  /* shutting down or staying down */
+    {
+        if (0 != _pr_fd_cache.limit_high)  /* shutting down */
+        {
+            _pr_fd_cache.limit_high = 0;  /* stop use */
+            /*
+            ** Hold the lock throughout - nobody's going to want it
+            ** other than another caller to this routine. Just don't
+            ** let that happen.
+            **
+            ** Put all the cached fds onto the new cache.
+            */
+            while (NULL != _pr_fd_cache.head)
+            {
+                PRFileDesc *fd = _pr_fd_cache.head;
+                _pr_fd_cache.head = fd->higher;
+                PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
+            }
+            _pr_fd_cache.limit_low = 0;
+            _pr_fd_cache.tail = NULL;
+            _pr_fd_cache.count = 0;
+        }
+    }
+    else  /* starting up or just adjusting parameters */
+    {
+        PRBool was_using_stack = (0 == _pr_fd_cache.limit_high);
+        _pr_fd_cache.limit_low = low;
+        _pr_fd_cache.limit_high = high;
+        if (was_using_stack)  /* was using stack - feed into cache */
+        {
+            PRStackElem *pop;
+            while (NULL != (pop = PR_StackPop(_pr_fd_cache.stack)))
+            {
+                PRFileDesc *fd = (PRFileDesc*)
+                    ((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
+                if (NULL == _pr_fd_cache.tail) _pr_fd_cache.tail = fd;
+                fd->higher = _pr_fd_cache.head;
+                _pr_fd_cache.head = fd;
+                _pr_fd_cache.count += 1;
+            }
+        }
+    }
+    PR_Unlock(_pr_fd_cache.ml);
+    return PR_SUCCESS;
+}  /* PR_SetFDCacheSize */
+
+void _PR_InitFdCache(void)
+{
+    /*
+    ** The fd caching is enabled by default for DEBUG builds,
+    ** disabled by default for OPT builds. That default can
+    ** be overridden at runtime using environment variables
+    ** or a super-wiz-bang API.
+    */
+    const char *low = PR_GetEnv("NSPR_FD_CACHE_SIZE_LOW");
+    const char *high = PR_GetEnv("NSPR_FD_CACHE_SIZE_HIGH");
+
+    /* 
+    ** _low is allowed to be zero, _high is not.
+    ** If _high is zero, we're not doing the caching.
+    */
+
+    _pr_fd_cache.limit_low = 0;
+#if defined(DEBUG)
+    _pr_fd_cache.limit_high = FD_SETSIZE;
+#else
+    _pr_fd_cache.limit_high = 0;
+#endif  /* defined(DEBUG) */
+
+    if (NULL != low) _pr_fd_cache.limit_low = atoi(low);
+    if (NULL != high) _pr_fd_cache.limit_high = atoi(high);
+
+    if (_pr_fd_cache.limit_low < 0)
+        _pr_fd_cache.limit_low = 0;
+    if (_pr_fd_cache.limit_low > FD_SETSIZE)
+        _pr_fd_cache.limit_low = FD_SETSIZE;
+
+    if (_pr_fd_cache.limit_high > FD_SETSIZE)
+        _pr_fd_cache.limit_high = FD_SETSIZE;
+
+    if (_pr_fd_cache.limit_high < _pr_fd_cache.limit_low)
+        _pr_fd_cache.limit_high = _pr_fd_cache.limit_low;
+
+    _pr_fd_cache.ml = PR_NewLock();
+    PR_ASSERT(NULL != _pr_fd_cache.ml);
+    _pr_fd_cache.stack = PR_CreateStack("FD");
+    PR_ASSERT(NULL != _pr_fd_cache.stack);
+
+}  /* _PR_InitFdCache */
+
+void _PR_CleanupFdCache(void)
+{
+    PRFileDesc *fd, *next;
+    PRStackElem *pop;
+
+    for (fd = _pr_fd_cache.head; fd != NULL; fd = next)
+    {
+        next = fd->higher;
+        PR_DELETE(fd->secret);
+        PR_DELETE(fd);
+    }
+    _pr_fd_cache.head = NULL;
+    _pr_fd_cache.tail = NULL;
+    _pr_fd_cache.count = 0;
+    PR_DestroyLock(_pr_fd_cache.ml);
+    _pr_fd_cache.ml = NULL;
+    while ((pop = PR_StackPop(_pr_fd_cache.stack)) != NULL)
+    {
+        fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
+        PR_DELETE(fd->secret);
+        PR_DELETE(fd);
+    }
+    PR_DestroyStack(_pr_fd_cache.stack);
+    _pr_fd_cache.stack = NULL;
+}  /* _PR_CleanupFdCache */
+
+/* prfdcach.c */
diff --git a/mozilla/nsprpub/pr/src/io/prfile.c b/mozilla/nsprpub/pr/src/io/prfile.c
new file mode 100644
index 0000000..00dbb89
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prfile.c
@@ -0,0 +1,815 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef XP_UNIX
+#if defined(AIX) || defined(QNX)
+/* To pick up sysconf */
+#include <unistd.h>
+#else
+/* To pick up getrlimit, setrlimit */
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#endif /* XP_UNIX */
+
+extern PRLock *_pr_flock_lock;
+extern PRCondVar *_pr_flock_cv;
+
+static PRInt32 PR_CALLBACK FileRead(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+    PRInt32 rv = 0;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (_PR_PENDING_INTERRUPT(me)) {
+ 		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		rv = -1;
+    }
+    if (_PR_IO_PENDING(me)) {
+        PR_SetError(PR_IO_PENDING_ERROR, 0);
+	rv = -1;
+    }
+    if (rv == -1)
+    	return rv;
+
+	rv = _PR_MD_READ(fd, buf, amount);
+	if (rv < 0) {
+		PR_ASSERT(rv == -1);
+	}
+    PR_LOG(_pr_io_lm, PR_LOG_MAX, ("read -> %d", rv));
+    return rv;
+}
+
+static PRInt32 PR_CALLBACK FileWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+    PRInt32 rv = 0;
+    PRInt32 temp, count;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (_PR_PENDING_INTERRUPT(me)) {
+        me->flags &= ~_PR_INTERRUPT;
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+	    rv = -1;
+    }
+    if (_PR_IO_PENDING(me)) {
+        PR_SetError(PR_IO_PENDING_ERROR, 0);
+	    rv = -1;
+    }
+    if (rv != 0)
+    	return rv;
+
+    count = 0;
+#if !defined(_PR_HAVE_O_APPEND)  /* Bugzilla: 4090, 276330 */
+    if (fd->secret->appendMode) {
+        if (PR_Seek64(fd, 0, PR_SEEK_END) == -1) {
+            return -1;
+        }
+    } /* if (fd->secret->appendMode...) */
+#endif /* _PR_HAVE_O_APPEND */
+    while (amount > 0) {
+		temp = _PR_MD_WRITE(fd, buf, amount);
+		if (temp < 0) {
+			count = -1;
+			break;
+		}
+		count += temp;
+		if (fd->secret->nonblocking) {
+			break;
+		}
+		buf = (const void*) ((const char*)buf + temp);
+		amount -= temp;
+    }
+    PR_LOG(_pr_io_lm, PR_LOG_MAX, ("write -> %d", count));
+    return count;
+}
+
+static PROffset32 PR_CALLBACK FileSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
+{
+    PROffset32 result;
+
+    result = _PR_MD_LSEEK(fd, offset, whence);
+    return result;
+}
+
+static PROffset64 PR_CALLBACK FileSeek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
+{
+    PROffset64 result;
+
+    result = _PR_MD_LSEEK64(fd, offset, whence);
+    return result;
+}
+
+static PRInt32 PR_CALLBACK FileAvailable(PRFileDesc *fd)
+{
+    PRInt32 result, cur, end;
+
+    cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
+
+	if (cur >= 0)
+    	end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
+
+    if ((cur < 0) || (end < 0)) {
+        return -1;
+    }
+
+    result = end - cur;
+    _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
+
+    return result;
+}
+
+static PRInt64 PR_CALLBACK FileAvailable64(PRFileDesc *fd)
+{
+    PRInt64 result, cur, end;
+    PRInt64 minus_one;
+
+    LL_I2L(minus_one, -1);
+    cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
+
+    if (LL_GE_ZERO(cur))
+    	end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
+
+    if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
+
+    LL_SUB(result, end, cur);
+    (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
+
+    return result;
+}
+
+static PRInt32 PR_CALLBACK PipeAvailable(PRFileDesc *fd)
+{
+	PRInt32 rv;
+	rv =  _PR_MD_PIPEAVAILABLE(fd);
+	return rv;		
+}
+
+static PRInt64 PR_CALLBACK PipeAvailable64(PRFileDesc *fd)
+{
+    PRInt64 rv;
+    LL_I2L(rv, _PR_MD_PIPEAVAILABLE(fd));
+	return rv;		
+}
+
+static PRStatus PR_CALLBACK PipeSync(PRFileDesc *fd)
+{
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK FileGetInfo(PRFileDesc *fd, PRFileInfo *info)
+{
+	PRInt32 rv;
+
+    rv = _PR_MD_GETOPENFILEINFO(fd, info);
+    if (rv < 0) {
+	return PR_FAILURE;
+    } else
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK FileGetInfo64(PRFileDesc *fd, PRFileInfo64 *info)
+{
+    /* $$$$ NOT YET IMPLEMENTED */
+	PRInt32 rv;
+
+    rv = _PR_MD_GETOPENFILEINFO64(fd, info);
+    if (rv < 0) return PR_FAILURE;
+    else return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK FileSync(PRFileDesc *fd)
+{
+    PRInt32 result;
+    result = _PR_MD_FSYNC(fd);
+    if (result < 0) {
+		return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK FileClose(PRFileDesc *fd)
+{
+    if (!fd || !fd->secret
+            || (fd->secret->state != _PR_FILEDESC_OPEN
+            && fd->secret->state != _PR_FILEDESC_CLOSED)) {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    if (fd->secret->state == _PR_FILEDESC_OPEN) {
+        if (_PR_MD_CLOSE_FILE(fd->secret->md.osfd) < 0) {
+            return PR_FAILURE;
+        }
+        fd->secret->state = _PR_FILEDESC_CLOSED;
+    }
+    PR_FreeFileDesc(fd);
+    return PR_SUCCESS;
+}
+
+static PRInt16 PR_CALLBACK FilePoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+    *out_flags = 0;
+    return in_flags;
+}  /* FilePoll */
+
+static PRIOMethods _pr_fileMethods = {
+    PR_DESC_FILE,
+    FileClose,
+    FileRead,
+    FileWrite,
+    FileAvailable,
+    FileAvailable64,
+    FileSync,
+    FileSeek,
+    FileSeek64,
+    FileGetInfo,
+    FileGetInfo64,
+    (PRWritevFN)_PR_InvalidInt,		
+    (PRConnectFN)_PR_InvalidStatus,		
+    (PRAcceptFN)_PR_InvalidDesc,		
+    (PRBindFN)_PR_InvalidStatus,		
+    (PRListenFN)_PR_InvalidStatus,		
+    (PRShutdownFN)_PR_InvalidStatus,	
+    (PRRecvFN)_PR_InvalidInt,		
+    (PRSendFN)_PR_InvalidInt,		
+    (PRRecvfromFN)_PR_InvalidInt,	
+    (PRSendtoFN)_PR_InvalidInt,		
+    FilePoll,         
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,	
+    (PRGetpeernameFN)_PR_InvalidStatus,	
+    (PRReservedFN)_PR_InvalidInt,	
+    (PRReservedFN)_PR_InvalidInt,	
+    (PRGetsocketoptionFN)_PR_InvalidStatus,	
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
+{
+    return &_pr_fileMethods;
+}
+
+static PRIOMethods _pr_pipeMethods = {
+    PR_DESC_PIPE,
+    FileClose,
+    FileRead,
+    FileWrite,
+    PipeAvailable,
+    PipeAvailable64,
+    PipeSync,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,		
+    (PRConnectFN)_PR_InvalidStatus,		
+    (PRAcceptFN)_PR_InvalidDesc,		
+    (PRBindFN)_PR_InvalidStatus,		
+    (PRListenFN)_PR_InvalidStatus,		
+    (PRShutdownFN)_PR_InvalidStatus,	
+    (PRRecvFN)_PR_InvalidInt,		
+    (PRSendFN)_PR_InvalidInt,		
+    (PRRecvfromFN)_PR_InvalidInt,	
+    (PRSendtoFN)_PR_InvalidInt,		
+    FilePoll,         
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,	
+    (PRGetpeernameFN)_PR_InvalidStatus,	
+    (PRReservedFN)_PR_InvalidInt,	
+    (PRReservedFN)_PR_InvalidInt,	
+    (PRGetsocketoptionFN)_PR_InvalidStatus,	
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
+{
+    return &_pr_pipeMethods;
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
+{
+    PROsfd osfd;
+    PRFileDesc *fd = 0;
+#if !defined(_PR_HAVE_O_APPEND)
+    PRBool  appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    /* Map pr open flags and mode to os specific flags */
+
+    osfd = _PR_MD_OPEN(name, flags, mode);
+    if (osfd != -1) {
+        fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
+        if (!fd) {
+            (void) _PR_MD_CLOSE_FILE(osfd);
+        } else {
+#if !defined(_PR_HAVE_O_APPEND)
+            fd->secret->appendMode = appendMode;
+#endif
+            _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
+        }
+    }
+    return fd;
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
+    const char *name, PRIntn flags, PRIntn mode)
+{
+    PROsfd osfd;
+    PRFileDesc *fd = 0;
+#if !defined(_PR_HAVE_O_APPEND)
+    PRBool  appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    /* Map pr open flags and mode to os specific flags */
+
+    osfd = _PR_MD_OPEN_FILE(name, flags, mode);
+    if (osfd != -1) {
+        fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
+        if (!fd) {
+            (void) _PR_MD_CLOSE_FILE(osfd);
+        } else {
+#if !defined(_PR_HAVE_O_APPEND)
+            fd->secret->appendMode = appendMode;
+#endif
+            _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
+        }
+    }
+    return fd;
+}
+
+PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
+{
+#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
+    struct rlimit rlim;
+
+    if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+       /* XXX need to call PR_SetError() */
+       return -1;
+    }
+
+    return rlim.rlim_max;
+#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX)
+    return sysconf(_SC_OPEN_MAX);
+#elif defined(WIN32)
+    /*
+     * There is a systemwide limit of 65536 user handles.
+     */
+    return 16384;
+#elif defined (WIN16)
+    return FOPEN_MAX;
+#elif defined(XP_OS2)
+    ULONG ulReqCount = 0;
+    ULONG ulCurMaxFH = 0;
+    DosSetRelMaxFH(&ulReqCount, &ulCurMaxFH);
+    return ulCurMaxFH;
+#elif defined(XP_BEOS)
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+   return -1;
+#else
+    write me;
+#endif
+}
+
+PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(int table_size)
+{
+#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
+    struct rlimit rlim;
+    PRInt32 tableMax = PR_GetSysfdTableMax();
+
+    if (tableMax < 0) 
+        return -1;
+
+    if (tableMax > FD_SETSIZE)
+        tableMax = FD_SETSIZE;
+
+    rlim.rlim_max = tableMax;
+
+    /* Grow as much as we can; even if too big */
+    if ( rlim.rlim_max < table_size )
+        rlim.rlim_cur = rlim.rlim_max;
+    else
+        rlim.rlim_cur = table_size;
+
+    if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+        /* XXX need to call PR_SetError() */
+        return -1;
+    }
+
+    return rlim.rlim_cur;
+#elif defined(XP_OS2)
+    PRInt32 tableMax = PR_GetSysfdTableMax();
+    if (table_size > tableMax) {
+      APIRET rc = NO_ERROR;
+      rc = DosSetMaxFH(table_size);
+      if (rc == NO_ERROR)
+        return table_size;
+      else
+        return -1;
+    } 
+    return tableMax;
+#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX) \
+        || defined(WIN32) || defined(WIN16) || defined(XP_BEOS)
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return -1;
+#else
+    write me;
+#endif
+}
+
+PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
+{
+	PRInt32 rv;
+
+	rv = _PR_MD_DELETE(name);
+	if (rv < 0) {
+		return PR_FAILURE;
+	} else
+		return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
+{
+	PRInt32 rv;
+
+	rv = _PR_MD_GETFILEINFO(fn, info);
+	if (rv < 0) {
+		return PR_FAILURE;
+	} else
+		return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
+{
+    PRInt32 rv;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    rv = _PR_MD_GETFILEINFO64(fn, info);
+    if (rv < 0) {
+        return PR_FAILURE;
+    } else {
+        return PR_SUCCESS;
+    }
+}
+
+PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
+{
+	PRInt32 rv;
+
+	rv = _PR_MD_RENAME(from, to);
+	if (rv < 0) {
+		return PR_FAILURE;
+	} else
+		return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
+{
+PRInt32 rv;
+
+	rv = _PR_MD_ACCESS(name, how);
+	if (rv < 0) {
+		return PR_FAILURE;
+	} else
+		return PR_SUCCESS;
+}
+
+/*
+** Import an existing OS file to NSPR 
+*/
+PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PROsfd osfd)
+{
+    PRFileDesc *fd = NULL;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
+    if( !fd ) {
+        (void) _PR_MD_CLOSE_FILE(osfd);
+    } else {
+        _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+    }
+
+    return fd;
+}
+
+/*
+** Import an existing OS pipe to NSPR 
+*/
+PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PROsfd osfd)
+{
+    PRFileDesc *fd = NULL;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    fd = PR_AllocFileDesc(osfd, &_pr_pipeMethods);
+    if( !fd ) {
+        (void) _PR_MD_CLOSE_FILE(osfd);
+    } else {
+        _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+#ifdef WINNT
+        fd->secret->md.sync_file_io = PR_TRUE;
+#endif
+    }
+
+    return fd;
+}
+
+#ifndef NO_NSPR_10_SUPPORT
+/*
+** PR_Stat() for Win16 is defined in w16io.c
+** it is a hack to circumvent problems in Gromit and Java
+** See also: BugSplat: 98516.
+*/
+#if !defined(WIN16)
+/*
+ * This function is supposed to be for backward compatibility with
+ * nspr 1.0.  Therefore, it still uses the nspr 1.0 error-reporting
+ * mechanism -- returns a PRInt32, which is the error code when the call
+ * fails.
+ * 
+ * If we need this function in nspr 2.0, it should be changed to
+ * return PRStatus, as follows:
+ *
+ * PR_IMPLEMENT(PRStatus) PR_Stat(const char *name, struct stat *buf)
+ * {
+ *     PRInt32 rv;
+ *
+ *     rv = _PR_MD_STAT(name, buf);
+ *     if (rv < 0)
+ *         return PR_FAILURE;
+ *     else
+ *         return PR_SUCCESS;
+ * }
+ *
+ * -- wtc, 2/14/97.
+ */
+PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
+{
+    PRInt32 rv;
+
+    rv = _PR_MD_STAT(name, buf);
+	return rv;
+}
+
+#endif /* !defined(WIN16)  */
+#endif /* ! NO_NSPR_10_SUPPORT */
+
+PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
+{
+    PRStatus status = PR_SUCCESS;
+
+#ifdef WINNT
+    if (!fd->secret->md.io_model_committed) {
+        PRInt32 rv;
+        rv = _md_Associate((HANDLE)fd->secret->md.osfd);
+        PR_ASSERT(0 != rv);
+        fd->secret->md.io_model_committed = PR_TRUE;
+    }
+#endif
+
+    PR_Lock(_pr_flock_lock);
+    while (fd->secret->lockCount == -1)
+        PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
+    if (fd->secret->lockCount == 0) {
+        fd->secret->lockCount = -1;
+        PR_Unlock(_pr_flock_lock);
+        status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
+        PR_Lock(_pr_flock_lock);
+        fd->secret->lockCount = (status == PR_SUCCESS) ? 1 : 0;
+        PR_NotifyAllCondVar(_pr_flock_cv);
+    } else {
+        fd->secret->lockCount++;
+    }
+    PR_Unlock(_pr_flock_lock);
+ 
+    return status;
+}
+
+PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
+{
+    PRStatus status = PR_SUCCESS;
+
+#ifdef WINNT
+    if (!fd->secret->md.io_model_committed) {
+        PRInt32 rv;
+        rv = _md_Associate((HANDLE)fd->secret->md.osfd);
+        PR_ASSERT(0 != rv);
+        fd->secret->md.io_model_committed = PR_TRUE;
+    }
+#endif
+
+    PR_Lock(_pr_flock_lock);
+    if (fd->secret->lockCount == 0) {
+        status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
+        PR_ASSERT(status == PR_SUCCESS || fd->secret->lockCount == 0);
+        if (status == PR_SUCCESS)
+            fd->secret->lockCount = 1;
+    } else {
+        fd->secret->lockCount++;
+    }
+    PR_Unlock(_pr_flock_lock);
+
+    return status;
+}
+
+PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
+{
+    PRStatus rv = PR_SUCCESS;
+
+    PR_Lock(_pr_flock_lock);
+    if (fd->secret->lockCount == 1) {
+        rv = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
+        if (rv == PR_SUCCESS) 
+            fd->secret->lockCount = 0;
+    } else {
+        fd->secret->lockCount--;
+    }
+    PR_Unlock(_pr_flock_lock);
+
+    return rv;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CreatePipe(
+    PRFileDesc **readPipe,
+    PRFileDesc **writePipe
+)
+{
+#if defined(WIN32) && !defined(WINCE)
+    HANDLE readEnd, writeEnd;
+    SECURITY_ATTRIBUTES pipeAttributes;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    ZeroMemory(&pipeAttributes, sizeof(pipeAttributes));
+    pipeAttributes.nLength = sizeof(pipeAttributes);
+    pipeAttributes.bInheritHandle = TRUE;
+    if (CreatePipe(&readEnd, &writeEnd, &pipeAttributes, 0) == 0) {
+        PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+        return PR_FAILURE;
+    }
+    *readPipe = PR_AllocFileDesc((PROsfd)readEnd, &_pr_pipeMethods);
+    if (NULL == *readPipe) {
+        CloseHandle(readEnd);
+        CloseHandle(writeEnd);
+        return PR_FAILURE;
+    }
+    *writePipe = PR_AllocFileDesc((PROsfd)writeEnd, &_pr_pipeMethods);
+    if (NULL == *writePipe) {
+        PR_Close(*readPipe);
+        CloseHandle(writeEnd);
+        return PR_FAILURE;
+    }
+#ifdef WINNT
+    (*readPipe)->secret->md.sync_file_io = PR_TRUE;
+    (*writePipe)->secret->md.sync_file_io = PR_TRUE;
+#endif
+    (*readPipe)->secret->inheritable = _PR_TRI_TRUE;
+    (*writePipe)->secret->inheritable = _PR_TRI_TRUE;
+    return PR_SUCCESS;
+#elif defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+#ifdef XP_OS2
+    HFILE pipefd[2];
+#else
+    int pipefd[2];
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#ifdef XP_OS2
+    if (DosCreatePipe(&pipefd[0], &pipefd[1], 4096) != 0) {
+#else
+    if (pipe(pipefd) == -1) {
+#endif
+        /* XXX map pipe error */
+        PR_SetError(PR_UNKNOWN_ERROR, errno);
+        return PR_FAILURE;
+    }
+    *readPipe = PR_AllocFileDesc(pipefd[0], &_pr_pipeMethods);
+    if (NULL == *readPipe) {
+        close(pipefd[0]);
+        close(pipefd[1]);
+        return PR_FAILURE;
+    }
+    *writePipe = PR_AllocFileDesc(pipefd[1], &_pr_pipeMethods);
+    if (NULL == *writePipe) {
+        PR_Close(*readPipe);
+        close(pipefd[1]);
+        return PR_FAILURE;
+    }
+#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */
+    _PR_MD_MAKE_NONBLOCK(*readPipe);
+#endif
+    _PR_MD_INIT_FD_INHERITABLE(*readPipe, PR_FALSE);
+#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */
+    _PR_MD_MAKE_NONBLOCK(*writePipe);
+#endif
+    _PR_MD_INIT_FD_INHERITABLE(*writePipe, PR_FALSE);
+    return PR_SUCCESS;
+#else
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+#endif
+}
+
+#ifdef MOZ_UNICODE
+/* ================ UTF16 Interfaces ================================ */
+PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
+    const PRUnichar *name, PRIntn flags, PRIntn mode)
+{ 
+    PROsfd osfd;
+    PRFileDesc *fd = 0;
+#if !defined(_PR_HAVE_O_APPEND)
+    PRBool  appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE;
+#endif
+   
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+  
+    /* Map pr open flags and mode to os specific flags */
+    osfd = _PR_MD_OPEN_FILE_UTF16(name, flags, mode);
+    if (osfd != -1) {
+        fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
+        if (!fd) {
+            (void) _PR_MD_CLOSE_FILE(osfd);
+        } else {
+#if !defined(_PR_HAVE_O_APPEND)
+            fd->secret->appendMode = appendMode;
+#endif
+            _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
+        }
+    }
+    return fd;
+}
+ 
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
+{
+    PRInt32 rv;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    rv = _PR_MD_GETFILEINFO64_UTF16(fn, info);
+    if (rv < 0) {
+        return PR_FAILURE;
+    } else {
+        return PR_SUCCESS;
+    }
+}
+
+/* ================ UTF16 Interfaces ================================ */
+#endif /* MOZ_UNICODE */
diff --git a/mozilla/nsprpub/pr/src/io/prio.c b/mozilla/nsprpub/pr/src/io/prio.c
new file mode 100644
index 0000000..b779b1c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prio.c
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h> /* for memset() */
+
+
+/************************************************************************/
+
+PRLock *_pr_flock_lock;
+PRCondVar *_pr_flock_cv;
+
+#ifdef WINCE
+/*
+ * There are no stdin, stdout, stderr in Windows CE.  INVALID_HANDLE_VALUE
+ * should cause all I/O functions on the handle to fail.
+ */
+#define STD_INPUT_HANDLE  ((DWORD)-10)
+#define STD_OUTPUT_HANDLE ((DWORD)-11)
+#define STD_ERROR_HANDLE  ((DWORD)-12)
+
+static HANDLE GetStdHandle(DWORD nStdHandle)
+{
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return INVALID_HANDLE_VALUE;
+}
+#endif
+
+void _PR_InitIO(void)
+{
+    const PRIOMethods *methods = PR_GetFileMethods();
+
+    _PR_InitFdCache();
+
+    _pr_flock_lock = PR_NewLock();
+    _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
+
+#ifdef WIN32
+    _pr_stdin = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_INPUT_HANDLE),
+            methods);
+    _pr_stdout = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_OUTPUT_HANDLE),
+            methods);
+    _pr_stderr = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_ERROR_HANDLE),
+            methods);
+#ifdef WINNT
+    _pr_stdin->secret->md.sync_file_io = PR_TRUE;
+    _pr_stdout->secret->md.sync_file_io = PR_TRUE;
+    _pr_stderr->secret->md.sync_file_io = PR_TRUE;
+#endif
+#else
+    _pr_stdin = PR_AllocFileDesc(0, methods);
+    _pr_stdout = PR_AllocFileDesc(1, methods);
+    _pr_stderr = PR_AllocFileDesc(2, methods);
+#endif
+    _PR_MD_INIT_FD_INHERITABLE(_pr_stdin, PR_TRUE);
+    _PR_MD_INIT_FD_INHERITABLE(_pr_stdout, PR_TRUE);
+    _PR_MD_INIT_FD_INHERITABLE(_pr_stderr, PR_TRUE);
+
+    _PR_MD_INIT_IO();
+}
+
+void _PR_CleanupIO(void)
+{
+    PR_FreeFileDesc(_pr_stdin);
+    _pr_stdin = NULL;
+    PR_FreeFileDesc(_pr_stdout);
+    _pr_stdout = NULL;
+    PR_FreeFileDesc(_pr_stderr);
+    _pr_stderr = NULL;
+
+    if (_pr_flock_cv) {
+        PR_DestroyCondVar(_pr_flock_cv);
+        _pr_flock_cv = NULL;
+    }
+    if (_pr_flock_lock) {
+        PR_DestroyLock(_pr_flock_lock);
+        _pr_flock_lock = NULL;
+    }
+
+    _PR_CleanupFdCache();
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
+{
+    PRFileDesc *result = NULL;
+    PR_ASSERT((int) osfd >= PR_StandardInput && osfd <= PR_StandardError);
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    
+    switch (osfd)
+    {
+        case PR_StandardInput: result = _pr_stdin; break;
+        case PR_StandardOutput: result = _pr_stdout; break;
+        case PR_StandardError: result = _pr_stderr; break;
+        default:
+            (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    }
+    return result;
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
+    PROsfd osfd, const PRIOMethods *methods)
+{
+    PRFileDesc *fd;
+
+#ifdef XP_UNIX
+	/*
+	 * Assert that the file descriptor is small enough to fit in the
+	 * fd_set passed to select
+	 */
+	PR_ASSERT(osfd < FD_SETSIZE);
+#endif
+    fd = _PR_Getfd();
+    if (fd) {
+        /* Initialize the members of PRFileDesc and PRFilePrivate */
+        fd->methods = methods;
+        fd->secret->state = _PR_FILEDESC_OPEN;
+	fd->secret->md.osfd = osfd;
+        _PR_MD_INIT_FILEDESC(fd);
+    } else {
+	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    }
+
+    return fd;
+}
+
+PR_IMPLEMENT(void) PR_FreeFileDesc(PRFileDesc *fd)
+{
+    PR_ASSERT(fd);
+    _PR_Putfd(fd);
+}
+
+/*
+** Wait for some i/o to finish on one or more more poll descriptors.
+*/
+PR_IMPLEMENT(PRInt32) PR_Poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+	return(_PR_MD_PR_POLL(pds, npds, timeout));
+}
+
+/*
+** Set the inheritance attribute of a file descriptor.
+*/
+PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
+    PRFileDesc *fd,
+    PRBool inheritable)
+{
+#if defined(XP_UNIX) || defined(WIN32) || defined(XP_OS2) || defined(XP_BEOS)
+    /*
+     * Only a non-layered, NSPR file descriptor can be inherited
+     * by a child process.
+     */
+    if (fd->identity != PR_NSPR_IO_LAYER) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    if (fd->secret->inheritable != inheritable) {
+        if (_PR_MD_SET_FD_INHERITABLE(fd, inheritable) == PR_FAILURE) {
+            return PR_FAILURE;
+        }
+        fd->secret->inheritable = inheritable;
+    }
+    return PR_SUCCESS;
+#else
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+#endif
+}
+
+/*
+** This function only has a useful implementation in the debug build of
+** the pthreads version.
+*/
+PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
+{
+    /* do nothing */
+}  /* PT_FPrintStats */
diff --git a/mozilla/nsprpub/pr/src/io/priometh.c b/mozilla/nsprpub/pr/src/io/priometh.c
new file mode 100644
index 0000000..1ca474f
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/priometh.c
@@ -0,0 +1,628 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+
+/*****************************************************************************/
+/************************** Invalid I/O method object ************************/
+/*****************************************************************************/
+PRIOMethods _pr_faulty_methods = {
+    (PRDescType)0,
+    (PRCloseFN)_PR_InvalidStatus,
+    (PRReadFN)_PR_InvalidInt,
+    (PRWriteFN)_PR_InvalidInt,
+    (PRAvailableFN)_PR_InvalidInt,
+    (PRAvailable64FN)_PR_InvalidInt64,
+    (PRFsyncFN)_PR_InvalidStatus,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+    (PRPollFN)_PR_InvalidInt16,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt
+};
+
+PRIntn _PR_InvalidInt(void)
+{
+    PR_ASSERT(!"I/O method is invalid");
+    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+    return -1;
+}  /* _PR_InvalidInt */
+
+PRInt16 _PR_InvalidInt16(void)
+{
+    PR_ASSERT(!"I/O method is invalid");
+    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+    return -1;
+}  /* _PR_InvalidInt */
+
+PRInt64 _PR_InvalidInt64(void)
+{
+    PRInt64 rv;
+    LL_I2L(rv, -1);
+    PR_ASSERT(!"I/O method is invalid");
+    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+    return rv;
+}  /* _PR_InvalidInt */
+
+/*
+ * An invalid method that returns PRStatus
+ */
+
+PRStatus _PR_InvalidStatus(void)
+{
+    PR_ASSERT(!"I/O method is invalid");
+    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+    return PR_FAILURE;
+}  /* _PR_InvalidDesc */
+
+/*
+ * An invalid method that returns a pointer
+ */
+
+PRFileDesc *_PR_InvalidDesc(void)
+{
+    PR_ASSERT(!"I/O method is invalid");
+    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+    return NULL;
+}  /* _PR_InvalidDesc */
+
+PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file)
+{
+    return file->methods->file_type;
+}
+
+PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd)
+{
+    return (fd->methods->close)(fd);
+}
+
+PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+	return((fd->methods->read)(fd,buf,amount));
+}
+
+PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+	return((fd->methods->write)(fd,buf,amount));
+}
+
+PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
+{
+	return((fd->methods->seek)(fd, offset, whence));
+}
+
+PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
+{
+	return((fd->methods->seek64)(fd, offset, whence));
+}
+
+PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd)
+{
+	return((fd->methods->available)(fd));
+}
+
+PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd)
+{
+	return((fd->methods->available64)(fd));
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info)
+{
+	return((fd->methods->fileInfo)(fd, info));
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
+{
+	return((fd->methods->fileInfo64)(fd, info));
+}
+
+PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd)
+{
+	return((fd->methods->fsync)(fd));
+}
+
+PR_IMPLEMENT(PRStatus) PR_Connect(
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	return((fd->methods->connect)(fd,addr,timeout));
+}
+
+PR_IMPLEMENT(PRStatus) PR_ConnectContinue(
+    PRFileDesc *fd, PRInt16 out_flags)
+{
+	return((fd->methods->connectcontinue)(fd,out_flags));
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr,
+PRIntervalTime timeout)
+{
+	return((fd->methods->accept)(fd,addr,timeout));
+}
+
+PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr)
+{
+	return((fd->methods->bind)(fd,addr));
+}
+
+PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
+{
+	return((fd->methods->shutdown)(fd,how));
+}
+
+PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog)
+{
+	return((fd->methods->listen)(fd,backlog));
+}
+
+PR_IMPLEMENT(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+PRIntn flags, PRIntervalTime timeout)
+{
+	return((fd->methods->recv)(fd,buf,amount,flags,timeout));
+}
+
+PR_IMPLEMENT(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+PRIntn flags, PRIntervalTime timeout)
+{
+	return((fd->methods->send)(fd,buf,amount,flags,timeout));
+}
+
+PR_IMPLEMENT(PRInt32) PR_Writev(PRFileDesc *fd, const PRIOVec *iov,
+PRInt32 iov_size, PRIntervalTime timeout)
+{
+    if (iov_size > PR_MAX_IOVECTOR_SIZE)
+    {
+        PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+        return -1;
+    }
+	return((fd->methods->writev)(fd,iov,iov_size,timeout));
+}
+
+PR_IMPLEMENT(PRInt32) PR_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
+{
+	return((fd->methods->recvfrom)(fd,buf,amount,flags,addr,timeout));
+}
+
+PR_IMPLEMENT(PRInt32) PR_SendTo(
+    PRFileDesc *fd, const void *buf, PRInt32 amount,
+    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	return((fd->methods->sendto)(fd,buf,amount,flags,addr,timeout));
+}
+
+PR_IMPLEMENT(PRInt32) PR_TransmitFile(
+    PRFileDesc *sd, PRFileDesc *fd, const void *hdr, PRInt32 hlen,
+    PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+	return((sd->methods->transmitfile)(sd,fd,hdr,hlen,flags,timeout));
+}
+
+PR_IMPLEMENT(PRInt32) PR_AcceptRead(
+    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
+    void *buf, PRInt32 amount, PRIntervalTime timeout)
+{
+	return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout));
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
+{
+	return((fd->methods->getsockname)(fd,addr));
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
+{
+	return((fd->methods->getpeername)(fd,addr));
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetSocketOption(
+    PRFileDesc *fd, PRSocketOptionData *data)
+{
+	return((fd->methods->getsocketoption)(fd, data));
+}
+
+PR_IMPLEMENT(PRStatus) PR_SetSocketOption(
+    PRFileDesc *fd, const PRSocketOptionData *data)
+{
+	return((fd->methods->setsocketoption)(fd, data));
+}
+
+PR_IMPLEMENT(PRInt32) PR_SendFile(
+	PRFileDesc *sd, PRSendFileData *sfd,
+	PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+	return((sd->methods->sendfile)(sd,sfd,flags,timeout));
+}
+
+PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead(
+    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
+    void *buf, PRInt32 amount, PRIntervalTime timeout)
+{
+    PRInt32 rv = -1;
+    PRNetAddr remote;
+    PRFileDesc *accepted = NULL;
+
+    /*
+    ** The timeout does not apply to the accept portion of the
+    ** operation - it waits indefinitely.
+    */
+    accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT);
+    if (NULL == accepted) return rv;
+
+    rv = PR_Recv(accepted, buf, amount, 0, timeout);
+    if (rv >= 0)
+    {
+        /* copy the new info out where caller can see it */
+#define AMASK ((PRPtrdiff)7)  /* mask for alignment of PRNetAddr */
+        PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK;
+        *raddr = (PRNetAddr*)(aligned & ~AMASK);
+        memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
+        *nd = accepted;
+        return rv;
+    }
+
+    PR_Close(accepted);
+    return rv;
+}
+
+/*
+ * PR_EmulateSendFile
+ *
+ *    Send file sfd->fd across socket sd. If header/trailer are specified
+ *    they are sent before and after the file, respectively.
+ *
+ *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
+ *    
+ *    return number of bytes sent or -1 on error
+ *
+ */
+
+#if defined(XP_UNIX) || defined(WIN32)
+
+/*
+ * An implementation based on memory-mapped files
+ */
+
+#define SENDFILE_MMAP_CHUNK	(256 * 1024)
+
+PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
+    PRFileDesc *sd, PRSendFileData *sfd,
+    PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    PRInt32 rv, count = 0;
+    PRInt32 len, file_bytes, index = 0;
+    PRFileInfo info;
+    PRIOVec iov[3];
+    PRFileMap *mapHandle = NULL;
+    void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */
+    PRUint32 file_mmap_offset, alignment;
+    PRInt64 zero64;
+    PROffset64 file_mmap_offset64;
+    PRUint32 addr_offset, mmap_len;
+
+    /* Get file size */
+    if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
+        count = -1;
+        goto done;
+    }
+    if (sfd->file_nbytes &&
+            (info.size < (sfd->file_offset + sfd->file_nbytes))) {
+        /*
+         * there are fewer bytes in file to send than specified
+         */
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        count = -1;
+        goto done;
+    }
+    if (sfd->file_nbytes)
+        file_bytes = sfd->file_nbytes;
+    else
+        file_bytes = info.size - sfd->file_offset;
+
+    alignment = PR_GetMemMapAlignment();
+
+    /* number of initial bytes to skip in mmap'd segment */
+    addr_offset = sfd->file_offset % alignment;
+
+    /* find previous mmap alignment boundary */
+    file_mmap_offset = sfd->file_offset - addr_offset;
+
+    /*
+     * If the file is large, mmap and send the file in chunks so as
+     * to not consume too much virtual address space
+     */
+    mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
+    len = mmap_len - addr_offset;
+
+    /*
+     * Map in (part of) file. Take care of zero-length files.
+     */
+    if (len) {
+        LL_I2L(zero64, 0);
+        mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY);
+        if (!mapHandle) {
+            count = -1;
+            goto done;
+        }
+        LL_I2L(file_mmap_offset64, file_mmap_offset);
+        addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len);
+        if (!addr) {
+            count = -1;
+            goto done;
+        }
+    }
+    /*
+     * send headers first, followed by the file
+     */
+    if (sfd->hlen) {
+        iov[index].iov_base = (char *) sfd->header;
+        iov[index].iov_len = sfd->hlen;
+        index++;
+    }
+    if (len) {
+        iov[index].iov_base = (char*)addr + addr_offset;
+        iov[index].iov_len = len;
+        index++;
+    }
+    if ((file_bytes == len) && (sfd->tlen)) {
+        /*
+         * all file data is mapped in; send the trailer too
+         */
+        iov[index].iov_base = (char *) sfd->trailer;
+        iov[index].iov_len = sfd->tlen;
+        index++;
+    }
+    rv = PR_Writev(sd, iov, index, timeout);
+    if (len)
+        PR_MemUnmap(addr, mmap_len);
+    if (rv < 0) {
+        count = -1;
+        goto done;
+    }
+
+    PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
+
+    file_bytes -= len;
+    count += rv;
+    if (!file_bytes)    /* header, file and trailer are sent */
+        goto done;
+
+    /*
+     * send remaining bytes of the file, if any
+     */
+    len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
+    while (len > 0) {
+        /*
+         * Map in (part of) file
+         */
+        file_mmap_offset = sfd->file_offset + count - sfd->hlen;
+        PR_ASSERT((file_mmap_offset % alignment) == 0);
+
+        LL_I2L(file_mmap_offset64, file_mmap_offset);
+        addr = PR_MemMap(mapHandle, file_mmap_offset64, len);
+        if (!addr) {
+            count = -1;
+            goto done;
+        }
+        rv = PR_Send(sd, addr, len, 0, timeout);
+        PR_MemUnmap(addr, len);
+        if (rv < 0) {
+            count = -1;
+            goto done;
+        }
+
+        PR_ASSERT(rv == len);
+        file_bytes -= rv;
+        count += rv;
+        len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
+    }
+    PR_ASSERT(0 == file_bytes);
+    if (sfd->tlen) {
+        rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
+        if (rv >= 0) {
+            PR_ASSERT(rv == sfd->tlen);
+            count += rv;
+        } else
+            count = -1;
+    }
+done:
+    if (mapHandle)
+        PR_CloseFileMap(mapHandle);
+    if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
+        PR_Close(sd);
+    return count;
+}
+
+#else
+
+PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
+    PRFileDesc *sd, PRSendFileData *sfd,
+    PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    PRInt32 rv, count = 0;
+    PRInt32 rlen;
+    const void * buffer;
+    PRInt32 buflen;
+    PRInt32 sendbytes, readbytes;
+    char *buf;
+
+#define _SENDFILE_BUFSIZE   (16 * 1024)
+
+    buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
+    if (buf == NULL) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return -1;
+    }
+
+    /*
+     * send header first
+     */
+    buflen = sfd->hlen;
+    buffer = sfd->header;
+    while (buflen) {
+        rv = PR_Send(sd, buffer, buflen, 0, timeout);
+        if (rv < 0) {
+            /* PR_Send() has invoked PR_SetError(). */
+            rv = -1;
+            goto done;
+        } else {
+            count += rv;
+            buffer = (const void*) ((const char*)buffer + rv);
+            buflen -= rv;
+        }
+    }
+
+    /*
+     * send file next
+     */
+    if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
+        rv = -1;
+        goto done;
+    }
+    sendbytes = sfd->file_nbytes;
+    if (sendbytes == 0) {
+        /* send entire file */
+        while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
+            while (rlen) {
+                char *bufptr = buf;
+
+                rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
+                if (rv < 0) {
+                    /* PR_Send() has invoked PR_SetError(). */
+                    rv = -1;
+                    goto done;
+                } else {
+                    count += rv;
+                    bufptr = ((char*)bufptr + rv);
+                    rlen -= rv;
+                }
+            }
+        }
+        if (rlen < 0) {
+            /* PR_Read() has invoked PR_SetError(). */
+            rv = -1;
+            goto done;
+        }
+    } else {
+        readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
+        while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
+            while (rlen) {
+                char *bufptr = buf;
+
+                rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
+                if (rv < 0) {
+                    /* PR_Send() has invoked PR_SetError(). */
+                    rv = -1;
+                    goto done;
+                } else {
+                    count += rv;
+                    sendbytes -= rv;
+                    bufptr = ((char*)bufptr + rv);
+                    rlen -= rv;
+                }
+            }
+            readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
+        }
+        if (rlen < 0) {
+            /* PR_Read() has invoked PR_SetError(). */
+            rv = -1;
+            goto done;
+        } else if (sendbytes != 0) {
+            /*
+             * there are fewer bytes in file to send than specified
+             */
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = -1;
+            goto done;
+        }
+    }
+
+    /*
+     * send trailer last
+     */
+    buflen = sfd->tlen;
+    buffer = sfd->trailer;
+    while (buflen) {
+        rv =  PR_Send(sd, buffer, buflen, 0, timeout);
+        if (rv < 0) {
+            /* PR_Send() has invoked PR_SetError(). */
+            rv = -1;
+            goto done;
+        } else {
+            count += rv;
+            buffer = (const void*) ((const char*)buffer + rv);
+            buflen -= rv;
+        }
+    }
+    rv = count;
+
+done:
+    if (buf)
+        PR_DELETE(buf);
+    if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
+        PR_Close(sd);
+    return rv;
+}
+
+#endif
+
+/* priometh.c */
diff --git a/mozilla/nsprpub/pr/src/io/pripv6.c b/mozilla/nsprpub/pr/src/io/pripv6.c
new file mode 100644
index 0000000..e4af39c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/pripv6.c
@@ -0,0 +1,396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:        pripv6.c
+** Description: Support for various functions unique to IPv6
+*/
+#include "primpl.h"
+#include <string.h>
+
+#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
+
+static PRIOMethods ipv6_to_v4_tcpMethods;
+static PRIOMethods ipv6_to_v4_udpMethods;
+static PRDescIdentity _pr_ipv6_to_ipv4_id;
+extern PRBool IsValidNetAddr(const PRNetAddr *addr);
+extern PRIPv6Addr _pr_in6addr_any;
+extern PRIPv6Addr _pr_in6addr_loopback;
+
+/*
+ * convert an IPv4-mapped IPv6 addr to an IPv4 addr
+ */
+static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
+											PRNetAddr *dst_v4addr)
+{
+const PRUint8 *srcp;
+
+	PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
+
+	if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) {
+		srcp = src_v6addr->ipv6.ip.pr_s6_addr;
+		memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4);
+    } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) {
+        dst_v4addr->inet.ip = htonl(INADDR_ANY);
+    } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) {
+        dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK);
+    }
+	dst_v4addr->inet.family = PR_AF_INET;
+	dst_v4addr->inet.port = src_v6addr->ipv6.port;
+}
+
+/*
+ * convert an IPv4 addr to an IPv4-mapped IPv6 addr
+ */
+static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
+                                            PRNetAddr *dst_v6addr)
+{
+PRUint8 *dstp;
+
+	PR_ASSERT(PR_AF_INET == src_v4addr->inet.family);
+	dst_v6addr->ipv6.family = PR_AF_INET6;
+	dst_v6addr->ipv6.port = src_v4addr->inet.port;
+
+ 	if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
+		dst_v6addr->ipv6.ip = _pr_in6addr_any;
+	} else {
+		dstp = dst_v6addr->ipv6.ip.pr_s6_addr;
+		memset(dstp, 0, 10);
+		memset(dstp + 10, 0xff, 2);
+		memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
+	}
+}
+
+static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
+								const PRNetAddr *addr)
+{
+	PRNetAddr tmp_ipv4addr;
+	const PRNetAddr *tmp_addrp;
+	PRFileDesc *lo = fd->lower;
+
+	if (PR_AF_INET6 != addr->raw.family) {
+        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return PR_FAILURE;
+	}
+	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
+    			PR_IsNetAddrType(addr, PR_IpAddrAny)) {
+		_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
+		tmp_addrp = &tmp_ipv4addr;
+	} else {
+        PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
+		return PR_FAILURE;
+	}
+	return((lo->methods->bind)(lo,tmp_addrp));
+}
+
+static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRNetAddr tmp_ipv4addr;
+	const PRNetAddr *tmp_addrp;
+
+	if (PR_AF_INET6 != addr->raw.family) {
+        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return PR_FAILURE;
+	}
+	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
+			PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
+		_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
+		tmp_addrp = &tmp_ipv4addr;
+	} else {
+        PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
+		return PR_FAILURE;
+	}
+	return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
+}
+
+static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
+    PRFileDesc *fd, const void *buf, PRInt32 amount,
+    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRNetAddr tmp_ipv4addr;
+	const PRNetAddr *tmp_addrp;
+
+	if (PR_AF_INET6 != addr->raw.family) {
+        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return PR_FAILURE;
+	}
+	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
+			PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
+		_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
+		tmp_addrp = &tmp_ipv4addr;
+	} else {
+        PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
+		return PR_FAILURE;
+	}
+    return (fd->lower->methods->sendto)(
+        fd->lower, buf, amount, flags, tmp_addrp, timeout);
+}
+
+static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept (
+    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PRStatus rv;
+    PRFileDesc *newfd;
+    PRFileDesc *newstack;
+	PRNetAddr tmp_ipv4addr;
+    PRNetAddr *addrlower = NULL;
+
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    newstack = PR_NEW(PRFileDesc);
+    if (NULL == newstack)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+    *newstack = *fd;  /* make a copy of the accepting layer */
+
+    if (addr)
+        addrlower = &tmp_ipv4addr;
+    newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
+    if (NULL == newfd)
+    {
+        PR_DELETE(newstack);
+        return NULL;
+    }
+    if (addr)
+        _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
+
+    rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
+    PR_ASSERT(PR_SUCCESS == rv);
+    return newfd;  /* that's it */
+}
+
+static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
+			PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
+							PRIntervalTime timeout)
+{
+    PRInt32 nbytes;
+    PRStatus rv;
+	PRNetAddr tmp_ipv4addr;
+    PRFileDesc *newstack;
+
+    PR_ASSERT(sd != NULL);
+    PR_ASSERT(sd->lower != NULL);
+
+    newstack = PR_NEW(PRFileDesc);
+    if (NULL == newstack)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return -1;
+    }
+    *newstack = *sd;  /* make a copy of the accepting layer */
+
+    nbytes = sd->lower->methods->acceptread(
+        sd->lower, nd, ipv6_raddr, buf, amount, timeout);
+    if (-1 == nbytes)
+    {
+        PR_DELETE(newstack);
+        return nbytes;
+    }
+	tmp_ipv4addr = **ipv6_raddr;	/* copy */
+	_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
+
+    /* this PR_PushIOLayer call cannot fail */
+    rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
+    PR_ASSERT(PR_SUCCESS == rv);
+    return nbytes;
+}
+
+static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
+										PRNetAddr *ipv6addr)
+{
+	PRStatus result;
+	PRNetAddr tmp_ipv4addr;
+
+	result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
+	if (PR_SUCCESS == result) {
+		_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
+		PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
+	}
+	return result;
+}
+
+static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
+										PRNetAddr *ipv6addr)
+{
+	PRStatus result;
+	PRNetAddr tmp_ipv4addr;
+
+	result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr);
+	if (PR_SUCCESS == result) {
+		_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
+		PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
+	}
+	return result;
+}
+
+static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
+			PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
+				PRIntervalTime timeout)
+{
+	PRNetAddr tmp_ipv4addr;
+	PRInt32 result;
+
+    result = (fd->lower->methods->recvfrom)(
+        fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
+	if (-1 != result) {
+		_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
+		PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
+	}
+	return result;
+}
+
+#if defined(_PR_INET6_PROBE)
+static PRBool ipv6_is_present;
+extern PRBool _pr_test_ipv6_socket(void);
+
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+extern PRStatus _pr_find_getipnodebyname(void);
+#endif
+
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
+extern PRStatus _pr_find_getaddrinfo(void);
+#endif
+
+static PRBool
+_pr_probe_ipv6_presence(void)
+{
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+    if (_pr_find_getipnodebyname() != PR_SUCCESS)
+        return PR_FALSE;
+#endif
+
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
+    if (_pr_find_getaddrinfo() != PR_SUCCESS)
+        return PR_FALSE;
+#endif
+
+    return _pr_test_ipv6_socket();
+}
+#endif  /* _PR_INET6_PROBE */
+
+static PRCallOnceType _pr_init_ipv6_once;
+
+static PRStatus PR_CALLBACK _pr_init_ipv6(void)
+{
+    const PRIOMethods *stubMethods;
+
+#if defined(_PR_INET6_PROBE)
+    ipv6_is_present = _pr_probe_ipv6_presence();
+    if (ipv6_is_present)
+        return PR_SUCCESS;
+#endif
+
+    _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
+    PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
+
+	stubMethods = PR_GetDefaultIOMethods();
+
+	ipv6_to_v4_tcpMethods = *stubMethods;  /* first get the entire batch */
+	/* then override the ones we care about */
+	ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect;
+	ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind;
+	ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept;
+	ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead;
+	ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
+	ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
+/*
+	ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
+	ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
+*/
+	ipv6_to_v4_udpMethods = *stubMethods;  /* first get the entire batch */
+	/* then override the ones we care about */
+	ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect;
+	ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind;
+	ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo;
+	ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom;
+	ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName;
+	ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
+/*
+	ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
+	ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
+*/
+	return PR_SUCCESS;
+}
+
+#if defined(_PR_INET6_PROBE)
+PRBool _pr_ipv6_is_present(void)
+{
+    if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS)
+        return PR_FALSE;
+    return ipv6_is_present;
+}
+#endif
+
+PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
+{
+	PRFileDesc *ipv6_fd = NULL;
+
+	if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS)
+		return PR_FAILURE;
+
+	/*
+	 * For platforms with no support for IPv6 
+	 * create layered socket for IPv4-mapped IPv6 addresses
+	 */
+	if (fd->methods->file_type == PR_DESC_SOCKET_TCP)
+		ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
+									&ipv6_to_v4_tcpMethods);
+	else
+		ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
+									&ipv6_to_v4_udpMethods);
+	if (NULL == ipv6_fd) {
+		goto errorExit;
+	} 
+	ipv6_fd->secret = NULL;
+
+	if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
+		goto errorExit;
+	}
+
+	return PR_SUCCESS;
+errorExit:
+
+	if (ipv6_fd)
+		ipv6_fd->dtor(ipv6_fd);
+	return PR_FAILURE;
+}
+
+#endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */
diff --git a/mozilla/nsprpub/pr/src/io/prlayer.c b/mozilla/nsprpub/pr/src/io/prlayer.c
new file mode 100644
index 0000000..cf48d23
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prlayer.c
@@ -0,0 +1,768 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:        prlayer.c
+** Description: Routines for handling pushable protocol modules on sockets.
+*/
+
+#include "primpl.h"
+#include "prerror.h"
+#include "prmem.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prio.h"
+
+#include <string.h> /* for memset() */
+static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack);
+
+void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd)
+{
+    PR_ASSERT(fd != NULL);
+    if (NULL != fd->lower) fd->lower->higher = fd->higher;
+    if (NULL != fd->higher) fd->higher->lower = fd->lower;
+    PR_DELETE(fd);
+}
+
+/*
+** Default methods that just call down to the next fd.
+*/
+static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd)
+{
+    PRFileDesc *top, *lower;
+	PRStatus rv;
+
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+    PR_ASSERT(fd->secret == NULL);
+    PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
+
+	if (PR_IO_LAYER_HEAD == fd->identity) {
+		/*
+		 * new style stack; close all the layers, before deleting the
+		 * stack head
+		 */
+		rv = fd->lower->methods->close(fd->lower);
+		_PR_DestroyIOLayer(fd);
+		return rv;
+	} else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) {
+		/*
+		 * lower layers of new style stack
+		 */
+		lower = fd->lower;
+		/*
+		 * pop and cleanup current layer
+		 */
+    	top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER);
+		top->dtor(top);
+		/*
+		 * then call lower layer
+		 */
+		return (lower->methods->close(lower));
+	} else {
+		/* old style stack */
+    	top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
+		top->dtor(top);
+		return (fd->methods->close)(fd);
+	}
+}
+
+static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->read)(fd->lower, buf, amount);
+}
+
+static PRInt32 PR_CALLBACK pl_DefWrite (
+    PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->write)(fd->lower, buf, amount);
+}
+
+static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->available)(fd->lower);
+}
+
+static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->available64)(fd->lower);
+}
+
+static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->fsync)(fd->lower);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSeek (
+    PRFileDesc *fd, PRInt32 offset, PRSeekWhence how)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->seek)(fd->lower, offset, how);
+}
+
+static PRInt64 PR_CALLBACK pl_DefSeek64 (
+    PRFileDesc *fd, PRInt64 offset, PRSeekWhence how)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->seek64)(fd->lower, offset, how);
+}
+
+static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->fileInfo)(fd->lower, info);
+}
+
+static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->fileInfo64)(fd->lower, info);
+}
+
+static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov,
+    PRInt32 size, PRIntervalTime timeout)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
+}
+
+static PRStatus PR_CALLBACK pl_DefConnect (
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->connect)(fd->lower, addr, timeout);
+}
+
+static PRStatus PR_CALLBACK pl_DefConnectcontinue (
+    PRFileDesc *fd, PRInt16 out_flags)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
+}
+
+static PRFileDesc* PR_CALLBACK pl_TopAccept (
+    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PRStatus rv;
+    PRFileDesc *newfd, *layer = fd;
+    PRFileDesc *newstack;
+	PRBool newstyle_stack = PR_FALSE;
+
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+	/* test for new style stack */
+	while (NULL != layer->higher)
+		layer = layer->higher;
+	newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
+    newstack = PR_NEW(PRFileDesc);
+    if (NULL == newstack)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+    *newstack = *fd;  /* make a copy of the accepting layer */
+
+    newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
+    if (NULL == newfd)
+    {
+        PR_DELETE(newstack);
+        return NULL;
+    }
+
+    if (newstyle_stack) {
+		newstack->lower = newfd;
+		newfd->higher = newstack;
+		return newstack;
+	} else {
+		/* this PR_PushIOLayer call cannot fail */
+		rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
+		PR_ASSERT(PR_SUCCESS == rv);
+    	return newfd;  /* that's it */
+	}
+}
+
+static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->bind)(fd->lower, addr);
+}
+
+static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->listen)(fd->lower, backlog);
+}
+
+static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->shutdown)(fd->lower, how);
+}
+
+static PRInt32 PR_CALLBACK pl_DefRecv (
+    PRFileDesc *fd, void *buf, PRInt32 amount,
+    PRIntn flags, PRIntervalTime timeout)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->recv)(
+        fd->lower, buf, amount, flags, timeout);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSend (
+    PRFileDesc *fd, const void *buf,
+    PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
+}
+
+static PRInt32 PR_CALLBACK pl_DefRecvfrom (
+    PRFileDesc *fd, void *buf, PRInt32 amount,
+    PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->recvfrom)(
+        fd->lower, buf, amount, flags, addr, timeout);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSendto (
+    PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+    const PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->sendto)(
+        fd->lower, buf, amount, flags, addr, timeout);
+}
+
+static PRInt16 PR_CALLBACK pl_DefPoll (
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
+}
+
+static PRInt32 PR_CALLBACK pl_DefAcceptread (
+    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf,
+    PRInt32 amount, PRIntervalTime t)
+{
+    PRInt32 nbytes;
+    PRStatus rv;
+    PRFileDesc *newstack;
+    PRFileDesc *layer = sd;
+	PRBool newstyle_stack = PR_FALSE;
+
+    PR_ASSERT(sd != NULL);
+    PR_ASSERT(sd->lower != NULL);
+
+	/* test for new style stack */
+	while (NULL != layer->higher)
+		layer = layer->higher;
+	newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
+    newstack = PR_NEW(PRFileDesc);
+    if (NULL == newstack)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return -1;
+    }
+    *newstack = *sd;  /* make a copy of the accepting layer */
+
+    nbytes = sd->lower->methods->acceptread(
+        sd->lower, nd, raddr, buf, amount, t);
+    if (-1 == nbytes)
+    {
+        PR_DELETE(newstack);
+        return nbytes;
+    }
+    if (newstyle_stack) {
+		newstack->lower = *nd;
+		(*nd)->higher = newstack;
+		*nd = newstack;
+		return nbytes;
+	} else {
+		/* this PR_PushIOLayer call cannot fail */
+		rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
+		PR_ASSERT(PR_SUCCESS == rv);
+		return nbytes;
+	}
+}
+
+static PRInt32 PR_CALLBACK pl_DefTransmitfile (
+    PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen,
+    PRTransmitFileFlags flags, PRIntervalTime t)
+{
+    PR_ASSERT(sd != NULL);
+    PR_ASSERT(sd->lower != NULL);
+
+    return sd->lower->methods->transmitfile(
+        sd->lower, fd, headers, hlen, flags, t);
+}
+
+static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->getsockname)(fd->lower, addr);
+}
+
+static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->getpeername)(fd->lower, addr);
+}
+
+static PRStatus PR_CALLBACK pl_DefGetsocketoption (
+    PRFileDesc *fd, PRSocketOptionData *data)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->getsocketoption)(fd->lower, data);
+}
+
+static PRStatus PR_CALLBACK pl_DefSetsocketoption (
+    PRFileDesc *fd, const PRSocketOptionData *data)
+{
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(fd->lower != NULL);
+
+    return (fd->lower->methods->setsocketoption)(fd->lower, data);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSendfile (
+	PRFileDesc *sd, PRSendFileData *sfd,
+	PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    PR_ASSERT(sd != NULL);
+    PR_ASSERT(sd->lower != NULL);
+
+    return sd->lower->methods->sendfile(
+        sd->lower, sfd, flags, timeout);
+}
+
+/* Methods for the top of the stack.  Just call down to the next fd. */
+static PRIOMethods pl_methods = {
+    PR_DESC_LAYERED,
+    pl_TopClose,
+    pl_DefRead,
+    pl_DefWrite,
+    pl_DefAvailable,
+    pl_DefAvailable64,
+    pl_DefFsync,
+    pl_DefSeek,
+    pl_DefSeek64,
+    pl_DefFileInfo,
+    pl_DefFileInfo64,
+    pl_DefWritev,
+    pl_DefConnect,
+    pl_TopAccept,
+    pl_DefBind,
+    pl_DefListen,
+    pl_DefShutdown,
+    pl_DefRecv,
+    pl_DefSend,
+    pl_DefRecvfrom,
+    pl_DefSendto,
+    pl_DefPoll,
+    pl_DefAcceptread,
+    pl_DefTransmitfile,
+    pl_DefGetsockname,
+    pl_DefGetpeername,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt,
+    pl_DefGetsocketoption,
+    pl_DefSetsocketoption,
+    pl_DefSendfile,
+    pl_DefConnectcontinue,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt
+};
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void)
+{
+    return &pl_methods;
+}  /* PR_GetDefaultIOMethods */
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub(
+    PRDescIdentity ident, const PRIOMethods *methods)
+{
+    PRFileDesc *fd = NULL;
+    PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
+    if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident))
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    else
+    {
+        fd = PR_NEWZAP(PRFileDesc);
+        if (NULL == fd)
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        else
+        {
+            fd->methods = methods;
+            fd->dtor = pl_FDDestructor;
+            fd->identity = ident;
+        }
+    }
+    return fd;
+}  /* PR_CreateIOLayerStub */
+
+/*
+ * PR_CreateIOLayer
+ *		Create a new style stack, where the stack top is a dummy header.
+ *		Unlike the old style stacks, the contents of the stack head
+ *		are not modified when a layer is pushed onto or popped from a new
+ *		style stack.
+ */
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top)
+{
+    PRFileDesc *fd = NULL;
+
+	fd = PR_NEWZAP(PRFileDesc);
+	if (NULL == fd)
+		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	else
+	{
+		fd->methods = &pl_methods;
+		fd->dtor = pl_FDDestructor;
+		fd->identity = PR_IO_LAYER_HEAD;
+		fd->higher = NULL;
+		fd->lower = top;
+		top->higher = fd;
+		top->lower = NULL;
+	}
+    return fd;
+}  /* PR_CreateIOLayer */
+
+/*
+ * _PR_DestroyIOLayer
+ *		Delete the stack head of a new style stack.
+ */
+
+static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack)
+{
+    if (NULL == stack)
+        return PR_FAILURE;
+    else {
+        PR_DELETE(stack);
+    	return PR_SUCCESS;
+    }
+}  /* _PR_DestroyIOLayer */
+
+PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
+    PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd)
+{
+    PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id);
+
+    PR_ASSERT(fd != NULL);
+    PR_ASSERT(stack != NULL);
+    PR_ASSERT(insert != NULL);
+    PR_ASSERT(PR_IO_LAYER_HEAD != id);
+    if ((NULL == stack) || (NULL == fd) || (NULL == insert))
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    if (stack == insert)
+    {
+		/* going on top of the stack */
+		/* old-style stack */	
+		PRFileDesc copy = *stack;
+		*stack = *fd;
+		*fd = copy;
+		fd->higher = stack;
+		stack->lower = fd;
+		stack->higher = NULL;
+	} else {
+        /*
+		 * going somewhere in the middle of the stack for both old and new
+		 * style stacks, or going on top of stack for new style stack
+		 */
+        fd->lower = insert;
+        fd->higher = insert->higher;
+
+        insert->higher->lower = fd;
+        insert->higher = fd;
+    }
+
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
+{
+    PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
+
+    PR_ASSERT(0 != id);
+    PR_ASSERT(NULL != stack);
+    PR_ASSERT(NULL != extract);
+    if ((NULL == stack) || (0 == id) || (NULL == extract))
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return NULL;
+    }
+
+    if (extract == stack) {
+        /* popping top layer of the stack */
+		/* old style stack */
+        PRFileDesc copy = *stack;
+        extract = stack->lower;
+        *stack = *extract;
+        *extract = copy;
+        stack->higher = NULL;
+	} else if ((PR_IO_LAYER_HEAD == stack->identity) &&
+					(extract == stack->lower) && (extract->lower == NULL)) {
+			/*
+			 * new style stack
+			 * popping the only layer in the stack; delete the stack too
+			 */
+			stack->lower = NULL;
+			_PR_DestroyIOLayer(stack);
+	} else {
+		/* for both kinds of stacks */
+        extract->lower->higher = extract->higher;
+        extract->higher->lower = extract->lower;
+    }
+    extract->higher = extract->lower = NULL;
+    return extract;
+}  /* PR_PopIOLayer */
+
+#define ID_CACHE_INCREMENT 16
+typedef struct _PRIdentity_cache
+{
+    PRLock *ml;
+    char **name;
+    PRIntn length;
+    PRDescIdentity ident;
+} _PRIdentity_cache;
+
+static _PRIdentity_cache identity_cache;
+
+PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name)
+{
+    PRDescIdentity identity, length;
+    char **names = NULL, *name = NULL, **old = NULL;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident);
+
+    if (NULL != layer_name)
+    {
+        name = (char*)PR_Malloc(strlen(layer_name) + 1);
+        if (NULL == name)
+        {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return PR_INVALID_IO_LAYER;
+        }
+        strcpy(name, layer_name);
+    }
+
+    /* this initial code runs unsafe */
+retry:
+    PR_ASSERT(NULL == names);
+    length = identity_cache.length;
+    if (length < (identity_cache.ident + 1))
+    {
+        length += ID_CACHE_INCREMENT;
+        names = (char**)PR_CALLOC(length * sizeof(char*));
+        if (NULL == names)
+        {
+            if (NULL != name) PR_DELETE(name);
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return PR_INVALID_IO_LAYER;
+        }
+    }
+
+    /* now we get serious about thread safety */
+    PR_Lock(identity_cache.ml);
+    PR_ASSERT(identity_cache.ident <= identity_cache.length);
+    identity = identity_cache.ident + 1;
+    if (identity > identity_cache.length)  /* there's no room */
+    {
+        /* we have to do something - hopefully it's already done */
+        if ((NULL != names) && (length >= identity))
+        {
+            /* what we did is still okay */
+            memcpy(
+                names, identity_cache.name,
+                identity_cache.length * sizeof(char*));
+            old = identity_cache.name;
+            identity_cache.name = names;
+            identity_cache.length = length;
+            names = NULL;
+        }
+        else
+        {
+            PR_ASSERT(identity_cache.ident <= identity_cache.length);
+            PR_Unlock(identity_cache.ml);
+            if (NULL != names) PR_DELETE(names);
+            goto retry;
+        }
+    }
+    if (NULL != name) /* there's a name to be stored */
+    {
+        identity_cache.name[identity] = name;
+    }
+    identity_cache.ident = identity;
+    PR_ASSERT(identity_cache.ident <= identity_cache.length);
+    PR_Unlock(identity_cache.ml);
+
+    if (NULL != old) PR_DELETE(old);
+    if (NULL != names) PR_DELETE(names);
+
+    return identity;
+}  /* PR_GetUniqueIdentity */
+
+PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (PR_TOP_IO_LAYER == ident) return NULL;
+
+    PR_ASSERT(ident <= identity_cache.ident);
+    return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
+}  /* PR_GetNameForIdentity */
+
+PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd)
+{
+    PR_ASSERT(NULL != fd);
+    if (PR_IO_LAYER_HEAD == fd->identity) {
+    	PR_ASSERT(NULL != fd->lower);
+    	return fd->lower->identity;
+	} else
+    	return fd->identity;
+}  /* PR_GetLayersIdentity */
+
+PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id)
+{
+    PRFileDesc *layer = fd;
+
+    if (PR_TOP_IO_LAYER == id) {
+    	if (PR_IO_LAYER_HEAD == fd->identity)
+			return fd->lower;
+		else 
+			return fd;
+	}
+
+    for (layer = fd; layer != NULL; layer = layer->lower)
+    {
+        if (id == layer->identity) return layer;
+    }
+    for (layer = fd; layer != NULL; layer = layer->higher)
+    {
+        if (id == layer->identity) return layer;
+    }
+    return NULL;
+}  /* PR_GetIdentitiesLayer */
+
+void _PR_InitLayerCache(void)
+{
+    memset(&identity_cache, 0, sizeof(identity_cache));
+    identity_cache.ml = PR_NewLock();
+    PR_ASSERT(NULL != identity_cache.ml);
+}  /* _PR_InitLayerCache */
+
+void _PR_CleanupLayerCache(void)
+{
+    if (identity_cache.ml)
+    {
+        PR_DestroyLock(identity_cache.ml);
+        identity_cache.ml = NULL;
+    }
+
+    if (identity_cache.name)
+    {
+        PRDescIdentity ident;
+
+        for (ident = 0; ident <= identity_cache.ident; ident++)
+            PR_DELETE(identity_cache.name[ident]);
+
+        PR_DELETE(identity_cache.name);
+    }
+}  /* _PR_CleanupLayerCache */
+
+/* prlayer.c */
diff --git a/mozilla/nsprpub/pr/src/io/prlog.c b/mozilla/nsprpub/pr/src/io/prlog.c
new file mode 100644
index 0000000..8a79601
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prlog.c
@@ -0,0 +1,564 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   IBM Corporation
+ *
+ * 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 "primpl.h"
+#include "prenv.h"
+#include "prprf.h"
+#include <string.h>
+
+/*
+ * Lock used to lock the log.
+ *
+ * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may
+ * contain assertions.  We have to avoid assertions in _PR_LOCK_LOG
+ * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG.
+ * This can lead to infinite recursion.
+ */
+static PRLock *_pr_logLock;
+#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
+#define _PR_LOCK_LOG() PR_Lock(_pr_logLock);
+#define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock);
+#elif defined(_PR_GLOBAL_THREADS_ONLY)
+#define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock)
+#define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); }
+#else
+
+#define _PR_LOCK_LOG() \
+{ \
+    PRIntn _is; \
+    PRThread *_me = _PR_MD_CURRENT_THREAD(); \
+    if (!_PR_IS_NATIVE_THREAD(_me)) \
+        _PR_INTSOFF(_is); \
+    _PR_LOCK_LOCK(_pr_logLock)
+
+#define _PR_UNLOCK_LOG() \
+    _PR_LOCK_UNLOCK(_pr_logLock); \
+    PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \
+    if (!_PR_IS_NATIVE_THREAD(_me)) \
+        _PR_INTSON(_is); \
+}
+
+#endif
+
+#if defined(XP_PC)
+#define strcasecmp stricmp
+#endif
+
+/*
+ * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE,
+ * because every asynchronous file io operation leads to a fiber context
+ * switch.  So we define _PUT_LOG as fputs (from stdio.h).  A side
+ * benefit is that fputs handles the LF->CRLF translation.  This
+ * code can also be used on other platforms with file stream io.
+ */
+#if defined(WIN32) || defined(XP_OS2)
+#define _PR_USE_STDIO_FOR_LOGGING
+#endif
+
+/*
+** Coerce Win32 log output to use OutputDebugString() when
+** NSPR_LOG_FILE is set to "WinDebug".
+*/
+#if defined(XP_PC)
+#define WIN32_DEBUG_FILE (FILE*)-2
+#endif
+
+#ifdef WINCE
+static void OutputDebugStringA(const char* msg) {
+    int len = MultiByteToWideChar(CP_ACP, 0, msg, -1, 0, 0);
+    WCHAR *wMsg = (WCHAR *)PR_Malloc(len * sizeof(WCHAR));
+    MultiByteToWideChar(CP_ACP, 0, msg, -1, wMsg, len);
+    OutputDebugStringW(wMsg);
+    PR_Free(wMsg);
+}
+#endif
+
+/* Macros used to reduce #ifdef pollution */
+
+#if defined(_PR_USE_STDIO_FOR_LOGGING) && defined(XP_PC)
+#define _PUT_LOG(fd, buf, nb) \
+    PR_BEGIN_MACRO \
+    if (logFile == WIN32_DEBUG_FILE) { \
+        char savebyte = buf[nb]; \
+        buf[nb] = '\0'; \
+        OutputDebugStringA(buf); \
+        buf[nb] = savebyte; \
+    } else { \
+        fwrite(buf, 1, nb, fd); \
+        fflush(fd); \
+    } \
+    PR_END_MACRO
+#elif defined(_PR_USE_STDIO_FOR_LOGGING)
+#define _PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);}
+#elif defined(_PR_PTHREADS)
+#define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
+#else
+#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
+#endif
+
+/************************************************************************/
+
+static PRLogModuleInfo *logModules;
+
+static char *logBuf = NULL;
+static char *logp;
+static char *logEndp;
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+static FILE *logFile = NULL;
+#else
+static PRFileDesc *logFile = 0;
+#endif
+static PRBool outputTimeStamp = PR_FALSE;
+
+#define LINE_BUF_SIZE           512
+#define DEFAULT_BUF_SIZE        16384
+
+#ifdef _PR_NEED_STRCASECMP
+
+/*
+ * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms
+ * such as NCR and Unixware.  Linking with both libc and libucb
+ * may cause some problem, so I just provide our own implementation
+ * of strcasecmp here.
+ */
+
+static const unsigned char uc[] =
+{
+    '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+    '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+    '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+    '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+    ' ',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
+    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+    '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
+    '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177'
+};
+
+PRIntn strcasecmp(const char *a, const char *b)
+{
+    const unsigned char *ua = (const unsigned char *)a;
+    const unsigned char *ub = (const unsigned char *)b;
+
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
+    {
+        a++;
+        ua++;
+        ub++;
+    }
+
+    return (PRIntn)(uc[*ua] - uc[*ub]);
+}
+
+#endif /* _PR_NEED_STRCASECMP */
+
+void _PR_InitLog(void)
+{
+    char *ev;
+
+    _pr_logLock = PR_NewLock();
+
+    ev = PR_GetEnv("NSPR_LOG_MODULES");
+    if (ev && ev[0]) {
+        char module[64];  /* Security-Critical: If you change this
+                           * size, you must also change the sscanf
+                           * format string to be size-1.
+                           */
+        PRBool isSync = PR_FALSE;
+        PRIntn evlen = strlen(ev), pos = 0;
+        PRInt32 bufSize = DEFAULT_BUF_SIZE;
+        while (pos < evlen) {
+            PRIntn level = 1, count = 0, delta = 0;
+            count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
+                           module, &delta, &level, &delta);
+            pos += delta;
+            if (count == 0) break;
+
+            /*
+            ** If count == 2, then we got module and level. If count
+            ** == 1, then level defaults to 1 (module enabled).
+            */
+            if (strcasecmp(module, "sync") == 0) {
+                isSync = PR_TRUE;
+            } else if (strcasecmp(module, "bufsize") == 0) {
+                if (level >= LINE_BUF_SIZE) {
+                    bufSize = level;
+                }
+            } else if (strcasecmp(module, "timestamp") == 0) {
+                outputTimeStamp = PR_TRUE;
+            } else {
+                PRLogModuleInfo *lm = logModules;
+                PRBool skip_modcheck =
+                    (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE;
+
+                while (lm != NULL) {
+                    if (skip_modcheck) lm -> level = (PRLogModuleLevel)level;
+                    else if (strcasecmp(module, lm->name) == 0) {
+                        lm->level = (PRLogModuleLevel)level;
+                        break;
+                    }
+                    lm = lm->next;
+                }
+            }
+            /*found:*/
+            count = sscanf(&ev[pos], " , %n", &delta);
+            pos += delta;
+            if (count == EOF) break;
+        }
+        PR_SetLogBuffering(isSync ? 0 : bufSize);
+
+#ifdef XP_UNIX
+        if ((getuid() != geteuid()) || (getgid() != getegid())) {
+            return;
+        }
+#endif /* XP_UNIX */
+
+        ev = PR_GetEnv("NSPR_LOG_FILE");
+        if (ev && ev[0]) {
+            if (!PR_SetLogFile(ev)) {
+#ifdef XP_PC
+                char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev);
+                if (str) {
+                    OutputDebugStringA(str);
+                    PR_smprintf_free(str);
+                }
+#else
+                fprintf(stderr, "Unable to create nspr log file '%s'\n", ev);
+#endif
+            }
+        } else {
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+            logFile = stderr;
+#else
+            logFile = _pr_stderr;
+#endif
+        }
+    }
+}
+
+void _PR_LogCleanup(void)
+{
+    PRLogModuleInfo *lm = logModules;
+
+    PR_LogFlush();
+
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+    if (logFile
+        && logFile != stdout
+        && logFile != stderr
+#ifdef XP_PC
+        && logFile != WIN32_DEBUG_FILE
+#endif
+        ) {
+        fclose(logFile);
+    }
+#else
+    if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
+        PR_Close(logFile);
+    }
+#endif
+    logFile = NULL;
+
+    if (logBuf)
+        PR_DELETE(logBuf);
+
+    while (lm != NULL) {
+        PRLogModuleInfo *next = lm->next;
+        free((/*const*/ char *)lm->name);
+        PR_Free(lm);
+        lm = next;
+    }
+    logModules = NULL;
+
+    if (_pr_logLock) {
+        PR_DestroyLock(_pr_logLock);
+        _pr_logLock = NULL;
+    }
+}
+
+static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
+{
+    char *ev;
+
+    ev = PR_GetEnv("NSPR_LOG_MODULES");
+    if (ev && ev[0]) {
+        char module[64];  /* Security-Critical: If you change this
+                           * size, you must also change the sscanf
+                           * format string to be size-1.
+                           */
+        PRIntn evlen = strlen(ev), pos = 0;
+        while (pos < evlen) {
+            PRIntn level = 1, count = 0, delta = 0;
+
+            count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
+                           module, &delta, &level, &delta);
+            pos += delta;
+            if (count == 0) break;
+
+            /*
+            ** If count == 2, then we got module and level. If count
+            ** == 1, then level defaults to 1 (module enabled).
+            */
+            if (lm != NULL)
+            {
+                if ((strcasecmp(module, "all") == 0)
+                    || (strcasecmp(module, lm->name) == 0))
+                {
+                    lm->level = (PRLogModuleLevel)level;
+                }
+            }
+            count = sscanf(&ev[pos], " , %n", &delta);
+            pos += delta;
+            if (count == EOF) break;
+        }
+    }
+} /* end _PR_SetLogModuleLevel() */
+
+PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name)
+{
+    PRLogModuleInfo *lm;
+
+        if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    lm = PR_NEWZAP(PRLogModuleInfo);
+    if (lm) {
+        lm->name = strdup(name);
+        lm->level = PR_LOG_NONE;
+        lm->next = logModules;
+        logModules = lm;
+        _PR_SetLogModuleLevel(lm);
+    }
+    return lm;
+}
+
+PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file)
+{
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+    FILE *newLogFile;
+
+#ifdef XP_PC
+    if ( strcmp( file, "WinDebug") == 0)
+    {
+        newLogFile = WIN32_DEBUG_FILE;
+    }
+    else
+#endif
+    {
+        newLogFile = fopen(file, "w");
+        if (!newLogFile)
+            return PR_FALSE;
+
+#ifndef WINCE  /* _IONBF does not exist in the Windows Mobile 6 SDK. */
+        /* We do buffering ourselves. */
+        setvbuf(newLogFile, NULL, _IONBF, 0);
+#endif
+    }
+    if (logFile
+        && logFile != stdout
+        && logFile != stderr
+#ifdef XP_PC
+        && logFile != WIN32_DEBUG_FILE
+#endif
+        ) {
+        fclose(logFile);
+    }
+    logFile = newLogFile;
+    return PR_TRUE;
+#else
+    PRFileDesc *newLogFile;
+
+    newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0666);
+    if (newLogFile) {
+        if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
+            PR_Close(logFile);
+        }
+        logFile = newLogFile;
+    }
+    return (PRBool) (newLogFile != 0);
+#endif /* _PR_USE_STDIO_FOR_LOGGING */
+}
+
+PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size)
+{
+    PR_LogFlush();
+
+    if (logBuf)
+        PR_DELETE(logBuf);
+
+    if (buffer_size >= LINE_BUF_SIZE) {
+        logp = logBuf = (char*) PR_MALLOC(buffer_size);
+        logEndp = logp + buffer_size;
+    }
+}
+
+PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...)
+{
+    va_list ap;
+    char line[LINE_BUF_SIZE];
+    char *line_long = NULL;
+    PRUint32 nb_tid = 0, nb;
+    PRThread *me;
+    PRExplodedTime now;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (!logFile) {
+        return;
+    }
+
+    if (outputTimeStamp) {
+        PR_ExplodeTime(PR_Now(), PR_GMTParameters, &now);
+        nb_tid = PR_snprintf(line, sizeof(line)-1,
+                             "%04d-%02d-%02d %02d:%02d:%02d.%06d UTC - ",
+                             now.tm_year, now.tm_month + 1, now.tm_mday,
+                             now.tm_hour, now.tm_min, now.tm_sec,
+                             now.tm_usec);
+    }
+
+    me = PR_GetCurrentThread();
+    nb_tid += PR_snprintf(line+nb_tid, sizeof(line)-nb_tid-1, "%ld[%p]: ",
+#if defined(_PR_BTHREADS)
+                          me, me);
+#else
+                          me ? me->id : 0L, me);
+#endif
+
+    va_start(ap, fmt);
+    nb = nb_tid + PR_vsnprintf(line+nb_tid, sizeof(line)-nb_tid-1, fmt, ap);
+    va_end(ap);
+
+    /*
+     * Check if we might have run out of buffer space (in case we have a
+     * long line), and malloc a buffer just this once.
+     */
+    if (nb == sizeof(line)-2) {
+        va_start(ap, fmt);
+        line_long = PR_vsmprintf(fmt, ap);
+        va_end(ap);
+        /* If this failed, we'll fall back to writing the truncated line. */
+    }
+
+    if (line_long) {
+        nb = strlen(line_long);
+        _PR_LOCK_LOG();
+        if (logBuf != 0) {
+            _PUT_LOG(logFile, logBuf, logp - logBuf);
+            logp = logBuf;
+        }
+        /*
+         * Write out the thread id (with an optional timestamp) and the
+         * malloc'ed buffer.
+         */
+        _PUT_LOG(logFile, line, nb_tid);
+        _PUT_LOG(logFile, line_long, nb);
+        /* Ensure there is a trailing newline. */
+        if (!nb || (line_long[nb-1] != '\n')) {
+            char eol[2];
+            eol[0] = '\n';
+            eol[1] = '\0';
+            _PUT_LOG(logFile, eol, 1);
+        }
+        _PR_UNLOCK_LOG();
+        PR_smprintf_free(line_long);
+    } else {
+        /* Ensure there is a trailing newline. */
+        if (nb && (line[nb-1] != '\n')) {
+            line[nb++] = '\n';
+            line[nb] = '\0';
+        }
+        _PR_LOCK_LOG();
+        if (logBuf == 0) {
+            _PUT_LOG(logFile, line, nb);
+        } else {
+            /* If nb can't fit into logBuf, write out logBuf first. */
+            if (logp + nb > logEndp) {
+                _PUT_LOG(logFile, logBuf, logp - logBuf);
+                logp = logBuf;
+            }
+            /* nb is guaranteed to fit into logBuf. */
+            memcpy(logp, line, nb);
+            logp += nb;
+        }
+        _PR_UNLOCK_LOG();
+    }
+    PR_LogFlush();
+}
+
+PR_IMPLEMENT(void) PR_LogFlush(void)
+{
+    if (logBuf && logFile) {
+        _PR_LOCK_LOG();
+            if (logp > logBuf) {
+                _PUT_LOG(logFile, logBuf, logp - logBuf);
+                logp = logBuf;
+            }
+        _PR_UNLOCK_LOG();
+    }
+}
+
+PR_IMPLEMENT(void) PR_Abort(void)
+{
+    PR_LogPrint("Aborting");
+    abort();
+}
+
+PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln)
+{
+    PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln);
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+    fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
+#endif
+#ifdef WIN32
+    DebugBreak();
+#endif
+#ifdef XP_OS2
+    asm("int $3");
+#endif
+    abort();
+}
diff --git a/mozilla/nsprpub/pr/src/io/prmapopt.c b/mozilla/nsprpub/pr/src/io/prmapopt.c
new file mode 100644
index 0000000..04501b0
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prmapopt.c
@@ -0,0 +1,495 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * This file defines _PR_MapOptionName().  The purpose of putting
+ * _PR_MapOptionName() in a separate file is to work around a Winsock
+ * header file problem on Windows NT.
+ *
+ * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
+ * to use Service Pack 3 extensions), windows.h includes winsock2.h
+ * (instead of winsock.h), which doesn't define many socket options
+ * defined in winsock.h.
+ *
+ * We need the socket options defined in winsock.h.  So this file
+ * includes winsock.h, with _WIN32_WINNT undefined.
+ */
+
+#if defined(WINNT) || defined(__MINGW32__)
+#include <winsock.h>
+#endif
+
+/* MinGW doesn't define these in its winsock.h. */
+#ifdef __MINGW32__
+#ifndef IP_TTL
+#define IP_TTL 7
+#endif
+#ifndef IP_TOS
+#define IP_TOS 8
+#endif
+#endif
+
+#include "primpl.h"
+
+#if defined(NEXTSTEP)
+/* NEXTSTEP is special: this must come before netinet/tcp.h. */
+#include <netinet/in_systm.h>  /* n_short, n_long, n_time */
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
+#endif
+
+#ifndef _PR_PTHREADS
+
+PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
+{
+    PRStatus rv;
+    PRInt32 length;
+    PRInt32 level, name;
+
+    /*
+     * PR_SockOpt_Nonblocking is a special case that does not
+     * translate to a getsockopt() call
+     */
+    if (PR_SockOpt_Nonblocking == data->option)
+    {
+        data->value.non_blocking = fd->secret->nonblocking;
+        return PR_SUCCESS;
+    }
+
+    rv = _PR_MapOptionName(data->option, &level, &name);
+    if (PR_SUCCESS == rv)
+    {
+        switch (data->option)
+        {
+            case PR_SockOpt_Linger:
+            {
+#if !defined(XP_BEOS) || defined(BONE_VERSION)
+                struct linger linger;
+                length = sizeof(linger);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name, (char *) &linger, &length);
+                if (PR_SUCCESS == rv)
+                {
+                    PR_ASSERT(sizeof(linger) == length);
+                    data->value.linger.polarity =
+                        (linger.l_onoff) ? PR_TRUE : PR_FALSE;
+                    data->value.linger.linger =
+                        PR_SecondsToInterval(linger.l_linger);
+                }
+                break;
+#else
+                PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+                return PR_FAILURE;
+#endif
+            }
+            case PR_SockOpt_Reuseaddr:
+            case PR_SockOpt_Keepalive:
+            case PR_SockOpt_NoDelay:
+            case PR_SockOpt_Broadcast:
+            {
+#ifdef WIN32 /* Winsock */
+                BOOL value;
+#else
+                PRIntn value;
+#endif
+                length = sizeof(value);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name, (char*)&value, &length);
+                if (PR_SUCCESS == rv)
+                    data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
+                break;
+            }
+            case PR_SockOpt_McastLoopback:
+            {
+#ifdef WIN32 /* Winsock */
+                BOOL bool;
+#else
+                PRUint8 bool;
+#endif
+                length = sizeof(bool);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name, (char*)&bool, &length);
+                if (PR_SUCCESS == rv)
+                    data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
+                break;
+            }
+            case PR_SockOpt_RecvBufferSize:
+            case PR_SockOpt_SendBufferSize:
+            case PR_SockOpt_MaxSegment:
+            {
+                PRIntn value;
+                length = sizeof(value);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name, (char*)&value, &length);
+                if (PR_SUCCESS == rv)
+                    data->value.recv_buffer_size = value;
+                break;
+            }
+            case PR_SockOpt_IpTimeToLive:
+            case PR_SockOpt_IpTypeOfService:
+            {
+                /* These options should really be an int (or PRIntn). */
+                length = sizeof(PRUintn);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name, (char*)&data->value.ip_ttl, &length);
+                break;
+            }
+            case PR_SockOpt_McastTimeToLive:
+            {
+#ifdef WIN32 /* Winsock */
+                int ttl;
+#else
+                PRUint8 ttl;
+#endif
+                length = sizeof(ttl);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name, (char*)&ttl, &length);
+                if (PR_SUCCESS == rv)
+                    data->value.mcast_ttl = ttl;
+                break;
+            }
+#ifdef IP_ADD_MEMBERSHIP
+            case PR_SockOpt_AddMember:
+            case PR_SockOpt_DropMember:
+            {
+                struct ip_mreq mreq;
+                length = sizeof(mreq);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name, (char*)&mreq, &length);
+                if (PR_SUCCESS == rv)
+                {
+                    data->value.add_member.mcaddr.inet.ip =
+                        mreq.imr_multiaddr.s_addr;
+                    data->value.add_member.ifaddr.inet.ip =
+                        mreq.imr_interface.s_addr;
+                }
+                break;
+            }
+#endif /* IP_ADD_MEMBERSHIP */
+            case PR_SockOpt_McastInterface:
+            {
+                /* This option is a struct in_addr. */
+                length = sizeof(data->value.mcast_if.inet.ip);
+                rv = _PR_MD_GETSOCKOPT(
+                    fd, level, name,
+                    (char*)&data->value.mcast_if.inet.ip, &length);
+                break;
+            }
+            default:
+                PR_NOT_REACHED("Unknown socket option");
+                break;
+        }  
+    }
+    return rv;
+}  /* _PR_SocketGetSocketOption */
+
+PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
+{
+    PRStatus rv;
+    PRInt32 level, name;
+
+    /*
+     * PR_SockOpt_Nonblocking is a special case that does not
+     * translate to a setsockopt call.
+     */
+    if (PR_SockOpt_Nonblocking == data->option)
+    {
+#ifdef WINNT
+        PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
+            || (fd->secret->nonblocking == data->value.non_blocking));
+        if (fd->secret->md.io_model_committed
+            && (fd->secret->nonblocking != data->value.non_blocking))
+        {
+            /*
+             * On NT, once we have associated a socket with the io
+             * completion port, we can't disassociate it.  So we
+             * can't change the nonblocking option of the socket
+             * afterwards.
+             */
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            return PR_FAILURE;
+        }
+#endif
+        fd->secret->nonblocking = data->value.non_blocking;
+        return PR_SUCCESS;
+    }
+
+    rv = _PR_MapOptionName(data->option, &level, &name);
+    if (PR_SUCCESS == rv)
+    {
+        switch (data->option)
+        {
+            case PR_SockOpt_Linger:
+            {
+#if !defined(XP_BEOS) || defined(BONE_VERSION)
+                struct linger linger;
+                linger.l_onoff = data->value.linger.polarity;
+                linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&linger, sizeof(linger));
+                break;
+#else
+                PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+                return PR_FAILURE;
+#endif
+            }
+            case PR_SockOpt_Reuseaddr:
+            case PR_SockOpt_Keepalive:
+            case PR_SockOpt_NoDelay:
+            case PR_SockOpt_Broadcast:
+            {
+#ifdef WIN32 /* Winsock */
+                BOOL value;
+#else
+                PRIntn value;
+#endif
+                value = (data->value.reuse_addr) ? 1 : 0;
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&value, sizeof(value));
+                break;
+            }
+            case PR_SockOpt_McastLoopback:
+            {
+#ifdef WIN32 /* Winsock */
+                BOOL bool;
+#else
+                PRUint8 bool;
+#endif
+                bool = data->value.mcast_loopback ? 1 : 0;
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&bool, sizeof(bool));
+                break;
+            }
+            case PR_SockOpt_RecvBufferSize:
+            case PR_SockOpt_SendBufferSize:
+            case PR_SockOpt_MaxSegment:
+            {
+                PRIntn value = data->value.recv_buffer_size;
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&value, sizeof(value));
+                break;
+            }
+            case PR_SockOpt_IpTimeToLive:
+            case PR_SockOpt_IpTypeOfService:
+            {
+                /* These options should really be an int (or PRIntn). */
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
+                break;
+            }
+            case PR_SockOpt_McastTimeToLive:
+            {
+#ifdef WIN32 /* Winsock */
+                int ttl;
+#else
+                PRUint8 ttl;
+#endif
+                ttl = data->value.mcast_ttl;
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&ttl, sizeof(ttl));
+                break;
+            }
+#ifdef IP_ADD_MEMBERSHIP
+            case PR_SockOpt_AddMember:
+            case PR_SockOpt_DropMember:
+            {
+                struct ip_mreq mreq;
+                mreq.imr_multiaddr.s_addr =
+                    data->value.add_member.mcaddr.inet.ip;
+                mreq.imr_interface.s_addr =
+                    data->value.add_member.ifaddr.inet.ip;
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&mreq, sizeof(mreq));
+                break;
+            }
+#endif /* IP_ADD_MEMBERSHIP */
+            case PR_SockOpt_McastInterface:
+            {
+                /* This option is a struct in_addr. */
+                rv = _PR_MD_SETSOCKOPT(
+                    fd, level, name, (char*)&data->value.mcast_if.inet.ip,
+                    sizeof(data->value.mcast_if.inet.ip));
+                break;
+            }
+            default:
+                PR_NOT_REACHED("Unknown socket option");
+                break;
+        }  
+    }
+    return rv;
+}  /* _PR_SocketSetSocketOption */
+
+#endif /* ! _PR_PTHREADS */
+
+/*
+ *********************************************************************
+ *********************************************************************
+ **
+ ** Make sure that the following is at the end of this file,
+ ** because we will be playing with macro redefines.
+ **
+ *********************************************************************
+ *********************************************************************
+ */
+
+/*
+ * Not every platform has all the socket options we want to
+ * support.  Some older operating systems such as SunOS 4.1.3
+ * don't have the IP multicast socket options.  Win32 doesn't
+ * have TCP_MAXSEG.
+ *
+ * To deal with this problem, we define the missing socket
+ * options as _PR_NO_SUCH_SOCKOPT.  _PR_MapOptionName() fails with
+ * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
+ * available on the platform is requested.
+ */
+
+/*
+ * Sanity check.  SO_LINGER and TCP_NODELAY should be available
+ * on all platforms.  Just to make sure we have included the
+ * appropriate header files.  Then any undefined socket options
+ * are really missing.
+ */
+
+#if !defined(SO_LINGER)
+#error "SO_LINGER is not defined"
+#endif
+
+/*
+ * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
+ * in <netinet/tcp.h>
+ */
+#if !defined(NCR)
+#if !defined(TCP_NODELAY)
+#error "TCP_NODELAY is not defined"
+#endif
+#endif
+
+/*
+ * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
+ * a valid socket option.
+ */
+#define _PR_NO_SUCH_SOCKOPT -1
+
+#ifndef SO_KEEPALIVE
+#define SO_KEEPALIVE        _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef SO_SNDBUF
+#define SO_SNDBUF           _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef SO_RCVBUF
+#define SO_RCVBUF           _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef IP_MULTICAST_IF                 /* set/get IP multicast interface   */
+#define IP_MULTICAST_IF     _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef IP_MULTICAST_TTL                /* set/get IP multicast timetolive  */
+#define IP_MULTICAST_TTL    _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef IP_MULTICAST_LOOP               /* set/get IP multicast loopback    */
+#define IP_MULTICAST_LOOP   _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef IP_ADD_MEMBERSHIP               /* add  an IP group membership      */
+#define IP_ADD_MEMBERSHIP   _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef IP_DROP_MEMBERSHIP              /* drop an IP group membership      */
+#define IP_DROP_MEMBERSHIP  _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef IP_TTL                          /* set/get IP Time To Live          */
+#define IP_TTL              _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef IP_TOS                          /* set/get IP Type Of Service       */
+#define IP_TOS              _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef TCP_NODELAY                     /* don't delay to coalesce data     */
+#define TCP_NODELAY         _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef TCP_MAXSEG                      /* maxumum segment size for tcp     */
+#define TCP_MAXSEG          _PR_NO_SUCH_SOCKOPT
+#endif
+
+#ifndef SO_BROADCAST                 /* enable broadcast on udp sockets */
+#define SO_BROADCAST        _PR_NO_SUCH_SOCKOPT
+#endif
+
+PRStatus _PR_MapOptionName(
+    PRSockOption optname, PRInt32 *level, PRInt32 *name)
+{
+    static PRInt32 socketOptions[PR_SockOpt_Last] =
+    {
+        0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
+        IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
+        IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
+        TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST
+    };
+    static PRInt32 socketLevels[PR_SockOpt_Last] =
+    {
+        0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
+        IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
+        IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
+        IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET
+    };
+
+    if ((optname < PR_SockOpt_Linger)
+    || (optname >= PR_SockOpt_Last))
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
+    {
+        PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
+        return PR_FAILURE;
+    }
+    *name = socketOptions[optname];
+    *level = socketLevels[optname];
+    return PR_SUCCESS;
+}  /* _PR_MapOptionName */
diff --git a/mozilla/nsprpub/pr/src/io/prmmap.c b/mozilla/nsprpub/pr/src/io/prmmap.c
new file mode 100644
index 0000000..e5c1e5d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prmmap.c
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ *********************************************************************
+ *
+ * Memory-mapped files
+ *
+ *********************************************************************
+ */
+
+#include "primpl.h"
+
+PR_IMPLEMENT(PRFileMap *) PR_CreateFileMap(
+    PRFileDesc *fd,
+    PRInt64 size,
+    PRFileMapProtect prot)
+{
+    PRFileMap *fmap;
+
+    PR_ASSERT(prot == PR_PROT_READONLY || prot == PR_PROT_READWRITE
+            || prot == PR_PROT_WRITECOPY);
+    fmap = PR_NEWZAP(PRFileMap);
+    if (NULL == fmap) {
+	PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	return NULL;
+    }
+    fmap->fd = fd;
+    fmap->prot = prot;
+    if (_PR_MD_CREATE_FILE_MAP(fmap, size) == PR_SUCCESS) {
+	return fmap;
+    } else {
+	PR_DELETE(fmap);
+	return NULL;
+    }
+}
+
+PR_IMPLEMENT(PRInt32) PR_GetMemMapAlignment(void)
+{
+    return _PR_MD_GET_MEM_MAP_ALIGNMENT();
+}
+
+PR_IMPLEMENT(void *) PR_MemMap(
+    PRFileMap *fmap,
+    PROffset64 offset,
+    PRUint32 len)
+{
+    return _PR_MD_MEM_MAP(fmap, offset, len);
+}
+
+PR_IMPLEMENT(PRStatus) PR_MemUnmap(void *addr, PRUint32 len)
+{
+    return _PR_MD_MEM_UNMAP(addr, len);
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseFileMap(PRFileMap *fmap)
+{
+    return _PR_MD_CLOSE_FILE_MAP(fmap);
+}
diff --git a/mozilla/nsprpub/pr/src/io/prmwait.c b/mozilla/nsprpub/pr/src/io/prmwait.c
new file mode 100644
index 0000000..5b30f69
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prmwait.c
@@ -0,0 +1,1488 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#include "pprmwait.h"
+
+#define _MW_REHASH_MAX 11
+
+static PRLock *mw_lock = NULL;
+static _PRGlobalState *mw_state = NULL;
+
+static PRIntervalTime max_polling_interval;
+
+#ifdef WINNT
+
+typedef struct TimerEvent {
+    PRIntervalTime absolute;
+    void (*func)(void *);
+    void *arg;
+    LONG ref_count;
+    PRCList links;
+} TimerEvent;
+
+#define TIMER_EVENT_PTR(_qp) \
+    ((TimerEvent *) ((char *) (_qp) - offsetof(TimerEvent, links)))
+
+struct {
+    PRLock *ml;
+    PRCondVar *new_timer;
+    PRCondVar *cancel_timer;
+    PRThread *manager_thread;
+    PRCList timer_queue;
+} tm_vars;
+
+static PRStatus TimerInit(void);
+static void TimerManager(void *arg);
+static TimerEvent *CreateTimer(PRIntervalTime timeout,
+    void (*func)(void *), void *arg);
+static PRBool CancelTimer(TimerEvent *timer);
+
+static void TimerManager(void *arg)
+{
+    PRIntervalTime now;
+    PRIntervalTime timeout;
+    PRCList *head;
+    TimerEvent *timer;
+
+    PR_Lock(tm_vars.ml);
+    while (1)
+    {
+        if (PR_CLIST_IS_EMPTY(&tm_vars.timer_queue))
+        {
+            PR_WaitCondVar(tm_vars.new_timer, PR_INTERVAL_NO_TIMEOUT);
+        }
+        else
+        {
+            now = PR_IntervalNow();
+            head = PR_LIST_HEAD(&tm_vars.timer_queue);
+            timer = TIMER_EVENT_PTR(head);
+            if ((PRInt32) (now - timer->absolute) >= 0)
+            {
+                PR_REMOVE_LINK(head);
+                /*
+                 * make its prev and next point to itself so that
+                 * it's obvious that it's not on the timer_queue.
+                 */
+                PR_INIT_CLIST(head);
+                PR_ASSERT(2 == timer->ref_count);
+                PR_Unlock(tm_vars.ml);
+                timer->func(timer->arg);
+                PR_Lock(tm_vars.ml);
+                timer->ref_count -= 1;
+                if (0 == timer->ref_count)
+                {
+                    PR_NotifyAllCondVar(tm_vars.cancel_timer);
+                }
+            }
+            else
+            {
+                timeout = (PRIntervalTime)(timer->absolute - now);
+                PR_WaitCondVar(tm_vars.new_timer, timeout);
+            } 
+        }
+    }
+    PR_Unlock(tm_vars.ml);
+}
+
+static TimerEvent *CreateTimer(
+    PRIntervalTime timeout,
+    void (*func)(void *),
+    void *arg)
+{
+    TimerEvent *timer;
+    PRCList *links, *tail;
+    TimerEvent *elem;
+
+    timer = PR_NEW(TimerEvent);
+    if (NULL == timer)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return timer;
+    }
+    timer->absolute = PR_IntervalNow() + timeout;
+    timer->func = func;
+    timer->arg = arg;
+    timer->ref_count = 2;
+    PR_Lock(tm_vars.ml);
+    tail = links = PR_LIST_TAIL(&tm_vars.timer_queue);
+    while (links->prev != tail)
+    {
+        elem = TIMER_EVENT_PTR(links);
+        if ((PRInt32)(timer->absolute - elem->absolute) >= 0)
+        {
+            break;
+        }
+        links = links->prev;
+    }
+    PR_INSERT_AFTER(&timer->links, links);
+    PR_NotifyCondVar(tm_vars.new_timer);
+    PR_Unlock(tm_vars.ml);
+    return timer;
+}
+
+static PRBool CancelTimer(TimerEvent *timer)
+{
+    PRBool canceled = PR_FALSE;
+
+    PR_Lock(tm_vars.ml);
+    timer->ref_count -= 1;
+    if (timer->links.prev == &timer->links)
+    {
+        while (timer->ref_count == 1)
+        {
+            PR_WaitCondVar(tm_vars.cancel_timer, PR_INTERVAL_NO_TIMEOUT);
+        }
+    }
+    else
+    {
+        PR_REMOVE_LINK(&timer->links);
+        canceled = PR_TRUE;
+    }
+    PR_Unlock(tm_vars.ml);
+    PR_DELETE(timer);
+    return canceled; 
+}
+
+static PRStatus TimerInit(void)
+{
+    tm_vars.ml = PR_NewLock();
+    if (NULL == tm_vars.ml)
+    {
+        goto failed;
+    }
+    tm_vars.new_timer = PR_NewCondVar(tm_vars.ml);
+    if (NULL == tm_vars.new_timer)
+    {
+        goto failed;
+    }
+    tm_vars.cancel_timer = PR_NewCondVar(tm_vars.ml);
+    if (NULL == tm_vars.cancel_timer)
+    {
+        goto failed;
+    }
+    PR_INIT_CLIST(&tm_vars.timer_queue);
+    tm_vars.manager_thread = PR_CreateThread(
+        PR_SYSTEM_THREAD, TimerManager, NULL, PR_PRIORITY_NORMAL,
+        PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
+    if (NULL == tm_vars.manager_thread)
+    {
+        goto failed;
+    }
+    return PR_SUCCESS;
+
+failed:
+    if (NULL != tm_vars.cancel_timer)
+    {
+        PR_DestroyCondVar(tm_vars.cancel_timer);
+    }
+    if (NULL != tm_vars.new_timer)
+    {
+        PR_DestroyCondVar(tm_vars.new_timer);
+    }
+    if (NULL != tm_vars.ml)
+    {
+        PR_DestroyLock(tm_vars.ml);
+    }
+    return PR_FAILURE;
+}
+
+#endif /* WINNT */
+
+/******************************************************************/
+/******************************************************************/
+/************************ The private portion *********************/
+/******************************************************************/
+/******************************************************************/
+void _PR_InitMW(void)
+{
+#ifdef WINNT
+    /*
+     * We use NT 4's InterlockedCompareExchange() to operate
+     * on PRMWStatus variables.
+     */
+    PR_ASSERT(sizeof(LONG) == sizeof(PRMWStatus));
+    TimerInit();
+#endif
+    mw_lock = PR_NewLock();
+    PR_ASSERT(NULL != mw_lock);
+    mw_state = PR_NEWZAP(_PRGlobalState);
+    PR_ASSERT(NULL != mw_state);
+    PR_INIT_CLIST(&mw_state->group_list);
+    max_polling_interval = PR_MillisecondsToInterval(MAX_POLLING_INTERVAL);
+}  /* _PR_InitMW */
+
+void _PR_CleanupMW(void)
+{
+    PR_DestroyLock(mw_lock);
+    mw_lock = NULL;
+    if (mw_state->group) {
+        PR_DestroyWaitGroup(mw_state->group);
+        /* mw_state->group is set to NULL as a side effect. */
+    }
+    PR_DELETE(mw_state);
+}  /* _PR_CleanupMW */
+
+static PRWaitGroup *MW_Init2(void)
+{
+    PRWaitGroup *group = mw_state->group;  /* it's the null group */
+    if (NULL == group)  /* there is this special case */
+    {
+        group = PR_CreateWaitGroup(_PR_DEFAULT_HASH_LENGTH);
+        if (NULL == group) goto failed_alloc;
+        PR_Lock(mw_lock);
+        if (NULL == mw_state->group)
+        {
+            mw_state->group = group;
+            group = NULL;
+        }
+        PR_Unlock(mw_lock);
+        if (group != NULL) (void)PR_DestroyWaitGroup(group);
+        group = mw_state->group;  /* somebody beat us to it */
+    }
+failed_alloc:
+    return group;  /* whatever */
+}  /* MW_Init2 */
+
+static _PR_HashStory MW_AddHashInternal(PRRecvWait *desc, _PRWaiterHash *hash)
+{
+    /*
+    ** The entries are put in the table using the fd (PRFileDesc*) of
+    ** the receive descriptor as the key. This allows us to locate
+    ** the appropriate entry aqain when the poll operation finishes.
+    **
+    ** The pointer to the file descriptor object is first divided by
+    ** the natural alignment of a pointer in the belief that object
+    ** will have at least that many zeros in the low order bits.
+    ** This may not be a good assuption.
+    **
+    ** We try to put the entry in by rehashing _MW_REHASH_MAX times. After
+    ** that we declare defeat and force the table to be reconstructed.
+    ** Since some fds might be added more than once, won't that cause
+    ** collisions even in an empty table?
+    */
+    PRIntn rehash = _MW_REHASH_MAX;
+    PRRecvWait **waiter;
+    PRUintn hidx = _MW_HASH(desc->fd, hash->length);
+    PRUintn hoffset = 0;
+
+    while (rehash-- > 0)
+    {
+        waiter = &hash->recv_wait;
+        if (NULL == waiter[hidx])
+        {
+            waiter[hidx] = desc;
+            hash->count += 1;
+#if 0
+            printf("Adding 0x%x->0x%x ", desc, desc->fd);
+            printf(
+                "table[%u:%u:*%u]: 0x%x->0x%x\n",
+                hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd);
+#endif
+            return _prmw_success;
+        }
+        if (desc == waiter[hidx])
+        {
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);  /* desc already in table */
+            return _prmw_error;
+        }
+#if 0
+        printf("Failing 0x%x->0x%x ", desc, desc->fd);
+        printf(
+            "table[*%u:%u:%u]: 0x%x->0x%x\n",
+            hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd);
+#endif
+        if (0 == hoffset)
+        {
+            hoffset = _MW_HASH2(desc->fd, hash->length);
+            PR_ASSERT(0 != hoffset);
+        }
+        hidx = (hidx + hoffset) % (hash->length);
+    }
+    return _prmw_rehash;    
+}  /* MW_AddHashInternal */
+
+static _PR_HashStory MW_ExpandHashInternal(PRWaitGroup *group)
+{
+    PRRecvWait **desc;
+    PRUint32 pidx, length;
+    _PRWaiterHash *newHash, *oldHash = group->waiter;
+    PRBool retry;
+    _PR_HashStory hrv;
+
+    static const PRInt32 prime_number[] = {
+        _PR_DEFAULT_HASH_LENGTH, 179, 521, 907, 1427,
+        2711, 3917, 5021, 8219, 11549, 18911, 26711, 33749, 44771};
+    PRUintn primes = (sizeof(prime_number) / sizeof(PRInt32));
+
+    /* look up the next size we'd like to use for the hash table */
+    for (pidx = 0; pidx < primes; ++pidx)
+    {
+        if (prime_number[pidx] == oldHash->length)
+        {
+            break;
+        }
+    }
+    /* table size must be one of the prime numbers */
+    PR_ASSERT(pidx < primes);
+
+    /* if pidx == primes - 1, we can't expand the table any more */
+    while (pidx < primes - 1)
+    {
+        /* next size */
+        ++pidx;
+        length = prime_number[pidx];
+
+        /* allocate the new hash table and fill it in with the old */
+        newHash = (_PRWaiterHash*)PR_CALLOC(
+            sizeof(_PRWaiterHash) + (length * sizeof(PRRecvWait*)));
+        if (NULL == newHash)
+        {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return _prmw_error;
+        }
+
+        newHash->length = length;
+        retry = PR_FALSE;
+        for (desc = &oldHash->recv_wait;
+            newHash->count < oldHash->count; ++desc)
+        {
+            PR_ASSERT(desc < &oldHash->recv_wait + oldHash->length);
+            if (NULL != *desc)
+            {
+                hrv = MW_AddHashInternal(*desc, newHash);
+                PR_ASSERT(_prmw_error != hrv);
+                if (_prmw_success != hrv)
+                {
+                    PR_DELETE(newHash);
+                    retry = PR_TRUE;
+                    break;
+                }
+            }
+        }
+        if (retry) continue;
+
+        PR_DELETE(group->waiter);
+        group->waiter = newHash;
+        group->p_timestamp += 1;
+        return _prmw_success;
+    }
+
+    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    return _prmw_error;  /* we're hosed */
+}  /* MW_ExpandHashInternal */
+
+#ifndef WINNT
+static void _MW_DoneInternal(
+    PRWaitGroup *group, PRRecvWait **waiter, PRMWStatus outcome)
+{
+    /*
+    ** Add this receive wait object to the list of finished I/O
+    ** operations for this particular group. If there are other
+    ** threads waiting on the group, notify one. If not, arrange
+    ** for this thread to return.
+    */
+
+#if 0
+    printf("Removing 0x%x->0x%x\n", *waiter, (*waiter)->fd);
+#endif
+    (*waiter)->outcome = outcome;
+    PR_APPEND_LINK(&((*waiter)->internal), &group->io_ready);
+    PR_NotifyCondVar(group->io_complete);
+    PR_ASSERT(0 != group->waiter->count);
+    group->waiter->count -= 1;
+    *waiter = NULL;
+}  /* _MW_DoneInternal */
+#endif /* WINNT */
+
+static PRRecvWait **_MW_LookupInternal(PRWaitGroup *group, PRFileDesc *fd)
+{
+    /*
+    ** Find the receive wait object corresponding to the file descriptor.
+    ** Only search the wait group specified.
+    */
+    PRRecvWait **desc;
+    PRIntn rehash = _MW_REHASH_MAX;
+    _PRWaiterHash *hash = group->waiter;
+    PRUintn hidx = _MW_HASH(fd, hash->length);
+    PRUintn hoffset = 0;
+    
+    while (rehash-- > 0)
+    {
+        desc = (&hash->recv_wait) + hidx;
+        if ((*desc != NULL) && ((*desc)->fd == fd)) return desc;
+        if (0 == hoffset)
+        {
+            hoffset = _MW_HASH2(fd, hash->length);
+            PR_ASSERT(0 != hoffset);
+        }
+        hidx = (hidx + hoffset) % (hash->length);
+    }
+    return NULL;
+}  /* _MW_LookupInternal */
+
+#ifndef WINNT
+static PRStatus _MW_PollInternal(PRWaitGroup *group)
+{
+    PRRecvWait **waiter;
+    PRStatus rv = PR_FAILURE;
+    PRInt32 count, count_ready;
+    PRIntervalTime polling_interval;
+
+    group->poller = PR_GetCurrentThread();
+
+    while (PR_TRUE)
+    {
+        PRIntervalTime now, since_last_poll;
+        PRPollDesc *poll_list;
+
+        while (0 == group->waiter->count)
+        {
+            PRStatus st;
+            st = PR_WaitCondVar(group->new_business, PR_INTERVAL_NO_TIMEOUT);
+            if (_prmw_running != group->state)
+            {
+                PR_SetError(PR_INVALID_STATE_ERROR, 0);
+                goto aborted;
+            }
+            if (_MW_ABORTED(st)) goto aborted;
+        }
+
+        /*
+        ** There's something to do. See if our existing polling list
+        ** is large enough for what we have to do?
+        */
+
+        while (group->polling_count < group->waiter->count)
+        {
+            PRUint32 old_count = group->waiter->count;
+            PRUint32 new_count = PR_ROUNDUP(old_count, _PR_POLL_COUNT_FUDGE);
+            PRSize new_size = sizeof(PRPollDesc) * new_count;
+            PRPollDesc *old_polling_list = group->polling_list;
+
+            PR_Unlock(group->ml);
+            poll_list = (PRPollDesc*)PR_CALLOC(new_size);
+            if (NULL == poll_list)
+            {
+                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+                PR_Lock(group->ml);
+                goto failed_alloc;
+            }
+            if (NULL != old_polling_list)
+                PR_DELETE(old_polling_list);
+            PR_Lock(group->ml);
+            if (_prmw_running != group->state)
+            {
+                PR_SetError(PR_INVALID_STATE_ERROR, 0);
+                goto aborted;
+            }
+            group->polling_list = poll_list;
+            group->polling_count = new_count;
+        }
+
+        now = PR_IntervalNow();
+        polling_interval = max_polling_interval;
+        since_last_poll = now - group->last_poll;
+
+        waiter = &group->waiter->recv_wait;
+        poll_list = group->polling_list;
+        for (count = 0; count < group->waiter->count; ++waiter)
+        {
+            PR_ASSERT(waiter < &group->waiter->recv_wait
+                + group->waiter->length);
+            if (NULL != *waiter)  /* a live one! */
+            {
+                if ((PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout)
+                && (since_last_poll >= (*waiter)->timeout))
+                    _MW_DoneInternal(group, waiter, PR_MW_TIMEOUT);
+                else
+                {
+                    if (PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout)
+                    {
+                        (*waiter)->timeout -= since_last_poll;
+                        if ((*waiter)->timeout < polling_interval)
+                            polling_interval = (*waiter)->timeout;
+                    }
+                    PR_ASSERT(poll_list < group->polling_list
+                        + group->polling_count);
+                    poll_list->fd = (*waiter)->fd;
+                    poll_list->in_flags = PR_POLL_READ;
+                    poll_list->out_flags = 0;
+#if 0
+                    printf(
+                        "Polling 0x%x[%d]: [fd: 0x%x, tmo: %u]\n",
+                        poll_list, count, poll_list->fd, (*waiter)->timeout);
+#endif
+                    poll_list += 1;
+                    count += 1;
+                }
+            }
+        } 
+
+        PR_ASSERT(count == group->waiter->count);
+
+        /*
+        ** If there are no more threads waiting for completion,
+        ** we need to return.
+        */
+        if ((!PR_CLIST_IS_EMPTY(&group->io_ready))
+        && (1 == group->waiting_threads)) break;
+
+        if (0 == count) continue;  /* wait for new business */
+
+        group->last_poll = now;
+
+        PR_Unlock(group->ml);
+
+        count_ready = PR_Poll(group->polling_list, count, polling_interval);
+
+        PR_Lock(group->ml);
+
+        if (_prmw_running != group->state)
+        {
+            PR_SetError(PR_INVALID_STATE_ERROR, 0);
+            goto aborted;
+        }
+        if (-1 == count_ready)
+        {
+            goto failed_poll;  /* that's a shame */
+        }
+        else if (0 < count_ready)
+        {
+            for (poll_list = group->polling_list; count > 0;
+            poll_list++, count--)
+            {
+                PR_ASSERT(
+                    poll_list < group->polling_list + group->polling_count);
+                if (poll_list->out_flags != 0)
+                {
+                    waiter = _MW_LookupInternal(group, poll_list->fd);
+                    /*
+                    ** If 'waiter' is NULL, that means the wait receive
+                    ** descriptor has been canceled.
+                    */
+                    if (NULL != waiter)
+                        _MW_DoneInternal(group, waiter, PR_MW_SUCCESS);
+                }
+            }
+        }
+        /*
+        ** If there are no more threads waiting for completion,
+        ** we need to return.
+        ** This thread was "borrowed" to do the polling, but it really
+        ** belongs to the client.
+        */
+        if ((!PR_CLIST_IS_EMPTY(&group->io_ready))
+        && (1 == group->waiting_threads)) break;
+    }
+
+    rv = PR_SUCCESS;
+
+aborted:
+failed_poll:
+failed_alloc:
+    group->poller = NULL;  /* we were that, not we ain't */
+    if ((_prmw_running == group->state) && (group->waiting_threads > 1))
+    {
+        /* Wake up one thread to become the new poller. */
+        PR_NotifyCondVar(group->io_complete);
+    }
+    return rv;  /* we return with the lock held */
+}  /* _MW_PollInternal */
+#endif /* !WINNT */
+
+static PRMWGroupState MW_TestForShutdownInternal(PRWaitGroup *group)
+{
+    PRMWGroupState rv = group->state;
+    /*
+    ** Looking at the group's fields is safe because
+    ** once the group's state is no longer running, it
+    ** cannot revert and there is a safe check on entry
+    ** to make sure no more threads are made to wait.
+    */
+    if ((_prmw_stopping == rv)
+    && (0 == group->waiting_threads))
+    {
+        rv = group->state = _prmw_stopped;
+        PR_NotifyCondVar(group->mw_manage);
+    }
+    return rv;
+}  /* MW_TestForShutdownInternal */
+
+#ifndef WINNT
+static void _MW_InitialRecv(PRCList *io_ready)
+{
+    PRRecvWait *desc = (PRRecvWait*)io_ready;
+    if ((NULL == desc->buffer.start)
+    || (0 == desc->buffer.length))
+        desc->bytesRecv = 0;
+    else
+    {
+        desc->bytesRecv = (desc->fd->methods->recv)(
+            desc->fd, desc->buffer.start,
+            desc->buffer.length, 0, desc->timeout);
+        if (desc->bytesRecv < 0)  /* SetError should already be there */
+            desc->outcome = PR_MW_FAILURE;
+    }
+}  /* _MW_InitialRecv */
+#endif
+
+#ifdef WINNT
+static void NT_TimeProc(void *arg)
+{
+    _MDOverlapped *overlapped = (_MDOverlapped *)arg;
+    PRRecvWait *desc =  overlapped->data.mw.desc;
+    PRFileDesc *bottom;
+    
+    if (InterlockedCompareExchange((LONG *)&desc->outcome,
+        (LONG)PR_MW_TIMEOUT, (LONG)PR_MW_PENDING) != (LONG)PR_MW_PENDING)
+    {
+        /* This wait recv descriptor has already completed. */
+        return;
+    }
+
+    /* close the osfd to abort the outstanding async io request */
+    /* $$$$
+    ** Little late to be checking if NSPR's on the bottom of stack,
+    ** but if we don't check, we can't assert that the private data
+    ** is what we think it is.
+    ** $$$$
+    */
+    bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER);
+    PR_ASSERT(NULL != bottom);
+    if (NULL != bottom)  /* now what!?!?! */
+    {
+        bottom->secret->state = _PR_FILEDESC_CLOSED;
+        if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR)
+        {
+            fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError());
+            PR_ASSERT(!"What shall I do?");
+        }
+    }
+    return;
+}  /* NT_TimeProc */
+
+static PRStatus NT_HashRemove(PRWaitGroup *group, PRFileDesc *fd)
+{
+    PRRecvWait **waiter;
+
+    _PR_MD_LOCK(&group->mdlock);
+    waiter = _MW_LookupInternal(group, fd);
+    if (NULL != waiter)
+    {
+        group->waiter->count -= 1;
+        *waiter = NULL;
+    }
+    _PR_MD_UNLOCK(&group->mdlock);
+    return (NULL != waiter) ? PR_SUCCESS : PR_FAILURE;
+}
+
+PRStatus NT_HashRemoveInternal(PRWaitGroup *group, PRFileDesc *fd)
+{
+    PRRecvWait **waiter;
+
+    waiter = _MW_LookupInternal(group, fd);
+    if (NULL != waiter)
+    {
+        group->waiter->count -= 1;
+        *waiter = NULL;
+    }
+    return (NULL != waiter) ? PR_SUCCESS : PR_FAILURE;
+}
+#endif /* WINNT */
+
+/******************************************************************/
+/******************************************************************/
+/********************** The public API portion ********************/
+/******************************************************************/
+/******************************************************************/
+PR_IMPLEMENT(PRStatus) PR_AddWaitFileDesc(
+    PRWaitGroup *group, PRRecvWait *desc)
+{
+    _PR_HashStory hrv;
+    PRStatus rv = PR_FAILURE;
+#ifdef WINNT
+    _MDOverlapped *overlapped;
+    HANDLE hFile;
+    BOOL bResult;
+    DWORD dwError;
+    PRFileDesc *bottom;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    if ((NULL == group) && (NULL == (group = MW_Init2())))
+    {
+        return rv;
+    }
+
+    PR_ASSERT(NULL != desc->fd);
+
+    desc->outcome = PR_MW_PENDING;  /* nice, well known value */
+    desc->bytesRecv = 0;  /* likewise, though this value is ambiguious */
+
+    PR_Lock(group->ml);
+
+    if (_prmw_running != group->state)
+    {
+        /* Not allowed to add after cancelling the group */
+        desc->outcome = PR_MW_INTERRUPT;
+        PR_SetError(PR_INVALID_STATE_ERROR, 0);
+        PR_Unlock(group->ml);
+        return rv;
+    }
+
+#ifdef WINNT
+    _PR_MD_LOCK(&group->mdlock);
+#endif
+
+    /*
+    ** If the waiter count is zero at this point, there's no telling
+    ** how long we've been idle. Therefore, initialize the beginning
+    ** of the timing interval. As long as the list doesn't go empty,
+    ** it will maintain itself.
+    */
+    if (0 == group->waiter->count)
+        group->last_poll = PR_IntervalNow();
+
+    do
+    {
+        hrv = MW_AddHashInternal(desc, group->waiter);
+        if (_prmw_rehash != hrv) break;
+        hrv = MW_ExpandHashInternal(group);  /* gruesome */
+        if (_prmw_success != hrv) break;
+    } while (PR_TRUE);
+
+#ifdef WINNT
+    _PR_MD_UNLOCK(&group->mdlock);
+#endif
+
+    PR_NotifyCondVar(group->new_business);  /* tell the world */
+    rv = (_prmw_success == hrv) ? PR_SUCCESS : PR_FAILURE;
+    PR_Unlock(group->ml);
+
+#ifdef WINNT
+    overlapped = PR_NEWZAP(_MDOverlapped);
+    if (NULL == overlapped)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        NT_HashRemove(group, desc->fd);
+        return rv;
+    }
+    overlapped->ioModel = _MD_MultiWaitIO;
+    overlapped->data.mw.desc = desc;
+    overlapped->data.mw.group = group;
+    if (desc->timeout != PR_INTERVAL_NO_TIMEOUT)
+    {
+        overlapped->data.mw.timer = CreateTimer(
+            desc->timeout,
+            NT_TimeProc,
+            overlapped);
+        if (0 == overlapped->data.mw.timer)
+        {
+            NT_HashRemove(group, desc->fd);
+            PR_DELETE(overlapped);
+            /*
+             * XXX It appears that a maximum of 16 timer events can
+             * be outstanding. GetLastError() returns 0 when I try it.
+             */
+            PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, GetLastError());
+            return PR_FAILURE;
+        }
+    }
+
+    /* Reach to the bottom layer to get the OS fd */
+    bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER);
+    PR_ASSERT(NULL != bottom);
+    if (NULL == bottom)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    hFile = (HANDLE)bottom->secret->md.osfd; 
+    if (!bottom->secret->md.io_model_committed)
+    {
+        PRInt32 st;
+        st = _md_Associate(hFile);
+        PR_ASSERT(0 != st);
+        bottom->secret->md.io_model_committed = PR_TRUE;
+    }
+    bResult = ReadFile(hFile,
+        desc->buffer.start,
+        (DWORD)desc->buffer.length,
+        NULL,
+        &overlapped->overlapped);
+    if (FALSE == bResult && (dwError = GetLastError()) != ERROR_IO_PENDING)
+    {
+        if (desc->timeout != PR_INTERVAL_NO_TIMEOUT)
+        {
+            if (InterlockedCompareExchange((LONG *)&desc->outcome,
+                (LONG)PR_MW_FAILURE, (LONG)PR_MW_PENDING)
+                == (LONG)PR_MW_PENDING)
+            {
+                CancelTimer(overlapped->data.mw.timer);
+            }
+            NT_HashRemove(group, desc->fd);
+            PR_DELETE(overlapped);
+        }
+        _PR_MD_MAP_READ_ERROR(dwError);
+        rv = PR_FAILURE;
+    }
+#endif
+
+    return rv;
+}  /* PR_AddWaitFileDesc */
+
+PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group)
+{
+    PRCList *io_ready = NULL;
+#ifdef WINNT
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    _MDOverlapped *overlapped;    
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    if ((NULL == group) && (NULL == (group = MW_Init2()))) goto failed_init;
+
+    PR_Lock(group->ml);
+
+    if (_prmw_running != group->state)
+    {
+        PR_SetError(PR_INVALID_STATE_ERROR, 0);
+        goto invalid_state;
+    }
+
+    group->waiting_threads += 1;  /* the polling thread is counted */
+
+#ifdef WINNT
+    _PR_MD_LOCK(&group->mdlock);
+    while (PR_CLIST_IS_EMPTY(&group->io_ready))
+    {
+        _PR_THREAD_LOCK(me);
+        me->state = _PR_IO_WAIT;
+        PR_APPEND_LINK(&me->waitQLinks, &group->wait_list);
+        if (!_PR_IS_NATIVE_THREAD(me))
+        {
+            _PR_SLEEPQ_LOCK(me->cpu);
+            _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT);
+            _PR_SLEEPQ_UNLOCK(me->cpu);
+        }
+        _PR_THREAD_UNLOCK(me);
+        _PR_MD_UNLOCK(&group->mdlock);
+        PR_Unlock(group->ml);
+        _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
+        me->state = _PR_RUNNING;
+        PR_Lock(group->ml);
+        _PR_MD_LOCK(&group->mdlock);
+        if (_PR_PENDING_INTERRUPT(me)) {
+            PR_REMOVE_LINK(&me->waitQLinks);
+            _PR_MD_UNLOCK(&group->mdlock);
+            me->flags &= ~_PR_INTERRUPT;
+            me->io_suspended = PR_FALSE;
+            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+            goto aborted;
+        }
+    }
+    io_ready = PR_LIST_HEAD(&group->io_ready);
+    PR_ASSERT(io_ready != NULL);
+    PR_REMOVE_LINK(io_ready);
+    _PR_MD_UNLOCK(&group->mdlock);
+    overlapped = (_MDOverlapped *)
+        ((char *)io_ready - offsetof(_MDOverlapped, data));
+    io_ready = &overlapped->data.mw.desc->internal;
+#else
+    do
+    {
+        /*
+        ** If the I/O ready list isn't empty, have this thread
+        ** return with the first receive wait object that's available.
+        */
+        if (PR_CLIST_IS_EMPTY(&group->io_ready))
+        {
+            /*
+            ** Is there a polling thread yet? If not, grab this thread
+            ** and use it.
+            */
+            if (NULL == group->poller)
+            {
+                /*
+                ** This thread will stay do polling until it becomes the only one
+                ** left to service a completion. Then it will return and there will
+                ** be none left to actually poll or to run completions.
+                **
+                ** The polling function should only return w/ failure or
+                ** with some I/O ready.
+                */
+                if (PR_FAILURE == _MW_PollInternal(group)) goto failed_poll;
+            }
+            else
+            {
+                /*
+                ** There are four reasons a thread can be awakened from
+                ** a wait on the io_complete condition variable.
+                ** 1. Some I/O has completed, i.e., the io_ready list
+                **    is nonempty.
+                ** 2. The wait group is canceled.
+                ** 3. The thread is interrupted.
+                ** 4. The current polling thread has to leave and needs
+                **    a replacement.
+                ** The logic to find a new polling thread is made more
+                ** complicated by all the other possible events.
+                ** I tried my best to write the logic clearly, but
+                ** it is still full of if's with continue and goto.
+                */
+                PRStatus st;
+                do 
+                {
+                    st = PR_WaitCondVar(group->io_complete, PR_INTERVAL_NO_TIMEOUT);
+                    if (_prmw_running != group->state)
+                    {
+                        PR_SetError(PR_INVALID_STATE_ERROR, 0);
+                        goto aborted;
+                    }
+                    if (_MW_ABORTED(st) || (NULL == group->poller)) break;
+                } while (PR_CLIST_IS_EMPTY(&group->io_ready));
+
+                /*
+                ** The thread is interrupted and has to leave.  It might
+                ** have also been awakened to process ready i/o or be the
+                ** new poller.  To be safe, if either condition is true,
+                ** we awaken another thread to take its place.
+                */
+                if (_MW_ABORTED(st))
+                {
+                    if ((NULL == group->poller
+                    || !PR_CLIST_IS_EMPTY(&group->io_ready))
+                    && group->waiting_threads > 1)
+                        PR_NotifyCondVar(group->io_complete);
+                    goto aborted;
+                }
+
+                /*
+                ** A new poller is needed, but can I be the new poller?
+                ** If there is no i/o ready, sure.  But if there is any
+                ** i/o ready, it has a higher priority.  I want to
+                ** process the ready i/o first and wake up another
+                ** thread to be the new poller.
+                */ 
+                if (NULL == group->poller)
+                {
+                    if (PR_CLIST_IS_EMPTY(&group->io_ready))
+                        continue;
+                    if (group->waiting_threads > 1)
+                        PR_NotifyCondVar(group->io_complete);
+                }
+            }
+            PR_ASSERT(!PR_CLIST_IS_EMPTY(&group->io_ready));
+        }
+        io_ready = PR_LIST_HEAD(&group->io_ready);
+        PR_NotifyCondVar(group->io_taken);
+        PR_ASSERT(io_ready != NULL);
+        PR_REMOVE_LINK(io_ready);
+    } while (NULL == io_ready);
+
+failed_poll:
+
+#endif
+
+aborted:
+
+    group->waiting_threads -= 1;
+invalid_state:
+    (void)MW_TestForShutdownInternal(group);
+    PR_Unlock(group->ml);
+
+failed_init:
+    if (NULL != io_ready)
+    {
+        /* If the operation failed, record the reason why */
+        switch (((PRRecvWait*)io_ready)->outcome)
+        {
+            case PR_MW_PENDING:
+                PR_ASSERT(0);
+                break;
+            case PR_MW_SUCCESS:
+#ifndef WINNT
+                _MW_InitialRecv(io_ready);
+#endif
+                break;
+#ifdef WINNT
+            case PR_MW_FAILURE:
+                _PR_MD_MAP_READ_ERROR(overlapped->data.mw.error);
+                break;
+#endif
+            case PR_MW_TIMEOUT:
+                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                break;
+            case PR_MW_INTERRUPT:
+                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                break;
+            default: break;
+        }
+#ifdef WINNT
+        if (NULL != overlapped->data.mw.timer)
+        {
+            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+                != overlapped->data.mw.desc->timeout);
+            CancelTimer(overlapped->data.mw.timer);
+        }
+        else
+        {
+            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+                == overlapped->data.mw.desc->timeout);
+        }
+        PR_DELETE(overlapped);
+#endif
+    }
+    return (PRRecvWait*)io_ready;
+}  /* PR_WaitRecvReady */
+
+PR_IMPLEMENT(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc)
+{
+#if !defined(WINNT)
+    PRRecvWait **recv_wait;
+#endif
+    PRStatus rv = PR_SUCCESS;
+    if (NULL == group) group = mw_state->group;
+    PR_ASSERT(NULL != group);
+    if (NULL == group)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    PR_Lock(group->ml);
+
+    if (_prmw_running != group->state)
+    {
+        PR_SetError(PR_INVALID_STATE_ERROR, 0);
+        rv = PR_FAILURE;
+        goto unlock;
+    }
+
+#ifdef WINNT
+    if (InterlockedCompareExchange((LONG *)&desc->outcome,
+        (LONG)PR_MW_INTERRUPT, (LONG)PR_MW_PENDING) == (LONG)PR_MW_PENDING)
+    {
+        PRFileDesc *bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER);
+        PR_ASSERT(NULL != bottom);
+        if (NULL == bottom)
+        {
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            goto unlock;
+        }
+        bottom->secret->state = _PR_FILEDESC_CLOSED;
+#if 0
+        fprintf(stderr, "cancel wait recv: closing socket\n");
+#endif
+        if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR)
+        {
+            fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError());
+            exit(1);
+        }
+    }
+#else
+    if (NULL != (recv_wait = _MW_LookupInternal(group, desc->fd)))
+    {
+        /* it was in the wait table */
+        _MW_DoneInternal(group, recv_wait, PR_MW_INTERRUPT);
+        goto unlock;
+    }
+    if (!PR_CLIST_IS_EMPTY(&group->io_ready))
+    {
+        /* is it already complete? */
+        PRCList *head = PR_LIST_HEAD(&group->io_ready);
+        do
+        {
+            PRRecvWait *done = (PRRecvWait*)head;
+            if (done == desc) goto unlock;
+            head = PR_NEXT_LINK(head);
+        } while (head != &group->io_ready);
+    }
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    rv = PR_FAILURE;
+
+#endif
+unlock:
+    PR_Unlock(group->ml);
+    return rv;
+}  /* PR_CancelWaitFileDesc */
+
+PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group)
+{
+    PRRecvWait **desc;
+    PRRecvWait *recv_wait = NULL;
+#ifdef WINNT
+    _MDOverlapped *overlapped;
+    PRRecvWait **end;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+#endif
+
+    if (NULL == group) group = mw_state->group;
+    PR_ASSERT(NULL != group);
+    if (NULL == group)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return NULL;
+    }
+
+    PR_Lock(group->ml);
+    if (_prmw_stopped != group->state)
+    {
+        if (_prmw_running == group->state)
+            group->state = _prmw_stopping;  /* so nothing new comes in */
+        if (0 == group->waiting_threads)  /* is there anybody else? */
+            group->state = _prmw_stopped;  /* we can stop right now */
+        else
+        {
+            PR_NotifyAllCondVar(group->new_business);
+            PR_NotifyAllCondVar(group->io_complete);
+        }
+        while (_prmw_stopped != group->state)
+            (void)PR_WaitCondVar(group->mw_manage, PR_INTERVAL_NO_TIMEOUT);
+    }
+
+#ifdef WINNT
+    _PR_MD_LOCK(&group->mdlock);
+#endif
+    /* make all the existing descriptors look done/interrupted */
+#ifdef WINNT
+    end = &group->waiter->recv_wait + group->waiter->length;
+    for (desc = &group->waiter->recv_wait; desc < end; ++desc)
+    {
+        if (NULL != *desc)
+        {
+            if (InterlockedCompareExchange((LONG *)&(*desc)->outcome,
+                (LONG)PR_MW_INTERRUPT, (LONG)PR_MW_PENDING)
+                == (LONG)PR_MW_PENDING)
+            {
+                PRFileDesc *bottom = PR_GetIdentitiesLayer(
+                    (*desc)->fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottom);
+                if (NULL == bottom)
+                {
+                    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+                    goto invalid_arg;
+                }
+                bottom->secret->state = _PR_FILEDESC_CLOSED;
+#if 0
+                fprintf(stderr, "cancel wait group: closing socket\n");
+#endif
+                if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR)
+                {
+                    fprintf(stderr, "closesocket failed: %d\n",
+                        WSAGetLastError());
+                    exit(1);
+                }
+            }
+        }
+    }
+    while (group->waiter->count > 0)
+    {
+        _PR_THREAD_LOCK(me);
+        me->state = _PR_IO_WAIT;
+        PR_APPEND_LINK(&me->waitQLinks, &group->wait_list);
+        if (!_PR_IS_NATIVE_THREAD(me))
+        {
+            _PR_SLEEPQ_LOCK(me->cpu);
+            _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT);
+            _PR_SLEEPQ_UNLOCK(me->cpu);
+        }
+        _PR_THREAD_UNLOCK(me);
+        _PR_MD_UNLOCK(&group->mdlock);
+        PR_Unlock(group->ml);
+        _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
+        me->state = _PR_RUNNING;
+        PR_Lock(group->ml);
+        _PR_MD_LOCK(&group->mdlock);
+    }
+#else
+    for (desc = &group->waiter->recv_wait; group->waiter->count > 0; ++desc)
+    {
+        PR_ASSERT(desc < &group->waiter->recv_wait + group->waiter->length);
+        if (NULL != *desc)
+            _MW_DoneInternal(group, desc, PR_MW_INTERRUPT);
+    }
+#endif
+
+    /* take first element of finished list and return it or NULL */
+    if (PR_CLIST_IS_EMPTY(&group->io_ready))
+        PR_SetError(PR_GROUP_EMPTY_ERROR, 0);
+    else
+    {
+        PRCList *head = PR_LIST_HEAD(&group->io_ready);
+        PR_REMOVE_AND_INIT_LINK(head);
+#ifdef WINNT
+        overlapped = (_MDOverlapped *)
+            ((char *)head - offsetof(_MDOverlapped, data));
+        head = &overlapped->data.mw.desc->internal;
+        if (NULL != overlapped->data.mw.timer)
+        {
+            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+                != overlapped->data.mw.desc->timeout);
+            CancelTimer(overlapped->data.mw.timer);
+        }
+        else
+        {
+            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+                == overlapped->data.mw.desc->timeout);
+        }
+        PR_DELETE(overlapped);
+#endif
+        recv_wait = (PRRecvWait*)head;
+    }
+#ifdef WINNT
+invalid_arg:
+    _PR_MD_UNLOCK(&group->mdlock);
+#endif
+    PR_Unlock(group->ml);
+
+    return recv_wait;
+}  /* PR_CancelWaitGroup */
+
+PR_IMPLEMENT(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size /* ignored */)
+{
+    PRWaitGroup *wg;
+
+    if (NULL == (wg = PR_NEWZAP(PRWaitGroup)))
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        goto failed;
+    }
+    /* the wait group itself */
+    wg->ml = PR_NewLock();
+    if (NULL == wg->ml) goto failed_lock;
+    wg->io_taken = PR_NewCondVar(wg->ml);
+    if (NULL == wg->io_taken) goto failed_cvar0;
+    wg->io_complete = PR_NewCondVar(wg->ml);
+    if (NULL == wg->io_complete) goto failed_cvar1;
+    wg->new_business = PR_NewCondVar(wg->ml);
+    if (NULL == wg->new_business) goto failed_cvar2;
+    wg->mw_manage = PR_NewCondVar(wg->ml);
+    if (NULL == wg->mw_manage) goto failed_cvar3;
+
+    PR_INIT_CLIST(&wg->group_link);
+    PR_INIT_CLIST(&wg->io_ready);
+
+    /* the waiters sequence */
+    wg->waiter = (_PRWaiterHash*)PR_CALLOC(
+        sizeof(_PRWaiterHash) +
+        (_PR_DEFAULT_HASH_LENGTH * sizeof(PRRecvWait*)));
+    if (NULL == wg->waiter)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        goto failed_waiter;
+    }
+    wg->waiter->count = 0;
+    wg->waiter->length = _PR_DEFAULT_HASH_LENGTH;
+
+#ifdef WINNT
+    _PR_MD_NEW_LOCK(&wg->mdlock);
+    PR_INIT_CLIST(&wg->wait_list);
+#endif /* WINNT */
+
+    PR_Lock(mw_lock);
+    PR_APPEND_LINK(&wg->group_link, &mw_state->group_list);
+    PR_Unlock(mw_lock);
+    return wg;
+
+failed_waiter:
+    PR_DestroyCondVar(wg->mw_manage);
+failed_cvar3:
+    PR_DestroyCondVar(wg->new_business);
+failed_cvar2:
+    PR_DestroyCondVar(wg->io_complete);
+failed_cvar1:
+    PR_DestroyCondVar(wg->io_taken);
+failed_cvar0:
+    PR_DestroyLock(wg->ml);
+failed_lock:
+    PR_DELETE(wg);
+    wg = NULL;
+
+failed:
+    return wg;
+}  /* MW_CreateWaitGroup */
+
+PR_IMPLEMENT(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group)
+{
+    PRStatus rv = PR_SUCCESS;
+    if (NULL == group) group = mw_state->group;
+    PR_ASSERT(NULL != group);
+    if (NULL != group)
+    {
+        PR_Lock(group->ml);
+        if ((group->waiting_threads == 0)
+        && (group->waiter->count == 0)
+        && PR_CLIST_IS_EMPTY(&group->io_ready))
+        {
+            group->state = _prmw_stopped;
+        }
+        else
+        {
+            PR_SetError(PR_INVALID_STATE_ERROR, 0);
+            rv = PR_FAILURE;
+        }
+        PR_Unlock(group->ml);
+        if (PR_FAILURE == rv) return rv;
+
+        PR_Lock(mw_lock);
+        PR_REMOVE_LINK(&group->group_link);
+        PR_Unlock(mw_lock);
+
+#ifdef WINNT
+        /*
+         * XXX make sure wait_list is empty and waiter is empty.
+         * These must be checked while holding mdlock.
+         */
+        _PR_MD_FREE_LOCK(&group->mdlock);
+#endif
+
+        PR_DELETE(group->waiter);
+        PR_DELETE(group->polling_list);
+        PR_DestroyCondVar(group->mw_manage);
+        PR_DestroyCondVar(group->new_business);
+        PR_DestroyCondVar(group->io_complete);
+        PR_DestroyCondVar(group->io_taken);
+        PR_DestroyLock(group->ml);
+        if (group == mw_state->group) mw_state->group = NULL;
+        PR_DELETE(group);
+    }
+    else
+    {
+        /* The default wait group is not created yet. */
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        rv = PR_FAILURE;
+    }
+    return rv;
+}  /* PR_DestroyWaitGroup */
+
+/**********************************************************************
+***********************************************************************
+******************** Wait group enumerations **************************
+***********************************************************************
+**********************************************************************/
+
+PR_IMPLEMENT(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group)
+{
+    PRMWaitEnumerator *enumerator = PR_NEWZAP(PRMWaitEnumerator);
+    if (NULL == enumerator) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    else
+    {
+        enumerator->group = group;
+        enumerator->seal = _PR_ENUM_SEALED;
+    }
+    return enumerator;
+}  /* PR_CreateMWaitEnumerator */
+
+PR_IMPLEMENT(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator)
+{
+    PR_ASSERT(NULL != enumerator);
+    PR_ASSERT(_PR_ENUM_SEALED == enumerator->seal);
+    if ((NULL == enumerator) || (_PR_ENUM_SEALED != enumerator->seal))
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    enumerator->seal = _PR_ENUM_UNSEALED;
+    PR_Free(enumerator);
+    return PR_SUCCESS;
+}  /* PR_DestroyMWaitEnumerator */
+
+PR_IMPLEMENT(PRRecvWait*) PR_EnumerateWaitGroup(
+    PRMWaitEnumerator *enumerator, const PRRecvWait *previous)
+{
+    PRRecvWait *result = NULL;
+    
+    /* entry point sanity checking */
+    PR_ASSERT(NULL != enumerator);
+    PR_ASSERT(_PR_ENUM_SEALED == enumerator->seal);
+    if ((NULL == enumerator)
+    || (_PR_ENUM_SEALED != enumerator->seal)) goto bad_argument;
+
+    /* beginning of enumeration */
+    if (NULL == previous)
+    {
+        if (NULL == enumerator->group)
+        {
+            enumerator->group = mw_state->group;
+            if (NULL == enumerator->group)
+            {
+                PR_SetError(PR_GROUP_EMPTY_ERROR, 0);
+                return NULL;
+            }
+        }
+        enumerator->waiter = &enumerator->group->waiter->recv_wait;
+        enumerator->p_timestamp = enumerator->group->p_timestamp;
+        enumerator->thread = PR_GetCurrentThread();
+        enumerator->index = 0;
+    }
+    /* continuing an enumeration */
+    else
+    {
+        PRThread *me = PR_GetCurrentThread();
+        PR_ASSERT(me == enumerator->thread);
+        if (me != enumerator->thread) goto bad_argument;
+
+        /* need to restart the enumeration */
+        if (enumerator->p_timestamp != enumerator->group->p_timestamp)
+            return PR_EnumerateWaitGroup(enumerator, NULL);
+    }
+
+    /* actually progress the enumeration */
+#if defined(WINNT)
+    _PR_MD_LOCK(&enumerator->group->mdlock);
+#else
+    PR_Lock(enumerator->group->ml);
+#endif
+    while (enumerator->index++ < enumerator->group->waiter->length)
+    {
+        if (NULL != (result = *(enumerator->waiter)++)) break;
+    }
+#if defined(WINNT)
+    _PR_MD_UNLOCK(&enumerator->group->mdlock);
+#else
+    PR_Unlock(enumerator->group->ml);
+#endif
+
+    return result;  /* what we live for */
+
+bad_argument:
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return NULL;  /* probably ambiguous */
+}  /* PR_EnumerateWaitGroup */
+
+/* prmwait.c */
diff --git a/mozilla/nsprpub/pr/src/io/prpolevt.c b/mozilla/nsprpub/pr/src/io/prpolevt.c
new file mode 100644
index 0000000..f94190d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prpolevt.c
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ *********************************************************************
+ *
+ * Pollable events
+ *
+ * Pollable events are implemented using layered I/O.  The only
+ * I/O methods that are implemented for pollable events are poll
+ * and close.  No other methods can be invoked on a pollable
+ * event.
+ *
+ * A pipe or socket pair is created and the pollable event layer
+ * is pushed onto the read end.  A pointer to the write end is
+ * saved in the PRFilePrivate structure of the pollable event.
+ *
+ *********************************************************************
+ */
+
+#include "prinit.h"
+#include "prio.h"
+#include "prmem.h"
+#include "prerror.h"
+#include "prlog.h"
+
+/*
+ * These internal functions are declared in primpl.h,
+ * but we can't include primpl.h because the definition
+ * of struct PRFilePrivate in this file (for the pollable
+ * event layer) will conflict with the definition of
+ * struct PRFilePrivate in primpl.h (for the NSPR layer).
+ */
+extern PRIntn _PR_InvalidInt(void);
+extern PRInt64 _PR_InvalidInt64(void);
+extern PRStatus _PR_InvalidStatus(void);
+extern PRFileDesc *_PR_InvalidDesc(void);
+
+/*
+ * PRFilePrivate structure for the NSPR pollable events layer
+ */
+struct PRFilePrivate {
+    PRFileDesc *writeEnd;  /* the write end of the pipe/socketpair */
+};
+
+static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd);
+
+static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags);
+
+static PRIOMethods _pr_polevt_methods = {
+    PR_DESC_LAYERED,
+    _pr_PolEvtClose,
+    (PRReadFN)_PR_InvalidInt,
+    (PRWriteFN)_PR_InvalidInt,
+    (PRAvailableFN)_PR_InvalidInt,
+    (PRAvailable64FN)_PR_InvalidInt64,
+    (PRFsyncFN)_PR_InvalidStatus,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+    _pr_PolEvtPoll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRDescIdentity _pr_polevt_id;
+static PRCallOnceType _pr_polevt_once_control;
+static PRStatus PR_CALLBACK _pr_PolEvtInit(void);
+
+static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+    return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
+}
+
+static PRStatus PR_CALLBACK _pr_PolEvtInit(void)
+{
+    _pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events");
+    if (PR_INVALID_IO_LAYER == _pr_polevt_id) {
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+#if !defined(XP_UNIX)
+#define USE_TCP_SOCKETPAIR
+#endif
+
+PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
+{
+    PRFileDesc *event;
+    PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */
+#ifdef USE_TCP_SOCKETPAIR
+    PRSocketOptionData socket_opt;
+    PRStatus rv;
+#endif
+
+    fd[0] = fd[1] = NULL;
+
+    if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) {
+        return NULL;
+    }
+
+    event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods);
+    if (NULL == event) {
+        goto errorExit;
+    } 
+    event->secret = PR_NEW(PRFilePrivate);
+    if (event->secret == NULL) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        goto errorExit;
+    }
+
+#ifndef USE_TCP_SOCKETPAIR
+    if (PR_CreatePipe(&fd[0], &fd[1]) == PR_FAILURE) {
+        fd[0] = fd[1] = NULL;
+        goto errorExit;
+    }
+#else
+    if (PR_NewTCPSocketPair(fd) == PR_FAILURE) {
+        fd[0] = fd[1] = NULL;
+        goto errorExit;
+    }
+	/*
+	 * set the TCP_NODELAY option to reduce notification latency
+	 */
+    socket_opt.option = PR_SockOpt_NoDelay;
+    socket_opt.value.no_delay = PR_TRUE;
+    rv = PR_SetSocketOption(fd[1], &socket_opt);
+    PR_ASSERT(PR_SUCCESS == rv);
+#endif
+
+    event->secret->writeEnd = fd[1];
+    if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) {
+        goto errorExit;
+    }
+
+    return fd[0];
+
+errorExit:
+    if (fd[0]) {
+        PR_Close(fd[0]);
+        PR_Close(fd[1]);
+    }
+    if (event) {
+        PR_DELETE(event->secret);
+        event->dtor(event);
+    }
+    return NULL;
+}
+
+static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd)
+{
+    PRFileDesc *event;
+
+    event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
+    PR_ASSERT(NULL == event->higher && NULL == event->lower);
+    PR_Close(fd);
+    PR_Close(event->secret->writeEnd);
+    PR_DELETE(event->secret);
+    event->dtor(event);
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
+{
+    return PR_Close(event);
+}
+
+static const char magicChar = '\x38';
+
+PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event)
+{
+    if (PR_Write(event->secret->writeEnd, &magicChar, 1) != 1) {
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event)
+{
+    char buf[1024];
+    PRInt32 nBytes;
+#ifdef DEBUG
+    PRIntn i;
+#endif
+
+    nBytes = PR_Read(event->lower, buf, sizeof(buf));
+    if (nBytes == -1) {
+        return PR_FAILURE;
+    }
+
+#ifdef DEBUG
+    /*
+     * Make sure people do not write to the pollable event fd
+     * directly.
+     */
+    for (i = 0; i < nBytes; i++) {
+        PR_ASSERT(buf[i] == magicChar);
+    }
+#endif
+
+    return PR_SUCCESS;
+}
diff --git a/mozilla/nsprpub/pr/src/io/prprf.c b/mozilla/nsprpub/pr/src/io/prprf.c
new file mode 100644
index 0000000..8dda74c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prprf.c
@@ -0,0 +1,1230 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** Portable safe sprintf code.
+**
+** Author: Kipp E.B. Hickman
+*/
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include "primpl.h"
+#include "prprf.h"
+#include "prlong.h"
+#include "prlog.h"
+#include "prmem.h"
+
+/*
+** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)
+*/
+
+/*
+** XXX This needs to be internationalized!
+*/
+
+typedef struct SprintfStateStr SprintfState;
+
+struct SprintfStateStr {
+    int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len);
+
+    char *base;
+    char *cur;
+    PRUint32 maxlen;
+
+    int (*func)(void *arg, const char *sp, PRUint32 len);
+    void *arg;
+};
+
+/*
+** Numbered Argument
+*/
+struct NumArg {
+    int type;           /* type of the numbered argument    */
+    union {             /* the numbered argument            */
+	int i;
+	unsigned int ui;
+	PRInt32 i32;
+	PRUint32 ui32;
+	PRInt64 ll;
+	PRUint64 ull;
+	double d;
+	const char *s;
+	int *ip;
+    } u;
+};
+
+#define NAS_DEFAULT_NUM 20  /* default number of NumberedArgument array */
+
+
+#define TYPE_INT16	0
+#define TYPE_UINT16	1
+#define TYPE_INTN	2
+#define TYPE_UINTN	3
+#define TYPE_INT32	4
+#define TYPE_UINT32	5
+#define TYPE_INT64	6
+#define TYPE_UINT64	7
+#define TYPE_STRING	8
+#define TYPE_DOUBLE	9
+#define TYPE_INTSTR	10
+#define TYPE_UNKNOWN	20
+
+#define FLAG_LEFT	0x1
+#define FLAG_SIGNED	0x2
+#define FLAG_SPACED	0x4
+#define FLAG_ZEROS	0x8
+#define FLAG_NEG	0x10
+
+/*
+** Fill into the buffer using the data in src
+*/
+static int fill2(SprintfState *ss, const char *src, int srclen, int width,
+		int flags)
+{
+    char space = ' ';
+    int rv;
+
+    width -= srclen;
+    if ((width > 0) && ((flags & FLAG_LEFT) == 0)) {	/* Right adjusting */
+	if (flags & FLAG_ZEROS) {
+	    space = '0';
+	}
+	while (--width >= 0) {
+	    rv = (*ss->stuff)(ss, &space, 1);
+	    if (rv < 0) {
+		return rv;
+	    }
+	}
+    }
+
+    /* Copy out the source data */
+    rv = (*ss->stuff)(ss, src, srclen);
+    if (rv < 0) {
+	return rv;
+    }
+
+    if ((width > 0) && ((flags & FLAG_LEFT) != 0)) {	/* Left adjusting */
+	while (--width >= 0) {
+	    rv = (*ss->stuff)(ss, &space, 1);
+	    if (rv < 0) {
+		return rv;
+	    }
+	}
+    }
+    return 0;
+}
+
+/*
+** Fill a number. The order is: optional-sign zero-filling conversion-digits
+*/
+static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
+		  int prec, int type, int flags)
+{
+    int zerowidth = 0;
+    int precwidth = 0;
+    int signwidth = 0;
+    int leftspaces = 0;
+    int rightspaces = 0;
+    int cvtwidth;
+    int rv;
+    char sign;
+
+    if ((type & 1) == 0) {
+	if (flags & FLAG_NEG) {
+	    sign = '-';
+	    signwidth = 1;
+	} else if (flags & FLAG_SIGNED) {
+	    sign = '+';
+	    signwidth = 1;
+	} else if (flags & FLAG_SPACED) {
+	    sign = ' ';
+	    signwidth = 1;
+	}
+    }
+    cvtwidth = signwidth + srclen;
+
+    if (prec > 0) {
+	if (prec > srclen) {
+	    precwidth = prec - srclen;		/* Need zero filling */
+	    cvtwidth += precwidth;
+	}
+    }
+
+    if ((flags & FLAG_ZEROS) && (prec < 0)) {
+	if (width > cvtwidth) {
+	    zerowidth = width - cvtwidth;	/* Zero filling */
+	    cvtwidth += zerowidth;
+	}
+    }
+
+    if (flags & FLAG_LEFT) {
+	if (width > cvtwidth) {
+	    /* Space filling on the right (i.e. left adjusting) */
+	    rightspaces = width - cvtwidth;
+	}
+    } else {
+	if (width > cvtwidth) {
+	    /* Space filling on the left (i.e. right adjusting) */
+	    leftspaces = width - cvtwidth;
+	}
+    }
+    while (--leftspaces >= 0) {
+	rv = (*ss->stuff)(ss, " ", 1);
+	if (rv < 0) {
+	    return rv;
+	}
+    }
+    if (signwidth) {
+	rv = (*ss->stuff)(ss, &sign, 1);
+	if (rv < 0) {
+	    return rv;
+	}
+    }
+    while (--precwidth >= 0) {
+	rv = (*ss->stuff)(ss, "0", 1);
+	if (rv < 0) {
+	    return rv;
+	}
+    }
+    while (--zerowidth >= 0) {
+	rv = (*ss->stuff)(ss, "0", 1);
+	if (rv < 0) {
+	    return rv;
+	}
+    }
+    rv = (*ss->stuff)(ss, src, srclen);
+    if (rv < 0) {
+	return rv;
+    }
+    while (--rightspaces >= 0) {
+	rv = (*ss->stuff)(ss, " ", 1);
+	if (rv < 0) {
+	    return rv;
+	}
+    }
+    return 0;
+}
+
+/*
+** Convert a long into its printable form
+*/
+static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
+		 int type, int flags, const char *hexp)
+{
+    char cvtbuf[100];
+    char *cvt;
+    int digits;
+
+    /* according to the man page this needs to happen */
+    if ((prec == 0) && (num == 0)) {
+	return 0;
+    }
+
+    /*
+    ** Converting decimal is a little tricky. In the unsigned case we
+    ** need to stop when we hit 10 digits. In the signed case, we can
+    ** stop when the number is zero.
+    */
+    cvt = cvtbuf + sizeof(cvtbuf);
+    digits = 0;
+    while (num) {
+	int digit = (((unsigned long)num) % radix) & 0xF;
+	*--cvt = hexp[digit];
+	digits++;
+	num = (long)(((unsigned long)num) / radix);
+    }
+    if (digits == 0) {
+	*--cvt = '0';
+	digits++;
+    }
+
+    /*
+    ** Now that we have the number converted without its sign, deal with
+    ** the sign and zero padding.
+    */
+    return fill_n(ss, cvt, digits, width, prec, type, flags);
+}
+
+/*
+** Convert a 64-bit integer into its printable form
+*/
+static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, int radix,
+		  int type, int flags, const char *hexp)
+{
+    char cvtbuf[100];
+    char *cvt;
+    int digits;
+    PRInt64 rad;
+
+    /* according to the man page this needs to happen */
+    if ((prec == 0) && (LL_IS_ZERO(num))) {
+	return 0;
+    }
+
+    /*
+    ** Converting decimal is a little tricky. In the unsigned case we
+    ** need to stop when we hit 10 digits. In the signed case, we can
+    ** stop when the number is zero.
+    */
+    LL_I2L(rad, radix);
+    cvt = cvtbuf + sizeof(cvtbuf);
+    digits = 0;
+    while (!LL_IS_ZERO(num)) {
+	PRInt32 digit;
+	PRInt64 quot, rem;
+	LL_UDIVMOD(&quot, &rem, num, rad);
+	LL_L2I(digit, rem);
+	*--cvt = hexp[digit & 0xf];
+	digits++;
+	num = quot;
+    }
+    if (digits == 0) {
+	*--cvt = '0';
+	digits++;
+    }
+
+    /*
+    ** Now that we have the number converted without its sign, deal with
+    ** the sign and zero padding.
+    */
+    return fill_n(ss, cvt, digits, width, prec, type, flags);
+}
+
+/*
+** Convert a double precision floating point number into its printable
+** form.
+**
+** XXX stop using sprintf to convert floating point
+*/
+static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
+{
+    char fin[20];
+    char fout[300];
+    int amount = fmt1 - fmt0;
+
+    PR_ASSERT((amount > 0) && (amount < sizeof(fin)));
+    if (amount >= sizeof(fin)) {
+	/* Totally bogus % command to sprintf. Just ignore it */
+	return 0;
+    }
+    memcpy(fin, fmt0, amount);
+    fin[amount] = 0;
+
+    /* Convert floating point using the native sprintf code */
+#ifdef DEBUG
+    {
+        const char *p = fin;
+        while (*p) {
+            PR_ASSERT(*p != 'L');
+            p++;
+        }
+    }
+#endif
+    sprintf(fout, fin, d);
+
+    /*
+    ** This assert will catch overflow's of fout, when building with
+    ** debugging on. At least this way we can track down the evil piece
+    ** of calling code and fix it!
+    */
+    PR_ASSERT(strlen(fout) < sizeof(fout));
+
+    return (*ss->stuff)(ss, fout, strlen(fout));
+}
+
+/*
+** Convert a string into its printable form.  "width" is the output
+** width. "prec" is the maximum number of characters of "s" to output,
+** where -1 means until NUL.
+*/
+static int cvt_s(SprintfState *ss, const char *str, int width, int prec,
+		 int flags)
+{
+    int slen;
+
+    if (prec == 0)
+	return 0;
+
+    /* Limit string length by precision value */
+    if (!str) {
+    	str = "(null)";
+    } 
+    if (prec > 0) {
+	/* this is:  slen = strnlen(str, prec); */
+	register const char *s;
+
+	for(s = str; prec && *s; s++, prec-- )
+	    ;
+	slen = s - str;
+    } else {
+	slen = strlen(str);
+    }
+
+    /* and away we go */
+    return fill2(ss, str, slen, width, flags);
+}
+
+/*
+** BuildArgArray stands for Numbered Argument list Sprintf
+** for example,  
+**	fmp = "%4$i, %2$d, %3s, %1d";
+** the number must start from 1, and no gap among them
+*/
+
+static struct NumArg* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArg* nasArray )
+{
+    int number = 0, cn = 0, i;
+    const char* p;
+    char  c;
+    struct NumArg* nas;
+    
+
+    /*
+    **	first pass:
+    **	determine how many legal % I have got, then allocate space
+    */
+
+    p = fmt;
+    *rv = 0;
+    i = 0;
+    while( ( c = *p++ ) != 0 ){
+	if( c != '%' )
+	    continue;
+	if( ( c = *p++ ) == '%' )	/* skip %% case */
+	    continue;
+
+	while( c != 0 ){
+	    if( c > '9' || c < '0' ){
+		if( c == '$' ){		/* numbered argument case */
+		    if( i > 0 ){
+			*rv = -1;
+			return NULL;
+		    }
+		    number++;
+		} else{			/* non-numbered argument case */
+		    if( number > 0 ){
+			*rv = -1;
+			return NULL;
+		    }
+		    i = 1;
+		}
+		break;
+	    }
+
+	    c = *p++;
+	}
+    }
+
+    if( number == 0 ){
+	return NULL;
+    }
+
+    
+    if( number > NAS_DEFAULT_NUM ){
+	nas = (struct NumArg*)PR_MALLOC( number * sizeof( struct NumArg ) );
+	if( !nas ){
+	    *rv = -1;
+	    return NULL;
+	}
+    } else {
+	nas = nasArray;
+    }
+
+    for( i = 0; i < number; i++ ){
+	nas[i].type = TYPE_UNKNOWN;
+    }
+
+
+    /*
+    ** second pass:
+    ** set nas[].type
+    */
+
+    p = fmt;
+    while( ( c = *p++ ) != 0 ){
+    	if( c != '%' )	continue;
+	    c = *p++;
+	if( c == '%' )	continue;
+
+	cn = 0;
+	while( c && c != '$' ){	    /* should imporve error check later */
+	    cn = cn*10 + c - '0';
+	    c = *p++;
+	}
+
+	if( !c || cn < 1 || cn > number ){
+	    *rv = -1;
+	    break;
+        }
+
+	/* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
+        cn--;
+	if( nas[cn].type != TYPE_UNKNOWN )
+	    continue;
+
+        c = *p++;
+
+        /* width */
+        if (c == '*') {
+	    /* not supported feature, for the argument is not numbered */
+	    *rv = -1;
+	    break;
+	}
+
+	while ((c >= '0') && (c <= '9')) {
+	    c = *p++;
+	}
+
+	/* precision */
+	if (c == '.') {
+	    c = *p++;
+	    if (c == '*') {
+	        /* not supported feature, for the argument is not numbered */
+	        *rv = -1;
+	        break;
+	    }
+
+	    while ((c >= '0') && (c <= '9')) {
+		c = *p++;
+	    }
+	}
+
+	/* size */
+	nas[cn].type = TYPE_INTN;
+	if (c == 'h') {
+	    nas[cn].type = TYPE_INT16;
+	    c = *p++;
+	} else if (c == 'L') {
+	    /* XXX not quite sure here */
+	    nas[cn].type = TYPE_INT64;
+	    c = *p++;
+	} else if (c == 'l') {
+	    nas[cn].type = TYPE_INT32;
+	    c = *p++;
+	    if (c == 'l') {
+	        nas[cn].type = TYPE_INT64;
+	        c = *p++;
+	    }
+	}
+
+	/* format */
+	switch (c) {
+	case 'd':
+	case 'c':
+	case 'i':
+	case 'o':
+	case 'u':
+	case 'x':
+	case 'X':
+	    break;
+
+	case 'e':
+	case 'f':
+	case 'g':
+	    nas[ cn ].type = TYPE_DOUBLE;
+	    break;
+
+	case 'p':
+	    /* XXX should use cpp */
+	    if (sizeof(void *) == sizeof(PRInt32)) {
+		nas[ cn ].type = TYPE_UINT32;
+	    } else if (sizeof(void *) == sizeof(PRInt64)) {
+	        nas[ cn ].type = TYPE_UINT64;
+	    } else if (sizeof(void *) == sizeof(PRIntn)) {
+	        nas[ cn ].type = TYPE_UINTN;
+	    } else {
+	        nas[ cn ].type = TYPE_UNKNOWN;
+	    }
+	    break;
+
+	case 'C':
+	case 'S':
+	case 'E':
+	case 'G':
+	    /* XXX not supported I suppose */
+	    PR_ASSERT(0);
+	    nas[ cn ].type = TYPE_UNKNOWN;
+	    break;
+
+	case 's':
+	    nas[ cn ].type = TYPE_STRING;
+	    break;
+
+	case 'n':
+	    nas[ cn ].type = TYPE_INTSTR;
+	    break;
+
+	default:
+	    PR_ASSERT(0);
+	    nas[ cn ].type = TYPE_UNKNOWN;
+	    break;
+	}
+
+	/* get a legal para. */
+	if( nas[ cn ].type == TYPE_UNKNOWN ){
+	    *rv = -1;
+	    break;
+	}
+    }
+
+
+    /*
+    ** third pass
+    ** fill the nas[cn].ap
+    */
+
+    if( *rv < 0 ){
+	if( nas != nasArray )
+	    PR_DELETE( nas );
+	return NULL;
+    }
+
+    cn = 0;
+    while( cn < number ){
+	if( nas[cn].type == TYPE_UNKNOWN ){
+	    cn++;
+	    continue;
+	}
+
+	switch( nas[cn].type ){
+	case TYPE_INT16:
+	case TYPE_UINT16:
+	case TYPE_INTN:
+	    nas[cn].u.i = va_arg( ap, int );
+	    break;
+
+	case TYPE_UINTN:
+	    nas[cn].u.ui = va_arg( ap, unsigned int );
+	    break;
+
+	case TYPE_INT32:
+	    nas[cn].u.i32 = va_arg( ap, PRInt32 );
+	    break;
+
+	case TYPE_UINT32:
+	    nas[cn].u.ui32 = va_arg( ap, PRUint32 );
+	    break;
+
+	case TYPE_INT64:
+	    nas[cn].u.ll = va_arg( ap, PRInt64 );
+	    break;
+
+	case TYPE_UINT64:
+	    nas[cn].u.ull = va_arg( ap, PRUint64 );
+	    break;
+
+	case TYPE_STRING:
+	    nas[cn].u.s = va_arg( ap, char* );
+	    break;
+
+	case TYPE_INTSTR:
+	    nas[cn].u.ip = va_arg( ap, int* );
+	    break;
+
+	case TYPE_DOUBLE:
+	    nas[cn].u.d = va_arg( ap, double );
+	    break;
+
+	default:
+	    if( nas != nasArray )
+		PR_DELETE( nas );
+	    *rv = -1;
+	    return NULL;
+	}
+
+	cn++;
+    }
+
+
+    return nas;
+}
+
+/*
+** The workhorse sprintf code.
+*/
+static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
+{
+    char c;
+    int flags, width, prec, radix, type;
+    union {
+	char ch;
+	int i;
+	long l;
+	PRInt64 ll;
+	double d;
+	const char *s;
+	int *ip;
+    } u;
+    const char *fmt0;
+    static char *hex = "0123456789abcdef";
+    static char *HEX = "0123456789ABCDEF";
+    char *hexp;
+    int rv, i;
+    struct NumArg* nas = NULL;
+    struct NumArg* nap;
+    struct NumArg  nasArray[ NAS_DEFAULT_NUM ];
+    char  pattern[20];
+    const char* dolPt = NULL;  /* in "%4$.2f", dolPt will point to . */
+
+
+    /*
+    ** build an argument array, IF the fmt is numbered argument
+    ** list style, to contain the Numbered Argument list pointers
+    */
+
+    nas = BuildArgArray( fmt, ap, &rv, nasArray );
+    if( rv < 0 ){
+	/* the fmt contains error Numbered Argument format, jliu@netscape.com */
+	PR_ASSERT(0);
+	return rv;
+    }
+
+    while ((c = *fmt++) != 0) {
+	if (c != '%') {
+	    rv = (*ss->stuff)(ss, fmt - 1, 1);
+	    if (rv < 0) {
+		return rv;
+	    }
+	    continue;
+	}
+	fmt0 = fmt - 1;
+
+	/*
+	** Gobble up the % format string. Hopefully we have handled all
+	** of the strange cases!
+	*/
+	flags = 0;
+	c = *fmt++;
+	if (c == '%') {
+	    /* quoting a % with %% */
+	    rv = (*ss->stuff)(ss, fmt - 1, 1);
+	    if (rv < 0) {
+		return rv;
+	    }
+	    continue;
+	}
+
+	if( nas != NULL ){
+	    /* the fmt contains the Numbered Arguments feature */
+	    i = 0;
+	    while( c && c != '$' ){	    /* should imporve error check later */
+		i = ( i * 10 ) + ( c - '0' );
+		c = *fmt++;
+	    }
+
+	    if( nas[i-1].type == TYPE_UNKNOWN ){
+		if( nas && ( nas != nasArray ) )
+		    PR_DELETE( nas );
+		return -1;
+	    }
+
+	    nap = &nas[i-1];
+	    dolPt = fmt;
+	    c = *fmt++;
+	}
+
+	/*
+	 * Examine optional flags.  Note that we do not implement the
+	 * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
+	 * somewhat ambiguous and not ideal, which is perhaps why
+	 * the various sprintf() implementations are inconsistent
+	 * on this feature.
+	 */
+	while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
+	    if (c == '-') flags |= FLAG_LEFT;
+	    if (c == '+') flags |= FLAG_SIGNED;
+	    if (c == ' ') flags |= FLAG_SPACED;
+	    if (c == '0') flags |= FLAG_ZEROS;
+	    c = *fmt++;
+	}
+	if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
+	if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
+
+	/* width */
+	if (c == '*') {
+	    c = *fmt++;
+	    width = va_arg(ap, int);
+	} else {
+	    width = 0;
+	    while ((c >= '0') && (c <= '9')) {
+		width = (width * 10) + (c - '0');
+		c = *fmt++;
+	    }
+	}
+
+	/* precision */
+	prec = -1;
+	if (c == '.') {
+	    c = *fmt++;
+	    if (c == '*') {
+		c = *fmt++;
+		prec = va_arg(ap, int);
+	    } else {
+		prec = 0;
+		while ((c >= '0') && (c <= '9')) {
+		    prec = (prec * 10) + (c - '0');
+		    c = *fmt++;
+		}
+	    }
+	}
+
+	/* size */
+	type = TYPE_INTN;
+	if (c == 'h') {
+	    type = TYPE_INT16;
+	    c = *fmt++;
+	} else if (c == 'L') {
+	    /* XXX not quite sure here */
+	    type = TYPE_INT64;
+	    c = *fmt++;
+	} else if (c == 'l') {
+	    type = TYPE_INT32;
+	    c = *fmt++;
+	    if (c == 'l') {
+		type = TYPE_INT64;
+		c = *fmt++;
+	    }
+	}
+
+	/* format */
+	hexp = hex;
+	switch (c) {
+	  case 'd': case 'i':			/* decimal/integer */
+	    radix = 10;
+	    goto fetch_and_convert;
+
+	  case 'o':				/* octal */
+	    radix = 8;
+	    type |= 1;
+	    goto fetch_and_convert;
+
+	  case 'u':				/* unsigned decimal */
+	    radix = 10;
+	    type |= 1;
+	    goto fetch_and_convert;
+
+	  case 'x':				/* unsigned hex */
+	    radix = 16;
+	    type |= 1;
+	    goto fetch_and_convert;
+
+	  case 'X':				/* unsigned HEX */
+	    radix = 16;
+	    hexp = HEX;
+	    type |= 1;
+	    goto fetch_and_convert;
+
+	  fetch_and_convert:
+	    switch (type) {
+	      case TYPE_INT16:
+		u.l = nas ? nap->u.i : va_arg(ap, int);
+		if (u.l < 0) {
+		    u.l = -u.l;
+		    flags |= FLAG_NEG;
+		}
+		goto do_long;
+	      case TYPE_UINT16:
+		u.l = (nas ? nap->u.i : va_arg(ap, int)) & 0xffff;
+		goto do_long;
+	      case TYPE_INTN:
+		u.l = nas ? nap->u.i : va_arg(ap, int);
+		if (u.l < 0) {
+		    u.l = -u.l;
+		    flags |= FLAG_NEG;
+		}
+		goto do_long;
+	      case TYPE_UINTN:
+		u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int));
+		goto do_long;
+
+	      case TYPE_INT32:
+		u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32);
+		if (u.l < 0) {
+		    u.l = -u.l;
+		    flags |= FLAG_NEG;
+		}
+		goto do_long;
+	      case TYPE_UINT32:
+		u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32));
+	      do_long:
+		rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
+		if (rv < 0) {
+		    return rv;
+		}
+		break;
+
+	      case TYPE_INT64:
+		u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64);
+		if (!LL_GE_ZERO(u.ll)) {
+		    LL_NEG(u.ll, u.ll);
+		    flags |= FLAG_NEG;
+		}
+		goto do_longlong;
+	      case TYPE_UINT64:
+		u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64);
+	      do_longlong:
+		rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
+		if (rv < 0) {
+		    return rv;
+		}
+		break;
+	    }
+	    break;
+
+	  case 'e':
+	  case 'E':
+	  case 'f':
+	  case 'g':
+	    u.d = nas ? nap->u.d : va_arg(ap, double);
+	    if( nas != NULL ){
+		i = fmt - dolPt;
+		if( i < sizeof( pattern ) ){
+		    pattern[0] = '%';
+		    memcpy( &pattern[1], dolPt, i );
+		    rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
+		}
+	    } else
+		rv = cvt_f(ss, u.d, fmt0, fmt);
+
+	    if (rv < 0) {
+		return rv;
+	    }
+	    break;
+
+	  case 'c':
+	    u.ch = nas ? nap->u.i : va_arg(ap, int);
+            if ((flags & FLAG_LEFT) == 0) {
+                while (width-- > 1) {
+                    rv = (*ss->stuff)(ss, " ", 1);
+                    if (rv < 0) {
+                        return rv;
+                    }
+                }
+            }
+	    rv = (*ss->stuff)(ss, &u.ch, 1);
+	    if (rv < 0) {
+		return rv;
+	    }
+            if (flags & FLAG_LEFT) {
+                while (width-- > 1) {
+                    rv = (*ss->stuff)(ss, " ", 1);
+                    if (rv < 0) {
+                        return rv;
+                    }
+                }
+            }
+	    break;
+
+	  case 'p':
+	    if (sizeof(void *) == sizeof(PRInt32)) {
+	    	type = TYPE_UINT32;
+	    } else if (sizeof(void *) == sizeof(PRInt64)) {
+	    	type = TYPE_UINT64;
+	    } else if (sizeof(void *) == sizeof(int)) {
+		type = TYPE_UINTN;
+	    } else {
+		PR_ASSERT(0);
+		break;
+	    }
+	    radix = 16;
+	    goto fetch_and_convert;
+
+#if 0
+	  case 'C':
+	  case 'S':
+	  case 'E':
+	  case 'G':
+	    /* XXX not supported I suppose */
+	    PR_ASSERT(0);
+	    break;
+#endif
+
+	  case 's':
+	    u.s = nas ? nap->u.s : va_arg(ap, const char*);
+	    rv = cvt_s(ss, u.s, width, prec, flags);
+	    if (rv < 0) {
+		return rv;
+	    }
+	    break;
+
+	  case 'n':
+	    u.ip = nas ? nap->u.ip : va_arg(ap, int*);
+	    if (u.ip) {
+		*u.ip = ss->cur - ss->base;
+	    }
+	    break;
+
+	  default:
+	    /* Not a % token after all... skip it */
+#if 0
+	    PR_ASSERT(0);
+#endif
+	    rv = (*ss->stuff)(ss, "%", 1);
+	    if (rv < 0) {
+		return rv;
+	    }
+	    rv = (*ss->stuff)(ss, fmt - 1, 1);
+	    if (rv < 0) {
+		return rv;
+	    }
+	}
+    }
+
+    /* Stuff trailing NUL */
+    rv = (*ss->stuff)(ss, "\0", 1);
+
+    if( nas && ( nas != nasArray ) ){
+	PR_DELETE( nas );
+    }
+
+    return rv;
+}
+
+/************************************************************************/
+
+static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len)
+{
+    int rv;
+
+    rv = (*ss->func)(ss->arg, sp, len);
+    if (rv < 0) {
+	return rv;
+    }
+    ss->maxlen += len;
+    return 0;
+}
+
+PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg, 
+                                 const char *fmt, ...)
+{
+    va_list ap;
+    PRUint32 rv;
+
+    va_start(ap, fmt);
+    rv = PR_vsxprintf(func, arg, fmt, ap);
+    va_end(ap);
+    return rv;
+}
+
+PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRStuffFunc func, void *arg, 
+                                  const char *fmt, va_list ap)
+{
+    SprintfState ss;
+    int rv;
+
+    ss.stuff = FuncStuff;
+    ss.func = func;
+    ss.arg = arg;
+    ss.maxlen = 0;
+    rv = dosprintf(&ss, fmt, ap);
+    return (rv < 0) ? (PRUint32)-1 : ss.maxlen;
+}
+
+/*
+** Stuff routine that automatically grows the malloc'd output buffer
+** before it overflows.
+*/
+static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len)
+{
+    ptrdiff_t off;
+    char *newbase;
+    PRUint32 newlen;
+
+    off = ss->cur - ss->base;
+    if (off + len >= ss->maxlen) {
+	/* Grow the buffer */
+	newlen = ss->maxlen + ((len > 32) ? len : 32);
+	if (ss->base) {
+	    newbase = (char*) PR_REALLOC(ss->base, newlen);
+	} else {
+	    newbase = (char*) PR_MALLOC(newlen);
+	}
+	if (!newbase) {
+	    /* Ran out of memory */
+	    return -1;
+	}
+	ss->base = newbase;
+	ss->maxlen = newlen;
+	ss->cur = ss->base + off;
+    }
+
+    /* Copy data */
+    while (len) {
+	--len;
+	*ss->cur++ = *sp++;
+    }
+    PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen);
+    return 0;
+}
+
+/*
+** sprintf into a malloc'd buffer
+*/
+PR_IMPLEMENT(char *) PR_smprintf(const char *fmt, ...)
+{
+    va_list ap;
+    char *rv;
+
+    va_start(ap, fmt);
+    rv = PR_vsmprintf(fmt, ap);
+    va_end(ap);
+    return rv;
+}
+
+/*
+** Free memory allocated, for the caller, by PR_smprintf
+*/
+PR_IMPLEMENT(void) PR_smprintf_free(char *mem)
+{
+	PR_DELETE(mem);
+}
+
+PR_IMPLEMENT(char *) PR_vsmprintf(const char *fmt, va_list ap)
+{
+    SprintfState ss;
+    int rv;
+
+    ss.stuff = GrowStuff;
+    ss.base = 0;
+    ss.cur = 0;
+    ss.maxlen = 0;
+    rv = dosprintf(&ss, fmt, ap);
+    if (rv < 0) {
+	if (ss.base) {
+	    PR_DELETE(ss.base);
+	}
+	return 0;
+    }
+    return ss.base;
+}
+
+/*
+** Stuff routine that discards overflow data
+*/
+static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len)
+{
+    PRUint32 limit = ss->maxlen - (ss->cur - ss->base);
+
+    if (len > limit) {
+	len = limit;
+    }
+    while (len) {
+	--len;
+	*ss->cur++ = *sp++;
+    }
+    return 0;
+}
+
+/*
+** sprintf into a fixed size buffer. Make sure there is a NUL at the end
+** when finished.
+*/
+PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...)
+{
+    va_list ap;
+    PRUint32 rv;
+
+    va_start(ap, fmt);
+    rv = PR_vsnprintf(out, outlen, fmt, ap);
+    va_end(ap);
+    return rv;
+}
+
+PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt,
+                                  va_list ap)
+{
+    SprintfState ss;
+    PRUint32 n;
+
+    PR_ASSERT((PRInt32)outlen > 0);
+    if ((PRInt32)outlen <= 0) {
+	return 0;
+    }
+
+    ss.stuff = LimitStuff;
+    ss.base = out;
+    ss.cur = out;
+    ss.maxlen = outlen;
+    (void) dosprintf(&ss, fmt, ap);
+
+    /* If we added chars, and we didn't append a null, do it now. */
+    if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') )
+        *(ss.cur - 1) = '\0';
+
+    n = ss.cur - ss.base;
+    return n ? n - 1 : n;
+}
+
+PR_IMPLEMENT(char *) PR_sprintf_append(char *last, const char *fmt, ...)
+{
+    va_list ap;
+    char *rv;
+
+    va_start(ap, fmt);
+    rv = PR_vsprintf_append(last, fmt, ap);
+    va_end(ap);
+    return rv;
+}
+
+PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap)
+{
+    SprintfState ss;
+    int rv;
+
+    ss.stuff = GrowStuff;
+    if (last) {
+	int lastlen = strlen(last);
+	ss.base = last;
+	ss.cur = last + lastlen;
+	ss.maxlen = lastlen;
+    } else {
+	ss.base = 0;
+	ss.cur = 0;
+	ss.maxlen = 0;
+    }
+    rv = dosprintf(&ss, fmt, ap);
+    if (rv < 0) {
+	if (ss.base) {
+	    PR_DELETE(ss.base);
+	}
+	return 0;
+    }
+    return ss.base;
+}
+
diff --git a/mozilla/nsprpub/pr/src/io/prscanf.c b/mozilla/nsprpub/pr/src/io/prscanf.c
new file mode 100644
index 0000000..618f184
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prscanf.c
@@ -0,0 +1,669 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * Scan functions for NSPR types
+ *
+ * Author: Wan-Teh Chang
+ *
+ * Acknowledgment: The implementation is inspired by the source code
+ * in P.J. Plauger's "The Standard C Library," Prentice-Hall, 1992.
+ */
+
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef SUNOS4
+#include "md/sunos4.h"  /* for strtoul */
+#endif
+#include "prprf.h"
+#include "prdtoa.h"
+#include "prlog.h"
+#include "prerror.h"
+
+/*
+ * A function that reads a character from 'stream'.
+ * Returns the character read, or EOF if end of stream is reached.
+ */
+typedef int (*_PRGetCharFN)(void *stream);
+
+/*
+ * A function that pushes the character 'ch' back to 'stream'.
+ */
+typedef void (*_PRUngetCharFN)(void *stream, int ch); 
+
+/*
+ * The size specifier for the integer and floating point number
+ * conversions in format control strings.
+ */
+typedef enum {
+    _PR_size_none,  /* No size specifier is given */
+    _PR_size_h,     /* The 'h' specifier, suggesting "short" */
+    _PR_size_l,     /* The 'l' specifier, suggesting "long" */
+    _PR_size_L,     /* The 'L' specifier, meaning a 'long double' */
+    _PR_size_ll     /* The 'll' specifier, suggesting "long long" */
+} _PRSizeSpec;
+
+/*
+ * The collection of data that is passed between the scan function
+ * and its subordinate functions.  The fields of this structure
+ * serve as the input or output arguments for these functions.
+ */
+typedef struct {
+    _PRGetCharFN get;        /* get a character from input stream */
+    _PRUngetCharFN unget;    /* unget (push back) a character */
+    void *stream;            /* argument for get and unget */
+    va_list ap;              /* the variable argument list */
+    int nChar;               /* number of characters read from 'stream' */
+
+    PRBool assign;           /* assign, or suppress assignment? */
+    int width;               /* field width */
+    _PRSizeSpec sizeSpec;    /* 'h', 'l', 'L', or 'll' */
+
+    PRBool converted;        /* is the value actually converted? */
+} ScanfState;
+
+#define GET(state) ((state)->nChar++, (state)->get((state)->stream))
+#define UNGET(state, ch) \
+        ((state)->nChar--, (state)->unget((state)->stream, ch))
+
+/*
+ * The following two macros, GET_IF_WITHIN_WIDTH and WITHIN_WIDTH,
+ * are always used together.
+ *
+ * GET_IF_WITHIN_WIDTH calls the GET macro and assigns its return
+ * value to 'ch' only if we have not exceeded the field width of
+ * 'state'.  Therefore, after GET_IF_WITHIN_WIDTH, the value of
+ * 'ch' is valid only if the macro WITHIN_WIDTH evaluates to true.
+ */
+
+#define GET_IF_WITHIN_WIDTH(state, ch) \
+        if (--(state)->width >= 0) { \
+            (ch) = GET(state); \
+        }
+#define WITHIN_WIDTH(state) ((state)->width >= 0)
+
+/*
+ * _pr_strtoull:
+ *     Convert a string to an unsigned 64-bit integer.  The string
+ *     'str' is assumed to be a representation of the integer in
+ *     base 'base'.
+ *
+ * Warning: 
+ *     - Only handle base 8, 10, and 16.
+ *     - No overflow checking.
+ */
+
+static PRUint64
+_pr_strtoull(const char *str, char **endptr, int base)
+{
+    static const int BASE_MAX = 16;
+    static const char digits[] = "0123456789abcdef";
+    char *digitPtr;
+    PRUint64 x;    /* return value */
+    PRInt64 base64;
+    const char *cPtr;
+    PRBool negative;
+    const char *digitStart;
+
+    PR_ASSERT(base == 0 || base == 8 || base == 10 || base == 16);
+    if (base < 0 || base == 1 || base > BASE_MAX) {
+        if (endptr) {
+            *endptr = (char *) str;
+            return LL_ZERO;
+        }
+    }
+
+    cPtr = str;
+    while (isspace(*cPtr)) {
+        ++cPtr;
+    }
+
+    negative = PR_FALSE;
+    if (*cPtr == '-') {
+        negative = PR_TRUE;
+        cPtr++;
+    } else if (*cPtr == '+') {
+        cPtr++;
+    }
+
+    if (base == 16) {
+        if (*cPtr == '0' && (cPtr[1] == 'x' || cPtr[1] == 'X')) {
+            cPtr += 2;
+        }
+    } else if (base == 0) {
+        if (*cPtr != '0') {
+            base = 10;
+        } else if (cPtr[1] == 'x' || cPtr[1] == 'X') {
+            base = 16;
+            cPtr += 2;
+        } else {
+            base = 8;
+        } 
+    }
+    PR_ASSERT(base != 0);
+    LL_I2L(base64, base);
+    digitStart = cPtr;
+
+    /* Skip leading zeros */
+    while (*cPtr == '0') {
+        cPtr++;
+    }
+
+    LL_I2L(x, 0);
+    while ((digitPtr = (char*)memchr(digits, tolower(*cPtr), base)) != NULL) {
+        PRUint64 d;
+
+        LL_I2L(d, (digitPtr - digits));
+        LL_MUL(x, x, base64);
+        LL_ADD(x, x, d);
+        cPtr++;
+    }
+
+    if (cPtr == digitStart) {
+        if (endptr) {
+            *endptr = (char *) str;
+        }
+        return LL_ZERO;
+    }
+
+    if (negative) {
+#ifdef HAVE_LONG_LONG
+        /* The cast to a signed type is to avoid a compiler warning */
+        x = -(PRInt64)x;
+#else
+        LL_NEG(x, x);
+#endif
+    }
+
+    if (endptr) {
+        *endptr = (char *) cPtr;
+    }
+    return x;
+}
+
+/*
+ * The maximum field width (in number of characters) that is enough
+ * (may be more than necessary) to represent a 64-bit integer or
+ * floating point number.
+ */
+#define FMAX 31
+#define DECIMAL_POINT '.'
+
+static PRStatus
+GetInt(ScanfState *state, int code)
+{
+    char buf[FMAX + 1], *p;
+    int ch;
+    static const char digits[] = "0123456789abcdefABCDEF";
+    PRBool seenDigit = PR_FALSE;
+    int base;
+    int dlen;
+
+    switch (code) {
+        case 'd': case 'u':
+            base = 10;
+            break;
+        case 'i':
+            base = 0;
+            break;
+        case 'x': case 'X': case 'p':
+            base = 16;
+            break;
+        case 'o':
+            base = 8;
+            break;
+        default:
+            return PR_FAILURE;
+    }
+    if (state->width == 0 || state->width > FMAX) {
+        state->width = FMAX;
+    }
+    p = buf;
+    GET_IF_WITHIN_WIDTH(state, ch);
+    if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
+        *p++ = ch;
+        GET_IF_WITHIN_WIDTH(state, ch);
+    }
+    if (WITHIN_WIDTH(state) && ch == '0') {
+        seenDigit = PR_TRUE;
+        *p++ = ch;
+        GET_IF_WITHIN_WIDTH(state, ch);
+        if (WITHIN_WIDTH(state)
+                && (ch == 'x' || ch == 'X')
+                && (base == 0 || base == 16)) {
+            base = 16;
+            *p++ = ch;
+            GET_IF_WITHIN_WIDTH(state, ch);
+        } else if (base == 0) {
+            base = 8;
+        }
+    }
+    if (base == 0 || base == 10) {
+        dlen = 10;
+    } else if (base == 8) {
+        dlen = 8;
+    } else {
+        PR_ASSERT(base == 16);
+        dlen = 16 + 6; /* 16 digits, plus 6 in uppercase */
+    }
+    while (WITHIN_WIDTH(state) && memchr(digits, ch, dlen)) {
+        *p++ = ch;
+        GET_IF_WITHIN_WIDTH(state, ch);
+        seenDigit = PR_TRUE;
+    }
+    if (WITHIN_WIDTH(state)) {
+        UNGET(state, ch);
+    }
+    if (!seenDigit) {
+        return PR_FAILURE;
+    }
+    *p = '\0';
+    if (state->assign) {
+        if (code == 'd' || code == 'i') {
+            if (state->sizeSpec == _PR_size_ll) {
+                PRInt64 llval = _pr_strtoull(buf, NULL, base);
+                *va_arg(state->ap, PRInt64 *) = llval;
+            } else {
+                long lval = strtol(buf, NULL, base);
+
+                if (state->sizeSpec == _PR_size_none) {
+                    *va_arg(state->ap, PRIntn *) = lval;
+                } else if (state->sizeSpec == _PR_size_h) {
+                    *va_arg(state->ap, PRInt16 *) = (PRInt16)lval;
+                } else if (state->sizeSpec == _PR_size_l) {
+                    *va_arg(state->ap, PRInt32 *) = lval;
+                } else {
+                    return PR_FAILURE;
+                }
+            }
+        } else {
+            if (state->sizeSpec == _PR_size_ll) {
+                PRUint64 llval = _pr_strtoull(buf, NULL, base);
+                *va_arg(state->ap, PRUint64 *) = llval;
+            } else {
+                unsigned long lval = strtoul(buf, NULL, base);
+
+                if (state->sizeSpec == _PR_size_none) {
+                    *va_arg(state->ap, PRUintn *) = lval;
+                } else if (state->sizeSpec == _PR_size_h) {
+                    *va_arg(state->ap, PRUint16 *) = (PRUint16)lval;
+                } else if (state->sizeSpec == _PR_size_l) {
+                    *va_arg(state->ap, PRUint32 *) = lval;
+                } else {
+                    return PR_FAILURE;
+                }
+            }
+        }
+        state->converted = PR_TRUE;
+    }
+    return PR_SUCCESS;
+}
+
+static PRStatus
+GetFloat(ScanfState *state)
+{
+    char buf[FMAX + 1], *p;
+    int ch;
+    PRBool seenDigit = PR_FALSE;
+
+    if (state->width == 0 || state->width > FMAX) {
+        state->width = FMAX;
+    }
+    p = buf;
+    GET_IF_WITHIN_WIDTH(state, ch);
+    if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
+        *p++ = ch;
+        GET_IF_WITHIN_WIDTH(state, ch);
+    }
+    while (WITHIN_WIDTH(state) && isdigit(ch)) {
+        *p++ = ch;
+        GET_IF_WITHIN_WIDTH(state, ch);
+        seenDigit = PR_TRUE;
+    }
+    if (WITHIN_WIDTH(state) && ch == DECIMAL_POINT) {
+        *p++ = ch;
+        GET_IF_WITHIN_WIDTH(state, ch);
+        while (WITHIN_WIDTH(state) && isdigit(ch)) {
+            *p++ = ch;
+            GET_IF_WITHIN_WIDTH(state, ch);
+            seenDigit = PR_TRUE;
+        }
+    }
+
+    /*
+     * This is not robust.  For example, "1.2e+" would confuse
+     * the code below to read 'e' and '+', only to realize that
+     * it should have stopped at "1.2".  But we can't push back
+     * more than one character, so there is nothing I can do.
+     */
+
+    /* Parse exponent */
+    if (WITHIN_WIDTH(state) && (ch == 'e' || ch == 'E') && seenDigit) {
+        *p++ = ch;
+        GET_IF_WITHIN_WIDTH(state, ch);
+        if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
+            *p++ = ch;
+            GET_IF_WITHIN_WIDTH(state, ch);
+        }
+        while (WITHIN_WIDTH(state) && isdigit(ch)) {
+            *p++ = ch;
+            GET_IF_WITHIN_WIDTH(state, ch);
+        }
+    }
+    if (WITHIN_WIDTH(state)) {
+        UNGET(state, ch);
+    }
+    if (!seenDigit) {
+        return PR_FAILURE;
+    }
+    *p = '\0';
+    if (state->assign) {
+        PRFloat64 dval = PR_strtod(buf, NULL);
+
+        state->converted = PR_TRUE;
+        if (state->sizeSpec == _PR_size_l) {
+            *va_arg(state->ap, PRFloat64 *) = dval;
+        } else if (state->sizeSpec == _PR_size_L) {
+#if defined(OSF1) || defined(IRIX)
+            *va_arg(state->ap, double *) = dval;
+#else
+            *va_arg(state->ap, long double *) = dval;
+#endif
+        } else {
+            *va_arg(state->ap, float *) = (float) dval;
+        }
+    }
+    return PR_SUCCESS;
+}
+
+/*
+ * Convert, and return the end of the conversion spec.
+ * Return NULL on error.
+ */
+
+static const char *
+Convert(ScanfState *state, const char *fmt)
+{
+    const char *cPtr;
+    int ch;
+    char *cArg = NULL;
+
+    state->converted = PR_FALSE;
+    cPtr = fmt;
+    if (*cPtr != 'c' && *cPtr != 'n' && *cPtr != '[') {
+        do {
+            ch = GET(state);
+        } while (isspace(ch));
+        UNGET(state, ch);
+    }
+    switch (*cPtr) {
+        case 'c':
+            if (state->assign) {
+                cArg = va_arg(state->ap, char *);
+            }
+            if (state->width == 0) {
+                state->width = 1;
+            }
+            for (; state->width > 0; state->width--) {
+                ch = GET(state);
+                if (ch == EOF) {
+                    return NULL;
+                } else if (state->assign) {
+                    *cArg++ = ch;
+                }
+            }
+            if (state->assign) {
+                state->converted = PR_TRUE;
+            }
+            break;
+        case 'p':
+        case 'd': case 'i': case 'o':
+        case 'u': case 'x': case 'X':
+            if (GetInt(state, *cPtr) == PR_FAILURE) {
+                return NULL;
+            }
+            break;
+        case 'e': case 'E': case 'f':
+        case 'g': case 'G':
+            if (GetFloat(state) == PR_FAILURE) {
+                return NULL;
+            }
+            break;
+        case 'n':
+            /* do not consume any input */
+            if (state->assign) {
+                switch (state->sizeSpec) {
+                    case _PR_size_none:
+                        *va_arg(state->ap, PRIntn *) = state->nChar;
+                        break;
+                    case _PR_size_h:
+                        *va_arg(state->ap, PRInt16 *) = state->nChar;
+                        break;
+                    case _PR_size_l:
+                        *va_arg(state->ap, PRInt32 *) = state->nChar;
+                        break;
+                    case _PR_size_ll:
+                        LL_I2L(*va_arg(state->ap, PRInt64 *), state->nChar);
+                        break;
+                    default:
+                        PR_ASSERT(0);
+                }
+            }
+            break;
+        case 's':
+            if (state->width == 0) {
+                state->width = INT_MAX;
+            }
+            if (state->assign) {
+                cArg = va_arg(state->ap, char *);
+            }
+            for (; state->width > 0; state->width--) {
+                ch = GET(state);
+                if ((ch == EOF) || isspace(ch)) {
+                    UNGET(state, ch);
+                    break;
+                }
+                if (state->assign) {
+                    *cArg++ = ch;
+                }
+            }
+            if (state->assign) {
+                *cArg = '\0';
+                state->converted = PR_TRUE;
+            }
+            break;
+        case '%':
+            ch = GET(state);
+            if (ch != '%') {
+                UNGET(state, ch);
+                return NULL;
+            }
+            break;
+        case '[':
+            {
+                PRBool complement = PR_FALSE;
+                const char *closeBracket;
+                size_t n;
+
+                if (*++cPtr == '^') {
+                    complement = PR_TRUE;
+                    cPtr++;
+                }
+                closeBracket = strchr(*cPtr == ']' ? cPtr + 1 : cPtr, ']');
+                if (closeBracket == NULL) {
+                    return NULL;
+                }
+                n = closeBracket - cPtr;
+                if (state->width == 0) {
+                    state->width = INT_MAX;
+                }
+                if (state->assign) {
+                    cArg = va_arg(state->ap, char *);
+                }
+                for (; state->width > 0; state->width--) {
+                    ch = GET(state);
+                    if ((ch == EOF) 
+                            || (!complement && !memchr(cPtr, ch, n))
+                            || (complement && memchr(cPtr, ch, n))) {
+                        UNGET(state, ch);
+                        break;
+                    }
+                    if (state->assign) {
+                        *cArg++ = ch;
+                    }
+                }
+                if (state->assign) {
+                    *cArg = '\0';
+                    state->converted = PR_TRUE;
+                }
+                cPtr = closeBracket;
+            }
+            break;
+        default:
+            return NULL;
+    }
+    return cPtr;
+}
+
+static PRInt32
+DoScanf(ScanfState *state, const char *fmt)
+{
+    PRInt32 nConverted = 0;
+    const char *cPtr;
+    int ch;
+
+    state->nChar = 0;
+    cPtr = fmt;
+    while (1) {
+        if (isspace(*cPtr)) {
+            /* white space: skip */
+            do {
+                cPtr++;
+            } while (isspace(*cPtr));
+            do {
+                ch = GET(state);
+            } while (isspace(ch));
+            UNGET(state, ch);
+        } else if (*cPtr == '%') {
+            /* format spec: convert */
+            cPtr++;
+            state->assign = PR_TRUE;
+            if (*cPtr == '*') {
+                cPtr++;
+                state->assign = PR_FALSE;
+            }
+            for (state->width = 0; isdigit(*cPtr); cPtr++) {
+                state->width = state->width * 10 + *cPtr - '0';
+            }
+            state->sizeSpec = _PR_size_none;
+            if (*cPtr == 'h') {
+                cPtr++;
+                state->sizeSpec = _PR_size_h;
+            } else if (*cPtr == 'l') {
+                cPtr++;
+                if (*cPtr == 'l') {
+                    cPtr++;
+                    state->sizeSpec = _PR_size_ll;
+                } else {
+                    state->sizeSpec = _PR_size_l;
+                }
+            } else if (*cPtr == 'L') {
+                cPtr++;
+                state->sizeSpec = _PR_size_L;
+            }
+            cPtr = Convert(state, cPtr);
+            if (cPtr == NULL) {
+                return (nConverted > 0 ? nConverted : EOF);
+            }
+            if (state->converted) {
+                nConverted++;
+            }
+            cPtr++;
+        } else {
+            /* others: must match */
+            if (*cPtr == '\0') {
+                return nConverted;
+            }
+            ch = GET(state);
+            if (ch != *cPtr) {
+                UNGET(state, ch);
+                return nConverted;
+            }
+            cPtr++;
+        }
+    }
+}
+
+static int
+StringGetChar(void *stream)
+{
+    char *cPtr = *((char **) stream);
+
+    if (*cPtr == '\0') {
+        return EOF;
+    } else {
+        *((char **) stream) = cPtr + 1;
+        return (unsigned char) *cPtr;
+    }
+}
+
+static void
+StringUngetChar(void *stream, int ch)
+{
+    char *cPtr = *((char **) stream);
+
+    if (ch != EOF) {
+        *((char **) stream) = cPtr - 1;
+    }
+}
+
+PR_IMPLEMENT(PRInt32)
+PR_sscanf(const char *buf, const char *fmt, ...)
+{
+    PRInt32 rv;
+    ScanfState state;
+
+    state.get = &StringGetChar;
+    state.unget = &StringUngetChar;
+    state.stream = (void *) &buf;
+    va_start(state.ap, fmt);
+    rv = DoScanf(&state, fmt);
+    va_end(state.ap);
+    return rv;
+}
diff --git a/mozilla/nsprpub/pr/src/io/prsocket.c b/mozilla/nsprpub/pr/src/io/prsocket.c
new file mode 100644
index 0000000..8b4ef26
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prsocket.c
@@ -0,0 +1,1834 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+
+/************************************************************************/
+
+/* These two functions are only used in assertions. */
+#if defined(DEBUG)
+
+PRBool IsValidNetAddr(const PRNetAddr *addr)
+{
+    if ((addr != NULL)
+#if defined(XP_UNIX) || defined(XP_OS2)
+	    && (addr->raw.family != PR_AF_LOCAL)
+#endif
+	    && (addr->raw.family != PR_AF_INET6)
+	    && (addr->raw.family != PR_AF_INET)) {
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
+{
+    /*
+     * The definition of the length of a Unix domain socket address
+     * is not uniform, so we don't check it.
+     */
+    if ((addr != NULL)
+#if defined(XP_UNIX) || defined(XP_OS2)
+            && (addr->raw.family != AF_UNIX)
+#endif
+            && (PR_NETADDR_SIZE(addr) != addr_len)) {
+#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
+        /*
+         * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
+         * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
+         * field and is 28 bytes.  It is possible for socket functions
+         * to return an addr_len greater than sizeof(struct sockaddr_in6).
+         * We need to allow that.  (Bugzilla bug #77264)
+         */
+        if ((PR_AF_INET6 == addr->raw.family)
+                && (sizeof(addr->ipv6) == addr_len)) {
+            return PR_TRUE;
+        }
+#endif
+        /*
+         * The accept(), getsockname(), etc. calls on some platforms
+         * do not set the actual socket address length on return.
+         * In this case, we verifiy addr_len is still the value we
+         * passed in (i.e., sizeof(PRNetAddr)).
+         */
+#if defined(QNX)
+        if (sizeof(PRNetAddr) == addr_len) {
+            return PR_TRUE;
+        }
+#endif
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+#endif /* DEBUG */
+
+static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
+PRInt32 iov_size, PRIntervalTime timeout)
+{
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	int w = 0;
+	const PRIOVec *tmp_iov;
+#define LOCAL_MAXIOV    8
+	PRIOVec local_iov[LOCAL_MAXIOV];
+	PRIOVec *iov_copy = NULL;
+	int tmp_out;
+	int index, iov_cnt;
+	int count=0, sz = 0;    /* 'count' is the return value. */
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+    /*
+     * Assume the first writev will succeed.  Copy iov's only on
+     * failure.
+     */
+    tmp_iov = iov;
+    for (index = 0; index < iov_size; index++)
+        sz += iov[index].iov_len;
+
+	iov_cnt = iov_size;
+
+	while (sz > 0) {
+
+		w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
+		if (w < 0) {
+			count = -1;
+			break;
+		}
+		count += w;
+		if (fd->secret->nonblocking) {
+			break;
+		}
+		sz -= w;
+
+		if (sz > 0) {
+			/* find the next unwritten vector */
+			for ( index = 0, tmp_out = count;
+				tmp_out >= iov[index].iov_len;
+				tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */
+
+			if (tmp_iov == iov) {
+				/*
+				 * The first writev failed so we
+				 * must copy iov's around.
+				 * Avoid calloc/free if there
+				 * are few enough iov's.
+				 */
+				if (iov_size - index <= LOCAL_MAXIOV)
+					iov_copy = local_iov;
+				else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) *
+					sizeof *iov_copy)) == NULL) {
+					PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+					return -1;
+				}
+				tmp_iov = iov_copy;
+			}
+
+			PR_ASSERT(tmp_iov == iov_copy);
+
+			/* fill in the first partial read */
+			iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
+			iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
+			index++;
+
+			/* copy the remaining vectors */
+			for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
+				iov_copy[iov_cnt].iov_base = iov[index].iov_base;
+				iov_copy[iov_cnt].iov_len = iov[index].iov_len;
+			}
+		}
+	}
+
+	if (iov_copy != local_iov)
+		PR_DELETE(iov_copy);
+	return count;
+}
+
+/************************************************************************/
+
+PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PROsfd osfd)
+{
+PRFileDesc *fd;
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+	fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	if (fd != NULL) {
+		_PR_MD_MAKE_NONBLOCK(fd);
+		_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+#ifdef _PR_NEED_SECRET_AF
+		/* this means we can only import IPv4 sockets here.
+		 * but this is what the function in ptio.c does.
+		 * We need a way to import IPv6 sockets, too.
+		 */
+		fd->secret->af = AF_INET;
+#endif
+	} else
+		_PR_MD_CLOSE_SOCKET(osfd);
+	return(fd);
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PROsfd osfd)
+{
+PRFileDesc *fd;
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+	fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
+	if (fd != NULL) {
+		_PR_MD_MAKE_NONBLOCK(fd);
+		_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+	} else
+		_PR_MD_CLOSE_SOCKET(osfd);
+	return(fd);
+}
+
+
+static const PRIOMethods* PR_GetSocketPollFdMethods(void);
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd)
+{
+    PRFileDesc *fd;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    fd = _PR_Getfd();
+
+    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    else
+    {
+        fd->secret->md.osfd = osfd;
+        fd->secret->inheritable = _PR_TRI_FALSE;
+    	fd->secret->state = _PR_FILEDESC_OPEN;
+        fd->methods = PR_GetSocketPollFdMethods();
+    }
+
+    return fd;
+}  /* PR_CreateSocketPollFD */
+
+PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
+{
+    if (NULL == fd)
+    {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+    fd->secret->state = _PR_FILEDESC_CLOSED;
+    _PR_Putfd(fd);
+    return PR_SUCCESS;
+}  /* PR_DestroySocketPollFd */
+
+static PRStatus PR_CALLBACK SocketConnect(
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRInt32 rv;    /* Return value of _PR_MD_CONNECT */
+    const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+	PRNetAddr addrCopy;
+#endif
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return PR_FAILURE;
+	}
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+	}
+#endif
+
+	rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
+	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
+	if (rv == 0)
+		return PR_SUCCESS;
+	else
+		return PR_FAILURE;
+}
+
+static PRStatus PR_CALLBACK SocketConnectContinue(
+    PRFileDesc *fd, PRInt16 out_flags)
+{
+    PROsfd osfd;
+    int err;
+
+    if (out_flags & PR_POLL_NVAL) {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+    if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
+        PR_ASSERT(out_flags == 0);
+        PR_SetError(PR_IN_PROGRESS_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    osfd = fd->secret->md.osfd;
+
+#if defined(XP_UNIX)
+
+    err = _MD_unix_get_nonblocking_connect_error(osfd);
+    if (err != 0) {
+        _PR_MD_MAP_CONNECT_ERROR(err);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+
+#elif defined(WIN32) || defined(WIN16)
+
+#if defined(WIN32)
+    /*
+     * The sleep circumvents a bug in Win32 WinSock.
+     * See Microsoft Knowledge Base article ID: Q165989.
+     */
+    Sleep(0);
+#endif /* WIN32 */
+
+    if (out_flags & PR_POLL_EXCEPT) {
+        int len = sizeof(err);
+        if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
+                == SOCKET_ERROR) {
+            _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
+            return PR_FAILURE;
+        }
+        if (err != 0) {
+            _PR_MD_MAP_CONNECT_ERROR(err);
+        } else {
+            PR_SetError(PR_UNKNOWN_ERROR, 0);
+        }
+        return PR_FAILURE;
+    }
+
+    PR_ASSERT(out_flags & PR_POLL_WRITE);
+    return PR_SUCCESS;
+
+#elif defined(XP_OS2)
+
+    err = _MD_os2_get_nonblocking_connect_error(osfd);
+    if (err != 0) {
+        _PR_MD_MAP_CONNECT_ERROR(err);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+
+#elif defined(XP_BEOS)
+
+#ifdef BONE_VERSION  /* bug 122364 */
+    /* temporary workaround until getsockopt(SO_ERROR) works in BONE */
+    if (out_flags & PR_POLL_EXCEPT) {
+        PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
+        return PR_FAILURE;
+    }
+    PR_ASSERT(out_flags & PR_POLL_WRITE);
+    return PR_SUCCESS;
+#else
+    err = _MD_beos_get_nonblocking_connect_error(fd);
+    if( err != 0 ) {
+        _PR_MD_MAP_CONNECT_ERROR(err);
+        return PR_FAILURE;
+    }
+    else
+        return PR_SUCCESS;
+#endif /* BONE_VERSION */
+
+#else
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+#endif
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
+{
+    /* Find the NSPR layer and invoke its connectcontinue method */
+    PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+
+    if (NULL == bottom) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    return SocketConnectContinue(bottom, pd->out_flags);
+}
+
+static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
+PRIntervalTime timeout)
+{
+	PROsfd osfd;
+	PRFileDesc *fd2;
+	PRUint32 al;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+#ifdef WINNT
+	PRNetAddr addrCopy;
+#endif
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return 0;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return 0;
+	}
+
+#ifdef WINNT
+	if (addr == NULL) {
+		addr = &addrCopy;
+	}
+#endif
+	al = sizeof(PRNetAddr);
+	osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
+	if (osfd == -1)
+		return 0;
+
+	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	if (!fd2) {
+		_PR_MD_CLOSE_SOCKET(osfd);
+		return NULL;
+	}
+
+	fd2->secret->nonblocking = fd->secret->nonblocking;
+	fd2->secret->inheritable = fd->secret->inheritable;
+#ifdef WINNT
+	if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
+		/*
+		 * The new socket has been associated with an I/O
+		 * completion port.  There is no going back.
+		 */
+		fd2->secret->md.io_model_committed = PR_TRUE;
+	}
+	PR_ASSERT(al == PR_NETADDR_SIZE(addr));
+	fd2->secret->md.accepted_socket = PR_TRUE;
+	memcpy(&fd2->secret->md.peer_addr, addr, al);
+#endif
+
+	/*
+	 * On some platforms, the new socket created by accept()
+	 * inherits the nonblocking (or overlapped io) attribute
+	 * of the listening socket.  As an optimization, these
+	 * platforms can skip the following _PR_MD_MAKE_NONBLOCK
+	 * call.
+	 */
+#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
+	_PR_MD_MAKE_NONBLOCK(fd2);
+#endif
+
+#ifdef _PR_INET6
+	if (addr && (AF_INET6 == addr->raw.family))
+        addr->raw.family = PR_AF_INET6;
+#endif
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+	PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
+
+	return fd2;
+}
+
+#ifdef WINNT
+PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
+PRIntervalTime timeout)
+{
+	PROsfd osfd;
+	PRFileDesc *fd2;
+	PRIntn al;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRNetAddr addrCopy;
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return 0;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return 0;
+	}
+
+		if (addr == NULL) {
+			addr = &addrCopy;
+		}
+		al = PR_NETADDR_SIZE(addr);
+		osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
+		if (osfd == -1) {
+			return 0;
+		}
+
+	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	if (!fd2) {
+		_PR_MD_CLOSE_SOCKET(osfd);
+	} else {
+		fd2->secret->nonblocking = fd->secret->nonblocking;
+		fd2->secret->md.io_model_committed = PR_TRUE;
+	        PR_ASSERT(al == PR_NETADDR_SIZE(addr));
+        	fd2->secret->md.accepted_socket = PR_TRUE;
+        	memcpy(&fd2->secret->md.peer_addr, addr, al);
+#ifdef _PR_INET6
+		if (AF_INET6 == addr->raw.family)
+        	addr->raw.family = PR_AF_INET6;
+#endif
+#ifdef _PR_NEED_SECRET_AF
+		fd2->secret->af = fd->secret->af;
+#endif
+	}
+	return fd2;
+}
+#endif /* WINNT */
+
+
+static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
+{
+	PRInt32 result;
+    const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+	PRNetAddr addrCopy;
+#endif
+
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+
+#ifdef XP_UNIX
+	if (addr->raw.family == AF_UNIX) {
+		/* Disallow relative pathnames */
+		if (addr->local.path[0] != '/') {
+			PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+			return PR_FAILURE;
+		}
+	}
+#endif /* XP_UNIX */
+
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+	}
+#endif
+	result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
+{
+	PRInt32 result;
+
+	result = _PR_MD_LISTEN(fd, backlog);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
+{
+	PRInt32 result;
+
+	result = _PR_MD_SHUTDOWN(fd, how);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+	return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if ((flags != 0) && (flags != PR_MSG_PEEK)) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	PR_LOG(_pr_io_lm, PR_LOG_MAX,
+		("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d",
+		fd, fd->secret->md.osfd, buf, amount, flags));
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if (fd->secret->peekBytes != 0) {
+		rv = (amount < fd->secret->peekBytes) ?
+			amount : fd->secret->peekBytes;
+		memcpy(buf, fd->secret->peekBuffer, rv);
+		if (flags == 0) {
+			/* consume the bytes in the peek buffer */
+			fd->secret->peekBytes -= rv;
+			if (fd->secret->peekBytes != 0) {
+				memmove(fd->secret->peekBuffer,
+					fd->secret->peekBuffer + rv,
+					fd->secret->peekBytes);
+			}
+		}
+		return rv;
+	}
+
+	/* allocate peek buffer, if necessary */
+	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
+		PR_ASSERT(0 == fd->secret->peekBytes);
+		/* impose a max size on the peek buffer */
+		if (amount > _PR_PEEK_BUFFER_MAX) {
+			amount = _PR_PEEK_BUFFER_MAX;
+		}
+		if (fd->secret->peekBufSize < amount) {
+			if (fd->secret->peekBuffer) {
+				PR_Free(fd->secret->peekBuffer);
+			}
+			fd->secret->peekBufSize = amount;
+			fd->secret->peekBuffer = PR_Malloc(amount);
+			if (NULL == fd->secret->peekBuffer) {
+				fd->secret->peekBufSize = 0;
+				PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+				return -1;
+			}
+		}
+	}
+#endif
+
+	rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
+	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
+		rv, PR_GetError(), PR_GetOSError()));
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
+		if (rv > 0) {
+			memcpy(fd->secret->peekBuffer, buf, rv);
+			fd->secret->peekBytes = rv;
+		}
+	}
+#endif
+
+	return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+	return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}
+
+static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
+PRIntn flags, PRIntervalTime timeout)
+{
+	PRInt32 temp, count;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	count = 0;
+	while (amount > 0) {
+		PR_LOG(_pr_io_lm, PR_LOG_MAX,
+		    ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d",
+		    fd, fd->secret->md.osfd, buf, amount));
+		temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
+		if (temp < 0) {
+					count = -1;
+					break;
+				}
+
+		count += temp;
+		if (fd->secret->nonblocking) {
+			break;
+		}
+		buf = (const void*) ((const char*)buf + temp);
+
+		amount -= temp;
+	}
+	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
+	return count;
+}
+
+static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+	return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}
+
+static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd)
+{
+	if (!fd || !fd->secret
+			|| (fd->secret->state != _PR_FILEDESC_OPEN
+			&& fd->secret->state != _PR_FILEDESC_CLOSED)) {
+		PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+		return PR_FAILURE;
+	}
+
+	if (fd->secret->state == _PR_FILEDESC_OPEN) {
+		if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
+			return PR_FAILURE;
+		}
+		fd->secret->state = _PR_FILEDESC_CLOSED;
+	}
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if (fd->secret->peekBuffer) {
+		PR_ASSERT(fd->secret->peekBufSize > 0);
+		PR_DELETE(fd->secret->peekBuffer);
+		fd->secret->peekBufSize = 0;
+		fd->secret->peekBytes = 0;
+	}
+#endif
+
+	PR_FreeFileDesc(fd);
+	return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
+{
+	PRInt32 rv;
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if (fd->secret->peekBytes != 0) {
+		return fd->secret->peekBytes;
+	}
+#endif
+	rv =  _PR_MD_SOCKETAVAILABLE(fd);
+	return rv;		
+}
+
+static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
+{
+    PRInt64 rv;
+#ifdef _PR_HAVE_PEEK_BUFFER
+    if (fd->secret->peekBytes != 0) {
+        LL_I2L(rv, fd->secret->peekBytes);
+        return rv;
+    }
+#endif
+    LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
+	return rv;		
+}
+
+static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
+{
+	return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketSendTo(
+    PRFileDesc *fd, const void *buf, PRInt32 amount,
+    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRInt32 temp, count;
+    const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+	PRNetAddr addrCopy;
+#endif
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+	}
+#endif
+
+	count = 0;
+	while (amount > 0) {
+		temp = _PR_MD_SENDTO(fd, buf, amount, flags,
+		    addrp, PR_NETADDR_SIZE(addr), timeout);
+		if (temp < 0) {
+					count = -1;
+					break;
+				}
+		count += temp;
+		if (fd->secret->nonblocking) {
+			break;
+		}
+		buf = (const void*) ((const char*)buf + temp);
+		amount -= temp;
+	}
+	return count;
+}
+
+static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRUint32 al;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	al = sizeof(PRNetAddr);
+	rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
+#ifdef _PR_INET6
+	if (addr && (AF_INET6 == addr->raw.family))
+        addr->raw.family = PR_AF_INET6;
+#endif
+	return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	/* The socket must be in blocking mode. */
+	if (sd->secret->nonblocking) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+	*nd = NULL;
+
+#if defined(WINNT)
+	{
+	PROsfd newSock;
+	PRNetAddr *raddrCopy;
+
+	if (raddr == NULL) {
+		raddr = &raddrCopy;
+	}
+	rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
+	if (rv < 0) {
+		rv = -1;
+	} else {
+		/* Successfully accepted and read; create the new PRFileDesc */
+		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+		if (*nd == 0) {
+			_PR_MD_CLOSE_SOCKET(newSock);
+			/* PR_AllocFileDesc() has invoked PR_SetError(). */
+			rv = -1;
+		} else {
+			(*nd)->secret->md.io_model_committed = PR_TRUE;
+			(*nd)->secret->md.accepted_socket = PR_TRUE;
+			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+				PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+			if (AF_INET6 == *raddr->raw.family)
+        		*raddr->raw.family = PR_AF_INET6;
+#endif
+		}
+	}
+	}
+#else
+	rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
+#endif
+	return rv;
+}
+
+#ifdef WINNT
+PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PROsfd newSock;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRNetAddr *raddrCopy;
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	*nd = NULL;
+
+	if (raddr == NULL) {
+		raddr = &raddrCopy;
+	}
+	rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, 
+	    timeout, PR_TRUE, NULL, NULL);
+	if (rv < 0) {
+		rv = -1;
+	} else {
+		/* Successfully accepted and read; create the new PRFileDesc */
+		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+		if (*nd == 0) {
+			_PR_MD_CLOSE_SOCKET(newSock);
+			/* PR_AllocFileDesc() has invoked PR_SetError(). */
+			rv = -1;
+		} else {
+			(*nd)->secret->md.io_model_committed = PR_TRUE;
+			(*nd)->secret->md.accepted_socket = PR_TRUE;
+			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+				PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+			if (AF_INET6 == *raddr->raw.family)
+        		*raddr->raw.family = PR_AF_INET6;
+#endif
+#ifdef _PR_NEED_SECRET_AF
+			(*nd)->secret->af = sd->secret->af;
+#endif
+		}
+	}
+	return rv;
+}
+
+PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
+PRFileDesc *sd, PRFileDesc **nd, 
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout,
+_PR_AcceptTimeoutCallback callback,
+void *callbackArg)
+{
+	PRInt32 rv;
+	PROsfd newSock;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRNetAddr *raddrCopy;
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	*nd = NULL;
+
+	if (raddr == NULL) {
+		raddr = &raddrCopy;
+	}
+	rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
+	    timeout, PR_TRUE, callback, callbackArg);
+	if (rv < 0) {
+		rv = -1;
+	} else {
+		/* Successfully accepted and read; create the new PRFileDesc */
+		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+		if (*nd == 0) {
+			_PR_MD_CLOSE_SOCKET(newSock);
+			/* PR_AllocFileDesc() has invoked PR_SetError(). */
+			rv = -1;
+		} else {
+			(*nd)->secret->md.io_model_committed = PR_TRUE;
+			(*nd)->secret->md.accepted_socket = PR_TRUE;
+			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+				PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+			if (AF_INET6 == *raddr->raw.family)
+        		*raddr->raw.family = PR_AF_INET6;
+#endif
+#ifdef _PR_NEED_SECRET_AF
+			(*nd)->secret->af = sd->secret->af;
+#endif
+		}
+	}
+	return rv;
+}
+#endif /* WINNT */
+
+#ifdef WINNT
+PR_IMPLEMENT(void)
+PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
+{
+	_PR_MD_UPDATE_ACCEPT_CONTEXT(
+		socket->secret->md.osfd, acceptSocket->secret->md.osfd);
+}
+#endif /* WINNT */
+
+static PRInt32 PR_CALLBACK SocketSendFile(
+    PRFileDesc *sd, PRSendFileData *sfd,
+    PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	/* The socket must be in blocking mode. */
+	if (sd->secret->nonblocking) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+#if defined(WINNT)
+	rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
+	if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
+		/*
+		 * This should be kept the same as SocketClose, except
+		 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
+		 * not be called because the socket will be recycled.
+		 */
+		PR_FreeFileDesc(sd);
+	}
+#else
+	rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
+#endif	/* WINNT */
+
+	return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
+const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
+PRIntervalTime timeout)
+{
+	PRSendFileData sfd;
+
+	sfd.fd = fd;
+	sfd.file_offset = 0;
+	sfd.file_nbytes = 0;
+	sfd.header = headers;
+	sfd.hlen = hlen;
+	sfd.trailer = NULL;
+	sfd.tlen = 0;
+
+	return(SocketSendFile(sd, &sfd, flags, timeout));
+}
+
+static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
+{
+	PRInt32 result;
+	PRUint32 addrlen;
+
+	addrlen = sizeof(PRNetAddr);
+	result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+#ifdef _PR_INET6
+	if (AF_INET6 == addr->raw.family)
+        addr->raw.family = PR_AF_INET6;
+#endif
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+	PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
+{
+	PRInt32 result;
+	PRUint32 addrlen;
+
+	addrlen = sizeof(PRNetAddr);
+	result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+#ifdef _PR_INET6
+	if (AF_INET6 == addr->raw.family)
+        addr->raw.family = PR_AF_INET6;
+#endif
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+	PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
+	return PR_SUCCESS;
+}
+
+static PRInt16 PR_CALLBACK SocketPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+    *out_flags = 0;
+    return in_flags;
+}  /* SocketPoll */
+
+static PRIOMethods tcpMethods = {
+	PR_DESC_SOCKET_TCP,
+	SocketClose,
+	SocketRead,
+	SocketWrite,
+	SocketAvailable,
+	SocketAvailable64,
+	SocketSync,
+	(PRSeekFN)_PR_InvalidInt,
+	(PRSeek64FN)_PR_InvalidInt64,
+	(PRFileInfoFN)_PR_InvalidStatus,
+	(PRFileInfo64FN)_PR_InvalidStatus,
+	SocketWritev,
+	SocketConnect,
+	SocketAccept,
+	SocketBind,
+	SocketListen,
+	SocketShutdown,
+	SocketRecv,
+	SocketSend,
+	(PRRecvfromFN)_PR_InvalidInt,
+	(PRSendtoFN)_PR_InvalidInt,
+	SocketPoll,
+	SocketAcceptRead,
+	SocketTransmitFile,
+	SocketGetName,
+	SocketGetPeerName,
+	(PRReservedFN)_PR_InvalidInt,
+	(PRReservedFN)_PR_InvalidInt,
+	_PR_SocketGetSocketOption,
+	_PR_SocketSetSocketOption,
+    SocketSendFile, 
+    SocketConnectContinue,
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRIOMethods udpMethods = {
+	PR_DESC_SOCKET_UDP,
+	SocketClose,
+	SocketRead,
+	SocketWrite,
+	SocketAvailable,
+	SocketAvailable64,
+	SocketSync,
+	(PRSeekFN)_PR_InvalidInt,
+	(PRSeek64FN)_PR_InvalidInt64,
+	(PRFileInfoFN)_PR_InvalidStatus,
+	(PRFileInfo64FN)_PR_InvalidStatus,
+	SocketWritev,
+	SocketConnect,
+	(PRAcceptFN)_PR_InvalidDesc,
+	SocketBind,
+	SocketListen,
+	SocketShutdown,
+	SocketRecv,
+	SocketSend,
+	SocketRecvFrom,
+	SocketSendTo,
+	SocketPoll,
+	(PRAcceptreadFN)_PR_InvalidInt,
+	(PRTransmitfileFN)_PR_InvalidInt,
+	SocketGetName,
+	SocketGetPeerName,
+	(PRReservedFN)_PR_InvalidInt,
+	(PRReservedFN)_PR_InvalidInt,
+	_PR_SocketGetSocketOption,
+	_PR_SocketSetSocketOption,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+
+static PRIOMethods socketpollfdMethods = {
+    (PRDescType) 0,
+    (PRCloseFN)_PR_InvalidStatus,
+    (PRReadFN)_PR_InvalidInt,
+    (PRWriteFN)_PR_InvalidInt,
+    (PRAvailableFN)_PR_InvalidInt,
+    (PRAvailable64FN)_PR_InvalidInt64,
+    (PRFsyncFN)_PR_InvalidStatus,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+	SocketPoll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods()
+{
+	return &tcpMethods;
+}
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods()
+{
+	return &udpMethods;
+}
+
+static const PRIOMethods* PR_GetSocketPollFdMethods()
+{
+    return &socketpollfdMethods;
+}  /* PR_GetSocketPollFdMethods */
+
+#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
+PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
+
+#if defined(_PR_INET6_PROBE)
+
+extern PRBool _pr_ipv6_is_present(void);
+
+PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
+{
+	PROsfd osfd;
+
+	osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
+	if (osfd != -1) {
+		_PR_MD_CLOSE_SOCKET(osfd);
+		return PR_TRUE;
+	}
+	return PR_FALSE;
+}
+#endif	/* _PR_INET6_PROBE */
+
+#endif
+
+PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
+{
+	PROsfd osfd;
+	PRFileDesc *fd;
+	PRInt32 tmp_domain = domain;
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+	if (PR_AF_INET != domain
+			&& PR_AF_INET6 != domain
+#if defined(XP_UNIX) || defined(XP_OS2)
+			&& PR_AF_LOCAL != domain
+#endif
+			) {
+		PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return NULL;
+	}
+
+#if defined(_PR_INET6_PROBE)
+	if (PR_AF_INET6 == domain)
+		domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
+#elif defined(_PR_INET6)
+	if (PR_AF_INET6 == domain)
+		domain = AF_INET6;
+#else
+	if (PR_AF_INET6 == domain)
+		domain = AF_INET;
+#endif	/* _PR_INET6 */
+	osfd = _PR_MD_SOCKET(domain, type, proto);
+	if (osfd == -1) {
+		return 0;
+	}
+	if (type == SOCK_STREAM)
+		fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	else
+		fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
+	/*
+	 * Make the sockets non-blocking
+	 */
+	if (fd != NULL) {
+		_PR_MD_MAKE_NONBLOCK(fd);
+		_PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
+#ifdef _PR_NEED_SECRET_AF
+		fd->secret->af = domain;
+#endif
+#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
+		/*
+		 * For platforms with no support for IPv6 
+		 * create layered socket for IPv4-mapped IPv6 addresses
+		 */
+		if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
+			if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
+				PR_Close(fd);
+				fd = NULL;
+			}
+		}
+#endif
+	} else
+		_PR_MD_CLOSE_SOCKET(osfd);
+
+	return fd;
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
+{
+	PRInt32 domain = AF_INET;
+
+	return PR_Socket(domain, SOCK_STREAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
+{
+	PRInt32 domain = AF_INET;
+
+	return PR_Socket(domain, SOCK_DGRAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
+{
+	return PR_Socket(af, SOCK_STREAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
+{
+	return PR_Socket(af, SOCK_DGRAM, 0);
+}
+
+PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
+{
+#ifdef XP_UNIX
+	PRInt32 rv, osfd[2];
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+
+	rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
+	if (rv == -1) {
+		return PR_FAILURE;
+	}
+
+	f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
+	if (!f[0]) {
+		_PR_MD_CLOSE_SOCKET(osfd[0]);
+		_PR_MD_CLOSE_SOCKET(osfd[1]);
+		/* PR_AllocFileDesc() has invoked PR_SetError(). */
+		return PR_FAILURE;
+	}
+	f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
+	if (!f[1]) {
+		PR_Close(f[0]);
+		_PR_MD_CLOSE_SOCKET(osfd[1]);
+		/* PR_AllocFileDesc() has invoked PR_SetError(). */
+		return PR_FAILURE;
+	}
+	_PR_MD_MAKE_NONBLOCK(f[0]);
+	_PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
+	_PR_MD_MAKE_NONBLOCK(f[1]);
+	_PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
+	return PR_SUCCESS;
+#elif defined(WINNT)
+    /*
+     * A socket pair is often used for interprocess communication,
+     * so we need to make sure neither socket is associated with
+     * the I/O completion port; otherwise it can't be used by a
+     * child process.
+     *
+     * The default implementation below cannot be used for NT
+     * because PR_Accept would have associated the I/O completion
+     * port with the listening and accepted sockets.
+     */
+    SOCKET listenSock;
+    SOCKET osfd[2];
+    struct sockaddr_in selfAddr, peerAddr;
+    int addrLen;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    osfd[0] = osfd[1] = INVALID_SOCKET;
+    listenSock = socket(AF_INET, SOCK_STREAM, 0);
+    if (listenSock == INVALID_SOCKET) {
+        goto failed;
+    }
+    selfAddr.sin_family = AF_INET;
+    selfAddr.sin_port = 0;
+    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
+    addrLen = sizeof(selfAddr);
+    if (bind(listenSock, (struct sockaddr *) &selfAddr,
+            addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
+            &addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    if (listen(listenSock, 5) == SOCKET_ERROR) {
+        goto failed;
+    }
+    osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
+    if (osfd[0] == INVALID_SOCKET) {
+        goto failed;
+    }
+    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    /*
+     * Only a thread is used to do the connect and accept.
+     * I am relying on the fact that connect returns
+     * successfully as soon as the connect request is put
+     * into the listen queue (but before accept is called).
+     * This is the behavior of the BSD socket code.  If
+     * connect does not return until accept is called, we
+     * will need to create another thread to call connect.
+     */
+    if (connect(osfd[0], (struct sockaddr *) &selfAddr,
+            addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    /*
+     * A malicious local process may connect to the listening
+     * socket, so we need to verify that the accepted connection
+     * is made from our own socket osfd[0].
+     */
+    if (getsockname(osfd[0], (struct sockaddr *) &selfAddr,
+            &addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen);
+    if (osfd[1] == INVALID_SOCKET) {
+        goto failed;
+    }
+    if (peerAddr.sin_port != selfAddr.sin_port) {
+        /* the connection we accepted is not from osfd[0] */
+        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+        goto failed;
+    }
+    closesocket(listenSock);
+
+    f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
+    if (!f[0]) {
+        closesocket(osfd[0]);
+        closesocket(osfd[1]);
+        /* PR_AllocFileDesc() has invoked PR_SetError(). */
+        return PR_FAILURE;
+    }
+    f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
+    if (!f[1]) {
+        PR_Close(f[0]);
+        closesocket(osfd[1]);
+        /* PR_AllocFileDesc() has invoked PR_SetError(). */
+        return PR_FAILURE;
+    }
+    _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
+    _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
+    return PR_SUCCESS;
+
+failed:
+    if (listenSock != INVALID_SOCKET) {
+        closesocket(listenSock);
+    }
+    if (osfd[0] != INVALID_SOCKET) {
+        closesocket(osfd[0]);
+    }
+    if (osfd[1] != INVALID_SOCKET) {
+        closesocket(osfd[1]);
+    }
+    return PR_FAILURE;
+#else /* not Unix or NT */
+    /*
+     * default implementation
+     */
+    PRFileDesc *listenSock;
+    PRNetAddr selfAddr, peerAddr;
+    PRUint16 port;
+
+    f[0] = f[1] = NULL;
+    listenSock = PR_NewTCPSocket();
+    if (listenSock == NULL) {
+        goto failed;
+    }
+    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
+    if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    port = ntohs(selfAddr.inet.port);
+    if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+        goto failed;
+    }
+    f[0] = PR_NewTCPSocket();
+    if (f[0] == NULL) {
+        goto failed;
+    }
+#ifdef _PR_CONNECT_DOES_NOT_BIND
+    /*
+     * If connect does not implicitly bind the socket (e.g., on
+     * BeOS), we have to bind the socket so that we can get its
+     * port with getsockname later.
+     */
+    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr);
+    if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+#endif
+    PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
+
+    /*
+     * Only a thread is used to do the connect and accept.
+     * I am relying on the fact that PR_Connect returns
+     * successfully as soon as the connect request is put
+     * into the listen queue (but before PR_Accept is called).
+     * This is the behavior of the BSD socket code.  If
+     * connect does not return until accept is called, we
+     * will need to create another thread to call connect.
+     */
+    if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
+            == PR_FAILURE) {
+        goto failed;
+    }
+    /*
+     * A malicious local process may connect to the listening
+     * socket, so we need to verify that the accepted connection
+     * is made from our own socket f[0].
+     */
+    if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
+    if (f[1] == NULL) {
+        goto failed;
+    }
+    if (peerAddr.inet.port != selfAddr.inet.port) {
+        /* the connection we accepted is not from f[0] */
+        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+        goto failed;
+    }
+    PR_Close(listenSock);
+    return PR_SUCCESS;
+
+failed:
+    if (listenSock) {
+        PR_Close(listenSock);
+    }
+    if (f[0]) {
+        PR_Close(f[0]);
+    }
+    if (f[1]) {
+        PR_Close(f[1]);
+    }
+    return PR_FAILURE;
+#endif
+}
+
+PR_IMPLEMENT(PROsfd)
+PR_FileDesc2NativeHandle(PRFileDesc *fd)
+{
+    if (fd) {
+        fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
+    }
+    if (!fd) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return -1;
+    }
+    return fd->secret->md.osfd;
+}
+
+PR_IMPLEMENT(void)
+PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PROsfd handle)
+{
+	if (fd)
+		fd->secret->md.osfd = handle;
+}
+
+/*
+** Select compatibility
+**
+*/
+
+PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
+{
+	memset(set, 0, sizeof(PR_fd_set));
+}
+
+PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
+{
+	PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
+
+	set->harray[set->hsize++] = fh;
+}
+
+PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
+{
+	PRUint32 index, index2;
+
+	for (index = 0; index<set->hsize; index++)
+		if (set->harray[index] == fh) {
+			for (index2=index; index2 < (set->hsize-1); index2++) {
+				set->harray[index2] = set->harray[index2+1];
+			}
+			set->hsize--;
+			break;
+		}
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
+{
+	PRUint32 index;
+	for (index = 0; index<set->hsize; index++)
+		if (set->harray[index] == fh) {
+			return 1;
+		}
+	return 0;
+}
+
+PR_IMPLEMENT(void) PR_FD_NSET(PROsfd fd, PR_fd_set *set)
+{
+	PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
+
+	set->narray[set->nsize++] = fd;
+}
+
+PR_IMPLEMENT(void) PR_FD_NCLR(PROsfd fd, PR_fd_set *set)
+{
+	PRUint32 index, index2;
+
+	for (index = 0; index<set->nsize; index++)
+		if (set->narray[index] == fd) {
+			for (index2=index; index2 < (set->nsize-1); index2++) {
+				set->narray[index2] = set->narray[index2+1];
+			}
+			set->nsize--;
+			break;
+		}
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PROsfd fd, PR_fd_set *set)
+{
+	PRUint32 index;
+	for (index = 0; index<set->nsize; index++)
+		if (set->narray[index] == fd) {
+			return 1;
+		}
+	return 0;
+}
+
+
+#if !defined(NEED_SELECT)
+#include "obsolete/probslet.h"
+
+#define PD_INCR 20
+
+static PRPollDesc *_pr_setfd(
+    PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
+{
+    PRUintn fsidx, pdidx;
+    PRPollDesc *poll = polldesc;
+
+    if (NULL == set) return poll;
+
+	/* First set the pr file handle osfds */
+	for (fsidx = 0; fsidx < set->hsize; fsidx++)
+	{
+	    for (pdidx = 0; 1; pdidx++)
+        {
+            if ((PRFileDesc*)-1 == poll[pdidx].fd)
+            {
+                /* our vector is full - extend and condition it */
+                poll = (PRPollDesc*)PR_Realloc(
+                    poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
+                if (NULL == poll) goto out_of_memory;
+                memset(
+                    poll + pdidx * sizeof(PRPollDesc),
+                    0, PD_INCR * sizeof(PRPollDesc));
+                poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
+            }
+            if ((NULL == poll[pdidx].fd)
+            || (poll[pdidx].fd == set->harray[fsidx]))
+            {
+                /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
+                /* either empty or prevously defined */
+                poll[pdidx].fd = set->harray[fsidx];  /* possibly redundant */
+                poll[pdidx].in_flags |= flags;  /* possibly redundant */
+                break;
+            }
+        }
+	}
+
+#if 0
+	/* Second set the native osfds */
+	for (fsidx = 0; fsidx < set->nsize; fsidx++)
+	{
+	    for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
+        {
+            if ((PRFileDesc*)-1 == poll[pdidx].fd)
+            {
+                /* our vector is full - extend and condition it */
+                poll = PR_Realloc(
+                    poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
+                if (NULL == poll) goto out_of_memory;
+                memset(
+                    poll + pdidx * sizeof(PRPollDesc),
+                    0, PD_INCR * sizeof(PRPollDesc));
+                poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
+            }
+            if ((NULL == poll[pdidx].fd)
+            || (poll[pdidx].fd == set->narray[fsidx]))
+            {
+                /* either empty or prevously defined */
+                poll[pdidx].fd = set->narray[fsidx];
+                PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
+                poll[pdidx].in_flags |= flags;
+                break;
+            }
+        }
+	}
+#endif /* 0 */
+
+	return poll;
+
+out_of_memory:
+    if (NULL != polldesc) PR_DELETE(polldesc);
+    return NULL;
+}  /* _pr_setfd */
+
+#endif /* !defined(NEED_SELECT) */
+
+PR_IMPLEMENT(PRInt32) PR_Select(
+    PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
+    PR_fd_set *pr_ex, PRIntervalTime timeout)
+{
+
+#if !defined(NEED_SELECT)
+    PRInt32 npds = 0; 
+    /*
+    ** Find out how many fds are represented in the three lists.
+    ** Then allocate a polling descriptor for the logical union
+    ** (there can't be any overlapping) and call PR_Poll().
+    */
+
+    PRPollDesc *copy, *poll;
+
+    static PRBool warning = PR_TRUE;
+    if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
+
+    /* try to get an initial guesss at how much space we need */
+    npds = 0;
+    if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0))
+        npds = pr_rd->hsize + pr_rd->nsize;
+    if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0))
+        npds = pr_wr->hsize + pr_wr->nsize;
+    if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0))
+        npds = pr_ex->hsize + pr_ex->nsize;
+
+    if (0 == npds)
+    {
+        PR_Sleep(timeout);
+        return 0;
+    }
+
+    copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
+    if (NULL == poll) goto out_of_memory;
+    poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
+
+    poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
+    if (NULL == poll) goto out_of_memory;
+    poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
+    if (NULL == poll) goto out_of_memory;
+    poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
+    if (NULL == poll) goto out_of_memory;
+    unused = 0;
+    while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
+    {
+        ++unused;
+    }
+
+    PR_ASSERT(unused > 0);
+    npds = PR_Poll(poll, unused, timeout);
+
+    if (npds > 0)
+    {
+        /* Copy the results back into the fd sets */
+        if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0;
+        if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0;
+        if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0;
+        for (copy = &poll[unused - 1]; copy >= poll; --copy)
+        {
+            if (copy->out_flags & PR_POLL_NVAL)
+            {
+                PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+                npds = -1;
+                break;
+            }
+            if (copy->out_flags & PR_POLL_READ)
+                if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd;
+            if (copy->out_flags & PR_POLL_WRITE)
+                if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd;
+            if (copy->out_flags & PR_POLL_EXCEPT)
+                if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd;
+        }
+    }
+    PR_DELETE(poll);
+
+    return npds;
+out_of_memory:
+    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    return -1;    
+
+#endif /* !defined(NEED_SELECT) */
+    
+}
diff --git a/mozilla/nsprpub/pr/src/io/prstdio.c b/mozilla/nsprpub/pr/src/io/prstdio.c
new file mode 100644
index 0000000..b8a091f
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/io/prstdio.c
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+
+/*
+** fprintf to a PRFileDesc
+*/
+PR_IMPLEMENT(PRUint32) PR_fprintf(PRFileDesc* fd, const char *fmt, ...)
+{
+    va_list ap;
+    PRUint32 rv;
+
+    va_start(ap, fmt);
+    rv = PR_vfprintf(fd, fmt, ap);
+    va_end(ap);
+    return rv;
+}
+
+PR_IMPLEMENT(PRUint32) PR_vfprintf(PRFileDesc* fd, const char *fmt, va_list ap)
+{
+    /* XXX this could be better */
+    PRUint32 rv, len;
+    char* msg = PR_vsmprintf(fmt, ap);
+    if (NULL == msg) {
+        return -1;
+    }
+    len = strlen(msg);
+#ifdef XP_OS2
+    /*
+     * OS/2 really needs a \r for every \n.
+     * In the future we should try to use scatter-gather instead of a
+     * succession of PR_Write.
+     */
+    if (isatty(PR_FileDesc2NativeHandle(fd))) {
+        PRUint32 last = 0, idx;
+        PRInt32 tmp;
+        rv = 0;
+        for (idx = 0; idx < len+1; idx++) {
+            if ((idx - last > 0) && (('\n' == msg[idx]) || (idx == len))) {
+                tmp = PR_Write(fd, msg + last, idx - last);
+                if (tmp >= 0) {
+                    rv += tmp;
+                }
+                last = idx;
+            }
+            /*
+             * if current character is \n, and
+             * previous character isn't \r, and
+             * next character isn't \r
+             */
+            if (('\n' == msg[idx]) &&
+                ((0 == idx) || ('\r' != msg[idx-1])) &&
+                ('\r' != msg[idx+1])) {
+                /* add extra \r */
+                tmp = PR_Write(fd, "\r", 1);
+                if (tmp >= 0) {
+                    rv += tmp;
+                }
+            }
+        }
+    } else {
+        rv = PR_Write(fd, msg, len);
+    }
+#else
+    rv = PR_Write(fd, msg, len);
+#endif
+    PR_DELETE(msg);
+    return rv;
+}
diff --git a/mozilla/nsprpub/pr/src/linking/prlink.c b/mozilla/nsprpub/pr/src/linking/prlink.c
new file mode 100644
index 0000000..873c5e8
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/linking/prlink.c
@@ -0,0 +1,1637 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Steve Streeter (Hewlett-Packard Company)
+ *
+ * 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 "primpl.h"
+
+#include <string.h>
+
+#ifdef XP_BEOS
+#include <image.h>
+#endif
+
+#if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
+#include <CodeFragments.h>
+#include <TextUtils.h>
+#include <Types.h>
+#include <Aliases.h>
+#include <CFURL.h>
+#include <CFBundle.h>
+#include <CFString.h>
+#include <CFDictionary.h>
+#include <CFData.h>
+#endif
+
+#ifdef XP_UNIX
+#ifdef USE_DLFCN
+#include <dlfcn.h>
+/* Define these on systems that don't have them. */
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#ifndef RTLD_LAZY
+#define RTLD_LAZY RTLD_NOW
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+#ifndef RTLD_LOCAL
+#define RTLD_LOCAL 0
+#endif
+#ifdef AIX
+#include <sys/ldr.h>
+#ifndef L_IGNOREUNLOAD /* AIX 4.3.3 does not have L_IGNOREUNLOAD. */
+#define L_IGNOREUNLOAD 0x10000000
+#endif
+#endif
+#ifdef OSF1
+#include <loader.h>
+#include <rld_interface.h>
+#endif
+#elif defined(USE_HPSHL)
+#include <dl.h>
+#elif defined(USE_MACH_DYLD)
+#include <mach-o/dyld.h>
+#endif
+#endif /* XP_UNIX */
+
+#define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY
+
+/*
+ * On these platforms, symbols have a leading '_'.
+ */
+#if defined(SUNOS4) || (defined(DARWIN) && defined(USE_MACH_DYLD)) \
+    || defined(NEXTSTEP) || defined(XP_OS2) \
+    || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__))
+#define NEED_LEADING_UNDERSCORE
+#endif
+
+#define PR_LD_PATHW 0x8000  /* for PR_LibSpec_PathnameU */
+
+/************************************************************************/
+
+struct PRLibrary {
+    char*                       name;  /* Our own copy of the name string */
+    PRLibrary*                  next;
+    int                         refCount;
+    const PRStaticLinkTable*    staticTable;
+
+#ifdef XP_PC
+#ifdef XP_OS2
+    HMODULE                     dlh;
+#else
+    HINSTANCE                   dlh;
+#endif
+#endif
+
+#if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
+    CFragConnectionID           connection;
+    CFBundleRef                 bundle;
+    Ptr                         main;
+    CFMutableDictionaryRef      wrappers;
+    const struct mach_header*   image;
+#endif
+
+#ifdef XP_UNIX
+#if defined(USE_HPSHL)
+    shl_t                       dlh;
+#elif defined(USE_MACH_DYLD)
+    NSModule                    dlh;
+#else
+    void*                       dlh;
+#endif 
+#endif 
+
+#ifdef XP_BEOS
+    void*                       dlh;
+    void*                       stub_dlh;
+#endif
+};
+
+static PRLibrary *pr_loadmap;
+static PRLibrary *pr_exe_loadmap;
+static PRMonitor *pr_linker_lock;
+static char* _pr_currentLibPath = NULL;
+
+static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags);
+
+/************************************************************************/
+
+#if !defined(USE_DLFCN) && !defined(HAVE_STRERROR)
+#define ERR_STR_BUF_LENGTH    20
+#endif
+
+static void DLLErrorInternal(PRIntn oserr)
+/*
+** This whole function, and most of the code in this file, are run
+** with a big hairy lock wrapped around it. Not the best of situations,
+** but will eventually come up with the right answer.
+*/
+{
+    const char *error = NULL;
+#ifdef USE_DLFCN
+    error = dlerror();  /* $$$ That'll be wrong some of the time - AOF */
+#elif defined(HAVE_STRERROR)
+    error = strerror(oserr);  /* this should be okay */
+#else
+    char errStrBuf[ERR_STR_BUF_LENGTH];
+    PR_snprintf(errStrBuf, sizeof(errStrBuf), "error %d", oserr);
+    error = errStrBuf;
+#endif
+    if (NULL != error)
+        PR_SetErrorText(strlen(error), error);
+}  /* DLLErrorInternal */
+
+void _PR_InitLinker(void)
+{
+    PRLibrary *lm = NULL;
+#if defined(XP_UNIX)
+    void *h;
+#endif
+
+    if (!pr_linker_lock) {
+        pr_linker_lock = PR_NewNamedMonitor("linker-lock");
+    }
+    PR_EnterMonitor(pr_linker_lock);
+
+#if defined(XP_PC)
+    lm = PR_NEWZAP(PRLibrary);
+    lm->name = strdup("Executable");
+#if defined(XP_OS2)
+    lm->dlh = NULLHANDLE;
+#else
+    /* A module handle for the executable. */
+    lm->dlh = GetModuleHandle(NULL);
+#endif /* ! XP_OS2 */
+
+    lm->refCount    = 1;
+    lm->staticTable = NULL;
+    pr_exe_loadmap  = lm;
+    pr_loadmap      = lm;
+
+#elif defined(XP_UNIX)
+#ifdef HAVE_DLL
+#ifdef USE_DLFCN
+    h = dlopen(0, RTLD_LAZY);
+    if (!h) {
+        char *error;
+        
+        DLLErrorInternal(_MD_ERRNO());
+        error = (char*)PR_MALLOC(PR_GetErrorTextLength());
+        (void) PR_GetErrorText(error);
+        fprintf(stderr, "failed to initialize shared libraries [%s]\n",
+            error);
+        PR_DELETE(error);
+        abort();/* XXX */
+    }
+#elif defined(USE_HPSHL)
+    h = NULL;
+    /* don't abort with this NULL */
+#elif defined(USE_MACH_DYLD)
+    h = NULL; /* XXXX  toshok */
+#else
+#error no dll strategy
+#endif /* USE_DLFCN */
+
+    lm = PR_NEWZAP(PRLibrary);
+    if (lm) {
+        lm->name = strdup("a.out");
+        lm->refCount = 1;
+        lm->dlh = h;
+        lm->staticTable = NULL;
+    }
+    pr_exe_loadmap = lm;
+    pr_loadmap = lm;
+#endif /* HAVE_DLL */
+#endif /* XP_UNIX */
+
+    if (lm) {
+        PR_LOG(_pr_linker_lm, PR_LOG_MIN,
+            ("Loaded library %s (init)", lm->name));
+    }
+
+    PR_ExitMonitor(pr_linker_lock);
+}
+
+/*
+ * _PR_ShutdownLinker does not unload the dlls loaded by the application
+ * via calls to PR_LoadLibrary.  Any dlls that still remain on the
+ * pr_loadmap list when NSPR shuts down are application programming errors.
+ * The only exception is pr_exe_loadmap, which was added to the list by
+ * NSPR and hence should be cleaned up by NSPR.
+ */
+void _PR_ShutdownLinker(void)
+{
+    /* FIXME: pr_exe_loadmap should be destroyed. */
+    
+    PR_DestroyMonitor(pr_linker_lock);
+    pr_linker_lock = NULL;
+
+    if (_pr_currentLibPath) {
+        free(_pr_currentLibPath);
+        _pr_currentLibPath = NULL;
+    }
+}
+
+/******************************************************************************/
+
+PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path)
+{
+    PRStatus rv = PR_SUCCESS;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    PR_EnterMonitor(pr_linker_lock);
+    if (_pr_currentLibPath) {
+        free(_pr_currentLibPath);
+    }
+    if (path) {
+        _pr_currentLibPath = strdup(path);
+        if (!_pr_currentLibPath) {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        rv = PR_FAILURE;
+        }
+    } else {
+        _pr_currentLibPath = 0;
+    }
+    PR_ExitMonitor(pr_linker_lock);
+    return rv;
+}
+
+/*
+** Return the library path for finding shared libraries.
+*/
+PR_IMPLEMENT(char *) 
+PR_GetLibraryPath(void)
+{
+    char *ev;
+    char *copy = NULL;  /* a copy of _pr_currentLibPath */
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    PR_EnterMonitor(pr_linker_lock);
+    if (_pr_currentLibPath != NULL) {
+        goto exit;
+    }
+
+    /* initialize pr_currentLibPath */
+
+#ifdef XP_PC
+    ev = getenv("LD_LIBRARY_PATH");
+    if (!ev) {
+    ev = ".;\\lib";
+    }
+    ev = strdup(ev);
+#endif
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+#if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS)
+    {
+    char *p=NULL;
+    int len;
+
+#ifdef XP_BEOS
+    ev = getenv("LIBRARY_PATH");
+    if (!ev) {
+        ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib";
+    }
+#else
+    ev = getenv("LD_LIBRARY_PATH");
+    if (!ev) {
+        ev = "/usr/lib:/lib";
+    }
+#endif
+    len = strlen(ev) + 1;        /* +1 for the null */
+
+    p = (char*) malloc(len);
+    if (p) {
+        strcpy(p, ev);
+    }   /* if (p)  */
+    ev = p;
+    PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev));
+
+    }
+#else
+    /* AFAIK there isn't a library path with the HP SHL interface --Rob */
+    ev = strdup("");
+#endif
+#endif
+
+    /*
+     * If ev is NULL, we have run out of memory
+     */
+    _pr_currentLibPath = ev;
+
+  exit:
+    if (_pr_currentLibPath) {
+        copy = strdup(_pr_currentLibPath);
+    }
+    PR_ExitMonitor(pr_linker_lock);
+    if (!copy) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    }
+    return copy;
+}
+
+/*
+** Build library name from path, lib and extensions
+*/
+PR_IMPLEMENT(char*) 
+PR_GetLibraryName(const char *path, const char *lib)
+{
+    char *fullname;
+
+#ifdef XP_PC
+    if (strstr(lib, PR_DLL_SUFFIX) == NULL)
+    {
+        if (path) {
+            fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX);
+        } else {
+            fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX);
+        }
+    } else {
+        if (path) {
+            fullname = PR_smprintf("%s\\%s", path, lib);
+        } else {
+            fullname = PR_smprintf("%s", lib);
+        }
+    }
+#endif /* XP_PC */
+#if defined(XP_UNIX) || defined(XP_BEOS)
+    if (strstr(lib, PR_DLL_SUFFIX) == NULL)
+    {
+        if (path) {
+            fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX);
+        } else {
+            fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX);
+        }
+    } else {
+        if (path) {
+            fullname = PR_smprintf("%s/%s", path, lib);
+        } else {
+            fullname = PR_smprintf("%s", lib);
+        }
+    }
+#endif /* XP_UNIX || XP_BEOS */
+    return fullname;
+}
+
+/*
+** Free the memory allocated, for the caller, by PR_GetLibraryName
+*/
+PR_IMPLEMENT(void) 
+PR_FreeLibraryName(char *mem)
+{
+    PR_smprintf_free(mem);
+}
+
+static PRLibrary* 
+pr_UnlockedFindLibrary(const char *name)
+{
+    PRLibrary* lm = pr_loadmap;
+    const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR);
+    np = np ? np + 1 : name;
+    while (lm) {
+    const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR);
+    cp = cp ? cp + 1 : lm->name;
+#ifdef WIN32
+        /* Windows DLL names are case insensitive... */
+    if (strcmpi(np, cp) == 0) 
+#elif defined(XP_OS2)
+    if (stricmp(np, cp) == 0)
+#else
+    if (strcmp(np, cp)  == 0) 
+#endif
+    {
+        /* found */
+        lm->refCount++;
+        PR_LOG(_pr_linker_lm, PR_LOG_MIN,
+           ("%s incr => %d (find lib)",
+            lm->name, lm->refCount));
+        return lm;
+    }
+    lm = lm->next;
+    }
+    return NULL;
+}
+
+PR_IMPLEMENT(PRLibrary*)
+PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags)
+{
+    if (flags == 0) {
+        flags = _PR_DEFAULT_LD_FLAGS;
+    }
+    switch (libSpec.type) {
+        case PR_LibSpec_Pathname:
+            return pr_LoadLibraryByPathname(libSpec.value.pathname, flags);
+#ifdef WIN32
+        case PR_LibSpec_PathnameU:
+            /*
+             * cast to |char *| and set PR_LD_PATHW flag so that
+             * it can be cast back to PRUnichar* in the callee.
+             */
+            return pr_LoadLibraryByPathname((const char*) 
+                                            libSpec.value.pathname_u, 
+                                            flags | PR_LD_PATHW);
+#endif
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            return NULL;
+    }
+}
+            
+PR_IMPLEMENT(PRLibrary*) 
+PR_LoadLibrary(const char *name)
+{
+    PRLibSpec libSpec;
+
+    libSpec.type = PR_LibSpec_Pathname;
+    libSpec.value.pathname = name;
+    return PR_LoadLibraryWithFlags(libSpec, 0);
+}
+
+#if defined(USE_MACH_DYLD)
+static NSModule
+pr_LoadMachDyldModule(const char *name)
+{
+    NSObjectFileImage ofi;
+    NSModule h = NULL;
+    if (NSCreateObjectFileImageFromFile(name, &ofi)
+            == NSObjectFileImageSuccess) {
+        h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE
+                         | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+        /*
+         * TODO: If NSLinkModule fails, use NSLinkEditError to retrieve
+         * error information.
+         */
+        if (NSDestroyObjectFileImage(ofi) == FALSE) {
+            if (h) {
+                (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE);
+                h = NULL;
+            }
+        }
+    }
+    return h;
+}
+#endif
+
+#if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
+
+/*
+** macLibraryLoadProc is a function definition for a Mac shared library
+** loading method. The "name" param is the same full or partial pathname
+** that was passed to pr_LoadLibraryByPathName. The function must fill
+** in the fields of "lm" which apply to its library type. Returns
+** PR_SUCCESS if successful.
+*/
+
+typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm);
+
+#ifdef __ppc__
+
+/*
+** CFM and its TVectors only exist on PowerPC.  Other OS X architectures
+** only use Mach-O as a native binary format.
+*/
+
+static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp)
+{
+    static uint32 glue[6] = { 0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420 };
+    uint32* newGlue = NULL;
+
+    if (tvp != NULL) {
+        CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII);
+        if (nameRef) {
+            CFMutableDataRef glueData = (CFMutableDataRef) CFDictionaryGetValue(dict, nameRef);
+            if (glueData == NULL) {
+                glueData = CFDataCreateMutable(NULL, sizeof(glue));
+                if (glueData != NULL) {
+                    newGlue = (uint32*) CFDataGetMutableBytePtr(glueData);
+                    memcpy(newGlue, glue, sizeof(glue));
+                    newGlue[0] |= ((UInt32)tvp >> 16);
+                    newGlue[1] |= ((UInt32)tvp & 0xFFFF);
+                    MakeDataExecutable(newGlue, sizeof(glue));
+                    CFDictionaryAddValue(dict, nameRef, glueData);
+                    CFRelease(glueData);
+
+                    PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name));
+                }
+            } else {
+                PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name));
+
+                newGlue = (uint32*) CFDataGetMutableBytePtr(glueData);
+            }
+            CFRelease(nameRef);
+        }
+    }
+    
+    return newGlue;
+}
+
+static PRStatus
+pr_LoadViaCFM(const char *name, PRLibrary *lm)
+{
+    OSErr err;
+    Str255 errName;
+    FSRef ref;
+    FSSpec fileSpec;
+    Boolean tempUnusedBool;
+
+    /*
+     * Make an FSSpec from the path name and call GetDiskFragment.
+     */
+
+    /* Use direct conversion of POSIX path to FSRef to FSSpec. */
+    err = FSPathMakeRef((const UInt8*)name, &ref, NULL);
+    if (err != noErr)
+        return PR_FAILURE;
+    err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL,
+                           &fileSpec, NULL);
+    if (err != noErr)
+        return PR_FAILURE;
+
+    /* Resolve an alias if this was one */
+    err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool,
+                           &tempUnusedBool);
+    if (err != noErr)
+        return PR_FAILURE;
+
+    /* Finally, try to load the library */
+    err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name,
+                          kLoadCFrag, &lm->connection, &lm->main, errName);
+
+    if (err == noErr && lm->connection) {
+        /*
+         * if we're a mach-o binary, need to wrap all CFM function
+         * pointers. need a hash-table of already seen function
+         * pointers, etc.
+         */
+        lm->wrappers = CFDictionaryCreateMutable(NULL, 16,
+                       &kCFTypeDictionaryKeyCallBacks,
+                       &kCFTypeDictionaryValueCallBacks);
+        if (lm->wrappers) {
+            lm->main = TV2FP(lm->wrappers, "main", lm->main);
+        } else
+            err = memFullErr;
+    }
+    return (err == noErr) ? PR_SUCCESS : PR_FAILURE;
+}
+#endif /* __ppc__ */
+
+/*
+** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle
+** directory. The caller is responsible for calling CFRelease() to
+** deallocate.
+*/
+
+static PRStatus
+pr_LoadCFBundle(const char *name, PRLibrary *lm)
+{
+    CFURLRef bundleURL;
+    CFBundleRef bundle = NULL;
+    char pathBuf[PATH_MAX];
+    const char *resolvedPath;
+    CFStringRef pathRef;
+
+    /* Takes care of relative paths and symlinks */
+    resolvedPath = realpath(name, pathBuf);
+    if (!resolvedPath)
+        return PR_FAILURE;
+        
+    pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8);
+    if (pathRef) {
+        bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef,
+                                                  kCFURLPOSIXPathStyle, true);
+        if (bundleURL) {
+            bundle = CFBundleCreate(NULL, bundleURL);
+            CFRelease(bundleURL);
+        }
+        CFRelease(pathRef);
+    }
+
+    lm->bundle = bundle;
+    return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE;
+}
+
+static PRStatus
+pr_LoadViaDyld(const char *name, PRLibrary *lm)
+{
+    lm->dlh = pr_LoadMachDyldModule(name);
+    if (lm->dlh == NULL) {
+        lm->image = NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR
+                               | NSADDIMAGE_OPTION_WITH_SEARCHING);
+        if (lm->image == NULL) {
+            NSLinkEditErrors linkEditError;
+            int errorNum;
+            const char *errorString;
+            const char *fileName;
+            NSLinkEditError(&linkEditError, &errorNum, &fileName, &errorString);
+            PR_LOG(_pr_linker_lm, PR_LOG_MIN, 
+                   ("LoadMachDyldModule error %d:%d for file %s:\n%s",
+                    linkEditError, errorNum, fileName, errorString));
+        }
+    }
+    return (lm->dlh != NULL || lm->image != NULL) ? PR_SUCCESS : PR_FAILURE;
+}
+
+#endif /* XP_MACOSX && USE_MACH_DYLD */
+
+/*
+** Dynamically load a library. Only load libraries once, so scan the load
+** map first.
+*/
+static PRLibrary*
+pr_LoadLibraryByPathname(const char *name, PRIntn flags)
+{
+    PRLibrary *lm;
+    PRLibrary* result = NULL;
+    PRInt32 oserr;
+#ifdef WIN32
+    char utf8name_stack[MAX_PATH];
+    char *utf8name_malloc = NULL;
+    char *utf8name = utf8name_stack;
+    PRUnichar wname_stack[MAX_PATH];
+    PRUnichar *wname_malloc = NULL;
+    PRUnichar *wname = wname_stack;
+    int len;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    /* See if library is already loaded */
+    PR_EnterMonitor(pr_linker_lock);
+
+#ifdef WIN32
+    if (flags & PR_LD_PATHW) {
+        /* cast back what's cast to |char *| for the argument passing. */
+        wname = (LPWSTR) name;
+    } else {
+        int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
+        if (wlen > MAX_PATH)
+            wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar));
+        if (wname == NULL ||
+            !MultiByteToWideChar(CP_ACP, 0,  name, -1, wname, wlen)) {
+            oserr = _MD_ERRNO();
+            goto unlock;
+        }
+    }
+    len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
+    if (len > MAX_PATH)
+        utf8name = utf8name_malloc = PR_Malloc(len);
+    if (utf8name == NULL ||
+        !WideCharToMultiByte(CP_UTF8, 0, wname, -1,
+                             utf8name, len, NULL, NULL)) {
+        oserr = _MD_ERRNO();
+        goto unlock;
+    }
+    /* the list of loaded library names are always kept in UTF-8 
+     * on Win32 platforms */
+    result = pr_UnlockedFindLibrary(utf8name);
+#else
+    result = pr_UnlockedFindLibrary(name);
+#endif
+
+    if (result != NULL) goto unlock;
+
+    lm = PR_NEWZAP(PRLibrary);
+    if (lm == NULL) {
+        oserr = _MD_ERRNO();
+        goto unlock;
+    }
+    lm->staticTable = NULL;
+
+#ifdef XP_OS2  /* Why isn't all this stuff in MD code?! */
+    {
+        HMODULE h;
+        UCHAR pszError[_MAX_PATH];
+        ULONG ulRc = NO_ERROR;
+
+          ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h);
+          if (ulRc != NO_ERROR) {
+              oserr = ulRc;
+              PR_DELETE(lm);
+              goto unlock;
+          }
+          lm->name = strdup(name);
+          lm->dlh  = h;
+          lm->next = pr_loadmap;
+          pr_loadmap = lm;
+    }
+#endif /* XP_OS2 */
+
+#ifdef WIN32
+    {
+    HINSTANCE h;
+
+    h = LoadLibraryExW(wname, NULL,
+                       (flags & PR_LD_ALT_SEARCH_PATH) ?
+                       LOAD_WITH_ALTERED_SEARCH_PATH : 0);
+    if (h == NULL) {
+        oserr = _MD_ERRNO();
+        PR_DELETE(lm);
+        goto unlock;
+    }
+    lm->name = strdup(utf8name);
+    lm->dlh = h;
+    lm->next = pr_loadmap;
+    pr_loadmap = lm;
+    }
+#endif /* WIN32 */
+
+#if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
+    {
+    int     i;
+    PRStatus status;
+
+    static const macLibraryLoadProc loadProcs[] = {
+#ifdef __ppc__
+        pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM
+#else  /* __ppc__ */
+        pr_LoadViaDyld, pr_LoadCFBundle
+#endif /* __ppc__ */
+    };
+
+    for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) {
+        if ((status = loadProcs[i](name, lm)) == PR_SUCCESS)
+            break;
+    }
+    if (status != PR_SUCCESS) {
+        oserr = cfragNoLibraryErr;
+        PR_DELETE(lm);
+        goto unlock;        
+    }
+    lm->name = strdup(name);
+    lm->next = pr_loadmap;
+    pr_loadmap = lm;
+    }
+#endif
+
+#if defined(XP_UNIX) && !(defined(XP_MACOSX) && defined(USE_MACH_DYLD))
+#ifdef HAVE_DLL
+    {
+#if defined(USE_DLFCN)
+#ifdef NTO
+    /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */
+    int dl_flags = RTLD_GROUP;
+#elif defined(AIX)
+    /* AIX needs RTLD_MEMBER to load an archive member.  (bug 228899) */
+    int dl_flags = RTLD_MEMBER;
+#else
+    int dl_flags = 0;
+#endif
+    void *h = NULL;
+
+    if (flags & PR_LD_LAZY) {
+        dl_flags |= RTLD_LAZY;
+    }
+    if (flags & PR_LD_NOW) {
+        dl_flags |= RTLD_NOW;
+    }
+    if (flags & PR_LD_GLOBAL) {
+        dl_flags |= RTLD_GLOBAL;
+    }
+    if (flags & PR_LD_LOCAL) {
+        dl_flags |= RTLD_LOCAL;
+    }
+#if defined(DARWIN)
+    /* ensure the file exists if it contains a slash character i.e. path */
+    /* DARWIN's dlopen ignores the provided path and checks for the */
+    /* plain filename in DYLD_LIBRARY_PATH */
+    if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL ||
+        PR_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+            h = dlopen(name, dl_flags);
+        }
+#else
+    h = dlopen(name, dl_flags);
+#endif
+#elif defined(USE_HPSHL)
+    int shl_flags = 0;
+    shl_t h;
+
+    /*
+     * Use the DYNAMIC_PATH flag only if 'name' is a plain file
+     * name (containing no directory) to match the behavior of
+     * dlopen().
+     */
+    if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) {
+        shl_flags |= DYNAMIC_PATH;
+    }
+    if (flags & PR_LD_LAZY) {
+        shl_flags |= BIND_DEFERRED;
+    }
+    if (flags & PR_LD_NOW) {
+        shl_flags |= BIND_IMMEDIATE;
+    }
+    /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */
+    h = shl_load(name, shl_flags, 0L);
+#elif defined(USE_MACH_DYLD)
+    NSModule h = pr_LoadMachDyldModule(name);
+#else
+#error Configuration error
+#endif
+    if (!h) {
+        oserr = _MD_ERRNO();
+        PR_DELETE(lm);
+        goto unlock;
+    }
+    lm->name = strdup(name);
+    lm->dlh = h;
+    lm->next = pr_loadmap;
+    pr_loadmap = lm;
+    }
+#endif /* HAVE_DLL */
+#endif /* XP_UNIX && !(XP_MACOSX && USE_MACH_DYLD) */
+
+    lm->refCount = 1;
+
+#ifdef XP_BEOS
+    {
+        image_info info;
+        int32 cookie = 0;
+        image_id imageid = B_ERROR;
+        image_id stubid = B_ERROR;
+        PRLibrary *p;
+
+        for (p = pr_loadmap; p != NULL; p = p->next) {
+            /* hopefully, our caller will always use the same string
+               to refer to the same library */
+            if (strcmp(name, p->name) == 0) {
+                /* we've already loaded this library */
+                imageid = info.id;
+                lm->refCount++;
+                break;
+            }
+        }
+
+        if(imageid == B_ERROR) {
+            /* it appears the library isn't yet loaded - load it now */
+            char stubName [B_PATH_NAME_LENGTH + 1];
+
+            /* the following is a work-around to a "bug" in the beos -
+               the beos system loader allows only 32M (system-wide)
+               to be used by code loaded as "add-ons" (code loaded
+               through the 'load_add_on()' system call, which includes
+               mozilla components), but allows 256M to be used by
+               shared libraries.
+               
+               unfortunately, mozilla is too large to fit into the
+               "add-on" space, so we must trick the loader into
+               loading some of the components as shared libraries.  this
+               is accomplished by creating a "stub" add-on (an empty
+               shared object), and linking it with the component
+               (the actual .so file generated by the build process,
+               without any modifications).  when this stub is loaded
+               by load_add_on(), the loader will automatically load the
+               component into the shared library space.
+            */
+
+            strcpy(stubName, name);
+            strcat(stubName, ".stub");
+
+            /* first, attempt to load the stub (thereby loading the
+               component as a shared library */
+            if ((stubid = load_add_on(stubName)) > B_ERROR) {
+                /* the stub was loaded successfully. */
+                imageid = B_FILE_NOT_FOUND;
+
+                cookie = 0;
+                while (get_next_image_info(0, &cookie, &info) == B_OK) {
+                    const char *endOfSystemName = strrchr(info.name, '/');
+                    const char *endOfPassedName = strrchr(name, '/');
+                    if( 0 == endOfSystemName ) 
+                        endOfSystemName = info.name;
+                    else
+                        endOfSystemName++;
+                    if( 0 == endOfPassedName )
+                        endOfPassedName = name;
+                    else
+                        endOfPassedName++;
+                    if (strcmp(endOfSystemName, endOfPassedName) == 0) {
+                        /* this is the actual component - remember it */
+                        imageid = info.id;
+                        break;
+                    }
+                }
+
+            } else {
+                /* we failed to load the "stub" - try to load the
+                   component directly as an add-on */
+                stubid = B_ERROR;
+                imageid = load_add_on(name);
+            }
+        }
+
+        if (imageid <= B_ERROR) {
+            oserr = imageid;
+            PR_DELETE( lm );
+            goto unlock;
+        }
+        lm->name = strdup(name);
+        lm->dlh = (void*)imageid;
+        lm->stub_dlh = (void*)stubid;
+        lm->next = pr_loadmap;
+        pr_loadmap = lm;
+    }
+#endif
+
+    result = lm;    /* success */
+    PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name));
+
+  unlock:
+    if (result == NULL) {
+        PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr);
+        DLLErrorInternal(oserr);  /* sets error text */
+    }
+#ifdef WIN32
+    if (utf8name_malloc) 
+        PR_Free(utf8name_malloc);
+    if (wname_malloc)
+        PR_Free(wname_malloc);
+#endif
+    PR_ExitMonitor(pr_linker_lock);
+    return result;
+}
+
+/*
+** Unload a shared library which was loaded via PR_LoadLibrary
+*/
+PR_IMPLEMENT(PRStatus) 
+PR_UnloadLibrary(PRLibrary *lib)
+{
+    int result = 0;
+    PRStatus status = PR_SUCCESS;
+
+    if ((lib == 0) || (lib->refCount <= 0)) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    PR_EnterMonitor(pr_linker_lock);
+    if (--lib->refCount > 0) {
+    PR_LOG(_pr_linker_lm, PR_LOG_MIN,
+           ("%s decr => %d",
+        lib->name, lib->refCount));
+    goto done;
+    }
+
+#ifdef XP_BEOS
+    if(((image_id)lib->stub_dlh) == B_ERROR)
+        unload_add_on( (image_id) lib->dlh );
+    else
+        unload_add_on( (image_id) lib->stub_dlh);
+#endif
+
+#ifdef XP_UNIX
+#ifdef HAVE_DLL
+#ifdef USE_DLFCN
+    result = dlclose(lib->dlh);
+#elif defined(USE_HPSHL)
+    result = shl_unload(lib->dlh);
+#elif defined(USE_MACH_DYLD)
+    if (lib->dlh)
+        result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1;
+#else
+#error Configuration error
+#endif
+#endif /* HAVE_DLL */
+#endif /* XP_UNIX */
+#ifdef XP_PC
+    if (lib->dlh) {
+        FreeLibrary((HINSTANCE)(lib->dlh));
+        lib->dlh = (HINSTANCE)NULL;
+    }
+#endif  /* XP_PC */
+
+#if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
+    /* Close the connection */
+    if (lib->connection)
+        CloseConnection(&(lib->connection));
+    if (lib->bundle)
+        CFRelease(lib->bundle);
+    if (lib->wrappers)
+        CFRelease(lib->wrappers);
+    /* No way to unload an image (lib->image) */
+#endif
+
+    /* unlink from library search list */
+    if (pr_loadmap == lib)
+        pr_loadmap = pr_loadmap->next;
+    else if (pr_loadmap != NULL) {
+        PRLibrary* prev = pr_loadmap;
+        PRLibrary* next = pr_loadmap->next;
+        while (next != NULL) {
+            if (next == lib) {
+                prev->next = next->next;
+                goto freeLib;
+            }
+            prev = next;
+            next = next->next;
+        }
+        /*
+         * fail (the library is not on the _pr_loadmap list),
+         * but don't wipe out an error from dlclose/shl_unload.
+         */
+        PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent");
+        if (result == 0) {
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            status = PR_FAILURE;
+        }
+    }
+    /*
+     * We free the PRLibrary structure whether dlclose/shl_unload
+     * succeeds or not.
+     */
+
+  freeLib:
+    PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name));
+    free(lib->name);
+    lib->name = NULL;
+    PR_DELETE(lib);
+    if (result != 0) {
+        PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO());
+        DLLErrorInternal(_MD_ERRNO());
+        status = PR_FAILURE;
+    }
+
+done:
+    PR_ExitMonitor(pr_linker_lock);
+    return status;
+}
+
+static void* 
+pr_FindSymbolInLib(PRLibrary *lm, const char *name)
+{
+    void *f = NULL;
+#ifdef XP_OS2
+    int rc;
+#endif
+
+    if (lm->staticTable != NULL) {
+        const PRStaticLinkTable* tp;
+        for (tp = lm->staticTable; tp->name; tp++) {
+            if (strcmp(name, tp->name) == 0) {
+                return (void*) tp->fp;
+            }
+        }
+        /* 
+        ** If the symbol was not found in the static table then check if
+        ** the symbol was exported in the DLL... Win16 only!!
+        */
+#if !defined(WIN16) && !defined(XP_BEOS)
+        PR_SetError(PR_FIND_SYMBOL_ERROR, 0);
+        return (void*)NULL;
+#endif
+    }
+    
+#ifdef XP_OS2
+    rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
+#if defined(NEED_LEADING_UNDERSCORE)
+    /*
+     * Older plugins (not built using GCC) will have symbols that are not
+     * underscore prefixed.  We check for that here.
+     */
+    if (rc != NO_ERROR) {
+        name++;
+        DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
+    }
+#endif
+#endif  /* XP_OS2 */
+
+#ifdef WIN32
+    f = GetProcAddress(lm->dlh, name);
+#endif  /* WIN32 */
+
+#if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
+/* add this offset to skip the leading underscore in name */
+#define SYM_OFFSET 1
+    if (lm->bundle) {
+        CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII);
+        if (nameRef) {
+            f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef);
+            CFRelease(nameRef);
+        }
+    }
+    if (lm->connection) {
+        Ptr                 symAddr;
+        CFragSymbolClass    symClass;
+        Str255              pName;
+        
+        PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET));
+        
+        c2pstrcpy(pName, name + SYM_OFFSET);
+        
+        f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL;
+        
+#ifdef __ppc__
+        /* callers expect mach-o function pointers, so must wrap tvectors with glue. */
+        if (f && symClass == kTVectorCFragSymbol) {
+            f = TV2FP(lm->wrappers, name + SYM_OFFSET, f);
+        }
+#endif /* __ppc__ */
+        
+        if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main;
+    }
+    if (lm->image) {
+        NSSymbol symbol;
+        symbol = NSLookupSymbolInImage(lm->image, name,
+                 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
+                 | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+        if (symbol != NULL)
+            f = NSAddressOfSymbol(symbol);
+        else
+            f = NULL;
+    }
+#undef SYM_OFFSET
+#endif /* XP_MACOSX && USE_MACH_DYLD */
+
+#ifdef XP_BEOS
+    if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) {
+        f = NULL;
+    }
+#endif
+
+#ifdef XP_UNIX
+#ifdef HAVE_DLL
+#ifdef USE_DLFCN
+    f = dlsym(lm->dlh, name);
+#elif defined(USE_HPSHL)
+    if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) {
+        f = NULL;
+    }
+#elif defined(USE_MACH_DYLD)
+    if (lm->dlh) {
+        NSSymbol symbol;
+        symbol = NSLookupSymbolInModule(lm->dlh, name);
+        if (symbol != NULL)
+            f = NSAddressOfSymbol(symbol);
+        else
+            f = NULL;
+    }
+#endif
+#endif /* HAVE_DLL */
+#endif /* XP_UNIX */
+    if (f == NULL) {
+        PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO());
+        DLLErrorInternal(_MD_ERRNO());
+    }
+    return f;
+}
+
+/*
+** Called by class loader to resolve missing native's
+*/
+PR_IMPLEMENT(void*) 
+PR_FindSymbol(PRLibrary *lib, const char *raw_name)
+{
+    void *f = NULL;
+#if defined(NEED_LEADING_UNDERSCORE)
+    char *name;
+#else
+    const char *name;
+#endif
+    /*
+    ** Mangle the raw symbol name in any way that is platform specific.
+    */
+#if defined(NEED_LEADING_UNDERSCORE)
+    /* Need a leading _ */
+    name = PR_smprintf("_%s", raw_name);
+#elif defined(AIX)
+    /*
+    ** AIX with the normal linker put's a "." in front of the symbol
+    ** name.  When use "svcc" and "svld" then the "." disappears. Go
+    ** figure.
+    */
+    name = raw_name;
+#else
+    name = raw_name;
+#endif
+
+    PR_EnterMonitor(pr_linker_lock);
+    PR_ASSERT(lib != NULL);
+    f = pr_FindSymbolInLib(lib, name);
+
+#if defined(NEED_LEADING_UNDERSCORE)
+    PR_smprintf_free(name);
+#endif
+
+    PR_ExitMonitor(pr_linker_lock);
+    return f;
+}
+
+/*
+** Return the address of the function 'raw_name' in the library 'lib'
+*/
+PR_IMPLEMENT(PRFuncPtr) 
+PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name)
+{
+    return ((PRFuncPtr) PR_FindSymbol(lib, raw_name));
+}
+
+PR_IMPLEMENT(void*) 
+PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
+{
+    void *f = NULL;
+#if defined(NEED_LEADING_UNDERSCORE)
+    char *name;
+#else
+    const char *name;
+#endif
+    PRLibrary* lm;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    /*
+    ** Mangle the raw symbol name in any way that is platform specific.
+    */
+#if defined(NEED_LEADING_UNDERSCORE)
+    /* Need a leading _ */
+    name = PR_smprintf("_%s", raw_name);
+#elif defined(AIX)
+    /*
+    ** AIX with the normal linker put's a "." in front of the symbol
+    ** name.  When use "svcc" and "svld" then the "." disappears. Go
+    ** figure.
+    */
+    name = raw_name;
+#else
+    name = raw_name;
+#endif
+
+    PR_EnterMonitor(pr_linker_lock);
+
+    /* search all libraries */
+    for (lm = pr_loadmap; lm != NULL; lm = lm->next) {
+        f = pr_FindSymbolInLib(lm, name);
+        if (f != NULL) {
+            *lib = lm;
+            lm->refCount++;
+            PR_LOG(_pr_linker_lm, PR_LOG_MIN,
+                       ("%s incr => %d (for %s)",
+                    lm->name, lm->refCount, name));
+            break;
+        }
+    }
+#if defined(NEED_LEADING_UNDERSCORE)
+    PR_smprintf_free(name);
+#endif
+
+    PR_ExitMonitor(pr_linker_lock);
+    return f;
+}
+
+PR_IMPLEMENT(PRFuncPtr) 
+PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
+{
+    return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib));
+}
+
+/*
+** Add a static library to the list of loaded libraries. If LoadLibrary
+** is called with the name then we will pretend it was already loaded
+*/
+PR_IMPLEMENT(PRLibrary*) 
+PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt)
+{
+    PRLibrary *lm=NULL;
+    PRLibrary* result = NULL;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    /* See if library is already loaded */
+    PR_EnterMonitor(pr_linker_lock);
+
+    /* If the lbrary is already loaded, then add the static table information... */
+    result = pr_UnlockedFindLibrary(name);
+    if (result != NULL) {
+        PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) );
+        result->staticTable = slt;
+        goto unlock;
+    }
+
+    /* Add library to list...Mark it static */
+    lm = PR_NEWZAP(PRLibrary);
+    if (lm == NULL) goto unlock;
+
+    lm->name = strdup(name);
+    lm->refCount    = 1;
+    lm->dlh         = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0;
+    lm->staticTable = slt;
+    lm->next        = pr_loadmap;
+    pr_loadmap      = lm;
+
+    result = lm;    /* success */
+    PR_ASSERT(lm->refCount == 1);
+    PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name));
+  unlock:
+    PR_ExitMonitor(pr_linker_lock);
+    return result;
+}
+
+PR_IMPLEMENT(char *)
+PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr)
+{
+#if defined(USE_DLFCN) && (defined(SOLARIS) || defined(FREEBSD) \
+        || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
+        || defined(DARWIN))
+    Dl_info dli;
+    char *result;
+
+    if (dladdr((void *)addr, &dli) == 0) {
+        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
+        DLLErrorInternal(_MD_ERRNO());
+        return NULL;
+    }
+    result = PR_Malloc(strlen(dli.dli_fname)+1);
+    if (result != NULL) {
+        strcpy(result, dli.dli_fname);
+    }
+    return result;
+#elif defined(USE_MACH_DYLD)
+    char *result;
+    const char *image_name;
+    int i, count = _dyld_image_count();
+
+    for (i = 0; i < count; i++) {
+        image_name = _dyld_get_image_name(i);
+        if (strstr(image_name, name) != NULL) {
+            result = PR_Malloc(strlen(image_name)+1);
+            if (result != NULL) {
+                strcpy(result, image_name);
+            }
+            return result;
+        }
+    }
+    PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
+    return NULL;
+#elif defined(AIX)
+    char *result;
+#define LD_INFO_INCREMENT 64
+    struct ld_info *info;
+    unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info);
+    struct ld_info *infop;
+    int loadflags = L_GETINFO | L_IGNOREUNLOAD;
+
+    for (;;) {
+        info = PR_Malloc(info_length);
+        if (info == NULL) {
+            return NULL;
+        }
+        /* If buffer is too small, loadquery fails with ENOMEM. */
+        if (loadquery(loadflags, info, info_length) != -1) {
+            break;
+        }
+        /*
+         * Calling loadquery when compiled for 64-bit with the
+         * L_IGNOREUNLOAD flag can cause an invalid argument error
+         * on AIX 5.1. Detect this error the first time that
+         * loadquery is called, and try calling it again without
+         * this flag set.
+         */
+        if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) {
+            loadflags &= ~L_IGNOREUNLOAD;
+            if (loadquery(loadflags, info, info_length) != -1) {
+                break;
+            }
+        }
+        PR_Free(info);
+        if (errno != ENOMEM) {
+            /* should not happen */
+            _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
+            return NULL;
+        }
+        /* retry with a larger buffer */
+        info_length += LD_INFO_INCREMENT * sizeof(struct ld_info);
+    }
+
+    for (infop = info;
+         ;
+         infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) {
+        unsigned long start = (unsigned long)infop->ldinfo_dataorg;
+        unsigned long end = start + infop->ldinfo_datasize;
+        if (start <= (unsigned long)addr && end > (unsigned long)addr) {
+            result = PR_Malloc(strlen(infop->ldinfo_filename)+1);
+            if (result != NULL) {
+                strcpy(result, infop->ldinfo_filename);
+            }
+            break;
+        }
+        if (!infop->ldinfo_next) {
+            PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
+            result = NULL;
+            break;
+        }
+    }
+    PR_Free(info);
+    return result;
+#elif defined(OSF1)
+    /* Contributed by Steve Streeter of HP */
+    ldr_process_t process, ldr_my_process();
+    ldr_module_t mod_id;
+    ldr_module_info_t info;
+    ldr_region_t regno;
+    ldr_region_info_t reginfo;
+    size_t retsize;
+    int rv;
+    char *result;
+
+    /* Get process for which dynamic modules will be listed */
+
+    process = ldr_my_process();
+
+    /* Attach to process */
+
+    rv = ldr_xattach(process);
+    if (rv) {
+        /* should not happen */
+        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
+        return NULL;
+    }
+
+    /* Print information for list of modules */
+
+    mod_id = LDR_NULL_MODULE;
+
+    for (;;) {
+
+        /* Get information for the next module in the module list. */
+
+        ldr_next_module(process, &mod_id);
+        if (ldr_inq_module(process, mod_id, &info, sizeof(info),
+                           &retsize) != 0) {
+            /* No more modules */
+            break;
+        }
+        if (retsize < sizeof(info)) {
+            continue;
+        }
+
+        /*
+         * Get information for each region in the module and check if any
+         * contain the address of this function.
+         */
+
+        for (regno = 0; ; regno++) {
+            if (ldr_inq_region(process, mod_id, regno, &reginfo,
+                               sizeof(reginfo), &retsize) != 0) {
+                /* No more regions */
+                break;
+            }
+            if (((unsigned long)reginfo.lri_mapaddr <=
+                (unsigned long)addr) &&
+                (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) >
+                (unsigned long)addr)) {
+                /* Found it. */
+                result = PR_Malloc(strlen(info.lmi_name)+1);
+                if (result != NULL) {
+                    strcpy(result, info.lmi_name);
+                }
+                return result;
+            }
+        }
+    }
+    PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
+    return NULL;
+#elif defined(HPUX) && defined(USE_HPSHL)
+    int index;
+    struct shl_descriptor desc;
+    char *result;
+
+    for (index = 0; shl_get_r(index, &desc) == 0; index++) {
+        if (strstr(desc.filename, name) != NULL) {
+            result = PR_Malloc(strlen(desc.filename)+1);
+            if (result != NULL) {
+                strcpy(result, desc.filename);
+            }
+            return result;
+        }
+    }
+    /*
+     * Since the index value of a library is decremented if
+     * a library preceding it in the shared library search
+     * list was unloaded, it is possible that we missed some
+     * libraries as we went up the list.  So we should go
+     * down the list to be sure that we not miss anything.
+     */
+    for (index--; index >= 0; index--) {
+        if ((shl_get_r(index, &desc) == 0)
+                && (strstr(desc.filename, name) != NULL)) {
+            result = PR_Malloc(strlen(desc.filename)+1);
+            if (result != NULL) {
+                strcpy(result, desc.filename);
+            }
+            return result;
+        }
+    }
+    PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
+    return NULL;
+#elif defined(HPUX) && defined(USE_DLFCN)
+    struct load_module_desc desc;
+    char *result;
+    const char *module_name;
+
+    if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) {
+        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
+        DLLErrorInternal(_MD_ERRNO());
+        return NULL;
+    }
+    module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0);
+    if (module_name == NULL) {
+        /* should not happen */
+        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
+        DLLErrorInternal(_MD_ERRNO());
+        return NULL;
+    }
+    result = PR_Malloc(strlen(module_name)+1);
+    if (result != NULL) {
+        strcpy(result, module_name);
+    }
+    return result;
+#elif defined(WIN32)
+    PRUnichar wname[MAX_PATH];
+    HMODULE handle = NULL;
+    PRUnichar module_name[MAX_PATH];
+    int len;
+    char *result;
+
+    if (MultiByteToWideChar(CP_ACP, 0, name, -1, wname, MAX_PATH)) {
+        handle = GetModuleHandleW(wname);
+    }
+    if (handle == NULL) {
+        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
+        DLLErrorInternal(_MD_ERRNO());
+        return NULL;
+    }
+    if (GetModuleFileNameW(handle, module_name, MAX_PATH) == 0) {
+        /* should not happen */
+        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
+        return NULL;
+    }
+    len = WideCharToMultiByte(CP_ACP, 0, module_name, -1,
+                              NULL, 0, NULL, NULL);
+    if (len == 0) {
+        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
+        return NULL;
+    }
+    result = PR_Malloc(len * sizeof(PRUnichar));
+    if (result != NULL) {
+        WideCharToMultiByte(CP_ACP, 0, module_name, -1,
+                            result, len, NULL, NULL);
+    }
+    return result;
+#elif defined(XP_OS2)
+    HMODULE module = NULL;
+    char module_name[_MAX_PATH];
+    char *result;
+    APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr);
+    if ((NO_ERROR != ulrc) || (NULL == module) ) {
+        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
+        DLLErrorInternal(_MD_ERRNO());
+        return NULL;
+    }
+    ulrc = DosQueryModuleName(module, sizeof module_name, module_name);
+    if (NO_ERROR != ulrc) {
+        /* should not happen */
+        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
+        return NULL;
+    }
+    result = PR_Malloc(strlen(module_name)+1);
+    if (result != NULL) {
+        strcpy(result, module_name);
+    }
+    return result;
+#else
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+#endif
+}
diff --git a/mozilla/nsprpub/pr/src/malloc/prmalloc.c b/mozilla/nsprpub/pr/src/malloc/prmalloc.c
new file mode 100644
index 0000000..10e9cf7
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/malloc/prmalloc.c
@@ -0,0 +1,1174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+/*
+** We override malloc etc. on any platform which has preemption +
+** nspr20 user level threads.  When we're debugging, we can make our
+** version of malloc fail occasionally.
+*/
+#ifdef _PR_OVERRIDE_MALLOC
+
+/*
+** Thread safe version of malloc, calloc, realloc, free
+*/
+#include <stdarg.h>
+
+#ifdef DEBUG
+#define SANITY
+#define EXTRA_SANITY
+#else
+#undef SANITY
+#undef EXTRA_SANITY
+#endif
+
+/* Forward decls */
+void *_PR_UnlockedMalloc(size_t size);
+void _PR_UnlockedFree(void *ptr);
+void *_PR_UnlockedRealloc(void *ptr, size_t size);
+void *_PR_UnlockedCalloc(size_t n, size_t elsize);
+
+/************************************************************************/
+
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+/*
+ * Defining SANITY will enable some checks which will tell you if the users
+ * program did botch something
+ */
+
+/*
+ * Defining EXTRA_SANITY will enable some checks which are mostly related
+ * to internal conditions in malloc.c
+ */
+
+/*
+ * Very verbose progress on stdout...
+ */
+#if 0
+#  define TRACE(foo)    printf  foo
+static int malloc_event;
+#else
+#  define TRACE(foo)	
+#endif
+
+/* XXX Pick a number, any number */
+#   define malloc_pagesize		4096UL
+#   define malloc_pageshift		12UL
+
+#ifdef XP_UNIX
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#endif
+
+/*
+ * This structure describes a page's worth of chunks.
+ */
+
+struct pginfo {
+    struct pginfo	*next;	/* next on the free list */
+    char		*page;	/* Pointer to the page */
+    u_short		size;	/* size of this page's chunks */
+    u_short		shift;	/* How far to shift for this size chunks */
+    u_short		free;	/* How many free chunks */
+    u_short		total;	/* How many chunk */
+    u_long		bits[1]; /* Which chunks are free */
+};
+
+struct pgfree {
+    struct pgfree	*next;	/* next run of free pages */
+    struct pgfree	*prev;	/* prev run of free pages */
+    char		*page;	/* pointer to free pages */
+    char		*end;	/* pointer to end of free pages */
+    u_long		size;	/* number of bytes free */
+};
+
+/*
+ * How many bits per u_long in the bitmap.
+ * Change only if not 8 bits/byte
+ */
+#define	MALLOC_BITS	(8*sizeof(u_long))
+
+/*
+ * Magic values to put in the page_directory
+ */
+#define MALLOC_NOT_MINE	((struct pginfo*) 0)
+#define MALLOC_FREE 	((struct pginfo*) 1)
+#define MALLOC_FIRST	((struct pginfo*) 2)
+#define MALLOC_FOLLOW	((struct pginfo*) 3)
+#define MALLOC_MAGIC	((struct pginfo*) 4)
+
+/*
+ * Set to one when malloc_init has been called
+ */
+static	unsigned	initialized;
+
+/*
+ * The size of a page.
+ * Must be a integral multiplum of the granularity of mmap(2).
+ * Your toes will curl if it isn't a power of two
+ */
+#define malloc_pagemask	((malloc_pagesize)-1)
+
+/*
+ * The size of the largest chunk.
+ * Half a page.
+ */
+#define malloc_maxsize	((malloc_pagesize)>>1)
+
+/*
+ * malloc_pagesize == 1 << malloc_pageshift
+ */
+#ifndef malloc_pageshift
+static	unsigned	malloc_pageshift;
+#endif /* malloc_pageshift */
+
+/*
+ * The smallest allocation we bother about.
+ * Must be power of two
+ */
+#ifndef malloc_minsize
+static	unsigned  malloc_minsize;
+#endif /* malloc_minsize */
+
+/*
+ * The largest chunk we care about.
+ * Must be smaller than pagesize
+ * Must be power of two
+ */
+#ifndef malloc_maxsize
+static	unsigned  malloc_maxsize;
+#endif /* malloc_maxsize */
+
+#ifndef malloc_cache
+static	unsigned  malloc_cache;
+#endif /* malloc_cache */
+
+/*
+ * The offset from pagenumber to index into the page directory
+ */
+static	u_long  malloc_origo;
+
+/*
+ * The last index in the page directory we care about
+ */
+static	u_long  last_index;
+
+/*
+ * Pointer to page directory.
+ * Allocated "as if with" malloc
+ */
+static	struct	pginfo **page_dir;
+
+/*
+ * How many slots in the page directory
+ */
+static	unsigned	malloc_ninfo;
+
+/*
+ * Free pages line up here 
+ */
+static struct pgfree	free_list;
+
+/*
+ * Abort() if we fail to get VM ?
+ */
+static int malloc_abort;
+
+#ifdef SANITY
+/*
+ * Are we trying to die ?
+ */
+static int suicide;
+#endif
+
+/*
+ * dump statistics
+ */
+static int malloc_stats;
+
+/*
+ * always realloc ?
+ */
+static int malloc_realloc;
+
+/*
+ * my last break.
+ */
+static void *malloc_brk;
+
+/*
+ * one location cache for free-list holders
+ */
+static struct pgfree *px;
+
+static int set_pgdir(void *ptr, struct  pginfo *info);
+static int extend_page_directory(u_long index);
+
+#ifdef SANITY
+void
+malloc_dump(FILE *fd)
+{
+    struct pginfo **pd;
+    struct pgfree *pf;
+    int j;
+
+    pd = page_dir;
+
+    /* print out all the pages */
+    for(j=0;j<=last_index;j++) {
+	fprintf(fd,"%08lx %5d ",(j+malloc_origo) << malloc_pageshift,j);
+	if (pd[j] == MALLOC_NOT_MINE) {
+	    for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++)
+		;
+	    j--;
+	    fprintf(fd,".. %5d not mine\n",	j);
+	} else if (pd[j] == MALLOC_FREE) {
+	    for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++)
+		;
+	    j--;
+	    fprintf(fd,".. %5d free\n", j);
+	} else if (pd[j] == MALLOC_FIRST) {
+	    for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++)
+		;
+	    j--;
+	    fprintf(fd,".. %5d in use\n", j);
+	} else if (pd[j] < MALLOC_MAGIC) {
+	    fprintf(fd,"(%p)\n", pd[j]);
+	} else {
+	    fprintf(fd,"%p %d (of %d) x %d @ %p --> %p\n",
+		pd[j],pd[j]->free, pd[j]->total, 
+		pd[j]->size, pd[j]->page, pd[j]->next);
+	}
+    }
+
+    for(pf=free_list.next; pf; pf=pf->next) {
+	fprintf(fd,"Free: @%p [%p...%p[ %ld ->%p <-%p\n",
+		pf,pf->page,pf->end,pf->size,pf->prev,pf->next);
+	if (pf == pf->next) {
+		fprintf(fd,"Free_list loops.\n");
+		break;
+	}
+    }
+
+    /* print out various info */
+    fprintf(fd,"Minsize\t%d\n",malloc_minsize);
+    fprintf(fd,"Maxsize\t%ld\n",malloc_maxsize);
+    fprintf(fd,"Pagesize\t%ld\n",malloc_pagesize);
+    fprintf(fd,"Pageshift\t%ld\n",malloc_pageshift);
+    fprintf(fd,"FirstPage\t%ld\n",malloc_origo);
+    fprintf(fd,"LastPage\t%ld %lx\n",last_index+malloc_pageshift,
+	(last_index + malloc_pageshift) << malloc_pageshift);
+    fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift);
+}
+
+static void wrterror(char *fmt, ...)
+{
+    char *q = "malloc() error: ";
+    char buf[100];
+    va_list ap;
+
+    suicide = 1;
+
+    va_start(ap, fmt);
+    PR_vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    fputs(q, stderr);
+    fputs(buf, stderr);
+
+    malloc_dump(stderr);
+    PR_Abort();
+}
+
+static void wrtwarning(char *fmt, ...)
+{
+    char *q = "malloc() warning: ";
+    char buf[100];
+    va_list ap;
+
+    va_start(ap, fmt);
+    PR_vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    fputs(q, stderr);
+    fputs(buf, stderr);
+}
+#endif /* SANITY */
+
+
+/*
+ * Allocate a number of pages from the OS
+ */
+static caddr_t
+map_pages(int pages, int update)
+{
+    caddr_t result,tail;
+
+    result = ((caddr_t)sbrk(0)) + malloc_pagemask - 1;
+    result = (caddr_t) ((u_long)result & ~malloc_pagemask);
+    tail = result + (pages << malloc_pageshift);
+    if (!brk(tail)) {
+	last_index = ((u_long)tail >> malloc_pageshift) - malloc_origo -1;
+	malloc_brk = tail;
+	TRACE(("%6d S %p .. %p\n",malloc_event++, result, tail));
+	if (!update || last_index < malloc_ninfo ||
+	  extend_page_directory(last_index))
+	    return result;
+    }
+    TRACE(("%6d s %d %p %d\n",malloc_event++,pages,sbrk(0),errno));
+#ifdef EXTRA_SANITY
+    wrterror("map_pages fails\n");
+#endif
+    return 0;
+}
+
+#define set_bit(_pi,_bit) \
+    (_pi)->bits[(_bit)/MALLOC_BITS] |= 1L<<((_bit)%MALLOC_BITS)
+
+#define clr_bit(_pi,_bit) \
+    (_pi)->bits[(_bit)/MALLOC_BITS] &= ~(1L<<((_bit)%MALLOC_BITS));
+
+#define tst_bit(_pi,_bit) \
+    ((_pi)->bits[(_bit)/MALLOC_BITS] & (1L<<((_bit)%MALLOC_BITS)))
+
+/*
+ * Extend page directory
+ */
+static int
+extend_page_directory(u_long index)
+{
+    struct  pginfo **young, **old;
+    int i;
+
+    TRACE(("%6d E %lu\n",malloc_event++,index));
+    
+    /* Make it this many pages */
+    i = index * sizeof *page_dir;
+    i /= malloc_pagesize;
+    i += 2;
+
+    /* Get new pages, if you used this much mem you don't care :-) */
+    young = (struct pginfo**) map_pages(i,0);
+    if (!young)
+	return 0;
+
+    /* Copy the old stuff */
+    memset(young, 0, i * malloc_pagesize);
+    memcpy(young, page_dir,
+	    malloc_ninfo * sizeof *page_dir);
+
+    /* register the new size */
+    malloc_ninfo = i * malloc_pagesize / sizeof *page_dir;
+
+    /* swap the pointers */
+    old = page_dir;
+    page_dir = young;
+
+    /* Mark the pages */
+    index = ((u_long)young >> malloc_pageshift) - malloc_origo;
+    page_dir[index] = MALLOC_FIRST;
+    while (--i) {
+	page_dir[++index] = MALLOC_FOLLOW;
+    }
+
+    /* Now free the old stuff */
+    _PR_UnlockedFree(old);
+    return 1;
+}
+
+/*
+ * Set entry in page directory.
+ * Extend page directory if need be.
+ */
+static int
+set_pgdir(void *ptr, struct  pginfo *info)
+{
+    u_long index = ((u_long)ptr >> malloc_pageshift) - malloc_origo;
+
+    if (index >= malloc_ninfo && !extend_page_directory(index))
+	return 0;
+    page_dir[index] = info;
+    return 1;
+}
+
+/*
+ * Initialize the world
+ */
+static void
+malloc_init (void)
+{
+    int i;
+    char *p;
+
+    TRACE(("%6d I\n",malloc_event++));
+#ifdef DEBUG
+    for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) {
+	switch (*p) {
+	    case 'a': malloc_abort = 0; break;
+	    case 'A': malloc_abort = 1; break;
+	    case 'd': malloc_stats = 0; break;
+	    case 'D': malloc_stats = 1; break;
+	    case 'r': malloc_realloc = 0; break;
+	    case 'R': malloc_realloc = 1; break;
+	    default:
+		wrtwarning("Unknown chars in MALLOC_OPTIONS\n");
+		break;
+	}
+    }
+#endif
+
+#ifndef malloc_pagesize
+    /* determine our pagesize */
+    malloc_pagesize = getpagesize();
+#endif /* malloc_pagesize */
+
+#ifndef malloc_pageshift
+    /* determine how much we shift by to get there */
+    for (i = malloc_pagesize; i > 1; i >>= 1)
+	malloc_pageshift++;
+#endif /* malloc_pageshift */
+
+#ifndef malloc_cache
+    malloc_cache = 50 << malloc_pageshift;	
+#endif /* malloc_cache */
+
+#ifndef malloc_minsize
+    /*
+     * find the smallest size allocation we will bother about.
+     * this is determined as the smallest allocation that can hold
+     * it's own pginfo;
+     */
+    i = 2;
+    for(;;) {
+	int j;
+
+	/* Figure out the size of the bits */
+	j = malloc_pagesize/i;
+	j /= 8;
+	if (j < sizeof(u_long))
+		j = sizeof (u_long);
+	if (sizeof(struct pginfo) + j - sizeof (u_long) <= i)
+		break;
+	i += i;
+    }
+    malloc_minsize = i;
+#endif /* malloc_minsize */
+
+
+    /* Allocate one page for the page directory */
+    page_dir = (struct pginfo **) map_pages(1,0);
+#ifdef SANITY
+    if (!page_dir)
+	wrterror("fatal: my first mmap failed.  (check limits ?)\n");
+#endif
+
+    /*
+     * We need a maximum of malloc_pageshift buckets, steal these from the
+     * front of the page_directory;
+     */
+    malloc_origo = (u_long) page_dir >> malloc_pageshift;
+    malloc_origo -= malloc_pageshift;
+
+    /* Clear it */
+    memset(page_dir,0,malloc_pagesize);
+
+    /* Find out how much it tells us */
+    malloc_ninfo = malloc_pagesize / sizeof *page_dir;
+
+    /* Plug the page directory into itself */
+    i = set_pgdir(page_dir,MALLOC_FIRST);
+#ifdef SANITY
+    if (!i)
+	wrterror("fatal: couldn't set myself in the page directory\n");
+#endif
+
+    /* Been here, done that */
+    initialized++;
+}
+
+/*
+ * Allocate a number of complete pages
+ */
+static void *malloc_pages(size_t size)
+{
+    void *p,*delay_free = 0;
+    int i;
+    struct pgfree *pf;
+    u_long index;
+
+    /* How many pages ? */
+    size += (malloc_pagesize-1);
+    size &= ~malloc_pagemask;
+
+    p = 0;
+    /* Look for free pages before asking for more */
+    for(pf = free_list.next; pf; pf = pf->next) {
+#ifdef EXTRA_SANITY
+	if (pf->page == pf->end)
+	    wrterror("zero entry on free_list\n");
+	if (pf->page > pf->end) {
+	    TRACE(("%6d !s %p %p %p <%d>\n",malloc_event++,
+		pf,pf->page,pf->end,__LINE__));
+	    wrterror("sick entry on free_list\n");
+	}
+	if ((void*)pf->page >= (void*)sbrk(0))
+	    wrterror("entry on free_list past brk\n");
+	if (page_dir[((u_long)pf->page >> malloc_pageshift) - malloc_origo] 
+	  != MALLOC_FREE) {
+	    TRACE(("%6d !f %p %p %p <%d>\n",malloc_event++,
+		pf,pf->page,pf->end,__LINE__));
+	    wrterror("non-free first page on free-list\n");
+	}
+	if (page_dir[((u_long)pf->end >> malloc_pageshift) - 1 - malloc_origo] 
+	  != MALLOC_FREE)
+	    wrterror("non-free last page on free-list\n");
+#endif /* EXTRA_SANITY */
+	if (pf->size < size) 
+	    continue;
+	else if (pf->size == size) {
+	    p = pf->page;
+	    if (pf->next)
+		    pf->next->prev = pf->prev;
+	    pf->prev->next = pf->next;
+	    delay_free = pf;
+	    break;
+	} else {
+	    p = pf->page;
+	    pf->page += size;
+	    pf->size -= size;
+	    break;
+        }
+    }
+#ifdef EXTRA_SANITY
+    if (p && page_dir[((u_long)p >> malloc_pageshift) - malloc_origo] 
+      != MALLOC_FREE) {
+	wrterror("allocated non-free page on free-list\n");
+    }
+#endif /* EXTRA_SANITY */
+
+    size >>= malloc_pageshift;
+
+    /* Map new pages */
+    if (!p)
+	p = map_pages(size,1);
+
+    if (p) {
+	/* Mark the pages in the directory */
+	index = ((u_long)p >> malloc_pageshift) - malloc_origo;
+	page_dir[index] = MALLOC_FIRST;
+	for (i=1;i<size;i++)
+	    page_dir[index+i] = MALLOC_FOLLOW;
+    }
+    if (delay_free) {
+	if (!px) 
+	    px = (struct pgfree*)delay_free;
+	else
+	    _PR_UnlockedFree(delay_free);
+    }
+    return p;
+}
+
+/*
+ * Allocate a page of fragments
+ */
+
+static int
+malloc_make_chunks(int bits)
+{
+    struct  pginfo *bp;
+    void *pp;
+    int i,k,l;
+
+    /* Allocate a new bucket */
+    pp = malloc_pages(malloc_pagesize);
+    if (!pp)
+	return 0;
+    l = sizeof *bp - sizeof(u_long);
+    l += sizeof(u_long) *
+	(((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS);
+    if ((1<<(bits)) <= l+l) {
+	bp = (struct  pginfo *)pp;
+    } else {
+	bp = (struct  pginfo *)_PR_UnlockedMalloc(l);
+    }
+    if (!bp)
+	return 0;
+    bp->size = (1<<bits);
+    bp->shift = bits;
+    bp->total = bp->free = malloc_pagesize >> bits;
+    bp->next = page_dir[bits];
+    bp->page = (char*)pp;
+    i = set_pgdir(pp,bp);
+    if (!i)
+	return 0;
+
+    /* We can safely assume that there is nobody in this chain */
+    page_dir[bits] = bp;
+
+    /* set all valid bits in the bits */
+    k = bp->total;
+    i = 0;
+/*
+    for(;k-i >= MALLOC_BITS; i += MALLOC_BITS)
+	bp->bits[i / MALLOC_BITS] = ~0;
+*/
+    for(; i < k; i++)
+	set_bit(bp,i);
+
+    if (bp != pp)
+	return 1;
+
+    /* We may have used the first ones already */
+    for(i=0;l > 0;i++) {
+	clr_bit(bp,i);
+	bp->free--;
+	bp->total--;
+	l -= (1 << bits);
+    }
+    return 1;
+}
+
+/*
+ * Allocate a fragment
+ */
+static void *malloc_bytes(size_t size)
+{
+    size_t s;
+    int j;
+    struct  pginfo *bp;
+    int k;
+    u_long *lp, bf;
+
+    /* Don't bother with anything less than this */
+    if (size < malloc_minsize) {
+	size = malloc_minsize;
+    }
+
+    /* Find the right bucket */
+    j = 1;
+    s = size - 1;
+    while (s >>= 1) {
+        j++;
+    }
+
+    /* If it's empty, make a page more of that size chunks */
+    if (!page_dir[j] && !malloc_make_chunks(j))
+	return 0;
+
+    /* Find first word of bitmap which isn't empty */
+    bp = page_dir[j];
+    for (lp = bp->bits; !*lp; lp++)
+	;
+
+    /* Find that bit */
+    bf = *lp;
+    k = 0;
+    while ((bf & 1) == 0) {
+	bf >>= 1;
+	k++;
+    }
+
+    *lp ^= 1L<<k;                       /* clear it */
+    bp->free--;
+    if (!bp->free) {
+	page_dir[j] = bp->next;
+	bp->next = 0;
+    }
+    k += (lp - bp->bits)*MALLOC_BITS;
+    return bp->page + (k << bp->shift);
+}
+
+void *_PR_UnlockedMalloc(size_t size)
+{
+    void *result;
+
+    /* Round up to a multiple of 8 bytes */
+    if (size & 7) {
+	size = size + 8 - (size & 7);
+    }
+
+    if (!initialized)
+	malloc_init();
+
+#ifdef SANITY
+    if (suicide)
+	PR_Abort();
+#endif
+
+    if (size <= malloc_maxsize)
+	result =  malloc_bytes(size);
+    else
+	result =  malloc_pages(size);
+#ifdef SANITY
+    if (malloc_abort && !result)
+	wrterror("malloc() returns NULL\n");
+#endif
+    TRACE(("%6d M %p %d\n",malloc_event++,result,size));
+
+    return result;
+}
+
+void *_PR_UnlockedMemalign(size_t alignment, size_t size)
+{
+    void *result;
+
+    /*
+     * alignment has to be a power of 2
+     */
+
+    if ((size <= alignment) && (alignment <= malloc_maxsize))
+		size = alignment;	
+    else
+           	size += alignment - 1;	
+
+    /* Round up to a multiple of 8 bytes */
+    if (size & 7) {
+	size = size + 8 - (size & 7);
+    }
+
+    if (!initialized)
+	malloc_init();
+
+#ifdef SANITY
+    if (suicide)
+	abort();
+#endif
+
+    if (size <= malloc_maxsize)
+	result =  malloc_bytes(size);
+    else
+	result =  malloc_pages(size);
+#ifdef SANITY
+    if (malloc_abort && !result)
+	wrterror("malloc() returns NULL\n");
+#endif
+    TRACE(("%6d A %p %d\n",malloc_event++,result,size));
+
+    if ((u_long)result & (alignment - 1))
+    	return ((void *)(((u_long)result + alignment)  & ~(alignment - 1)));
+    else
+    	return result;
+}
+
+void *_PR_UnlockedCalloc(size_t n, size_t nelem)
+{
+    void *p;
+
+    /* Compute total size and then round up to a double word amount */
+    n *= nelem;
+    if (n & 7) {
+	n = n + 8 - (n & 7);
+    }
+
+    /* Get the memory */
+    p = _PR_UnlockedMalloc(n);
+    if (p) {
+	/* Zero it */
+	memset(p, 0, n);
+    }
+    return p;
+}
+
+/*
+ * Change an allocation's size
+ */
+void *_PR_UnlockedRealloc(void *ptr, size_t size)
+{
+    void *p;
+    u_long osize,page,index,tmp_index;
+    struct pginfo **mp;
+
+    if (!initialized)
+	malloc_init();
+
+#ifdef SANITY
+    if (suicide)
+	PR_Abort();
+#endif
+
+    /* used as free() */
+    TRACE(("%6d R %p %d\n",malloc_event++, ptr, size));
+    if (ptr && !size) {
+	_PR_UnlockedFree(ptr);
+	return _PR_UnlockedMalloc (1);
+    }
+
+    /* used as malloc() */
+    if (!ptr) {
+	p = _PR_UnlockedMalloc(size);
+	return p;
+    }
+
+    /* Find the page directory entry for the page in question */
+    page = (u_long)ptr >> malloc_pageshift;
+    index = page - malloc_origo;
+
+    /*
+     * check if memory was allocated by memalign
+     */
+    tmp_index = index;
+    while (page_dir[tmp_index] == MALLOC_FOLLOW)
+	tmp_index--;
+    if (tmp_index != index) {
+	/*
+	 * memalign-allocated memory
+	 */
+	index = tmp_index;
+	page = index + malloc_origo;			
+	ptr = (void *) (page << malloc_pageshift);
+    }
+    TRACE(("%6d R2 %p %d\n",malloc_event++, ptr, size));
+
+    /* make sure it makes sense in some fashion */
+    if (index < malloc_pageshift || index > last_index) {
+#ifdef SANITY
+	wrtwarning("junk pointer passed to realloc()\n");
+#endif
+	return 0;
+    }
+
+    /* find the size of that allocation, and see if we need to relocate */
+    mp = &page_dir[index];
+    if (*mp == MALLOC_FIRST) {
+	osize = malloc_pagesize;
+	while (mp[1] == MALLOC_FOLLOW) {
+	    osize += malloc_pagesize;
+	    mp++;
+	}
+        if (!malloc_realloc && 
+		size < osize && 
+		size > malloc_maxsize &&
+	    size > (osize - malloc_pagesize)) {
+	    return ptr;
+	}
+    } else if (*mp >= MALLOC_MAGIC) {
+	osize = (*mp)->size;
+	if (!malloc_realloc &&
+		size < osize && 
+	    (size > (*mp)->size/2 || (*mp)->size == malloc_minsize)) {
+	    return ptr;
+	}
+    } else {
+#ifdef SANITY
+	wrterror("realloc() of wrong page.\n");
+#endif
+    }
+
+    /* try to reallocate */
+    p = _PR_UnlockedMalloc(size);
+
+    if (p) {
+	/* copy the lesser of the two sizes */
+	if (osize < size)
+	    memcpy(p,ptr,osize);
+	else
+	    memcpy(p,ptr,size);
+	_PR_UnlockedFree(ptr);
+    }
+#ifdef DEBUG
+    else if (malloc_abort)
+	wrterror("realloc() returns NULL\n");
+#endif
+
+    return p;
+}
+
+/*
+ * Free a sequence of pages
+ */
+
+static void
+free_pages(char *ptr, u_long page, int index, struct pginfo *info)
+{
+    int i;
+    struct pgfree *pf,*pt;
+    u_long l;
+    char *tail;
+
+    TRACE(("%6d FP %p %d\n",malloc_event++, ptr, page));
+    /* Is it free already ? */
+    if (info == MALLOC_FREE) {
+#ifdef SANITY
+	wrtwarning("freeing free page at %p.\n", ptr);
+#endif
+	return;
+    }
+
+#ifdef SANITY
+    /* Is it not the right place to begin ? */
+    if (info != MALLOC_FIRST)
+	wrterror("freeing wrong page.\n");
+
+    /* Is this really a pointer to a page ? */
+    if ((u_long)ptr & malloc_pagemask)
+	wrterror("freeing messed up page pointer.\n");
+#endif
+
+    /* Count how many pages it is anyway */
+    page_dir[index] = MALLOC_FREE;
+    for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++)
+	page_dir[index + i] = MALLOC_FREE;
+
+    l = i << malloc_pageshift;
+
+    tail = ptr+l;
+
+    /* add to free-list */
+    if (!px)
+	px = (struct pgfree*)_PR_UnlockedMalloc(sizeof *pt);
+    /* XXX check success */
+    px->page = ptr;
+    px->end =  tail;
+    px->size = l;
+    if (!free_list.next) {
+	px->next = free_list.next;
+	px->prev = &free_list;
+	free_list.next = px;
+	pf = px;
+	px = 0;
+    } else {
+	tail = ptr+l;
+	for(pf = free_list.next; pf->next && pf->end < ptr; pf = pf->next)
+	    ;
+	for(; pf; pf = pf->next) {
+	    if (pf->end == ptr ) {
+		/* append to entry */
+		pf->end += l;
+		pf->size += l;
+		if (pf->next && pf->end == pf->next->page ) {
+		    pt = pf->next;
+		    pf->end = pt->end;
+		    pf->size += pt->size;
+		    pf->next = pt->next;
+		    if (pf->next)
+			pf->next->prev = pf;
+		    _PR_UnlockedFree(pt);
+		}
+	    } else if (pf->page == tail) {
+		/* prepend to entry */
+		pf->size += l;
+		pf->page = ptr;
+	    } else if (pf->page > ptr) {
+		px->next = pf;
+		px->prev = pf->prev;
+		pf->prev = px;
+		px->prev->next = px;
+		pf = px;
+		px = 0;
+	    } else if (!pf->next) {
+		px->next = 0;
+		px->prev = pf;
+		pf->next = px;
+		pf = px;
+		px = 0;
+	    } else {
+		continue;
+	    }
+	    break;
+	}
+    }
+    if (!pf->next &&
+      pf->size > malloc_cache &&
+      pf->end == malloc_brk &&
+      malloc_brk == (void*)sbrk(0)) {
+	pf->end = pf->page + malloc_cache;
+	pf->size = malloc_cache;
+	TRACE(("%6d U %p %d\n",malloc_event++,pf->end,pf->end - pf->page));
+	brk(pf->end);
+	malloc_brk = pf->end;
+	/* Find the page directory entry for the page in question */
+	page = (u_long)pf->end >> malloc_pageshift;
+	index = page - malloc_origo;
+	/* Now update the directory */
+	for(i=index;i <= last_index;)
+	    page_dir[i++] = MALLOC_NOT_MINE;
+	last_index = index - 1;
+    }
+}
+
+/*
+ * Free a chunk, and possibly the page it's on, if the page becomes empty.
+ */
+
+static void
+free_bytes(void *ptr, u_long page, int index, struct pginfo *info)
+{
+    int i;
+    struct pginfo **mp;
+    void *vp;
+
+    /* Make sure that pointer is multiplum of chunk-size */
+#ifdef SANITY
+    if ((u_long)ptr & (info->size - 1))
+	wrterror("freeing messed up chunk pointer\n");
+#endif
+
+    /* Find the chunk number on the page */
+    i = ((u_long)ptr & malloc_pagemask) >> info->shift;
+
+    /* See if it's free already */
+    if (tst_bit(info,i)) {
+#ifdef SANITY
+	wrtwarning("freeing free chunk at %p\n", ptr);
+#endif
+	return;
+    }
+
+    /* Mark it free */
+    set_bit(info,i);
+    info->free++;
+
+    /* If the page was full before, we need to put it on the queue now */
+    if (info->free == 1) {
+	mp = page_dir + info->shift;
+	while (*mp && (*mp)->next && (*mp)->next->page < info->page)
+	    mp = &(*mp)->next;
+	info->next = *mp;
+	*mp = info;
+	return;
+    }
+
+    /* If this page isn't empty, don't do anything. */
+    if (info->free != info->total)
+	return;
+
+    /* We may want to keep at least one page of each size chunks around.  */
+    mp = page_dir + info->shift;
+    if (0 && (*mp == info) && !info->next)
+	return;
+
+    /* Find & remove this page in the queue */
+    while (*mp != info) {
+	mp = &((*mp)->next);
+#ifdef EXTRA_SANITY
+	if (!*mp) {
+		TRACE(("%6d !q %p\n",malloc_event++,info));
+		wrterror("Not on queue\n");
+	}
+#endif
+    }
+    *mp = info->next;
+
+    /* Free the page & the info structure if need be */
+    set_pgdir(info->page,MALLOC_FIRST);
+    if((void*)info->page == (void*)info) {
+	_PR_UnlockedFree(info->page);
+    } else {
+	vp = info->page;
+	_PR_UnlockedFree(info);
+	_PR_UnlockedFree(vp);
+    }
+}
+
+void _PR_UnlockedFree(void *ptr)
+{
+    u_long page;
+    struct pginfo *info;
+    int index, tmp_index;
+
+    TRACE(("%6d F %p\n",malloc_event++,ptr));
+    /* This is legal */
+    if (!ptr)
+	return;
+
+#ifdef SANITY
+    /* There wouldn't be anything to free */
+    if (!initialized) {
+	wrtwarning("free() called before malloc() ever got called\n");
+	return;
+    }
+#endif
+
+#ifdef SANITY
+    if (suicide)
+	PR_Abort();
+#endif
+
+    /* Find the page directory entry for the page in question */
+    page = (u_long)ptr >> malloc_pageshift;
+    index = page - malloc_origo;
+
+    /*
+     * check if memory was allocated by memalign
+     */
+    tmp_index = index;
+    while (page_dir[tmp_index] == MALLOC_FOLLOW)
+	tmp_index--;
+    if (tmp_index != index) {
+	/*
+	 * memalign-allocated memory
+	 */
+	index = tmp_index;
+	page = index + malloc_origo;			
+	ptr = (void *) (page << malloc_pageshift);
+    }
+    /* make sure it makes sense in some fashion */
+    if (index < malloc_pageshift) {
+#ifdef SANITY
+	wrtwarning("junk pointer %p (low) passed to free()\n", ptr);
+#endif
+	return;
+    }
+    if (index > last_index) {
+#ifdef SANITY
+	wrtwarning("junk pointer %p (high) passed to free()\n", ptr);
+#endif
+	return;
+    }
+
+    /* handle as page-allocation or chunk allocation */
+    info = page_dir[index];
+    if (info < MALLOC_MAGIC)
+        free_pages((char*)ptr, page, index, info);
+    else 
+	free_bytes(ptr,page,index,info);
+    return;
+}
+#endif /* _PR_OVERRIDE_MALLOC */
diff --git a/mozilla/nsprpub/pr/src/malloc/prmem.c b/mozilla/nsprpub/pr/src/malloc/prmem.c
new file mode 100644
index 0000000..73fa59b
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/malloc/prmem.c
@@ -0,0 +1,726 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** Thread safe versions of malloc, free, realloc, calloc and cfree.
+*/
+
+#include "primpl.h"
+
+#ifdef _PR_ZONE_ALLOCATOR
+
+/*
+** The zone allocator code must use native mutexes and cannot
+** use PRLocks because PR_NewLock calls PR_Calloc, resulting
+** in cyclic dependency of initialization.
+*/
+
+#include <string.h>	
+
+union memBlkHdrUn;
+
+typedef struct MemoryZoneStr {
+    union memBlkHdrUn    *head;         /* free list */
+    pthread_mutex_t       lock;
+    size_t                blockSize;    /* size of blocks on this free list */
+    PRUint32              locked;       /* current state of lock */
+    PRUint32              contention;   /* counter: had to wait for lock */
+    PRUint32              hits;         /* allocated from free list */
+    PRUint32              misses;       /* had to call malloc */
+    PRUint32              elements;     /* on free list */
+} MemoryZone;
+
+typedef union memBlkHdrUn {
+    unsigned char filler[48];  /* fix the size of this beast */
+    struct memBlkHdrStr {
+        union memBlkHdrUn    *next;
+        MemoryZone           *zone;
+        size_t                blockSize;
+        size_t                requestedSize;
+        PRUint32              magic;
+    } s;
+} MemBlockHdr;
+
+#define MEM_ZONES     7
+#define THREAD_POOLS 11  /* prime number for modulus */
+#define ZONE_MAGIC  0x0BADC0DE
+
+static MemoryZone zones[MEM_ZONES][THREAD_POOLS];
+
+static PRBool use_zone_allocator = PR_FALSE;
+
+static void pr_ZoneFree(void *ptr);
+
+void
+_PR_DestroyZones(void)
+{   
+    int i, j;
+
+    if (!use_zone_allocator)
+        return;
+    
+    for (j = 0; j < THREAD_POOLS; j++) {
+        for (i = 0; i < MEM_ZONES; i++) {
+            MemoryZone *mz = &zones[i][j];
+            pthread_mutex_destroy(&mz->lock);
+            while (mz->head) {
+                MemBlockHdr *hdr = mz->head;
+                mz->head = hdr->s.next;  /* unlink it */
+                free(hdr);
+                mz->elements--;
+            }
+        }
+    } 
+    use_zone_allocator = PR_FALSE;
+} 
+
+/*
+** pr_FindSymbolInProg
+**
+** Find the specified data symbol in the program and return
+** its address.
+*/
+
+#ifdef HAVE_DLL
+
+#ifdef USE_DLFCN
+
+#include <dlfcn.h>
+
+static void *
+pr_FindSymbolInProg(const char *name)
+{
+    void *h;
+    void *sym;
+
+    h = dlopen(0, RTLD_LAZY);
+    if (h == NULL)
+        return NULL;
+    sym = dlsym(h, name);
+    (void)dlclose(h);
+    return sym;
+}
+
+#elif defined(USE_HPSHL)
+
+#include <dl.h>
+
+static void *
+pr_FindSymbolInProg(const char *name)
+{
+    shl_t h = NULL;
+    void *sym;
+
+    if (shl_findsym(&h, name, TYPE_DATA, &sym) == -1)
+        return NULL;
+    return sym;
+}
+
+#elif defined(USE_MACH_DYLD)
+
+static void *
+pr_FindSymbolInProg(const char *name)
+{
+    /* FIXME: not implemented */
+    return NULL;
+}
+
+#else
+
+#error "The zone allocator is not supported on this platform"
+
+#endif
+
+#else /* !defined(HAVE_DLL) */
+
+static void *
+pr_FindSymbolInProg(const char *name)
+{
+    /* can't be implemented */
+    return NULL;
+}
+
+#endif /* HAVE_DLL */
+
+void
+_PR_InitZones(void)
+{
+    int i, j;
+    char *envp;
+    PRBool *sym;
+
+    if ((sym = (PRBool *)pr_FindSymbolInProg("nspr_use_zone_allocator")) != NULL) {
+        use_zone_allocator = *sym;
+    } else if ((envp = getenv("NSPR_USE_ZONE_ALLOCATOR")) != NULL) {
+        use_zone_allocator = (atoi(envp) == 1);
+    }
+
+    if (!use_zone_allocator)
+        return;
+
+    for (j = 0; j < THREAD_POOLS; j++) { 
+        for (i = 0; i < MEM_ZONES; i++) {
+            MemoryZone *mz = &zones[i][j];
+            int rv = pthread_mutex_init(&mz->lock, NULL);
+            PR_ASSERT(0 == rv);
+            if (rv != 0) {
+                goto loser;
+            } 
+            mz->blockSize = 16 << ( 2 * i);
+        }
+    }
+    return;
+
+loser:
+    _PR_DestroyZones();
+    return;
+}
+
+PR_IMPLEMENT(void)
+PR_FPrintZoneStats(PRFileDesc *debug_out)
+{
+    int i, j;
+
+    for (j = 0; j < THREAD_POOLS; j++) {
+        for (i = 0; i < MEM_ZONES; i++) {
+            MemoryZone   *mz   = &zones[i][j];
+            MemoryZone    zone = *mz;
+            if (zone.elements || zone.misses || zone.hits) {
+                PR_fprintf(debug_out,
+"pool: %d, zone: %d, size: %d, free: %d, hit: %d, miss: %d, contend: %d\n",
+                    j, i, zone.blockSize, zone.elements,
+                    zone.hits, zone.misses, zone.contention);
+            }
+	}
+    }
+}
+
+static void *
+pr_ZoneMalloc(PRUint32 size)
+{
+    void         *rv;
+    unsigned int  zone;
+    size_t        blockSize;
+    MemBlockHdr  *mb, *mt;
+    MemoryZone   *mz;
+
+    /* Always allocate a non-zero amount of bytes */
+    if (size < 1) {
+        size = 1;
+    }
+    for (zone = 0, blockSize = 16; zone < MEM_ZONES; ++zone, blockSize <<= 2) {
+        if (size <= blockSize) {
+            break;
+        }
+    }
+    if (zone < MEM_ZONES) {
+        pthread_t me = pthread_self();
+        unsigned int pool = (PRUptrdiff)me % THREAD_POOLS;
+        PRUint32     wasLocked;
+        mz = &zones[zone][pool];
+        wasLocked = mz->locked;
+        pthread_mutex_lock(&mz->lock);
+        mz->locked = 1;
+        if (wasLocked)
+            mz->contention++;
+        if (mz->head) {
+            mb = mz->head;
+            PR_ASSERT(mb->s.magic == ZONE_MAGIC);
+            PR_ASSERT(mb->s.zone  == mz);
+            PR_ASSERT(mb->s.blockSize == blockSize);
+            PR_ASSERT(mz->blockSize == blockSize);
+
+            mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
+            PR_ASSERT(mt->s.magic == ZONE_MAGIC);
+            PR_ASSERT(mt->s.zone  == mz);
+            PR_ASSERT(mt->s.blockSize == blockSize);
+
+            mz->hits++;
+            mz->elements--;
+            mz->head = mb->s.next;    /* take off free list */
+            mz->locked = 0;
+            pthread_mutex_unlock(&mz->lock);
+
+            mt->s.next          = mb->s.next          = NULL;
+            mt->s.requestedSize = mb->s.requestedSize = size;
+
+            rv = (void *)(mb + 1);
+            return rv;
+        }
+
+        mz->misses++;
+        mz->locked = 0;
+        pthread_mutex_unlock(&mz->lock);
+
+        mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
+        if (!mb) {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return NULL;
+        }
+        mb->s.next          = NULL;
+        mb->s.zone          = mz;
+        mb->s.magic         = ZONE_MAGIC;
+        mb->s.blockSize     = blockSize;
+        mb->s.requestedSize = size;
+
+        mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
+        memcpy(mt, mb, sizeof *mb);
+
+        rv = (void *)(mb + 1);
+        return rv;
+    }
+
+    /* size was too big.  Create a block with no zone */
+    blockSize = (size & 15) ? size + 16 - (size & 15) : size;
+    mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
+    if (!mb) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+    mb->s.next          = NULL;
+    mb->s.zone          = NULL;
+    mb->s.magic         = ZONE_MAGIC;
+    mb->s.blockSize     = blockSize;
+    mb->s.requestedSize = size;
+
+    mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
+    memcpy(mt, mb, sizeof *mb);
+
+    rv = (void *)(mb + 1);
+    return rv;
+}
+
+
+static void *
+pr_ZoneCalloc(PRUint32 nelem, PRUint32 elsize)
+{
+    PRUint32 size = nelem * elsize;
+    void *p = pr_ZoneMalloc(size);
+    if (p) {
+        memset(p, 0, size);
+    }
+    return p;
+}
+
+static void *
+pr_ZoneRealloc(void *oldptr, PRUint32 bytes)
+{
+    void         *rv;
+    MemBlockHdr  *mb;
+    int           ours;
+    MemBlockHdr   phony;
+
+    if (!oldptr)
+        return pr_ZoneMalloc(bytes);
+    mb = (MemBlockHdr *)((char *)oldptr - (sizeof *mb));
+    if (mb->s.magic != ZONE_MAGIC) {
+        /* Maybe this just came from ordinary malloc */
+#ifdef DEBUG
+        fprintf(stderr,
+            "Warning: reallocing memory block %p from ordinary malloc\n",
+            oldptr);
+#endif
+        /*
+         * We are going to realloc oldptr.  If realloc succeeds, the
+         * original value of oldptr will point to freed memory.  So this
+         * function must not fail after a successfull realloc call.  We
+         * must perform any operation that may fail before the realloc
+         * call.
+         */
+        rv = pr_ZoneMalloc(bytes);  /* this may fail */
+        if (!rv) {
+            return rv;
+        }
+
+        /* We don't know how big it is.  But we can fix that. */
+        oldptr = realloc(oldptr, bytes);
+        /*
+         * If realloc returns NULL, this function loses the original
+         * value of oldptr.  This isn't a leak because the caller of
+         * this function still has the original value of oldptr.
+         */
+        if (!oldptr) {
+            if (bytes) {
+                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+                pr_ZoneFree(rv);
+                return oldptr;
+            }
+        }
+        phony.s.requestedSize = bytes;
+        mb = &phony;
+        ours = 0;
+    } else {
+        size_t blockSize = mb->s.blockSize;
+        MemBlockHdr *mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
+
+        PR_ASSERT(mt->s.magic == ZONE_MAGIC);
+        PR_ASSERT(mt->s.zone  == mb->s.zone);
+        PR_ASSERT(mt->s.blockSize == blockSize);
+	
+        if (bytes <= blockSize) {
+            /* The block is already big enough. */
+            mt->s.requestedSize = mb->s.requestedSize = bytes;
+            return oldptr;
+        }
+        ours = 1;
+        rv = pr_ZoneMalloc(bytes);
+        if (!rv) {
+            return rv;
+        }
+    }
+    
+    if (oldptr && mb->s.requestedSize)
+        memcpy(rv, oldptr, mb->s.requestedSize);
+    if (ours)
+        pr_ZoneFree(oldptr);
+    else if (oldptr)
+        free(oldptr);
+    return rv;
+}
+
+static void
+pr_ZoneFree(void *ptr)
+{
+    MemBlockHdr  *mb, *mt;
+    MemoryZone   *mz;
+    size_t        blockSize;
+    PRUint32      wasLocked;
+
+    if (!ptr)
+        return;
+
+    mb = (MemBlockHdr *)((char *)ptr - (sizeof *mb));
+
+    if (mb->s.magic != ZONE_MAGIC) {
+        /* maybe this came from ordinary malloc */
+#ifdef DEBUG
+        fprintf(stderr,
+            "Warning: freeing memory block %p from ordinary malloc\n", ptr);
+#endif
+        free(ptr);
+        return;
+    }
+
+    blockSize = mb->s.blockSize;
+    mz        = mb->s.zone;
+    mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
+    PR_ASSERT(mt->s.magic == ZONE_MAGIC);
+    PR_ASSERT(mt->s.zone  == mz);
+    PR_ASSERT(mt->s.blockSize == blockSize);
+    if (!mz) {
+        PR_ASSERT(blockSize > 65536);
+        /* This block was not in any zone.  Just free it. */
+        free(mb);
+        return;
+    }
+    PR_ASSERT(mz->blockSize == blockSize);
+    wasLocked = mz->locked;
+    pthread_mutex_lock(&mz->lock);
+    mz->locked = 1;
+    if (wasLocked)
+        mz->contention++;
+    mt->s.next = mb->s.next = mz->head;        /* put on head of list */
+    mz->head = mb;
+    mz->elements++;
+    mz->locked = 0;
+    pthread_mutex_unlock(&mz->lock);
+}
+
+PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    return use_zone_allocator ? pr_ZoneMalloc(size) : malloc(size);
+}
+
+PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    return use_zone_allocator ?
+        pr_ZoneCalloc(nelem, elsize) : calloc(nelem, elsize);
+}
+
+PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : realloc(ptr, size);
+}
+
+PR_IMPLEMENT(void) PR_Free(void *ptr)
+{
+    if (use_zone_allocator)
+        pr_ZoneFree(ptr);
+    else
+        free(ptr);
+}
+
+#else /* !defined(_PR_ZONE_ALLOCATOR) */
+
+/*
+** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply
+** call their libc equivalents now.  This may seem redundant, but it
+** ensures that we are calling into the same runtime library.  On
+** Win32, it is possible to have multiple runtime libraries (e.g.,
+** objects compiled with /MD and /MDd) in the same process, and
+** they maintain separate heaps, which cannot be mixed.
+*/
+PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
+{
+#if defined (WIN16)
+    return PR_MD_malloc( (size_t) size);
+#else
+    return malloc(size);
+#endif
+}
+
+PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
+{
+#if defined (WIN16)
+    return PR_MD_calloc( (size_t)nelem, (size_t)elsize );
+    
+#else
+    return calloc(nelem, elsize);
+#endif
+}
+
+PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
+{
+#if defined (WIN16)
+    return PR_MD_realloc( ptr, (size_t) size);
+#else
+    return realloc(ptr, size);
+#endif
+}
+
+PR_IMPLEMENT(void) PR_Free(void *ptr)
+{
+#if defined (WIN16)
+    PR_MD_free( ptr );
+#else
+    free(ptr);
+#endif
+}
+
+#endif /* _PR_ZONE_ALLOCATOR */
+
+/*
+** Complexity alert!
+**
+** If malloc/calloc/free (etc.) were implemented to use pr lock's then
+** the entry points could block when called if some other thread had the
+** lock.
+**
+** Most of the time this isn't a problem. However, in the case that we
+** are using the thread safe malloc code after PR_Init but before
+** PR_AttachThread has been called (on a native thread that nspr has yet
+** to be told about) we could get royally screwed if the lock was busy
+** and we tried to context switch the thread away. In this scenario
+** 	PR_CURRENT_THREAD() == NULL
+**
+** To avoid this unfortunate case, we use the low level locking
+** facilities for malloc protection instead of the slightly higher level
+** locking. This makes malloc somewhat faster so maybe it's a good thing
+** anyway.
+*/
+#ifdef _PR_OVERRIDE_MALLOC
+
+/* Imports */
+extern void *_PR_UnlockedMalloc(size_t size);
+extern void *_PR_UnlockedMemalign(size_t alignment, size_t size);
+extern void _PR_UnlockedFree(void *ptr);
+extern void *_PR_UnlockedRealloc(void *ptr, size_t size);
+extern void *_PR_UnlockedCalloc(size_t n, size_t elsize);
+
+static PRBool _PR_malloc_initialised = PR_FALSE;
+
+#ifdef _PR_PTHREADS
+static pthread_mutex_t _PR_MD_malloc_crustylock;
+
+#define _PR_Lock_Malloc() {						\
+    				if(PR_TRUE == _PR_malloc_initialised) { \
+					PRStatus rv;			\
+					rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \
+					PR_ASSERT(0 == rv);		\
+				}
+
+#define _PR_Unlock_Malloc() 	if(PR_TRUE == _PR_malloc_initialised) { \
+					PRStatus rv;			\
+					rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \
+					PR_ASSERT(0 == rv);		\
+				}					\
+			  }
+#else /* _PR_PTHREADS */
+static _MDLock _PR_MD_malloc_crustylock;
+
+#ifdef IRIX
+#define _PR_Lock_Malloc() {						\
+			   PRIntn _is;					\
+    				if(PR_TRUE == _PR_malloc_initialised) { \
+				if (_PR_MD_GET_ATTACHED_THREAD() && 		\
+					!_PR_IS_NATIVE_THREAD( 		\
+					_PR_MD_GET_ATTACHED_THREAD()))	\
+						_PR_INTSOFF(_is); 	\
+					_PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
+				}
+
+#define _PR_Unlock_Malloc() 	if(PR_TRUE == _PR_malloc_initialised) { \
+					_PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
+				if (_PR_MD_GET_ATTACHED_THREAD() && 		\
+					!_PR_IS_NATIVE_THREAD( 		\
+					_PR_MD_GET_ATTACHED_THREAD()))	\
+						_PR_INTSON(_is);	\
+				}					\
+			  }
+#else	/* IRIX */
+#define _PR_Lock_Malloc() {						\
+			   PRIntn _is;					\
+    				if(PR_TRUE == _PR_malloc_initialised) { \
+				if (_PR_MD_CURRENT_THREAD() && 		\
+					!_PR_IS_NATIVE_THREAD( 		\
+					_PR_MD_CURRENT_THREAD()))	\
+						_PR_INTSOFF(_is); 	\
+					_PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
+				}
+
+#define _PR_Unlock_Malloc() 	if(PR_TRUE == _PR_malloc_initialised) { \
+					_PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
+				if (_PR_MD_CURRENT_THREAD() && 		\
+					!_PR_IS_NATIVE_THREAD( 		\
+					_PR_MD_CURRENT_THREAD()))	\
+						_PR_INTSON(_is);	\
+				}					\
+			  }
+#endif	/* IRIX	*/
+#endif /* _PR_PTHREADS */
+
+PR_IMPLEMENT(PRStatus) _PR_MallocInit(void)
+{
+    PRStatus rv = PR_SUCCESS;
+
+    if( PR_TRUE == _PR_malloc_initialised ) return PR_SUCCESS;
+
+#ifdef _PR_PTHREADS
+    {
+	int status;
+	pthread_mutexattr_t mattr;
+
+	status = _PT_PTHREAD_MUTEXATTR_INIT(&mattr);
+	PR_ASSERT(0 == status);
+	status = _PT_PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr);
+	PR_ASSERT(0 == status);
+	status = _PT_PTHREAD_MUTEXATTR_DESTROY(&mattr);
+	PR_ASSERT(0 == status);
+    }
+#else /* _PR_PTHREADS */
+    _MD_NEW_LOCK(&_PR_MD_malloc_crustylock);
+#endif /* _PR_PTHREADS */
+
+    if( PR_SUCCESS == rv )
+    {
+        _PR_malloc_initialised = PR_TRUE;
+    }
+
+    return rv;
+}
+
+void *malloc(size_t size)
+{
+    void *p;
+    _PR_Lock_Malloc();
+    p = _PR_UnlockedMalloc(size);
+    _PR_Unlock_Malloc();
+    return p;
+}
+
+#if defined(IRIX)
+void *memalign(size_t alignment, size_t size)
+{
+    void *p;
+    _PR_Lock_Malloc();
+    p = _PR_UnlockedMemalign(alignment, size);
+    _PR_Unlock_Malloc();
+    return p;
+}
+
+void *valloc(size_t size)
+{
+    return(memalign(sysconf(_SC_PAGESIZE),size));
+}
+#endif	/* IRIX */
+
+void free(void *ptr)
+{
+    _PR_Lock_Malloc();
+    _PR_UnlockedFree(ptr);
+    _PR_Unlock_Malloc();
+}
+
+void *realloc(void *ptr, size_t size)
+{
+    void *p;
+    _PR_Lock_Malloc();
+    p = _PR_UnlockedRealloc(ptr, size);
+    _PR_Unlock_Malloc();
+    return p;
+}
+
+void *calloc(size_t n, size_t elsize)
+{
+    void *p;
+    _PR_Lock_Malloc();
+    p = _PR_UnlockedCalloc(n, elsize);
+    _PR_Unlock_Malloc();
+    return p;
+}
+
+void cfree(void *p)
+{
+    _PR_Lock_Malloc();
+    _PR_UnlockedFree(p);
+    _PR_Unlock_Malloc();
+}
+
+void _PR_InitMem(void)
+{
+    PRStatus rv;
+    rv = _PR_MallocInit();
+    PR_ASSERT(PR_SUCCESS == rv);
+}
+
+#endif /* _PR_OVERRIDE_MALLOC */
diff --git a/mozilla/nsprpub/pr/src/md/prosdep.c b/mozilla/nsprpub/pr/src/md/prosdep.c
new file mode 100644
index 0000000..d80256a
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/prosdep.c
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "prbit.h"
+#include "prsystem.h"
+
+#ifdef XP_UNIX
+#include <unistd.h>
+#endif
+#ifdef SUNOS4
+#include "md/sunos4.h"
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif 
+#ifdef XP_BEOS
+#include <OS.h>
+#endif
+
+PRInt32 _pr_pageShift;
+PRInt32 _pr_pageSize;
+
+/*
+** Get system page size
+*/
+static void GetPageSize(void)
+{
+	PRInt32 pageSize;
+
+    /* Get page size */
+#ifdef XP_UNIX
+#if defined SUNOS4 || defined BSDI || defined AIX \
+        || defined LINUX || defined __GNU__ || defined __GLIBC__ \
+        || defined FREEBSD || defined NETBSD || defined OPENBSD \
+        || defined DARWIN || defined NEXTSTEP || defined SYMBIAN
+    _pr_pageSize = getpagesize();
+#elif defined(HPUX)
+    /* I have no idea. Don't get me started. --Rob */
+    _pr_pageSize = sysconf(_SC_PAGE_SIZE);
+#else
+    _pr_pageSize = sysconf(_SC_PAGESIZE);
+#endif
+#endif /* XP_UNIX */
+
+#ifdef XP_BEOS
+    _pr_pageSize = B_PAGE_SIZE;
+#endif
+
+#ifdef XP_PC
+#ifdef _WIN32
+    SYSTEM_INFO info;
+    GetSystemInfo(&info);
+    _pr_pageSize = info.dwPageSize;
+#else
+    _pr_pageSize = 4096;
+#endif
+#endif /* XP_PC */
+
+	pageSize = _pr_pageSize;
+	PR_CEILING_LOG2(_pr_pageShift, pageSize);
+}
+
+PR_IMPLEMENT(PRInt32) PR_GetPageShift(void)
+{
+    if (!_pr_pageSize) {
+	GetPageSize();
+    }
+    return _pr_pageShift;
+}
+
+PR_IMPLEMENT(PRInt32) PR_GetPageSize(void)
+{
+    if (!_pr_pageSize) {
+	GetPageSize();
+    }
+    return _pr_pageSize;
+}
diff --git a/mozilla/nsprpub/pr/src/md/unix/darwin.c b/mozilla/nsprpub/pr/src/md/unix/darwin.c
new file mode 100644
index 0000000..3a1329e
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/darwin.c
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+void _MD_EarlyInit(void)
+{
+}
+
+PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
+{
+#if !defined(_PR_PTHREADS)
+    if (isCurrent) {
+	(void) setjmp(CONTEXT(t));
+    }
+    *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
+    return (PRWord *) CONTEXT(t);
+#else
+	*np = 0;
+	return NULL;
+#endif
+}
+
+#if !defined(_PR_PTHREADS)
+void
+_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri)
+{
+    return;
+}
+
+PRStatus
+_MD_InitializeThread(PRThread *thread)
+{
+	return PR_SUCCESS;
+}
+
+PRStatus
+_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
+{
+    PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
+    _PR_MD_SWITCH_CONTEXT(thread);
+    return PR_SUCCESS;
+}
+
+PRStatus
+_MD_WAKEUP_WAITER(PRThread *thread)
+{
+    if (thread) {
+	PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
+    }
+    return PR_SUCCESS;
+}
+
+/* These functions should not be called for Darwin */
+void
+_MD_YIELD(void)
+{
+    PR_NOT_REACHED("_MD_YIELD should not be called for Darwin.");
+}
+
+PRStatus
+_MD_CREATE_THREAD(
+    PRThread *thread,
+    void (*start) (void *),
+    PRThreadPriority priority,
+    PRThreadScope scope,
+    PRThreadState state,
+    PRUint32 stackSize)
+{
+    PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Darwin.");
+	return PR_FAILURE;
+}
+#endif /* ! _PR_PTHREADS */
+
+/* darwin.c */
+
diff --git a/mozilla/nsprpub/pr/src/md/unix/os_Darwin.s b/mozilla/nsprpub/pr/src/md/unix/os_Darwin.s
new file mode 100644
index 0000000..ce2cc0b
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/os_Darwin.s
@@ -0,0 +1,45 @@
+# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+#
+# ***** 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 Portable Runtime (NSPR).
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# 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 *****
+
+#ifdef __i386__
+#include "os_Darwin_x86.s"
+#elif defined(__x86_64__)
+#include "os_Darwin_x86_64.s"
+#elif defined(__ppc__)
+#include "os_Darwin_ppc.s"
+#endif
diff --git a/mozilla/nsprpub/pr/src/md/unix/os_Darwin_ppc.s b/mozilla/nsprpub/pr/src/md/unix/os_Darwin_ppc.s
new file mode 100644
index 0000000..4b61fb4
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/os_Darwin_ppc.s
@@ -0,0 +1,96 @@
+# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+#
+# ***** 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 Portable Runtime (NSPR).
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# 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 *****
+
+#
+# Based on the programming examples in The PowerPC Architecture:
+# A Specification for A New Family of RISC Processors, 2nd Ed.,
+# Book I, Section E.1, "Synchronization," pp. 249-256, May 1994.
+#
+
+.text
+
+#
+# PRInt32 __PR_DarwinPPC_AtomicIncrement(PRInt32 *val);
+#
+        .align  2
+        .globl  __PR_DarwinPPC_AtomicIncrement
+__PR_DarwinPPC_AtomicIncrement:
+        lwarx   r4,0,r3
+        addi    r0,r4,1
+        stwcx.  r0,0,r3
+        bne-    __PR_DarwinPPC_AtomicIncrement
+        mr      r3,r0
+        blr
+
+#
+# PRInt32 __PR_DarwinPPC_AtomicDecrement(PRInt32 *val);
+#
+        .align  2
+        .globl  __PR_DarwinPPC_AtomicDecrement
+__PR_DarwinPPC_AtomicDecrement:
+        lwarx   r4,0,r3
+        addi    r0,r4,-1
+        stwcx.  r0,0,r3
+        bne-    __PR_DarwinPPC_AtomicDecrement
+        mr      r3,r0
+        blr
+
+#
+# PRInt32 __PR_DarwinPPC_AtomicSet(PRInt32 *val, PRInt32 newval);
+#
+        .align  2
+        .globl  __PR_DarwinPPC_AtomicSet
+__PR_DarwinPPC_AtomicSet:
+        lwarx   r5,0,r3
+        stwcx.  r4,0,r3
+        bne-    __PR_DarwinPPC_AtomicSet
+        mr      r3,r5
+        blr
+
+#
+# PRInt32 __PR_DarwinPPC_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+#
+        .align  2
+        .globl  __PR_DarwinPPC_AtomicAdd
+__PR_DarwinPPC_AtomicAdd:
+        lwarx   r5,0,r3
+        add     r0,r4,r5
+        stwcx.  r0,0,r3
+        bne-    __PR_DarwinPPC_AtomicAdd
+        mr      r3,r0
+        blr
diff --git a/mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86.s b/mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86.s
new file mode 100644
index 0000000..276b16e
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86.s
@@ -0,0 +1,109 @@
+# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+#
+# ***** 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 Portable Runtime (NSPR).
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Josh Aas <josh@mozilla.com>
+#
+# 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 *****
+
+#
+# Based on os_Linux_x86.s
+#
+
+#
+# PRInt32 __PR_Darwin_x86_AtomicIncrement(PRInt32 *val);
+#
+# Atomically increment the integer pointed to by 'val' and return
+# the result of the increment.
+#
+    .text
+    .globl __PR_Darwin_x86_AtomicIncrement
+    .align 4
+__PR_Darwin_x86_AtomicIncrement:
+    movl 4(%esp), %ecx
+    movl $1, %eax
+    lock
+    xaddl %eax, (%ecx)
+    incl %eax
+    ret
+
+#
+# PRInt32 __PR_Darwin_x86_AtomicDecrement(PRInt32 *val);
+#
+# Atomically decrement the integer pointed to by 'val' and return
+# the result of the decrement.
+#
+    .text
+    .globl __PR_Darwin_x86_AtomicDecrement
+    .align 4
+__PR_Darwin_x86_AtomicDecrement:
+    movl 4(%esp), %ecx
+    movl $-1, %eax
+    lock
+    xaddl %eax, (%ecx)
+    decl %eax
+    ret
+
+#
+# PRInt32 __PR_Darwin_x86_AtomicSet(PRInt32 *val, PRInt32 newval);
+#
+# Atomically set the integer pointed to by 'val' to the new
+# value 'newval' and return the old value.
+#
+    .text
+    .globl __PR_Darwin_x86_AtomicSet
+    .align 4
+__PR_Darwin_x86_AtomicSet:
+    movl 4(%esp), %ecx
+    movl 8(%esp), %eax
+    xchgl %eax, (%ecx)
+    ret
+
+#
+# PRInt32 __PR_Darwin_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+#
+# Atomically add 'val' to the integer pointed to by 'ptr'
+# and return the result of the addition.
+#
+    .text
+    .globl __PR_Darwin_x86_AtomicAdd
+    .align 4
+__PR_Darwin_x86_AtomicAdd:
+    movl 4(%esp), %ecx
+    movl 8(%esp), %eax
+    movl %eax, %edx
+    lock
+    xaddl %eax, (%ecx)
+    addl %edx, %eax
+    ret
diff --git a/mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86_64.s b/mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86_64.s
new file mode 100644
index 0000000..031186f
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86_64.s
@@ -0,0 +1,95 @@
+# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+# 
+# ***** 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 Portable Runtime (NSPR).
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# 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 *****
+
+# PRInt32 __PR_Darwin_x86_64_AtomicIncrement(PRInt32 *val)
+#
+# Atomically increment the integer pointed to by 'val' and return
+# the result of the increment.
+#
+    .text
+    .globl __PR_Darwin_x86_64_AtomicIncrement
+    .align 4
+__PR_Darwin_x86_64_AtomicIncrement:
+    movl $1, %eax
+    lock
+    xaddl %eax, (%rdi)
+    incl %eax
+    ret
+
+# PRInt32 __PR_Darwin_x86_64_AtomicDecrement(PRInt32 *val)
+#
+# Atomically decrement the integer pointed to by 'val' and return
+# the result of the decrement.
+#
+    .text
+    .globl __PR_Darwin_x86_64_AtomicDecrement
+    .align 4
+__PR_Darwin_x86_64_AtomicDecrement:
+    movl $-1, %eax
+    lock
+    xaddl %eax, (%rdi)
+    decl %eax
+    ret
+
+# PRInt32 __PR_Darwin_x86_64_AtomicSet(PRInt32 *val, PRInt32 newval)
+#
+# Atomically set the integer pointed to by 'val' to the new
+# value 'newval' and return the old value.
+#
+    .text
+    .globl __PR_Darwin_x86_64_AtomicSet
+    .align 4
+__PR_Darwin_x86_64_AtomicSet:
+    movl %esi, %eax
+    xchgl %eax, (%rdi)
+    ret
+
+# PRInt32 __PR_Darwin_x86_64_AtomicAdd(PRInt32 *ptr, PRInt32 val)
+#
+# Atomically add 'val' to the integer pointed to by 'ptr'
+# and return the result of the addition.
+#
+    .text
+    .globl __PR_Darwin_x86_64_AtomicAdd
+    .align 4
+__PR_Darwin_x86_64_AtomicAdd:
+    movl %esi, %eax
+    lock
+    xaddl %eax, (%rdi)
+    addl %esi, %eax
+    ret
diff --git a/mozilla/nsprpub/pr/src/md/unix/unix.c b/mozilla/nsprpub/pr/src/md/unix/unix.c
new file mode 100644
index 0000000..7c07459
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/unix.c
@@ -0,0 +1,3744 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+#ifdef _PR_POLL_AVAILABLE
+#include <poll.h>
+#endif
+
+/* To get FIONREAD */
+#if defined(NCR) || defined(UNIXWARE) || defined(NEC) || defined(SNI) \
+        || defined(SONY)
+#include <sys/filio.h>
+#endif
+
+#if defined(NTO)
+#include <sys/statvfs.h>
+#endif
+
+/*
+ * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
+ * PRInt32* pointer to a _PRSockLen_t* pointer.
+ */
+#if defined(HAVE_SOCKLEN_T) \
+    || (defined(__GLIBC__) && __GLIBC__ >= 2)
+#define _PRSockLen_t socklen_t
+#elif defined(IRIX) || defined(HPUX) || defined(OSF1) || defined(SOLARIS) \
+    || defined(AIX4_1) || defined(LINUX) || defined(SONY) \
+    || defined(BSDI) || defined(SCO) || defined(NEC) || defined(SNI) \
+    || defined(SUNOS4) || defined(NCR) || defined(DARWIN) \
+    || defined(NEXTSTEP) || defined(QNX)
+#define _PRSockLen_t int
+#elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \
+    || defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) \
+    || defined(DGUX) || defined(NTO) || defined(RISCOS)
+#define _PRSockLen_t size_t
+#else
+#error "Cannot determine architecture"
+#endif
+
+/*
+** Global lock variable used to bracket calls into rusty libraries that
+** aren't thread safe (like libc, libX, etc).
+*/
+static PRLock *_pr_rename_lock = NULL;
+static PRMonitor *_pr_Xfe_mon = NULL;
+
+static PRInt64 minus_one;
+
+sigset_t timer_set;
+
+#if !defined(_PR_PTHREADS)
+
+static sigset_t empty_set;
+
+#ifdef SOLARIS
+#include <sys/file.h>
+#include <sys/filio.h>
+#endif
+
+#ifndef PIPE_BUF
+#define PIPE_BUF 512
+#endif
+
+/*
+ * _nspr_noclock - if set clock interrupts are disabled
+ */
+int _nspr_noclock = 1;
+
+#ifdef IRIX
+extern PRInt32 _nspr_terminate_on_error;
+#endif
+
+/*
+ * There is an assertion in this code that NSPR's definition of PRIOVec
+ * is bit compatible with UNIX' definition of a struct iovec. This is
+ * applicable to the 'writev()' operations where the types are casually
+ * cast to avoid warnings.
+ */
+
+int _pr_md_pipefd[2] = { -1, -1 };
+static char _pr_md_pipebuf[PIPE_BUF];
+static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag,
+							PRIntervalTime timeout);
+
+_PRInterruptTable _pr_interruptTable[] = {
+    { 
+        "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt,     },
+    { 
+        0     }
+};
+
+void _MD_unix_init_running_cpu(_PRCPU *cpu)
+{
+    PR_INIT_CLIST(&(cpu->md.md_unix.ioQ));
+    cpu->md.md_unix.ioq_max_osfd = -1;
+    cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT;
+}
+
+PRStatus _MD_open_dir(_MDDir *d, const char *name)
+{
+int err;
+
+    d->d = opendir(name);
+    if (!d->d) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_OPENDIR_ERROR(err);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PRInt32 _MD_close_dir(_MDDir *d)
+{
+int rv = 0, err;
+
+    if (d->d) {
+        rv = closedir(d->d);
+        if (rv == -1) {
+                err = _MD_ERRNO();
+                _PR_MD_MAP_CLOSEDIR_ERROR(err);
+        }
+    }
+    return rv;
+}
+
+char * _MD_read_dir(_MDDir *d, PRIntn flags)
+{
+struct dirent *de;
+int err;
+
+    for (;;) {
+        /*
+          * XXX: readdir() is not MT-safe. There is an MT-safe version
+          * readdir_r() on some systems.
+          */
+        _MD_ERRNO() = 0;
+        de = readdir(d->d);
+        if (!de) {
+            err = _MD_ERRNO();
+            _PR_MD_MAP_READDIR_ERROR(err);
+            return 0;
+        }        
+        if ((flags & PR_SKIP_DOT) &&
+            (de->d_name[0] == '.') && (de->d_name[1] == 0))
+            continue;
+        if ((flags & PR_SKIP_DOT_DOT) &&
+            (de->d_name[0] == '.') && (de->d_name[1] == '.') &&
+            (de->d_name[2] == 0))
+            continue;
+        if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.'))
+            continue;
+        break;
+    }
+    return de->d_name;
+}
+
+PRInt32 _MD_delete(const char *name)
+{
+PRInt32 rv, err;
+#ifdef UNIXWARE
+    sigset_t set, oset;
+#endif
+
+#ifdef UNIXWARE
+    sigfillset(&set);
+    sigprocmask(SIG_SETMASK, &set, &oset);
+#endif
+    rv = unlink(name);
+#ifdef UNIXWARE
+    sigprocmask(SIG_SETMASK, &oset, NULL);
+#endif
+    if (rv == -1) {
+            err = _MD_ERRNO();
+            _PR_MD_MAP_UNLINK_ERROR(err);
+    }
+    return(rv);
+}
+
+PRInt32 _MD_rename(const char *from, const char *to)
+{
+    PRInt32 rv = -1, err;
+
+    /*
+    ** This is trying to enforce the semantics of WINDOZE' rename
+    ** operation. That means one is not allowed to rename over top
+    ** of an existing file. Holding a lock across these two function
+    ** and the open function is known to be a bad idea, but ....
+    */
+    if (NULL != _pr_rename_lock)
+        PR_Lock(_pr_rename_lock);
+    if (0 == access(to, F_OK))
+        PR_SetError(PR_FILE_EXISTS_ERROR, 0);
+    else
+    {
+        rv = rename(from, to);
+        if (rv < 0) {
+            err = _MD_ERRNO();
+            _PR_MD_MAP_RENAME_ERROR(err);
+        }
+    }
+    if (NULL != _pr_rename_lock)
+        PR_Unlock(_pr_rename_lock);
+    return rv;
+}
+
+PRInt32 _MD_access(const char *name, PRAccessHow how)
+{
+PRInt32 rv, err;
+int amode;
+
+    switch (how) {
+        case PR_ACCESS_WRITE_OK:
+            amode = W_OK;
+            break;
+        case PR_ACCESS_READ_OK:
+            amode = R_OK;
+            break;
+        case PR_ACCESS_EXISTS:
+            amode = F_OK;
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = -1;
+            goto done;
+    }
+    rv = access(name, amode);
+
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_ACCESS_ERROR(err);
+    }
+
+done:
+    return(rv);
+}
+
+PRInt32 _MD_mkdir(const char *name, PRIntn mode)
+{
+int rv, err;
+
+    /*
+    ** This lock is used to enforce rename semantics as described
+    ** in PR_Rename. Look there for more fun details.
+    */
+    if (NULL !=_pr_rename_lock)
+        PR_Lock(_pr_rename_lock);
+    rv = mkdir(name, mode);
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_MKDIR_ERROR(err);
+    }
+    if (NULL !=_pr_rename_lock)
+        PR_Unlock(_pr_rename_lock);
+    return rv;
+}
+
+PRInt32 _MD_rmdir(const char *name)
+{
+int rv, err;
+
+    rv = rmdir(name);
+    if (rv == -1) {
+            err = _MD_ERRNO();
+            _PR_MD_MAP_RMDIR_ERROR(err);
+    }
+    return rv;
+}
+
+PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+PRThread *me = _PR_MD_CURRENT_THREAD();
+PRInt32 rv, err;
+#ifndef _PR_USE_POLL
+fd_set rd;
+#else
+struct pollfd pfd;
+#endif /* _PR_USE_POLL */
+PRInt32 osfd = fd->secret->md.osfd;
+
+#ifndef _PR_USE_POLL
+    FD_ZERO(&rd);
+    FD_SET(osfd, &rd);
+#else
+    pfd.fd = osfd;
+    pfd.events = POLLIN;
+#endif /* _PR_USE_POLL */
+    while ((rv = read(osfd,buf,amount)) == -1) {
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+                if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ,
+										PR_INTERVAL_NO_TIMEOUT)) < 0)
+					goto done;								
+            } else {
+#ifndef _PR_USE_POLL
+                while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL))
+                        == -1 && (err = _MD_ERRNO()) == EINTR) {
+                    /* retry _MD_SELECT() if it is interrupted */
+                }
+#else /* _PR_USE_POLL */
+                while ((rv = _MD_POLL(&pfd, 1, -1))
+                        == -1 && (err = _MD_ERRNO()) == EINTR) {
+                    /* retry _MD_POLL() if it is interrupted */
+                }
+#endif /* _PR_USE_POLL */
+                if (rv == -1) {
+                    break;
+                }
+            }
+            if (_PR_PENDING_INTERRUPT(me))
+                break;
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+    if (rv < 0) {
+        if (_PR_PENDING_INTERRUPT(me)) {
+            me->flags &= ~_PR_INTERRUPT;
+            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        } else {
+            _PR_MD_MAP_READ_ERROR(err);
+        }
+    }
+done:
+    return(rv);
+}
+
+PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+PRThread *me = _PR_MD_CURRENT_THREAD();
+PRInt32 rv, err;
+#ifndef _PR_USE_POLL
+fd_set wd;
+#else
+struct pollfd pfd;
+#endif /* _PR_USE_POLL */
+PRInt32 osfd = fd->secret->md.osfd;
+
+#ifndef _PR_USE_POLL
+    FD_ZERO(&wd);
+    FD_SET(osfd, &wd);
+#else
+    pfd.fd = osfd;
+    pfd.events = POLLOUT;
+#endif /* _PR_USE_POLL */
+    while ((rv = write(osfd,buf,amount)) == -1) {
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+                if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE,
+										PR_INTERVAL_NO_TIMEOUT)) < 0)
+                    goto done;
+            } else {
+#ifndef _PR_USE_POLL
+                while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL))
+                        == -1 && (err = _MD_ERRNO()) == EINTR) {
+                    /* retry _MD_SELECT() if it is interrupted */
+                }
+#else /* _PR_USE_POLL */
+                while ((rv = _MD_POLL(&pfd, 1, -1))
+                        == -1 && (err = _MD_ERRNO()) == EINTR) {
+                    /* retry _MD_POLL() if it is interrupted */
+                }
+#endif /* _PR_USE_POLL */
+                if (rv == -1) {
+                    break;
+                }
+            }
+            if (_PR_PENDING_INTERRUPT(me))
+                break;
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+    if (rv < 0) {
+        if (_PR_PENDING_INTERRUPT(me)) {
+            me->flags &= ~_PR_INTERRUPT;
+            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        } else {
+            _PR_MD_MAP_WRITE_ERROR(err);
+        }
+    }
+done:
+    return(rv);
+}
+
+PRInt32 _MD_fsync(PRFileDesc *fd)
+{
+PRInt32 rv, err;
+
+    rv = fsync(fd->secret->md.osfd);
+    if (rv == -1) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_FSYNC_ERROR(err);
+    }
+    return(rv);
+}
+
+PRInt32 _MD_close(PRInt32 osfd)
+{
+PRInt32 rv, err;
+
+    rv = close(osfd);
+    if (rv == -1) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_CLOSE_ERROR(err);
+    }
+    return(rv);
+}
+
+PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
+{
+    PRInt32 osfd, err;
+
+    osfd = socket(domain, type, proto);
+
+    if (osfd == -1) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_SOCKET_ERROR(err);
+        return(osfd);
+    }
+
+    return(osfd);
+}
+
+PRInt32 _MD_socketavailable(PRFileDesc *fd)
+{
+    PRInt32 result;
+
+    if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) {
+        _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO());
+        return -1;
+    }
+    return result;
+}
+
+PRInt64 _MD_socketavailable64(PRFileDesc *fd)
+{
+    PRInt64 result;
+    LL_I2L(result, _MD_socketavailable(fd));
+    return result;
+}  /* _MD_socketavailable64 */
+
+#define READ_FD        1
+#define WRITE_FD    2
+
+/*
+ * socket_io_wait --
+ *
+ * wait for socket i/o, periodically checking for interrupt
+ *
+ * The first implementation uses select(), for platforms without
+ * poll().  The second (preferred) implementation uses poll().
+ */
+
+#ifndef _PR_USE_POLL
+
+static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
+    PRIntervalTime timeout)
+{
+    PRInt32 rv = -1;
+    struct timeval tv;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRIntervalTime epoch, now, elapsed, remaining;
+    PRBool wait_for_remaining;
+    PRInt32 syserror;
+    fd_set rd_wr;
+
+    switch (timeout) {
+        case PR_INTERVAL_NO_WAIT:
+            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+            break;
+        case PR_INTERVAL_NO_TIMEOUT:
+            /*
+             * This is a special case of the 'default' case below.
+             * Please see the comments there.
+             */
+            tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
+            tv.tv_usec = 0;
+            FD_ZERO(&rd_wr);
+            do {
+                FD_SET(osfd, &rd_wr);
+                if (fd_type == READ_FD)
+                    rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
+                else
+                    rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
+                if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
+                    _PR_MD_MAP_SELECT_ERROR(syserror);
+                    break;
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+            } while (rv == 0 || (rv == -1 && syserror == EINTR));
+            break;
+        default:
+            now = epoch = PR_IntervalNow();
+            remaining = timeout;
+            FD_ZERO(&rd_wr);
+            do {
+                /*
+                 * We block in _MD_SELECT for at most
+                 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
+                 * so that there is an upper limit on the delay
+                 * before the interrupt bit is checked.
+                 */
+                wait_for_remaining = PR_TRUE;
+                tv.tv_sec = PR_IntervalToSeconds(remaining);
+                if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
+                    wait_for_remaining = PR_FALSE;
+                    tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
+                    tv.tv_usec = 0;
+                } else {
+                    tv.tv_usec = PR_IntervalToMicroseconds(
+                        remaining -
+                        PR_SecondsToInterval(tv.tv_sec));
+                }
+                FD_SET(osfd, &rd_wr);
+                if (fd_type == READ_FD)
+                    rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
+                else
+                    rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
+                /*
+                 * we don't consider EINTR a real error
+                 */
+                if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
+                    _PR_MD_MAP_SELECT_ERROR(syserror);
+                    break;
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+                /*
+                 * We loop again if _MD_SELECT timed out or got interrupted
+                 * by a signal, and the timeout deadline has not passed yet.
+                 */
+                if (rv == 0 || (rv == -1 && syserror == EINTR)) {
+                    /*
+                     * If _MD_SELECT timed out, we know how much time
+                     * we spent in blocking, so we can avoid a
+                     * PR_IntervalNow() call.
+                     */
+                    if (rv == 0) {
+                        if (wait_for_remaining) {
+                            now += remaining;
+                        } else {
+                            now += PR_SecondsToInterval(tv.tv_sec)
+                                + PR_MicrosecondsToInterval(tv.tv_usec);
+                        }
+                    } else {
+                        now = PR_IntervalNow();
+                    }
+                    elapsed = (PRIntervalTime) (now - epoch);
+                    if (elapsed >= timeout) {
+                        PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                        rv = -1;
+                        break;
+                    } else {
+                        remaining = timeout - elapsed;
+                    }
+                }
+            } while (rv == 0 || (rv == -1 && syserror == EINTR));
+            break;
+    }
+    return(rv);
+}
+
+#else /* _PR_USE_POLL */
+
+static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
+    PRIntervalTime timeout)
+{
+    PRInt32 rv = -1;
+    int msecs;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRIntervalTime epoch, now, elapsed, remaining;
+    PRBool wait_for_remaining;
+    PRInt32 syserror;
+    struct pollfd pfd;
+
+    switch (timeout) {
+        case PR_INTERVAL_NO_WAIT:
+            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+            break;
+        case PR_INTERVAL_NO_TIMEOUT:
+            /*
+             * This is a special case of the 'default' case below.
+             * Please see the comments there.
+             */
+            msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
+            pfd.fd = osfd;
+            if (fd_type == READ_FD) {
+                pfd.events = POLLIN;
+            } else {
+                pfd.events = POLLOUT;
+            }
+            do {
+                rv = _MD_POLL(&pfd, 1, msecs);
+                if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
+                    _PR_MD_MAP_POLL_ERROR(syserror);
+                    break;
+                }
+				/*
+				 * If POLLERR is set, don't process it; retry the operation
+				 */
+                if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) {
+					rv = -1;
+                    _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents);
+                    break;
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+            } while (rv == 0 || (rv == -1 && syserror == EINTR));
+            break;
+        default:
+            now = epoch = PR_IntervalNow();
+            remaining = timeout;
+            pfd.fd = osfd;
+            if (fd_type == READ_FD) {
+                pfd.events = POLLIN;
+            } else {
+                pfd.events = POLLOUT;
+            }
+            do {
+                /*
+                 * We block in _MD_POLL for at most
+                 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
+                 * so that there is an upper limit on the delay
+                 * before the interrupt bit is checked.
+                 */
+                wait_for_remaining = PR_TRUE;
+                msecs = PR_IntervalToMilliseconds(remaining);
+                if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {
+                    wait_for_remaining = PR_FALSE;
+                    msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
+                }
+                rv = _MD_POLL(&pfd, 1, msecs);
+                /*
+                 * we don't consider EINTR a real error
+                 */
+                if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
+                    _PR_MD_MAP_POLL_ERROR(syserror);
+                    break;
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+				/*
+				 * If POLLERR is set, don't process it; retry the operation
+				 */
+                if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) {
+					rv = -1;
+                    _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents);
+                    break;
+                }
+                /*
+                 * We loop again if _MD_POLL timed out or got interrupted
+                 * by a signal, and the timeout deadline has not passed yet.
+                 */
+                if (rv == 0 || (rv == -1 && syserror == EINTR)) {
+                    /*
+                     * If _MD_POLL timed out, we know how much time
+                     * we spent in blocking, so we can avoid a
+                     * PR_IntervalNow() call.
+                     */
+                    if (rv == 0) {
+                        if (wait_for_remaining) {
+                            now += remaining;
+                        } else {
+                            now += PR_MillisecondsToInterval(msecs);
+                        }
+                    } else {
+                        now = PR_IntervalNow();
+                    }
+                    elapsed = (PRIntervalTime) (now - epoch);
+                    if (elapsed >= timeout) {
+                        PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                        rv = -1;
+                        break;
+                    } else {
+                        remaining = timeout - elapsed;
+                    }
+                }
+            } while (rv == 0 || (rv == -1 && syserror == EINTR));
+            break;
+    }
+    return(rv);
+}
+
+#endif /* _PR_USE_POLL */
+
+static PRInt32 local_io_wait(
+    PRInt32 osfd,
+    PRInt32 wait_flag,
+    PRIntervalTime timeout)
+{
+    _PRUnixPollDesc pd;
+    PRInt32 rv;
+
+    PR_LOG(_pr_io_lm, PR_LOG_MIN,
+       ("waiting to %s on osfd=%d",
+        (wait_flag == _PR_UNIX_POLL_READ) ? "read" : "write",
+        osfd));
+
+    if (timeout == PR_INTERVAL_NO_WAIT) return 0;
+
+    pd.osfd = osfd;
+    pd.in_flags = wait_flag;
+    pd.out_flags = 0;
+
+    rv = _PR_WaitForMultipleFDs(&pd, 1, timeout);
+
+    if (rv == 0) {
+        PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+        rv = -1;
+    }
+    return rv;
+}
+
+
+PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+                                PRInt32 flags, PRIntervalTime timeout)
+{
+    PRInt32 osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+/*
+ * Many OS's (Solaris, Unixware) have a broken recv which won't read
+ * from socketpairs.  As long as we don't use flags on socketpairs, this
+ * is a decent fix. - mikep
+ */
+#if defined(UNIXWARE) || defined(SOLARIS) || defined(NCR)
+    while ((rv = read(osfd,buf,amount)) == -1) {
+#else
+    while ((rv = recv(osfd,buf,amount,flags)) == -1) {
+#endif
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+				if ((rv = local_io_wait(osfd,_PR_UNIX_POLL_READ,timeout)) < 0)
+					goto done;
+            } else {
+                if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
+                    goto done;
+            }
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_RECV_ERROR(err);
+    }
+done:
+    return(rv);
+}
+
+PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+                        PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
+                        PRIntervalTime timeout)
+{
+    PRInt32 osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    while ((*addrlen = PR_NETADDR_SIZE(addr)),
+                ((rv = recvfrom(osfd, buf, amount, flags,
+                        (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -1)) {
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+                if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0)
+                    goto done;
+            } else {
+                if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
+                    goto done;
+            }
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_RECVFROM_ERROR(err);
+    }
+done:
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    if (rv != -1) {
+        /* ignore the sa_len field of struct sockaddr */
+        if (addr) {
+            addr->raw.family = ((struct sockaddr *) addr)->sa_family;
+        }
+    }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+    return(rv);
+}
+
+PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+                            PRInt32 flags, PRIntervalTime timeout)
+{
+    PRInt32 osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+#if defined(SOLARIS)
+	PRInt32 tmp_amount = amount;
+#endif
+
+    /*
+     * On pre-2.6 Solaris, send() is much slower than write().
+     * On 2.6 and beyond, with in-kernel sockets, send() and
+     * write() are fairly equivalent in performance.
+     */
+#if defined(SOLARIS)
+    PR_ASSERT(0 == flags);
+    while ((rv = write(osfd,buf,tmp_amount)) == -1) {
+#else
+    while ((rv = send(osfd,buf,amount,flags)) == -1) {
+#endif
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK))    {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+                if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
+                    goto done;
+            } else {
+                if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
+                    goto done;
+            }
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+#if defined(SOLARIS)
+			/*
+			 * The write system call has been reported to return the ERANGE
+			 * error on occasion. Try to write in smaller chunks to workaround
+			 * this bug.
+			 */
+			if (err == ERANGE) {
+				if (tmp_amount > 1) {
+					tmp_amount = tmp_amount/2;	/* half the bytes */
+					continue;
+				}
+			}
+#endif
+            break;
+        }
+    }
+        /*
+         * optimization; if bytes sent is less than "amount" call
+         * select before returning. This is because it is likely that
+         * the next send() call will return EWOULDBLOCK.
+         */
+    if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
+            && (timeout != PR_INTERVAL_NO_WAIT)) {
+        if (_PR_IS_NATIVE_THREAD(me)) {
+			if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) {
+				rv = -1;
+				goto done;
+			}
+        } else {
+			if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) {
+				rv = -1;
+				goto done;
+			}
+        }
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_SEND_ERROR(err);
+    }
+done:
+    return(rv);
+}
+
+PRInt32 _MD_sendto(
+    PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+    const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
+{
+    PRInt32 osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    PRNetAddr addrCopy;
+
+    addrCopy = *addr;
+    ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
+    ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
+
+    while ((rv = sendto(osfd, buf, amount, flags,
+            (struct sockaddr *) &addrCopy, addrlen)) == -1) {
+#else
+    while ((rv = sendto(osfd, buf, amount, flags,
+            (struct sockaddr *) addr, addrlen)) == -1) {
+#endif
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK))    {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+				if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
+					goto done;
+            } else {
+                if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
+                    goto done;
+            }
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_SENDTO_ERROR(err);
+    }
+done:
+    return(rv);
+}
+
+PRInt32 _MD_writev(
+    PRFileDesc *fd, const PRIOVec *iov,
+    PRInt32 iov_size, PRIntervalTime timeout)
+{
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRInt32 index, amount = 0;
+    PRInt32 osfd = fd->secret->md.osfd;
+
+    /*
+     * Calculate the total number of bytes to be sent; needed for
+     * optimization later.
+     * We could avoid this if this number was passed in; but it is
+     * probably not a big deal because iov_size is usually small (less than
+     * 3)
+     */
+    if (!fd->secret->nonblocking) {
+        for (index=0; index<iov_size; index++) {
+            amount += iov[index].iov_len;
+        }
+    }
+
+    while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) {
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK))    {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+				if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
+					goto done;
+            } else {
+                if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
+                    goto done;
+            }
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+    /*
+     * optimization; if bytes sent is less than "amount" call
+     * select before returning. This is because it is likely that
+     * the next writev() call will return EWOULDBLOCK.
+     */
+    if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
+            && (timeout != PR_INTERVAL_NO_WAIT)) {
+        if (_PR_IS_NATIVE_THREAD(me)) {
+            if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
+				rv = -1;
+                goto done;
+			}
+        } else {
+			if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) {
+				rv = -1;
+				goto done;
+			}
+        }
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_WRITEV_ERROR(err);
+    }
+done:
+    return(rv);
+}
+
+PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr,
+                            PRUint32 *addrlen, PRIntervalTime timeout)
+{
+    PRInt32 osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    while ((rv = accept(osfd, (struct sockaddr *) addr,
+                                        (_PRSockLen_t *)addrlen)) == -1) {
+        err = _MD_ERRNO();
+        if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == ECONNABORTED)) {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+				if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0)
+					goto done;
+            } else {
+                if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
+                    goto done;
+            }
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_ACCEPT_ERROR(err);
+    }
+done:
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    if (rv != -1) {
+        /* ignore the sa_len field of struct sockaddr */
+        if (addr) {
+            addr->raw.family = ((struct sockaddr *) addr)->sa_family;
+        }
+    }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+    return(rv);
+}
+
+extern int _connect (int s, const struct sockaddr *name, int namelen);
+PRInt32 _MD_connect(
+    PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
+{
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRInt32 osfd = fd->secret->md.osfd;
+#ifdef IRIX
+extern PRInt32 _MD_irix_connect(
+        PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout);
+#endif
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    PRNetAddr addrCopy;
+
+    addrCopy = *addr;
+    ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
+    ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
+#endif
+
+    /*
+     * We initiate the connection setup by making a nonblocking connect()
+     * call.  If the connect() call fails, there are two cases we handle
+     * specially:
+     * 1. The connect() call was interrupted by a signal.  In this case
+     *    we simply retry connect().
+     * 2. The NSPR socket is nonblocking and connect() fails with
+     *    EINPROGRESS.  We first wait until the socket becomes writable.
+     *    Then we try to find out whether the connection setup succeeded
+     *    or failed.
+     */
+
+retry:
+#ifdef IRIX
+    if ((rv = _MD_irix_connect(osfd, addr, addrlen, timeout)) == -1) {
+#else
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) {
+#else
+    if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) {
+#endif
+#endif
+        err = _MD_ERRNO();
+
+        if (err == EINTR) {
+            if (_PR_PENDING_INTERRUPT(me)) {
+                me->flags &= ~_PR_INTERRUPT;
+                PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
+                return -1;
+            }
+            goto retry;
+        }
+
+        if (!fd->secret->nonblocking && (err == EINPROGRESS)) {
+            if (!_PR_IS_NATIVE_THREAD(me)) {
+
+				if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
+                    return -1;
+            } else {
+                /*
+                 * socket_io_wait() may return -1 or 1.
+                 */
+
+                rv = socket_io_wait(osfd, WRITE_FD, timeout);
+                if (rv == -1) {
+                    return -1;
+                }
+            }
+
+            PR_ASSERT(rv == 1);
+            if (_PR_PENDING_INTERRUPT(me)) {
+                me->flags &= ~_PR_INTERRUPT;
+                PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
+                return -1;
+            }
+            err = _MD_unix_get_nonblocking_connect_error(osfd);
+            if (err != 0) {
+                _PR_MD_MAP_CONNECT_ERROR(err);
+                return -1;
+            }
+            return 0;
+        }
+
+        _PR_MD_MAP_CONNECT_ERROR(err);
+    }
+
+    return rv;
+}  /* _MD_connect */
+
+PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
+{
+    PRInt32 rv, err;
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    PRNetAddr addrCopy;
+
+    addrCopy = *addr;
+    ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
+    ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
+    rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen);
+#else
+    rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
+#endif
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_BIND_ERROR(err);
+    }
+    return(rv);
+}
+
+PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
+{
+    PRInt32 rv, err;
+
+    rv = listen(fd->secret->md.osfd, backlog);
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_LISTEN_ERROR(err);
+    }
+    return(rv);
+}
+
+PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how)
+{
+    PRInt32 rv, err;
+
+    rv = shutdown(fd->secret->md.osfd, how);
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_SHUTDOWN_ERROR(err);
+    }
+    return(rv);
+}
+
+PRInt32 _MD_socketpair(int af, int type, int flags,
+                                                        PRInt32 *osfd)
+{
+    PRInt32 rv, err;
+
+    rv = socketpair(af, type, flags, osfd);
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_SOCKETPAIR_ERROR(err);
+    }
+    return rv;
+}
+
+PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr,
+                                                PRUint32 *addrlen)
+{
+    PRInt32 rv, err;
+
+    rv = getsockname(fd->secret->md.osfd,
+            (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    if (rv == 0) {
+        /* ignore the sa_len field of struct sockaddr */
+        if (addr) {
+            addr->raw.family = ((struct sockaddr *) addr)->sa_family;
+        }
+    }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_GETSOCKNAME_ERROR(err);
+    }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
+}
+
+PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr,
+                                        PRUint32 *addrlen)
+{
+    PRInt32 rv, err;
+
+    rv = getpeername(fd->secret->md.osfd,
+            (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    if (rv == 0) {
+        /* ignore the sa_len field of struct sockaddr */
+        if (addr) {
+            addr->raw.family = ((struct sockaddr *) addr)->sa_family;
+        }
+    }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_GETPEERNAME_ERROR(err);
+    }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
+}
+
+PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level,
+                        PRInt32 optname, char* optval, PRInt32* optlen)
+{
+    PRInt32 rv, err;
+
+    rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (_PRSockLen_t *)optlen);
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_GETSOCKOPT_ERROR(err);
+    }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
+}
+
+PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level,   
+                    PRInt32 optname, const char* optval, PRInt32 optlen)
+{
+    PRInt32 rv, err;
+
+    rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_SETSOCKOPT_ERROR(err);
+    }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
+}
+
+PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable)
+{
+    int rv;
+
+    rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC);
+    if (-1 == rv) {
+        PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported)
+{
+    if (imported) {
+        fd->secret->inheritable = _PR_TRI_UNKNOWN;
+    } else {
+        /* By default, a Unix fd is not closed on exec. */
+#ifdef DEBUG
+        {
+            int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
+            PR_ASSERT(0 == flags);
+        }
+#endif
+        fd->secret->inheritable = _PR_TRI_TRUE;
+    }
+}
+
+/************************************************************************/
+#if !defined(_PR_USE_POLL)
+
+/*
+** Scan through io queue and find any bad fd's that triggered the error
+** from _MD_SELECT
+*/
+static void FindBadFDs(void)
+{
+    PRCList *q;
+    PRThread *me = _MD_CURRENT_THREAD();
+
+    PR_ASSERT(!_PR_IS_NATIVE_THREAD(me));
+    q = (_PR_IOQ(me->cpu)).next;
+    _PR_IOQ_MAX_OSFD(me->cpu) = -1;
+    _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
+    while (q != &_PR_IOQ(me->cpu)) {
+        PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
+        PRBool notify = PR_FALSE;
+        _PRUnixPollDesc *pds = pq->pds;
+        _PRUnixPollDesc *epds = pds + pq->npds;
+        PRInt32 pq_max_osfd = -1;
+
+        q = q->next;
+        for (; pds < epds; pds++) {
+            PRInt32 osfd = pds->osfd;
+            pds->out_flags = 0;
+            PR_ASSERT(osfd >= 0 || pds->in_flags == 0);
+            if (pds->in_flags == 0) {
+                continue;  /* skip this fd */
+            }
+            if (fcntl(osfd, F_GETFL, 0) == -1) {
+                /* Found a bad descriptor, remove it from the fd_sets. */
+                PR_LOG(_pr_io_lm, PR_LOG_MAX,
+                    ("file descriptor %d is bad", osfd));
+                pds->out_flags = _PR_UNIX_POLL_NVAL;
+                notify = PR_TRUE;
+            }
+            if (osfd > pq_max_osfd) {
+                pq_max_osfd = osfd;
+            }
+        }
+
+        if (notify) {
+            PRIntn pri;
+            PR_REMOVE_LINK(&pq->links);
+            pq->on_ioq = PR_FALSE;
+
+            /*
+         * Decrement the count of descriptors for each desciptor/event
+         * because this I/O request is being removed from the
+         * ioq
+         */
+            pds = pq->pds;
+            for (; pds < epds; pds++) {
+                PRInt32 osfd = pds->osfd;
+                PRInt16 in_flags = pds->in_flags;
+                PR_ASSERT(osfd >= 0 || in_flags == 0);
+                if (in_flags & _PR_UNIX_POLL_READ) {
+                    if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
+                        FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
+                }
+                if (in_flags & _PR_UNIX_POLL_WRITE) {
+                    if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
+                        FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
+                }
+                if (in_flags & _PR_UNIX_POLL_EXCEPT) {
+                    if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
+                        FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
+                }
+            }
+
+            _PR_THREAD_LOCK(pq->thr);
+            if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
+                _PRCPU *cpu = pq->thr->cpu;
+                _PR_SLEEPQ_LOCK(pq->thr->cpu);
+                _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
+                _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
+
+				if (pq->thr->flags & _PR_SUSPENDING) {
+				    /*
+				     * set thread state to SUSPENDED;
+				     * a Resume operation on the thread
+				     * will move it to the runQ
+				     */
+				    pq->thr->state = _PR_SUSPENDED;
+				    _PR_MISCQ_LOCK(pq->thr->cpu);
+				    _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
+				    _PR_MISCQ_UNLOCK(pq->thr->cpu);
+				} else {
+				    pri = pq->thr->priority;
+				    pq->thr->state = _PR_RUNNABLE;
+
+				    _PR_RUNQ_LOCK(cpu);
+				    _PR_ADD_RUNQ(pq->thr, cpu, pri);
+				    _PR_RUNQ_UNLOCK(cpu);
+				}
+            }
+            _PR_THREAD_UNLOCK(pq->thr);
+        } else {
+            if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
+                _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
+            if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
+                _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
+        }
+    }
+    if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
+        if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0])
+            _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
+    }
+}
+#endif  /* !defined(_PR_USE_POLL) */
+
+/************************************************************************/
+
+/*
+** Called by the scheduler when there is nothing to do. This means that
+** all threads are blocked on some monitor somewhere.
+**
+** Note: this code doesn't release the scheduler lock.
+*/
+/*
+** Pause the current CPU. longjmp to the cpu's pause stack
+**
+** This must be called with the scheduler locked
+*/
+void _MD_PauseCPU(PRIntervalTime ticks)
+{
+    PRThread *me = _MD_CURRENT_THREAD();
+#ifdef _PR_USE_POLL
+    int timeout;
+    struct pollfd *pollfds;    /* an array of pollfd structures */
+    struct pollfd *pollfdPtr;    /* a pointer that steps through the array */
+    unsigned long npollfds;     /* number of pollfd structures in array */
+    unsigned long pollfds_size;
+    int nfd;                    /* to hold the return value of poll() */
+#else
+    struct timeval timeout, *tvp;
+    fd_set r, w, e;
+    fd_set *rp, *wp, *ep;
+    PRInt32 max_osfd, nfd;
+#endif  /* _PR_USE_POLL */
+    PRInt32 rv;
+    PRCList *q;
+    PRUint32 min_timeout;
+    sigset_t oldset;
+#ifdef IRIX
+extern sigset_t ints_off;
+#endif
+
+    PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
+
+    _PR_MD_IOQ_LOCK();
+
+#ifdef _PR_USE_POLL
+    /* Build up the pollfd structure array to wait on */
+
+    /* Find out how many pollfd structures are needed */
+    npollfds = _PR_IOQ_OSFD_CNT(me->cpu);
+    PR_ASSERT(npollfds >= 0);
+
+    /*
+     * We use a pipe to wake up a native thread.  An fd is needed
+     * for the pipe and we poll it for reading.
+     */
+    if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
+        npollfds++;
+#ifdef	IRIX
+		/*
+		 * On Irix, a second pipe is used to cause the primordial cpu to
+		 * wakeup and exit, when the process is exiting because of a call
+		 * to exit/PR_ProcessExit.
+		 */
+		if (me->cpu->id == 0) {
+        	npollfds++;
+		}
+#endif
+	}
+
+    /*
+     * if the cpu's pollfd array is not big enough, release it and allocate a new one
+     */
+    if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) {
+        if (_PR_IOQ_POLLFDS(me->cpu) != NULL)
+            PR_DELETE(_PR_IOQ_POLLFDS(me->cpu));
+        pollfds_size =  PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds);
+        pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd));
+        _PR_IOQ_POLLFDS(me->cpu) = pollfds;
+        _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size;
+    } else {
+        pollfds = _PR_IOQ_POLLFDS(me->cpu);
+    }
+    pollfdPtr = pollfds;
+
+    /*
+     * If we need to poll the pipe for waking up a native thread,
+     * the pipe's fd is the first element in the pollfds array.
+     */
+    if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
+        pollfdPtr->fd = _pr_md_pipefd[0];
+        pollfdPtr->events = POLLIN;
+        pollfdPtr++;
+#ifdef	IRIX
+		/*
+		 * On Irix, the second element is the exit pipe
+		 */
+		if (me->cpu->id == 0) {
+			pollfdPtr->fd = _pr_irix_primoridal_cpu_fd[0];
+			pollfdPtr->events = POLLIN;
+			pollfdPtr++;
+		}
+#endif
+    }
+
+    min_timeout = PR_INTERVAL_NO_TIMEOUT;
+    for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) {
+        PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
+        _PRUnixPollDesc *pds = pq->pds;
+        _PRUnixPollDesc *epds = pds + pq->npds;
+
+        if (pq->timeout < min_timeout) {
+            min_timeout = pq->timeout;
+        }
+        for (; pds < epds; pds++, pollfdPtr++) {
+            /*
+         * Assert that the pollfdPtr pointer does not go
+         * beyond the end of the pollfds array
+         */
+            PR_ASSERT(pollfdPtr < pollfds + npollfds);
+            pollfdPtr->fd = pds->osfd;
+            /* direct copy of poll flags */
+            pollfdPtr->events = pds->in_flags;
+        }
+    }
+    _PR_IOQ_TIMEOUT(me->cpu) = min_timeout;
+#else
+    /*
+     * assigment of fd_sets
+     */
+    r = _PR_FD_READ_SET(me->cpu);
+    w = _PR_FD_WRITE_SET(me->cpu);
+    e = _PR_FD_EXCEPTION_SET(me->cpu);
+
+    rp = &r;
+    wp = &w;
+    ep = &e;
+
+    max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1;
+    min_timeout = _PR_IOQ_TIMEOUT(me->cpu);
+#endif  /* _PR_USE_POLL */
+    /*
+    ** Compute the minimum timeout value: make it the smaller of the
+    ** timeouts specified by the i/o pollers or the timeout of the first
+    ** sleeping thread.
+    */
+    q = _PR_SLEEPQ(me->cpu).next;
+
+    if (q != &_PR_SLEEPQ(me->cpu)) {
+        PRThread *t = _PR_THREAD_PTR(q);
+
+        if (t->sleep < min_timeout) {
+            min_timeout = t->sleep;
+        }
+    }
+    if (min_timeout > ticks) {
+        min_timeout = ticks;
+    }
+
+#ifdef _PR_USE_POLL
+    if (min_timeout == PR_INTERVAL_NO_TIMEOUT)
+        timeout = -1;
+    else
+        timeout = PR_IntervalToMilliseconds(min_timeout);
+#else
+    if (min_timeout == PR_INTERVAL_NO_TIMEOUT) {
+        tvp = NULL;
+    } else {
+        timeout.tv_sec = PR_IntervalToSeconds(min_timeout);
+        timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout)
+            % PR_USEC_PER_SEC;
+        tvp = &timeout;
+    }
+#endif  /* _PR_USE_POLL */
+
+    _PR_MD_IOQ_UNLOCK();
+    _MD_CHECK_FOR_EXIT();
+    /*
+     * check for i/o operations
+     */
+#ifndef _PR_NO_CLOCK_TIMER
+    /*
+     * Disable the clock interrupts while we are in select, if clock interrupts
+     * are enabled. Otherwise, when the select/poll calls are interrupted, the
+     * timer value starts ticking from zero again when the system call is restarted.
+     */
+#ifdef IRIX
+    /*
+     * SIGCHLD signal is used on Irix to detect he termination of an
+     * sproc by SIGSEGV, SIGBUS or SIGABRT signals when
+     * _nspr_terminate_on_error is set.
+     */
+    if ((!_nspr_noclock) || (_nspr_terminate_on_error))
+#else
+        if (!_nspr_noclock)
+#endif    /* IRIX */
+#ifdef IRIX
+    sigprocmask(SIG_BLOCK, &ints_off, &oldset);
+#else
+    PR_ASSERT(sigismember(&timer_set, SIGALRM));
+    sigprocmask(SIG_BLOCK, &timer_set, &oldset);
+#endif    /* IRIX */
+#endif  /* !_PR_NO_CLOCK_TIMER */
+
+#ifndef _PR_USE_POLL
+    PR_ASSERT(FD_ISSET(_pr_md_pipefd[0],rp));
+    nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp);
+#else
+    nfd = _MD_POLL(pollfds, npollfds, timeout);
+#endif  /* !_PR_USE_POLL */
+
+#ifndef _PR_NO_CLOCK_TIMER
+#ifdef IRIX
+    if ((!_nspr_noclock) || (_nspr_terminate_on_error))
+#else
+        if (!_nspr_noclock)
+#endif    /* IRIX */
+    sigprocmask(SIG_SETMASK, &oldset, 0);
+#endif  /* !_PR_NO_CLOCK_TIMER */
+
+    _MD_CHECK_FOR_EXIT();
+
+#ifdef IRIX
+	_PR_MD_primordial_cpu();
+#endif
+
+    _PR_MD_IOQ_LOCK();
+    /*
+    ** Notify monitors that are associated with the selected descriptors.
+    */
+#ifdef _PR_USE_POLL
+    if (nfd > 0) {
+        pollfdPtr = pollfds;
+        if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
+            /*
+			 * Assert that the pipe is the first element in the
+			 * pollfds array.
+			 */
+            PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]);
+            if ((pollfds[0].revents & POLLIN) && (nfd == 1)) {
+                /*
+				 * woken up by another thread; read all the data
+				 * in the pipe to empty the pipe
+				 */
+                while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf,
+                    PIPE_BUF)) == PIPE_BUF){
+                }
+                PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN)));
+            }
+            pollfdPtr++;
+#ifdef	IRIX
+			/*
+			 * On Irix, check to see if the primordial cpu needs to exit
+			 * to cause the process to terminate
+			 */
+			if (me->cpu->id == 0) {
+            	PR_ASSERT(pollfds[1].fd == _pr_irix_primoridal_cpu_fd[0]);
+				if (pollfdPtr->revents & POLLIN) {
+					if (_pr_irix_process_exit) {
+						/*
+						 * process exit due to a call to PR_ProcessExit
+						 */
+						prctl(PR_SETEXITSIG, SIGKILL);
+						_exit(_pr_irix_process_exit_code);
+					} else {
+						while ((rv = read(_pr_irix_primoridal_cpu_fd[0],
+							_pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) {
+						}
+						PR_ASSERT(rv > 0);
+					}
+				}
+				pollfdPtr++;
+			}
+#endif
+        }
+        for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) {
+            PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
+            PRBool notify = PR_FALSE;
+            _PRUnixPollDesc *pds = pq->pds;
+            _PRUnixPollDesc *epds = pds + pq->npds;
+
+            for (; pds < epds; pds++, pollfdPtr++) {
+                /*
+                  * Assert that the pollfdPtr pointer does not go beyond
+                  * the end of the pollfds array.
+                  */
+                PR_ASSERT(pollfdPtr < pollfds + npollfds);
+                /*
+                 * Assert that the fd's in the pollfds array (stepped
+                 * through by pollfdPtr) are in the same order as
+                 * the fd's in _PR_IOQ() (stepped through by q and pds).
+                 * This is how the pollfds array was created earlier.
+                 */
+                PR_ASSERT(pollfdPtr->fd == pds->osfd);
+                pds->out_flags = pollfdPtr->revents;
+                /* Negative fd's are ignored by poll() */
+                if (pds->osfd >= 0 && pds->out_flags) {
+                    notify = PR_TRUE;
+                }
+            }
+            if (notify) {
+                PRIntn pri;
+                PRThread *thred;
+
+                PR_REMOVE_LINK(&pq->links);
+                pq->on_ioq = PR_FALSE;
+
+                thred = pq->thr;
+                _PR_THREAD_LOCK(thred);
+                if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
+                    _PRCPU *cpu = pq->thr->cpu;
+                    _PR_SLEEPQ_LOCK(pq->thr->cpu);
+                    _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
+                    _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
+
+					if (pq->thr->flags & _PR_SUSPENDING) {
+					    /*
+					     * set thread state to SUSPENDED;
+					     * a Resume operation on the thread
+					     * will move it to the runQ
+					     */
+					    pq->thr->state = _PR_SUSPENDED;
+					    _PR_MISCQ_LOCK(pq->thr->cpu);
+					    _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
+					    _PR_MISCQ_UNLOCK(pq->thr->cpu);
+					} else {
+						pri = pq->thr->priority;
+						pq->thr->state = _PR_RUNNABLE;
+
+						_PR_RUNQ_LOCK(cpu);
+						_PR_ADD_RUNQ(pq->thr, cpu, pri);
+						_PR_RUNQ_UNLOCK(cpu);
+						if (_pr_md_idle_cpus > 1)
+							_PR_MD_WAKEUP_WAITER(thred);
+					}
+                }
+                _PR_THREAD_UNLOCK(thred);
+                _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds;
+                PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0);
+            }
+        }
+    } else if (nfd == -1) {
+        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno));
+    }
+
+#else
+    if (nfd > 0) {
+        q = _PR_IOQ(me->cpu).next;
+        _PR_IOQ_MAX_OSFD(me->cpu) = -1;
+        _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
+        while (q != &_PR_IOQ(me->cpu)) {
+            PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
+            PRBool notify = PR_FALSE;
+            _PRUnixPollDesc *pds = pq->pds;
+            _PRUnixPollDesc *epds = pds + pq->npds;
+            PRInt32 pq_max_osfd = -1;
+
+            q = q->next;
+            for (; pds < epds; pds++) {
+                PRInt32 osfd = pds->osfd;
+                PRInt16 in_flags = pds->in_flags;
+                PRInt16 out_flags = 0;
+                PR_ASSERT(osfd >= 0 || in_flags == 0);
+                if ((in_flags & _PR_UNIX_POLL_READ) && FD_ISSET(osfd, rp)) {
+                    out_flags |= _PR_UNIX_POLL_READ;
+                }
+                if ((in_flags & _PR_UNIX_POLL_WRITE) && FD_ISSET(osfd, wp)) {
+                    out_flags |= _PR_UNIX_POLL_WRITE;
+                }
+                if ((in_flags & _PR_UNIX_POLL_EXCEPT) && FD_ISSET(osfd, ep)) {
+                    out_flags |= _PR_UNIX_POLL_EXCEPT;
+                }
+                pds->out_flags = out_flags;
+                if (out_flags) {
+                    notify = PR_TRUE;
+                }
+                if (osfd > pq_max_osfd) {
+                    pq_max_osfd = osfd;
+                }
+            }
+            if (notify == PR_TRUE) {
+                PRIntn pri;
+                PRThread *thred;
+
+                PR_REMOVE_LINK(&pq->links);
+                pq->on_ioq = PR_FALSE;
+
+                /*
+                 * Decrement the count of descriptors for each desciptor/event
+                 * because this I/O request is being removed from the
+                 * ioq
+                 */
+                pds = pq->pds;
+                for (; pds < epds; pds++) {
+                    PRInt32 osfd = pds->osfd;
+                    PRInt16 in_flags = pds->in_flags;
+                    PR_ASSERT(osfd >= 0 || in_flags == 0);
+                    if (in_flags & _PR_UNIX_POLL_READ) {
+                        if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
+                            FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
+                    }
+                    if (in_flags & _PR_UNIX_POLL_WRITE) {
+                        if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
+                            FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
+                    }
+                    if (in_flags & _PR_UNIX_POLL_EXCEPT) {
+                        if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
+                            FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
+                    }
+                }
+
+                /*
+                 * Because this thread can run on a different cpu right
+                 * after being added to the run queue, do not dereference
+                 * pq
+                 */
+                 thred = pq->thr;
+                _PR_THREAD_LOCK(thred);
+                if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
+                    _PRCPU *cpu = thred->cpu;
+                    _PR_SLEEPQ_LOCK(pq->thr->cpu);
+                    _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
+                    _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
+
+					if (pq->thr->flags & _PR_SUSPENDING) {
+					    /*
+					     * set thread state to SUSPENDED;
+					     * a Resume operation on the thread
+					     * will move it to the runQ
+					     */
+					    pq->thr->state = _PR_SUSPENDED;
+					    _PR_MISCQ_LOCK(pq->thr->cpu);
+					    _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
+					    _PR_MISCQ_UNLOCK(pq->thr->cpu);
+					} else {
+						pri = pq->thr->priority;
+						pq->thr->state = _PR_RUNNABLE;
+
+						pq->thr->cpu = cpu;
+						_PR_RUNQ_LOCK(cpu);
+						_PR_ADD_RUNQ(pq->thr, cpu, pri);
+						_PR_RUNQ_UNLOCK(cpu);
+						if (_pr_md_idle_cpus > 1)
+							_PR_MD_WAKEUP_WAITER(thred);
+					}
+                }
+                _PR_THREAD_UNLOCK(thred);
+            } else {
+                if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
+                    _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
+                if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
+                    _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
+            }
+        }
+        if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
+            if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) {
+                /*
+             * woken up by another thread; read all the data
+             * in the pipe to empty the pipe
+             */
+                while ((rv =
+                    read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF))
+                    == PIPE_BUF){
+                }
+                PR_ASSERT((rv > 0) ||
+                    ((rv == -1) && (errno == EAGAIN)));
+            }
+            if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0])
+                _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
+#ifdef	IRIX
+			if ((me->cpu->id == 0) && 
+						(FD_ISSET(_pr_irix_primoridal_cpu_fd[0], rp))) {
+				if (_pr_irix_process_exit) {
+					/*
+					 * process exit due to a call to PR_ProcessExit
+					 */
+					prctl(PR_SETEXITSIG, SIGKILL);
+					_exit(_pr_irix_process_exit_code);
+				} else {
+						while ((rv = read(_pr_irix_primoridal_cpu_fd[0],
+							_pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) {
+						}
+						PR_ASSERT(rv > 0);
+				}
+			}
+			if (me->cpu->id == 0) {
+				if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_irix_primoridal_cpu_fd[0])
+					_PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0];
+			}
+#endif
+        }
+    } else if (nfd < 0) {
+        if (errno == EBADF) {
+            FindBadFDs();
+        } else {
+            PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d",
+                errno));
+        }
+    } else {
+        PR_ASSERT(nfd == 0);
+        /*
+         * compute the new value of _PR_IOQ_TIMEOUT
+         */
+        q = _PR_IOQ(me->cpu).next;
+        _PR_IOQ_MAX_OSFD(me->cpu) = -1;
+        _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
+        while (q != &_PR_IOQ(me->cpu)) {
+            PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
+            _PRUnixPollDesc *pds = pq->pds;
+            _PRUnixPollDesc *epds = pds + pq->npds;
+            PRInt32 pq_max_osfd = -1;
+
+            q = q->next;
+            for (; pds < epds; pds++) {
+                if (pds->osfd > pq_max_osfd) {
+                    pq_max_osfd = pds->osfd;
+                }
+            }
+            if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
+                _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
+            if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
+                _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
+        }
+        if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
+            if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0])
+                _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
+        }
+    }
+#endif  /* _PR_USE_POLL */
+    _PR_MD_IOQ_UNLOCK();
+}
+
+void _MD_Wakeup_CPUs()
+{
+    PRInt32 rv, data;
+
+    data = 0;
+    rv = write(_pr_md_pipefd[1], &data, 1);
+
+    while ((rv < 0) && (errno == EAGAIN)) {
+        /*
+         * pipe full, read all data in pipe to empty it
+         */
+        while ((rv =
+            read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF))
+            == PIPE_BUF) {
+        }
+        PR_ASSERT((rv > 0) ||
+            ((rv == -1) && (errno == EAGAIN)));
+        rv = write(_pr_md_pipefd[1], &data, 1);
+    }
+}
+
+
+void _MD_InitCPUS()
+{
+    PRInt32 rv, flags;
+    PRThread *me = _MD_CURRENT_THREAD();
+
+    rv = pipe(_pr_md_pipefd);
+    PR_ASSERT(rv == 0);
+    _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
+#ifndef _PR_USE_POLL
+    FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu));
+#endif
+
+    flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0);
+    fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK);
+    flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0);
+    fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK);
+}
+
+/*
+** Unix SIGALRM (clock) signal handler
+*/
+static void ClockInterruptHandler()
+{
+    int olderrno;
+    PRUintn pri;
+    _PRCPU *cpu = _PR_MD_CURRENT_CPU();
+    PRThread *me = _MD_CURRENT_THREAD();
+
+#ifdef SOLARIS
+    if (!me || _PR_IS_NATIVE_THREAD(me)) {
+        _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOCK;
+        return;
+    }
+#endif
+
+    if (_PR_MD_GET_INTSOFF() != 0) {
+        cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK;
+        return;
+    }
+    _PR_MD_SET_INTSOFF(1);
+
+    olderrno = errno;
+    _PR_ClockInterrupt();
+    errno = olderrno;
+
+    /*
+    ** If the interrupt wants a resched or if some other thread at
+    ** the same priority needs the cpu, reschedule.
+    */
+    pri = me->priority;
+    if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) {
+#ifdef _PR_NO_PREEMPT
+        cpu->resched = PR_TRUE;
+        if (pr_interruptSwitchHook) {
+            (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg);
+        }
+#else /* _PR_NO_PREEMPT */
+        /*
+    ** Re-enable unix interrupts (so that we can use
+    ** setjmp/longjmp for context switching without having to
+    ** worry about the signal state)
+    */
+        sigprocmask(SIG_SETMASK, &empty_set, 0);
+        PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch"));
+
+        if(!(me->flags & _PR_IDLE_THREAD)) {
+            _PR_THREAD_LOCK(me);
+            me->state = _PR_RUNNABLE;
+            me->cpu = cpu;
+            _PR_RUNQ_LOCK(cpu);
+            _PR_ADD_RUNQ(me, cpu, pri);
+            _PR_RUNQ_UNLOCK(cpu);
+            _PR_THREAD_UNLOCK(me);
+        } else
+            me->state = _PR_RUNNABLE;
+        _MD_SWITCH_CONTEXT(me);
+        PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch"));
+#endif /* _PR_NO_PREEMPT */
+    }
+    /*
+     * Because this thread could be running on a different cpu after
+     * a context switch the current cpu should be accessed and the
+     * value of the 'cpu' variable should not be used.
+     */
+    _PR_MD_SET_INTSOFF(0);
+}
+
+/*
+ * On HP-UX 9, we have to use the sigvector() interface to restart
+ * interrupted system calls, because sigaction() does not have the
+ * SA_RESTART flag.
+ */
+
+#ifdef HPUX9
+static void HPUX9_ClockInterruptHandler(
+    int sig,
+    int code,
+    struct sigcontext *scp)
+{
+    ClockInterruptHandler();
+    scp->sc_syscall_action = SIG_RESTART;
+}
+#endif /* HPUX9 */
+
+/* # of milliseconds per clock tick that we will use */
+#define MSEC_PER_TICK    50
+
+
+void _MD_StartInterrupts()
+{
+    char *eval;
+
+    if ((eval = getenv("NSPR_NOCLOCK")) != NULL) {
+        if (atoi(eval) == 0)
+            _nspr_noclock = 0;
+        else
+            _nspr_noclock = 1;
+    }
+
+#ifndef _PR_NO_CLOCK_TIMER
+    if (!_nspr_noclock) {
+        _MD_EnableClockInterrupts();
+    }
+#endif
+}
+
+void _MD_StopInterrupts()
+{
+    sigprocmask(SIG_BLOCK, &timer_set, 0);
+}
+
+void _MD_EnableClockInterrupts()
+{
+    struct itimerval itval;
+    extern PRUintn _pr_numCPU;
+#ifdef HPUX9
+    struct sigvec vec;
+
+    vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler;
+    vec.sv_mask = 0;
+    vec.sv_flags = 0;
+    sigvector(SIGALRM, &vec, 0);
+#else
+    struct sigaction vtact;
+
+    vtact.sa_handler = (void (*)()) ClockInterruptHandler;
+    sigemptyset(&vtact.sa_mask);
+    vtact.sa_flags = SA_RESTART;
+    sigaction(SIGALRM, &vtact, 0);
+#endif /* HPUX9 */
+
+    PR_ASSERT(_pr_numCPU == 1);
+	itval.it_interval.tv_sec = 0;
+	itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC;
+	itval.it_value = itval.it_interval;
+	setitimer(ITIMER_REAL, &itval, 0);
+}
+
+void _MD_DisableClockInterrupts()
+{
+    struct itimerval itval;
+    extern PRUintn _pr_numCPU;
+
+    PR_ASSERT(_pr_numCPU == 1);
+	itval.it_interval.tv_sec = 0;
+	itval.it_interval.tv_usec = 0;
+	itval.it_value = itval.it_interval;
+	setitimer(ITIMER_REAL, &itval, 0);
+}
+
+void _MD_BlockClockInterrupts()
+{
+    sigprocmask(SIG_BLOCK, &timer_set, 0);
+}
+
+void _MD_UnblockClockInterrupts()
+{
+    sigprocmask(SIG_UNBLOCK, &timer_set, 0);
+}
+
+void _MD_MakeNonblock(PRFileDesc *fd)
+{
+    PRInt32 osfd = fd->secret->md.osfd;
+    int flags;
+
+    if (osfd <= 2) {
+        /* Don't mess around with stdin, stdout or stderr */
+        return;
+    }
+    flags = fcntl(osfd, F_GETFL, 0);
+
+    /*
+     * Use O_NONBLOCK (POSIX-style non-blocking I/O) whenever possible.
+     * On SunOS 4, we must use FNDELAY (BSD-style non-blocking I/O),
+     * otherwise connect() still blocks and can be interrupted by SIGALRM.
+     */
+
+#ifdef SUNOS4
+    fcntl(osfd, F_SETFL, flags | FNDELAY);
+#else
+    fcntl(osfd, F_SETFL, flags | O_NONBLOCK);
+#endif
+    }
+
+PRInt32 _MD_open(const char *name, PRIntn flags, PRIntn mode)
+{
+    PRInt32 osflags;
+    PRInt32 rv, err;
+
+    if (flags & PR_RDWR) {
+        osflags = O_RDWR;
+    } else if (flags & PR_WRONLY) {
+        osflags = O_WRONLY;
+    } else {
+        osflags = O_RDONLY;
+    }
+
+    if (flags & PR_EXCL)
+        osflags |= O_EXCL;
+    if (flags & PR_APPEND)
+        osflags |= O_APPEND;
+    if (flags & PR_TRUNCATE)
+        osflags |= O_TRUNC;
+    if (flags & PR_SYNC) {
+#if defined(O_SYNC)
+        osflags |= O_SYNC;
+#elif defined(O_FSYNC)
+        osflags |= O_FSYNC;
+#else
+#error "Neither O_SYNC nor O_FSYNC is defined on this platform"
+#endif
+    }
+
+    /*
+    ** On creations we hold the 'create' lock in order to enforce
+    ** the semantics of PR_Rename. (see the latter for more details)
+    */
+    if (flags & PR_CREATE_FILE)
+    {
+        osflags |= O_CREAT;
+        if (NULL !=_pr_rename_lock)
+            PR_Lock(_pr_rename_lock);
+    }
+
+    rv = _md_iovector._open64(name, osflags, mode);
+
+    if (rv < 0) {
+        err = _MD_ERRNO();
+        _PR_MD_MAP_OPEN_ERROR(err);
+    }
+
+    if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
+        PR_Unlock(_pr_rename_lock);
+    return rv;
+}
+
+PRIntervalTime intr_timeout_ticks;
+
+#if defined(SOLARIS) || defined(IRIX)
+static void sigsegvhandler() {
+    fprintf(stderr,"Received SIGSEGV\n");
+    fflush(stderr);
+    pause();
+}
+
+static void sigaborthandler() {
+    fprintf(stderr,"Received SIGABRT\n");
+    fflush(stderr);
+    pause();
+}
+
+static void sigbushandler() {
+    fprintf(stderr,"Received SIGBUS\n");
+    fflush(stderr);
+    pause();
+}
+#endif /* SOLARIS, IRIX */
+
+#endif  /* !defined(_PR_PTHREADS) */
+
+void _MD_query_fd_inheritable(PRFileDesc *fd)
+{
+    int flags;
+
+    PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
+    flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
+    PR_ASSERT(-1 != flags);
+    fd->secret->inheritable = (flags & FD_CLOEXEC) ?
+        _PR_TRI_FALSE : _PR_TRI_TRUE;
+}
+
+PROffset32 _MD_lseek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
+{
+    PROffset32 rv, where;
+
+    switch (whence) {
+        case PR_SEEK_SET:
+            where = SEEK_SET;
+            break;
+        case PR_SEEK_CUR:
+            where = SEEK_CUR;
+            break;
+        case PR_SEEK_END:
+            where = SEEK_END;
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = -1;
+            goto done;
+    }
+    rv = lseek(fd->secret->md.osfd,offset,where);
+    if (rv == -1)
+    {
+        PRInt32 syserr = _MD_ERRNO();
+        _PR_MD_MAP_LSEEK_ERROR(syserr);
+    }
+done:
+    return(rv);
+}
+
+PROffset64 _MD_lseek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
+{
+    PRInt32 where;
+    PROffset64 rv;
+
+    switch (whence)
+    {
+        case PR_SEEK_SET:
+            where = SEEK_SET;
+            break;
+        case PR_SEEK_CUR:
+            where = SEEK_CUR;
+            break;
+        case PR_SEEK_END:
+            where = SEEK_END;
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = minus_one;
+            goto done;
+    }
+    rv = _md_iovector._lseek64(fd->secret->md.osfd, offset, where);
+    if (LL_EQ(rv, minus_one))
+    {
+        PRInt32 syserr = _MD_ERRNO();
+        _PR_MD_MAP_LSEEK_ERROR(syserr);
+    }
+done:
+    return rv;
+}  /* _MD_lseek64 */
+
+/*
+** _MD_set_fileinfo_times --
+**     Set the modifyTime and creationTime of the PRFileInfo
+**     structure using the values in struct stat.
+**
+** _MD_set_fileinfo64_times --
+**     Set the modifyTime and creationTime of the PRFileInfo64
+**     structure using the values in _MDStat64.
+*/
+
+#if defined(_PR_STAT_HAS_ST_ATIM)
+/*
+** struct stat has st_atim, st_mtim, and st_ctim fields of
+** type timestruc_t.
+*/
+static void _MD_set_fileinfo_times(
+    const struct stat *sb,
+    PRFileInfo *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtim.tv_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtim.tv_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctim.tv_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctim.tv_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+
+static void _MD_set_fileinfo64_times(
+    const _MDStat64 *sb,
+    PRFileInfo64 *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtim.tv_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtim.tv_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctim.tv_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctim.tv_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+#elif defined(_PR_STAT_HAS_ST_ATIM_UNION)
+/*
+** The st_atim, st_mtim, and st_ctim fields in struct stat are
+** unions with a st__tim union member of type timestruc_t.
+*/
+static void _MD_set_fileinfo_times(
+    const struct stat *sb,
+    PRFileInfo *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+
+static void _MD_set_fileinfo64_times(
+    const _MDStat64 *sb,
+    PRFileInfo64 *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+#elif defined(_PR_STAT_HAS_ST_ATIMESPEC)
+/*
+** struct stat has st_atimespec, st_mtimespec, and st_ctimespec
+** fields of type struct timespec.
+*/
+#if defined(_PR_TIMESPEC_HAS_TS_SEC)
+static void _MD_set_fileinfo_times(
+    const struct stat *sb,
+    PRFileInfo *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+
+static void _MD_set_fileinfo64_times(
+    const _MDStat64 *sb,
+    PRFileInfo64 *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+#else /* _PR_TIMESPEC_HAS_TS_SEC */
+/*
+** The POSIX timespec structure has tv_sec and tv_nsec.
+*/
+static void _MD_set_fileinfo_times(
+    const struct stat *sb,
+    PRFileInfo *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+
+static void _MD_set_fileinfo64_times(
+    const _MDStat64 *sb,
+    PRFileInfo64 *info)
+{
+    PRInt64 us, s2us;
+
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec);
+    LL_MUL(info->modifyTime, info->modifyTime, s2us);
+    LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000);
+    LL_ADD(info->modifyTime, info->modifyTime, us);
+    LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec);
+    LL_MUL(info->creationTime, info->creationTime, s2us);
+    LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000);
+    LL_ADD(info->creationTime, info->creationTime, us);
+}
+#endif /* _PR_TIMESPEC_HAS_TS_SEC */
+#elif defined(_PR_STAT_HAS_ONLY_ST_ATIME)
+/*
+** struct stat only has st_atime, st_mtime, and st_ctime fields
+** of type time_t.
+*/
+static void _MD_set_fileinfo_times(
+    const struct stat *sb,
+    PRFileInfo *info)
+{
+    PRInt64 s, s2us;
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(s, sb->st_mtime);
+    LL_MUL(s, s, s2us);
+    info->modifyTime = s;
+    LL_I2L(s, sb->st_ctime);
+    LL_MUL(s, s, s2us);
+    info->creationTime = s;
+}
+
+static void _MD_set_fileinfo64_times(
+    const _MDStat64 *sb,
+    PRFileInfo64 *info)
+{
+    PRInt64 s, s2us;
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(s, sb->st_mtime);
+    LL_MUL(s, s, s2us);
+    info->modifyTime = s;
+    LL_I2L(s, sb->st_ctime);
+    LL_MUL(s, s, s2us);
+    info->creationTime = s;
+}
+#else
+#error "I don't know yet"
+#endif
+
+static int _MD_convert_stat_to_fileinfo(
+    const struct stat *sb,
+    PRFileInfo *info)
+{
+    if (S_IFREG & sb->st_mode)
+        info->type = PR_FILE_FILE;
+    else if (S_IFDIR & sb->st_mode)
+        info->type = PR_FILE_DIRECTORY;
+    else
+        info->type = PR_FILE_OTHER;
+
+#if defined(_PR_HAVE_LARGE_OFF_T)
+    if (0x7fffffffL < sb->st_size)
+    {
+        PR_SetError(PR_FILE_TOO_BIG_ERROR, 0);
+        return -1;
+    }
+#endif /* defined(_PR_HAVE_LARGE_OFF_T) */
+    info->size = sb->st_size;
+
+    _MD_set_fileinfo_times(sb, info);
+    return 0;
+}  /* _MD_convert_stat_to_fileinfo */
+
+static int _MD_convert_stat64_to_fileinfo64(
+    const _MDStat64 *sb,
+    PRFileInfo64 *info)
+{
+    if (S_IFREG & sb->st_mode)
+        info->type = PR_FILE_FILE;
+    else if (S_IFDIR & sb->st_mode)
+        info->type = PR_FILE_DIRECTORY;
+    else
+        info->type = PR_FILE_OTHER;
+
+    LL_I2L(info->size, sb->st_size);
+
+    _MD_set_fileinfo64_times(sb, info);
+    return 0;
+}  /* _MD_convert_stat64_to_fileinfo64 */
+
+PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info)
+{
+    PRInt32 rv;
+    struct stat sb;
+
+    rv = stat(fn, &sb);
+    if (rv < 0)
+        _PR_MD_MAP_STAT_ERROR(_MD_ERRNO());
+    else if (NULL != info)
+        rv = _MD_convert_stat_to_fileinfo(&sb, info);
+    return rv;
+}
+
+PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info)
+{
+    _MDStat64 sb;
+    PRInt32 rv = _md_iovector._stat64(fn, &sb);
+    if (rv < 0)
+        _PR_MD_MAP_STAT_ERROR(_MD_ERRNO());
+    else if (NULL != info)
+        rv = _MD_convert_stat64_to_fileinfo64(&sb, info);
+    return rv;
+}
+
+PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info)
+{
+    struct stat sb;
+    PRInt32 rv = fstat(fd->secret->md.osfd, &sb);
+    if (rv < 0)
+        _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO());
+    else if (NULL != info)
+        rv = _MD_convert_stat_to_fileinfo(&sb, info);
+    return rv;
+}
+
+PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info)
+{
+    _MDStat64 sb;
+    PRInt32 rv = _md_iovector._fstat64(fd->secret->md.osfd, &sb);
+    if (rv < 0)
+        _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO());
+    else if (NULL != info)
+        rv = _MD_convert_stat64_to_fileinfo64(&sb, info);
+    return rv;
+}
+
+/*
+ * _md_iovector._open64 must be initialized to 'open' so that _PR_InitLog can
+ * open the log file during NSPR initialization, before _md_iovector is
+ * initialized by _PR_MD_FINAL_INIT.  This means the log file cannot be a
+ * large file on some platforms.
+ */
+#ifdef SYMBIAN
+struct _MD_IOVector _md_iovector; /* Will crash if NSPR_LOG_FILE is set. */
+#else
+struct _MD_IOVector _md_iovector = { open };
+#endif
+
+/*
+** These implementations are to emulate large file routines on systems that
+** don't have them. Their goal is to check in case overflow occurs. Otherwise
+** they will just operate as normal using 32-bit file routines.
+**
+** The checking might be pre- or post-op, depending on the semantics.
+*/
+
+#if defined(SOLARIS2_5)
+
+static PRIntn _MD_solaris25_fstat64(PRIntn osfd, _MDStat64 *buf)
+{
+    PRInt32 rv;
+    struct stat sb;
+
+    rv = fstat(osfd, &sb);
+    if (rv >= 0)
+    {
+        /*
+        ** I'm only copying the fields that are immediately needed.
+        ** If somebody else calls this function, some of the fields
+        ** may not be defined.
+        */
+        (void)memset(buf, 0, sizeof(_MDStat64));
+        buf->st_mode = sb.st_mode;
+        buf->st_ctim = sb.st_ctim;
+        buf->st_mtim = sb.st_mtim;
+        buf->st_size = sb.st_size;
+    }
+    return rv;
+}  /* _MD_solaris25_fstat64 */
+
+static PRIntn _MD_solaris25_stat64(const char *fn, _MDStat64 *buf)
+{
+    PRInt32 rv;
+    struct stat sb;
+
+    rv = stat(fn, &sb);
+    if (rv >= 0)
+    {
+        /*
+        ** I'm only copying the fields that are immediately needed.
+        ** If somebody else calls this function, some of the fields
+        ** may not be defined.
+        */
+        (void)memset(buf, 0, sizeof(_MDStat64));
+        buf->st_mode = sb.st_mode;
+        buf->st_ctim = sb.st_ctim;
+        buf->st_mtim = sb.st_mtim;
+        buf->st_size = sb.st_size;
+    }
+    return rv;
+}  /* _MD_solaris25_stat64 */
+#endif /* defined(SOLARIS2_5) */
+
+#if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5)
+
+static PROffset64 _MD_Unix_lseek64(PRIntn osfd, PROffset64 offset, PRIntn whence)
+{
+    PRUint64 maxoff;
+    PROffset64 rv = minus_one;
+    LL_I2L(maxoff, 0x7fffffff);
+    if (LL_CMP(offset, <=, maxoff))
+    {
+        off_t off;
+        LL_L2I(off, offset);
+        LL_I2L(rv, lseek(osfd, off, whence));
+    }
+    else errno = EFBIG;  /* we can't go there */
+    return rv;
+}  /* _MD_Unix_lseek64 */
+
+static void* _MD_Unix_mmap64(
+    void *addr, PRSize len, PRIntn prot, PRIntn flags,
+    PRIntn fildes, PRInt64 offset)
+{
+    PR_SetError(PR_FILE_TOO_BIG_ERROR, 0);
+    return NULL;
+}  /* _MD_Unix_mmap64 */
+#endif /* defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) */
+
+#if defined(OSF1) && defined(__GNUC__)
+
+/*
+ * On OSF1 V5.0A, <sys/stat.h> defines stat and fstat as
+ * macros when compiled under gcc, so it is rather tricky to
+ * take the addresses of the real functions the macros expend
+ * to.  A simple solution is to define forwarder functions
+ * and take the addresses of the forwarder functions instead.
+ */
+
+static int stat_forwarder(const char *path, struct stat *buffer)
+{
+    return stat(path, buffer);
+}
+
+static int fstat_forwarder(int filedes, struct stat *buffer)
+{
+    return fstat(filedes, buffer);
+}
+
+#endif
+
+static void _PR_InitIOV(void)
+{
+#if defined(SOLARIS2_5)
+    PRLibrary *lib;
+    void *open64_func;
+
+    open64_func = PR_FindSymbolAndLibrary("open64", &lib);
+    if (NULL != open64_func)
+    {
+        PR_ASSERT(NULL != lib);
+        _md_iovector._open64 = (_MD_Open64)open64_func;
+        _md_iovector._mmap64 = (_MD_Mmap64)PR_FindSymbol(lib, "mmap64");
+        _md_iovector._fstat64 = (_MD_Fstat64)PR_FindSymbol(lib, "fstat64");
+        _md_iovector._stat64 = (_MD_Stat64)PR_FindSymbol(lib, "stat64");
+        _md_iovector._lseek64 = (_MD_Lseek64)PR_FindSymbol(lib, "lseek64");
+        (void)PR_UnloadLibrary(lib);
+    }
+    else
+    {
+        _md_iovector._open64 = open;
+        _md_iovector._mmap64 = _MD_Unix_mmap64;
+        _md_iovector._fstat64 = _MD_solaris25_fstat64;
+        _md_iovector._stat64 = _MD_solaris25_stat64;
+        _md_iovector._lseek64 = _MD_Unix_lseek64;
+    }
+#elif defined(_PR_NO_LARGE_FILES)
+    _md_iovector._open64 = open;
+    _md_iovector._mmap64 = _MD_Unix_mmap64;
+    _md_iovector._fstat64 = fstat;
+    _md_iovector._stat64 = stat;
+    _md_iovector._lseek64 = _MD_Unix_lseek64;
+#elif defined(_PR_HAVE_OFF64_T)
+#if defined(IRIX5_3)
+    _md_iovector._open64 = open;
+#else
+    _md_iovector._open64 = open64;
+#endif
+    _md_iovector._mmap64 = mmap64;
+    _md_iovector._fstat64 = fstat64;
+    _md_iovector._stat64 = stat64;
+    _md_iovector._lseek64 = lseek64;
+#elif defined(_PR_HAVE_LARGE_OFF_T)
+    _md_iovector._open64 = open;
+    _md_iovector._mmap64 = mmap;
+#if defined(OSF1) && defined(__GNUC__)
+    _md_iovector._fstat64 = fstat_forwarder;
+    _md_iovector._stat64 = stat_forwarder;
+#else
+    _md_iovector._fstat64 = fstat;
+    _md_iovector._stat64 = stat;
+#endif
+    _md_iovector._lseek64 = lseek;
+#else
+#error "I don't know yet"
+#endif
+    LL_I2L(minus_one, -1);
+}  /* _PR_InitIOV */
+
+void _PR_UnixInit(void)
+{
+    struct sigaction sigact;
+    int rv;
+
+    sigemptyset(&timer_set);
+
+#if !defined(_PR_PTHREADS)
+
+    sigaddset(&timer_set, SIGALRM);
+    sigemptyset(&empty_set);
+    intr_timeout_ticks =
+            PR_SecondsToInterval(_PR_INTERRUPT_CHECK_INTERVAL_SECS);
+
+#if defined(SOLARIS) || defined(IRIX)
+
+    if (getenv("NSPR_SIGSEGV_HANDLE")) {
+        sigact.sa_handler = sigsegvhandler;
+        sigact.sa_flags = 0;
+        sigact.sa_mask = timer_set;
+        sigaction(SIGSEGV, &sigact, 0);
+    }
+
+    if (getenv("NSPR_SIGABRT_HANDLE")) {
+        sigact.sa_handler = sigaborthandler;
+        sigact.sa_flags = 0;
+        sigact.sa_mask = timer_set;
+        sigaction(SIGABRT, &sigact, 0);
+    }
+
+    if (getenv("NSPR_SIGBUS_HANDLE")) {
+        sigact.sa_handler = sigbushandler;
+        sigact.sa_flags = 0;
+        sigact.sa_mask = timer_set;
+        sigaction(SIGBUS, &sigact, 0);
+    }
+
+#endif
+#endif  /* !defined(_PR_PTHREADS) */
+
+    /*
+     * Under HP-UX DCE threads, sigaction() installs a per-thread
+     * handler, so we use sigvector() to install a process-wide
+     * handler.
+     */
+#if defined(HPUX) && defined(_PR_DCETHREADS)
+    {
+        struct sigvec vec;
+
+        vec.sv_handler = SIG_IGN;
+        vec.sv_mask = 0;
+        vec.sv_flags = 0;
+        rv = sigvector(SIGPIPE, &vec, NULL);
+        PR_ASSERT(0 == rv);
+    }
+#else
+    sigact.sa_handler = SIG_IGN;
+    sigemptyset(&sigact.sa_mask);
+    sigact.sa_flags = 0;
+    rv = sigaction(SIGPIPE, &sigact, 0);
+    PR_ASSERT(0 == rv);
+#endif /* HPUX && _PR_DCETHREADS */
+
+    _pr_rename_lock = PR_NewLock();
+    PR_ASSERT(NULL != _pr_rename_lock);
+    _pr_Xfe_mon = PR_NewMonitor();
+    PR_ASSERT(NULL != _pr_Xfe_mon);
+
+    _PR_InitIOV();  /* one last hack */
+}
+
+#if !defined(_PR_PTHREADS)
+
+/*
+ * Variables used by the GC code, initialized in _MD_InitSegs().
+ */
+static PRInt32 _pr_zero_fd = -1;
+static PRLock *_pr_md_lock = NULL;
+
+/*
+ * _MD_InitSegs --
+ *
+ * This is Unix's version of _PR_MD_INIT_SEGS(), which is
+ * called by _PR_InitSegs(), which in turn is called by
+ * PR_Init().
+ */
+void _MD_InitSegs(void)
+{
+#ifdef DEBUG
+    /*
+    ** Disable using mmap(2) if NSPR_NO_MMAP is set
+    */
+    if (getenv("NSPR_NO_MMAP")) {
+        _pr_zero_fd = -2;
+        return;
+    }
+#endif
+    _pr_zero_fd = open("/dev/zero",O_RDWR , 0);
+    /* Prevent the fd from being inherited by child processes */
+    fcntl(_pr_zero_fd, F_SETFD, FD_CLOEXEC);
+    _pr_md_lock = PR_NewLock();
+}
+
+PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr)
+{
+    static char *lastaddr = (char*) _PR_STACK_VMBASE;
+    PRStatus retval = PR_SUCCESS;
+    int prot;
+    void *rv;
+
+    PR_ASSERT(seg != 0);
+    PR_ASSERT(size != 0);
+
+    PR_Lock(_pr_md_lock);
+    if (_pr_zero_fd < 0) {
+from_heap:
+        seg->vaddr = PR_MALLOC(size);
+        if (!seg->vaddr) {
+            retval = PR_FAILURE;
+        }
+        else {
+            seg->size = size;
+        }
+        goto exit;
+    }
+
+    prot = PROT_READ|PROT_WRITE;
+    /*
+     * On Alpha Linux, the user-level thread stack needs
+     * to be made executable because longjmp/signal seem
+     * to put machine instructions on the stack.
+     */
+#if defined(LINUX) && defined(__alpha)
+    prot |= PROT_EXEC;
+#endif
+    rv = mmap((vaddr != 0) ? vaddr : lastaddr, size, prot,
+        _MD_MMAP_FLAGS,
+        _pr_zero_fd, 0);
+    if (rv == (void*)-1) {
+        goto from_heap;
+    }
+    lastaddr += size;
+    seg->vaddr = rv;
+    seg->size = size;
+    seg->flags = _PR_SEG_VM;
+
+exit:
+    PR_Unlock(_pr_md_lock);
+    return retval;
+}
+
+void _MD_FreeSegment(PRSegment *seg)
+{
+    if (seg->flags & _PR_SEG_VM)
+        (void) munmap(seg->vaddr, seg->size);
+    else
+        PR_DELETE(seg->vaddr);
+}
+
+#endif /* _PR_PTHREADS */
+
+/*
+ *-----------------------------------------------------------------------
+ *
+ * PR_Now --
+ *
+ *     Returns the current time in microseconds since the epoch.
+ *     The epoch is midnight January 1, 1970 GMT.
+ *     The implementation is machine dependent.  This is the Unix
+ *     implementation.
+ *     Cf. time_t time(time_t *tp)
+ *
+ *-----------------------------------------------------------------------
+ */
+
+PR_IMPLEMENT(PRTime)
+PR_Now(void)
+{
+    struct timeval tv;
+    PRInt64 s, us, s2us;
+
+    GETTIMEOFDAY(&tv);
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(s, tv.tv_sec);
+    LL_I2L(us, tv.tv_usec);
+    LL_MUL(s, s, s2us);
+    LL_ADD(s, s, us);
+    return s;
+}
+
+PRIntervalTime _PR_UNIX_GetInterval()
+{
+    struct timeval time;
+    PRIntervalTime ticks;
+
+    (void)GETTIMEOFDAY(&time);  /* fallicy of course */
+    ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC;  /* that's in milliseconds */
+    ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC;  /* so's that */
+    return ticks;
+}  /* _PR_SUNOS_GetInterval */
+
+PRIntervalTime _PR_UNIX_TicksPerSecond()
+{
+    return 1000;  /* this needs some work :) */
+}
+
+#if !defined(_PR_PTHREADS)
+/*
+ * Wait for I/O on multiple descriptors.
+ *
+ * Return 0 if timed out, return -1 if interrupted,
+ * else return the number of ready descriptors.
+ */
+PRInt32 _PR_WaitForMultipleFDs(
+    _PRUnixPollDesc *unixpds,
+    PRInt32 pdcnt,
+    PRIntervalTime timeout)
+{
+    PRPollQueue pq;
+    PRIntn is;
+    PRInt32 rv;
+    _PRCPU *io_cpu;
+    _PRUnixPollDesc *unixpd, *eunixpd;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
+
+    if (_PR_PENDING_INTERRUPT(me)) {
+        me->flags &= ~_PR_INTERRUPT;
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        return -1;
+    }
+
+    pq.pds = unixpds;
+    pq.npds = pdcnt;
+
+    _PR_INTSOFF(is);
+    _PR_MD_IOQ_LOCK();
+    _PR_THREAD_LOCK(me);
+
+    pq.thr = me;
+    io_cpu = me->cpu;
+    pq.on_ioq = PR_TRUE;
+    pq.timeout = timeout;
+    _PR_ADD_TO_IOQ(pq, me->cpu);
+
+#if !defined(_PR_USE_POLL)
+    eunixpd = unixpds + pdcnt;
+    for (unixpd = unixpds; unixpd < eunixpd; unixpd++) {
+        PRInt32 osfd = unixpd->osfd;
+        if (unixpd->in_flags & _PR_UNIX_POLL_READ) {
+            FD_SET(osfd, &_PR_FD_READ_SET(me->cpu));
+            _PR_FD_READ_CNT(me->cpu)[osfd]++;
+        }
+        if (unixpd->in_flags & _PR_UNIX_POLL_WRITE) {
+            FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu));
+            (_PR_FD_WRITE_CNT(me->cpu))[osfd]++;
+        }
+        if (unixpd->in_flags & _PR_UNIX_POLL_EXCEPT) {
+            FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
+            (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++;
+        }
+        if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) {
+            _PR_IOQ_MAX_OSFD(me->cpu) = osfd;
+        }
+    }
+#endif  /* !defined(_PR_USE_POLL) */
+
+    if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) {
+        _PR_IOQ_TIMEOUT(me->cpu) = timeout;
+    }
+
+    _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt;
+        
+    _PR_SLEEPQ_LOCK(me->cpu);
+    _PR_ADD_SLEEPQ(me, timeout);
+    me->state = _PR_IO_WAIT;
+    me->io_pending = PR_TRUE;
+    me->io_suspended = PR_FALSE;
+    _PR_SLEEPQ_UNLOCK(me->cpu);
+    _PR_THREAD_UNLOCK(me);
+    _PR_MD_IOQ_UNLOCK();
+
+    _PR_MD_WAIT(me, timeout);
+
+    me->io_pending = PR_FALSE;
+    me->io_suspended = PR_FALSE;
+
+    /*
+     * This thread should run on the same cpu on which it was blocked; when 
+     * the IO request times out the fd sets and fd counts for the
+     * cpu are updated below.
+     */
+    PR_ASSERT(me->cpu == io_cpu);
+
+    /*
+    ** If we timed out the pollq might still be on the ioq. Remove it
+    ** before continuing.
+    */
+    if (pq.on_ioq) {
+        _PR_MD_IOQ_LOCK();
+        /*
+         * Need to check pq.on_ioq again
+         */
+        if (pq.on_ioq) {
+            PR_REMOVE_LINK(&pq.links);
+#ifndef _PR_USE_POLL
+            eunixpd = unixpds + pdcnt;
+            for (unixpd = unixpds; unixpd < eunixpd; unixpd++) {
+                PRInt32 osfd = unixpd->osfd;
+                PRInt16 in_flags = unixpd->in_flags;
+
+                if (in_flags & _PR_UNIX_POLL_READ) {
+                    if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
+                        FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
+                }
+                if (in_flags & _PR_UNIX_POLL_WRITE) {
+                    if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
+                        FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
+                }
+                if (in_flags & _PR_UNIX_POLL_EXCEPT) {
+                    if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
+                        FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
+                }
+            }
+#endif  /* _PR_USE_POLL */
+            PR_ASSERT(pq.npds == pdcnt);
+            _PR_IOQ_OSFD_CNT(me->cpu) -= pdcnt;
+            PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0);
+        }
+        _PR_MD_IOQ_UNLOCK();
+    }
+    /* XXX Should we use _PR_FAST_INTSON or _PR_INTSON? */
+    if (1 == pdcnt) {
+        _PR_FAST_INTSON(is);
+    } else {
+        _PR_INTSON(is);
+    }
+
+    if (_PR_PENDING_INTERRUPT(me)) {
+        me->flags &= ~_PR_INTERRUPT;
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        return -1;
+    }
+
+    rv = 0;
+    if (pq.on_ioq == PR_FALSE) {
+        /* Count the number of ready descriptors */
+        while (--pdcnt >= 0) {
+            if (unixpds->out_flags != 0) {
+                rv++;
+            }
+            unixpds++;
+        }
+    }
+
+    return rv;
+}
+
+/*
+ * Unblock threads waiting for I/O
+ *    used when interrupting threads
+ *
+ * NOTE: The thread lock should held when this function is called.
+ * On return, the thread lock is released.
+ */
+void _PR_Unblock_IO_Wait(PRThread *thr)
+{
+    int pri = thr->priority;
+    _PRCPU *cpu = thr->cpu;
+ 
+    /*
+     * GLOBAL threads wakeup periodically to check for interrupt
+     */
+    if (_PR_IS_NATIVE_THREAD(thr)) {
+        _PR_THREAD_UNLOCK(thr); 
+        return;
+    }
+
+    PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ));
+    _PR_SLEEPQ_LOCK(cpu);
+    _PR_DEL_SLEEPQ(thr, PR_TRUE);
+    _PR_SLEEPQ_UNLOCK(cpu);
+
+    PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD));
+    thr->state = _PR_RUNNABLE;
+    _PR_RUNQ_LOCK(cpu);
+    _PR_ADD_RUNQ(thr, cpu, pri);
+    _PR_RUNQ_UNLOCK(cpu);
+    _PR_THREAD_UNLOCK(thr);
+    _PR_MD_WAKEUP_WAITER(thr);
+}
+#endif  /* !defined(_PR_PTHREADS) */
+
+/*
+ * When a nonblocking connect has completed, determine whether it
+ * succeeded or failed, and if it failed, what the error code is.
+ *
+ * The function returns the error code.  An error code of 0 means
+ * that the nonblocking connect succeeded.
+ */
+
+int _MD_unix_get_nonblocking_connect_error(int osfd)
+{
+#if defined(NTO)
+    /* Neutrino does not support the SO_ERROR socket option */
+    PRInt32      rv;
+    PRNetAddr    addr;
+    _PRSockLen_t addrlen = sizeof(addr);
+
+    /* Test to see if we are using the Tiny TCP/IP Stack or the Full one. */
+    struct statvfs superblock;
+    rv = fstatvfs(osfd, &superblock);
+    if (rv == 0) {
+        if (strcmp(superblock.f_basetype, "ttcpip") == 0) {
+            /* Using the Tiny Stack! */
+            rv = getpeername(osfd, (struct sockaddr *) &addr,
+                    (_PRSockLen_t *) &addrlen);
+            if (rv == -1) {
+                int errno_copy = errno;    /* make a copy so I don't
+                                            * accidentally reset */
+
+                if (errno_copy == ENOTCONN) {
+                    struct stat StatInfo;
+                    rv = fstat(osfd, &StatInfo);
+                    if (rv == 0) {
+                        time_t current_time = time(NULL);
+
+                        /*
+                         * this is a real hack, can't explain why it
+                         * works it just does
+                         */
+                        if (abs(current_time - StatInfo.st_atime) < 5) {
+                            return ECONNREFUSED;
+                        } else {
+                            return ETIMEDOUT;
+                        }
+                    } else {
+                        return ECONNREFUSED;
+                    }
+                } else {
+                    return errno_copy;
+                }
+            } else {
+                /* No Error */
+                return 0;
+            }
+        } else {
+            /* Have the FULL Stack which supports SO_ERROR */
+            /* Hasn't been written yet, never been tested! */
+            /* Jerry.Kirk@Nexwarecorp.com */
+
+            int err;
+            _PRSockLen_t optlen = sizeof(err);
+
+            if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
+                    (char *) &err, &optlen) == -1) {
+                return errno;
+            } else {
+                return err;
+            }		
+        }
+    } else {
+        return ECONNREFUSED;
+    }	
+#elif defined(NCR) || defined(UNIXWARE) || defined(SNI) || defined(NEC)
+    /*
+     * getsockopt() fails with EPIPE, so use getmsg() instead.
+     */
+
+    int rv;
+    int flags = 0;
+    rv = getmsg(osfd, NULL, NULL, &flags);
+    PR_ASSERT(-1 == rv || 0 == rv);
+    if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) {
+        return errno;
+    }
+    return 0;  /* no error */
+#else
+    int err;
+    _PRSockLen_t optlen = sizeof(err);
+    if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) {
+        return errno;
+    } else {
+        return err;
+    }
+#endif
+}
+
+/************************************************************************/
+
+/*
+** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread
+** safe.  Unfortunately, neither is mozilla. To make these programs work
+** in a pre-emptive threaded environment, we need to use a lock.
+*/
+
+void PR_XLock(void)
+{
+    PR_EnterMonitor(_pr_Xfe_mon);
+}
+
+void PR_XUnlock(void)
+{
+    PR_ExitMonitor(_pr_Xfe_mon);
+}
+
+PRBool PR_XIsLocked(void)
+{
+    return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE;
+}
+
+void PR_XWait(int ms)
+{
+    PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms));
+}
+
+void PR_XNotify(void)
+{
+    PR_Notify(_pr_Xfe_mon);
+}
+
+void PR_XNotifyAll(void)
+{
+    PR_NotifyAll(_pr_Xfe_mon);
+}
+
+#if defined(HAVE_FCNTL_FILE_LOCKING)
+
+PRStatus
+_MD_LockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    struct flock arg;
+
+    arg.l_type = F_WRLCK;
+    arg.l_whence = SEEK_SET;
+    arg.l_start = 0;
+    arg.l_len = 0;  /* until EOF */
+    rv = fcntl(f, F_SETLKW, &arg);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+PRStatus
+_MD_TLockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    struct flock arg;
+
+    arg.l_type = F_WRLCK;
+    arg.l_whence = SEEK_SET;
+    arg.l_start = 0;
+    arg.l_len = 0;  /* until EOF */
+    rv = fcntl(f, F_SETLK, &arg);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+PRStatus
+_MD_UnlockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    struct flock arg;
+
+    arg.l_type = F_UNLCK;
+    arg.l_whence = SEEK_SET;
+    arg.l_start = 0;
+    arg.l_len = 0;  /* until EOF */
+    rv = fcntl(f, F_SETLK, &arg);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+#elif defined(HAVE_BSD_FLOCK)
+
+#include <sys/file.h>
+
+PRStatus
+_MD_LockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    rv = flock(f, LOCK_EX);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+PRStatus
+_MD_TLockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    rv = flock(f, LOCK_EX|LOCK_NB);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+PRStatus
+_MD_UnlockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    rv = flock(f, LOCK_UN);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+#else
+
+PRStatus
+_MD_LockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    rv = lockf(f, F_LOCK, 0);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+PRStatus
+_MD_TLockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    rv = lockf(f, F_TLOCK, 0);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+PRStatus
+_MD_UnlockFile(PRInt32 f)
+{
+    PRInt32 rv;
+    rv = lockf(f, F_ULOCK, 0);
+    if (rv == 0)
+        return PR_SUCCESS;
+    _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+#endif
+
+PRStatus _MD_gethostname(char *name, PRUint32 namelen)
+{
+    PRIntn rv;
+
+    rv = gethostname(name, namelen);
+    if (0 == rv) {
+        return PR_SUCCESS;
+    }
+    _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO());
+    return PR_FAILURE;
+}
+
+PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen)
+{
+	struct utsname info;
+
+	PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE));
+
+	if (uname(&info) == -1) {
+		_PR_MD_MAP_DEFAULT_ERROR(errno);
+    	return PR_FAILURE;
+	}
+	if (PR_SI_SYSNAME == cmd)
+		(void)PR_snprintf(name, namelen, info.sysname);
+	else if (PR_SI_RELEASE == cmd)
+		(void)PR_snprintf(name, namelen, info.release);
+	else
+		return PR_FAILURE;
+    return PR_SUCCESS;
+}
+
+/*
+ *******************************************************************
+ *
+ * Memory-mapped files
+ *
+ *******************************************************************
+ */
+
+PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
+{
+    PRFileInfo info;
+    PRUint32 sz;
+
+    LL_L2UI(sz, size);
+    if (sz) {
+        if (PR_GetOpenFileInfo(fmap->fd, &info) == PR_FAILURE) {
+            return PR_FAILURE;
+        }
+        if (sz > info.size) {
+            /*
+             * Need to extend the file
+             */
+            if (fmap->prot != PR_PROT_READWRITE) {
+                PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0);
+                return PR_FAILURE;
+            }
+            if (PR_Seek(fmap->fd, sz - 1, PR_SEEK_SET) == -1) {
+                return PR_FAILURE;
+            }
+            if (PR_Write(fmap->fd, "", 1) != 1) {
+                return PR_FAILURE;
+            }
+        }
+    }
+    if (fmap->prot == PR_PROT_READONLY) {
+        fmap->md.prot = PROT_READ;
+#ifdef OSF1V4_MAP_PRIVATE_BUG
+        /*
+         * Use MAP_SHARED to work around a bug in OSF1 V4.0D
+         * (QAR 70220 in the OSF_QAR database) that results in
+         * corrupted data in the memory-mapped region.  This
+         * bug is fixed in V5.0.
+         */
+        fmap->md.flags = MAP_SHARED;
+#else
+        fmap->md.flags = MAP_PRIVATE;
+#endif
+    } else if (fmap->prot == PR_PROT_READWRITE) {
+        fmap->md.prot = PROT_READ | PROT_WRITE;
+        fmap->md.flags = MAP_SHARED;
+    } else {
+        PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
+        fmap->md.prot = PROT_READ | PROT_WRITE;
+        fmap->md.flags = MAP_PRIVATE;
+    }
+    return PR_SUCCESS;
+}
+
+void * _MD_MemMap(
+    PRFileMap *fmap,
+    PRInt64 offset,
+    PRUint32 len)
+{
+    PRInt32 off;
+    void *addr;
+
+    LL_L2I(off, offset);
+    if ((addr = mmap(0, len, fmap->md.prot, fmap->md.flags,
+        fmap->fd->secret->md.osfd, off)) == (void *) -1) {
+            _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
+        addr = NULL;
+    }
+    return addr;
+}
+
+PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
+{
+    if (munmap(addr, len) == 0) {
+        return PR_SUCCESS;
+    } else {
+    if (errno == EINVAL) {
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno);
+    } else {
+        PR_SetError(PR_UNKNOWN_ERROR, errno);
+    }
+        return PR_FAILURE;
+    }
+}
+
+PRStatus _MD_CloseFileMap(PRFileMap *fmap)
+{
+    if ( PR_TRUE == fmap->md.isAnonFM ) {
+        PRStatus rc = PR_Close( fmap->fd );
+        if ( PR_FAILURE == rc ) {
+            PR_LOG( _pr_io_lm, PR_LOG_DEBUG,
+                ("_MD_CloseFileMap(): error closing anonymnous file map osfd"));
+            return PR_FAILURE;
+        }
+    }
+    PR_DELETE(fmap);
+    return PR_SUCCESS;
+}
+
+#if defined(_PR_NEED_FAKE_POLL)
+
+/*
+ * Some platforms don't have poll().  For easier porting of code
+ * that calls poll(), we emulate poll() using select().
+ */
+
+int poll(struct pollfd *filedes, unsigned long nfds, int timeout)
+{
+    int i;
+    int rv;
+    int maxfd;
+    fd_set rd, wr, ex;
+    struct timeval tv, *tvp;
+
+    if (timeout < 0 && timeout != -1) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (timeout == -1) {
+        tvp = NULL;
+    } else {
+        tv.tv_sec = timeout / 1000;
+        tv.tv_usec = (timeout % 1000) * 1000;
+        tvp = &tv;
+    }
+
+    maxfd = -1;
+    FD_ZERO(&rd);
+    FD_ZERO(&wr);
+    FD_ZERO(&ex);
+
+    for (i = 0; i < nfds; i++) {
+        int osfd = filedes[i].fd;
+        int events = filedes[i].events;
+        PRBool fdHasEvent = PR_FALSE;
+
+        if (osfd < 0) {
+            continue;  /* Skip this osfd. */
+        }
+
+        /*
+         * Map the poll events to the select fd_sets.
+         *     POLLIN, POLLRDNORM  ===> readable
+         *     POLLOUT, POLLWRNORM ===> writable
+         *     POLLPRI, POLLRDBAND ===> exception
+         *     POLLNORM, POLLWRBAND (and POLLMSG on some platforms)
+         *     are ignored.
+         *
+         * The output events POLLERR and POLLHUP are never turned on.
+         * POLLNVAL may be turned on.
+         */
+
+        if (events & (POLLIN | POLLRDNORM)) {
+            FD_SET(osfd, &rd);
+            fdHasEvent = PR_TRUE;
+        }
+        if (events & (POLLOUT | POLLWRNORM)) {
+            FD_SET(osfd, &wr);
+            fdHasEvent = PR_TRUE;
+        }
+        if (events & (POLLPRI | POLLRDBAND)) {
+            FD_SET(osfd, &ex);
+            fdHasEvent = PR_TRUE;
+        }
+        if (fdHasEvent && osfd > maxfd) {
+            maxfd = osfd;
+        }
+    }
+
+    rv = select(maxfd + 1, &rd, &wr, &ex, tvp);
+
+    /* Compute poll results */
+    if (rv > 0) {
+        rv = 0;
+        for (i = 0; i < nfds; i++) {
+            PRBool fdHasEvent = PR_FALSE;
+
+            filedes[i].revents = 0;
+            if (filedes[i].fd < 0) {
+                continue;
+            }
+            if (FD_ISSET(filedes[i].fd, &rd)) {
+                if (filedes[i].events & POLLIN) {
+                    filedes[i].revents |= POLLIN;
+                }
+                if (filedes[i].events & POLLRDNORM) {
+                    filedes[i].revents |= POLLRDNORM;
+                }
+                fdHasEvent = PR_TRUE;
+            }
+            if (FD_ISSET(filedes[i].fd, &wr)) {
+                if (filedes[i].events & POLLOUT) {
+                    filedes[i].revents |= POLLOUT;
+                }
+                if (filedes[i].events & POLLWRNORM) {
+                    filedes[i].revents |= POLLWRNORM;
+                }
+                fdHasEvent = PR_TRUE;
+            }
+            if (FD_ISSET(filedes[i].fd, &ex)) {
+                if (filedes[i].events & POLLPRI) {
+                    filedes[i].revents |= POLLPRI;
+                }
+                if (filedes[i].events & POLLRDBAND) {
+                    filedes[i].revents |= POLLRDBAND;
+                }
+                fdHasEvent = PR_TRUE;
+            }
+            if (fdHasEvent) {
+                rv++;
+            }
+        }
+        PR_ASSERT(rv > 0);
+    } else if (rv == -1 && errno == EBADF) {
+        rv = 0;
+        for (i = 0; i < nfds; i++) {
+            filedes[i].revents = 0;
+            if (filedes[i].fd < 0) {
+                continue;
+            }
+            if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) {
+                filedes[i].revents = POLLNVAL;
+                rv++;
+            }
+        }
+        PR_ASSERT(rv > 0);
+    }
+    PR_ASSERT(-1 != timeout || rv != 0);
+
+    return rv;
+}
+#endif /* _PR_NEED_FAKE_POLL */
diff --git a/mozilla/nsprpub/pr/src/md/unix/unix_errors.c b/mozilla/nsprpub/pr/src/md/unix/unix_errors.c
new file mode 100644
index 0000000..a1b88dc
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/unix_errors.c
@@ -0,0 +1,880 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#if defined(_PR_POLL_AVAILABLE)
+#include <poll.h>
+#endif
+#include <errno.h>
+
+void _MD_unix_map_default_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err ) {
+        case EACCES:
+            prError = PR_NO_ACCESS_RIGHTS_ERROR;
+            break;
+        case EADDRINUSE:
+            prError = PR_ADDRESS_IN_USE_ERROR;
+            break;
+        case EADDRNOTAVAIL:
+            prError = PR_ADDRESS_NOT_AVAILABLE_ERROR;
+            break;
+        case EAFNOSUPPORT:
+            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
+            break;
+        case EAGAIN:
+            prError = PR_WOULD_BLOCK_ERROR;
+            break;
+        /*
+         * On QNX and Neutrino, EALREADY is defined as EBUSY.
+         */
+#if EALREADY != EBUSY
+        case EALREADY:
+            prError = PR_ALREADY_INITIATED_ERROR;
+            break;
+#endif
+        case EBADF:
+            prError = PR_BAD_DESCRIPTOR_ERROR;
+            break;
+#ifdef EBADMSG
+        case EBADMSG:
+            prError = PR_IO_ERROR;
+            break;
+#endif
+        case EBUSY:
+            prError = PR_FILESYSTEM_MOUNTED_ERROR;
+            break;
+        case ECONNABORTED:
+            prError = PR_CONNECT_ABORTED_ERROR;
+            break;
+        case ECONNREFUSED:
+            prError = PR_CONNECT_REFUSED_ERROR;
+            break;
+        case ECONNRESET:
+            prError = PR_CONNECT_RESET_ERROR;
+            break;
+        case EDEADLK:
+            prError = PR_DEADLOCK_ERROR;
+            break;
+#ifdef EDIRCORRUPTED
+        case EDIRCORRUPTED:
+            prError = PR_DIRECTORY_CORRUPTED_ERROR;
+            break;
+#endif
+#ifdef EDQUOT
+        case EDQUOT:
+            prError = PR_NO_DEVICE_SPACE_ERROR;
+            break;
+#endif
+        case EEXIST:
+            prError = PR_FILE_EXISTS_ERROR;
+            break;
+        case EFAULT:
+            prError = PR_ACCESS_FAULT_ERROR;
+            break;
+        case EFBIG:
+            prError = PR_FILE_TOO_BIG_ERROR;
+            break;
+        case EHOSTUNREACH:
+            prError = PR_HOST_UNREACHABLE_ERROR;
+            break;
+        case EINPROGRESS:
+            prError = PR_IN_PROGRESS_ERROR;
+            break;
+        case EINTR:
+            prError = PR_PENDING_INTERRUPT_ERROR;
+            break;
+        case EINVAL:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case EIO:
+            prError = PR_IO_ERROR;
+            break;
+        case EISCONN:
+            prError = PR_IS_CONNECTED_ERROR;
+            break;
+        case EISDIR:
+            prError = PR_IS_DIRECTORY_ERROR;
+            break;
+        case ELOOP:
+            prError = PR_LOOP_ERROR;
+            break;
+        case EMFILE:
+            prError = PR_PROC_DESC_TABLE_FULL_ERROR;
+            break;
+        case EMLINK:
+            prError = PR_MAX_DIRECTORY_ENTRIES_ERROR;
+            break;
+        case EMSGSIZE:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+#ifdef EMULTIHOP
+        case EMULTIHOP:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+#endif
+        case ENAMETOOLONG:
+            prError = PR_NAME_TOO_LONG_ERROR;
+            break;
+        case ENETUNREACH:
+            prError = PR_NETWORK_UNREACHABLE_ERROR;
+            break;
+        case ENFILE:
+            prError = PR_SYS_DESC_TABLE_FULL_ERROR;
+            break;
+        /*
+         * On SCO OpenServer 5, ENOBUFS is defined as ENOSR.
+         */
+#if defined(ENOBUFS) && (ENOBUFS != ENOSR)
+        case ENOBUFS:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+#endif
+        case ENODEV:
+            prError = PR_FILE_NOT_FOUND_ERROR;
+            break;
+        case ENOENT:
+            prError = PR_FILE_NOT_FOUND_ERROR;
+            break;
+        case ENOLCK:
+            prError = PR_FILE_IS_LOCKED_ERROR;
+            break;
+#ifdef ENOLINK 
+        case ENOLINK:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+#endif
+        case ENOMEM:
+            prError = PR_OUT_OF_MEMORY_ERROR;
+            break;
+        case ENOPROTOOPT:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case ENOSPC:
+            prError = PR_NO_DEVICE_SPACE_ERROR;
+            break;
+#ifdef ENOSR
+        case ENOSR:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+#endif
+        case ENOSYS:
+            prError = PR_NOT_IMPLEMENTED_ERROR;
+            break;
+        case ENOTCONN:
+            prError = PR_NOT_CONNECTED_ERROR;
+            break;
+        case ENOTDIR:
+            prError = PR_NOT_DIRECTORY_ERROR;
+            break;
+        case ENOTSOCK:
+            prError = PR_NOT_SOCKET_ERROR;
+            break;
+        case ENXIO:
+            prError = PR_FILE_NOT_FOUND_ERROR;
+            break;
+        case EOPNOTSUPP:
+            prError = PR_NOT_TCP_SOCKET_ERROR;
+            break;
+#ifdef EOVERFLOW
+        case EOVERFLOW:
+            prError = PR_BUFFER_OVERFLOW_ERROR;
+            break;
+#endif
+        case EPERM:
+            prError = PR_NO_ACCESS_RIGHTS_ERROR;
+            break;
+        case EPIPE:
+            prError = PR_CONNECT_RESET_ERROR;
+            break;
+#ifdef EPROTO
+        case EPROTO:
+            prError = PR_IO_ERROR;
+            break;
+#endif
+        case EPROTONOSUPPORT:
+            prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR;
+            break;
+        case EPROTOTYPE:
+            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
+            break;
+        case ERANGE:
+            prError = PR_INVALID_METHOD_ERROR;
+            break;
+        case EROFS:
+            prError = PR_READ_ONLY_FILESYSTEM_ERROR;
+            break;
+        case ESPIPE:
+            prError = PR_INVALID_METHOD_ERROR;
+            break;
+        case ETIMEDOUT:
+            prError = PR_IO_TIMEOUT_ERROR;
+            break;
+#if EWOULDBLOCK != EAGAIN
+        case EWOULDBLOCK:
+            prError = PR_WOULD_BLOCK_ERROR;
+            break;
+#endif
+        case EXDEV:
+            prError = PR_NOT_SAME_DEVICE_ERROR;
+            break;
+        default:
+            prError = PR_UNKNOWN_ERROR;
+            break;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_opendir_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_closedir_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EINVAL:
+            prError = PR_BAD_DESCRIPTOR_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_readdir_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case 0:
+        case ENOENT:
+            prError = PR_NO_MORE_FILES_ERROR;
+            break;
+#ifdef EOVERFLOW
+        case EOVERFLOW:
+            prError = PR_IO_ERROR;
+            break;
+#endif
+        case EINVAL:
+            prError = PR_IO_ERROR;
+            break;
+        case ENXIO:
+            prError = PR_IO_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_unlink_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EPERM:
+            prError = PR_IS_DIRECTORY_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_stat_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_fstat_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_rename_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EEXIST:
+            prError = PR_DIRECTORY_NOT_EMPTY_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_access_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_mkdir_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_rmdir_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        /*
+         * On AIX 4.3, ENOTEMPTY is defined as EEXIST.
+         */
+#if ENOTEMPTY != EEXIST
+        case ENOTEMPTY:
+            prError = PR_DIRECTORY_NOT_EMPTY_ERROR;
+            break;
+#endif
+        case EEXIST:
+            prError = PR_DIRECTORY_NOT_EMPTY_ERROR;
+            break;
+        case EINVAL:
+            prError = PR_DIRECTORY_NOT_EMPTY_ERROR;
+            break;
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_read_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EINVAL:
+            prError = PR_INVALID_METHOD_ERROR;
+            break;
+        case ENXIO:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_write_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EINVAL:
+            prError = PR_INVALID_METHOD_ERROR;
+            break;
+        case ENXIO:
+            prError = PR_INVALID_METHOD_ERROR;
+            break;
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_lseek_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_fsync_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        case EINVAL:
+            prError = PR_INVALID_METHOD_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_close_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_socket_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ENOMEM:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_socketavailable_error(int err)
+{
+    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+}
+
+void _MD_unix_map_recv_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_recvfrom_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_send_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_sendto_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_writev_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_accept_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ENODEV:
+            prError = PR_NOT_TCP_SOCKET_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_connect_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EACCES:
+            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
+            break;
+#if defined(UNIXWARE) || defined(SNI) || defined(NEC)
+        /*
+         * On some platforms, if we connect to a port on the local host 
+         * (the loopback address) that no process is listening on, we get 
+         * EIO instead of ECONNREFUSED.
+         */
+        case EIO:
+            prError = PR_CONNECT_REFUSED_ERROR;
+            break;
+#endif
+        case ELOOP:
+            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
+            break;
+        case ENOENT:
+            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
+            break;
+        case ENXIO:
+            prError = PR_IO_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_bind_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EINVAL:
+            prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR;
+            break;
+        /*
+         * UNIX domain sockets are not supported in NSPR
+         */
+        case EIO:
+        case EISDIR:
+        case ELOOP:
+        case ENOENT:
+        case ENOTDIR:
+        case EROFS:
+            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_listen_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_shutdown_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_socketpair_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ENOMEM:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_getsockname_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ENOMEM:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_getpeername_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ENOMEM:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_getsockopt_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EINVAL:
+            prError = PR_BUFFER_OVERFLOW_ERROR;
+            break;
+        case ENOMEM:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_setsockopt_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EINVAL:
+            prError = PR_BUFFER_OVERFLOW_ERROR;
+            break;
+        case ENOMEM:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_open_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EAGAIN:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        case EBUSY:
+            prError = PR_IO_ERROR;
+            break;
+        case ENODEV:
+            prError = PR_FILE_NOT_FOUND_ERROR;
+            break;
+        case ENOMEM:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+#ifdef EOVERFLOW
+        case EOVERFLOW:
+            prError = PR_FILE_TOO_BIG_ERROR;
+            break;
+#endif
+        case ETIMEDOUT:
+            prError = PR_REMOTE_FILE_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_mmap_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EAGAIN:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        case EMFILE:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        case ENODEV:
+            prError = PR_OPERATION_NOT_SUPPORTED_ERROR;
+            break;
+        case ENXIO:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_gethostname_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+void _MD_unix_map_select_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+
+#if defined(_PR_POLL_AVAILABLE) || defined(_PR_NEED_FAKE_POLL)
+void _MD_unix_map_poll_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EAGAIN:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_poll_revents_error(int err)
+{
+    if (err & POLLNVAL)
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
+    else if (err & POLLHUP)
+        PR_SetError(PR_CONNECT_RESET_ERROR, EPIPE);
+    else if (err & POLLERR)
+        PR_SetError(PR_IO_ERROR, EIO);
+    else
+        PR_SetError(PR_UNKNOWN_ERROR, err);
+}
+#endif /* _PR_POLL_AVAILABLE || _PR_NEED_FAKE_POLL */
+
+
+void _MD_unix_map_flock_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EINVAL:
+            prError = PR_BAD_DESCRIPTOR_ERROR;
+            break;
+        case EWOULDBLOCK:
+            prError = PR_FILE_IS_LOCKED_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_unix_map_lockf_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EACCES:
+            prError = PR_FILE_IS_LOCKED_ERROR;
+            break;
+        case EDEADLK:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        default:
+            _MD_unix_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+#ifdef AIX
+void _MD_aix_map_sendfile_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+#endif /* AIX */
+
+#ifdef HPUX11
+void _MD_hpux_map_sendfile_error(int err)
+{
+    _MD_unix_map_default_error(err);
+}
+#endif /* HPUX11 */
+
+#ifdef SOLARIS
+void _MD_solaris_map_sendfile_error(int err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        /*
+         * Solaris defines a 0 return value for sendfile to mean end-of-file.
+         */
+        case 0:
+            prError = PR_END_OF_FILE_ERROR;
+            break;
+
+        default:
+            _MD_unix_map_default_error(err) ;
+            return;
+    }
+    PR_SetError(prError, err);
+}
+#endif /* SOLARIS */
+
+#ifdef LINUX
+void _MD_linux_map_sendfile_error(int err)
+{
+    _MD_unix_map_default_error(err) ;
+}
+#endif /* LINUX */
diff --git a/mozilla/nsprpub/pr/src/md/unix/uxpoll.c b/mozilla/nsprpub/pr/src/md/unix/uxpoll.c
new file mode 100644
index 0000000..aa02656
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/uxpoll.c
@@ -0,0 +1,708 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#if defined(_PR_PTHREADS)
+
+#error "This file should not be compiled"
+
+#else  /* defined(_PR_PTHREADS) */
+
+#include "primpl.h"
+
+#include <sys/time.h>
+
+#include <fcntl.h>
+#ifdef _PR_USE_POLL
+#include <poll.h>
+#endif
+
+#if defined(_PR_USE_POLL)
+static PRInt32 NativeThreadPoll(
+    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+    /*
+     * This function is mostly duplicated from ptio.s's PR_Poll().
+     */
+    PRInt32 ready = 0;
+    /*
+     * For restarting poll() if it is interrupted by a signal.
+     * We use these variables to figure out how much time has
+     * elapsed and how much of the timeout still remains.
+     */
+    PRIntn index, msecs;
+    struct pollfd *syspoll = NULL;
+    PRIntervalTime start, elapsed, remaining;
+
+    syspoll = (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
+    if (NULL == syspoll)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return -1;
+    }
+    for (index = 0; index < npds; ++index)
+    {
+        PRFileDesc *bottom;
+        PRInt16 in_flags_read = 0, in_flags_write = 0;
+        PRInt16 out_flags_read = 0, out_flags_write = 0;
+
+        if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
+        {
+            if (pds[index].in_flags & PR_POLL_READ)
+            {
+                in_flags_read = (pds[index].fd->methods->poll)(
+                    pds[index].fd,
+                    pds[index].in_flags & ~PR_POLL_WRITE,
+                    &out_flags_read);
+            }
+            if (pds[index].in_flags & PR_POLL_WRITE)
+            {
+                in_flags_write = (pds[index].fd->methods->poll)(
+                    pds[index].fd,
+                    pds[index].in_flags & ~PR_POLL_READ,
+                    &out_flags_write);
+            }
+            if ((0 != (in_flags_read & out_flags_read))
+            || (0 != (in_flags_write & out_flags_write)))
+            {
+                /* this one is ready right now */
+                if (0 == ready)
+                {
+                    /*
+                     * We will return without calling the system
+                     * poll function.  So zero the out_flags
+                     * fields of all the poll descriptors before
+                     * this one.
+                     */
+                    int i;
+                    for (i = 0; i < index; i++)
+                    {
+                        pds[i].out_flags = 0;
+                    }
+                }
+                ready += 1;
+                pds[index].out_flags = out_flags_read | out_flags_write;
+            }
+            else
+            {
+                pds[index].out_flags = 0;  /* pre-condition */
+                /* now locate the NSPR layer at the bottom of the stack */
+                bottom = PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottom);  /* what to do about that? */
+                if ((NULL != bottom)
+                && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                {
+                    if (0 == ready)
+                    {
+                        syspoll[index].fd = bottom->secret->md.osfd;
+                        syspoll[index].events = 0;  /* pre-condition */
+                        if (in_flags_read & PR_POLL_READ)
+                        {
+                            pds[index].out_flags |=
+                                _PR_POLL_READ_SYS_READ;
+                            syspoll[index].events |= POLLIN;
+                        }
+                        if (in_flags_read & PR_POLL_WRITE)
+                        {
+                            pds[index].out_flags |=
+                                _PR_POLL_READ_SYS_WRITE;
+                            syspoll[index].events |= POLLOUT;
+                        }
+                        if (in_flags_write & PR_POLL_READ)
+                        {
+                            pds[index].out_flags |=
+                                _PR_POLL_WRITE_SYS_READ;
+                            syspoll[index].events |= POLLIN;
+                        }
+                        if (in_flags_write & PR_POLL_WRITE)
+                        {
+                            pds[index].out_flags |=
+                                _PR_POLL_WRITE_SYS_WRITE;
+                            syspoll[index].events |= POLLOUT;
+                        }
+                        if (pds[index].in_flags & PR_POLL_EXCEPT)
+                            syspoll[index].events |= POLLPRI;
+                    }
+                }
+                else
+                {
+                    if (0 == ready)
+                    {
+                        int i;
+                        for (i = 0; i < index; i++)
+                        {
+                            pds[i].out_flags = 0;
+                        }
+                    }
+                    ready += 1;  /* this will cause an abrupt return */
+                    pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
+                }
+            }
+        }
+        else
+        {
+            /* make poll() ignore this entry */
+            syspoll[index].fd = -1;
+            syspoll[index].events = 0;
+            pds[index].out_flags = 0;
+        }
+    }
+
+    if (0 == ready)
+    {
+        switch (timeout)
+        {
+            case PR_INTERVAL_NO_WAIT: msecs = 0; break;
+            case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
+            default:
+                msecs = PR_IntervalToMilliseconds(timeout);
+                start = PR_IntervalNow();
+        }
+
+retry:
+        ready = _MD_POLL(syspoll, npds, msecs);
+        if (-1 == ready)
+        {
+            PRIntn oserror = errno;
+
+            if (EINTR == oserror)
+            {
+                if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry;
+                else if (timeout == PR_INTERVAL_NO_WAIT) ready = 0;
+                else
+                {
+                    elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
+                    if (elapsed > timeout) ready = 0;  /* timed out */
+                    else
+                    {
+                        remaining = timeout - elapsed;
+                        msecs = PR_IntervalToMilliseconds(remaining);
+                        goto retry;
+                    }
+                }
+            }
+            else _PR_MD_MAP_POLL_ERROR(oserror);
+        }
+        else if (ready > 0)
+        {
+            for (index = 0; index < npds; ++index)
+            {
+                PRInt16 out_flags = 0;
+                if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
+                {
+                    if (0 != syspoll[index].revents)
+                    {
+                        /*
+                        ** Set up the out_flags so that it contains the
+                        ** bits that the highest layer thinks are nice
+                        ** to have. Then the client of that layer will
+                        ** call the appropriate I/O function and maybe
+                        ** the protocol will make progress.
+                        */
+                        if (syspoll[index].revents & POLLIN)
+                        {
+                            if (pds[index].out_flags
+                            & _PR_POLL_READ_SYS_READ)
+                            {
+                                out_flags |= PR_POLL_READ;
+                            }
+                            if (pds[index].out_flags
+                            & _PR_POLL_WRITE_SYS_READ)
+                            {
+                                out_flags |= PR_POLL_WRITE;
+                            }
+                        }
+                        if (syspoll[index].revents & POLLOUT)
+                        {
+                            if (pds[index].out_flags
+                            & _PR_POLL_READ_SYS_WRITE)
+                            {
+                                out_flags |= PR_POLL_READ;
+                            }
+                            if (pds[index].out_flags
+                            & _PR_POLL_WRITE_SYS_WRITE)
+                            {
+                                out_flags |= PR_POLL_WRITE;
+                            }
+                        }
+                        if (syspoll[index].revents & POLLPRI)
+                            out_flags |= PR_POLL_EXCEPT;
+                        if (syspoll[index].revents & POLLERR)
+                            out_flags |= PR_POLL_ERR;
+                        if (syspoll[index].revents & POLLNVAL)
+                            out_flags |= PR_POLL_NVAL;
+                        if (syspoll[index].revents & POLLHUP)
+                            out_flags |= PR_POLL_HUP;
+                    }
+                }
+                pds[index].out_flags = out_flags;
+            }
+        }
+    }
+
+    PR_DELETE(syspoll);
+    return ready;
+
+}  /* NativeThreadPoll */
+#endif  /* defined(_PR_USE_POLL) */
+
+#if !defined(_PR_USE_POLL)
+static PRInt32 NativeThreadSelect(
+    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+    /*
+     * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL().
+     */
+    fd_set rd, wt, ex;
+    PRFileDesc *bottom;
+    PRPollDesc *pd, *epd;
+    PRInt32 maxfd = -1, ready, err;
+    PRIntervalTime remaining, elapsed, start;
+
+    struct timeval tv, *tvp = NULL;
+
+    FD_ZERO(&rd);
+    FD_ZERO(&wt);
+    FD_ZERO(&ex);
+
+    ready = 0;
+    for (pd = pds, epd = pd + npds; pd < epd; pd++)
+    {
+        PRInt16 in_flags_read = 0, in_flags_write = 0;
+        PRInt16 out_flags_read = 0, out_flags_write = 0;
+
+        if ((NULL != pd->fd) && (0 != pd->in_flags))
+        {
+            if (pd->in_flags & PR_POLL_READ)
+            {
+                in_flags_read = (pd->fd->methods->poll)(
+                    pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
+            }
+            if (pd->in_flags & PR_POLL_WRITE)
+            {
+                in_flags_write = (pd->fd->methods->poll)(
+                    pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
+            }
+            if ((0 != (in_flags_read & out_flags_read))
+            || (0 != (in_flags_write & out_flags_write)))
+            {
+                /* this one's ready right now */
+                if (0 == ready)
+                {
+                    /*
+                     * We will have to return without calling the
+                     * system poll/select function.  So zero the
+                     * out_flags fields of all the poll descriptors
+                     * before this one.
+                     */
+                    PRPollDesc *prev;
+                    for (prev = pds; prev < pd; prev++)
+                    {
+                        prev->out_flags = 0;
+                    }
+                }
+                ready += 1;
+                pd->out_flags = out_flags_read | out_flags_write;
+            }
+            else
+            {
+                pd->out_flags = 0;  /* pre-condition */
+
+                /* make sure this is an NSPR supported stack */
+                bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottom);  /* what to do about that? */
+                if ((NULL != bottom)
+                && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                {
+                    if (0 == ready)
+                    {
+                        PRInt32 osfd = bottom->secret->md.osfd;
+                        if (osfd > maxfd) maxfd = osfd;
+                        if (in_flags_read & PR_POLL_READ)
+                        {
+                            pd->out_flags |= _PR_POLL_READ_SYS_READ;
+                            FD_SET(osfd, &rd);
+                        }
+                        if (in_flags_read & PR_POLL_WRITE)
+                        {
+                            pd->out_flags |= _PR_POLL_READ_SYS_WRITE;
+                            FD_SET(osfd, &wt);
+                        }
+                        if (in_flags_write & PR_POLL_READ)
+                        {
+                            pd->out_flags |= _PR_POLL_WRITE_SYS_READ;
+                            FD_SET(osfd, &rd);
+                        }
+                        if (in_flags_write & PR_POLL_WRITE)
+                        {
+                            pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE;
+                            FD_SET(osfd, &wt);
+                        }
+                        if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex);
+                    }
+                }
+                else
+                {
+                    if (0 == ready)
+                    {
+                        PRPollDesc *prev;
+                        for (prev = pds; prev < pd; prev++)
+                        {
+                            prev->out_flags = 0;
+                        }
+                    }
+                    ready += 1;  /* this will cause an abrupt return */
+                    pd->out_flags = PR_POLL_NVAL;  /* bogii */
+                }
+            }
+        }
+        else
+        {
+            pd->out_flags = 0;
+        }
+    }
+
+    if (0 != ready) return ready;  /* no need to block */
+
+    remaining = timeout;
+    start = PR_IntervalNow();
+
+retry:
+    if (timeout != PR_INTERVAL_NO_TIMEOUT)
+    {
+        PRInt32 ticksPerSecond = PR_TicksPerSecond();
+        tv.tv_sec = remaining / ticksPerSecond;
+        tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond );
+        tvp = &tv;
+    }
+
+    ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp);
+
+    if (ready == -1 && errno == EINTR)
+    {
+        if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry;
+        else
+        {
+            elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
+            if (elapsed > timeout) ready = 0;  /* timed out */
+            else
+            {
+                remaining = timeout - elapsed;
+                goto retry;
+            }
+        }
+    }
+
+    /*
+    ** Now to unravel the select sets back into the client's poll
+    ** descriptor list. Is this possibly an area for pissing away
+    ** a few cycles or what?
+    */
+    if (ready > 0)
+    {
+        ready = 0;
+        for (pd = pds, epd = pd + npds; pd < epd; pd++)
+        {
+            PRInt16 out_flags = 0;
+            if ((NULL != pd->fd) && (0 != pd->in_flags))
+            {
+                PRInt32 osfd;
+                bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottom);
+
+                osfd = bottom->secret->md.osfd;
+
+                if (FD_ISSET(osfd, &rd))
+                {
+                    if (pd->out_flags & _PR_POLL_READ_SYS_READ)
+                        out_flags |= PR_POLL_READ;
+                    if (pd->out_flags & _PR_POLL_WRITE_SYS_READ)
+                        out_flags |= PR_POLL_WRITE;
+                } 
+                if (FD_ISSET(osfd, &wt))
+                {
+                    if (pd->out_flags & _PR_POLL_READ_SYS_WRITE)
+                        out_flags |= PR_POLL_READ;
+                    if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE)
+                        out_flags |= PR_POLL_WRITE;
+                } 
+                if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT;
+            }
+            pd->out_flags = out_flags;
+            if (out_flags) ready++;
+        }
+        PR_ASSERT(ready > 0);
+    }
+    else if (ready < 0)
+    {
+        err = _MD_ERRNO();
+        if (err == EBADF)
+        {
+            /* Find the bad fds */
+            ready = 0;
+            for (pd = pds, epd = pd + npds; pd < epd; pd++)
+            {
+                pd->out_flags = 0;
+                if ((NULL != pd->fd) && (0 != pd->in_flags))
+                {
+                    bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                    if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1)
+                    {
+                        pd->out_flags = PR_POLL_NVAL;
+                        ready++;
+                    }
+                }
+            }
+            PR_ASSERT(ready > 0);
+        }
+        else _PR_MD_MAP_SELECT_ERROR(err);
+    }
+
+    return ready;
+}  /* NativeThreadSelect */
+#endif  /* !defined(_PR_USE_POLL) */
+
+static PRInt32 LocalThreads(
+    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+    PRPollDesc *pd, *epd;
+    PRInt32 ready, pdcnt;
+    _PRUnixPollDesc *unixpds, *unixpd;
+
+    /*
+     * XXX
+     *        PRPollDesc has a PRFileDesc field, fd, while the IOQ
+     *        is a list of PRPollQueue structures, each of which contains
+     *        a _PRUnixPollDesc. A _PRUnixPollDesc struct contains
+     *        the OS file descriptor, osfd, and not a PRFileDesc.
+     *        So, we have allocate memory for _PRUnixPollDesc structures,
+     *        copy the flags information from the pds list and have pq
+     *        point to this list of _PRUnixPollDesc structures.
+     *
+     *        It would be better if the memory allocation can be avoided.
+     */
+
+    unixpd = unixpds = (_PRUnixPollDesc*)
+        PR_MALLOC(npds * sizeof(_PRUnixPollDesc));
+    if (NULL == unixpds)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return -1;
+    }
+
+    ready = 0;
+    for (pdcnt = 0, pd = pds, epd = pd + npds; pd < epd; pd++)
+    {
+        PRFileDesc *bottom;
+        PRInt16 in_flags_read = 0, in_flags_write = 0;
+        PRInt16 out_flags_read = 0, out_flags_write = 0;
+
+        if ((NULL != pd->fd) && (0 != pd->in_flags))
+        {
+            if (pd->in_flags & PR_POLL_READ)
+            {
+                in_flags_read = (pd->fd->methods->poll)(
+                    pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
+            }
+            if (pd->in_flags & PR_POLL_WRITE)
+            {
+                in_flags_write = (pd->fd->methods->poll)(
+                    pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
+            }
+            if ((0 != (in_flags_read & out_flags_read))
+            || (0 != (in_flags_write & out_flags_write)))
+            {
+                /* this one's ready right now */
+                if (0 == ready)
+                {
+                    /*
+                     * We will have to return without calling the
+                     * system poll/select function.  So zero the
+                     * out_flags fields of all the poll descriptors
+                     * before this one.
+                     */
+                    PRPollDesc *prev;
+                    for (prev = pds; prev < pd; prev++)
+                    {
+                        prev->out_flags = 0;
+                    }
+                }
+                ready += 1;
+                pd->out_flags = out_flags_read | out_flags_write;
+            }
+            else
+            {
+                pd->out_flags = 0;  /* pre-condition */
+                bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottom);  /* what to do about that? */
+                if ((NULL != bottom)
+                && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                {
+                    if (0 == ready)
+                    {
+                        unixpd->osfd = bottom->secret->md.osfd;
+                        unixpd->in_flags = 0;
+                        if (in_flags_read & PR_POLL_READ)
+                        {
+                            unixpd->in_flags |= _PR_UNIX_POLL_READ;
+                            pd->out_flags |= _PR_POLL_READ_SYS_READ;
+                        }
+                        if (in_flags_read & PR_POLL_WRITE)
+                        {
+                            unixpd->in_flags |= _PR_UNIX_POLL_WRITE;
+                            pd->out_flags |= _PR_POLL_READ_SYS_WRITE;
+                        }
+                        if (in_flags_write & PR_POLL_READ)
+                        {
+                            unixpd->in_flags |= _PR_UNIX_POLL_READ;
+                            pd->out_flags |= _PR_POLL_WRITE_SYS_READ;
+                        }
+                        if (in_flags_write & PR_POLL_WRITE)
+                        {
+                            unixpd->in_flags |= _PR_UNIX_POLL_WRITE;
+                            pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE;
+                        }
+                        if ((in_flags_read | in_flags_write) & PR_POLL_EXCEPT)
+                        {
+                            unixpd->in_flags |= _PR_UNIX_POLL_EXCEPT;
+                        }
+                        unixpd++; pdcnt++;
+                    }
+                }
+                else
+                {
+                    if (0 == ready)
+                    {
+                        PRPollDesc *prev;
+                        for (prev = pds; prev < pd; prev++)
+                        {
+                            prev->out_flags = 0;
+                        }
+                    }
+                    ready += 1;  /* this will cause an abrupt return */
+                    pd->out_flags = PR_POLL_NVAL;  /* bogii */
+                }
+            }
+        }
+    }
+
+    if (0 != ready)
+    {
+        /* no need to block */
+        PR_DELETE(unixpds);
+        return ready;
+    }
+
+    ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout);
+
+    /*
+     * Copy the out_flags from the _PRUnixPollDesc structures to the
+     * user's PRPollDesc structures and free the allocated memory
+     */
+    unixpd = unixpds;
+    for (pd = pds, epd = pd + npds; pd < epd; pd++)
+    {
+        PRInt16 out_flags = 0;
+        if ((NULL != pd->fd) && (0 != pd->in_flags))
+        {
+            /*
+             * take errors from the poll operation,
+             * the R/W bits from the request
+             */
+            if (0 != unixpd->out_flags)
+            {
+                if (unixpd->out_flags & _PR_UNIX_POLL_READ)
+                {
+                    if (pd->out_flags & _PR_POLL_READ_SYS_READ)
+                        out_flags |= PR_POLL_READ;
+                    if (pd->out_flags & _PR_POLL_WRITE_SYS_READ)
+                        out_flags |= PR_POLL_WRITE;
+                }
+                if (unixpd->out_flags & _PR_UNIX_POLL_WRITE)
+                {
+                    if (pd->out_flags & _PR_POLL_READ_SYS_WRITE)
+                        out_flags |= PR_POLL_READ;
+                    if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE)
+                        out_flags |= PR_POLL_WRITE;
+                }
+                if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT)
+                    out_flags |= PR_POLL_EXCEPT;
+                if (unixpd->out_flags & _PR_UNIX_POLL_ERR)
+                    out_flags |= PR_POLL_ERR;
+                if (unixpd->out_flags & _PR_UNIX_POLL_NVAL)
+                    out_flags |= PR_POLL_NVAL;
+                if (unixpd->out_flags & _PR_UNIX_POLL_HUP)
+                    out_flags |= PR_POLL_HUP;
+            }
+            unixpd++;
+        }
+        pd->out_flags = out_flags;
+    }
+
+    PR_DELETE(unixpds);
+
+    return ready;
+}  /* LocalThreads */
+
+#if defined(_PR_USE_POLL)
+#define NativeThreads NativeThreadPoll
+#else
+#define NativeThreads NativeThreadSelect
+#endif
+
+PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+    PRInt32 rv = 0;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (_PR_PENDING_INTERRUPT(me))
+    {
+        me->flags &= ~_PR_INTERRUPT;
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        return -1;
+    }
+    if (0 == npds) PR_Sleep(timeout);
+    else if (_PR_IS_NATIVE_THREAD(me))
+        rv = NativeThreads(pds, npds, timeout);
+    else rv = LocalThreads(pds, npds, timeout);
+
+    return rv;
+}  /* _MD_pr_poll */
+
+#endif  /* defined(_PR_PTHREADS) */               
+
+/* uxpoll.c */
+
diff --git a/mozilla/nsprpub/pr/src/md/unix/uxproces.c b/mozilla/nsprpub/pr/src/md/unix/uxproces.c
new file mode 100644
index 0000000..364301c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/uxproces.c
@@ -0,0 +1,912 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <string.h>
+#if defined(AIX)
+#include <dlfcn.h>  /* For dlopen, dlsym, dlclose */
+#endif
+
+#if defined(DARWIN)
+#include <crt_externs.h>
+#else
+PR_IMPORT_DATA(char **) environ;
+#endif
+
+/*
+ * HP-UX 9 doesn't have the SA_RESTART flag.
+ */
+#ifndef SA_RESTART
+#define SA_RESTART 0
+#endif
+
+/*
+ **********************************************************************
+ *
+ * The Unix process routines
+ *
+ **********************************************************************
+ */
+
+#define _PR_SIGNALED_EXITSTATUS 256
+
+typedef enum pr_PidState {
+    _PR_PID_DETACHED,
+    _PR_PID_REAPED,
+    _PR_PID_WAITING
+} pr_PidState;
+
+typedef struct pr_PidRecord {
+    pid_t pid;
+    int exitStatus;
+    pr_PidState state;
+    PRCondVar *reapedCV;
+    struct pr_PidRecord *next;
+} pr_PidRecord;
+
+/*
+ * Irix sprocs and LinuxThreads are actually a kind of processes
+ * that can share the virtual address space and file descriptors.
+ */
+#if (defined(IRIX) && !defined(_PR_PTHREADS)) \
+        || ((defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)) \
+        && defined(_PR_PTHREADS))
+#define _PR_SHARE_CLONES
+#endif
+
+/*
+ * The macro _PR_NATIVE_THREADS indicates that we are
+ * using native threads only, so waitpid() blocks just the
+ * calling thread, not the process.  In this case, the waitpid
+ * daemon thread can safely block in waitpid().  So we don't
+ * need to catch SIGCHLD, and the pipe to unblock PR_Poll() is
+ * also not necessary.
+ */
+
+#if defined(_PR_GLOBAL_THREADS_ONLY) \
+	|| (defined(_PR_PTHREADS) \
+	&& !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__))
+#define _PR_NATIVE_THREADS
+#endif
+
+/*
+ * All the static variables used by the Unix process routines are
+ * collected in this structure.
+ */
+
+static struct {
+    PRCallOnceType once;
+    PRThread *thread;
+    PRLock *ml;
+#if defined(_PR_NATIVE_THREADS)
+    PRInt32 numProcs;
+    PRCondVar *cv;
+#else
+    int pipefd[2];
+#endif
+    pr_PidRecord **pidTable;
+
+#ifdef _PR_SHARE_CLONES
+    struct pr_CreateProcOp *opHead, *opTail;
+#endif
+
+#ifdef AIX
+    pid_t (*forkptr)(void);  /* Newer versions of AIX (starting in 4.3.2)
+                              * have f_fork, which is faster than the
+                              * regular fork in a multithreaded process
+                              * because it skips calling the fork handlers.
+                              * So we look up the f_fork symbol to see if
+                              * it's available and fall back on fork.
+                              */
+#endif /* AIX */
+} pr_wp;
+
+#ifdef _PR_SHARE_CLONES
+static int pr_waitpid_daemon_exit;
+
+void
+_MD_unix_terminate_waitpid_daemon(void)
+{
+    if (pr_wp.thread) {
+        pr_waitpid_daemon_exit = 1;
+        write(pr_wp.pipefd[1], "", 1);
+        PR_JoinThread(pr_wp.thread);
+    }
+}
+#endif
+
+static PRStatus _MD_InitProcesses(void);
+#if !defined(_PR_NATIVE_THREADS)
+static void pr_InstallSigchldHandler(void);
+#endif
+
+static PRProcess *
+ForkAndExec(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    PRProcess *process;
+    int nEnv, idx;
+    char *const *childEnvp;
+    char **newEnvp = NULL;
+    int flags;
+
+    process = PR_NEW(PRProcess);
+    if (!process) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+
+    childEnvp = envp;
+    if (attr && attr->fdInheritBuffer) {
+        PRBool found = PR_FALSE;
+
+        if (NULL == childEnvp) {
+#ifdef DARWIN
+            childEnvp = *(_NSGetEnviron());
+#else
+            childEnvp = environ;
+#endif
+        }
+        for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
+        }
+        newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *));
+        if (NULL == newEnvp) {
+            PR_DELETE(process);
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return NULL;
+        }
+        for (idx = 0; idx < nEnv; idx++) {
+            newEnvp[idx] = childEnvp[idx];
+            if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
+                newEnvp[idx] = attr->fdInheritBuffer;
+                found = PR_TRUE;
+            }
+        }
+        if (!found) {
+            newEnvp[idx++] = attr->fdInheritBuffer;
+        }
+        newEnvp[idx] = NULL;
+        childEnvp = newEnvp;
+    }
+
+#ifdef AIX
+    process->md.pid = (*pr_wp.forkptr)();
+#elif defined(NTO) || defined(SYMBIAN)
+    /*
+     * fork() & exec() does not work in a multithreaded process.
+     * Use spawn() instead.
+     */
+    {
+        int fd_map[3] = { 0, 1, 2 };
+
+        if (attr) {
+            if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) {
+                fd_map[0] = dup(attr->stdinFd->secret->md.osfd);
+                flags = fcntl(fd_map[0], F_GETFL, 0);
+                if (flags & O_NONBLOCK)
+                    fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK);
+            }
+            if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) {
+                fd_map[1] = dup(attr->stdoutFd->secret->md.osfd);
+                flags = fcntl(fd_map[1], F_GETFL, 0);
+                if (flags & O_NONBLOCK)
+                    fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK);
+            }
+            if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) {
+                fd_map[2] = dup(attr->stderrFd->secret->md.osfd);
+                flags = fcntl(fd_map[2], F_GETFL, 0);
+                if (flags & O_NONBLOCK)
+                    fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK);
+            }
+
+            PR_ASSERT(attr->currentDirectory == NULL);  /* not implemented */
+        }
+
+#ifdef SYMBIAN
+        /* In Symbian OS, we use posix_spawn instead of fork() and exec() */
+        posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp);
+#else
+        process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp);
+#endif
+
+        if (fd_map[0] != 0)
+            close(fd_map[0]);
+        if (fd_map[1] != 1)
+            close(fd_map[1]);
+        if (fd_map[2] != 2)
+            close(fd_map[2]);
+    }
+#else
+    process->md.pid = fork();
+#endif
+    if ((pid_t) -1 == process->md.pid) {
+        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
+        PR_DELETE(process);
+        if (newEnvp) {
+            PR_DELETE(newEnvp);
+        }
+        return NULL;
+    } else if (0 == process->md.pid) {  /* the child process */
+        /*
+         * If the child process needs to exit, it must call _exit().
+         * Do not call exit(), because exit() will flush and close
+         * the standard I/O file descriptors, and hence corrupt
+         * the parent process's standard I/O data structures.
+         */
+
+#if !defined(NTO) && !defined(SYMBIAN)
+        if (attr) {
+            /* the osfd's to redirect stdin, stdout, and stderr to */
+            int in_osfd = -1, out_osfd = -1, err_osfd = -1;
+
+            if (attr->stdinFd
+                    && attr->stdinFd->secret->md.osfd != 0) {
+                in_osfd = attr->stdinFd->secret->md.osfd;
+                if (dup2(in_osfd, 0) != 0) {
+                    _exit(1);  /* failed */
+                }
+                flags = fcntl(0, F_GETFL, 0);
+                if (flags & O_NONBLOCK) {
+                    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
+                }
+            }
+            if (attr->stdoutFd
+                    && attr->stdoutFd->secret->md.osfd != 1) {
+                out_osfd = attr->stdoutFd->secret->md.osfd;
+                if (dup2(out_osfd, 1) != 1) {
+                    _exit(1);  /* failed */
+                }
+                flags = fcntl(1, F_GETFL, 0);
+                if (flags & O_NONBLOCK) {
+                    fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
+                }
+            }
+            if (attr->stderrFd
+                    && attr->stderrFd->secret->md.osfd != 2) {
+                err_osfd = attr->stderrFd->secret->md.osfd;
+                if (dup2(err_osfd, 2) != 2) {
+                    _exit(1);  /* failed */
+                }
+                flags = fcntl(2, F_GETFL, 0);
+                if (flags & O_NONBLOCK) {
+                    fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
+                }
+            }
+            if (in_osfd != -1) {
+                close(in_osfd);
+            }
+            if (out_osfd != -1 && out_osfd != in_osfd) {
+                close(out_osfd);
+            }
+            if (err_osfd != -1 && err_osfd != in_osfd
+                    && err_osfd != out_osfd) {
+                close(err_osfd);
+            }
+            if (attr->currentDirectory) {
+                if (chdir(attr->currentDirectory) < 0) {
+                    _exit(1);  /* failed */
+                }
+            }
+        }
+
+        if (childEnvp) {
+            (void)execve(path, argv, childEnvp);
+        } else {
+            /* Inherit the environment of the parent. */
+            (void)execv(path, argv);
+        }
+        /* Whoops! It returned. That's a bad sign. */
+        _exit(1);
+#endif /* !NTO */
+    }
+
+    if (newEnvp) {
+        PR_DELETE(newEnvp);
+    }
+
+#if defined(_PR_NATIVE_THREADS)
+    PR_Lock(pr_wp.ml);
+    if (0 == pr_wp.numProcs++) {
+        PR_NotifyCondVar(pr_wp.cv);
+    }
+    PR_Unlock(pr_wp.ml);
+#endif
+    return process;
+}
+
+#ifdef _PR_SHARE_CLONES
+
+struct pr_CreateProcOp {
+    const char *path;
+    char *const *argv;
+    char *const *envp;
+    const PRProcessAttr *attr;
+    PRProcess *process;
+    PRErrorCode prerror;
+    PRInt32 oserror;
+    PRBool done;
+    PRCondVar *doneCV;
+    struct pr_CreateProcOp *next;
+};
+
+PRProcess *
+_MD_CreateUnixProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    struct pr_CreateProcOp *op;
+    PRProcess *proc;
+    int rv;
+
+    if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
+	return NULL;
+    }
+
+    op = PR_NEW(struct pr_CreateProcOp);
+    if (NULL == op) {
+	PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	return NULL;
+    }
+    op->path = path;
+    op->argv = argv;
+    op->envp = envp;
+    op->attr = attr;
+    op->done = PR_FALSE;
+    op->doneCV = PR_NewCondVar(pr_wp.ml);
+    if (NULL == op->doneCV) {
+	PR_DELETE(op);
+	return NULL;
+    }
+    PR_Lock(pr_wp.ml);
+
+    /* add to the tail of op queue */
+    op->next = NULL;
+    if (pr_wp.opTail) {
+	pr_wp.opTail->next = op;
+	pr_wp.opTail = op;
+    } else {
+	PR_ASSERT(NULL == pr_wp.opHead);
+	pr_wp.opHead = pr_wp.opTail = op;
+    }
+
+    /* wake up the daemon thread */
+    do {
+        rv = write(pr_wp.pipefd[1], "", 1);
+    } while (-1 == rv && EINTR == errno);
+
+    while (op->done == PR_FALSE) {
+	PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT);
+    }
+    PR_Unlock(pr_wp.ml);
+    PR_DestroyCondVar(op->doneCV);
+    proc = op->process;
+    if (!proc) {
+	PR_SetError(op->prerror, op->oserror);
+    }
+    PR_DELETE(op);
+    return proc;
+}
+
+#else  /* ! _PR_SHARE_CLONES */
+
+PRProcess *
+_MD_CreateUnixProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
+	return NULL;
+    }
+    return ForkAndExec(path, argv, envp, attr);
+}  /* _MD_CreateUnixProcess */
+
+#endif  /* _PR_SHARE_CLONES */
+
+/*
+ * The pid table is a hashtable.
+ *
+ * The number of buckets in the hashtable (NBUCKETS) must be a power of 2.
+ */
+#define NBUCKETS_LOG2 6
+#define NBUCKETS (1 << NBUCKETS_LOG2)
+#define PID_HASH_MASK ((pid_t) (NBUCKETS - 1))
+
+static pr_PidRecord *
+FindPidTable(pid_t pid)
+{
+    pr_PidRecord *pRec;
+    int keyHash = (int) (pid & PID_HASH_MASK);
+
+    pRec =  pr_wp.pidTable[keyHash];
+    while (pRec) {
+	if (pRec->pid == pid) {
+	    break;
+	}
+	pRec = pRec->next;
+    }
+    return pRec;
+}
+
+static void
+InsertPidTable(pr_PidRecord *pRec)
+{
+    int keyHash = (int) (pRec->pid & PID_HASH_MASK);
+
+    pRec->next = pr_wp.pidTable[keyHash];
+    pr_wp.pidTable[keyHash] = pRec;
+}
+
+static void
+DeletePidTable(pr_PidRecord *pRec)
+{
+    int keyHash = (int) (pRec->pid & PID_HASH_MASK);
+
+    if (pr_wp.pidTable[keyHash] == pRec) {
+	pr_wp.pidTable[keyHash] = pRec->next;
+    } else {
+	pr_PidRecord *pred, *cur;  /* predecessor and current */
+
+	pred = pr_wp.pidTable[keyHash];
+	cur = pred->next;
+	while (cur) {
+	    if (cur == pRec) {
+		pred->next = cur->next;
+		break;
+            }
+	    pred = cur;
+	    cur = cur->next;
+        }
+	PR_ASSERT(cur != NULL);
+    }
+}
+
+static int
+ExtractExitStatus(int rawExitStatus)
+{
+    /*
+     * We did not specify the WCONTINUED and WUNTRACED options
+     * for waitpid, so these two events should not be reported.
+     */
+    PR_ASSERT(!WIFSTOPPED(rawExitStatus));
+#ifdef WIFCONTINUED
+    PR_ASSERT(!WIFCONTINUED(rawExitStatus));
+#endif
+    if (WIFEXITED(rawExitStatus)) {
+	return WEXITSTATUS(rawExitStatus);
+    } else {
+	PR_ASSERT(WIFSIGNALED(rawExitStatus));
+	return _PR_SIGNALED_EXITSTATUS;
+    }
+}
+
+static void
+ProcessReapedChildInternal(pid_t pid, int status)
+{
+    pr_PidRecord *pRec;
+
+    pRec = FindPidTable(pid);
+    if (NULL == pRec) {
+        pRec = PR_NEW(pr_PidRecord);
+        pRec->pid = pid;
+        pRec->state = _PR_PID_REAPED;
+        pRec->exitStatus = ExtractExitStatus(status);
+        pRec->reapedCV = NULL;
+        InsertPidTable(pRec);
+    } else {
+        PR_ASSERT(pRec->state != _PR_PID_REAPED);
+        if (_PR_PID_DETACHED == pRec->state) {
+            PR_ASSERT(NULL == pRec->reapedCV);
+            DeletePidTable(pRec);
+            PR_DELETE(pRec);
+        } else {
+            PR_ASSERT(_PR_PID_WAITING == pRec->state);
+            PR_ASSERT(NULL != pRec->reapedCV);
+            pRec->exitStatus = ExtractExitStatus(status);
+            pRec->state = _PR_PID_REAPED;
+            PR_NotifyCondVar(pRec->reapedCV);
+        }
+    }
+}
+
+#if defined(_PR_NATIVE_THREADS)
+
+/*
+ * If all the threads are native threads, the daemon thread is
+ * simpler.  We don't need to catch the SIGCHLD signal.  We can
+ * just have the daemon thread block in waitpid().
+ */
+
+static void WaitPidDaemonThread(void *unused)
+{
+    pid_t pid;
+    int status;
+
+    while (1) {
+        PR_Lock(pr_wp.ml);
+        while (0 == pr_wp.numProcs) {
+            PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
+        }
+        PR_Unlock(pr_wp.ml);
+
+	while (1) {
+	    do {
+	        pid = waitpid((pid_t) -1, &status, 0);
+	    } while ((pid_t) -1 == pid && EINTR == errno);
+
+            /*
+             * waitpid() cannot return 0 because we did not invoke it
+             * with the WNOHANG option.
+             */ 
+	    PR_ASSERT(0 != pid);
+
+            /*
+             * The only possible error code is ECHILD.  But if we do
+             * our accounting correctly, we should only call waitpid()
+             * when there is a child process to wait for.
+             */
+            PR_ASSERT((pid_t) -1 != pid);
+	    if ((pid_t) -1 == pid) {
+                break;
+            }
+
+	    PR_Lock(pr_wp.ml);
+            ProcessReapedChildInternal(pid, status);
+            pr_wp.numProcs--;
+            while (0 == pr_wp.numProcs) {
+                PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
+            }
+	    PR_Unlock(pr_wp.ml);
+	}
+    }
+}
+
+#else /* _PR_NATIVE_THREADS */
+
+static void WaitPidDaemonThread(void *unused)
+{
+    PRPollDesc pd;
+    PRFileDesc *fd;
+    int rv;
+    char buf[128];
+    pid_t pid;
+    int status;
+#ifdef _PR_SHARE_CLONES
+    struct pr_CreateProcOp *op;
+#endif
+
+#ifdef _PR_SHARE_CLONES
+    pr_InstallSigchldHandler();
+#endif
+
+    fd = PR_ImportFile(pr_wp.pipefd[0]);
+    PR_ASSERT(NULL != fd);
+    pd.fd = fd;
+    pd.in_flags = PR_POLL_READ;
+
+    while (1) {
+        rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+        PR_ASSERT(1 == rv);
+
+#ifdef _PR_SHARE_CLONES
+        if (pr_waitpid_daemon_exit) {
+            return;
+        }
+	PR_Lock(pr_wp.ml);
+#endif
+	    
+        do {
+            rv = read(pr_wp.pipefd[0], buf, sizeof(buf));
+        } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno));
+
+#ifdef _PR_SHARE_CLONES
+	PR_Unlock(pr_wp.ml);
+	while ((op = pr_wp.opHead) != NULL) {
+	    op->process = ForkAndExec(op->path, op->argv,
+		    op->envp, op->attr);
+	    if (NULL == op->process) {
+		op->prerror = PR_GetError();
+		op->oserror = PR_GetOSError();
+	    }
+	    PR_Lock(pr_wp.ml);
+	    pr_wp.opHead = op->next;
+	    if (NULL == pr_wp.opHead) {
+		pr_wp.opTail = NULL;
+	    }
+	    op->done = PR_TRUE;
+	    PR_NotifyCondVar(op->doneCV);
+	    PR_Unlock(pr_wp.ml);
+	}
+#endif
+
+	while (1) {
+	    do {
+	        pid = waitpid((pid_t) -1, &status, WNOHANG);
+	    } while ((pid_t) -1 == pid && EINTR == errno);
+	    if (0 == pid) break;
+	    if ((pid_t) -1 == pid) {
+		/* must be because we have no child processes */
+		PR_ASSERT(ECHILD == errno);
+		break;
+            }
+
+	    PR_Lock(pr_wp.ml);
+            ProcessReapedChildInternal(pid, status);
+	    PR_Unlock(pr_wp.ml);
+	}
+    }
+}
+
+static void pr_SigchldHandler(int sig)
+{
+    int errnoCopy;
+    int rv;
+
+    errnoCopy = errno;
+
+    do {
+        rv = write(pr_wp.pipefd[1], "", 1);
+    } while (-1 == rv && EINTR == errno);
+
+#ifdef DEBUG
+    if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) {
+        char *msg = "cannot write to pipe\n";
+        write(2, msg, strlen(msg) + 1);
+        _exit(1);
+    }
+#endif
+
+    errno = errnoCopy;
+}
+
+static void pr_InstallSigchldHandler()
+{
+#if defined(HPUX) && defined(_PR_DCETHREADS)
+#error "HP-UX DCE threads have their own SIGCHLD handler"
+#endif
+
+    struct sigaction act, oact;
+    int rv;
+
+    act.sa_handler = pr_SigchldHandler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+    rv = sigaction(SIGCHLD, &act, &oact);
+    PR_ASSERT(0 == rv);
+    /* Make sure we are not overriding someone else's SIGCHLD handler */
+#ifndef _PR_SHARE_CLONES
+    PR_ASSERT(oact.sa_handler == SIG_DFL);
+#endif
+}
+
+#endif  /* !defined(_PR_NATIVE_THREADS) */
+
+static PRStatus _MD_InitProcesses(void)
+{
+#if !defined(_PR_NATIVE_THREADS)
+    int rv;
+    int flags;
+#endif
+#ifdef SUNOS4
+#define _PR_NBIO_FLAG FNDELAY
+#else
+#define _PR_NBIO_FLAG O_NONBLOCK
+#endif
+
+#ifdef AIX
+    {
+        void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
+        pr_wp.forkptr = (pid_t (*)(void)) dlsym(handle, "f_fork");
+        if (!pr_wp.forkptr) {
+            pr_wp.forkptr = fork;
+        }
+        dlclose(handle);
+    }
+#endif /* AIX */
+
+    pr_wp.ml = PR_NewLock();
+    PR_ASSERT(NULL != pr_wp.ml);
+
+#if defined(_PR_NATIVE_THREADS)
+    pr_wp.numProcs = 0;
+    pr_wp.cv = PR_NewCondVar(pr_wp.ml);
+    PR_ASSERT(NULL != pr_wp.cv);
+#else
+    rv = pipe(pr_wp.pipefd);
+    PR_ASSERT(0 == rv);
+    flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0);
+    fcntl(pr_wp.pipefd[0], F_SETFL, flags | _PR_NBIO_FLAG);
+    flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0);
+    fcntl(pr_wp.pipefd[1], F_SETFL, flags | _PR_NBIO_FLAG);
+
+#ifndef _PR_SHARE_CLONES
+    pr_InstallSigchldHandler();
+#endif
+#endif  /* !_PR_NATIVE_THREADS */
+
+    pr_wp.thread = PR_CreateThread(PR_SYSTEM_THREAD,
+	    WaitPidDaemonThread, NULL, PR_PRIORITY_NORMAL,
+#ifdef _PR_SHARE_CLONES
+            PR_GLOBAL_THREAD,
+#else
+	    PR_LOCAL_THREAD,
+#endif
+	    PR_JOINABLE_THREAD, 0);
+    PR_ASSERT(NULL != pr_wp.thread);
+
+    pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *));
+    PR_ASSERT(NULL != pr_wp.pidTable);
+    return PR_SUCCESS;
+}
+
+PRStatus _MD_DetachUnixProcess(PRProcess *process)
+{
+    PRStatus retVal = PR_SUCCESS;
+    pr_PidRecord *pRec;
+
+    PR_Lock(pr_wp.ml);
+    pRec = FindPidTable(process->md.pid);
+    if (NULL == pRec) {
+	pRec = PR_NEW(pr_PidRecord);
+	if (NULL == pRec) {
+	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	    retVal = PR_FAILURE;
+	    goto done;
+	}
+	pRec->pid = process->md.pid;
+	pRec->state = _PR_PID_DETACHED;
+	pRec->reapedCV = NULL;
+	InsertPidTable(pRec);
+    } else {
+	PR_ASSERT(_PR_PID_REAPED == pRec->state);
+	if (_PR_PID_REAPED != pRec->state) {
+	    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+	    retVal = PR_FAILURE;
+	} else {
+	    DeletePidTable(pRec);
+	    PR_ASSERT(NULL == pRec->reapedCV);
+	    PR_DELETE(pRec);
+	}
+    }
+    PR_DELETE(process);
+
+done:
+    PR_Unlock(pr_wp.ml);
+    return retVal;
+}
+
+PRStatus _MD_WaitUnixProcess(
+    PRProcess *process,
+    PRInt32 *exitCode)
+{
+    pr_PidRecord *pRec;
+    PRStatus retVal = PR_SUCCESS;
+    PRBool interrupted = PR_FALSE;
+
+    PR_Lock(pr_wp.ml);
+    pRec = FindPidTable(process->md.pid);
+    if (NULL == pRec) {
+	pRec = PR_NEW(pr_PidRecord);
+	if (NULL == pRec) {
+	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	    retVal = PR_FAILURE;
+	    goto done;
+	}
+	pRec->pid = process->md.pid;
+	pRec->state = _PR_PID_WAITING;
+	pRec->reapedCV = PR_NewCondVar(pr_wp.ml);
+	if (NULL == pRec->reapedCV) {
+	    PR_DELETE(pRec);
+	    retVal = PR_FAILURE;
+	    goto done;
+	}
+	InsertPidTable(pRec);
+	while (!interrupted && _PR_PID_REAPED != pRec->state) {
+	    if (PR_WaitCondVar(pRec->reapedCV,
+		    PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE
+		    && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
+		interrupted = PR_TRUE;
+            }
+	}
+	if (_PR_PID_REAPED == pRec->state) {
+            if (exitCode) {
+                *exitCode = pRec->exitStatus;
+            }
+	} else {
+	    PR_ASSERT(interrupted);
+	    retVal = PR_FAILURE;
+	}
+	DeletePidTable(pRec);
+	PR_DestroyCondVar(pRec->reapedCV);
+	PR_DELETE(pRec);
+    } else {
+	PR_ASSERT(_PR_PID_REAPED == pRec->state);
+	PR_ASSERT(NULL == pRec->reapedCV);
+	DeletePidTable(pRec);
+        if (exitCode) {
+            *exitCode = pRec->exitStatus;
+        }
+	PR_DELETE(pRec);
+    }
+    PR_DELETE(process);
+
+done:
+    PR_Unlock(pr_wp.ml);
+    return retVal;
+}  /* _MD_WaitUnixProcess */
+
+PRStatus _MD_KillUnixProcess(PRProcess *process)
+{
+    PRErrorCode prerror;
+    PRInt32 oserror;
+
+#ifdef SYMBIAN
+    /* In Symbian OS, we can not kill other process with Open C */
+    PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, oserror);
+    return PR_FAILURE;
+#else
+    if (kill(process->md.pid, SIGKILL) == 0) {
+	return PR_SUCCESS;
+    }
+    oserror = errno;
+    switch (oserror) {
+        case EPERM:
+	    prerror = PR_NO_ACCESS_RIGHTS_ERROR;
+	    break;
+        case ESRCH:
+	    prerror = PR_INVALID_ARGUMENT_ERROR;
+	    break;
+        default:
+	    prerror = PR_UNKNOWN_ERROR;
+	    break;
+    }
+    PR_SetError(prerror, oserror);
+    return PR_FAILURE;
+#endif
+}  /* _MD_KillUnixProcess */
diff --git a/mozilla/nsprpub/pr/src/md/unix/uxrng.c b/mozilla/nsprpub/pr/src/md/unix/uxrng.c
new file mode 100644
index 0000000..cafd928
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/uxrng.c
@@ -0,0 +1,324 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 "primpl.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+
+
+#if defined(SOLARIS)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    hrtime_t t;
+    t = gethrtime();
+    if (t) {
+	    return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
+    }
+    return 0;
+}
+
+#elif defined(SUNOS4)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+#elif defined(HPUX)
+
+#ifdef __ia64
+#include <ia64/sys/inline.h>
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    PRUint64 t;
+
+    t = _Asm_mov_from_ar(_AREG44);
+    return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
+}
+#else
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    extern int ret_cr16();
+    int cr16val;
+
+    cr16val = ret_cr16();
+    return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)));
+}
+#endif
+
+#elif defined(OSF1)
+
+#include <c_asm.h>
+
+/*
+ * Use the "get the cycle counter" instruction on the alpha.
+ * The low 32 bits completely turn over in less than a minute.
+ * The high 32 bits are some non-counter gunk that changes sometimes.
+ */
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    unsigned long t;
+
+#ifdef __GNUC__
+    __asm__("rpcc %0" : "=r" (t));
+#else
+    t = asm("rpcc %v0");
+#endif
+    return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
+}
+
+#elif defined(AIX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+#elif (defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD_kernel__) \
+    || defined(NETBSD) || defined(__NetBSD_kernel__) || defined(OPENBSD) \
+    || defined(SYMBIAN))
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static int      fdDevURandom;
+static PRCallOnceType coOpenDevURandom;
+
+static PRStatus OpenDevURandom( void )
+{
+    fdDevURandom = open( "/dev/urandom", O_RDONLY );
+    return((-1 == fdDevURandom)? PR_FAILURE : PR_SUCCESS );
+} /* end OpenDevURandom() */
+
+static size_t GetDevURandom( void *buf, size_t size )
+{
+    int bytesIn;
+    int rc;
+
+    rc = PR_CallOnce( &coOpenDevURandom, OpenDevURandom );
+    if ( PR_FAILURE == rc ) {
+        _PR_MD_MAP_OPEN_ERROR( errno );
+        return(0);
+    }
+
+    bytesIn = read( fdDevURandom, buf, size );
+    if ( -1 == bytesIn ) {
+        _PR_MD_MAP_READ_ERROR( errno );
+        return(0);
+    }
+
+    return( bytesIn );
+} /* end GetDevURandom() */
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{             
+    return(GetDevURandom( buf, maxbytes ));
+}
+
+#elif defined(NCR)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+#elif defined(IRIX)
+#include <fcntl.h>
+#undef PRIVATE
+#include <sys/mman.h>
+#include <sys/syssgi.h>
+#include <sys/immu.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+
+static size_t GetHighResClock(void *buf, size_t maxbuf)
+{
+    unsigned phys_addr, raddr, cycleval;
+    static volatile unsigned *iotimer_addr = NULL;
+    static int tries = 0;
+    static int cntr_size;
+    int mfd;
+    unsigned s0[2];
+
+#ifndef SGI_CYCLECNTR_SIZE
+#define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
+#endif
+
+    if (iotimer_addr == NULL) {
+	    if (tries++ > 1) {
+	        /* Don't keep trying if it didn't work */
+	        return 0;
+	    }
+
+	    /*
+	    ** For SGI machines we can use the cycle counter, if it has one,
+	    ** to generate some truly random numbers
+	    */
+	    phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
+	    if (phys_addr) {
+	        int pgsz = getpagesize();
+	        int pgoffmask = pgsz - 1;
+
+	        raddr = phys_addr & ~pgoffmask;
+	        mfd = open("/dev/mmem", O_RDONLY);
+	        if (mfd < 0) {
+    		    return 0;
+	        }
+	        iotimer_addr = (unsigned *)
+		    mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
+	        if (iotimer_addr == (unsigned*)-1) {
+	    	    close(mfd);
+		        iotimer_addr = NULL;
+		        return 0;
+	        }
+	        iotimer_addr = (unsigned*)
+		    ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
+	        /*
+	         * The file 'mfd' is purposefully not closed.
+	         */
+	        cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
+	        if (cntr_size < 0) {
+    		    struct utsname utsinfo;
+
+		        /* 
+		         * We must be executing on a 6.0 or earlier system, since the
+		         * SGI_CYCLECNTR_SIZE call is not supported.
+		         * 
+		         * The only pre-6.1 platforms with 64-bit counters are
+		         * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
+		         */
+		        uname(&utsinfo);
+		        if (!strncmp(utsinfo.machine, "IP19", 4) ||
+		            !strncmp(utsinfo.machine, "IP21", 4))
+			        cntr_size = 64;
+		        else
+			        cntr_size = 32;
+	        }
+	        cntr_size /= 8;	/* Convert from bits to bytes */
+	    }
+    }
+
+    s0[0] = *iotimer_addr;
+    if (cntr_size > 4)
+	s0[1] = *(iotimer_addr + 1);
+    memcpy(buf, (char *)&s0[0], cntr_size);
+    return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size);
+}
+
+#elif defined(SONY)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+#elif defined(SNI)
+#include <sys/times.h>
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    int ticks;
+    struct tms buffer;
+
+    ticks=times(&buffer);
+    return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
+}
+
+#elif defined(NEC)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+#elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \
+    || defined(QNX) || defined(DARWIN) || defined(RISCOS)
+#include <sys/times.h>
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    int ticks;
+    struct tms buffer;
+
+    ticks=times(&buffer);
+    return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
+}
+#else
+#error! Platform undefined
+#endif /* defined(SOLARIS) */
+
+extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size )
+{
+    struct timeval tv;
+    int n = 0;
+    int s;
+
+    n += GetHighResClock(buf, size);
+    size -= n;
+
+    GETTIMEOFDAY(&tv);
+
+    if ( size > 0 ) {
+        s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec));
+        size -= s;
+        n += s;
+    }
+    if ( size > 0 ) {
+        s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec));
+        size -= s;
+        n += s;
+    }
+
+    return n;
+} /* end _PR_MD_GetRandomNoise() */
diff --git a/mozilla/nsprpub/pr/src/md/unix/uxshm.c b/mozilla/nsprpub/pr/src/md/unix/uxshm.c
new file mode 100644
index 0000000..4eef672
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/uxshm.c
@@ -0,0 +1,675 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** uxshm.c -- Unix Implementations NSPR Named Shared Memory
+**
+**
+** lth. Jul-1999.
+**
+*/
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+#include "primpl.h"       
+#include <fcntl.h>
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+
+#define NSPR_IPC_SHM_KEY 'b'
+/*
+** Implementation for System V
+*/
+#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+#define _MD_DELETE_SHARED_MEMORY  _MD_DeleteSharedMemory
+
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+    const char *name,
+    PRSize      size,
+    PRIntn      flags,
+    PRIntn      mode
+)
+{
+    PRStatus rc = PR_SUCCESS;
+    key_t   key;
+    PRSharedMemory *shm;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return( NULL );
+    }
+
+    shm = PR_NEWZAP( PRSharedMemory );
+    if ( NULL == shm ) 
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); 
+        return( NULL );
+    }
+
+    shm->ipcname = (char*)PR_MALLOC( strlen( ipcname ) + 1 );
+    if ( NULL == shm->ipcname )
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); 
+        PR_DELETE( shm );
+        return( NULL );
+    }
+
+    /* copy args to struct */
+    strcpy( shm->ipcname, ipcname );
+    shm->size = size; 
+    shm->mode = mode; 
+    shm->flags = flags;
+    shm->ident = _PR_SHM_IDENT;
+
+    /* create the file first */
+    if ( flags & PR_SHM_CREATE )  {
+        int osfd = open( shm->ipcname, (O_RDWR | O_CREAT), shm->mode );
+        if ( -1 == osfd ) {
+            _PR_MD_MAP_OPEN_ERROR( errno );
+            PR_FREEIF( shm->ipcname );
+            PR_DELETE( shm );
+            return( NULL );
+        } 
+        if ( close(osfd) == -1 ) {
+            _PR_MD_MAP_CLOSE_ERROR( errno );
+            PR_FREEIF( shm->ipcname );
+            PR_DELETE( shm );
+            return( NULL );
+        }
+    }
+
+    /* hash the shm.name to an ID */
+    key = ftok( shm->ipcname, NSPR_IPC_SHM_KEY );
+    if ( -1 == key )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): ftok() failed on name: %s", shm->ipcname));
+        PR_FREEIF( shm->ipcname );
+        PR_DELETE( shm );
+        return( NULL );
+    }
+
+    /* get the shared memory */
+    if ( flags & PR_SHM_CREATE )  {
+        shm->id = shmget( key, shm->size, ( shm->mode | IPC_CREAT|IPC_EXCL));
+        if ( shm->id >= 0 ) {
+            return( shm );
+        }
+        if ((errno == EEXIST) && (flags & PR_SHM_EXCL)) {
+            PR_SetError( PR_FILE_EXISTS_ERROR, errno );
+            PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+                ("_MD_OpenSharedMemory(): shmget() exclusive failed, errno: %d", errno));
+            PR_FREEIF(shm->ipcname);
+            PR_DELETE(shm);
+            return(NULL);
+        }
+    } 
+
+    shm->id = shmget( key, shm->size, shm->mode );
+    if ( -1 == shm->id ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): shmget() failed, errno: %d", errno));
+        PR_FREEIF(shm->ipcname);
+        PR_DELETE(shm);
+        return(NULL);
+    }
+
+    return( shm );
+} /* end _MD_OpenSharedMemory() */
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    void        *addr;
+    PRUint32    aFlags = shm->mode;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    aFlags |= (flags & PR_SHM_READONLY )? SHM_RDONLY : 0;
+
+    addr = shmat( shm->id, NULL, aFlags );
+    if ( (void*)-1 == addr )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_AttachSharedMemory(): shmat() failed on name: %s, OsError: %d", 
+                shm->ipcname, PR_GetOSError() ));
+        addr = NULL;
+    }
+
+    return addr;
+}    
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PRStatus rc = PR_SUCCESS;
+    PRIntn   urc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    urc = shmdt( addr );
+    if ( -1 == urc )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DetachSharedMemory(): shmdt() failed on name: %s", shm->ipcname ));
+    }
+
+    return rc;
+}    
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    PR_FREEIF(shm->ipcname);
+    PR_DELETE(shm);
+
+    return PR_SUCCESS;
+}    
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    PRStatus rc = PR_SUCCESS;
+    key_t   key;
+    int     id;
+    PRIntn  urc;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError( PR_UNKNOWN_ERROR , errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return(PR_FAILURE);
+    }
+
+    /* create the file first */ 
+    {
+        int osfd = open( ipcname, (O_RDWR | O_CREAT), 0666 );
+        if ( -1 == osfd ) {
+            _PR_MD_MAP_OPEN_ERROR( errno );
+            return( PR_FAILURE );
+        } 
+        if ( close(osfd) == -1 ) {
+            _PR_MD_MAP_CLOSE_ERROR( errno );
+            return( PR_FAILURE );
+        }
+    }
+
+    /* hash the shm.name to an ID */
+    key = ftok( ipcname, NSPR_IPC_SHM_KEY );
+    if ( -1 == key )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): ftok() failed on name: %s", ipcname));
+    }
+
+#ifdef SYMBIAN
+    /* In Symbian OS the system imposed minimum is 1 byte, instead of ZERO */
+    id = shmget( key, 1, 0 );
+#else
+    id = shmget( key, 0, 0 );
+#endif
+    if ( -1 == id ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): shmget() failed, errno: %d", errno));
+        return(PR_FAILURE);
+    }
+
+    urc = shmctl( id, IPC_RMID, NULL );
+    if ( -1 == urc )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): shmctl() failed on name: %s", ipcname ));
+        return(PR_FAILURE);
+    }
+
+    urc = unlink( ipcname );
+    if ( -1 == urc ) {
+        _PR_MD_MAP_UNLINK_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): unlink() failed: %s", ipcname ));
+        return(PR_FAILURE);
+    }
+
+    return rc;
+}  /* end _MD_DeleteSharedMemory() */
+
+/*
+** Implementation for Posix
+*/
+#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+#include <sys/mman.h>
+
+#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+#define _MD_DELETE_SHARED_MEMORY  _MD_DeleteSharedMemory
+
+struct _MDSharedMemory {
+    int     handle;
+};
+
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+    const char *name,
+    PRSize      size,
+    PRIntn      flags,
+    PRIntn      mode
+)
+{
+    PRStatus    rc = PR_SUCCESS;
+    PRInt32     end;
+    PRSharedMemory *shm;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError( PR_UNKNOWN_ERROR , errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return( NULL );
+    }
+
+    shm = PR_NEWZAP( PRSharedMemory );
+    if ( NULL == shm ) 
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); 
+        return( NULL );
+    }
+
+    shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
+    if ( NULL == shm->ipcname )
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); 
+        return( NULL );
+    }
+
+    /* copy args to struct */
+    strcpy( shm->ipcname, ipcname );
+    shm->size = size; 
+    shm->mode = mode;
+    shm->flags = flags;
+    shm->ident = _PR_SHM_IDENT;
+
+    /*
+    ** Create the shared memory
+    */
+    if ( flags & PR_SHM_CREATE )  {
+        int oflag = (O_CREAT | O_RDWR);
+        
+        if ( flags & PR_SHM_EXCL )
+            oflag |= O_EXCL;
+        shm->id = shm_open( shm->ipcname, oflag, shm->mode );
+    } else {
+        shm->id = shm_open( shm->ipcname, O_RDWR, shm->mode );
+    }
+
+    if ( -1 == shm->id )  {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): shm_open failed: %s, OSError: %d",
+                shm->ipcname, PR_GetOSError())); 
+        PR_DELETE( shm->ipcname );
+        PR_DELETE( shm );
+        return(NULL);
+    }
+
+    end = ftruncate( shm->id, shm->size );
+    if ( -1 == end ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): ftruncate failed, OSError: %d",
+                PR_GetOSError()));
+        PR_DELETE( shm->ipcname );
+        PR_DELETE( shm );
+        return(NULL);
+    }
+
+    return(shm);
+} /* end _MD_OpenSharedMemory() */
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    void        *addr;
+    PRIntn      prot = (PROT_READ | PROT_WRITE);
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    if ( PR_SHM_READONLY == flags)
+        prot ^= PROT_WRITE;
+
+    addr = mmap( (void*)0, shm->size, prot, MAP_SHARED, shm->id, 0 );
+    if ((void*)-1 == addr )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_AttachSharedMemory(): mmap failed: %s, errno: %d",
+                shm->ipcname, PR_GetOSError()));
+        addr = NULL;
+    } else {
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_AttachSharedMemory(): name: %s, attached at: %p", shm->ipcname, addr));
+    }
+    
+    return addr;
+}    
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PRStatus    rc = PR_SUCCESS;
+    PRIntn      urc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    urc = munmap( addr, shm->size );
+    if ( -1 == urc )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DetachSharedMemory(): munmap failed: %s, errno: %d", 
+                shm->ipcname, PR_GetOSError()));
+    }
+    return rc;
+}    
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    int urc;
+    
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    urc = close( shm->id );
+    if ( -1 == urc ) {
+        _PR_MD_MAP_CLOSE_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_CloseSharedMemory(): close() failed, error: %d", PR_GetOSError()));
+        return(PR_FAILURE);
+    }
+    PR_DELETE( shm->ipcname );
+    PR_DELETE( shm );
+    return PR_SUCCESS;
+}    
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    PRStatus    rc = PR_SUCCESS;
+    PRUintn     urc;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError( PR_UNKNOWN_ERROR , errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return rc;
+    }
+
+    urc = shm_unlink( ipcname );
+    if ( -1 == urc ) {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): shm_unlink failed: %s, errno: %d", 
+                ipcname, PR_GetOSError()));
+    } else {
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): %s, success", ipcname));
+    }
+
+    return rc;
+} /* end _MD_DeleteSharedMemory() */
+#endif
+
+
+
+/*
+** Unix implementation for anonymous memory (file) mapping
+*/
+extern PRLogModuleInfo *_pr_shma_lm;
+
+#include <unistd.h>
+
+extern PRFileMap* _md_OpenAnonFileMap( 
+    const char *dirName,
+    PRSize      size,
+    PRFileMapProtect prot
+)
+{
+    PRFileMap   *fm = NULL;
+    PRFileDesc  *fd;
+    int         osfd;
+    PRIntn      urc;
+    PRIntn      mode = 0600;
+    char        *genName;
+    pid_t       pid = getpid(); /* for generating filename */
+    PRThread    *tid = PR_GetCurrentThread(); /* for generating filename */
+    int         incr; /* for generating filename */
+    const int   maxTries = 20; /* maximum # attempts at a unique filename */
+    PRInt64     size64; /* 64-bit version of 'size' */
+
+    /*
+    ** generate a filename from input and runtime environment
+    ** open the file, unlink the file.
+    ** make maxTries number of attempts at uniqueness in the filename
+    */
+    for ( incr = 0; incr < maxTries ; incr++ ) {
+#if defined(SYMBIAN)
+#define NSPR_AFM_FILENAME "%s\\NSPR-AFM-%d-%p.%d"
+#else
+#define NSPR_AFM_FILENAME "%s/.NSPR-AFM-%d-%p.%d"
+#endif
+        genName = PR_smprintf( NSPR_AFM_FILENAME,
+            dirName, (int) pid, tid, incr );
+        if ( NULL == genName ) {
+            PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+                ("_md_OpenAnonFileMap(): PR_snprintf(): failed, generating filename"));
+            goto Finished;
+        }
+        
+        /* create the file */
+        osfd = open( genName, (O_CREAT | O_EXCL | O_RDWR), mode );
+        if ( -1 == osfd ) {
+            if ( EEXIST == errno )  {
+                PR_smprintf_free( genName );
+                continue; /* name exists, try again */
+            } else {
+                _PR_MD_MAP_OPEN_ERROR( errno );
+                PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+                    ("_md_OpenAnonFileMap(): open(): failed, filename: %s, errno: %d", 
+                        genName, PR_GetOSError()));
+                PR_smprintf_free( genName );
+                goto Finished;
+            }
+        }
+        break; /* name generation and open successful, break; */
+    } /* end for() */
+
+    if ( incr == maxTries ) {
+        PR_ASSERT( -1 == osfd );
+        PR_ASSERT( EEXIST == errno );
+        _PR_MD_MAP_OPEN_ERROR( errno );
+        goto Finished;
+    }
+
+    urc = unlink( genName );
+#if defined(SYMBIAN) && defined(__WINS__)
+    /* If it is being used by the system or another process, Symbian OS 
+     * Emulator(WINS) considers this an error. */
+    if ( -1 == urc && EACCES != errno ) {
+#else
+    if ( -1 == urc ) {
+#endif
+        _PR_MD_MAP_UNLINK_ERROR( errno );
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): failed on unlink(), errno: %d", errno));
+        PR_smprintf_free( genName );
+        close( osfd );
+        goto Finished;        
+    }
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): unlink(): %s", genName ));
+
+    PR_smprintf_free( genName );
+
+    fd = PR_ImportFile( osfd );
+    if ( NULL == fd ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): PR_ImportFile(): failed"));
+        goto Finished;        
+    }
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): fd: %p", fd ));
+
+    urc = ftruncate( fd->secret->md.osfd, size );
+    if ( -1 == urc ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): failed on ftruncate(), errno: %d", errno));
+        PR_Close( fd );
+        goto Finished;        
+    }
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): ftruncate(): size: %d", size ));
+
+    LL_UI2L(size64, size);  /* PRSize (size_t) is unsigned */
+    fm = PR_CreateFileMap( fd, size64, prot );
+    if ( NULL == fm )  {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("PR_OpenAnonFileMap(): failed"));
+        PR_Close( fd );
+        goto Finished;        
+    }
+    fm->md.isAnonFM = PR_TRUE; /* set fd close */
+
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): PR_CreateFileMap(): fm: %p", fm ));
+
+Finished:    
+    return(fm);
+} /* end md_OpenAnonFileMap() */
+
+/*
+** _md_ExportFileMapAsString()
+**
+**
+*/
+extern PRStatus _md_ExportFileMapAsString(
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+)
+{
+    PRIntn  written;
+    PRIntn  prot = (PRIntn)fm->prot;
+    
+    written = PR_snprintf( buf, bufSize, "%ld:%d",
+        fm->fd->secret->md.osfd, prot );
+        
+    return((written == -1)? PR_FAILURE : PR_SUCCESS);
+} /* end _md_ExportFileMapAsString() */
+
+
+extern PRFileMap * _md_ImportFileMapFromString(
+    const char *fmstring
+)
+{
+    PRStatus    rc;
+    PRInt32     osfd;
+    PRIntn      prot; /* really: a PRFileMapProtect */
+    PRFileDesc  *fd;
+    PRFileMap   *fm = NULL; /* default return value */
+    PRFileInfo64 info;
+
+    PR_sscanf( fmstring, "%ld:%d", &osfd, &prot );
+
+    /* import the os file descriptor */
+    fd = PR_ImportFile( osfd );
+    if ( NULL == fd ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_ImportFile() failed"));
+        goto Finished;
+    }
+
+    rc = PR_GetOpenFileInfo64( fd, &info );
+    if ( PR_FAILURE == rc )  {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_GetOpenFileInfo64() failed"));    
+        goto Finished;
+    }
+
+    fm = PR_CreateFileMap( fd, info.size, (PRFileMapProtect)prot );
+    if ( NULL == fm ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_CreateFileMap() failed"));    
+    }
+
+Finished:
+    return(fm);
+} /* end _md_ImportFileMapFromString() */
diff --git a/mozilla/nsprpub/pr/src/md/unix/uxwrap.c b/mozilla/nsprpub/pr/src/md/unix/uxwrap.c
new file mode 100644
index 0000000..ef226a6
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/unix/uxwrap.c
@@ -0,0 +1,548 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ *------------------------------------------------------------------------
+ * File: uxwrap.c
+ *
+ *     Our wrapped versions of the Unix select() and poll() system calls.
+ *
+ *------------------------------------------------------------------------
+ */
+
+#include "primpl.h"
+
+#if defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(QNX)
+/* Do not wrap select() and poll(). */
+#else  /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */
+/* The include files for select() */
+#ifdef IRIX
+#include <unistd.h>
+#include <bstring.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#define ZAP_SET(_to, _width)				      \
+    PR_BEGIN_MACRO					      \
+	memset(_to, 0,					      \
+	       ((_width + 8*sizeof(int)-1) / (8*sizeof(int))) \
+		* sizeof(int)				      \
+	       );					      \
+    PR_END_MACRO
+
+/* see comments in ns/cmd/xfe/mozilla.c (look for "PR_XGetXtHackFD") */
+static int _pr_xt_hack_fd = -1;
+ 
+int PR_XGetXtHackFD(void)
+{
+    int fds[2];
+ 
+    if (_pr_xt_hack_fd == -1) {
+        if (!pipe(fds)) {
+            _pr_xt_hack_fd = fds[0];
+        }
+    }
+    return _pr_xt_hack_fd;
+}
+
+static int (*_pr_xt_hack_okayToReleaseXLock)(void) = 0;
+
+void PR_SetXtHackOkayToReleaseXLockFn(int (*fn)(void))
+{
+    _pr_xt_hack_okayToReleaseXLock = fn; 
+}
+
+
+/*
+ *-----------------------------------------------------------------------
+ *  select() --
+ *
+ *    Wrap up the select system call so that we can deschedule
+ *    a thread that tries to wait for i/o.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+#if defined(HPUX9)
+int select(size_t width, int *rl, int *wl, int *el, const struct timeval *tv)
+#elif defined(NEXTSTEP)
+int wrap_select(int width, fd_set *rd, fd_set *wr, fd_set *ex,
+        const struct timeval *tv)
+#elif defined(AIX_RENAME_SELECT)
+int wrap_select(unsigned long width, void *rl, void *wl, void *el,
+        struct timeval *tv)
+#elif defined(_PR_SELECT_CONST_TIMEVAL)
+int select(int width, fd_set *rd, fd_set *wr, fd_set *ex,
+        const struct timeval *tv)
+#else
+int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv)
+#endif
+{
+    int osfd;
+    _PRUnixPollDesc *unixpds, *unixpd, *eunixpd;
+    PRInt32 pdcnt;
+    PRIntervalTime timeout;
+    int retVal;
+#if defined(HPUX9) || defined(AIX_RENAME_SELECT)
+    fd_set *rd = (fd_set*) rl;
+    fd_set *wr = (fd_set*) wl;
+    fd_set *ex = (fd_set*) el;
+#endif
+
+#if 0
+    /*
+     * Easy special case: zero timeout.  Simply call the native
+     * select() with no fear of blocking.
+     */
+    if (tv != NULL && tv->tv_sec == 0 && tv->tv_usec == 0) {
+#if defined(HPUX9) || defined(AIX_RENAME_SELECT)
+        return _MD_SELECT(width, rl, wl, el, tv);
+#else
+        return _MD_SELECT(width, rd, wr, ex, tv);
+#endif
+    }
+#endif
+
+    if (!_pr_initialized) {
+        _PR_ImplicitInitialization();
+    }
+		
+#ifndef _PR_LOCAL_THREADS_ONLY
+    if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) {
+        return _MD_SELECT(width, rd, wr, ex, tv);	
+    }
+#endif
+
+    if (width < 0 || width > FD_SETSIZE) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    /* Compute timeout */
+    if (tv) {
+        /*
+         * These acceptable ranges for t_sec and t_usec are taken
+         * from the select() man pages.
+         */
+        if (tv->tv_sec < 0 || tv->tv_sec > 100000000
+                || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
+            errno = EINVAL;
+            return -1;
+        }
+
+        /* Convert microseconds to ticks */
+        timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec);
+    } else {
+        /* tv being a NULL pointer means blocking indefinitely */
+        timeout = PR_INTERVAL_NO_TIMEOUT;
+    }
+
+    /* Check for no descriptors case (just doing a timeout) */
+    if ((!rd && !wr && !ex) || !width) {
+        PR_Sleep(timeout);
+        return 0;
+    }
+
+    /*
+     * Set up for PR_Poll().  The PRPollDesc array is allocated
+     * dynamically.  If this turns out to have high performance
+     * penalty, one can change to use a large PRPollDesc array
+     * on the stack, and allocate dynamically only when it turns
+     * out to be not large enough.
+     *
+     * I allocate an array of size 'width', which is the maximum
+     * number of fds we may need to poll.
+     */
+    unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc));
+    if (!unixpds) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    pdcnt = 0;
+    unixpd = unixpds;
+    for (osfd = 0; osfd < width; osfd++) {
+        int in_flags = 0;
+        if (rd && FD_ISSET(osfd, rd)) {
+            in_flags |= _PR_UNIX_POLL_READ;
+        }
+        if (wr && FD_ISSET(osfd, wr)) {
+            in_flags |= _PR_UNIX_POLL_WRITE;
+        }
+        if (ex && FD_ISSET(osfd, ex)) {
+            in_flags |= _PR_UNIX_POLL_EXCEPT;
+        }
+        if (in_flags) {
+            unixpd->osfd = osfd;
+            unixpd->in_flags = in_flags;
+            unixpd->out_flags = 0;
+            unixpd++;
+            pdcnt++;
+        }
+    }
+
+    /*
+     * see comments in mozilla/cmd/xfe/mozilla.c (look for
+     * "PR_XGetXtHackFD")
+     */
+   {
+     int needToLockXAgain;
+ 
+     needToLockXAgain = 0;
+     if (rd && (_pr_xt_hack_fd != -1)
+             && FD_ISSET(_pr_xt_hack_fd, rd) && PR_XIsLocked()
+             && (!_pr_xt_hack_okayToReleaseXLock
+             || _pr_xt_hack_okayToReleaseXLock())) {
+         PR_XUnlock();
+         needToLockXAgain = 1;
+     }
+
+    /* This is the potentially blocking step */
+    retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout);
+
+     if (needToLockXAgain) {
+         PR_XLock();
+     }
+   }
+
+    if (retVal > 0) {
+        /* Compute select results */
+        if (rd) ZAP_SET(rd, width);
+        if (wr) ZAP_SET(wr, width);
+        if (ex) ZAP_SET(ex, width);
+
+        /*
+         * The return value can be either the number of ready file
+         * descriptors or the number of set bits in the three fd_set's.
+         */
+        retVal = 0;  /* we're going to recompute */
+        eunixpd = unixpds + pdcnt;
+        for (unixpd = unixpds; unixpd < eunixpd; unixpd++) {
+            if (unixpd->out_flags) {
+                int nbits = 0;  /* The number of set bits on for this fd */
+
+                if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) {
+                    errno = EBADF;
+                    PR_LOG(_pr_io_lm, PR_LOG_ERROR,
+                            ("select returns EBADF for %d", unixpd->osfd));
+                    retVal = -1;
+                    break;
+                }
+                /*
+                 * If a socket has a pending error, it is considered
+                 * both readable and writable.  (See W. Richard Stevens,
+                 * Unix Network Programming, Vol. 1, 2nd Ed., Section 6.3,
+                 * pp. 153-154.)  We also consider a socket readable if
+                 * it has a hangup condition.
+                 */
+                if (rd && (unixpd->in_flags & _PR_UNIX_POLL_READ)
+                        && (unixpd->out_flags & (_PR_UNIX_POLL_READ
+                        | _PR_UNIX_POLL_ERR | _PR_UNIX_POLL_HUP))) {
+                    FD_SET(unixpd->osfd, rd);
+                    nbits++;
+                }
+                if (wr && (unixpd->in_flags & _PR_UNIX_POLL_WRITE)
+                        && (unixpd->out_flags & (_PR_UNIX_POLL_WRITE
+                        | _PR_UNIX_POLL_ERR))) {
+                    FD_SET(unixpd->osfd, wr);
+                    nbits++;
+                }
+                if (ex && (unixpd->in_flags & _PR_UNIX_POLL_WRITE)
+                        && (unixpd->out_flags & PR_POLL_EXCEPT)) {
+                    FD_SET(unixpd->osfd, ex);
+                    nbits++;
+                }
+                PR_ASSERT(nbits > 0);
+#if defined(HPUX) || defined(SOLARIS) || defined(SUNOS4) || defined(OSF1) || defined(AIX)
+                retVal += nbits;
+#else /* IRIX */
+                retVal += 1;
+#endif
+            }
+        }
+    }
+
+    PR_ASSERT(tv || retVal != 0);
+    PR_LOG(_pr_io_lm, PR_LOG_MIN, ("select returns %d", retVal));
+    PR_DELETE(unixpds);
+
+    return retVal;
+}
+
+/*
+ * Redefine poll, when supported on platforms, for local threads
+ */
+
+/*
+ * I am commenting out the poll() wrapper for Linux for now
+ * because it is difficult to define _MD_POLL that works on all
+ * Linux varieties.  People reported that glibc 2.0.7 on Debian
+ * 2.0 Linux machines doesn't have the __syscall_poll symbol
+ * defined.  (WTC 30 Nov. 1998)
+ */
+#if defined(_PR_POLL_AVAILABLE) && !defined(LINUX)
+
+/*
+ *-----------------------------------------------------------------------
+ * poll() --
+ *
+ * RETURN VALUES: 
+ *     -1:  fails, errno indicates the error.
+ *      0:  timed out, the revents bitmasks are not set.
+ *      positive value: the number of file descriptors for which poll()
+ *          has set the revents bitmask.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+#include <poll.h>
+
+#if defined(AIX_RENAME_SELECT)
+int wrap_poll(void *listptr, unsigned long nfds, long timeout)
+#elif (defined(AIX) && !defined(AIX_RENAME_SELECT))
+int poll(void *listptr, unsigned long nfds, long timeout)
+#elif defined(OSF1) || (defined(HPUX) && !defined(HPUX9))
+int poll(struct pollfd filedes[], unsigned int nfds, int timeout)
+#elif defined(HPUX9)
+int poll(struct pollfd filedes[], int nfds, int timeout)
+#elif defined(NETBSD)
+int poll(struct pollfd *filedes, nfds_t nfds, int timeout)
+#elif defined(OPENBSD)
+int poll(struct pollfd filedes[], nfds_t nfds, int timeout)
+#elif defined(FREEBSD)
+int poll(struct pollfd *filedes, unsigned nfds, int timeout)
+#else
+int poll(struct pollfd *filedes, unsigned long nfds, int timeout)
+#endif
+{
+#ifdef AIX
+    struct pollfd *filedes = (struct pollfd *) listptr;
+#endif
+    struct pollfd *pfd, *epfd;
+    _PRUnixPollDesc *unixpds, *unixpd, *eunixpd;
+    PRIntervalTime ticks;
+    PRInt32 pdcnt;
+    int ready;
+
+    /*
+     * Easy special case: zero timeout.  Simply call the native
+     * poll() with no fear of blocking.
+     */
+    if (timeout == 0) {
+#if defined(AIX)
+        return _MD_POLL(listptr, nfds, timeout);
+#else
+        return _MD_POLL(filedes, nfds, timeout);
+#endif
+    }
+
+    if (!_pr_initialized) {
+        _PR_ImplicitInitialization();
+    }
+
+#ifndef _PR_LOCAL_THREADS_ONLY
+    if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) {
+    	return _MD_POLL(filedes, nfds, timeout);
+    }
+#endif
+
+    /* We do not support the pollmsg structures on AIX */
+#ifdef AIX
+    PR_ASSERT((nfds & 0xff00) == 0);
+#endif
+
+    if (timeout < 0 && timeout != -1) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    /* Convert timeout from miliseconds to ticks */
+    if (timeout == -1) {
+        ticks = PR_INTERVAL_NO_TIMEOUT;
+    } else {
+        ticks = PR_MillisecondsToInterval(timeout);
+    }
+
+    /* Check for no descriptor case (just do a timeout) */
+    if (nfds == 0) {
+        PR_Sleep(ticks);
+        return 0;
+    }
+
+    unixpds = (_PRUnixPollDesc *)
+            PR_MALLOC(nfds * sizeof(_PRUnixPollDesc));
+    if (NULL == unixpds) {
+        errno = EAGAIN;
+        return -1;
+    }
+
+    pdcnt = 0;
+    epfd = filedes + nfds;
+    unixpd = unixpds;
+    for (pfd = filedes; pfd < epfd; pfd++) {
+        /*
+         * poll() ignores negative fd's.
+         */
+        if (pfd->fd >= 0) {
+            unixpd->osfd = pfd->fd;
+#ifdef _PR_USE_POLL
+            unixpd->in_flags = pfd->events;
+#else
+            /*
+             * Map the poll events to one of the three that can be
+             * represented by the select fd_sets:
+             *     POLLIN, POLLRDNORM  ===> readable
+             *     POLLOUT, POLLWRNORM ===> writable
+             *     POLLPRI, POLLRDBAND ===> exception
+             *     POLLNORM, POLLWRBAND (and POLLMSG on some platforms)
+             *     are ignored.
+             *
+             * The output events POLLERR and POLLHUP are never turned on.
+             * POLLNVAL may be turned on.
+             */
+            unixpd->in_flags = 0;
+            if (pfd->events & (POLLIN
+#ifdef POLLRDNORM
+                    | POLLRDNORM
+#endif
+                    )) {
+                unixpd->in_flags |= _PR_UNIX_POLL_READ;
+            }
+            if (pfd->events & (POLLOUT
+#ifdef POLLWRNORM
+                    | POLLWRNORM
+#endif
+                    )) {
+                unixpd->in_flags |= _PR_UNIX_POLL_WRITE;
+            }
+            if (pfd->events & (POLLPRI
+#ifdef POLLRDBAND
+                    | POLLRDBAND
+#endif
+                    )) {
+                unixpd->in_flags |= PR_POLL_EXCEPT;
+            }
+#endif  /* _PR_USE_POLL */
+            unixpd->out_flags = 0;
+            unixpd++;
+            pdcnt++;
+        }
+    }
+
+    ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, ticks);
+    if (-1 == ready) {
+        if (PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
+            errno = EINTR;  /* XXX we aren't interrupted by a signal, but... */
+        } else {
+            errno = PR_GetOSError();
+        }
+    }
+    if (ready <= 0) {
+        goto done;
+    }
+
+    /*
+     * Copy the out_flags from the _PRUnixPollDesc structures to the
+     * user's pollfd structures and free the allocated memory
+     */
+    unixpd = unixpds;
+    for (pfd = filedes; pfd < epfd; pfd++) {
+        pfd->revents = 0;
+        if (pfd->fd >= 0) {
+#ifdef _PR_USE_POLL
+            pfd->revents = unixpd->out_flags;
+#else
+            if (0 != unixpd->out_flags) {
+                if (unixpd->out_flags & _PR_UNIX_POLL_READ) {
+                    if (pfd->events & POLLIN) {
+                        pfd->revents |= POLLIN;
+                    }
+#ifdef POLLRDNORM
+                    if (pfd->events & POLLRDNORM) {
+                        pfd->revents |= POLLRDNORM;
+                    }
+#endif
+                }
+                if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) {
+                    if (pfd->events & POLLOUT) {
+                        pfd->revents |= POLLOUT;
+                    }
+#ifdef POLLWRNORM
+                    if (pfd->events & POLLWRNORM) {
+                        pfd->revents |= POLLWRNORM;
+                    }
+#endif
+                }
+                if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) {
+                    if (pfd->events & POLLPRI) {
+                        pfd->revents |= POLLPRI;
+                    }
+#ifdef POLLRDBAND
+                    if (pfd->events & POLLRDBAND) {
+                        pfd->revents |= POLLRDBAND;
+                    }
+#endif
+                }
+                if (unixpd->out_flags & _PR_UNIX_POLL_ERR) {
+                    pfd->revents |= POLLERR;
+                }
+                if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) {
+                    pfd->revents |= POLLNVAL;
+                }
+                if (unixpd->out_flags & _PR_UNIX_POLL_HUP) {
+                    pfd->revents |= POLLHUP;
+                }
+            }
+#endif  /* _PR_USE_POLL */
+            unixpd++;
+        }
+    }
+
+done:
+    PR_DELETE(unixpds);
+    return ready;
+}
+
+#endif  /* !defined(LINUX) */
+
+#endif  /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */
+
+/* uxwrap.c */
+
diff --git a/mozilla/nsprpub/pr/src/md/windows/ntgc.c b/mozilla/nsprpub/pr/src/md/windows/ntgc.c
new file mode 100644
index 0000000..e12b30d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/ntgc.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * GC related routines
+ *
+ */
+#include <windows.h>
+#include "primpl.h"
+
+PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) 
+{
+#if defined(_X86_)
+    CONTEXT context;
+    context.ContextFlags = CONTEXT_INTEGER;
+
+    if (_PR_IS_NATIVE_THREAD(t)) {
+        context.ContextFlags |= CONTEXT_CONTROL;
+        if (GetThreadContext(t->md.handle, &context)) {
+            t->md.gcContext[0] = context.Eax;
+            t->md.gcContext[1] = context.Ebx;
+            t->md.gcContext[2] = context.Ecx;
+            t->md.gcContext[3] = context.Edx;
+            t->md.gcContext[4] = context.Esi;
+            t->md.gcContext[5] = context.Edi;
+            t->md.gcContext[6] = context.Esp;
+            t->md.gcContext[7] = context.Ebp;
+            *np = PR_NUM_GCREGS;
+        } else {
+            PR_ASSERT(0);/* XXX */
+        }
+    } else {
+        /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+         *
+         * This code is extremely machine dependant and completely 
+         * undocumented by MS.  Its only known to work experimentally.  
+         * Ready for a walk on the wild * side?
+         *
+         * WARNING WARNING WARNING WARNING WARNING WARNING WARNING */
+
+#if !defined WIN95 // Win95 does not have fibers
+        int *fiberData = t->md.fiber_id;
+
+        /* I found these offsets by disassembling SwitchToFiber().
+         * Are your palms sweating yet?
+         */
+
+        /* 
+        ** EAX is on the stack (ESP+0)
+        ** EDX is on the stack (ESP+4)
+        ** ECX is on the stack (ESP+8)
+        */
+        t->md.gcContext[0] = 0;                /* context.Eax */
+        t->md.gcContext[1] = fiberData[0x2e];  /* context.Ebx */
+        t->md.gcContext[2] = 0;                /* context.Ecx */
+        t->md.gcContext[2] = 0;                /* context.Edx */
+        t->md.gcContext[4] = fiberData[0x2d];  /* context.Esi */
+        t->md.gcContext[5] = fiberData[0x2c];  /* context.Edi */
+        t->md.gcContext[6] = fiberData[0x36];  /* context.Esp */
+        t->md.gcContext[7] = fiberData[0x32];  /* context.Ebp */
+        *np = PR_NUM_GCREGS;
+#endif
+    }
+    return (PRWord *)&t->md.gcContext;
+#else
+    PR_NOT_REACHED("not implemented");
+    return NULL;
+#endif /* defined(_X86_) */
+}
+
+/* This function is not used right now, but is left as a reference.
+ * If you ever need to get the fiberID from the currently running fiber, 
+ * this is it.
+ */
+void *
+GetMyFiberID()
+{
+#if defined(_X86_) && !defined(__MINGW32__)
+    void *fiberData;
+
+    /* A pointer to our tib entry is found at FS:[18]
+     * At offset 10h is the fiberData pointer.  The context of the 
+     * fiber is stored in there.  
+     */
+    __asm {
+        mov    EDX, FS:[18h]
+        mov    EAX, DWORD PTR [EDX+10h]
+        mov    [fiberData], EAX
+    }
+  
+    return fiberData;
+#else
+    PR_NOT_REACHED("not implemented");
+    return NULL;
+#endif /* defined(_X86_) */
+}
diff --git a/mozilla/nsprpub/pr/src/md/windows/ntinrval.c b/mozilla/nsprpub/pr/src/md/windows/ntinrval.c
new file mode 100644
index 0000000..f96c27b
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/ntinrval.c
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * NT interval timers
+ *
+ */
+
+#include "primpl.h"
+
+#ifdef WINCE
+typedef DWORD (*IntervalFuncType)(void);
+static IntervalFuncType intervalFunc;
+#endif
+
+void
+_PR_MD_INTERVAL_INIT()
+{
+#ifdef WINCE
+    HMODULE mmtimerlib = LoadLibraryW(L"mmtimer.dll");  /* XXX leaked! */
+    if (mmtimerlib) {
+        intervalFunc = (IntervalFuncType)GetProcAddress(mmtimerlib,
+                                                        "timeGetTime");
+    } else {
+        intervalFunc = &GetTickCount;
+    }
+#endif
+}
+
+PRIntervalTime 
+_PR_MD_GET_INTERVAL()
+{
+    /* milliseconds since system start */
+#ifdef WINCE
+    return (*intervalFunc)();
+#else
+    return timeGetTime();
+#endif
+}
+
+PRIntervalTime 
+_PR_MD_INTERVAL_PER_SEC()
+{
+    return 1000;
+}
diff --git a/mozilla/nsprpub/pr/src/md/windows/ntmisc.c b/mozilla/nsprpub/pr/src/md/windows/ntmisc.c
new file mode 100644
index 0000000..c47b599
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/ntmisc.c
@@ -0,0 +1,1208 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * ntmisc.c
+ *
+ */
+
+#include "primpl.h"
+#include <math.h>     /* for fabs() */
+#include <windows.h>
+
+char *_PR_MD_GET_ENV(const char *name)
+{
+    return getenv(name);
+}
+
+/*
+** _PR_MD_PUT_ENV() -- add or change environment variable
+**
+**
+*/
+PRIntn _PR_MD_PUT_ENV(const char *name)
+{
+    return(putenv(name));
+}
+
+
+/*
+ **************************************************************************
+ **************************************************************************
+ **
+ **     Date and time routines
+ **
+ **************************************************************************
+ **************************************************************************
+ */
+
+/*
+ * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
+ * We store the value in a PRTime variable for convenience.
+ */
+#ifdef __GNUC__
+const PRTime _pr_filetime_offset = 116444736000000000LL;
+const PRTime _pr_filetime_divisor = 10LL;
+#else
+const PRTime _pr_filetime_offset = 116444736000000000i64;
+const PRTime _pr_filetime_divisor = 10i64;
+#endif
+
+#ifdef WINCE
+
+#define FILETIME_TO_INT64(ft) \
+  (((PRInt64)ft.dwHighDateTime) << 32 | (PRInt64)ft.dwLowDateTime)
+
+static void
+LowResTime(LPFILETIME lpft)
+{
+    GetCurrentFT(lpft);
+}
+
+typedef struct CalibrationData {
+    long double freq;         /* The performance counter frequency */
+    long double offset;       /* The low res 'epoch' */
+    long double timer_offset; /* The high res 'epoch' */
+
+    /* The last high res time that we returned since recalibrating */
+    PRInt64 last;
+
+    PRBool calibrated;
+
+    CRITICAL_SECTION data_lock;
+    CRITICAL_SECTION calibration_lock;
+    PRInt64 granularity;
+} CalibrationData;
+
+static CalibrationData calibration;
+
+typedef void (*GetSystemTimeAsFileTimeFcn)(LPFILETIME);
+static GetSystemTimeAsFileTimeFcn ce6_GetSystemTimeAsFileTime = NULL;
+
+static void
+NowCalibrate(void)
+{
+    FILETIME ft, ftStart;
+    LARGE_INTEGER liFreq, now;
+
+    if (calibration.freq == 0.0) {
+	if(!QueryPerformanceFrequency(&liFreq)) {
+	    /* High-performance timer is unavailable */
+	    calibration.freq = -1.0;
+	} else {
+	    calibration.freq = (long double) liFreq.QuadPart;
+	}
+    }
+    if (calibration.freq > 0.0) {
+	PRInt64 calibrationDelta = 0;
+	/*
+	 * By wrapping a timeBegin/EndPeriod pair of calls around this loop,
+	 * the loop seems to take much less time (1 ms vs 15ms) on Vista. 
+	 */
+	timeBeginPeriod(1);
+	LowResTime(&ftStart);
+	do {
+	    LowResTime(&ft);
+	} while (memcmp(&ftStart,&ft, sizeof(ft)) == 0);
+	timeEndPeriod(1);
+
+	calibration.granularity = 
+	    (FILETIME_TO_INT64(ft) - FILETIME_TO_INT64(ftStart))/10;
+
+	QueryPerformanceCounter(&now);
+
+	calibration.offset = (long double) FILETIME_TO_INT64(ft);
+	calibration.timer_offset = (long double) now.QuadPart;
+	/*
+	 * The windows epoch is around 1600. The unix epoch is around 1970. 
+	 * _pr_filetime_offset is the difference (in windows time units which
+	 * are 10 times more highres than the JS time unit) 
+	 */
+	calibration.offset -= _pr_filetime_offset;
+	calibration.offset *= 0.1;
+	calibration.last = 0;
+
+	calibration.calibrated = PR_TRUE;
+    }
+}
+
+#define CALIBRATIONLOCK_SPINCOUNT 0
+#define DATALOCK_SPINCOUNT 4096
+#define LASTLOCK_SPINCOUNT 4096
+
+void
+_MD_InitTime(void)
+{
+    /* try for CE6 GetSystemTimeAsFileTime first */
+    HANDLE h = GetModuleHandleW(L"coredll.dll");
+    ce6_GetSystemTimeAsFileTime = (GetSystemTimeAsFileTimeFcn)
+        GetProcAddressA(h, "GetSystemTimeAsFileTime");
+
+    /* otherwise go the slow route */
+    if (ce6_GetSystemTimeAsFileTime == NULL) {
+        memset(&calibration, 0, sizeof(calibration));
+        NowCalibrate();
+        InitializeCriticalSection(&calibration.calibration_lock);
+        InitializeCriticalSection(&calibration.data_lock);
+    }
+}
+
+void
+_MD_CleanupTime(void)
+{
+    if (ce6_GetSystemTimeAsFileTime == NULL) {
+        DeleteCriticalSection(&calibration.calibration_lock);
+        DeleteCriticalSection(&calibration.data_lock);
+    }
+}
+
+#define MUTEX_SETSPINCOUNT(m, c)
+
+/*
+ *-----------------------------------------------------------------------
+ *
+ * PR_Now --
+ *
+ *     Returns the current time in microseconds since the epoch.
+ *     The epoch is midnight January 1, 1970 GMT.
+ *     The implementation is machine dependent.  This is the
+ *     implementation for Windows.
+ *     Cf. time_t time(time_t *tp)
+ *
+ *-----------------------------------------------------------------------
+ */
+
+PR_IMPLEMENT(PRTime)
+PR_Now(void)
+{
+    long double lowresTime, highresTimerValue;
+    FILETIME ft;
+    LARGE_INTEGER now;
+    PRBool calibrated = PR_FALSE;
+    PRBool needsCalibration = PR_FALSE;
+    PRInt64 returnedTime;
+    long double cachedOffset = 0.0;
+
+    if (ce6_GetSystemTimeAsFileTime) {
+        union {
+            FILETIME ft;
+            PRTime prt;
+        } currentTime;
+
+        PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
+
+        ce6_GetSystemTimeAsFileTime(&currentTime.ft);
+
+        /* written this way on purpose, since the second term becomes
+         * a constant, and the entire expression is faster to execute.
+         */
+        return currentTime.prt/_pr_filetime_divisor -
+            _pr_filetime_offset/_pr_filetime_divisor;
+    }
+
+    do {
+	if (!calibration.calibrated || needsCalibration) {
+	    EnterCriticalSection(&calibration.calibration_lock);
+	    EnterCriticalSection(&calibration.data_lock);
+
+	    /* Recalibrate only if no one else did before us */
+	    if (calibration.offset == cachedOffset) {
+		/*
+		 * Since calibration can take a while, make any other
+		 * threads immediately wait 
+		 */
+		MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
+
+		NowCalibrate();
+
+		calibrated = PR_TRUE;
+
+		/* Restore spin count */
+		MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT);
+	    }
+	    LeaveCriticalSection(&calibration.data_lock);
+	    LeaveCriticalSection(&calibration.calibration_lock);
+	}
+
+	/* Calculate a low resolution time */
+	LowResTime(&ft);
+	lowresTime =
+            ((long double)(FILETIME_TO_INT64(ft) - _pr_filetime_offset)) * 0.1;
+
+	if (calibration.freq > 0.0) {
+	    long double highresTime, diff;
+	    DWORD timeAdjustment, timeIncrement;
+	    BOOL timeAdjustmentDisabled;
+
+	    /* Default to 15.625 ms if the syscall fails */
+	    long double skewThreshold = 15625.25;
+
+	    /* Grab high resolution time */
+	    QueryPerformanceCounter(&now);
+	    highresTimerValue = (long double)now.QuadPart;
+
+	    EnterCriticalSection(&calibration.data_lock);
+	    highresTime = calibration.offset + 1000000L *
+		(highresTimerValue-calibration.timer_offset)/calibration.freq;
+	    cachedOffset = calibration.offset;
+
+	    /* 
+	     * On some dual processor/core systems, we might get an earlier 
+	     * time so we cache the last time that we returned.
+	     */
+	    calibration.last = PR_MAX(calibration.last,(PRInt64)highresTime);
+	    returnedTime = calibration.last;
+	    LeaveCriticalSection(&calibration.data_lock);
+
+	    /* Get an estimate of clock ticks per second from our own test */
+	    skewThreshold = calibration.granularity;
+	    /* Check for clock skew */
+	    diff = lowresTime - highresTime;
+
+	    /* 
+	     * For some reason that I have not determined, the skew can be
+	     * up to twice a kernel tick. This does not seem to happen by
+	     * itself, but I have only seen it triggered by another program
+	     * doing some kind of file I/O. The symptoms are a negative diff
+	     * followed by an equally large positive diff. 
+	     */
+	    if (fabs(diff) > 2*skewThreshold) {
+		if (calibrated) {
+		    /*
+		     * If we already calibrated once this instance, and the
+		     * clock is still skewed, then either the processor(s) are
+		     * wildly changing clockspeed or the system is so busy that
+		     * we get switched out for long periods of time. In either
+		     * case, it would be infeasible to make use of high
+		     * resolution results for anything, so let's resort to old
+		     * behavior for this call. It's possible that in the
+		     * future, the user will want the high resolution timer, so
+		     * we don't disable it entirely. 
+		     */
+		    returnedTime = (PRInt64)lowresTime;
+		    needsCalibration = PR_FALSE;
+		} else {
+		    /*
+		     * It is possible that when we recalibrate, we will return 
+		     * a value less than what we have returned before; this is
+		     * unavoidable. We cannot tell the different between a
+		     * faulty QueryPerformanceCounter implementation and user
+		     * changes to the operating system time. Since we must
+		     * respect user changes to the operating system time, we
+		     * cannot maintain the invariant that Date.now() never
+		     * decreases; the old implementation has this behavior as
+		     * well. 
+		     */
+		    needsCalibration = PR_TRUE;
+		}
+	    } else {
+		/* No detectable clock skew */
+		returnedTime = (PRInt64)highresTime;
+		needsCalibration = PR_FALSE;
+	    }
+	} else {
+	    /* No high resolution timer is available, so fall back */
+	    returnedTime = (PRInt64)lowresTime;
+	}
+    } while (needsCalibration);
+
+    return returnedTime;
+}
+
+#else
+
+PR_IMPLEMENT(PRTime)
+PR_Now(void)
+{
+    PRTime prt;
+    FILETIME ft;
+    SYSTEMTIME st;
+
+    GetSystemTime(&st);
+    SystemTimeToFileTime(&st, &ft);
+    _PR_FileTimeToPRTime(&ft, &prt);
+    return prt;       
+}
+
+#endif
+
+/*
+ ***********************************************************************
+ ***********************************************************************
+ *
+ * Process creation routines
+ *
+ ***********************************************************************
+ ***********************************************************************
+ */
+
+/*
+ * Assemble the command line by concatenating the argv array.
+ * On success, this function returns 0 and the resulting command
+ * line is returned in *cmdLine.  On failure, it returns -1.
+ */
+static int assembleCmdLine(char *const *argv, char **cmdLine)
+{
+    char *const *arg;
+    char *p, *q;
+    size_t cmdLineSize;
+    int numBackslashes;
+    int i;
+    int argNeedQuotes;
+
+    /*
+     * Find out how large the command line buffer should be.
+     */
+    cmdLineSize = 0;
+    for (arg = argv; *arg; arg++) {
+        /*
+         * \ and " need to be escaped by a \.  In the worst case,
+         * every character is a \ or ", so the string of length
+         * may double.  If we quote an argument, that needs two ".
+         * Finally, we need a space between arguments, and
+         * a null byte at the end of command line.
+         */
+        cmdLineSize += 2 * strlen(*arg)  /* \ and " need to be escaped */
+                + 2                      /* we quote every argument */
+                + 1;                     /* space in between, or final null */
+    }
+    p = *cmdLine = PR_MALLOC((PRUint32) cmdLineSize);
+    if (p == NULL) {
+        return -1;
+    }
+
+    for (arg = argv; *arg; arg++) {
+        /* Add a space to separates the arguments */
+        if (arg != argv) {
+            *p++ = ' '; 
+        }
+        q = *arg;
+        numBackslashes = 0;
+        argNeedQuotes = 0;
+
+        /*
+         * If the argument is empty or contains white space, it needs to
+         * be quoted.
+         */
+        if (**arg == '\0' || strpbrk(*arg, " \f\n\r\t\v")) {
+            argNeedQuotes = 1;
+        }
+
+        if (argNeedQuotes) {
+            *p++ = '"';
+        }
+        while (*q) {
+            if (*q == '\\') {
+                numBackslashes++;
+                q++;
+            } else if (*q == '"') {
+                if (numBackslashes) {
+                    /*
+                     * Double the backslashes since they are followed
+                     * by a quote
+                     */
+                    for (i = 0; i < 2 * numBackslashes; i++) {
+                        *p++ = '\\';
+                    }
+                    numBackslashes = 0;
+                }
+                /* To escape the quote */
+                *p++ = '\\';
+                *p++ = *q++;
+            } else {
+                if (numBackslashes) {
+                    /*
+                     * Backslashes are not followed by a quote, so
+                     * don't need to double the backslashes.
+                     */
+                    for (i = 0; i < numBackslashes; i++) {
+                        *p++ = '\\';
+                    }
+                    numBackslashes = 0;
+                }
+                *p++ = *q++;
+            }
+        }
+
+        /* Now we are at the end of this argument */
+        if (numBackslashes) {
+            /*
+             * Double the backslashes if we have a quote string
+             * delimiter at the end.
+             */
+            if (argNeedQuotes) {
+                numBackslashes *= 2;
+            }
+            for (i = 0; i < numBackslashes; i++) {
+                *p++ = '\\';
+            }
+        }
+        if (argNeedQuotes) {
+            *p++ = '"';
+        }
+    } 
+
+    *p = '\0';
+    return 0;
+}
+
+/*
+ * Assemble the environment block by concatenating the envp array
+ * (preserving the terminating null byte in each array element)
+ * and adding a null byte at the end.
+ *
+ * Returns 0 on success.  The resulting environment block is returned
+ * in *envBlock.  Note that if envp is NULL, a NULL pointer is returned
+ * in *envBlock.  Returns -1 on failure.
+ */
+static int assembleEnvBlock(char **envp, char **envBlock)
+{
+    char *p;
+    char *q;
+    char **env;
+    char *curEnv;
+    char *cwdStart, *cwdEnd;
+    size_t envBlockSize;
+
+    if (envp == NULL) {
+        *envBlock = NULL;
+        return 0;
+    }
+
+#ifdef WINCE
+    {
+        PRUnichar *wideCurEnv = mozce_GetEnvString();
+        int len = WideCharToMultiByte(CP_ACP, 0, wideCurEnv, -1,
+                                      NULL, 0, NULL, NULL);
+        curEnv = (char *) PR_MALLOC(len * sizeof(char));
+        WideCharToMultiByte(CP_ACP, 0, wideCurEnv, -1,
+                            curEnv, len, NULL, NULL);
+        free(wideCurEnv);
+    }
+#else
+    curEnv = GetEnvironmentStrings();
+#endif
+
+    cwdStart = curEnv;
+    while (*cwdStart) {
+        if (cwdStart[0] == '=' && cwdStart[1] != '\0'
+                && cwdStart[2] == ':' && cwdStart[3] == '=') {
+            break;
+        }
+        cwdStart += strlen(cwdStart) + 1;
+    }
+    cwdEnd = cwdStart;
+    if (*cwdEnd) {
+        cwdEnd += strlen(cwdEnd) + 1;
+        while (*cwdEnd) {
+            if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
+                    || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
+                break;
+            }
+            cwdEnd += strlen(cwdEnd) + 1;
+        }
+    }
+    envBlockSize = cwdEnd - cwdStart;
+
+    for (env = envp; *env; env++) {
+        envBlockSize += strlen(*env) + 1;
+    }
+    envBlockSize++;
+
+    p = *envBlock = PR_MALLOC((PRUint32) envBlockSize);
+    if (p == NULL) {
+#ifdef WINCE
+        PR_Free(curEnv);
+#else
+        FreeEnvironmentStrings(curEnv);
+#endif
+        return -1;
+    }
+
+    q = cwdStart;
+    while (q < cwdEnd) {
+        *p++ = *q++;
+    }
+#ifdef WINCE
+    PR_Free(curEnv);
+#else
+    FreeEnvironmentStrings(curEnv);
+#endif
+
+    for (env = envp; *env; env++) {
+        q = *env;
+        while (*q) {
+            *p++ = *q++;
+        }
+        *p++ = '\0';
+    }
+    *p = '\0';
+    return 0;
+}
+
+/*
+ * For qsort.  We sort (case-insensitive) the environment strings
+ * before generating the environment block.
+ */
+static int compare(const void *arg1, const void *arg2)
+{
+    return _stricmp(* (char**)arg1, * (char**)arg2);
+}
+
+PRProcess * _PR_CreateWindowsProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+#ifdef WINCE
+    STARTUPINFOW startupInfo;
+    PRUnichar *wideCmdLine;
+    PRUnichar *wideCwd;
+    int len = 0;
+#else
+    STARTUPINFO startupInfo;
+#endif
+    PROCESS_INFORMATION procInfo;
+    BOOL retVal;
+    char *cmdLine = NULL;
+    char *envBlock = NULL;
+    char **newEnvp = NULL;
+    const char *cwd = NULL; /* current working directory */
+    PRProcess *proc = NULL;
+    PRBool hasFdInheritBuffer;
+
+    proc = PR_NEW(PRProcess);
+    if (!proc) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        goto errorExit;
+    }
+
+    if (assembleCmdLine(argv, &cmdLine) == -1) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        goto errorExit;
+    }
+
+#ifndef WINCE
+    /*
+     * If attr->fdInheritBuffer is not NULL, we need to insert
+     * it into the envp array, so envp cannot be NULL.
+     */
+    hasFdInheritBuffer = (attr && attr->fdInheritBuffer);
+    if ((envp == NULL) && hasFdInheritBuffer) {
+        envp = environ;
+    }
+
+    if (envp != NULL) {
+        int idx;
+        int numEnv;
+        PRBool found = PR_FALSE;
+
+        numEnv = 0;
+        while (envp[numEnv]) {
+            numEnv++;
+        }
+        newEnvp = (char **) PR_MALLOC((numEnv + 2) * sizeof(char *));
+        for (idx = 0; idx < numEnv; idx++) {
+            newEnvp[idx] = envp[idx];
+            if (hasFdInheritBuffer && !found
+                    && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
+                newEnvp[idx] = attr->fdInheritBuffer;
+                found = PR_TRUE;
+            }
+        }
+        if (hasFdInheritBuffer && !found) {
+            newEnvp[idx++] = attr->fdInheritBuffer;
+        }
+        newEnvp[idx] = NULL;
+        qsort((void *) newEnvp, (size_t) idx, sizeof(char *), compare);
+    }
+    if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        goto errorExit;
+    }
+
+    ZeroMemory(&startupInfo, sizeof(startupInfo));
+    startupInfo.cb = sizeof(startupInfo);
+
+    if (attr) {
+        PRBool redirected = PR_FALSE;
+
+        /*
+         * XXX the default value for stdin, stdout, and stderr
+         * should probably be the console input and output, not
+         * those of the parent process.
+         */
+        startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+        startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+        startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+        if (attr->stdinFd) {
+            startupInfo.hStdInput = (HANDLE) attr->stdinFd->secret->md.osfd;
+            redirected = PR_TRUE;
+        }
+        if (attr->stdoutFd) {
+            startupInfo.hStdOutput = (HANDLE) attr->stdoutFd->secret->md.osfd;
+            redirected = PR_TRUE;
+        }
+        if (attr->stderrFd) {
+            startupInfo.hStdError = (HANDLE) attr->stderrFd->secret->md.osfd;
+            redirected = PR_TRUE;
+        }
+        if (redirected) {
+            startupInfo.dwFlags |= STARTF_USESTDHANDLES;
+        }
+        cwd = attr->currentDirectory;
+    }
+#endif
+
+#ifdef WINCE
+    len = MultiByteToWideChar(CP_ACP, 0, cmdLine, -1, NULL, 0);
+    wideCmdLine = (PRUnichar *)PR_MALLOC(len * sizeof(PRUnichar));
+    MultiByteToWideChar(CP_ACP, 0, cmdLine, -1, wideCmdLine, len);
+    len = MultiByteToWideChar(CP_ACP, 0, cwd, -1, NULL, 0);
+    wideCwd = PR_MALLOC(len * sizeof(PRUnichar));
+    MultiByteToWideChar(CP_ACP, 0, cwd, -1, wideCwd, len);
+    retVal = CreateProcessW(NULL,
+                            wideCmdLine,
+                            NULL,  /* security attributes for the new
+                                    * process */
+                            NULL,  /* security attributes for the primary
+                                    * thread in the new process */
+                            TRUE,  /* inherit handles */
+                            0,     /* creation flags */
+                            envBlock,  /* an environment block, consisting
+                                        * of a null-terminated block of
+                                        * null-terminated strings.  Each
+                                        * string is in the form:
+                                        *     name=value
+                                        * XXX: usually NULL */
+                            wideCwd,  /* current drive and directory */
+                            &startupInfo,
+                            &procInfo
+                           );
+    PR_Free(wideCmdLine);
+    PR_Free(wideCwd);
+#else
+    retVal = CreateProcess(NULL,
+                           cmdLine,
+                           NULL,  /* security attributes for the new
+                                   * process */
+                           NULL,  /* security attributes for the primary
+                                   * thread in the new process */
+                           TRUE,  /* inherit handles */
+                           0,     /* creation flags */
+                           envBlock,  /* an environment block, consisting
+                                       * of a null-terminated block of
+                                       * null-terminated strings.  Each
+                                       * string is in the form:
+                                       *     name=value
+                                       * XXX: usually NULL */
+                           cwd,  /* current drive and directory */
+                           &startupInfo,
+                           &procInfo
+                          );
+#endif
+
+    if (retVal == FALSE) {
+        /* XXX what error code? */
+        PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+        goto errorExit;
+    }
+
+    CloseHandle(procInfo.hThread);
+    proc->md.handle = procInfo.hProcess;
+    proc->md.id = procInfo.dwProcessId;
+
+    PR_DELETE(cmdLine);
+    if (newEnvp) {
+        PR_DELETE(newEnvp);
+    }
+    if (envBlock) {
+        PR_DELETE(envBlock);
+    }
+    return proc;
+
+errorExit:
+    if (cmdLine) {
+        PR_DELETE(cmdLine);
+    }
+    if (newEnvp) {
+        PR_DELETE(newEnvp);
+    }
+    if (envBlock) {
+        PR_DELETE(envBlock);
+    }
+    if (proc) {
+        PR_DELETE(proc);
+    }
+    return NULL;
+}  /* _PR_CreateWindowsProcess */
+
+PRStatus _PR_DetachWindowsProcess(PRProcess *process)
+{
+    CloseHandle(process->md.handle);
+    PR_DELETE(process);
+    return PR_SUCCESS;
+}
+
+/*
+ * XXX: This implementation is a temporary quick solution.
+ * It can be called by native threads only (not by fibers).
+ */
+PRStatus _PR_WaitWindowsProcess(PRProcess *process,
+    PRInt32 *exitCode)
+{
+    DWORD dwRetVal;
+
+    dwRetVal = WaitForSingleObject(process->md.handle, INFINITE);
+    if (dwRetVal == WAIT_FAILED) {
+        PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+        return PR_FAILURE;
+    }
+    PR_ASSERT(dwRetVal == WAIT_OBJECT_0);
+    if (exitCode != NULL &&
+            GetExitCodeProcess(process->md.handle, exitCode) == FALSE) {
+        PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+        return PR_FAILURE;
+    }
+    CloseHandle(process->md.handle);
+    PR_DELETE(process);
+    return PR_SUCCESS;
+}
+
+PRStatus _PR_KillWindowsProcess(PRProcess *process)
+{
+    /*
+     * On Unix, if a process terminates normally, its exit code is
+     * between 0 and 255.  So here on Windows, we use the exit code
+     * 256 to indicate that the process is killed.
+     */
+    if (TerminateProcess(process->md.handle, 256)) {
+	return PR_SUCCESS;
+    }
+    PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+    return PR_FAILURE;
+}
+
+PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen)
+{
+    PRIntn rv;
+    PRInt32 syserror;
+
+    rv = gethostname(name, (PRInt32) namelen);
+    if (0 == rv) {
+        return PR_SUCCESS;
+    }
+    syserror = WSAGetLastError();
+    PR_ASSERT(WSANOTINITIALISED != syserror);
+	_PR_MD_MAP_GETHOSTNAME_ERROR(syserror);
+    return PR_FAILURE;
+}
+
+PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen)
+{
+	OSVERSIONINFO osvi;
+
+	PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE));
+
+	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+	if (! GetVersionEx (&osvi) ) {
+		_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+    	return PR_FAILURE;
+	}
+
+	switch (osvi.dwPlatformId) {
+		case VER_PLATFORM_WIN32_NT:
+			if (PR_SI_SYSNAME == cmd)
+				(void)PR_snprintf(name, namelen, "Windows_NT");
+			else if (PR_SI_RELEASE == cmd)
+				(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, 
+            							osvi.dwMinorVersion);
+			break;
+		case VER_PLATFORM_WIN32_WINDOWS:
+			if (PR_SI_SYSNAME == cmd) {
+				if ((osvi.dwMajorVersion > 4) || 
+					((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0)))
+					(void)PR_snprintf(name, namelen, "Windows_98");
+				else
+					(void)PR_snprintf(name, namelen, "Windows_95");
+			} else if (PR_SI_RELEASE == cmd) {
+				(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, 
+            							osvi.dwMinorVersion);
+			}
+			break;
+#ifdef VER_PLATFORM_WIN32_CE
+    case VER_PLATFORM_WIN32_CE:
+			if (PR_SI_SYSNAME == cmd)
+				(void)PR_snprintf(name, namelen, "Windows_CE");
+			else if (PR_SI_RELEASE == cmd)
+				(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, 
+            							osvi.dwMinorVersion);
+			break;
+#endif
+   		default:
+			if (PR_SI_SYSNAME == cmd)
+				(void)PR_snprintf(name, namelen, "Windows_Unknown");
+			else if (PR_SI_RELEASE == cmd)
+				(void)PR_snprintf(name, namelen, "%d.%d",0,0);
+			break;
+	}
+	return PR_SUCCESS;
+}
+
+PRStatus _MD_WindowsGetReleaseName(char *name, PRUint32 namelen)
+{
+	OSVERSIONINFO osvi;
+
+	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+	if (! GetVersionEx (&osvi) ) {
+		_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+    	return PR_FAILURE;
+	}
+
+	switch (osvi.dwPlatformId) {
+		case VER_PLATFORM_WIN32_NT:
+		case VER_PLATFORM_WIN32_WINDOWS:
+			(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, 
+            							osvi.dwMinorVersion);
+			break;
+   		default:
+			(void)PR_snprintf(name, namelen, "%d.%d",0,0);
+			break;
+	}
+	return PR_SUCCESS;
+}
+
+/*
+ **********************************************************************
+ *
+ * Memory-mapped files
+ *
+ **********************************************************************
+ */
+
+PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
+{
+    DWORD dwHi, dwLo;
+    DWORD flProtect;
+    PROsfd osfd;
+
+    osfd = ( fmap->fd == (PRFileDesc*)-1 )?  -1 : fmap->fd->secret->md.osfd;
+
+    dwLo = (DWORD) (size & 0xffffffff);
+    dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff);
+
+    if (fmap->prot == PR_PROT_READONLY) {
+        flProtect = PAGE_READONLY;
+        fmap->md.dwAccess = FILE_MAP_READ;
+    } else if (fmap->prot == PR_PROT_READWRITE) {
+        flProtect = PAGE_READWRITE;
+        fmap->md.dwAccess = FILE_MAP_WRITE;
+    } else {
+        PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
+#ifdef WINCE
+        /* WINCE does not have FILE_MAP_COPY. */
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return PR_FAILURE;
+#else
+        flProtect = PAGE_WRITECOPY;
+        fmap->md.dwAccess = FILE_MAP_COPY;
+#endif
+    }
+
+    fmap->md.hFileMap = CreateFileMapping(
+        (HANDLE) osfd,
+        NULL,
+        flProtect,
+        dwHi,
+        dwLo,
+        NULL);
+
+    if (fmap->md.hFileMap == NULL) {
+        PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PRInt32 _MD_GetMemMapAlignment(void)
+{
+    SYSTEM_INFO info;
+    GetSystemInfo(&info);
+    return info.dwAllocationGranularity;
+}
+
+extern PRLogModuleInfo *_pr_shma_lm;
+
+void * _MD_MemMap(
+    PRFileMap *fmap,
+    PROffset64 offset,
+    PRUint32 len)
+{
+    DWORD dwHi, dwLo;
+    void *addr;
+
+    dwLo = (DWORD) (offset & 0xffffffff);
+    dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff);
+    if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess,
+            dwHi, dwLo, len)) == NULL) {
+        {
+            LPVOID lpMsgBuf; 
+            
+            FormatMessage( 
+                FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                NULL,
+                GetLastError(),
+                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                (LPTSTR) &lpMsgBuf,
+                0,
+                NULL 
+            );
+            PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf ));
+        }
+        PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+    }
+    return addr;
+}
+
+PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
+{
+    if (UnmapViewOfFile(addr)) {
+        return PR_SUCCESS;
+    } else {
+        PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
+        return PR_FAILURE;
+    }
+}
+
+PRStatus _MD_CloseFileMap(PRFileMap *fmap)
+{
+    CloseHandle(fmap->md.hFileMap);
+    PR_DELETE(fmap);
+    return PR_SUCCESS;
+}
+
+/*
+ ***********************************************************************
+ *
+ * Atomic increment and decrement operations for x86 processors
+ *
+ * We don't use InterlockedIncrement and InterlockedDecrement
+ * because on NT 3.51 and Win95, they return a number with
+ * the same sign as the incremented/decremented result, rather
+ * than the result itself.  On NT 4.0 these functions do return
+ * the incremented/decremented result.
+ *
+ * The result is returned in the eax register by the inline
+ * assembly code.  We disable the harmless "no return value"
+ * warning (4035) for these two functions.
+ *
+ ***********************************************************************
+ */
+
+#if defined(_M_IX86) || defined(_X86_)
+
+#pragma warning(disable: 4035)
+PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
+{    
+#if defined(__GNUC__)
+  PRInt32 result;
+  asm volatile ("lock ; xadd %0, %1" 
+                : "=r"(result), "=m"(*val)
+                : "0"(1), "m"(*val));
+  return result + 1;
+#else
+    __asm
+    {
+        mov ecx, val
+        mov eax, 1
+        lock xadd dword ptr [ecx], eax
+        inc eax
+    }
+#endif /* __GNUC__ */
+}
+#pragma warning(default: 4035)
+
+#pragma warning(disable: 4035)
+PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
+{
+#if defined(__GNUC__)
+  PRInt32 result;
+  asm volatile ("lock ; xadd %0, %1" 
+                : "=r"(result), "=m"(*val)
+                : "0"(-1), "m"(*val));
+  //asm volatile("lock ; xadd %0, %1" : "=m" (val), "=a" (result) : "-1" (1));
+  return result - 1;
+#else
+    __asm
+    {
+        mov ecx, val
+        mov eax, 0ffffffffh
+        lock xadd dword ptr [ecx], eax
+        dec eax
+    }
+#endif /* __GNUC__ */
+}
+#pragma warning(default: 4035)
+
+#pragma warning(disable: 4035)
+PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val)
+{
+#if defined(__GNUC__)
+  PRInt32 result;
+  //asm volatile("lock ; xadd %1, %0" : "=m" (intp), "=a" (result) : "1" (val));
+  asm volatile ("lock ; xadd %0, %1" 
+                : "=r"(result), "=m"(*intp)
+                : "0"(val), "m"(*intp));
+  return result + val;
+#else
+    __asm
+    {
+        mov ecx, intp
+        mov eax, val
+        mov edx, eax
+        lock xadd dword ptr [ecx], eax
+        add eax, edx
+    }
+#endif /* __GNUC__ */
+}
+#pragma warning(default: 4035)
+
+#ifdef _PR_HAVE_ATOMIC_CAS
+
+#pragma warning(disable: 4035)
+void 
+PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
+{
+#if defined(__GNUC__)
+  void **tos = (void **) stack;
+  void *tmp;
+  
+ retry:
+  if (*tos == (void *) -1)
+    goto retry;
+  
+  __asm__("xchg %0,%1"
+          : "=r" (tmp), "=m"(*tos)
+          : "0" (-1), "m"(*tos));
+  
+  if (tmp == (void *) -1)
+    goto retry;
+  
+  *(void **)stack_elem = tmp;
+  __asm__("" : : : "memory");
+  *tos = stack_elem;
+#else
+    __asm
+    {
+	mov ebx, stack
+	mov ecx, stack_elem
+retry:	mov eax,[ebx]
+	cmp eax,-1
+	je retry
+	mov eax,-1
+	xchg dword ptr [ebx], eax
+	cmp eax,-1
+	je  retry
+	mov [ecx],eax
+	mov [ebx],ecx
+    }
+#endif /* __GNUC__ */
+}
+#pragma warning(default: 4035)
+
+#pragma warning(disable: 4035)
+PRStackElem * 
+PR_StackPop(PRStack *stack)
+{
+#if defined(__GNUC__)
+  void **tos = (void **) stack;
+  void *tmp;
+  
+ retry:
+  if (*tos == (void *) -1)
+    goto retry;
+  
+  __asm__("xchg %0,%1"
+          : "=r" (tmp), "=m"(*tos)
+          : "0" (-1), "m"(*tos));
+
+  if (tmp == (void *) -1)
+    goto retry;
+  
+  if (tmp != (void *) 0)
+    {
+      void *next = *(void **)tmp;
+      *tos = next;
+      *(void **)tmp = 0;
+    }
+  else
+    *tos = tmp;
+  
+  return tmp;
+#else
+    __asm
+    {
+	mov ebx, stack
+retry:	mov eax,[ebx]
+	cmp eax,-1
+	je retry
+	mov eax,-1
+	xchg dword ptr [ebx], eax
+	cmp eax,-1
+	je  retry
+	cmp eax,0
+	je  empty
+	mov ecx,[eax]
+	mov [ebx],ecx
+	mov [eax],0
+	jmp done
+empty:
+	mov [ebx],eax
+done:	
+	}
+#endif /* __GNUC__ */
+}
+#pragma warning(default: 4035)
+
+#endif /* _PR_HAVE_ATOMIC_CAS */
+
+#endif /* x86 processors */
diff --git a/mozilla/nsprpub/pr/src/md/windows/ntsec.c b/mozilla/nsprpub/pr/src/md/windows/ntsec.c
new file mode 100644
index 0000000..1acb6c4
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/ntsec.c
@@ -0,0 +1,293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 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 "primpl.h"
+
+/*
+ * ntsec.c
+ *
+ * Implement the POSIX-style mode bits (access permissions) for
+ * files and other securable objects in Windows NT using Windows
+ * NT's security descriptors with appropriate discretionary
+ * access-control lists.
+ */
+
+/*
+ * The security identifiers (SIDs) for owner, primary group,
+ * and the Everyone (World) group.
+ *
+ * These SIDs are looked up during NSPR initialization and
+ * saved in this global structure (see _PR_NT_InitSids) so
+ * that _PR_NT_MakeSecurityDescriptorACL doesn't need to
+ * look them up every time.
+ */
+static struct {
+    PSID owner;
+    PSID group;
+    PSID everyone;
+} _pr_nt_sids;
+
+/*
+ * Initialize the SIDs for owner, primary group, and the Everyone
+ * group in the _pr_nt_sids structure.
+ *
+ * This function needs to be called by NSPR initialization.
+ */
+void _PR_NT_InitSids(void)
+{
+#ifdef WINCE /* not supported */
+    return;
+#else
+    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
+    HANDLE hToken = NULL; /* initialized to an arbitrary value to
+                           * silence a Purify UMR warning */
+    PSID infoBuffer[1024/sizeof(PSID)]; /* defined as an array of PSIDs
+                                         * to force proper alignment */
+    PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) infoBuffer;
+    PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup
+            = (PTOKEN_PRIMARY_GROUP) infoBuffer;
+    DWORD dwLength;
+    BOOL rv;
+
+    /*
+     * Look up and make a copy of the owner and primary group
+     * SIDs in the access token of the calling process.
+     */
+    rv = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
+    if (rv == 0) {
+        /*
+         * On non-NT systems, this function is not implemented
+         * (error code ERROR_CALL_NOT_IMPLEMENTED), and neither are
+         * the other security functions.  There is no point in
+         * going further.
+         *
+         * A process with insufficient access permissions may fail
+         * with the error code ERROR_ACCESS_DENIED.
+         */
+        PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
+                ("_PR_NT_InitSids: OpenProcessToken() failed. Error: %d",
+                GetLastError()));
+        return;
+    }
+
+    rv = GetTokenInformation(hToken, TokenOwner, infoBuffer,
+            sizeof(infoBuffer), &dwLength);
+    PR_ASSERT(rv != 0);
+    dwLength = GetLengthSid(pTokenOwner->Owner);
+    _pr_nt_sids.owner = (PSID) PR_Malloc(dwLength);
+    PR_ASSERT(_pr_nt_sids.owner != NULL);
+    rv = CopySid(dwLength, _pr_nt_sids.owner, pTokenOwner->Owner);
+    PR_ASSERT(rv != 0);
+
+    rv = GetTokenInformation(hToken, TokenPrimaryGroup, infoBuffer,
+            sizeof(infoBuffer), &dwLength);
+    PR_ASSERT(rv != 0);
+    dwLength = GetLengthSid(pTokenPrimaryGroup->PrimaryGroup);
+    _pr_nt_sids.group = (PSID) PR_Malloc(dwLength);
+    PR_ASSERT(_pr_nt_sids.group != NULL);
+    rv = CopySid(dwLength, _pr_nt_sids.group,
+            pTokenPrimaryGroup->PrimaryGroup);
+    PR_ASSERT(rv != 0);
+
+    rv = CloseHandle(hToken);
+    PR_ASSERT(rv != 0);
+
+    /* Create a well-known SID for the Everyone group. */
+    rv = AllocateAndInitializeSid(&SIDAuthWorld, 1,
+            SECURITY_WORLD_RID,
+            0, 0, 0, 0, 0, 0, 0,
+            &_pr_nt_sids.everyone);
+    PR_ASSERT(rv != 0);
+#endif
+}
+
+/*
+ * Free the SIDs for owner, primary group, and the Everyone group
+ * in the _pr_nt_sids structure.
+ *
+ * This function needs to be called by NSPR cleanup.
+ */
+void
+_PR_NT_FreeSids(void)
+{
+#ifdef WINCE
+    return;
+#else
+    if (_pr_nt_sids.owner) {
+        PR_Free(_pr_nt_sids.owner);
+    }
+    if (_pr_nt_sids.group) {
+        PR_Free(_pr_nt_sids.group);
+    }
+    if (_pr_nt_sids.everyone) {
+        FreeSid(_pr_nt_sids.everyone);
+    }
+#endif
+}
+
+/*
+ * Construct a security descriptor whose discretionary access-control
+ * list implements the specified mode bits.  The SIDs for owner, group,
+ * and everyone are obtained from the global _pr_nt_sids structure.
+ * Both the security descriptor and access-control list are returned
+ * and should be freed by a _PR_NT_FreeSecurityDescriptorACL call.
+ *
+ * The accessTable array maps NSPR's read, write, and execute access
+ * rights to the corresponding NT access rights for the securable
+ * object.
+ */
+PRStatus
+_PR_NT_MakeSecurityDescriptorACL(
+    PRIntn mode,
+    DWORD accessTable[],
+    PSECURITY_DESCRIPTOR *resultSD,
+    PACL *resultACL)
+{
+#ifdef WINCE
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+#else
+    PSECURITY_DESCRIPTOR pSD = NULL;
+    PACL pACL = NULL;
+    DWORD cbACL;  /* size of ACL */
+    DWORD accessMask;
+
+    if (_pr_nt_sids.owner == NULL) {
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    pSD = (PSECURITY_DESCRIPTOR) PR_Malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
+    if (pSD == NULL) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+    if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+    if (!SetSecurityDescriptorOwner(pSD, _pr_nt_sids.owner, FALSE)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+    if (!SetSecurityDescriptorGroup(pSD, _pr_nt_sids.group, FALSE)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+
+    /*
+     * Construct a discretionary access-control list with three
+     * access-control entries, one each for owner, primary group,
+     * and Everyone.
+     */
+
+    cbACL = sizeof(ACL)
+          + 3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))
+          + GetLengthSid(_pr_nt_sids.owner)
+          + GetLengthSid(_pr_nt_sids.group)
+          + GetLengthSid(_pr_nt_sids.everyone);
+    pACL = (PACL) PR_Malloc(cbACL);
+    if (pACL == NULL) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+    if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+    accessMask = 0;
+    if (mode & 00400) accessMask |= accessTable[0];
+    if (mode & 00200) accessMask |= accessTable[1];
+    if (mode & 00100) accessMask |= accessTable[2];
+    if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask,
+            _pr_nt_sids.owner)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+    accessMask = 0;
+    if (mode & 00040) accessMask |= accessTable[0];
+    if (mode & 00020) accessMask |= accessTable[1];
+    if (mode & 00010) accessMask |= accessTable[2];
+    if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask,
+            _pr_nt_sids.group)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+    accessMask = 0;
+    if (mode & 00004) accessMask |= accessTable[0];
+    if (mode & 00002) accessMask |= accessTable[1];
+    if (mode & 00001) accessMask |= accessTable[2];
+    if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask,
+            _pr_nt_sids.everyone)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+
+    if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        goto failed;
+    }
+
+    *resultSD = pSD;
+    *resultACL = pACL;
+    return PR_SUCCESS;
+
+failed:
+    if (pSD) {
+        PR_Free(pSD);
+    }
+    if (pACL) {
+        PR_Free(pACL);
+    }
+    return PR_FAILURE;
+#endif
+}
+
+/*
+ * Free the specified security descriptor and access-control list
+ * previously created by _PR_NT_MakeSecurityDescriptorACL.
+ */
+void
+_PR_NT_FreeSecurityDescriptorACL(PSECURITY_DESCRIPTOR pSD, PACL pACL)
+{
+    if (pSD) {
+        PR_Free(pSD);
+    }
+    if (pACL) {
+        PR_Free(pACL);
+    }
+}
diff --git a/mozilla/nsprpub/pr/src/md/windows/ntsem.c b/mozilla/nsprpub/pr/src/md/windows/ntsem.c
new file mode 100644
index 0000000..b25fac6
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/ntsem.c
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * NT-specific semaphore handling code.
+ *
+ */
+
+
+#include "primpl.h"
+
+
+void 
+_PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value)
+{
+    md->sem = CreateSemaphore(NULL, value, 0x7fffffff, NULL);
+}
+
+void 
+_PR_MD_DESTROY_SEM(_MDSemaphore *md)
+{
+    CloseHandle(md->sem);
+}
+
+PRStatus 
+_PR_MD_TIMED_WAIT_SEM(_MDSemaphore *md, PRIntervalTime ticks)
+{
+    int rv;
+
+    rv = WaitForSingleObject(md->sem, PR_IntervalToMilliseconds(ticks));
+
+    if (rv == WAIT_OBJECT_0)
+        return PR_SUCCESS;
+    else
+        return PR_FAILURE;
+}
+
+PRStatus 
+_PR_MD_WAIT_SEM(_MDSemaphore *md)
+{
+    return _PR_MD_TIMED_WAIT_SEM(md, PR_INTERVAL_NO_TIMEOUT);
+}
+
+void 
+_PR_MD_POST_SEM(_MDSemaphore *md)
+{
+    int old_count;
+
+    ReleaseSemaphore(md->sem, 1, &old_count);
+}
diff --git a/mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c b/mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c
new file mode 100644
index 0000000..443cd7f
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+/*
+ * File: w32ipcsem.c
+ * Description: implements named semaphores for NT and WIN95.
+ */
+
+#include "primpl.h"
+
+#ifdef WINCE
+static HANDLE OpenSemaphore(DWORD inDesiredAccess,
+                            BOOL inInheritHandle,
+                            const char *inName)
+{
+    HANDLE retval = NULL;
+    HANDLE semaphore = NULL;
+    PRUnichar wideName[MAX_PATH];  /* name size is limited to MAX_PATH */
+    
+    MultiByteToWideChar(CP_ACP, 0, inName, -1, wideName, MAX_PATH);
+    /* 0x7fffffff is the max count for our semaphore */
+    semaphore = CreateSemaphoreW(NULL, 0, 0x7fffffff, wideName);
+    if (NULL != semaphore) {
+        DWORD lastErr = GetLastError();
+      
+        if (ERROR_ALREADY_EXISTS != lastErr)
+            CloseHandle(semaphore);
+        else
+            retval = semaphore;
+    }
+    return retval;
+}
+#endif
+
+/*
+ * NSPR-to-NT access right mapping table for semaphore objects.
+ *
+ * The SYNCHRONIZE access is required by WaitForSingleObject.
+ * The SEMAPHORE_MODIFY_STATE access is required by ReleaseSemaphore.
+ * The OR of these three access masks must equal SEMAPHORE_ALL_ACCESS.
+ * This is because if a semaphore object with the specified name
+ * exists, CreateSemaphore requests SEMAPHORE_ALL_ACCESS access to
+ * the existing object.
+ */
+static DWORD semAccessTable[] = {
+    STANDARD_RIGHTS_REQUIRED|0x1, /* read (0x1 is "query state") */
+    STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, /* write */
+    0 /* execute */
+};
+
+#ifndef _PR_GLOBAL_THREADS_ONLY
+
+/*
+ * A fiber cannot call WaitForSingleObject because that
+ * will block the other fibers running on the same thread.
+ * If a fiber needs to wait on a (semaphore) handle, we
+ * create a native thread to call WaitForSingleObject and
+ * have the fiber join the native thread.
+ */
+
+/*
+ * Arguments, return value, and error code for WaitForSingleObject
+ */
+struct WaitSingleArg {
+    HANDLE handle;
+    DWORD timeout;
+    DWORD rv;
+    DWORD error;
+};
+
+static void WaitSingleThread(void *arg)
+{
+    struct WaitSingleArg *warg = (struct WaitSingleArg *) arg;
+
+    warg->rv = WaitForSingleObject(warg->handle, warg->timeout);
+    if (warg->rv == WAIT_FAILED) {
+        warg->error = GetLastError();
+    }
+}
+
+static DWORD FiberSafeWaitForSingleObject(
+    HANDLE hHandle,
+    DWORD dwMilliseconds
+)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (_PR_IS_NATIVE_THREAD(me)) {
+        return WaitForSingleObject(hHandle, dwMilliseconds);
+    } else {
+        PRThread *waitThread;
+        struct WaitSingleArg warg;
+        PRStatus rv;
+
+        warg.handle = hHandle;
+        warg.timeout = dwMilliseconds;
+        waitThread = PR_CreateThread(
+            PR_USER_THREAD, WaitSingleThread, &warg,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+        if (waitThread == NULL) {
+            return WAIT_FAILED;
+        }
+
+        rv = PR_JoinThread(waitThread);
+        PR_ASSERT(rv == PR_SUCCESS);
+        if (rv == PR_FAILURE) {
+            return WAIT_FAILED;
+        }
+        if (warg.rv == WAIT_FAILED) {
+            SetLastError(warg.error);
+        }
+        return warg.rv;
+    }
+}
+
+#endif /* !_PR_GLOBAL_THREADS_ONLY */
+
+PRSem *_PR_MD_OPEN_SEMAPHORE(
+    const char *osname, PRIntn flags, PRIntn mode, PRUintn value)
+{
+    PRSem *sem;
+    SECURITY_ATTRIBUTES sa;
+    LPSECURITY_ATTRIBUTES lpSA = NULL;
+    PSECURITY_DESCRIPTOR pSD = NULL;
+    PACL pACL = NULL;
+
+    sem = PR_NEW(PRSem);
+    if (sem == NULL) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+    if (flags & PR_SEM_CREATE) {
+        if (_PR_NT_MakeSecurityDescriptorACL(mode, semAccessTable,
+                &pSD, &pACL) == PR_SUCCESS) {
+            sa.nLength = sizeof(sa);
+            sa.lpSecurityDescriptor = pSD;
+            sa.bInheritHandle = FALSE;
+            lpSA = &sa;
+        }
+#ifdef WINCE
+        {
+            /* The size of a sem's name is limited to MAX_PATH. */
+            PRUnichar wosname[MAX_PATH]; 
+            MultiByteToWideChar(CP_ACP, 0, osname, -1, wosname, MAX_PATH);
+            sem->sem = CreateSemaphoreW(lpSA, value, 0x7fffffff, wosname);
+        }
+#else
+        sem->sem = CreateSemaphoreA(lpSA, value, 0x7fffffff, osname);
+#endif
+        if (lpSA != NULL) {
+            _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
+        }
+        if (sem->sem == NULL) {
+            _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+            PR_DELETE(sem);
+            return NULL;
+        }
+        if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) {
+            PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS);
+            CloseHandle(sem->sem);
+            PR_DELETE(sem);
+            return NULL;
+        }
+    } else {
+        sem->sem = OpenSemaphore(
+                SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, FALSE, osname);
+        if (sem->sem == NULL) {
+            DWORD err = GetLastError();
+
+            /*
+             * If we open a nonexistent named semaphore, NT
+             * returns ERROR_FILE_NOT_FOUND, while Win95
+             * returns ERROR_INVALID_NAME
+             */
+            if (err == ERROR_INVALID_NAME) {
+                PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+            } else {
+                _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+            }
+            PR_DELETE(sem);
+            return NULL;
+        }
+    }
+    return sem;
+}
+
+PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem)
+{
+    DWORD rv;
+
+#ifdef _PR_GLOBAL_THREADS_ONLY
+    rv = WaitForSingleObject(sem->sem, INFINITE);
+#else
+    rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE);
+#endif
+    PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0);
+    if (rv == WAIT_FAILED) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    if (rv != WAIT_OBJECT_0) {
+        /* Should not happen */
+        PR_SetError(PR_UNKNOWN_ERROR, 0);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem)
+{
+    if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem)
+{
+    if (CloseHandle(sem->sem) == FALSE) {
+        _PR_MD_MAP_CLOSE_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    PR_DELETE(sem);
+    return PR_SUCCESS;
+}
diff --git a/mozilla/nsprpub/pr/src/md/windows/w32poll.c b/mozilla/nsprpub/pr/src/md/windows/w32poll.c
new file mode 100644
index 0000000..2caaac2
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w32poll.c
@@ -0,0 +1,357 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * This file implements _PR_MD_PR_POLL for Win32.
+ */
+
+/* The default value of FD_SETSIZE is 64. */
+#define FD_SETSIZE 1024
+
+#include "primpl.h"
+
+#if !defined(_PR_GLOBAL_THREADS_ONLY)
+
+struct select_data_s {
+    PRInt32 status;
+    PRInt32 error;
+    fd_set *rd, *wt, *ex;
+    const struct timeval *tv;
+};
+
+static void
+_PR_MD_select_thread(void *cdata)
+{
+    struct select_data_s *cd = (struct select_data_s *)cdata;
+
+    cd->status = select(0, cd->rd, cd->wt, cd->ex, cd->tv);
+
+    if (cd->status == SOCKET_ERROR) {
+        cd->error = WSAGetLastError();
+    }
+}
+
+int _PR_NTFiberSafeSelect(
+    int nfds,
+    fd_set *readfds,
+    fd_set *writefds,
+    fd_set *exceptfds,
+    const struct timeval *timeout)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    int ready;
+
+    if (_PR_IS_NATIVE_THREAD(me)) {
+        ready = _MD_SELECT(nfds, readfds, writefds, exceptfds, timeout);
+    }
+    else
+    {
+        /*
+        ** Creating a new thread on each call!!
+        ** I guess web server doesn't use non-block I/O.
+        */
+        PRThread *selectThread;
+        struct select_data_s data;
+        data.status = 0;
+        data.error = 0;
+        data.rd = readfds;
+        data.wt = writefds;
+        data.ex = exceptfds;
+        data.tv = timeout;
+
+        selectThread = PR_CreateThread(
+            PR_USER_THREAD, _PR_MD_select_thread, &data,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+        if (selectThread == NULL) return -1;
+
+        PR_JoinThread(selectThread);
+        ready = data.status;
+        if (ready == SOCKET_ERROR) WSASetLastError(data.error);
+    }
+    return ready;
+}
+
+#endif /* !defined(_PR_GLOBAL_THREADS_ONLY) */
+
+PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+    int ready, err;
+    fd_set rd, wt, ex;
+    fd_set *rdp, *wtp, *exp;
+    int nrd, nwt, nex;
+    PRFileDesc *bottom;
+    PRPollDesc *pd, *epd;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    struct timeval tv, *tvp = NULL;
+
+    if (_PR_PENDING_INTERRUPT(me))
+    {
+        me->flags &= ~_PR_INTERRUPT;
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        return -1;
+    }
+
+    /*
+    ** Is it an empty set? If so, just sleep for the timeout and return
+    */
+    if (0 == npds)
+    {
+        PR_Sleep(timeout);
+        return 0;
+    }
+
+    nrd = nwt = nex = 0;
+    FD_ZERO(&rd);
+    FD_ZERO(&wt);
+    FD_ZERO(&ex);
+
+    ready = 0;
+    for (pd = pds, epd = pd + npds; pd < epd; pd++)
+    {
+        SOCKET osfd;
+        PRInt16 in_flags_read = 0, in_flags_write = 0;
+        PRInt16 out_flags_read = 0, out_flags_write = 0;
+
+        if ((NULL != pd->fd) && (0 != pd->in_flags))
+        {
+            if (pd->in_flags & PR_POLL_READ)
+            {
+                in_flags_read = (pd->fd->methods->poll)(
+                    pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_WRITE),
+                    &out_flags_read);
+            }
+            if (pd->in_flags & PR_POLL_WRITE)
+            {
+                in_flags_write = (pd->fd->methods->poll)(
+                    pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_READ),
+                    &out_flags_write);
+            }
+            if ((0 != (in_flags_read & out_flags_read))
+            || (0 != (in_flags_write & out_flags_write)))
+            {
+                /* this one's ready right now (buffered input) */
+                if (0 == ready)
+                {
+                    /*
+                     * We will have to return without calling the
+                     * system poll/select function.  So zero the
+                     * out_flags fields of all the poll descriptors
+                     * before this one.
+                     */
+                    PRPollDesc *prev;
+                    for (prev = pds; prev < pd; prev++)
+                    {
+                        prev->out_flags = 0;
+                    }
+                }
+                ready += 1;
+                pd->out_flags = out_flags_read | out_flags_write;
+            }
+            else
+            {
+                pd->out_flags = 0;  /* pre-condition */
+                /* make sure this is an NSPR supported stack */
+                bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottom);  /* what to do about that? */
+                if ((NULL != bottom)
+                && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                {
+                    if (0 == ready)
+                    {
+                        osfd = (SOCKET) bottom->secret->md.osfd;
+                        if (in_flags_read & PR_POLL_READ)
+                        {
+                            pd->out_flags |= _PR_POLL_READ_SYS_READ;
+                            FD_SET(osfd, &rd);
+                            nrd++;
+                        }
+                        if (in_flags_read & PR_POLL_WRITE)
+                        {
+                            pd->out_flags |= _PR_POLL_READ_SYS_WRITE;
+                            FD_SET(osfd, &wt);
+                            nwt++;
+                        }
+                        if (in_flags_write & PR_POLL_READ)
+                        {
+                            pd->out_flags |= _PR_POLL_WRITE_SYS_READ;
+                            FD_SET(osfd, &rd);
+                            nrd++;
+                        }
+                        if (in_flags_write & PR_POLL_WRITE)
+                        {
+                            pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE;
+                            FD_SET(osfd, &wt);
+                            nwt++;
+                        }
+                        if (pd->in_flags & PR_POLL_EXCEPT) {
+                            FD_SET(osfd, &ex);
+                            nex++;
+                        }
+                    }
+                }
+                else
+                {
+                    if (0 == ready)
+                    {
+                        PRPollDesc *prev;
+                        for (prev = pds; prev < pd; prev++)
+                        {
+                            prev->out_flags = 0;
+                        }
+                    }
+                    ready += 1;  /* this will cause an abrupt return */
+                    pd->out_flags = PR_POLL_NVAL;  /* bogii */
+                }
+            }
+        }
+        else
+        {
+            pd->out_flags = 0;
+        }
+    }
+
+    if (0 != ready) return ready;  /* no need to block */
+
+    /*
+     * FD_SET does nothing if the fd_set's internal fd_array is full.  If
+     * nrd, nwt, or nex is greater than FD_SETSIZE, we know FD_SET must
+     * have failed to insert an osfd into the corresponding fd_set, and
+     * therefore we should fail.
+     */
+    if ((nrd > FD_SETSIZE) || (nwt > FD_SETSIZE) || (nex > FD_SETSIZE)) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return -1;
+    }
+
+    rdp = (0 == nrd) ? NULL : &rd;
+    wtp = (0 == nwt) ? NULL : &wt;
+    exp = (0 == nex) ? NULL : &ex;
+
+    if ((NULL == rdp) && (NULL == wtp) && (NULL == exp)) {
+        PR_Sleep(timeout);
+        return 0;
+    }
+
+    if (timeout != PR_INTERVAL_NO_TIMEOUT)
+    {
+        PRInt32 ticksPerSecond = PR_TicksPerSecond();
+        tv.tv_sec = timeout / ticksPerSecond;
+        tv.tv_usec = PR_IntervalToMicroseconds( timeout % ticksPerSecond );
+        tvp = &tv;
+    }
+
+#if defined(_PR_GLOBAL_THREADS_ONLY)
+    ready = _MD_SELECT(0, rdp, wtp, exp, tvp);
+#else
+    ready = _PR_NTFiberSafeSelect(0, rdp, wtp, exp, tvp);
+#endif
+
+    /*
+    ** Now to unravel the select sets back into the client's poll
+    ** descriptor list. Is this possibly an area for pissing away
+    ** a few cycles or what?
+    */
+    if (ready > 0)
+    {
+        ready = 0;
+        for (pd = pds, epd = pd + npds; pd < epd; pd++)
+        {
+            PRInt16 out_flags = 0;
+            if ((NULL != pd->fd) && (0 != pd->in_flags))
+            {
+                SOCKET osfd;
+                bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottom);
+
+                osfd = (SOCKET) bottom->secret->md.osfd;
+
+                if (FD_ISSET(osfd, &rd))
+                {
+                    if (pd->out_flags & _PR_POLL_READ_SYS_READ)
+                        out_flags |= PR_POLL_READ;
+                    if (pd->out_flags & _PR_POLL_WRITE_SYS_READ)
+                        out_flags |= PR_POLL_WRITE;
+                } 
+                if (FD_ISSET(osfd, &wt))
+                {
+                    if (pd->out_flags & _PR_POLL_READ_SYS_WRITE)
+                        out_flags |= PR_POLL_READ;
+                    if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE)
+                        out_flags |= PR_POLL_WRITE;
+                } 
+                if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT;
+            }
+            pd->out_flags = out_flags;
+            if (out_flags) ready++;
+        }
+        PR_ASSERT(ready > 0);
+    }
+    else if (ready == SOCKET_ERROR)
+    {
+        err = WSAGetLastError();
+        if (err == WSAENOTSOCK)
+        {
+            /* Find the bad fds */
+            int optval;
+            int optlen = sizeof(optval);
+            ready = 0;
+            for (pd = pds, epd = pd + npds; pd < epd; pd++)
+            {
+                pd->out_flags = 0;
+                if ((NULL != pd->fd) && (0 != pd->in_flags))
+                {
+                    bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                    if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
+                        SO_TYPE, (char *) &optval, &optlen) == -1)
+                    {
+                        PR_ASSERT(WSAGetLastError() == WSAENOTSOCK);
+                        if (WSAGetLastError() == WSAENOTSOCK)
+                        {
+                            pd->out_flags = PR_POLL_NVAL;
+                            ready++;
+                        }
+                    }
+                }
+            }
+            PR_ASSERT(ready > 0);
+        }
+        else _PR_MD_MAP_SELECT_ERROR(err);
+    }
+
+    return ready;
+}
diff --git a/mozilla/nsprpub/pr/src/md/windows/w32rng.c b/mozilla/nsprpub/pr/src/md/windows/w32rng.c
new file mode 100644
index 0000000..5232b5f
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w32rng.c
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 <windows.h>
+#include <time.h>
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <primpl.h>
+
+static BOOL
+CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow)
+{
+    LARGE_INTEGER   liCount;
+
+    if (!QueryPerformanceCounter(&liCount))
+        return FALSE;
+
+    *lpdwHigh = liCount.u.HighPart;
+    *lpdwLow = liCount.u.LowPart;
+    return TRUE;
+}
+
+extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size )
+{
+    DWORD   dwHigh, dwLow, dwVal;
+    size_t  n = 0;
+    size_t  nBytes;
+    time_t  sTime;
+
+    if (size <= 0)
+        return 0;
+
+    CurrentClockTickTime(&dwHigh, &dwLow);
+
+    // get the maximally changing bits first
+    nBytes = sizeof(dwLow) > size ? size : sizeof(dwLow);
+    memcpy((char *)buf, &dwLow, nBytes);
+    n += nBytes;
+    size -= nBytes;
+
+    if (size <= 0)
+        return n;
+
+    nBytes = sizeof(dwHigh) > size ? size : sizeof(dwHigh);
+    memcpy(((char *)buf) + n, &dwHigh, nBytes);
+    n += nBytes;
+    size -= nBytes;
+
+    if (size <= 0)
+        return n;
+
+    // get the number of milliseconds that have elapsed since Windows started
+    dwVal = GetTickCount();
+
+    nBytes = sizeof(dwVal) > size ? size : sizeof(dwVal);
+    memcpy(((char *)buf) + n, &dwVal, nBytes);
+    n += nBytes;
+    size -= nBytes;
+
+    if (size <= 0)
+        return n;
+
+    // get the time in seconds since midnight Jan 1, 1970
+    time(&sTime);
+    nBytes = sizeof(sTime) > size ? size : sizeof(sTime);
+    memcpy(((char *)buf) + n, &sTime, nBytes);
+    n += nBytes;
+
+    return n;
+}
+
diff --git a/mozilla/nsprpub/pr/src/md/windows/w32shm.c b/mozilla/nsprpub/pr/src/md/windows/w32shm.c
new file mode 100644
index 0000000..e34a436
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w32shm.c
@@ -0,0 +1,379 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 <private/primpl.h>       
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+
+#if defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+/*
+ * NSPR-to-NT access right mapping table for file-mapping objects.
+ *
+ * The OR of these three access masks must equal FILE_MAP_ALL_ACCESS.
+ * This is because if a file-mapping object with the specified name
+ * exists, CreateFileMapping requests full access to the existing
+ * object.
+ */
+static DWORD filemapAccessTable[] = {
+    FILE_MAP_ALL_ACCESS & ~FILE_MAP_WRITE, /* read */
+    FILE_MAP_ALL_ACCESS & ~FILE_MAP_READ, /* write */ 
+    0  /* execute */
+};
+
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+        const char *name,
+        PRSize      size,
+        PRIntn      flags,
+        PRIntn      mode
+)
+{
+    char        ipcname[PR_IPC_NAME_SIZE];
+    PRStatus    rc = PR_SUCCESS;
+    DWORD dwHi, dwLo;
+    PRSharedMemory *shm;
+    DWORD flProtect = ( PAGE_READWRITE );
+    SECURITY_ATTRIBUTES sa;
+    LPSECURITY_ATTRIBUTES lpSA = NULL;
+    PSECURITY_DESCRIPTOR pSD = NULL;
+    PACL pACL = NULL;
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError(PR_UNKNOWN_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: name is invalid")); 
+        return(NULL);
+    }
+
+    shm = PR_NEWZAP( PRSharedMemory );
+    if ( NULL == shm ) 
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); 
+        return(NULL);
+    }
+
+    shm->ipcname = PR_MALLOC( (PRUint32) (strlen( ipcname ) + 1) );
+    if ( NULL == shm->ipcname )
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); 
+        PR_DELETE(shm);
+        return(NULL);
+    }
+
+    /* copy args to struct */
+    strcpy( shm->ipcname, ipcname );
+    shm->size = size; 
+    shm->mode = mode;
+    shm->flags = flags;
+    shm->ident = _PR_SHM_IDENT;
+
+    if (flags & PR_SHM_CREATE ) {
+        dwHi = (DWORD) (((PRUint64) shm->size >> 32) & 0xffffffff);
+        dwLo = (DWORD) (shm->size & 0xffffffff);
+
+        if (_PR_NT_MakeSecurityDescriptorACL(mode, filemapAccessTable,
+                &pSD, &pACL) == PR_SUCCESS) {
+            sa.nLength = sizeof(sa);
+            sa.lpSecurityDescriptor = pSD;
+            sa.bInheritHandle = FALSE;
+            lpSA = &sa;
+        }
+#ifdef WINCE
+        {
+            /*
+             * This is assuming that the name will never be larger than
+             * MAX_PATH.  Should we dynamically allocate?
+             */
+            PRUnichar wideIpcName[MAX_PATH];
+            MultiByteToWideChar(CP_ACP, 0, shm->ipcname, -1,
+                                wideIpcName, MAX_PATH);
+            shm->handle = CreateFileMappingW(
+                (HANDLE)-1 ,
+                lpSA,
+                flProtect,
+                dwHi,
+                dwLo,
+                wideIpcName);
+        }
+#else
+        shm->handle = CreateFileMappingA(
+            (HANDLE)-1 ,
+            lpSA,
+            flProtect,
+            dwHi,
+            dwLo,
+            shm->ipcname);
+#endif
+        if (lpSA != NULL) {
+            _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
+        }
+
+        if ( NULL == shm->handle ) {
+            PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                ( "PR_OpenSharedMemory: CreateFileMapping() failed: %s",
+                    shm->ipcname )); 
+            _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+            PR_FREEIF( shm->ipcname )
+            PR_DELETE( shm );
+            return(NULL);
+        } else {
+            if (( flags & PR_SHM_EXCL) && ( GetLastError() == ERROR_ALREADY_EXISTS ))  {
+                PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                    ( "PR_OpenSharedMemory: Request exclusive & already exists",
+                        shm->ipcname )); 
+                PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS );
+                CloseHandle( shm->handle );
+                PR_FREEIF( shm->ipcname )
+                PR_DELETE( shm );
+                return(NULL);
+            } else {
+                PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                    ( "PR_OpenSharedMemory: CreateFileMapping() success: %s, handle: %d",
+                        shm->ipcname, shm->handle ));
+                return(shm);
+            }
+        }
+    } else {
+#ifdef WINCE
+        PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+        shm->handle = NULL;  /* OpenFileMapping not supported */
+#else
+        shm->handle = OpenFileMapping( FILE_MAP_WRITE, TRUE, shm->ipcname );
+#endif
+        if ( NULL == shm->handle ) {
+            _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+            PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                ( "PR_OpenSharedMemory: OpenFileMapping() failed: %s, error: %d",
+                    shm->ipcname, PR_GetOSError())); 
+            PR_FREEIF( shm->ipcname );
+            PR_DELETE( shm );
+            return(NULL);
+        } else {
+            PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                ( "PR_OpenSharedMemory: OpenFileMapping() success: %s, handle: %d",
+                    shm->ipcname, shm->handle )); 
+                return(shm);
+        }
+    }
+    /* returns from separate paths */
+}
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    PRUint32    access = FILE_MAP_WRITE;
+    void        *addr;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    if ( PR_SHM_READONLY & flags )
+        access = FILE_MAP_READ;
+
+    addr = MapViewOfFile( shm->handle,
+        access,
+        0, 0,
+        shm->size );
+
+    if ( NULL == addr ) {
+        _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+        PR_LOG( _pr_shm_lm, PR_LOG_ERROR, 
+            ("_MD_AttachSharedMemory: MapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
+    }
+
+    return( addr );
+} /* end _MD_ATTACH_SHARED_MEMORY() */
+
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PRStatus rc = PR_SUCCESS;
+    BOOL        wrc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    wrc = UnmapViewOfFile( addr );
+    if ( FALSE == wrc ) 
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+        PR_LOG( _pr_shm_lm, PR_LOG_ERROR, 
+            ("_MD_DetachSharedMemory: UnmapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
+        rc = PR_FAILURE;
+    }
+
+    return( rc );
+}
+
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    PRStatus rc = PR_SUCCESS;
+    BOOL wrc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    wrc = CloseHandle( shm->handle );
+    if ( FALSE == wrc )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+        PR_LOG( _pr_shm_lm, PR_LOG_ERROR, 
+            ("_MD_CloseSharedMemory: CloseHandle() failed. OSerror: %d", PR_GetOSError()));
+        rc = PR_FAILURE;
+    }
+    PR_FREEIF( shm->ipcname );
+    PR_DELETE( shm );
+
+    return( rc );
+} /* end _MD_CLOSE_SHARED_MEMORY() */
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    return( PR_SUCCESS );
+}    
+
+
+/*
+** Windows implementation of anonymous memory (file) map
+*/
+extern PRLogModuleInfo *_pr_shma_lm;
+
+extern PRFileMap* _md_OpenAnonFileMap( 
+    const char *dirName,
+    PRSize      size,
+    PRFileMapProtect prot
+)
+{
+    PRFileMap   *fm;
+    HANDLE      hFileMap;
+
+    fm = PR_CreateFileMap( (PRFileDesc*)-1, size, prot );
+    if ( NULL == fm )  {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): PR_CreateFileMap(): failed"));
+        goto Finished;
+    }
+
+    /*
+    ** Make fm->md.hFileMap inheritable. We can't use
+    ** GetHandleInformation and SetHandleInformation
+    ** because these two functions fail with
+    ** ERROR_CALL_NOT_IMPLEMENTED on Win95.
+    */
+    if (DuplicateHandle(GetCurrentProcess(), fm->md.hFileMap,
+            GetCurrentProcess(), &hFileMap,
+            0, TRUE /* inheritable */,
+            DUPLICATE_SAME_ACCESS) == FALSE) {
+        PR_SetError( PR_UNKNOWN_ERROR, GetLastError() );
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): DuplicateHandle(): failed"));
+        PR_CloseFileMap( fm );
+        fm = NULL;
+        goto Finished;
+    }
+    CloseHandle(fm->md.hFileMap);
+    fm->md.hFileMap = hFileMap;
+
+Finished:    
+    return(fm);
+} /* end md_OpenAnonFileMap() */
+
+/*
+** _md_ExportFileMapAsString()
+**
+*/
+extern PRStatus _md_ExportFileMapAsString(
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+)
+{
+    PRIntn  written;
+
+    written = PR_snprintf( buf, (PRUint32) bufSize, "%d:%" PR_PRIdOSFD ":%ld",
+        (PRIntn)fm->prot, (PROsfd)fm->md.hFileMap, (PRInt32)fm->md.dwAccess );
+
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_ExportFileMapAsString(): prot: %x, hFileMap: %x, dwAccess: %x",
+            fm->prot, fm->md.hFileMap, fm->md.dwAccess ));
+        
+    return((written == -1)? PR_FAILURE : PR_SUCCESS);
+} /* end _md_ExportFileMapAsString() */
+
+
+/*
+** _md_ImportFileMapFromString()
+**
+*/
+extern PRFileMap * _md_ImportFileMapFromString(
+    const char *fmstring
+)
+{
+    PRIntn  prot;
+    PROsfd hFileMap;
+    PRInt32 dwAccess;
+    PRFileMap *fm = NULL;
+
+    PR_sscanf( fmstring, "%d:%" PR_SCNdOSFD ":%ld",
+        &prot, &hFileMap, &dwAccess );
+
+    fm = PR_NEWZAP(PRFileMap);
+    if ( NULL == fm ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_NEWZAP(): Failed"));
+        return(fm);
+    }
+
+    fm->prot = (PRFileMapProtect)prot;
+    fm->md.hFileMap = (HANDLE)hFileMap;
+    fm->md.dwAccess = (DWORD)dwAccess;
+    fm->fd = (PRFileDesc*)-1;
+
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_ImportFileMapFromString(): fm: %p, prot: %d, hFileMap: %8.8x, dwAccess: %8.8x, fd: %x",
+            fm, prot, fm->md.hFileMap, fm->md.dwAccess, fm->fd));
+    return(fm);
+} /* end _md_ImportFileMapFromString() */
+
+#else
+Error! Why is PR_HAVE_WIN32_NAMED_SHARED_MEMORY not defined? 
+#endif /* PR_HAVE_WIN32_NAMED_SHARED_MEMORY */
+/* --- end w32shm.c --- */
diff --git a/mozilla/nsprpub/pr/src/md/windows/w95cv.c b/mozilla/nsprpub/pr/src/md/windows/w95cv.c
new file mode 100644
index 0000000..975ac4b
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w95cv.c
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ *  w95cv.c -- Windows 95 Machine-Dependent Code for Condition Variables
+ *
+ *  We implement our own condition variable wait queue.  Each thread
+ *  has a semaphore object (thread->md.blocked_sema) to block on while
+ *  waiting on a condition variable.
+ *
+ *  We use a deferred condition notify algorithm.  When PR_NotifyCondVar
+ *  or PR_NotifyAllCondVar is called, the condition notifies are simply
+ *  recorded in the _MDLock structure.  We defer the condition notifies
+ *  until right after we unlock the lock.  This way the awakened threads
+ *  have a better chance to reaquire the lock.
+ */
+ 
+#include "primpl.h"
+
+/*
+ * AddThreadToCVWaitQueueInternal --
+ *
+ * Add the thread to the end of the condition variable's wait queue.
+ * The CV's lock must be locked when this function is called.
+ */
+
+static void
+AddThreadToCVWaitQueueInternal(PRThread *thred, struct _MDCVar *cv)
+{
+    PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL)
+            || (cv->waitTail == NULL && cv->waitHead == NULL));
+    cv->nwait += 1;
+    thred->md.inCVWaitQueue = PR_TRUE;
+    thred->md.next = NULL;
+    thred->md.prev = cv->waitTail;
+    if (cv->waitHead == NULL) {
+        cv->waitHead = thred;
+    } else {
+        cv->waitTail->md.next = thred;
+    }
+    cv->waitTail = thred;
+}
+
+/*
+ * md_UnlockAndPostNotifies --
+ *
+ * Unlock the lock, and then do the deferred condition notifies.
+ * If waitThred and waitCV are not NULL, waitThred is added to
+ * the wait queue of waitCV before the lock is unlocked.
+ *
+ * This function is called by _PR_MD_WAIT_CV and _PR_MD_UNLOCK,
+ * the two places where a lock is unlocked.
+ */
+static void
+md_UnlockAndPostNotifies(
+    _MDLock *lock,
+    PRThread *waitThred,
+    _MDCVar *waitCV)
+{
+    PRIntn index;
+    _MDNotified post;
+    _MDNotified *notified, *prev = NULL;
+
+    /*
+     * Time to actually notify any conditions that were affected
+     * while the lock was held.  Get a copy of the list that's in
+     * the lock structure and then zero the original.  If it's
+     * linked to other such structures, we own that storage.
+     */
+    post = lock->notified;  /* a safe copy; we own the lock */
+
+#if defined(DEBUG)
+    ZeroMemory(&lock->notified, sizeof(_MDNotified));  /* reset */
+#else
+    lock->notified.length = 0;  /* these are really sufficient */
+    lock->notified.link = NULL;
+#endif
+
+    /* 
+     * Figure out how many threads we need to wake up.
+     */
+    notified = &post;  /* this is where we start */
+    do {
+        for (index = 0; index < notified->length; ++index) {
+            _MDCVar *cv = notified->cv[index].cv;
+            PRThread *thred;
+            int i;
+            
+            /* Fast special case: no waiting threads */
+            if (cv->waitHead == NULL) {
+                notified->cv[index].notifyHead = NULL;
+                continue;
+            }
+
+            /* General case */
+            if (-1 == notified->cv[index].times) {
+                /* broadcast */
+                thred = cv->waitHead;
+                while (thred != NULL) {
+                    thred->md.inCVWaitQueue = PR_FALSE;
+                    thred = thred->md.next;
+                }
+                notified->cv[index].notifyHead = cv->waitHead;
+                cv->waitHead = cv->waitTail = NULL;
+                cv->nwait = 0;
+            } else {
+                thred = cv->waitHead;
+                i = notified->cv[index].times;
+                while (thred != NULL && i > 0) {
+                    thred->md.inCVWaitQueue = PR_FALSE;
+                    thred = thred->md.next;
+                    i--;
+                }
+                notified->cv[index].notifyHead = cv->waitHead;
+                cv->waitHead = thred;
+                if (cv->waitHead == NULL) {
+                    cv->waitTail = NULL;
+                } else {
+                    if (cv->waitHead->md.prev != NULL) {
+                        cv->waitHead->md.prev->md.next = NULL;
+                        cv->waitHead->md.prev = NULL;
+                    }
+                }
+                cv->nwait -= notified->cv[index].times - i;
+            }
+        }
+        notified = notified->link;
+    } while (NULL != notified);
+
+    if (waitThred) {
+        AddThreadToCVWaitQueueInternal(waitThred, waitCV);
+    }
+
+    /* Release the lock before notifying */
+        LeaveCriticalSection(&lock->mutex);
+
+    notified = &post;  /* this is where we start */
+    do {
+        for (index = 0; index < notified->length; ++index) {
+            PRThread *thred;
+            PRThread *next;
+
+            thred = notified->cv[index].notifyHead;
+            while (thred != NULL) {
+                BOOL rv;
+
+                next = thred->md.next;
+                thred->md.prev = thred->md.next = NULL;
+
+                rv = ReleaseSemaphore(thred->md.blocked_sema, 1, NULL);
+                PR_ASSERT(rv != 0);
+                thred = next;
+            }
+        }
+        prev = notified;
+        notified = notified->link;
+        if (&post != prev) PR_DELETE(prev);
+    } while (NULL != notified);
+}
+
+/*
+ * Notifies just get posted to the protecting mutex.  The
+ * actual notification is done when the lock is released so that
+ * MP systems don't contend for a lock that they can't have.
+ */
+static void md_PostNotifyToCvar(_MDCVar *cvar, _MDLock *lock,
+        PRBool broadcast)
+{
+    PRIntn index = 0;
+    _MDNotified *notified = &lock->notified;
+
+    while (1) {
+        for (index = 0; index < notified->length; ++index) {
+            if (notified->cv[index].cv == cvar) {
+                if (broadcast) {
+                    notified->cv[index].times = -1;
+                } else if (-1 != notified->cv[index].times) {
+                    notified->cv[index].times += 1;
+                }
+                return;
+            }
+        }
+        /* if not full, enter new CV in this array */
+        if (notified->length < _MD_CV_NOTIFIED_LENGTH) break;
+
+        /* if there's no link, create an empty array and link it */
+        if (NULL == notified->link) {
+            notified->link = PR_NEWZAP(_MDNotified);
+        }
+
+        notified = notified->link;
+    }
+
+    /* A brand new entry in the array */
+    notified->cv[index].times = (broadcast) ? -1 : 1;
+    notified->cv[index].cv = cvar;
+    notified->length += 1;
+}
+
+/*
+ * _PR_MD_NEW_CV() -- Creating new condition variable
+ * ... Solaris uses cond_init() in similar function.
+ *
+ * returns: -1 on failure
+ *          0 when it succeeds.
+ *
+ */
+PRInt32 
+_PR_MD_NEW_CV(_MDCVar *cv)
+{
+    cv->magic = _MD_MAGIC_CV;
+    /*
+     * The waitHead, waitTail, and nwait fields are zeroed
+     * when the PRCondVar structure is created.
+     */
+    return 0;
+} 
+
+void _PR_MD_FREE_CV(_MDCVar *cv)
+{
+    cv->magic = (PRUint32)-1;
+    return;
+}
+
+/*
+ *  _PR_MD_WAIT_CV() -- Wait on condition variable
+ */
+void _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout )
+{
+    PRThread *thred = _PR_MD_CURRENT_THREAD();
+    DWORD rv;
+    DWORD msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ?
+            INFINITE : PR_IntervalToMilliseconds(timeout);
+
+    /*
+     * If we have pending notifies, post them now.
+     */
+    if (0 != lock->notified.length) {
+        md_UnlockAndPostNotifies(lock, thred, cv);
+    } else {
+        AddThreadToCVWaitQueueInternal(thred, cv);
+        LeaveCriticalSection(&lock->mutex);
+    }
+
+    /* Wait for notification or timeout; don't really care which */
+    rv = WaitForSingleObject(thred->md.blocked_sema, msecs);
+
+    EnterCriticalSection(&(lock->mutex));
+
+    PR_ASSERT(rv != WAIT_ABANDONED);
+    PR_ASSERT(rv != WAIT_FAILED);
+    PR_ASSERT(rv != WAIT_OBJECT_0 || thred->md.inCVWaitQueue == PR_FALSE);
+
+    if (rv == WAIT_TIMEOUT) {
+        if (thred->md.inCVWaitQueue) {
+            PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL)
+                    || (cv->waitTail == NULL && cv->waitHead == NULL));
+            cv->nwait -= 1;
+            thred->md.inCVWaitQueue = PR_FALSE;
+            if (cv->waitHead == thred) {
+                cv->waitHead = thred->md.next;
+                if (cv->waitHead == NULL) {
+                    cv->waitTail = NULL;
+                } else {
+                    cv->waitHead->md.prev = NULL;
+                }
+            } else {
+                PR_ASSERT(thred->md.prev != NULL);
+                thred->md.prev->md.next = thred->md.next;
+                if (thred->md.next != NULL) {
+                    thred->md.next->md.prev = thred->md.prev;
+                } else {
+                    PR_ASSERT(cv->waitTail == thred);
+                    cv->waitTail = thred->md.prev;
+                }
+            }
+            thred->md.next = thred->md.prev = NULL;
+        } else {
+            /*
+             * This thread must have been notified, but the
+             * ReleaseSemaphore call happens after WaitForSingleObject
+             * times out.  Wait on the semaphore again to make it
+             * non-signaled.  We assume this wait won't take long.
+             */
+            rv = WaitForSingleObject(thred->md.blocked_sema, INFINITE);
+            PR_ASSERT(rv == WAIT_OBJECT_0);
+        }
+    }
+    PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE);
+    return;
+} /* --- end _PR_MD_WAIT_CV() --- */
+
+void _PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock)
+{
+    md_PostNotifyToCvar(cv, lock, PR_FALSE);
+    return;
+}
+
+void _PR_MD_NOTIFYALL_CV(_MDCVar *cv, _MDLock *lock)
+{
+    md_PostNotifyToCvar(cv, lock, PR_TRUE);
+    return;
+}
+
+void _PR_MD_UNLOCK(_MDLock *lock)
+{
+    if (0 != lock->notified.length) {
+        md_UnlockAndPostNotifies(lock, NULL, NULL);
+    } else {
+        LeaveCriticalSection(&lock->mutex);
+    }
+    return;
+}
diff --git a/mozilla/nsprpub/pr/src/md/windows/w95dllmain.c b/mozilla/nsprpub/pr/src/md/windows/w95dllmain.c
new file mode 100644
index 0000000..a5a1da9
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w95dllmain.c
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#if 0  /* STATIC LIBRARIES.  See the end of w95thred.c. */
+
+/*
+ * The DLL entry point (DllMain) for NSPR.
+ *
+ * This is used to detach threads that were automatically attached by
+ * nspr.
+ */
+
+#include <windows.h>
+#include <primpl.h>
+
+BOOL WINAPI DllMain(
+    HINSTANCE hinstDLL,
+    DWORD fdwReason,
+    LPVOID lpvReserved)
+{
+PRThread *me;
+
+    switch (fdwReason) {
+        case DLL_PROCESS_ATTACH:
+            break;
+        case DLL_THREAD_ATTACH:
+            break;
+        case DLL_THREAD_DETACH:
+            if (_pr_initialized) {
+                me = _MD_GET_ATTACHED_THREAD();
+                if ((me != NULL) && (me->flags & _PR_ATTACHED))
+                    _PRI_DetachThread();
+            }
+            break;
+        case DLL_PROCESS_DETACH:
+            break;
+    }
+    return TRUE;
+}
+
+#endif
diff --git a/mozilla/nsprpub/pr/src/md/windows/w95io.c b/mozilla/nsprpub/pr/src/md/windows/w95io.c
new file mode 100644
index 0000000..f9b2cc4
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w95io.c
@@ -0,0 +1,1786 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * 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 ***** */
+
+/* Windows 95 IO module
+ *
+ * Assumes synchronous I/O.
+ *
+ */
+
+#include "primpl.h"
+#include <direct.h>
+#include <mbstring.h>
+#ifdef MOZ_UNICODE
+#include <wchar.h>
+#endif /* MOZ_UNICODE */
+
+#ifdef WINCE
+
+static HANDLE CreateFileA(LPCSTR lpFileName,
+                          DWORD dwDesiredAccess,
+                          DWORD dwShareMode,
+                          LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+                          DWORD dwCreationDisposition,
+                          DWORD dwFlagsAndAttributes,
+                          HANDLE hTemplateFile)
+{
+    PRUnichar wFileName[MAX_PATH];
+    MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
+    return CreateFileW(wFileName, dwDesiredAccess, dwShareMode,
+                       lpSecurityAttributes, dwCreationDisposition,
+                       dwFlagsAndAttributes, hTemplateFile);
+}
+
+/*
+ * We seem to call FindFirstFileA and FindNextFileA just to get
+ * the file names in a directory listing.  If so, we could define
+ * a custom WIN32_FIND_DATAA structure with just the cFileName
+ * member, and the CopyFindFileDataW2A function could just
+ * copy/convert the cFileName member.
+ */
+static void CopyFindFileDataW2A(LPWIN32_FIND_DATAW from,
+                                LPWIN32_FIND_DATAA to)
+{
+    /*
+     * WIN32_FIND_DATAA and WIN32_FIND_DATAW are slightly different.
+     * The dwReserved0, dwReserved1, and cAlternateFileName members
+     * exist only in WIN32_FIND_DATAA.  The dwOID member exists only
+     * in WIN32_FIND_DATAW.
+     */
+    to->dwFileAttributes = from->dwFileAttributes;
+    to->ftCreationTime = from->ftCreationTime;
+    to->ftLastAccessTime = from->ftLastAccessTime;
+    to->ftLastWriteTime = from->ftLastWriteTime;
+    to->nFileSizeHigh = from->nFileSizeHigh;
+    to->nFileSizeLow = from->nFileSizeLow;
+    to->dwReserved0 = 0;
+    to->dwReserved1 = 0;
+    WideCharToMultiByte(CP_ACP, 0, from->cFileName, -1,
+                        to->cFileName, MAX_PATH, NULL, NULL);
+    to->cAlternateFileName[0] = '\0';
+}
+
+static HANDLE FindFirstFileA(LPCSTR lpFileName,
+                             LPWIN32_FIND_DATAA lpFindFileData)
+{
+    PRUnichar wFileName[MAX_PATH];
+    HANDLE hFindFile;
+    WIN32_FIND_DATAW wFindFileData;
+    
+    MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
+    hFindFile = FindFirstFileW(wFileName, &wFindFileData);
+    if (hFindFile != INVALID_HANDLE_VALUE) {
+        CopyFindFileDataW2A(&wFindFileData, lpFindFileData);
+    }
+    return hFindFile;
+}
+
+static BOOL FindNextFileA(HANDLE hFindFile,
+                          LPWIN32_FIND_DATAA lpFindFileData)
+{
+    WIN32_FIND_DATAW wFindFileData;
+    BOOL rv;
+
+    rv = FindNextFileW(hFindFile, &wFindFileData);
+    if (rv) {
+        CopyFindFileDataW2A(&wFindFileData, lpFindFileData);
+    }
+    return rv;
+}
+
+static BOOL GetFileAttributesExA(LPCSTR lpFileName,
+                                 GET_FILEEX_INFO_LEVELS fInfoLevelId,
+                                 LPVOID lpFileInformation)
+{
+    PRUnichar wFileName[MAX_PATH];
+    MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
+    return GetFileAttributesExW(wFileName, fInfoLevelId, lpFileInformation);
+}
+
+static BOOL DeleteFileA(LPCSTR lpFileName)
+{
+    PRUnichar wFileName[MAX_PATH];
+    MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
+    return DeleteFileW(wFileName);
+}
+
+static BOOL MoveFileA(LPCSTR from, LPCSTR to)
+{
+    PRUnichar wFrom[MAX_PATH];
+    PRUnichar wTo[MAX_PATH];
+    MultiByteToWideChar(CP_ACP, 0, from, -1, wFrom, MAX_PATH);
+    MultiByteToWideChar(CP_ACP, 0, to, -1, wTo, MAX_PATH);
+    return MoveFileW(wFrom, wTo);
+}
+
+static BOOL CreateDirectoryA(LPCSTR lpPathName,
+                             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+{
+    PRUnichar wPathName[MAX_PATH];
+    MultiByteToWideChar(CP_ACP, 0, lpPathName, -1, wPathName, MAX_PATH);
+    return CreateDirectoryW(wPathName, lpSecurityAttributes);
+}
+
+static BOOL RemoveDirectoryA(LPCSTR lpPathName)
+{
+    PRUnichar wPathName[MAX_PATH];
+    MultiByteToWideChar(CP_ACP, 0, lpPathName, -1, wPathName, MAX_PATH);
+    return RemoveDirectoryW(wPathName);
+}
+
+static long GetDriveType(const char *lpRootPathName)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return 0; // The drive type cannot be determined.
+}
+
+static DWORD GetFullPathName(const char *lpFileName,
+                             DWORD nBufferLength,
+                             const char *lpBuffer,
+                             const char **lpFilePart)
+{
+    // needs work dft
+    DWORD len = strlen(lpFileName);
+    if (len > nBufferLength)
+        return len;
+  
+    strncpy((char *)lpBuffer, lpFileName, len);
+    ((char *)lpBuffer)[len] = '\0';
+  
+    if (lpFilePart) {
+        char *sep = strrchr(lpBuffer, '\\');
+        if (sep) {
+            sep++; // pass the seperator
+            *lpFilePart = sep;
+        } else {
+            *lpFilePart = lpBuffer;
+        }
+    }
+    return len;
+}
+
+static BOOL LockFile(HANDLE hFile,
+                     DWORD dwFileOffsetLow,
+                     DWORD dwFileOffsetHigh,
+                     DWORD nNumberOfBytesToLockLow,
+                     DWORD nNumberOfBytesToLockHigh)
+{
+    OVERLAPPED overlapped = {0};
+    overlapped.Offset = dwFileOffsetLow;
+    overlapped.OffsetHigh = dwFileOffsetHigh;
+    return LockFileEx(hFile,
+                      LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
+                      0, // reserved
+                      nNumberOfBytesToLockLow,
+                      nNumberOfBytesToLockHigh, &overlapped);
+}
+
+static BOOL UnlockFile(HANDLE hFile,
+                       DWORD dwFileOffsetLow,
+                       DWORD dwFileOffsetHigh,
+                       DWORD nNumberOfBytesToUnlockLow,
+                       DWORD nNumberOfBytesToUnlockHigh)
+{
+    OVERLAPPED overlapped = {0};
+    overlapped.Offset = dwFileOffsetLow;
+    overlapped.OffsetHigh = dwFileOffsetHigh;
+    return UnlockFileEx(hFile,
+                        0, // reserved
+                        nNumberOfBytesToUnlockLow,
+                        nNumberOfBytesToUnlockHigh, &overlapped);
+}
+
+static unsigned char *_mbsdec(const unsigned char *string1,
+                              const unsigned char *string2)
+{
+    // needs work dft
+    return NULL;
+}
+
+static unsigned char *_mbsinc(const unsigned char *inCurrent)
+{
+    // needs work dft
+    return (unsigned char *)(inCurrent + 1);
+}
+
+#endif
+
+struct _MDLock               _pr_ioq_lock;
+
+/*
+ * NSPR-to-NT access right mapping table for files.
+ */
+static DWORD fileAccessTable[] = {
+    FILE_GENERIC_READ,
+    FILE_GENERIC_WRITE,
+    FILE_GENERIC_EXECUTE
+};
+
+/*
+ * NSPR-to-NT access right mapping table for directories.
+ */
+static DWORD dirAccessTable[] = {
+    FILE_GENERIC_READ,
+    FILE_GENERIC_WRITE|FILE_DELETE_CHILD,
+    FILE_GENERIC_EXECUTE
+};
+
+/* Windows CE has GetFileAttributesEx. */
+#ifndef WINCE
+typedef BOOL (WINAPI *GetFileAttributesExFn)(LPCTSTR,
+                                             GET_FILEEX_INFO_LEVELS,
+                                             LPVOID); 
+static GetFileAttributesExFn getFileAttributesEx;
+static void InitGetFileInfo(void);
+#endif
+
+static void InitUnicodeSupport(void);
+
+static PRBool IsPrevCharSlash(const char *str, const char *current);
+
+void
+_PR_MD_INIT_IO()
+{
+    WORD WSAVersion = 0x0101;
+    WSADATA WSAData;
+    int err;
+
+    err = WSAStartup( WSAVersion, &WSAData );
+    PR_ASSERT(0 == err);
+
+#ifdef DEBUG
+    /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */
+    {
+        SYSTEMTIME systime;
+        union {
+           PRTime prt;
+           FILETIME ft;
+        } filetime;
+        BOOL rv;
+
+        systime.wYear = 1970;
+        systime.wMonth = 1;
+        /* wDayOfWeek is ignored */
+        systime.wDay = 1;
+        systime.wHour = 0;
+        systime.wMinute = 0;
+        systime.wSecond = 0;
+        systime.wMilliseconds = 0;
+
+        rv = SystemTimeToFileTime(&systime, &filetime.ft);
+        PR_ASSERT(0 != rv);
+        PR_ASSERT(filetime.prt == _pr_filetime_offset);
+    }
+#endif /* DEBUG */
+
+    _PR_NT_InitSids();
+
+#ifndef WINCE
+    InitGetFileInfo();
+#endif
+
+    InitUnicodeSupport();
+
+    _PR_MD_InitSockets();
+}
+
+PRStatus
+_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
+{
+    DWORD rv;
+
+    PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+        INFINITE : PR_IntervalToMilliseconds(ticks);
+    rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
+    switch(rv) 
+    {
+        case WAIT_OBJECT_0:
+            return PR_SUCCESS;
+            break;
+        case WAIT_TIMEOUT:
+            _PR_THREAD_LOCK(thread);
+            if (thread->state == _PR_IO_WAIT) {
+			  ;
+            } else {
+                if (thread->wait.cvar != NULL) {
+                    thread->wait.cvar = NULL;
+                    _PR_THREAD_UNLOCK(thread);
+                } else {
+                    /* The CVAR was notified just as the timeout
+                     * occurred.  This led to us being notified twice.
+                     * call WaitForSingleObject() to clear the semaphore.
+                     */
+                    _PR_THREAD_UNLOCK(thread);
+                    rv = WaitForSingleObject(thread->md.blocked_sema, 0);
+                    PR_ASSERT(rv == WAIT_OBJECT_0);
+                }
+            }
+            return PR_SUCCESS;
+            break;
+        default:
+            return PR_FAILURE;
+            break;
+    }
+}
+PRStatus
+_PR_MD_WAKEUP_WAITER(PRThread *thread)
+{
+    if ( _PR_IS_NATIVE_THREAD(thread) ) 
+    {
+        if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE)
+            return PR_FAILURE;
+        else
+			return PR_SUCCESS;
+	}
+}
+
+
+/* --- FILE IO ----------------------------------------------------------- */
+/*
+ *  _PR_MD_OPEN() -- Open a file
+ *
+ *  returns: a fileHandle
+ *
+ *  The NSPR open flags (osflags) are translated into flags for Win95
+ *
+ *  Mode seems to be passed in as a unix style file permissions argument
+ *  as in 0666, in the case of opening the logFile. 
+ *
+ */
+PROsfd
+_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
+{
+    HANDLE file;
+    PRInt32 access = 0;
+    PRInt32 flags = 0;
+    PRInt32 flag6 = 0;
+    
+    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
+ 
+    if (osflags & PR_RDONLY || osflags & PR_RDWR)
+        access |= GENERIC_READ;
+    if (osflags & PR_WRONLY || osflags & PR_RDWR)
+        access |= GENERIC_WRITE;
+
+    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
+        flags = CREATE_NEW;
+    else if (osflags & PR_CREATE_FILE) {
+        if (osflags & PR_TRUNCATE)
+            flags = CREATE_ALWAYS;
+        else
+            flags = OPEN_ALWAYS;
+    } else {
+        if (osflags & PR_TRUNCATE)
+            flags = TRUNCATE_EXISTING;
+        else
+            flags = OPEN_EXISTING;
+    }
+
+    file = CreateFileA(name,
+                       access,
+                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                       NULL,
+                       flags,
+                       flag6,
+                       NULL);
+    if (file == INVALID_HANDLE_VALUE) {
+		_PR_MD_MAP_OPEN_ERROR(GetLastError());
+        return -1; 
+	}
+
+    return (PROsfd)file;
+}
+
+PROsfd
+_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode)
+{
+    HANDLE file;
+    PRInt32 access = 0;
+    PRInt32 flags = 0;
+    PRInt32 flag6 = 0;
+    SECURITY_ATTRIBUTES sa;
+    LPSECURITY_ATTRIBUTES lpSA = NULL;
+    PSECURITY_DESCRIPTOR pSD = NULL;
+    PACL pACL = NULL;
+
+    if (osflags & PR_CREATE_FILE) {
+        if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
+                &pSD, &pACL) == PR_SUCCESS) {
+            sa.nLength = sizeof(sa);
+            sa.lpSecurityDescriptor = pSD;
+            sa.bInheritHandle = FALSE;
+            lpSA = &sa;
+        }
+    }
+    
+    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
+ 
+    if (osflags & PR_RDONLY || osflags & PR_RDWR)
+        access |= GENERIC_READ;
+    if (osflags & PR_WRONLY || osflags & PR_RDWR)
+        access |= GENERIC_WRITE;
+
+    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
+        flags = CREATE_NEW;
+    else if (osflags & PR_CREATE_FILE) {
+        if (osflags & PR_TRUNCATE)
+            flags = CREATE_ALWAYS;
+        else
+            flags = OPEN_ALWAYS;
+    } else {
+        if (osflags & PR_TRUNCATE)
+            flags = TRUNCATE_EXISTING;
+        else
+            flags = OPEN_EXISTING;
+    }
+
+    file = CreateFileA(name,
+                       access,
+                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                       lpSA,
+                       flags,
+                       flag6,
+                       NULL);
+    if (lpSA != NULL) {
+        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
+    }
+    if (file == INVALID_HANDLE_VALUE) {
+		_PR_MD_MAP_OPEN_ERROR(GetLastError());
+        return -1; 
+	}
+
+    return (PROsfd)file;
+}
+
+PRInt32
+_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
+{
+    PRUint32 bytes;
+    int rv, err;
+
+    rv = ReadFile((HANDLE)fd->secret->md.osfd,
+            (LPVOID)buf,
+            len,
+            &bytes,
+            NULL);
+    
+    if (rv == 0) 
+    {
+        err = GetLastError();
+        /* ERROR_HANDLE_EOF can only be returned by async io */
+        PR_ASSERT(err != ERROR_HANDLE_EOF);
+        if (err == ERROR_BROKEN_PIPE)
+            return 0;
+		else {
+			_PR_MD_MAP_READ_ERROR(err);
+        return -1;
+    }
+    }
+    return bytes;
+}
+
+PRInt32
+_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
+{
+    PROsfd f = fd->secret->md.osfd;
+    PRInt32 bytes;
+    int rv;
+    
+    rv = WriteFile((HANDLE)f,
+            buf,
+            len,
+            &bytes,
+            NULL );
+            
+    if (rv == 0) 
+    {
+		_PR_MD_MAP_WRITE_ERROR(GetLastError());
+        return -1;
+    }
+    return bytes;
+} /* --- end _PR_MD_WRITE() --- */
+
+PROffset32
+_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
+{
+    DWORD moveMethod;
+    PROffset32 rv;
+
+    switch (whence) {
+        case PR_SEEK_SET:
+            moveMethod = FILE_BEGIN;
+            break;
+        case PR_SEEK_CUR:
+            moveMethod = FILE_CURRENT;
+            break;
+        case PR_SEEK_END:
+            moveMethod = FILE_END;
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            return -1;
+    }
+
+    rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod);
+
+    /*
+     * If the lpDistanceToMoveHigh argument (third argument) is
+     * NULL, SetFilePointer returns 0xffffffff on failure.
+     */
+    if (-1 == rv) {
+        _PR_MD_MAP_LSEEK_ERROR(GetLastError());
+    }
+    return rv;
+}
+
+PROffset64
+_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
+{
+    DWORD moveMethod;
+    LARGE_INTEGER li;
+    DWORD err;
+
+    switch (whence) {
+        case PR_SEEK_SET:
+            moveMethod = FILE_BEGIN;
+            break;
+        case PR_SEEK_CUR:
+            moveMethod = FILE_CURRENT;
+            break;
+        case PR_SEEK_END:
+            moveMethod = FILE_END;
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            return -1;
+    }
+
+    li.QuadPart = offset;
+    li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd,
+            li.LowPart, &li.HighPart, moveMethod);
+
+    if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) {
+        _PR_MD_MAP_LSEEK_ERROR(err);
+        li.QuadPart = -1;
+    }
+    return li.QuadPart;
+}
+
+/*
+ * This is documented to succeed on read-only files, but Win32's
+ * FlushFileBuffers functions fails with "access denied" in such a
+ * case.  So we only signal an error if the error is *not* "access
+ * denied".
+ */
+PRInt32
+_PR_MD_FSYNC(PRFileDesc *fd)
+{
+    /*
+     * From the documentation:
+     *
+     *	   On Windows NT, the function FlushFileBuffers fails if hFile
+     *	   is a handle to console output. That is because console
+     *	   output is not buffered. The function returns FALSE, and
+     *	   GetLastError returns ERROR_INVALID_HANDLE.
+     *
+     * On the other hand, on Win95, it returns without error.  I cannot
+     * assume that 0, 1, and 2 are console, because if someone closes
+     * System.out and then opens a file, they might get file descriptor
+     * 1.  An error on *that* version of 1 should be reported, whereas
+     * an error on System.out (which was the original 1) should be
+     * ignored.  So I use isatty() to ensure that such an error was due
+     * to this bogosity, and if it was, I ignore the error.
+     */
+
+    BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
+
+    if (!ok) {
+	DWORD err = GetLastError();
+	if (err != ERROR_ACCESS_DENIED) {	// from winerror.h
+			_PR_MD_MAP_FSYNC_ERROR(err);
+	    return -1;
+	}
+    }
+    return 0;
+}
+
+PRInt32
+_MD_CloseFile(PROsfd osfd)
+{
+    PRInt32 rv;
+    
+    rv = (CloseHandle((HANDLE)osfd))?0:-1;
+	if (rv == -1)
+		_PR_MD_MAP_CLOSE_ERROR(GetLastError());
+    return rv;
+}
+
+
+/* --- DIR IO ------------------------------------------------------------ */
+#define GetFileFromDIR(d)       (d)->d_entry.cFileName
+#define FileIsHidden(d)	((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
+
+static void FlipSlashes(char *cp, size_t len)
+{
+    while (len-- > 0) {
+        if (cp[0] == '/') {
+            cp[0] = PR_DIRECTORY_SEPARATOR;
+        }
+        cp = _mbsinc(cp);
+    }
+} /* end FlipSlashes() */
+
+
+/*
+**
+** Local implementations of standard Unix RTL functions which are not provided
+** by the VC RTL.
+**
+*/
+
+PRStatus
+_PR_MD_CLOSE_DIR(_MDDir *d)
+{
+    if ( d ) {
+        if (FindClose(d->d_hdl)) {
+        d->magic = (PRUint32)-1;
+        return PR_SUCCESS;
+		} else {
+			_PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
+        	return PR_FAILURE;
+		}
+    }
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return PR_FAILURE;
+}
+
+
+PRStatus
+_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
+{
+    char filename[ MAX_PATH ];
+    size_t len;
+
+    len = strlen(name);
+    /* Need 5 bytes for \*.* and the trailing null byte. */
+    if (len + 5 > MAX_PATH) {
+        PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
+        return PR_FAILURE;
+    }
+    strcpy(filename, name);
+
+    /*
+     * If 'name' ends in a slash or backslash, do not append
+     * another backslash.
+     */
+    if (IsPrevCharSlash(filename, filename + len)) {
+        len--;
+    }
+    strcpy(&filename[len], "\\*.*");
+    FlipSlashes( filename, strlen(filename) );
+
+    d->d_hdl = FindFirstFileA( filename, &(d->d_entry) );
+    if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
+		_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    d->firstEntry = PR_TRUE;
+    d->magic = _MD_MAGIC_DIR;
+    return PR_SUCCESS;
+}
+
+char *
+_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
+{
+    PRInt32 err;
+    BOOL rv;
+    char *fileName;
+
+    if ( d ) {
+        while (1) {
+            if (d->firstEntry) {
+                d->firstEntry = PR_FALSE;
+                rv = 1;
+            } else {
+                rv = FindNextFileA(d->d_hdl, &(d->d_entry));
+            }
+            if (rv == 0) {
+                break;
+            }
+            fileName = GetFileFromDIR(d);
+            if ( (flags & PR_SKIP_DOT) &&
+                 (fileName[0] == '.') && (fileName[1] == '\0'))
+                 continue;
+            if ( (flags & PR_SKIP_DOT_DOT) &&
+                 (fileName[0] == '.') && (fileName[1] == '.') &&
+                 (fileName[2] == '\0'))
+                 continue;
+            if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
+                 continue;
+            return fileName;
+        }
+        err = GetLastError();
+        PR_ASSERT(NO_ERROR != err);
+			_PR_MD_MAP_READDIR_ERROR(err);
+        return NULL;
+		}
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return NULL;
+}
+
+PRInt32
+_PR_MD_DELETE(const char *name)
+{
+    if (DeleteFileA(name)) {
+        return 0;
+    } else {
+		_PR_MD_MAP_DELETE_ERROR(GetLastError());
+        return -1;
+    }
+}
+
+void
+_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm)
+{
+    PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
+    CopyMemory(prtm, filetime, sizeof(PRTime));
+#if defined(__MINGW32__)
+    *prtm = (*prtm - _pr_filetime_offset) / 10LL;
+#else
+    *prtm = (*prtm - _pr_filetime_offset) / 10i64;
+#endif
+
+#ifdef DEBUG
+    /* Doublecheck our calculation. */
+    {
+        SYSTEMTIME systime;
+        PRExplodedTime etm;
+        PRTime cmp; /* for comparison */
+        BOOL rv;
+
+        rv = FileTimeToSystemTime(filetime, &systime);
+        PR_ASSERT(0 != rv);
+
+        /*
+         * PR_ImplodeTime ignores wday and yday.
+         */
+        etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC;
+        etm.tm_sec = systime.wSecond;
+        etm.tm_min = systime.wMinute;
+        etm.tm_hour = systime.wHour;
+        etm.tm_mday = systime.wDay;
+        etm.tm_month = systime.wMonth - 1;
+        etm.tm_year = systime.wYear;
+        /*
+         * It is not well-documented what time zone the FILETIME's
+         * are in.  WIN32_FIND_DATA is documented to be in UTC (GMT).
+         * But BY_HANDLE_FILE_INFORMATION is unclear about this.
+         * By our best judgement, we assume that FILETIME is in UTC.
+         */
+        etm.tm_params.tp_gmt_offset = 0;
+        etm.tm_params.tp_dst_offset = 0;
+        cmp = PR_ImplodeTime(&etm);
+
+        /*
+         * SYSTEMTIME is in milliseconds precision, so we convert PRTime's
+         * microseconds to milliseconds before doing the comparison.
+         */
+        PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC));
+    }
+#endif /* DEBUG */
+}
+
+PRInt32
+_PR_MD_STAT(const char *fn, struct stat *info)
+{
+#ifdef WINCE
+    // needs work. dft
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return -1;
+#else
+    PRInt32 rv;
+
+    rv = _stat(fn, (struct _stat *)info);
+    if (-1 == rv) {
+        /*
+         * Check for MSVC runtime library _stat() bug.
+         * (It's really a bug in FindFirstFile().)
+         * If a pathname ends in a backslash or slash,
+         * e.g., c:\temp\ or c:/temp/, _stat() will fail.
+         * Note: a pathname ending in a slash (e.g., c:/temp/)
+         * can be handled by _stat() on NT but not on Win95.
+         *
+         * We remove the backslash or slash at the end and
+         * try again.
+         */
+
+        size_t len = strlen(fn);
+        if (len > 0 && len <= _MAX_PATH
+                && IsPrevCharSlash(fn, fn + len)) {
+            char newfn[_MAX_PATH + 1];
+
+            strcpy(newfn, fn);
+            newfn[len - 1] = '\0';
+            rv = _stat(newfn, (struct _stat *)info);
+        }
+    }
+
+    if (-1 == rv) {
+        _PR_MD_MAP_STAT_ERROR(errno);
+    }
+    return rv;
+#endif
+}
+
+#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
+
+static PRBool
+IsPrevCharSlash(const char *str, const char *current)
+{
+    const char *prev;
+
+    if (str >= current)
+        return PR_FALSE;
+    prev = _mbsdec(str, current);
+    return (prev == current - 1) && _PR_IS_SLASH(*prev);
+}
+
+/*
+ * IsRootDirectory --
+ *
+ * Return PR_TRUE if the pathname 'fn' is a valid root directory,
+ * else return PR_FALSE.  The char buffer pointed to by 'fn' must
+ * be writable.  During the execution of this function, the contents
+ * of the buffer pointed to by 'fn' may be modified, but on return
+ * the original contents will be restored.  'buflen' is the size of
+ * the buffer pointed to by 'fn'.
+ *
+ * Root directories come in three formats:
+ * 1. / or \, meaning the root directory of the current drive.
+ * 2. C:/ or C:\, where C is a drive letter.
+ * 3. \\<server name>\<share point name>\ or
+ *    \\<server name>\<share point name>, meaning the root directory
+ *    of a UNC (Universal Naming Convention) name.
+ */
+
+static PRBool
+IsRootDirectory(char *fn, size_t buflen)
+{
+    char *p;
+    PRBool slashAdded = PR_FALSE;
+    PRBool rv = PR_FALSE;
+
+    if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') {
+        return PR_TRUE;
+    }
+
+    if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2])
+            && fn[3] == '\0') {
+        rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
+        return rv;
+    }
+
+    /* The UNC root directory */
+
+    if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) {
+        /* The 'server' part should have at least one character. */
+        p = &fn[2];
+        if (*p == '\0' || _PR_IS_SLASH(*p)) {
+            return PR_FALSE;
+        }
+
+        /* look for the next slash */
+        do {
+            p = _mbsinc(p);
+        } while (*p != '\0' && !_PR_IS_SLASH(*p));
+        if (*p == '\0') {
+            return PR_FALSE;
+        }
+
+        /* The 'share' part should have at least one character. */
+        p++;
+        if (*p == '\0' || _PR_IS_SLASH(*p)) {
+            return PR_FALSE;
+        }
+
+        /* look for the final slash */
+        do {
+            p = _mbsinc(p);
+        } while (*p != '\0' && !_PR_IS_SLASH(*p));
+        if (_PR_IS_SLASH(*p) && p[1] != '\0') {
+            return PR_FALSE;
+        }
+        if (*p == '\0') {
+            /*
+             * GetDriveType() doesn't work correctly if the
+             * path is of the form \\server\share, so we add
+             * a final slash temporarily.
+             */
+            if ((p + 1) < (fn + buflen)) {
+                *p++ = '\\';
+                *p = '\0';
+                slashAdded = PR_TRUE;
+            } else {
+                return PR_FALSE; /* name too long */
+            }
+        }
+        rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
+        /* restore the 'fn' buffer */
+        if (slashAdded) {
+            *--p = '\0';
+        }
+    }
+    return rv;
+}
+
+#ifndef WINCE
+/*
+ * InitGetFileInfo --
+ *
+ * Called during IO init. Checks for the existence of the system function
+ * GetFileAttributeEx, which when available is used in GETFILEINFO calls. 
+ * If the routine exists, then the address of the routine is stored in the
+ * variable getFileAttributesEx, which will be used to call the routine.
+ */
+static void InitGetFileInfo(void)
+{
+    HMODULE module;
+    module = GetModuleHandle("Kernel32.dll");
+    if (!module) {
+        PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
+                ("InitGetFileInfo: GetModuleHandle() failed: %d",
+                GetLastError()));
+        return;
+    }
+
+    getFileAttributesEx = (GetFileAttributesExFn)
+            GetProcAddress(module, "GetFileAttributesExA");
+}
+
+/*
+ * If GetFileAttributeEx doesn't exist, we call FindFirstFile as a
+ * fallback.
+ */
+static BOOL
+GetFileAttributesExFB(const char *fn, WIN32_FIND_DATA *findFileData)
+{
+    HANDLE hFindFile;
+
+    /*
+     * FindFirstFile() expands wildcard characters.  So
+     * we make sure the pathname contains no wildcard.
+     */
+    if (NULL != _mbspbrk(fn, "?*")) {
+        SetLastError(ERROR_INVALID_NAME);
+        return FALSE;
+    }
+
+    hFindFile = FindFirstFile(fn, findFileData);
+    if (INVALID_HANDLE_VALUE == hFindFile) {
+        DWORD len;
+        char *filePart;
+        char pathbuf[MAX_PATH + 1];
+
+        /*
+         * FindFirstFile() does not work correctly on root directories.
+         * It also doesn't work correctly on a pathname that ends in a
+         * slash.  So we first check to see if the pathname specifies a
+         * root directory.  If not, and if the pathname ends in a slash,
+         * we remove the final slash and try again.
+         */
+
+        /*
+         * If the pathname does not contain ., \, and /, it cannot be
+         * a root directory or a pathname that ends in a slash.
+         */
+        if (NULL == _mbspbrk(fn, ".\\/")) {
+            return FALSE;
+        } 
+        len = GetFullPathName(fn, sizeof(pathbuf), pathbuf,
+                &filePart);
+        if (0 == len) {
+            return FALSE;
+        }
+        if (len > sizeof(pathbuf)) {
+            SetLastError(ERROR_FILENAME_EXCED_RANGE);
+            return FALSE;
+        }
+        if (IsRootDirectory(pathbuf, sizeof(pathbuf))) {
+            findFileData->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
+            /* The file size doesn't have a meaning for directories. */
+            findFileData->nFileSizeHigh = 0;
+            findFileData->nFileSizeLow = 0;
+            /*
+             * For a directory, these timestamps all specify when the
+             * directory is created.  The creation time doesn't make
+             * sense for root directories, so we set it to (NSPR) time 0.
+             */
+            memcpy(&findFileData->ftCreationTime, &_pr_filetime_offset, 8);
+            findFileData->ftLastAccessTime = findFileData->ftCreationTime;
+            findFileData->ftLastWriteTime = findFileData->ftCreationTime;
+            return TRUE;
+        }
+        if (!IsPrevCharSlash(pathbuf, pathbuf + len)) {
+            return FALSE;
+        } else {
+            pathbuf[len - 1] = '\0';
+            hFindFile = FindFirstFile(pathbuf, findFileData);
+            if (INVALID_HANDLE_VALUE == hFindFile) {
+                return FALSE;
+            }
+        }
+    }
+
+    FindClose(hFindFile);
+    return TRUE;
+}
+#endif
+
+PRInt32
+_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
+{
+#ifdef WINCE
+    WIN32_FILE_ATTRIBUTE_DATA findFileData;
+#else
+    WIN32_FIND_DATA findFileData;
+#endif
+    BOOL rv;
+    
+    if (NULL == fn || '\0' == *fn) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return -1;
+    }
+
+#ifdef WINCE
+    rv = GetFileAttributesExA(fn, GetFileExInfoStandard, &findFileData);
+#else
+    /* GetFileAttributesEx is supported on Win 2K and up. */
+    if (getFileAttributesEx) {
+        rv = getFileAttributesEx(fn, GetFileExInfoStandard, &findFileData);
+    } else {
+        rv = GetFileAttributesExFB(fn, &findFileData);
+    }
+#endif
+    if (!rv) {
+        _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
+        return -1;
+    }
+
+    if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+        info->type = PR_FILE_DIRECTORY;
+    } else {
+        info->type = PR_FILE_FILE;
+    }
+
+    info->size = findFileData.nFileSizeHigh;
+    info->size = (info->size << 32) + findFileData.nFileSizeLow;
+
+    _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
+
+    if (0 == findFileData.ftCreationTime.dwLowDateTime &&
+            0 == findFileData.ftCreationTime.dwHighDateTime) {
+        info->creationTime = info->modifyTime;
+    } else {
+        _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
+                &info->creationTime);
+    }
+
+    return 0;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
+{
+    PRFileInfo64 info64;
+    PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64);
+    if (0 == rv)
+    {
+        info->type = info64.type;
+        info->size = (PRUint32) info64.size;
+        info->modifyTime = info64.modifyTime;
+        info->creationTime = info64.creationTime;
+    }
+    return rv;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
+{
+    int rv;
+
+    BY_HANDLE_FILE_INFORMATION hinfo;
+
+    rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo);
+    if (rv == FALSE) {
+		_PR_MD_MAP_FSTAT_ERROR(GetLastError());
+        return -1;
+	}
+
+    if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        info->type = PR_FILE_DIRECTORY;
+    else
+        info->type = PR_FILE_FILE;
+
+    info->size = hinfo.nFileSizeHigh;
+    info->size = (info->size << 32) + hinfo.nFileSizeLow;
+
+    _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) );
+    _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) );
+
+    return 0;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
+{
+    PRFileInfo64 info64;
+    int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64);
+    if (0 == rv)
+    {
+        info->type = info64.type;
+        info->modifyTime = info64.modifyTime;
+        info->creationTime = info64.creationTime;
+        LL_L2I(info->size, info64.size);
+    }
+    return rv;
+}
+
+PRStatus
+_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
+{
+#ifdef WINCE
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+#else
+    BOOL rv;
+
+    /*
+     * The SetHandleInformation function fails with the
+     * ERROR_CALL_NOT_IMPLEMENTED error on Win95.
+     */
+    rv = SetHandleInformation(
+            (HANDLE)fd->secret->md.osfd,
+            HANDLE_FLAG_INHERIT,
+            inheritable ? HANDLE_FLAG_INHERIT : 0);
+    if (0 == rv) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+#endif
+} 
+
+void
+_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported)
+{
+    if (imported) {
+        fd->secret->inheritable = _PR_TRI_UNKNOWN;
+    } else {
+        fd->secret->inheritable = _PR_TRI_FALSE;
+    }
+}
+
+void
+_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd)
+{
+#ifdef WINCE
+    fd->secret->inheritable = _PR_TRI_FALSE;
+#else
+    DWORD flags;
+
+    PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
+    if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) {
+        if (flags & HANDLE_FLAG_INHERIT) {
+            fd->secret->inheritable = _PR_TRI_TRUE;
+        } else {
+            fd->secret->inheritable = _PR_TRI_FALSE;
+        }
+    }
+#endif
+}
+
+PRInt32
+_PR_MD_RENAME(const char *from, const char *to)
+{
+    /* Does this work with dot-relative pathnames? */
+    if (MoveFileA(from, to)) {
+        return 0;
+    } else {
+		_PR_MD_MAP_RENAME_ERROR(GetLastError());
+        return -1;
+    }
+}
+
+PRInt32
+_PR_MD_ACCESS(const char *name, PRAccessHow how)
+{
+#ifdef WINCE
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return -1;
+#else
+PRInt32 rv;
+    switch (how) {
+      case PR_ACCESS_WRITE_OK:
+        rv = _access(name, 02);
+		break;
+      case PR_ACCESS_READ_OK:
+        rv = _access(name, 04);
+		break;
+      case PR_ACCESS_EXISTS:
+        return _access(name, 00);
+	  	break;
+      default:
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+    }
+	if (rv < 0)
+		_PR_MD_MAP_ACCESS_ERROR(errno);
+    return rv;
+#endif
+}
+
+PRInt32
+_PR_MD_MKDIR(const char *name, PRIntn mode)
+{
+    /* XXXMB - how to translate the "mode"??? */
+    if (CreateDirectoryA(name, NULL)) {
+        return 0;
+    } else {
+		_PR_MD_MAP_MKDIR_ERROR(GetLastError());
+        return -1;
+    }
+}
+
+PRInt32
+_PR_MD_MAKE_DIR(const char *name, PRIntn mode)
+{
+    BOOL rv;
+    SECURITY_ATTRIBUTES sa;
+    LPSECURITY_ATTRIBUTES lpSA = NULL;
+    PSECURITY_DESCRIPTOR pSD = NULL;
+    PACL pACL = NULL;
+
+    if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable,
+            &pSD, &pACL) == PR_SUCCESS) {
+        sa.nLength = sizeof(sa);
+        sa.lpSecurityDescriptor = pSD;
+        sa.bInheritHandle = FALSE;
+        lpSA = &sa;
+    }
+    rv = CreateDirectoryA(name, lpSA);
+    if (lpSA != NULL) {
+        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
+    }
+    if (rv) {
+        return 0;
+    } else {
+        _PR_MD_MAP_MKDIR_ERROR(GetLastError());
+        return -1;
+    }
+}
+
+PRInt32
+_PR_MD_RMDIR(const char *name)
+{
+    if (RemoveDirectoryA(name)) {
+        return 0;
+    } else {
+		_PR_MD_MAP_RMDIR_ERROR(GetLastError());
+        return -1;
+    }
+}
+
+PRStatus
+_PR_MD_LOCKFILE(PROsfd f)
+{
+    PRStatus  rc = PR_SUCCESS;
+	DWORD     rv;
+
+	rv = LockFile( (HANDLE)f,
+		0l, 0l,
+		0x0l, 0xffffffffl ); 
+	if ( rv == 0 ) {
+        DWORD rc = GetLastError();
+        PR_LOG( _pr_io_lm, PR_LOG_ERROR,
+            ("_PR_MD_LOCKFILE() failed. Error: %d", rc ));
+        rc = PR_FAILURE;
+    }
+
+    return rc;
+} /* end _PR_MD_LOCKFILE() */
+
+PRStatus
+_PR_MD_TLOCKFILE(PROsfd f)
+{
+    PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+    return PR_FAILURE;
+} /* end _PR_MD_TLOCKFILE() */
+
+
+PRStatus
+_PR_MD_UNLOCKFILE(PROsfd f)
+{
+	PRInt32   rv;
+    
+    rv = UnlockFile( (HANDLE) f,
+    		0l, 0l,
+            0x0l, 0xffffffffl ); 
+            
+    if ( rv )
+    {
+    	return PR_SUCCESS;
+    }
+    else
+    {
+		_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+		return PR_FAILURE;
+    }
+} /* end _PR_MD_UNLOCKFILE() */
+
+PRInt32
+_PR_MD_PIPEAVAILABLE(PRFileDesc *fd)
+{
+    if (NULL == fd)
+		PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+	else
+		PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return -1;
+}
+
+#ifdef MOZ_UNICODE
+
+typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
+static CreateFileWFn createFileW = CreateFileW;
+typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW);
+static FindFirstFileWFn findFirstFileW = FindFirstFileW;
+typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW);
+static FindNextFileWFn findNextFileW = FindNextFileW;
+typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *);
+static GetFullPathNameWFn getFullPathNameW = GetFullPathNameW;
+typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR);
+static GetDriveTypeWFn getDriveTypeW = GetDriveTypeW;
+
+#endif /* MOZ_UNICODE */
+
+PRBool _pr_useUnicode = PR_FALSE;
+
+static void InitUnicodeSupport(void)
+{
+#ifdef WINCE
+    /* The A functions don't even exist in Windows Mobile. */
+    _pr_useUnicode = PR_TRUE;
+#else
+    /*
+     * The W functions exist on Win9x as stubs that fail with the
+     * ERROR_CALL_NOT_IMPLEMENTED error.  We plan to emulate the
+     * MSLU W functions on Win9x in the future.
+     */
+
+    /* Find out if we are running on a Unicode enabled version of Windows */
+    OSVERSIONINFOA osvi = {0};
+
+    osvi.dwOSVersionInfoSize = sizeof(osvi);
+    if (GetVersionExA(&osvi)) {
+        _pr_useUnicode = (osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT);
+    } else {
+        _pr_useUnicode = PR_FALSE;
+    }
+#ifdef DEBUG
+    /*
+     * In debug builds, allow explicit use of ANSI methods to simulate
+     * a Win9x environment for testing purposes.
+     */
+    if (getenv("WINAPI_USE_ANSI"))
+        _pr_useUnicode = PR_FALSE;
+#endif
+#endif
+}
+
+#ifdef MOZ_UNICODE
+
+/* ================ UTF16 Interfaces ================================ */
+static void FlipSlashesW(PRUnichar *cp, size_t len)
+{
+    while (len-- > 0) {
+        if (cp[0] == L'/') {
+            cp[0] = L'\\';
+        }
+        cp++;
+    }
+} /* end FlipSlashesW() */
+
+PROsfd
+_PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode)
+{
+    HANDLE file;
+    PRInt32 access = 0;
+    PRInt32 flags = 0;
+    PRInt32 flag6 = 0;
+    SECURITY_ATTRIBUTES sa;
+    LPSECURITY_ATTRIBUTES lpSA = NULL;
+    PSECURITY_DESCRIPTOR pSD = NULL;
+    PACL pACL = NULL;
+
+    if (osflags & PR_CREATE_FILE) {
+        if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
+                &pSD, &pACL) == PR_SUCCESS) {
+            sa.nLength = sizeof(sa);
+            sa.lpSecurityDescriptor = pSD;
+            sa.bInheritHandle = FALSE;
+            lpSA = &sa;
+        }
+    }
+
+    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
+
+    if (osflags & PR_RDONLY || osflags & PR_RDWR)
+        access |= GENERIC_READ;
+    if (osflags & PR_WRONLY || osflags & PR_RDWR)
+        access |= GENERIC_WRITE;
+ 
+    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
+        flags = CREATE_NEW;
+    else if (osflags & PR_CREATE_FILE) {
+        if (osflags & PR_TRUNCATE)
+            flags = CREATE_ALWAYS;
+        else
+            flags = OPEN_ALWAYS;
+    } else {
+        if (osflags & PR_TRUNCATE)
+            flags = TRUNCATE_EXISTING;
+        else
+            flags = OPEN_EXISTING;
+    }
+
+    file = createFileW(name,
+                       access,
+                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                       lpSA,
+                       flags,
+                       flag6,
+                       NULL);
+    if (lpSA != NULL) {
+        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
+    }
+    if (file == INVALID_HANDLE_VALUE) {
+        _PR_MD_MAP_OPEN_ERROR(GetLastError());
+        return -1;
+    }
+ 
+    return (PROsfd)file;
+}
+ 
+PRStatus
+_PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name)
+{
+    PRUnichar filename[ MAX_PATH ];
+    int len;
+
+    len = wcslen(name);
+    /* Need 5 bytes for \*.* and the trailing null byte. */
+    if (len + 5 > MAX_PATH) {
+        PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
+        return PR_FAILURE;
+    }
+    wcscpy(filename, name);
+
+    /*
+     * If 'name' ends in a slash or backslash, do not append
+     * another backslash.
+     */
+    if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') {
+        len--;
+    }
+    wcscpy(&filename[len], L"\\*.*");
+    FlipSlashesW( filename, wcslen(filename) );
+
+    d->d_hdl = findFirstFileW( filename, &(d->d_entry) );
+    if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
+        _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    d->firstEntry = PR_TRUE;
+    d->magic = _MD_MAGIC_DIR;
+    return PR_SUCCESS;
+}
+
+PRUnichar *
+_PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags)
+{
+    PRInt32 err;
+    BOOL rv;
+    PRUnichar *fileName;
+
+    if ( d ) {
+        while (1) {
+            if (d->firstEntry) {
+                d->firstEntry = PR_FALSE;
+                rv = 1;
+            } else {
+                rv = findNextFileW(d->d_hdl, &(d->d_entry));
+            }
+            if (rv == 0) {
+                break;
+            }
+            fileName = GetFileFromDIR(d);
+            if ( (flags & PR_SKIP_DOT) &&
+                 (fileName[0] == L'.') && (fileName[1] == L'\0'))
+                continue;
+            if ( (flags & PR_SKIP_DOT_DOT) &&
+                 (fileName[0] == L'.') && (fileName[1] == L'.') &&
+                 (fileName[2] == L'\0'))
+                continue;
+            if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
+                continue;
+            return fileName;
+        }
+        err = GetLastError();
+        PR_ASSERT(NO_ERROR != err);
+        _PR_MD_MAP_READDIR_ERROR(err);
+        return NULL;
+    }
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return NULL;
+}
+ 
+PRStatus
+_PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d)
+{
+    if ( d ) {
+        if (FindClose(d->d_hdl)) {
+            d->magic = (PRUint32)-1;
+            return PR_SUCCESS;
+        } else {
+            _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
+            return PR_FAILURE;
+        }
+    }
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return PR_FAILURE;
+}
+
+#define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\')
+
+/*
+ * IsRootDirectoryW --
+ *
+ * Return PR_TRUE if the pathname 'fn' is a valid root directory,
+ * else return PR_FALSE.  The PRUnichar buffer pointed to by 'fn' must
+ * be writable.  During the execution of this function, the contents
+ * of the buffer pointed to by 'fn' may be modified, but on return
+ * the original contents will be restored.  'buflen' is the size of
+ * the buffer pointed to by 'fn', in PRUnichars.
+ *
+ * Root directories come in three formats:
+ * 1. / or \, meaning the root directory of the current drive.
+ * 2. C:/ or C:\, where C is a drive letter.
+ * 3. \\<server name>\<share point name>\ or
+ *    \\<server name>\<share point name>, meaning the root directory
+ *    of a UNC (Universal Naming Convention) name.
+ */
+
+static PRBool
+IsRootDirectoryW(PRUnichar *fn, size_t buflen)
+{
+    PRUnichar *p;
+    PRBool slashAdded = PR_FALSE;
+    PRBool rv = PR_FALSE;
+
+    if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') {
+        return PR_TRUE;
+    }
+
+    if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2])
+            && fn[3] == L'\0') {
+        rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
+        return rv;
+    }
+
+    /* The UNC root directory */
+
+    if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) {
+        /* The 'server' part should have at least one character. */
+        p = &fn[2];
+        if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
+            return PR_FALSE;
+        }
+
+        /* look for the next slash */
+        do {
+            p++;
+        } while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
+        if (*p == L'\0') {
+            return PR_FALSE;
+        }
+
+        /* The 'share' part should have at least one character. */
+        p++;
+        if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
+            return PR_FALSE;
+        }
+
+        /* look for the final slash */
+        do {
+            p++;
+        } while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
+        if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') {
+            return PR_FALSE;
+        }
+        if (*p == L'\0') {
+            /*
+             * GetDriveType() doesn't work correctly if the
+             * path is of the form \\server\share, so we add
+             * a final slash temporarily.
+             */
+            if ((p + 1) < (fn + buflen)) {
+                *p++ = L'\\';
+                *p = L'\0';
+                slashAdded = PR_TRUE;
+            } else {
+                return PR_FALSE; /* name too long */
+            }
+        }
+        rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
+        /* restore the 'fn' buffer */
+        if (slashAdded) {
+            *--p = L'\0';
+        }
+    }
+    return rv;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info)
+{
+    HANDLE hFindFile;
+    WIN32_FIND_DATAW findFileData;
+    PRUnichar pathbuf[MAX_PATH + 1];
+
+    if (NULL == fn || L'\0' == *fn) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return -1;
+    }
+
+    /*
+     * FindFirstFile() expands wildcard characters.  So
+     * we make sure the pathname contains no wildcard.
+     */
+    if (NULL != wcspbrk(fn, L"?*")) {
+        PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
+        return -1;
+    }
+
+    hFindFile = findFirstFileW(fn, &findFileData);
+    if (INVALID_HANDLE_VALUE == hFindFile) {
+        DWORD len;
+        PRUnichar *filePart;
+
+        /*
+         * FindFirstFile() does not work correctly on root directories.
+         * It also doesn't work correctly on a pathname that ends in a
+         * slash.  So we first check to see if the pathname specifies a
+         * root directory.  If not, and if the pathname ends in a slash,
+         * we remove the final slash and try again.
+         */
+
+        /*
+         * If the pathname does not contain ., \, and /, it cannot be
+         * a root directory or a pathname that ends in a slash.
+         */
+        if (NULL == wcspbrk(fn, L".\\/")) {
+            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
+            return -1;
+        } 
+        len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf,
+                &filePart);
+        if (0 == len) {
+            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
+            return -1;
+        }
+        if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) {
+            PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
+            return -1;
+        }
+        if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) {
+            info->type = PR_FILE_DIRECTORY;
+            info->size = 0;
+            /*
+             * These timestamps don't make sense for root directories.
+             */
+            info->modifyTime = 0;
+            info->creationTime = 0;
+            return 0;
+        }
+        if (!_PR_IS_W_SLASH(pathbuf[len - 1])) {
+            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
+            return -1;
+        } else {
+            pathbuf[len - 1] = L'\0';
+            hFindFile = findFirstFileW(pathbuf, &findFileData);
+            if (INVALID_HANDLE_VALUE == hFindFile) {
+                _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
+                return -1;
+            }
+        }
+    }
+
+    FindClose(hFindFile);
+
+    if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+        info->type = PR_FILE_DIRECTORY;
+    } else {
+        info->type = PR_FILE_FILE;
+    }
+
+    info->size = findFileData.nFileSizeHigh;
+    info->size = (info->size << 32) + findFileData.nFileSizeLow;
+
+    _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
+
+    if (0 == findFileData.ftCreationTime.dwLowDateTime &&
+            0 == findFileData.ftCreationTime.dwHighDateTime) {
+        info->creationTime = info->modifyTime;
+    } else {
+        _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
+                &info->creationTime);
+    }
+
+    return 0;
+}
+/* ================ end of UTF16 Interfaces ================================ */
+#endif /* MOZ_UNICODE */
diff --git a/mozilla/nsprpub/pr/src/md/windows/w95sock.c b/mozilla/nsprpub/pr/src/md/windows/w95sock.c
new file mode 100644
index 0000000..4e67a22
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w95sock.c
@@ -0,0 +1,771 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/* Win95 Sockets module
+ *
+ */
+
+#include "primpl.h"
+
+#define READ_FD     1
+#define WRITE_FD    2
+#define CONNECT_FD  3
+
+static PRInt32 socket_io_wait(
+    PROsfd osfd, 
+    PRInt32 fd_type,
+    PRIntervalTime timeout);
+
+
+/* --- SOCKET IO --------------------------------------------------------- */
+
+/*
+ * we only want to call WSAIoctl() on Vista and later
+ * so don't pay for it at build time (and avoid including winsock2.h)
+ */
+
+/* from ws2def.h */
+#define IOC_IN                      0x80000000      /* copy in parameters */
+#define IOC_VENDOR                  0x18000000
+#define _WSAIOW(x,y)                (IOC_IN|(x)|(y))
+/* from MSWSockDef.h */
+#define SIO_SET_COMPATIBILITY_MODE  _WSAIOW(IOC_VENDOR,300)
+
+typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID {
+    WsaBehaviorAll = 0,
+    WsaBehaviorReceiveBuffering,
+    WsaBehaviorAutoTuning
+} WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID;
+
+/* from sdkddkver.h */
+#define NTDDI_WIN6              0x06000000  /* Windows Vista */
+
+/* from winsock2.h */
+#define WSAEVENT                HANDLE
+
+#define WSAOVERLAPPED           OVERLAPPED
+typedef struct _OVERLAPPED *    LPWSAOVERLAPPED;
+
+typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(
+    IN DWORD dwError,
+    IN DWORD cbTransferred,
+    IN LPWSAOVERLAPPED lpOverlapped,
+    IN DWORD dwFlags
+);
+
+typedef int (__stdcall * WSAIOCTLPROC) (
+    SOCKET s,
+    DWORD dwIoControlCode,
+    LPVOID lpvInBuffer,
+    DWORD cbInBuffer,
+    LPVOID lpvOutBuffer,
+    DWORD cbOutBuffer,
+    LPDWORD lpcbBytesReturned,
+    LPWSAOVERLAPPED lpOverlapped,
+    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
+);
+
+typedef struct _WSA_COMPATIBILITY_MODE {
+    WSA_COMPATIBILITY_BEHAVIOR_ID BehaviorId;
+    ULONG TargetOsVersion;
+} WSA_COMPATIBILITY_MODE, *PWSA_COMPATIBILITY_MODE;
+
+static HMODULE libWinsock2 = NULL;
+static WSAIOCTLPROC wsaioctlProc = NULL;
+static PRBool socketSetCompatMode = PR_FALSE;
+
+void _PR_MD_InitSockets(void)
+{
+    OSVERSIONINFO osvi;
+
+    memset(&osvi, 0, sizeof(osvi));
+    osvi.dwOSVersionInfoSize = sizeof(osvi);
+    GetVersionEx(&osvi);
+
+    /* if Vista or later... */
+    if (osvi.dwMajorVersion >= 6)
+    {
+        libWinsock2 = LoadLibraryW(L"Ws2_32.dll");
+        if (libWinsock2)
+        {
+            wsaioctlProc = (WSAIOCTLPROC)GetProcAddress(libWinsock2, 
+                                                        "WSAIoctl");
+            if (wsaioctlProc)
+            {
+                socketSetCompatMode = PR_TRUE;
+            }
+        }
+    }
+}
+
+void _PR_MD_CleanupSockets(void)
+{
+    socketSetCompatMode = PR_FALSE;
+    wsaioctlProc = NULL;
+    if (libWinsock2)
+    {
+        FreeLibrary(libWinsock2);
+        libWinsock2 = NULL;
+    }
+}
+
+PROsfd
+_PR_MD_SOCKET(int af, int type, int flags)
+{
+    SOCKET sock;
+    u_long one = 1;
+
+    sock = socket(af, type, flags);
+
+    if (sock == INVALID_SOCKET ) 
+    {
+        _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError());
+        return (PROsfd)sock;
+    }
+
+    /*
+    ** Make the socket Non-Blocking
+    */
+    if (ioctlsocket( sock, FIONBIO, &one) != 0)
+    {
+        PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError());
+        closesocket(sock);
+        return -1;
+    }
+
+    if ((af == AF_INET || af == AF_INET6) && 
+        type == SOCK_STREAM && socketSetCompatMode)
+    {
+        WSA_COMPATIBILITY_MODE mode;
+        char dummy[4];
+        int ret_dummy;
+
+        mode.BehaviorId = WsaBehaviorAutoTuning;
+        mode.TargetOsVersion = NTDDI_WIN6;
+        if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE,  
+                         (char *)&mode, sizeof(mode),
+                         dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR)
+        {
+            int err = WSAGetLastError();
+            PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err));
+
+            /* SIO_SET_COMPATIBILITY_MODE may not be supported.
+            ** If the call to WSAIoctl() fails with WSAEOPNOTSUPP,
+            ** don't close the socket.
+            */ 
+        }
+    }
+
+    return (PROsfd)sock;
+}
+
+/*
+** _MD_CloseSocket() -- Close a socket
+**
+*/
+PRInt32
+_MD_CloseSocket(PROsfd osfd)
+{
+    PRInt32 rv;
+
+    rv = closesocket((SOCKET) osfd );
+    if (rv < 0)
+        _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
+
+    return rv;
+}
+
+PRInt32
+_MD_SocketAvailable(PRFileDesc *fd)
+{
+    PRInt32 result;
+
+    if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
+        return -1;
+    }
+    return result;
+}
+
+PROsfd _MD_Accept(
+    PRFileDesc *fd, 
+    PRNetAddr *raddr, 
+    PRUint32 *rlen,
+    PRIntervalTime timeout )
+{
+    PROsfd osfd = fd->secret->md.osfd;
+    SOCKET sock;
+    PRInt32 rv, err;
+
+    while ((sock = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) 
+    {
+        err = WSAGetLastError();
+        if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking))
+        {
+            if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
+            {
+                break;
+            }
+        }
+        else
+        {
+            _PR_MD_MAP_ACCEPT_ERROR(err);
+            break;
+        }
+    }
+    return(sock);
+} /* end _MD_accept() */
+
+PRInt32
+_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, 
+               PRIntervalTime timeout)
+{
+    PROsfd osfd = fd->secret->md.osfd;
+    PRInt32 rv;
+    int     err;
+
+    if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) 
+    {
+        err = WSAGetLastError();
+        if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK))
+        {
+            rv = socket_io_wait(osfd, CONNECT_FD, timeout);
+            if ( rv < 0 )
+            {
+                return(-1);
+            }
+            else
+            {
+                PR_ASSERT(rv > 0);
+                /* it's connected */
+                return(0);
+            } 
+        }
+        _PR_MD_MAP_CONNECT_ERROR(err);
+    }
+    return rv;
+}
+
+PRInt32
+_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
+{
+    PRInt32 rv;
+
+    rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen);
+
+    if (rv == SOCKET_ERROR)  {
+        _PR_MD_MAP_BIND_ERROR(WSAGetLastError());
+        return -1;
+    }
+
+    return 0;
+}
+
+PRInt32
+_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
+{
+    PRInt32 rv;
+
+    rv = listen(fd->secret->md.osfd, backlog);
+
+    if (rv == SOCKET_ERROR)  {
+        _PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError());
+        return -1;
+    }
+
+    return 0;
+}
+
+PRInt32
+_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, 
+            PRIntervalTime timeout)
+{
+    PROsfd osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    int osflags;
+
+    if (0 == flags) {
+        osflags = 0;
+    } else {
+        PR_ASSERT(PR_MSG_PEEK == flags);
+        osflags = MSG_PEEK;
+    }
+    while ((rv = recv( osfd, buf, amount, osflags)) == -1) 
+    {
+        if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
+            && (!fd->secret->nonblocking))
+        {
+            rv = socket_io_wait(osfd, READ_FD, timeout);
+            if ( rv < 0 )
+            {
+                return -1;
+            } 
+        } 
+        else 
+        {
+            _PR_MD_MAP_RECV_ERROR(err);
+            break;
+        }
+    } /* end while() */
+    return(rv);
+}
+
+PRInt32
+_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+            PRIntervalTime timeout)
+{
+    PROsfd osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    PRInt32 bytesSent = 0;
+
+    while(bytesSent < amount ) 
+    {
+        while ((rv = send( osfd, buf, amount, 0 )) == -1) 
+        {
+            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
+                && (!fd->secret->nonblocking))
+            {
+                rv = socket_io_wait(osfd, WRITE_FD, timeout);
+                if ( rv < 0 )
+                {
+                    return -1;
+                }
+            } 
+            else 
+            {
+                _PR_MD_MAP_SEND_ERROR(err);
+                return -1;
+            }
+        }
+        bytesSent += rv;
+        if (fd->secret->nonblocking)
+        {
+            break;
+        }
+        if (bytesSent < amount) 
+        {
+            rv = socket_io_wait(osfd, WRITE_FD, timeout);
+            if ( rv < 0 )
+            {
+                return -1;
+            }
+        }
+    }
+    return bytesSent;
+}
+
+PRInt32
+_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+              const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
+{
+    PROsfd osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+    PRInt32 bytesSent = 0;
+
+    while(bytesSent < amount) 
+    {
+        while ((rv = sendto( osfd, buf, amount, 0, (struct sockaddr *) addr,
+                addrlen)) == -1) 
+        {
+            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
+                && (!fd->secret->nonblocking))
+            {
+                rv = socket_io_wait(osfd, WRITE_FD, timeout);
+                if ( rv < 0 )
+                {
+                    return -1;
+                }
+            } 
+            else 
+            {
+                _PR_MD_MAP_SENDTO_ERROR(err);
+                return -1;
+            }
+        }
+        bytesSent += rv;
+        if (fd->secret->nonblocking)
+        {
+            break;
+        }
+        if (bytesSent < amount) 
+        {
+            rv = socket_io_wait(osfd, WRITE_FD, timeout);
+            if (rv < 0) 
+            {
+                return -1;
+            }
+        }
+    }
+    return bytesSent;
+}
+
+PRInt32
+_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+                PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
+{
+    PROsfd osfd = fd->secret->md.osfd;
+    PRInt32 rv, err;
+
+    while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr,
+            addrlen)) == -1) 
+    {
+        if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
+            && (!fd->secret->nonblocking))
+        {
+            rv = socket_io_wait(osfd, READ_FD, timeout);
+            if ( rv < 0)
+            {
+                return -1;
+            } 
+        } 
+        else 
+        {
+            _PR_MD_MAP_RECVFROM_ERROR(err);
+            break;
+        }
+    }
+    return(rv);
+}
+
+PRInt32
+_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
+{
+    int index;
+    int sent = 0;
+    int rv;
+
+    for (index=0; index < iov_size; index++) 
+    {
+        rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
+        if (rv > 0) 
+            sent += rv;
+        if ( rv != iov[index].iov_len ) 
+        {
+            if (rv < 0)
+            {
+                if (fd->secret->nonblocking
+                    && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
+                    && (sent > 0))
+                {
+                    return sent;
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            /* Only a nonblocking socket can have partial sends */
+            PR_ASSERT(fd->secret->nonblocking);
+            return sent;
+        }
+    }
+    return sent;
+}
+
+PRInt32
+_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
+{
+PRInt32 rv;
+
+    rv = shutdown(fd->secret->md.osfd, how);
+    if (rv < 0)
+        _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
+    return rv;
+}
+
+PRStatus
+_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
+{
+    PRInt32 rv;
+
+    rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
+    if (rv==0) {
+        return PR_SUCCESS;
+    } else {
+        _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
+        return PR_FAILURE;
+    }
+}
+
+PRStatus
+_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
+{
+    PRInt32 rv;
+
+    rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
+    if (rv==0) {
+        return PR_SUCCESS;
+    } else {
+        _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
+        return PR_FAILURE;
+    }
+}
+
+PRStatus
+_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
+{
+    PRInt32 rv;
+
+    rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
+    if (rv==0) {
+        return PR_SUCCESS;
+    } else {
+        _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
+        return PR_FAILURE;
+    }
+}
+
+PRStatus
+_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
+{
+    PRInt32 rv;
+
+    rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
+    if (rv==0) {
+        return PR_SUCCESS;
+    } else {
+        _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError());
+        return PR_FAILURE;
+    }
+}
+
+void
+_MD_MakeNonblock(PRFileDesc *f)
+{
+    return; /* do nothing */
+}
+
+
+
+/*
+ * socket_io_wait --
+ *
+ * Wait for socket i/o, periodically checking for interrupt.
+ *
+ * This function returns 1 on success.  On failure, it returns
+ * -1 and sets the error codes.  It never returns 0.
+ */
+#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
+
+static PRInt32 socket_io_wait(
+    PROsfd osfd, 
+    PRInt32 fd_type,
+    PRIntervalTime timeout)
+{
+    PRInt32 rv = -1;
+    struct timeval tv;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRIntervalTime elapsed, remaining;
+    PRBool wait_for_remaining;
+    fd_set rd_wr, ex;
+    int err, len;
+
+    switch (timeout) {
+        case PR_INTERVAL_NO_WAIT:
+            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+            break;
+        case PR_INTERVAL_NO_TIMEOUT:
+            /*
+             * This is a special case of the 'default' case below.
+             * Please see the comments there.
+             */
+            tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
+            tv.tv_usec = 0;
+            FD_ZERO(&rd_wr);
+            FD_ZERO(&ex);
+            do {
+                FD_SET(osfd, &rd_wr);
+                FD_SET(osfd, &ex);
+                switch( fd_type )
+                {
+                    case READ_FD:
+                        rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
+                        break;
+                    case WRITE_FD:
+                        rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
+                        break;
+                    case CONNECT_FD:
+                        rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
+                        break;
+                    default:
+                        PR_ASSERT(0);
+                        break;
+                } /* end switch() */
+                if (rv == -1 )
+                {
+                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                    break;
+                }
+                if ( rv > 0 && fd_type == CONNECT_FD )
+                {
+                    /*
+                     * Call Sleep(0) to work around a Winsock timing bug.
+                     */
+                    Sleep(0);
+                    if (FD_ISSET((SOCKET)osfd, &ex))
+                    {
+                        len = sizeof(err);
+                        if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
+                                (char *) &err, &len) == SOCKET_ERROR)
+                        {  
+                            _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
+                            return -1;
+                        }
+                        if (err != 0)
+                            _PR_MD_MAP_CONNECT_ERROR(err);
+                        else
+                            PR_SetError(PR_UNKNOWN_ERROR, 0);
+                        return -1;
+                    }
+                    if (FD_ISSET((SOCKET)osfd, &rd_wr))
+                    {
+                        /* it's connected */
+                        return 1;
+                    }
+                    PR_ASSERT(0);
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+            } while (rv == 0);
+            break;
+        default:
+            remaining = timeout;
+            FD_ZERO(&rd_wr);
+            FD_ZERO(&ex);
+            do {
+                /*
+                 * We block in _MD_SELECT for at most
+                 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
+                 * so that there is an upper limit on the delay
+                 * before the interrupt bit is checked.
+                 */
+                wait_for_remaining = PR_TRUE;
+                tv.tv_sec = PR_IntervalToSeconds(remaining);
+                if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
+                    wait_for_remaining = PR_FALSE;
+                    tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
+                    tv.tv_usec = 0;
+                } else {
+                    tv.tv_usec = PR_IntervalToMicroseconds(
+                        remaining -
+                        PR_SecondsToInterval(tv.tv_sec));
+                }
+                FD_SET(osfd, &rd_wr);
+                FD_SET(osfd, &ex);
+                switch( fd_type )
+                {
+                    case READ_FD:
+                        rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
+                        break;
+                    case WRITE_FD:
+                        rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
+                        break;
+                    case CONNECT_FD:
+                        rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
+                        break;
+                    default:
+                        PR_ASSERT(0);
+                        break;
+                } /* end switch() */
+                if (rv == -1)
+                {
+                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                    break;
+                }
+                if ( rv > 0 && fd_type == CONNECT_FD )
+                {
+                    /*
+                     * Call Sleep(0) to work around a Winsock timing bug.
+                     */
+                    Sleep(0);
+                    if (FD_ISSET((SOCKET)osfd, &ex))
+                    {
+                        len = sizeof(err);
+                        if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
+                                (char *) &err, &len) == SOCKET_ERROR)
+                        {  
+                            _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
+                            return -1;
+                        }
+                        if (err != 0)
+                            _PR_MD_MAP_CONNECT_ERROR(err);
+                        else
+                            PR_SetError(PR_UNKNOWN_ERROR, 0);
+                        return -1;
+                    }
+                    if (FD_ISSET((SOCKET)osfd, &rd_wr))
+                    {
+                        /* it's connected */
+                        return 1;
+                    }
+                    PR_ASSERT(0);
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+                /*
+                 * We loop again if _MD_SELECT timed out and the
+                 * timeout deadline has not passed yet.
+                 */
+                if (rv == 0 )
+                {
+                    if (wait_for_remaining) {
+                        elapsed = remaining;
+                    } else {
+                        elapsed = PR_SecondsToInterval(tv.tv_sec) 
+                                    + PR_MicrosecondsToInterval(tv.tv_usec);
+                    }
+                    if (elapsed >= remaining) {
+                        PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                        rv = -1;
+                        break;
+                    } else {
+                        remaining = remaining - elapsed;
+                    }
+                }
+            } while (rv == 0 );
+            break;
+    }
+    return(rv);
+} /* end socket_io_wait() */
diff --git a/mozilla/nsprpub/pr/src/md/windows/w95thred.c b/mozilla/nsprpub/pr/src/md/windows/w95thred.c
new file mode 100644
index 0000000..93dfd46
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/w95thred.c
@@ -0,0 +1,423 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#include <process.h>  /* for _beginthreadex() */
+
+#if _MSC_VER <= 1200
+/*
+ * VC++ 6.0 doesn't have DWORD_PTR.
+ */
+
+typedef DWORD DWORD_PTR;
+#endif /* _MSC_VER <= 1200 */
+
+/* --- globals ------------------------------------------------ */
+#ifdef _PR_USE_STATIC_TLS
+__declspec(thread) struct PRThread  *_pr_thread_last_run;
+__declspec(thread) struct PRThread  *_pr_currentThread;
+__declspec(thread) struct _PRCPU    *_pr_currentCPU;
+#else
+DWORD _pr_currentThreadIndex;
+DWORD _pr_lastThreadIndex;
+DWORD _pr_currentCPUIndex;
+#endif
+int                           _pr_intsOff = 0; 
+_PRInterruptTable             _pr_interruptTable[] = { { 0 } };
+
+void
+_PR_MD_EARLY_INIT()
+{
+#ifndef _PR_USE_STATIC_TLS
+    _pr_currentThreadIndex = TlsAlloc();
+    _pr_lastThreadIndex = TlsAlloc();
+    _pr_currentCPUIndex = TlsAlloc();
+#endif
+}
+
+void _PR_MD_CLEANUP_BEFORE_EXIT(void)
+{
+    _PR_NT_FreeSids();
+
+    _PR_MD_CleanupSockets();
+
+    WSACleanup();
+
+#ifndef _PR_USE_STATIC_TLS
+    TlsFree(_pr_currentThreadIndex);
+    TlsFree(_pr_lastThreadIndex);
+    TlsFree(_pr_currentCPUIndex);
+#endif
+}
+
+PRStatus
+_PR_MD_INIT_THREAD(PRThread *thread)
+{
+    if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
+        /*
+        ** Warning:
+        ** --------
+        ** NSPR requires a real handle to every thread.
+        ** GetCurrentThread() returns a pseudo-handle which
+        ** is not suitable for some thread operations (e.g.,
+        ** suspending).  Therefore, get a real handle from
+        ** the pseudo handle via DuplicateHandle(...)
+        */
+        DuplicateHandle(
+                GetCurrentProcess(),     /* Process of source handle */
+                GetCurrentThread(),      /* Pseudo Handle to dup */
+                GetCurrentProcess(),     /* Process of handle */
+                &(thread->md.handle),    /* resulting handle */
+                0L,                      /* access flags */
+                FALSE,                   /* Inheritable */
+                DUPLICATE_SAME_ACCESS);  /* Options */
+    }
+
+    /* Create the blocking IO semaphore */
+    thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL);
+    if (thread->md.blocked_sema == NULL)
+        return PR_FAILURE;
+	else
+		return PR_SUCCESS;
+}
+
+static unsigned __stdcall
+pr_root(void *arg)
+{
+    PRThread *thread = (PRThread *)arg;
+    thread->md.start(thread);
+    return 0;
+}
+
+PRStatus 
+_PR_MD_CREATE_THREAD(PRThread *thread, 
+                  void (*start)(void *), 
+                  PRThreadPriority priority, 
+                  PRThreadScope scope, 
+                  PRThreadState state, 
+                  PRUint32 stackSize)
+{
+
+    thread->md.start = start;
+    thread->md.handle = (HANDLE) _beginthreadex(
+                    NULL,
+                    thread->stack->stackSize,
+                    pr_root,
+                    (void *)thread,
+                    CREATE_SUSPENDED,
+                    &(thread->id));
+    if(!thread->md.handle) {
+        return PR_FAILURE;
+    }
+
+    thread->md.id = thread->id;
+    /*
+     * On windows, a thread is created with a thread priority of
+     * THREAD_PRIORITY_NORMAL.
+     */
+    if (priority != PR_PRIORITY_NORMAL) {
+        _PR_MD_SET_PRIORITY(&(thread->md), priority);
+    }
+
+    /* Activate the thread */
+    if ( ResumeThread( thread->md.handle ) != -1)
+        return PR_SUCCESS;
+
+    return PR_FAILURE;
+}
+
+void    
+_PR_MD_YIELD(void)
+{
+    /* Can NT really yield at all? */
+    Sleep(0);
+}
+
+void     
+_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri)
+{
+    int nativePri;
+    BOOL rv;
+
+    if (newPri < PR_PRIORITY_FIRST) {
+        newPri = PR_PRIORITY_FIRST;
+    } else if (newPri > PR_PRIORITY_LAST) {
+        newPri = PR_PRIORITY_LAST;
+    }
+    switch (newPri) {
+        case PR_PRIORITY_LOW:
+            nativePri = THREAD_PRIORITY_BELOW_NORMAL;
+            break;
+        case PR_PRIORITY_NORMAL:
+            nativePri = THREAD_PRIORITY_NORMAL;
+            break;
+        case PR_PRIORITY_HIGH:
+            nativePri = THREAD_PRIORITY_ABOVE_NORMAL;
+            break;
+        case PR_PRIORITY_URGENT:
+            nativePri = THREAD_PRIORITY_HIGHEST;
+    }
+    rv = SetThreadPriority(thread->handle, nativePri);
+    PR_ASSERT(rv);
+    if (!rv) {
+	PR_LOG(_pr_thread_lm, PR_LOG_MIN,
+                ("PR_SetThreadPriority: can't set thread priority\n"));
+    }
+    return;
+}
+
+void
+_PR_MD_CLEAN_THREAD(PRThread *thread)
+{
+    BOOL rv;
+
+    if (thread->md.blocked_sema) {
+        rv = CloseHandle(thread->md.blocked_sema);
+        PR_ASSERT(rv);
+        thread->md.blocked_sema = 0;
+    }
+
+    if (thread->md.handle) {
+        rv = CloseHandle(thread->md.handle);
+        PR_ASSERT(rv);
+        thread->md.handle = 0;
+    }
+}
+
+void
+_PR_MD_EXIT_THREAD(PRThread *thread)
+{
+    _PR_MD_CLEAN_THREAD(thread);
+    _PR_MD_SET_CURRENT_THREAD(NULL);
+}
+
+
+void
+_PR_MD_EXIT(PRIntn status)
+{
+    _exit(status);
+}
+
+PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask )
+{
+#ifdef WINCE
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return -1;
+#else
+    DWORD_PTR rv;
+
+    rv = SetThreadAffinityMask(thread->md.handle, mask);
+
+    return rv?0:-1;
+#endif
+}
+
+PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask)
+{
+#ifdef WINCE
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return -1;
+#else
+    BOOL rv;
+    DWORD_PTR process_mask;
+    DWORD_PTR system_mask;
+
+    rv = GetProcessAffinityMask(GetCurrentProcess(),
+            &process_mask, &system_mask);
+    if (rv)
+        *mask = (PRUint32)process_mask;
+
+    return rv?0:-1;
+#endif
+}
+
+void 
+_PR_MD_SUSPEND_CPU(_PRCPU *cpu) 
+{
+    _PR_MD_SUSPEND_THREAD(cpu->thread);
+}
+
+void
+_PR_MD_RESUME_CPU(_PRCPU *cpu)
+{
+    _PR_MD_RESUME_THREAD(cpu->thread);
+}
+
+void
+_PR_MD_SUSPEND_THREAD(PRThread *thread)
+{
+    if (_PR_IS_NATIVE_THREAD(thread)) {
+        DWORD previousSuspendCount;
+        /* XXXMB - SuspendThread() is not a blocking call; how do we
+         * know when the thread is *REALLY* suspended?
+         */
+        previousSuspendCount = SuspendThread(thread->md.handle);
+        PR_ASSERT(previousSuspendCount == 0);
+    }
+}
+
+void
+_PR_MD_RESUME_THREAD(PRThread *thread)
+{
+    if (_PR_IS_NATIVE_THREAD(thread)) {
+        DWORD previousSuspendCount;
+        previousSuspendCount = ResumeThread(thread->md.handle);
+        PR_ASSERT(previousSuspendCount == 1);
+    }
+}
+
+PRThread*
+_MD_CURRENT_THREAD(void)
+{
+PRThread *thread;
+
+	thread = _MD_GET_ATTACHED_THREAD();
+
+   	if (NULL == thread) {
+		thread = _PRI_AttachThread(
+            PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
+	}
+	PR_ASSERT(thread != NULL);
+	return thread;
+}
+
+// The following code is from Chromium src/base/thread_local_storage_win.cc,
+// r11329.
+
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives.  So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from http://www.codeproject.com/threads/tls.asp
+// and it works for VC++ 7.0 and later.
+
+#ifdef _WIN64
+
+// This makes the linker create the TLS directory if it's not already
+// there.  (e.g. if __declspec(thread) is not used).
+#pragma comment(linker, "/INCLUDE:_tls_used")
+
+#else  // _WIN64
+
+// This makes the linker create the TLS directory if it's not already
+// there.  (e.g. if __declspec(thread) is not used).
+#pragma comment(linker, "/INCLUDE:__tls_used")
+
+#endif  // _WIN64
+
+// Static callback function to call with each thread termination.
+static void NTAPI PR_OnThreadExit(PVOID module, DWORD reason, PVOID reserved)
+{
+PRThread *me;
+
+    switch (reason) {
+        case DLL_PROCESS_ATTACH:
+            break;
+        case DLL_THREAD_ATTACH:
+            break;
+        case DLL_THREAD_DETACH:
+            if (_pr_initialized) {
+                me = _MD_GET_ATTACHED_THREAD();
+                if ((me != NULL) && (me->flags & _PR_ATTACHED))
+                    _PRI_DetachThread();
+            }
+            break;
+        case DLL_PROCESS_DETACH:
+            break;
+    }
+}
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// By implicitly loaded, I mean that it is directly referenced by the main EXE
+// or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
+// implicitly loaded.
+//
+// See VC\crt\src\tlssup.c for reference.
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it. If this value is discarded, the PR_OnThreadExit
+// function will never be called.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback;
+const PIMAGE_TLS_CALLBACK p_thread_callback = PR_OnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+
+#else  // _WIN64
+
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback = PR_OnThreadExit;
+
+// Reset the default section.
+#pragma data_seg()
+
+#endif  // _WIN64
diff --git a/mozilla/nsprpub/pr/src/md/windows/win32_errors.c b/mozilla/nsprpub/pr/src/md/windows/win32_errors.c
new file mode 100644
index 0000000..ced1b7a
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/md/windows/win32_errors.c
@@ -0,0 +1,565 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "prerror.h"
+#include "prlog.h"
+#include <errno.h>
+#include <windows.h>
+
+/*
+ * On Win32, we map three kinds of error codes:
+ * - GetLastError(): for Win32 functions
+ * - WSAGetLastError(): for Winsock functions
+ * - errno: for standard C library functions
+ * 
+ * GetLastError() and WSAGetLastError() return error codes in
+ * non-overlapping ranges, so their error codes (ERROR_* and
+ * WSAE*) can be mapped by the same function.  On the other hand,
+ * errno and GetLastError() have overlapping ranges, so we need
+ * to use a separate function to map errno.
+ *
+ * We do not check for WSAEINPROGRESS and WSAEINTR because we do not
+ * use blocking Winsock 1.1 calls.
+ *
+ * Except for the 'socket' call, we do not check for WSAEINITIALISED.
+ * It is assumed that if Winsock is not initialized, that fact will
+ * be detected at the time we create new sockets.
+ */
+
+static void _MD_win32_map_default_errno(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case EACCES:
+            prError = PR_NO_ACCESS_RIGHTS_ERROR;
+            break;
+        case ENOENT:
+            prError = PR_FILE_NOT_FOUND_ERROR;
+            break;
+        default:
+            prError = PR_UNKNOWN_ERROR;
+            break;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_default_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case ERROR_ACCESS_DENIED:
+            prError = PR_NO_ACCESS_RIGHTS_ERROR;
+            break;
+        case ERROR_ALREADY_EXISTS:
+            prError = PR_FILE_EXISTS_ERROR;
+            break;
+        case ERROR_CALL_NOT_IMPLEMENTED:
+            prError = PR_NOT_IMPLEMENTED_ERROR;
+            break;
+        case ERROR_DISK_CORRUPT:
+            prError = PR_IO_ERROR; 
+            break;
+        case ERROR_DISK_FULL:
+            prError = PR_NO_DEVICE_SPACE_ERROR;
+            break;
+        case ERROR_DISK_OPERATION_FAILED:
+            prError = PR_IO_ERROR;
+            break;
+        case ERROR_DRIVE_LOCKED:
+            prError = PR_FILE_IS_LOCKED_ERROR;
+            break;
+        case ERROR_FILENAME_EXCED_RANGE:
+            prError = PR_NAME_TOO_LONG_ERROR;
+            break;
+        case ERROR_FILE_CORRUPT:
+            prError = PR_IO_ERROR;
+            break;
+        case ERROR_FILE_EXISTS:
+            prError = PR_FILE_EXISTS_ERROR;
+            break;
+        case ERROR_FILE_INVALID:
+            prError = PR_BAD_DESCRIPTOR_ERROR;
+            break;
+        case ERROR_FILE_NOT_FOUND:
+            prError = PR_FILE_NOT_FOUND_ERROR;
+            break;
+        case ERROR_HANDLE_DISK_FULL:
+            prError = PR_NO_DEVICE_SPACE_ERROR;
+            break;
+        case ERROR_INVALID_ADDRESS:
+            prError = PR_ACCESS_FAULT_ERROR;
+            break;
+        case ERROR_INVALID_HANDLE:
+            prError = PR_BAD_DESCRIPTOR_ERROR;
+            break;
+        case ERROR_INVALID_NAME:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case ERROR_INVALID_PARAMETER:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case ERROR_INVALID_USER_BUFFER:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        case ERROR_LOCKED:
+            prError = PR_FILE_IS_LOCKED_ERROR;
+            break;
+        case ERROR_NETNAME_DELETED:
+            prError = PR_CONNECT_RESET_ERROR;
+            break;
+        case ERROR_NOACCESS:
+            prError = PR_ACCESS_FAULT_ERROR;
+            break;
+        case ERROR_NOT_ENOUGH_MEMORY:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        case ERROR_NOT_ENOUGH_QUOTA:
+            prError = PR_OUT_OF_MEMORY_ERROR;
+            break;
+        case ERROR_NOT_READY:
+            prError = PR_IO_ERROR;
+            break;
+        case ERROR_NO_MORE_FILES:
+            prError = PR_NO_MORE_FILES_ERROR;
+            break;
+        case ERROR_OPEN_FAILED:
+            prError = PR_IO_ERROR;
+            break;
+        case ERROR_OPEN_FILES:
+            prError = PR_IO_ERROR;
+            break;
+        case ERROR_OPERATION_ABORTED:
+            prError = PR_OPERATION_ABORTED_ERROR;
+            break;
+        case ERROR_OUTOFMEMORY:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        case ERROR_PATH_BUSY:
+            prError = PR_IO_ERROR;
+            break;
+        case ERROR_PATH_NOT_FOUND:
+            prError = PR_FILE_NOT_FOUND_ERROR;
+            break;
+        case ERROR_SEEK_ON_DEVICE:
+            prError = PR_IO_ERROR;
+            break;
+        case ERROR_SHARING_VIOLATION:
+            prError = PR_FILE_IS_BUSY_ERROR;
+            break;
+        case ERROR_STACK_OVERFLOW:
+            prError = PR_ACCESS_FAULT_ERROR;
+            break;
+        case ERROR_TOO_MANY_OPEN_FILES:
+            prError = PR_SYS_DESC_TABLE_FULL_ERROR;
+            break;
+        case ERROR_WRITE_PROTECT:
+            prError = PR_NO_ACCESS_RIGHTS_ERROR;
+            break;
+        case WSAEACCES:
+            prError = PR_NO_ACCESS_RIGHTS_ERROR;
+            break;
+        case WSAEADDRINUSE:
+            prError = PR_ADDRESS_IN_USE_ERROR;
+            break;
+        case WSAEADDRNOTAVAIL:
+            prError = PR_ADDRESS_NOT_AVAILABLE_ERROR;
+            break;
+        case WSAEAFNOSUPPORT:
+            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
+            break;
+        case WSAEALREADY:
+            prError = PR_ALREADY_INITIATED_ERROR;
+            break;
+        case WSAEBADF:
+            prError = PR_BAD_DESCRIPTOR_ERROR;
+            break;
+        case WSAECONNABORTED:
+            prError = PR_CONNECT_ABORTED_ERROR;
+            break;
+        case WSAECONNREFUSED:
+            prError = PR_CONNECT_REFUSED_ERROR;
+            break;
+        case WSAECONNRESET:
+            prError = PR_CONNECT_RESET_ERROR;
+            break;
+        case WSAEDESTADDRREQ:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case WSAEFAULT:
+            prError = PR_ACCESS_FAULT_ERROR;
+            break;
+        case WSAEHOSTUNREACH:
+            prError = PR_HOST_UNREACHABLE_ERROR;
+            break;
+        case WSAEINVAL:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case WSAEISCONN:
+            prError = PR_IS_CONNECTED_ERROR;
+            break;
+        case WSAEMFILE:
+            prError = PR_PROC_DESC_TABLE_FULL_ERROR;
+            break;
+        case WSAEMSGSIZE:
+            prError = PR_BUFFER_OVERFLOW_ERROR;
+            break;
+        case WSAENETDOWN:
+            prError = PR_NETWORK_DOWN_ERROR;
+            break;
+        case WSAENETRESET:
+            prError = PR_CONNECT_ABORTED_ERROR;
+            break;
+        case WSAENETUNREACH:
+            prError = PR_NETWORK_UNREACHABLE_ERROR;
+            break;
+        case WSAENOBUFS:
+            prError = PR_INSUFFICIENT_RESOURCES_ERROR;
+            break;
+        case WSAENOPROTOOPT:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case WSAENOTCONN:
+            prError = PR_NOT_CONNECTED_ERROR;
+            break;
+        case WSAENOTSOCK:
+            prError = PR_NOT_SOCKET_ERROR;
+            break;
+        case WSAEOPNOTSUPP:
+            prError = PR_OPERATION_NOT_SUPPORTED_ERROR;
+            break;
+        case WSAEPROTONOSUPPORT:
+            prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR;
+            break;
+        case WSAEPROTOTYPE:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case WSAESHUTDOWN:
+            prError = PR_SOCKET_SHUTDOWN_ERROR;
+            break;
+        case WSAESOCKTNOSUPPORT:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        case WSAETIMEDOUT:
+            prError = PR_CONNECT_ABORTED_ERROR;
+            break;
+        case WSAEWOULDBLOCK:
+            prError = PR_WOULD_BLOCK_ERROR;
+            break;
+        default:
+            prError = PR_UNKNOWN_ERROR;
+            break;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_opendir_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_closedir_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_unix_readdir_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_delete_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+/* The error code for stat() is in errno. */
+void _MD_win32_map_stat_error(PRInt32 err)
+{
+    _MD_win32_map_default_errno(err);
+}
+
+void _MD_win32_map_fstat_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_rename_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+/* The error code for access() is in errno. */
+void _MD_win32_map_access_error(PRInt32 err)
+{
+    _MD_win32_map_default_errno(err);
+}
+
+void _MD_win32_map_mkdir_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_rmdir_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_read_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_transmitfile_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_write_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_lseek_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_fsync_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+/*
+ * For both CloseHandle() and closesocket().
+ */
+void _MD_win32_map_close_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_socket_error(PRInt32 err)
+{
+    PR_ASSERT(err != WSANOTINITIALISED);
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_recv_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_recvfrom_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_send_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAEMSGSIZE:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_sendto_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAEMSGSIZE:
+            prError = PR_INVALID_ARGUMENT_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_accept_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAEOPNOTSUPP:
+            prError = PR_NOT_TCP_SOCKET_ERROR;
+            break;
+        case WSAEINVAL:
+            prError = PR_INVALID_STATE_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_acceptex_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_connect_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAEWOULDBLOCK:
+            prError = PR_IN_PROGRESS_ERROR;
+            break;
+        case WSAEINVAL:
+            prError = PR_ALREADY_INITIATED_ERROR;
+            break;
+        case WSAETIMEDOUT:
+            prError = PR_IO_TIMEOUT_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_bind_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAEINVAL:
+            prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_listen_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAEOPNOTSUPP:
+            prError = PR_NOT_TCP_SOCKET_ERROR;
+            break;
+        case WSAEINVAL:
+            prError = PR_INVALID_STATE_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_shutdown_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_getsockname_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAEINVAL:
+            prError = PR_INVALID_STATE_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_getpeername_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_getsockopt_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_setsockopt_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_open_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+void _MD_win32_map_gethostname_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
+
+/* Win32 select() only works on sockets.  So in this
+** context, WSAENOTSOCK is equivalent to EBADF on Unix.  
+*/
+void _MD_win32_map_select_error(PRInt32 err)
+{
+    PRErrorCode prError;
+
+    switch (err) {
+        case WSAENOTSOCK:
+            prError = PR_BAD_DESCRIPTOR_ERROR;
+            break;
+        default:
+            _MD_win32_map_default_error(err);
+            return;
+    }
+    PR_SetError(prError, err);
+}
+
+void _MD_win32_map_lockf_error(PRInt32 err)
+{
+    _MD_win32_map_default_error(err);
+}
diff --git a/mozilla/nsprpub/pr/src/memory/prseg.c b/mozilla/nsprpub/pr/src/memory/prseg.c
new file mode 100644
index 0000000..14de666
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/memory/prseg.c
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#if defined(_PR_PTHREADS)
+
+/*
+** The pthreads version doesn't use these functions.
+*/
+void _PR_InitSegs(void)
+{
+}
+
+#else /* _PR_PTHREADS */
+
+void _PR_InitSegs(void)
+{
+	_PR_MD_INIT_SEGS();
+}
+
+/*
+** Allocate a memory segment. The size value is rounded up to the native
+** system page size and a page aligned portion of memory is returned.
+** This memory is not part of the malloc heap. If "vaddr" is not NULL
+** then PR tries to allocate the segment at the desired virtual address.
+*/
+PRSegment* _PR_NewSegment(PRUint32 size, void *vaddr)
+{
+    PRSegment *seg;
+
+	/* calloc the data structure for the segment */
+    seg = PR_NEWZAP(PRSegment);
+
+    if (seg) {
+	    size = ((size + _pr_pageSize - 1) >> _pr_pageShift) << _pr_pageShift;
+		/*
+		**	Now, allocate the actual segment memory (or map under some OS)
+		**	The OS specific code decides from where or how to allocate memory.
+		*/
+	    if (_PR_MD_ALLOC_SEGMENT(seg, size, vaddr) != PR_SUCCESS) {
+			PR_DELETE(seg);
+			return NULL;
+    	}
+	}
+
+    return seg;
+}
+
+/*
+** Free a memory segment.
+*/
+void _PR_DestroySegment(PRSegment *seg)
+{
+	_PR_MD_FREE_SEGMENT(seg);
+    PR_DELETE(seg);
+}
+
+#endif /* _PR_PTHREADS */
diff --git a/mozilla/nsprpub/pr/src/memory/prshm.c b/mozilla/nsprpub/pr/src/memory/prshm.c
new file mode 100644
index 0000000..ac63395
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/memory/prshm.c
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** prshm.c -- NSPR Named Shared Memory
+**
+** lth. Jul-1999.
+*/
+#include <string.h>
+#include "primpl.h"
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+
+#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+/* SysV implementation is in pr/src/md/unix/uxshm.c */
+#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+/* Posix implementation is in pr/src/md/unix/uxshm.c */
+#elif defined PR_HAVE_WIN32_NAMED_SHARED_MEMORY
+/* Win32 implementation is in pr/src/md/windows/w32shm.c */
+#else 
+/* 
+**  there is no named_shared_memory 
+*/
+extern PRSharedMemory*  _MD_OpenSharedMemory( const char *name, PRSize size, PRIntn flags, PRIntn mode )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}    
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}    
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}    
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}    
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}    
+#endif /* HAVE_SYSV_NAMED_SHARED_MEMORY */
+
+/*
+** FUNCTION: PR_OpenSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRSharedMemory * )
+    PR_OpenSharedMemory(
+        const char *name,
+        PRSize      size,
+        PRIntn      flags,
+        PRIntn      mode
+)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    return( _PR_MD_OPEN_SHARED_MEMORY( name, size, flags, mode ));
+} /* end PR_OpenSharedMemory() */
+
+/*
+** FUNCTION: PR_AttachSharedMemory()
+**
+*/
+PR_IMPLEMENT( void * )
+    PR_AttachSharedMemory(
+        PRSharedMemory *shm,
+        PRIntn          flags
+)
+{
+    return( _PR_MD_ATTACH_SHARED_MEMORY( shm, flags ));
+} /* end PR_AttachSharedMemory() */
+
+/*
+** FUNCTION: PR_DetachSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRStatus )
+    PR_DetachSharedMemory(
+        PRSharedMemory *shm,
+        void *addr
+)
+{
+    return( _PR_MD_DETACH_SHARED_MEMORY( shm, addr ));
+} /* end PR_DetachSharedMemory() */
+
+/*
+** FUNCTION: PR_CloseSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRStatus )
+    PR_CloseSharedMemory(
+        PRSharedMemory *shm
+)
+{
+    return( _PR_MD_CLOSE_SHARED_MEMORY( shm ));
+} /* end PR_CloseSharedMemory() */
+
+/*
+** FUNCTION: PR_DeleteSharedMemory()
+**
+*/
+PR_EXTERN( PRStatus )
+    PR_DeleteSharedMemory(
+        const char *name
+)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    return(_PR_MD_DELETE_SHARED_MEMORY( name ));
+} /* end PR_DestroySharedMemory() */
+/* end prshm.c */
diff --git a/mozilla/nsprpub/pr/src/memory/prshma.c b/mozilla/nsprpub/pr/src/memory/prshma.c
new file mode 100644
index 0000000..fbc2257
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/memory/prshma.c
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** prshma.h -- NSPR Anonymous Shared Memory
+**
+** 
+*/
+
+#include "primpl.h"
+
+extern PRLogModuleInfo *_pr_shma_lm;
+
+#if defined(XP_UNIX)
+/* defined in pr/src/md/unix/uxshm.c */
+#elif defined(WIN32)
+/* defined in pr/src/md/windows/w32shm.c */
+#else
+extern PRFileMap * _PR_MD_OPEN_ANON_FILE_MAP( const char *dirName, PRSize size, PRFileMapProtect prot )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+extern PRStatus _PR_MD_EXPORT_FILE_MAP_AS_STRING(PRFileMap *fm, PRSize bufSize, char *buf)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+extern PRFileMap * _PR_MD_IMPORT_FILE_MAP_FROM_STRING(const char *fmstring)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+#endif
+
+/*
+** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory
+**
+*/
+PR_IMPLEMENT(PRFileMap*)
+PR_OpenAnonFileMap(
+    const char *dirName,
+    PRSize      size, 
+    PRFileMapProtect prot
+)
+{
+    return(_PR_MD_OPEN_ANON_FILE_MAP( dirName, size, prot ));
+} /* end PR_OpenAnonFileMap() */
+
+/*
+** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export  
+**   to my children processes via PR_CreateProcess()
+**
+**
+*/
+PR_IMPLEMENT( PRStatus) 
+PR_ProcessAttrSetInheritableFileMap( 
+    PRProcessAttr   *attr,
+    PRFileMap       *fm, 
+    const char      *shmname
+)
+{
+    PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+    return( PR_FAILURE);
+} /* end PR_ProcessAttrSetInheritableFileMap() */ 
+
+/*
+** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported
+**   by my parent process via PR_CreateProcess()
+**
+*/
+PR_IMPLEMENT( PRFileMap *)
+PR_GetInheritedFileMap( 
+    const char *shmname 
+)
+{
+    PRFileMap   *fm = NULL;
+    PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+    return( fm );
+} /* end PR_GetInhteritedFileMap() */
+
+/*
+** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap
+**
+*/
+PR_IMPLEMENT( PRStatus )
+PR_ExportFileMapAsString( 
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+)
+{
+    return( _PR_MD_EXPORT_FILE_MAP_AS_STRING( fm, bufSize, buf ));
+} /* end PR_ExportFileMapAsString() */
+
+/*
+** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string
+**
+**
+*/
+PR_IMPLEMENT( PRFileMap * )
+PR_ImportFileMapFromString( 
+    const char *fmstring
+)
+{
+    return( _PR_MD_IMPORT_FILE_MAP_FROM_STRING(fmstring));
+} /* end PR_ImportFileMapFromString() */
+/* end prshma.c */
diff --git a/mozilla/nsprpub/pr/src/misc/pralarm.c b/mozilla/nsprpub/pr/src/misc/pralarm.c
new file mode 100644
index 0000000..932d077
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/pralarm.c
@@ -0,0 +1,278 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+/**********************************************************************/
+/******************************* PRALARM ******************************/
+/**********************************************************************/
+
+#include "obsolete/pralarm.h"
+
+struct PRAlarmID {                       /* typedef'd in pralarm.h       */
+    PRCList list;                        /* circular list linkage        */
+    PRAlarm *alarm;                      /* back pointer to owning alarm */
+    PRPeriodicAlarmFn function;          /* function to call for notify  */
+    void *clientData;                    /* opaque client context        */
+    PRIntervalTime period;               /* the client defined period    */
+    PRUint32 rate;                       /* rate of notification         */
+
+    PRUint32 accumulator;                /* keeps track of # notifies    */
+    PRIntervalTime epoch;                /* when timer was started       */
+    PRIntervalTime nextNotify;           /* when we'll next do our thing */
+    PRIntervalTime lastNotify;           /* when we last did our thing   */
+};
+
+typedef enum {alarm_active, alarm_inactive} _AlarmState;
+
+struct PRAlarm {                         /* typedef'd in pralarm.h       */
+    PRCList timers;                      /* base of alarm ids list       */
+    PRLock *lock;                        /* lock used to protect data    */
+    PRCondVar *cond;                     /* condition that used to wait  */
+    PRThread *notifier;                  /* thread to deliver notifies   */
+    PRAlarmID *current;                  /* current alarm being served   */
+    _AlarmState state;                   /* used to delete the alarm     */
+};
+
+static PRAlarmID *pr_getNextAlarm(PRAlarm *alarm, PRAlarmID *id)
+{
+/*
+ * Puts 'id' back into the sorted list iff it's not NULL.
+ * Removes the first element from the list and returns it (or NULL).
+ * List is "assumed" to be short.
+ *
+ * NB: Caller is providing locking
+ */
+    PRCList *timer;
+    PRAlarmID *result = id;
+    PRIntervalTime now = PR_IntervalNow();
+
+    if (!PR_CLIST_IS_EMPTY(&alarm->timers))
+    {    
+        if (id != NULL)  /* have to put this id back in */
+        {        
+            PRIntervalTime idDelta = now - id->nextNotify;
+            timer = alarm->timers.next;
+            do
+            {
+                result = (PRAlarmID*)timer;
+                if ((PRIntervalTime)(now - result->nextNotify) > idDelta)
+                {
+                    PR_INSERT_BEFORE(&id->list, &alarm->timers);
+                    break;
+                }
+                timer = timer->next;
+            } while (timer != &alarm->timers);
+        }
+        result = (PRAlarmID*)(timer = PR_LIST_HEAD(&alarm->timers));
+        PR_REMOVE_LINK(timer);  /* remove it from the list */
+    }
+
+    return result;
+}  /* pr_getNextAlarm */
+
+static PRIntervalTime pr_PredictNextNotifyTime(PRAlarmID *id)
+{
+    PRIntervalTime delta;
+    PRFloat64 baseRate = (PRFloat64)id->period / (PRFloat64)id->rate;
+    PRFloat64 offsetFromEpoch = (PRFloat64)id->accumulator * baseRate;
+
+    id->accumulator += 1;  /* every call advances to next period */
+    id->lastNotify = id->nextNotify;  /* just keeping track of things */
+    id->nextNotify = (PRIntervalTime)(offsetFromEpoch + 0.5);
+
+    delta = id->nextNotify - id->lastNotify;
+    return delta;
+}  /* pr_PredictNextNotifyTime */
+
+static void PR_CALLBACK pr_alarmNotifier(void *arg)
+{
+    /*
+     * This is the root of the notifier thread. There is one such thread
+     * for each PRAlarm. It may service an arbitrary (though assumed to be
+     * small) number of alarms using the same thread and structure. It
+     * continues to run until the alarm is destroyed.
+     */
+    PRAlarmID *id = NULL;
+    PRAlarm *alarm = (PRAlarm*)arg;
+    enum {notify, abort, scan} why = scan;
+
+    while (why != abort)
+    {
+        PRIntervalTime pause;
+
+        PR_Lock(alarm->lock);
+        while (why == scan)
+        {
+            alarm->current = NULL;  /* reset current id */
+            if (alarm->state == alarm_inactive) why = abort;  /* we're toast */
+            else if (why == scan)  /* the dominant case */
+            {
+                id = pr_getNextAlarm(alarm, id);  /* even if it's the same */
+                if (id == NULL)  /* there are no alarms set */
+                    (void)PR_WaitCondVar(alarm->cond, PR_INTERVAL_NO_TIMEOUT);
+                else
+                {
+                    pause = id->nextNotify - (PR_IntervalNow() - id->epoch);
+                    if ((PRInt32)pause <= 0)  /* is this one's time up? */
+                    {
+                        why = notify;  /* set up to do our thing */
+                        alarm->current = id;  /* id we're about to schedule */
+                    }
+                    else
+                        (void)PR_WaitCondVar(alarm->cond, pause);  /* dally */
+                }
+            }
+        }
+        PR_Unlock(alarm->lock);
+
+        if (why == notify)
+        {
+            (void)pr_PredictNextNotifyTime(id);
+            if (!id->function(id, id->clientData, ~pause))
+            {
+                /*
+                 * Notified function decided not to continue. Free
+                 * the alarm id to make sure it doesn't get back on
+                 * the list.
+                 */
+                PR_DELETE(id);  /* free notifier object */
+                id = NULL;  /* so it doesn't get back into the list */
+            }
+            why = scan;  /* so we can cycle through the loop again */
+        }
+    }
+
+}  /* pr_alarm_notifier */
+
+PR_IMPLEMENT(PRAlarm*) PR_CreateAlarm(void)
+{
+    PRAlarm *alarm = PR_NEWZAP(PRAlarm);
+    if (alarm != NULL)
+    {
+        if ((alarm->lock = PR_NewLock()) == NULL) goto done;
+        if ((alarm->cond = PR_NewCondVar(alarm->lock)) == NULL) goto done;
+        alarm->state = alarm_active;
+        PR_INIT_CLIST(&alarm->timers);
+        alarm->notifier = PR_CreateThread(
+            PR_USER_THREAD, pr_alarmNotifier, alarm,
+            PR_GetThreadPriority(PR_GetCurrentThread()),
+            PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+        if (alarm->notifier == NULL) goto done;
+    }
+    return alarm;
+
+done:
+    if (alarm->cond != NULL) PR_DestroyCondVar(alarm->cond);
+    if (alarm->lock != NULL) PR_DestroyLock(alarm->lock);
+    PR_DELETE(alarm);
+    return NULL;
+}  /* CreateAlarm */
+
+PR_IMPLEMENT(PRStatus) PR_DestroyAlarm(PRAlarm *alarm)
+{
+    PRStatus rv;
+
+    PR_Lock(alarm->lock);
+    alarm->state = alarm_inactive;
+    rv = PR_NotifyCondVar(alarm->cond);
+    PR_Unlock(alarm->lock);
+
+    if (rv == PR_SUCCESS)
+        rv = PR_JoinThread(alarm->notifier);
+    if (rv == PR_SUCCESS)
+    {
+        PR_DestroyCondVar(alarm->cond);
+        PR_DestroyLock(alarm->lock);
+        PR_DELETE(alarm);
+    }
+    return rv;
+}  /* PR_DestroyAlarm */
+
+PR_IMPLEMENT(PRAlarmID*) PR_SetAlarm(
+    PRAlarm *alarm, PRIntervalTime period, PRUint32 rate,
+    PRPeriodicAlarmFn function, void *clientData)
+{
+    /*
+     * Create a new periodic alarm an existing current structure.
+     * Set up the context and compute the first notify time (immediate).
+     * Link the new ID into the head of the list (since it's notifying
+     * immediately).
+     */
+
+    PRAlarmID *id = PR_NEWZAP(PRAlarmID);
+
+    if (!id)
+        return NULL;
+
+    id->alarm = alarm;
+    PR_INIT_CLIST(&id->list);
+    id->function = function;
+    id->clientData = clientData;
+    id->period = period;
+    id->rate = rate;
+    id->epoch = id->nextNotify = PR_IntervalNow();
+    (void)pr_PredictNextNotifyTime(id);
+
+    PR_Lock(alarm->lock);
+    PR_INSERT_BEFORE(&id->list, &alarm->timers);
+    PR_NotifyCondVar(alarm->cond);
+    PR_Unlock(alarm->lock);
+
+    return id;
+}  /* PR_SetAlarm */
+
+PR_IMPLEMENT(PRStatus) PR_ResetAlarm(
+    PRAlarmID *id, PRIntervalTime period, PRUint32 rate)
+{
+    /*
+     * Can only be called from within the notify routine. Doesn't
+     * need locking because it can only be called from within the
+     * notify routine.
+     */
+    if (id != id->alarm->current)
+        return PR_FAILURE;
+    id->period = period;
+    id->rate = rate;
+    id->accumulator = 1;
+    id->epoch = PR_IntervalNow();
+    (void)pr_PredictNextNotifyTime(id);
+    return PR_SUCCESS;
+}  /* PR_ResetAlarm */
+
+
+
diff --git a/mozilla/nsprpub/pr/src/misc/pratom.c b/mozilla/nsprpub/pr/src/misc/pratom.c
new file mode 100644
index 0000000..35b86c0
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/pratom.c
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+**     PR Atomic operations
+*/
+
+
+#include "pratom.h"
+#include "primpl.h"
+
+#include <string.h>
+
+/*
+ * The following is a fallback implementation that emulates
+ * atomic operations for platforms without atomic operations.
+ * If a platform has atomic operations, it should define the
+ * macro _PR_HAVE_ATOMIC_OPS, and the following will not be
+ * compiled in.
+ */
+
+#if !defined(_PR_HAVE_ATOMIC_OPS)
+
+#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
+/*
+ * PR_AtomicDecrement() is used in NSPR's thread-specific data
+ * destructor.  Because thread-specific data destructors may be
+ * invoked after a PR_Cleanup() call, we need an implementation
+ * of the atomic routines that doesn't need NSPR to be initialized.
+ */
+
+/*
+ * We use a set of locks for all the emulated atomic operations.
+ * By hashing on the address of the integer to be locked the
+ * contention between multiple threads should be lessened.
+ *
+ * The number of atomic locks can be set by the environment variable
+ * NSPR_ATOMIC_HASH_LOCKS
+ */
+
+/*
+ * lock counts should be a power of 2
+ */
+#define DEFAULT_ATOMIC_LOCKS	16	/* should be in sync with the number of initializers
+										below */
+#define MAX_ATOMIC_LOCKS		(4 * 1024)
+
+static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = {
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
+        PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
+
+#ifdef DEBUG
+static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS];
+static PRInt32 *hash_lock_counts = static_hash_lock_counts;
+#endif
+
+static PRUint32	num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
+static pthread_mutex_t *atomic_locks = static_atomic_locks;
+static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1;
+
+#define _PR_HASH_FOR_LOCK(ptr) 							\
+			((PRUint32) (((PRUptrdiff) (ptr) >> 2)	^	\
+						((PRUptrdiff) (ptr) >> 8)) &	\
+						atomic_hash_mask)
+
+void _PR_MD_INIT_ATOMIC()
+{
+char *eval;
+int index;
+
+
+	PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) ==
+						PR_CeilingLog2(MAX_ATOMIC_LOCKS));
+
+	PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) ==
+							PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS));
+
+	if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL)  &&
+		((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) {
+
+		if (num_atomic_locks > MAX_ATOMIC_LOCKS)
+			num_atomic_locks = MAX_ATOMIC_LOCKS;
+		else if (num_atomic_locks < 1) 
+			num_atomic_locks = 1;
+		else {
+			num_atomic_locks = PR_FloorLog2(num_atomic_locks);
+			num_atomic_locks = 1L << num_atomic_locks;
+		}
+		atomic_locks = (pthread_mutex_t *) PR_Malloc(sizeof(pthread_mutex_t) *
+						num_atomic_locks);
+		if (atomic_locks) {
+			for (index = 0; index < num_atomic_locks; index++) {
+				if (pthread_mutex_init(&atomic_locks[index], NULL)) {
+						PR_DELETE(atomic_locks);
+						atomic_locks = NULL;
+						break; 
+				}
+			}
+		}
+#ifdef DEBUG
+		if (atomic_locks) {
+			hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32));
+			if (hash_lock_counts == NULL) {
+				PR_DELETE(atomic_locks);
+				atomic_locks = NULL;
+			}
+		}
+#endif
+		if (atomic_locks == NULL) {
+			/*
+			 *	Use statically allocated locks
+			 */
+			atomic_locks = static_atomic_locks;
+			num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
+	#ifdef DEBUG
+			hash_lock_counts = static_hash_lock_counts;
+	#endif
+		}
+		atomic_hash_mask = num_atomic_locks - 1;
+	}
+	PR_ASSERT(PR_FloorLog2(num_atomic_locks) ==
+								PR_CeilingLog2(num_atomic_locks));
+}
+
+PRInt32
+_PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
+{
+    PRInt32 rv;
+    PRInt32 idx = _PR_HASH_FOR_LOCK(val);
+
+    pthread_mutex_lock(&atomic_locks[idx]);
+    rv = ++(*val);
+#ifdef DEBUG
+    hash_lock_counts[idx]++;
+#endif
+    pthread_mutex_unlock(&atomic_locks[idx]);
+    return rv;
+}
+
+PRInt32
+_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
+{
+    PRInt32 rv;
+    PRInt32 idx = _PR_HASH_FOR_LOCK(ptr);
+
+    pthread_mutex_lock(&atomic_locks[idx]);
+    rv = ((*ptr) += val);
+#ifdef DEBUG
+    hash_lock_counts[idx]++;
+#endif
+    pthread_mutex_unlock(&atomic_locks[idx]);
+    return rv;
+}
+
+PRInt32
+_PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
+{
+    PRInt32 rv;
+    PRInt32 idx = _PR_HASH_FOR_LOCK(val);
+
+    pthread_mutex_lock(&atomic_locks[idx]);
+    rv = --(*val);
+#ifdef DEBUG
+    hash_lock_counts[idx]++;
+#endif
+    pthread_mutex_unlock(&atomic_locks[idx]);
+    return rv;
+}
+
+PRInt32
+_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
+{
+    PRInt32 rv;
+    PRInt32 idx = _PR_HASH_FOR_LOCK(val);
+
+    pthread_mutex_lock(&atomic_locks[idx]);
+    rv = *val;
+    *val = newval;
+#ifdef DEBUG
+    hash_lock_counts[idx]++;
+#endif
+    pthread_mutex_unlock(&atomic_locks[idx]);
+    return rv;
+}
+#else  /* _PR_PTHREADS && !_PR_DCETHREADS */
+/*
+ * We use a single lock for all the emulated atomic operations.
+ * The lock contention should be acceptable.
+ */
+static PRLock *atomic_lock = NULL;
+void _PR_MD_INIT_ATOMIC(void)
+{
+    if (atomic_lock == NULL) {
+        atomic_lock = PR_NewLock();
+    }
+}
+
+PRInt32
+_PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
+{
+    PRInt32 rv;
+
+    if (!_pr_initialized) {
+        _PR_ImplicitInitialization();
+    }
+    PR_Lock(atomic_lock);
+    rv = ++(*val);
+    PR_Unlock(atomic_lock);
+    return rv;
+}
+
+PRInt32
+_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
+{
+    PRInt32 rv;
+
+    if (!_pr_initialized) {
+        _PR_ImplicitInitialization();
+    }
+    PR_Lock(atomic_lock);
+    rv = ((*ptr) += val);
+    PR_Unlock(atomic_lock);
+    return rv;
+}
+
+PRInt32
+_PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
+{
+    PRInt32 rv;
+
+    if (!_pr_initialized) {
+        _PR_ImplicitInitialization();
+    }
+    PR_Lock(atomic_lock);
+    rv = --(*val);
+    PR_Unlock(atomic_lock);
+    return rv;
+}
+
+PRInt32
+_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
+{
+    PRInt32 rv;
+
+    if (!_pr_initialized) {
+        _PR_ImplicitInitialization();
+    }
+    PR_Lock(atomic_lock);
+    rv = *val;
+    *val = newval;
+    PR_Unlock(atomic_lock);
+    return rv;
+}
+#endif  /* _PR_PTHREADS && !_PR_DCETHREADS */
+
+#endif  /* !_PR_HAVE_ATOMIC_OPS */
+
+void _PR_InitAtomic(void)
+{
+    _PR_MD_INIT_ATOMIC();
+}
+
+PR_IMPLEMENT(PRInt32)
+PR_AtomicIncrement(PRInt32 *val)
+{
+    return _PR_MD_ATOMIC_INCREMENT(val);
+}
+
+PR_IMPLEMENT(PRInt32)
+PR_AtomicDecrement(PRInt32 *val)
+{
+    return _PR_MD_ATOMIC_DECREMENT(val);
+}
+
+PR_IMPLEMENT(PRInt32)
+PR_AtomicSet(PRInt32 *val, PRInt32 newval)
+{
+    return _PR_MD_ATOMIC_SET(val, newval);
+}
+
+PR_IMPLEMENT(PRInt32)
+PR_AtomicAdd(PRInt32 *ptr, PRInt32 val)
+{
+    return _PR_MD_ATOMIC_ADD(ptr, val);
+}
+/*
+ * For platforms, which don't support the CAS (compare-and-swap) instruction
+ * (or an equivalent), the stack operations are implemented by use of PRLock
+ */
+
+PR_IMPLEMENT(PRStack *)
+PR_CreateStack(const char *stack_name)
+{
+PRStack *stack;
+
+    if (!_pr_initialized) {
+        _PR_ImplicitInitialization();
+    }
+
+    if ((stack = PR_NEW(PRStack)) == NULL) {
+		return NULL;
+	}
+	if (stack_name) {
+		stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1);
+		if (stack->prstk_name == NULL) {
+			PR_DELETE(stack);
+			return NULL;
+		}
+		strcpy(stack->prstk_name, stack_name);
+	} else
+		stack->prstk_name = NULL;
+
+#ifndef _PR_HAVE_ATOMIC_CAS
+    stack->prstk_lock = PR_NewLock();
+	if (stack->prstk_lock == NULL) {
+		PR_Free(stack->prstk_name);
+		PR_DELETE(stack);
+		return NULL;
+	}
+#endif /* !_PR_HAVE_ATOMIC_CAS */
+
+	stack->prstk_head.prstk_elem_next = NULL;
+	
+    return stack;
+}
+
+PR_IMPLEMENT(PRStatus)
+PR_DestroyStack(PRStack *stack)
+{
+	if (stack->prstk_head.prstk_elem_next != NULL) {
+		PR_SetError(PR_INVALID_STATE_ERROR, 0);
+		return PR_FAILURE;
+	}
+
+	if (stack->prstk_name)
+		PR_Free(stack->prstk_name);
+#ifndef _PR_HAVE_ATOMIC_CAS
+	PR_DestroyLock(stack->prstk_lock);
+#endif /* !_PR_HAVE_ATOMIC_CAS */
+	PR_DELETE(stack);
+
+	return PR_SUCCESS;
+}
+
+#ifndef _PR_HAVE_ATOMIC_CAS
+
+PR_IMPLEMENT(void)
+PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
+{
+    PR_Lock(stack->prstk_lock);
+	stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next;
+	stack->prstk_head.prstk_elem_next = stack_elem;
+    PR_Unlock(stack->prstk_lock);
+    return;
+}
+
+PR_IMPLEMENT(PRStackElem *)
+PR_StackPop(PRStack *stack)
+{
+PRStackElem *element;
+
+    PR_Lock(stack->prstk_lock);
+	element = stack->prstk_head.prstk_elem_next;
+	if (element != NULL) {
+		stack->prstk_head.prstk_elem_next = element->prstk_elem_next;
+		element->prstk_elem_next = NULL;	/* debugging aid */
+	}
+    PR_Unlock(stack->prstk_lock);
+    return element;
+}
+#endif /* !_PR_HAVE_ATOMIC_CAS */
diff --git a/mozilla/nsprpub/pr/src/misc/praton.c b/mozilla/nsprpub/pr/src/misc/praton.c
new file mode 100644
index 0000000..bff0cd1
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/praton.c
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*******************************************************************************
+ * The following function pr_inet_aton is based on the BSD function inet_aton
+ * with some modifications. The license and copyright notices applying to this
+ * function appear below. Modifications are also according to the license below.
+ ******************************************************************************/
+
+#include "prnetdb.h"
+
+/*
+ * Copyright (c) 1983, 1990, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define XX 127
+static const unsigned char index_hex[256] = {
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+};
+
+static PRBool _isdigit(char c) { return c >= '0' && c <= '9'; }
+static PRBool _isxdigit(char c) { return index_hex[(unsigned char) c] != XX; }
+static PRBool _isspace(char c) { return c == ' ' || (c >= '\t' && c <= '\r'); }
+#undef XX
+
+int
+pr_inet_aton(const char *cp, PRUint32 *addr)
+{
+    PRUint32 val;
+    int base, n;
+    char c;
+    PRUint8 parts[4];
+    PRUint8 *pp = parts;
+    int digit;
+
+    c = *cp;
+    for (;;) {
+        /*
+         * Collect number up to ``.''.
+         * Values are specified as for C:
+         * 0x=hex, 0=octal, isdigit=decimal.
+         */
+        if (!_isdigit(c))
+            return (0);
+        val = 0; base = 10; digit = 0;
+        if (c == '0') {
+            c = *++cp;
+            if (c == 'x' || c == 'X')
+                base = 16, c = *++cp;
+            else {
+                base = 8;
+                digit = 1;
+            }
+        }
+        for (;;) {
+            if (_isdigit(c)) {
+                if (base == 8 && (c == '8' || c == '9'))
+                    return (0);
+                val = (val * base) + (c - '0');
+                c = *++cp;
+                digit = 1;
+            } else if (base == 16 && _isxdigit(c)) {
+                val = (val << 4) + index_hex[(unsigned char) c];
+                c = *++cp;
+                digit = 1;
+            } else
+                break;
+        }
+        if (c == '.') {
+            /*
+             * Internet format:
+             *    a.b.c.d
+             *    a.b.c    (with c treated as 16 bits)
+             *    a.b    (with b treated as 24 bits)
+             */
+            if (pp >= parts + 3 || val > 0xffU)
+                return (0);
+            *pp++ = val;
+            c = *++cp;
+        } else
+            break;
+    }
+    /*
+     * Check for trailing characters.
+     */
+    if (c != '\0' && !_isspace(c))
+        return (0);
+    /*
+     * Did we get a valid digit?
+     */
+    if (!digit)
+        return (0);
+    /*
+     * Concoct the address according to
+     * the number of parts specified.
+     */
+    n = pp - parts + 1;
+    switch (n) {
+    case 1:                /*%< a -- 32 bits */
+        break;
+
+    case 2:                /*%< a.b -- 8.24 bits */
+        if (val > 0xffffffU)
+            return (0);
+        val |= parts[0] << 24;
+        break;
+
+    case 3:                /*%< a.b.c -- 8.8.16 bits */
+        if (val > 0xffffU)
+            return (0);
+        val |= (parts[0] << 24) | (parts[1] << 16);
+        break;
+
+    case 4:                /*%< a.b.c.d -- 8.8.8.8 bits */
+        if (val > 0xffU)
+            return (0);
+        val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+        break;
+    }
+    *addr = PR_htonl(val);
+    return (1);
+}
+
diff --git a/mozilla/nsprpub/pr/src/misc/prcountr.c b/mozilla/nsprpub/pr/src/misc/prcountr.c
new file mode 100644
index 0000000..a4e4f6c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prcountr.c
@@ -0,0 +1,506 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** prcountr.c -- NSPR Instrumentation Counters
+**
+** Implement the interface defined in prcountr.h
+**
+** Design Notes:
+**
+** The Counter Facility (CF) has a single anchor: qNameList.      
+** The anchor is a PRCList. qNameList is a list of links in QName
+** structures. From qNameList any QName structure and its
+** associated RName structure can be located. 
+** 
+** For each QName, a list of RName structures is anchored at
+** rnLink in the QName structure.
+** 
+** The counter itself is embedded in the RName structure.
+** 
+** For manipulating the counter database, single lock is used to
+** protect the entire list: counterLock.
+**
+** A PRCounterHandle, defined in prcountr.h, is really a pointer
+** to a RName structure. References by PRCounterHandle are
+** dead-reconed to the RName structure. The PRCounterHandle is
+** "overloaded" for traversing the QName structures; only the
+** function PR_FindNextQnameHandle() uses this overloading.
+**
+** 
+** ToDo (lth): decide on how to lock or atomically update
+** individual counters. Candidates are: the global lock; a lock
+** per RName structure; Atomic operations (Note that there are
+** not adaquate atomic operations (yet) to achieve this goal). At
+** this writing (6/19/98) , the update of the counter variable in
+** a QName structure is unprotected.
+**
+*/
+
+#include "prcountr.h"
+#include "prclist.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prmem.h"
+#include <string.h>
+
+/*
+**
+*/
+typedef struct QName
+{
+    PRCList link;
+    PRCList rNameList;
+    char    name[PRCOUNTER_NAME_MAX+1];
+} QName;
+
+/*
+**
+*/
+typedef struct RName
+{
+    PRCList link;
+    QName   *qName;
+    PRLock  *lock;
+    volatile PRUint32   counter;    
+    char    name[PRCOUNTER_NAME_MAX+1]; 
+    char    desc[PRCOUNTER_DESC_MAX+1]; 
+} RName;
+
+
+/*
+** Define the Counter Facility database
+*/
+static PRLock  *counterLock;
+static PRCList qNameList;
+static PRLogModuleInfo *lm;
+
+/*
+** _PR_CounterInitialize() -- Initialize the Counter Facility
+**
+*/
+static void _PR_CounterInitialize( void )
+{
+    /*
+    ** This function should be called only once
+    */
+    PR_ASSERT( counterLock == NULL );
+    
+    counterLock = PR_NewLock();
+    PR_INIT_CLIST( &qNameList );
+    lm = PR_NewLogModule("counters");
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete"));
+
+    return;
+} /* end _PR_CounterInitialize() */
+
+/*
+** PR_CreateCounter() -- Create a counter
+**
+**  ValidateArguments
+**  Lock
+**  if (qName not already in database)
+**      NewQname
+**  if (rName already in database )
+**      Assert
+**  else NewRname
+**  NewCounter
+**  link 'em up
+**  Unlock
+**
+*/
+PR_IMPLEMENT(PRCounterHandle) 
+	PR_CreateCounter( 
+		const char *qName, 
+    	const char *rName, 
+        const char *description 
+) 
+{
+    QName   *qnp;
+    RName   *rnp;
+    PRBool  matchQname = PR_FALSE;
+
+    /* Self initialize, if necessary */
+    if ( counterLock == NULL )
+        _PR_CounterInitialize();
+
+    /* Validate input arguments */
+    PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX );
+    PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX );
+    PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX );
+
+    /* Lock the Facility */
+    PR_Lock( counterLock );
+
+    /* Do we already have a matching QName? */
+    if (!PR_CLIST_IS_EMPTY( &qNameList ))
+    {
+        qnp = (QName *) PR_LIST_HEAD( &qNameList );
+        do {
+            if ( strcmp(qnp->name, qName) == 0)
+            {
+                matchQname = PR_TRUE;
+                break;
+            }
+            qnp = (QName *)PR_NEXT_LINK( &qnp->link );
+        } while( qnp != (QName *)PR_LIST_HEAD( &qNameList ));
+    }
+    /*
+    ** If we did not find a matching QName,
+    **    allocate one and initialize it.
+    **    link it onto the qNameList.
+    **
+    */
+    if ( matchQname != PR_TRUE )
+    {
+        qnp = PR_NEWZAP( QName );
+        PR_ASSERT( qnp != NULL );
+        PR_INIT_CLIST( &qnp->link ); 
+        PR_INIT_CLIST( &qnp->rNameList ); 
+        strcpy( qnp->name, qName );
+        PR_APPEND_LINK( &qnp->link, &qNameList ); 
+    }
+
+    /* Do we already have a matching RName? */
+    if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
+    {
+        rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
+        do {
+            /*
+            ** No duplicate RNames are allowed within a QName
+            **
+            */
+            PR_ASSERT( strcmp(rnp->name, rName));
+            rnp = (RName *)PR_NEXT_LINK( &rnp->link );
+        } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList ));
+    }
+
+    /* Get a new RName structure; initialize its members */
+    rnp = PR_NEWZAP( RName );
+    PR_ASSERT( rnp != NULL );
+    PR_INIT_CLIST( &rnp->link );
+    strcpy( rnp->name, rName );
+    strcpy( rnp->desc, description );
+    rnp->lock = PR_NewLock();
+    if ( rnp->lock == NULL )
+    {
+        PR_ASSERT(0);
+    }
+
+    PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */    
+    rnp->qName = qnp;                       /* point the RName to the QName */
+
+    /* Unlock the Facility */
+    PR_Unlock( counterLock );
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t",
+        qName, qnp, rName, rnp ));
+
+    return((PRCounterHandle)rnp);
+} /*  end PR_CreateCounter() */
+  
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_DestroyCounter( 
+		PRCounterHandle handle 
+)
+{
+    RName   *rnp = (RName *)handle;
+    QName   *qnp = rnp->qName;
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s", 
+        qnp->name, rnp->name));
+
+    /* Lock the Facility */
+    PR_Lock( counterLock );
+
+    /*
+    ** Remove RName from the list of RNames in QName
+    ** and free RName
+    */
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting RName: %s, %p", 
+        rnp->name, rnp));
+    PR_REMOVE_LINK( &rnp->link );
+    PR_Free( rnp->lock );
+    PR_DELETE( rnp );
+
+    /*
+    ** If this is the last RName within QName
+    **   remove QName from the qNameList and free it
+    */
+    if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
+    {
+        PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting unused QName: %s, %p", 
+            qnp->name, qnp));
+        PR_REMOVE_LINK( &qnp->link );
+        PR_DELETE( qnp );
+    } 
+
+    /* Unlock the Facility */
+    PR_Unlock( counterLock );
+    return;
+} /*  end PR_DestroyCounter() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRCounterHandle) 
+	PR_GetCounterHandleFromName( 
+    	const char *qName, 
+    	const char *rName 
+)
+{
+    const char    *qn, *rn, *desc;
+    PRCounterHandle     qh, rh = NULL;
+    RName   *rnp = NULL;
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t"
+        "QName: %s, RName: %s", qName, rName ));
+
+    qh = PR_FindNextCounterQname( NULL );
+    while (qh != NULL)
+    {
+        rh = PR_FindNextCounterRname( NULL, qh );
+        while ( rh != NULL )
+        {
+            PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc );
+            if ( (strcmp( qName, qn ) == 0)
+                && (strcmp( rName, rn ) == 0 ))
+            {
+                rnp = (RName *)rh;
+                goto foundIt;
+            }
+            rh = PR_FindNextCounterRname( rh, qh );
+        }
+        qh = PR_FindNextCounterQname( NULL );
+    }
+
+foundIt:
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
+    return(rh);
+} /*  end PR_GetCounterHandleFromName() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_GetCounterNameFromHandle( 
+    	PRCounterHandle handle,  
+	    const char **qName, 
+	    const char **rName, 
+		const char **description 
+)
+{
+    RName   *rnp = (RName *)handle;
+    QName   *qnp = rnp->qName;
+
+    *qName = qnp->name;
+    *rName = rnp->name;
+    *description = rnp->desc;
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterNameFromHandle: "
+        "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 
+        qnp, rnp, qnp->name, rnp->name, rnp->desc ));
+
+    return;
+} /*  end PR_GetCounterNameFromHandle() */
+
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_IncrementCounter( 
+		PRCounterHandle handle
+)
+{
+    PR_Lock(((RName *)handle)->lock);
+    ((RName *)handle)->counter++;
+    PR_Unlock(((RName *)handle)->lock);
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld", 
+        handle, ((RName *)handle)->counter ));
+
+    return;
+} /*  end PR_IncrementCounter() */
+
+
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_DecrementCounter( 
+		PRCounterHandle handle
+)
+{
+    PR_Lock(((RName *)handle)->lock);
+    ((RName *)handle)->counter--;
+    PR_Unlock(((RName *)handle)->lock);
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld", 
+        handle, ((RName *)handle)->counter ));
+
+    return;
+} /*  end PR_DecrementCounter()  */
+
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_AddToCounter( 
+    	PRCounterHandle handle, 
+	    PRUint32 value 
+)
+{
+    PR_Lock(((RName *)handle)->lock);
+    ((RName *)handle)->counter += value;
+    PR_Unlock(((RName *)handle)->lock);
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld", 
+        handle, ((RName *)handle)->counter ));
+
+    return;
+} /*  end PR_AddToCounter() */
+
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_SubtractFromCounter( 
+    	PRCounterHandle handle, 
+	    PRUint32 value 
+)
+{
+    PR_Lock(((RName *)handle)->lock);
+    ((RName *)handle)->counter -= value;
+    PR_Unlock(((RName *)handle)->lock);
+    
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld", 
+        handle, ((RName *)handle)->counter ));
+
+    return;
+} /*  end  PR_SubtractFromCounter() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRUint32) 
+	PR_GetCounter( 
+		PRCounterHandle handle 
+)
+{
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld", 
+        handle, ((RName *)handle)->counter ));
+
+    return(((RName *)handle)->counter);
+} /*  end  PR_GetCounter() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_SetCounter( 
+		PRCounterHandle handle, 
+		PRUint32 value 
+)
+{
+    ((RName *)handle)->counter = value;
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld", 
+        handle, ((RName *)handle)->counter ));
+
+    return;
+} /*  end  PR_SetCounter() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRCounterHandle) 
+	PR_FindNextCounterQname( 
+        PRCounterHandle handle
+)
+{
+    QName *qnp = (QName *)handle;
+
+    if ( PR_CLIST_IS_EMPTY( &qNameList ))
+            qnp = NULL;
+    else if ( qnp == NULL )
+        qnp = (QName *)PR_LIST_HEAD( &qNameList );
+    else if ( PR_NEXT_LINK( &qnp->link ) ==  &qNameList )
+        qnp = NULL;
+    else  
+        qnp = (QName *)PR_NEXT_LINK( &qnp->link );
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", 
+        handle, qnp ));
+
+    return((PRCounterHandle)qnp);
+} /*  end  PR_FindNextCounterQname() */
+
+
+/*
+**
+*/
+PR_IMPLEMENT(PRCounterHandle) 
+	PR_FindNextCounterRname( 
+        PRCounterHandle rhandle, 
+        PRCounterHandle qhandle 
+)
+{
+    RName *rnp = (RName *)rhandle;
+    QName *qnp = (QName *)qhandle;
+
+
+    if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
+        rnp = NULL;
+    else if ( rnp == NULL )
+        rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
+    else if ( PR_NEXT_LINK( &rnp->link ) ==  &qnp->rNameList )
+        rnp = NULL;
+    else
+        rnp = (RName *)PR_NEXT_LINK( &rnp->link );
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 
+        rhandle, qhandle, rnp ));
+
+    return((PRCounterHandle)rnp);
+} /*  end PR_FindNextCounterRname() */
diff --git a/mozilla/nsprpub/pr/src/misc/prdtoa.c b/mozilla/nsprpub/pr/src/misc/prdtoa.c
new file mode 100644
index 0000000..e1507df
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prdtoa.c
@@ -0,0 +1,3537 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * This file is based on the third-party code dtoa.c.  We minimize our
+ * modifications to third-party code to make it easy to merge new versions.
+ * The author of dtoa.c was not willing to add the parentheses suggested by
+ * GCC, so we suppress these warnings.
+ */
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
+#pragma GCC diagnostic ignored "-Wparentheses"
+#endif
+
+#include "primpl.h"
+
+#define MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	PR_Lock(dtoa_lock[n])
+#define FREE_DTOA_LOCK(n)	PR_Unlock(dtoa_lock[n])
+
+static PRLock *dtoa_lock[2];
+
+void _PR_InitDtoa(void)
+{
+    dtoa_lock[0] = PR_NewLock();
+    dtoa_lock[1] = PR_NewLock();
+}
+
+void _PR_CleanupDtoa(void)
+{
+    PR_DestroyLock(dtoa_lock[0]);
+    dtoa_lock[0] = NULL;
+    PR_DestroyLock(dtoa_lock[1]);
+    dtoa_lock[1] = NULL;
+
+    /* FIXME: deal with freelist and p5s. */
+}
+
+#if !defined(__ARM_EABI__) \
+    && (defined(__arm) || defined(__arm__) || defined(__arm26__) \
+    || defined(__arm32__))
+#define IEEE_ARM
+#elif defined(IS_LITTLE_ENDIAN)
+#define IEEE_8087
+#else
+#define IEEE_MC68k
+#endif
+
+#define Long PRInt32
+#define ULong PRUint32
+#define NO_LONG_LONG
+
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define IEEE_ARM for IEEE-arithmetic machines where the two words
+ *	in a double are stored in big endian order but the two shorts
+ *	in a word are still stored in little endian order.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and strtod and dtoa should round accordingly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a dtoa call after a dtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  The longest string dtoa can return is about 751 bytes
+ *	long.  For conversions by strtod of strings of 800 digits and
+ *	all dtoa conversions in single-threaded executions with 8-byte
+ *	pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ *	pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
+ *	Infinity and NaN (case insensitively).  On some systems (e.g.,
+ *	some HP systems), it may be necessary to #define NAN_WORD0
+ *	appropriately -- to the most significant word of a quiet NaN.
+ *	(On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtod also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits and spaces;
+ *	if there is only one string of hexadecimal digits, it is taken
+ *	for the 52 fraction bits of the resulting NaN; if there are two
+ *	or more strings of hex digits, the first is for the high 20 bits,
+ *	the second and subsequent for the low 32 bits, with intervening
+ *	white space ignored; but if this results in none of the 52
+ *	fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ *	and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ *	avoids underflows on inputs whose result does not underflow.
+ *	If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ *	floating-point numbers and flushes underflows to zero rather
+ *	than implementing gradual underflow, then you must also #define
+ *	Sudden_Underflow.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ *	computation should be done to set the inexact flag when the
+ *	result is inexact and avoid setting inexact when the result
+ *	is exact.  In this case, dtoa.c must be compiled in
+ *	an environment, perhaps provided by #include "dtoa.c" in a
+ *	suitable wrapper, that defines two functions,
+ *		int get_inexact(void);
+ *		void clear_inexact(void);
+ *	such that get_inexact() returns a nonzero value if the
+ *	inexact bit is already set, and clear_inexact() sets the
+ *	inexact bit to 0.  When SET_INEXACT is #defined, strtod
+ *	also does extra computations to set the underflow and overflow
+ *	flags when appropriate (i.e., when the result is tiny and
+ *	inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ *	the result overflows to +-Infinity or underflows to 0.
+ */
+
+#ifndef Long
+#define Long long
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+#ifdef MALLOC
+#ifdef KR_headers
+extern char *MALLOC();
+#else
+extern void *MALLOC(size_t);
+#endif
+#else
+#define MALLOC malloc
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+#ifdef IEEE_ARM
+#define IEEE_Arith
+#endif
+
+#include "errno.h"
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+/*
+ * MacOS 10.2 defines the macro FLT_ROUNDS to an internal function
+ * which does not exist on 10.1.  We can safely #define it to 1 here
+ * to allow 10.2 builds to run on 10.1, since we can't use fesetround()
+ * (which does not exist on 10.1 either).
+ */
+#if defined(XP_MACOSX) && (!defined(MAC_OS_X_VERSION_10_2) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2)
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+#endif /* DT < 10.2 */
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, IEEE_ARM, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#define dval(x) (x).d
+#ifdef IEEE_8087
+#define word0(x) (x).L[1]
+#define word1(x) (x).L[0]
+#else
+#define word0(x) (x).L[0]
+#define word1(x) (x).L[1]
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(IEEE_ARM) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm	/* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#define Rounding rounding
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Bias 129
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef KR_headers
+#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)
+#else
+#define FFFFFFFF 0xffffffffUL
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#endif
+
+#define Kmax 7
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+ static Bigint *freelist[Kmax+1];
+
+ static Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && (rv = freelist[k]))
+		freelist[k] = rv->next;
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ static void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE((void*)v);
+#else
+			free((void*)v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(Long) + 2*sizeof(int))
+
+ static Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ static Bigint *
+s2b
+#ifdef KR_headers
+	(s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9;
+#else
+	(CONST char *s, int nd0, int nd, ULong y9)
+#endif
+{
+	Bigint *b;
+	int i, k;
+	Long x, y;
+
+	x = (nd + 8) / 9;
+	for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+	b = Balloc(k);
+	b->x[0] = y9;
+	b->wds = 1;
+#else
+	b = Balloc(k+1);
+	b->x[0] = y9 & 0xffff;
+	b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+	i = 9;
+	if (9 < nd0) {
+		s += 9;
+		do b = multadd(b, 10, *s++ - '0');
+			while(++i < nd0);
+		s++;
+		}
+	else
+		s += 10;
+	for(; i < nd; i++)
+		b = multadd(b, 10, *s++ - '0');
+	return b;
+	}
+
+ static int
+hi0bits
+#ifdef KR_headers
+	(x) register ULong x;
+#else
+	(register ULong x)
+#endif
+{
+	register int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ static int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	register int k;
+	register ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ static Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ static Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		if (y = *xb++) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & FFFFFFFF;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if (y = *xb & 0xffff) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if (y = *xb >> 16) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if (y = *xb++) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ static Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	if (i = k & 3)
+		b = multadd(b, p05[i-1], 0);
+
+	if (!(k >>= 2))
+		return b;
+	if (!(p5 = p5s)) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		if (!(p5 = p5s)) {
+			p5 = p5s = i2b(625);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		if (!(p51 = p5->next)) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			if (!(p51 = p5->next)) {
+				p51 = p5->next = mult(p5,p5);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ static Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+	n = k >> 5;
+#else
+	n = k >> 4;
+#endif
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+#ifdef Pack_32
+	if (k &= 0x1f) {
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+		}
+#else
+	if (k &= 0xf) {
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+		}
+#endif
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ static int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ static Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ static double
+ulp
+#ifdef KR_headers
+	(dx) double dx;
+#else
+	(double dx)
+#endif
+{
+	register Long L;
+	U x, a;
+
+	dval(x) = dx;
+	L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+	if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+		L |= Exp_msk1 >> 4;
+#endif
+		word0(a) = L;
+		word1(a) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+		}
+	else {
+		L = -L >> Exp_shift;
+		if (L < Exp_shift) {
+			word0(a) = 0x80000 >> L;
+			word1(a) = 0;
+			}
+		else {
+			word0(a) = 0;
+			L -= Exp_shift;
+			word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+			}
+		}
+#endif
+#endif
+	return dval(a);
+	}
+
+ static double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> Ebits - k;
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << (32-Ebits) + k | w >> Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> 32 - k;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> 32 - k;
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(d) = d0 >> 16 | d0 << 16;
+	word1(d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+	return dval(d);
+	}
+
+ static Bigint *
+d2b
+#ifdef KR_headers
+	(dd, e, bits) double dd; int *e, *bits;
+#else
+	(double dd, int *e, int *bits)
+#endif
+{
+	U d;
+	Bigint *b;
+	int de, k;
+	ULong *x, y, z;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+#ifdef VAX
+	ULong d0, d1;
+#endif
+
+	dval(d) = dd;
+#ifdef VAX
+	d0 = word0(d) >> 16 | word0(d) << 16;
+	d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	if (de = (int)(d0 >> Exp_shift))
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	if (y = d1) {
+		if (k = lo0bits(&y)) {
+			x[0] = y | z << 32 - k;
+			z >>= k;
+			}
+		else
+			x[0] = y;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = (x[1] = z) ? 2 : 1;
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if (y = d1) {
+		if (k = lo0bits(&y))
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ static double
+ratio
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	U da, db;
+	int k, ka, kb;
+
+	dval(da) = b2d(a, &ka);
+	dval(db) = b2d(b, &kb);
+#ifdef Pack_32
+	k = ka - kb + 32*(a->wds - b->wds);
+#else
+	k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+	if (k > 0) {
+		word0(da) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(da) *= 1 << k;
+		}
+	else {
+		k = -k;
+		word0(db) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(db) *= 1 << k;
+		}
+#else
+	if (k > 0)
+		word0(da) += k*Exp_msk1;
+	else {
+		k = -k;
+		word0(db) += k*Exp_msk1;
+		}
+#endif
+	return dval(da) / dval(db);
+	}
+
+ static CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+ static CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+		9007199254740992.*9007199254740992.e-256
+		/* = 2^106 * 1e-53 */
+#else
+		1e-256
+#endif
+		};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static CONST double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#ifndef IEEE_Arith
+#undef INFNAN_CHECK
+#endif
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+ static int
+match
+#ifdef KR_headers
+	(sp, t) char **sp, *t;
+#else
+	(CONST char **sp, char *t)
+#endif
+{
+	int c, d;
+	CONST char *s = *sp;
+
+	while(d = *t++) {
+		if ((c = *++s) >= 'A' && c <= 'Z')
+			c += 'a' - 'A';
+		if (c != d)
+			return 0;
+		}
+	*sp = s + 1;
+	return 1;
+	}
+
+#ifndef No_Hex_NaN
+ static void
+hexnan
+#ifdef KR_headers
+	(rvp, sp) double *rvp; CONST char **sp;
+#else
+	(double *rvp, CONST char **sp)
+#endif
+{
+	ULong c, x[2];
+	CONST char *s;
+	int havedig, udx0, xshift;
+
+	x[0] = x[1] = 0;
+	havedig = xshift = 0;
+	udx0 = 1;
+	s = *sp;
+	while(c = *(CONST unsigned char*)++s) {
+		if (c >= '0' && c <= '9')
+			c -= '0';
+		else if (c >= 'a' && c <= 'f')
+			c += 10 - 'a';
+		else if (c >= 'A' && c <= 'F')
+			c += 10 - 'A';
+		else if (c <= ' ') {
+			if (udx0 && havedig) {
+				udx0 = 0;
+				xshift = 1;
+				}
+			continue;
+			}
+		else if (/*(*/ c == ')' && havedig) {
+			*sp = s + 1;
+			break;
+			}
+		else
+			return;	/* invalid form: don't change *sp */
+		havedig = 1;
+		if (xshift) {
+			xshift = 0;
+			x[0] = x[1];
+			x[1] = 0;
+			}
+		if (udx0)
+			x[0] = (x[0] << 4) | (x[1] >> 28);
+		x[1] = (x[1] << 4) | c;
+		}
+	if ((x[0] &= 0xfffff) || x[1]) {
+		word0(*rvp) = Exp_mask | x[0];
+		word1(*rvp) = x[1];
+		}
+	}
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+ PR_IMPLEMENT(double)
+PR_strtod
+#ifdef KR_headers
+	(s00, se) CONST char *s00; char **se;
+#else
+	(CONST char *s00, char **se)
+#endif
+{
+#ifdef Avoid_Underflow
+	int scale;
+#endif
+	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+		 e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+	CONST char *s, *s0, *s1;
+	double aadj, aadj1, adj;
+	U aadj2, rv, rv0;
+	Long L;
+	ULong y, z;
+	Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	int rounding;
+#endif
+#ifdef USE_LOCALE
+	CONST char *s2;
+#endif
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+
+	sign = nz0 = nz = 0;
+	dval(rv) = 0.;
+	for(s = s00;;s++) switch(*s) {
+		case '-':
+			sign = 1;
+			/* no break */
+		case '+':
+			if (*++s)
+				goto break2;
+			/* no break */
+		case 0:
+			goto ret0;
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			continue;
+		default:
+			goto break2;
+		}
+ break2:
+	if (*s == '0') {
+		nz0 = 1;
+		while(*++s == '0') ;
+		if (!*s)
+			goto ret;
+		}
+	s0 = s;
+	y = z = 0;
+	for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+		if (nd < 9)
+			y = 10*y + c - '0';
+		else if (nd < 16)
+			z = 10*z + c - '0';
+	nd0 = nd;
+#ifdef USE_LOCALE
+	s1 = localeconv()->decimal_point;
+	if (c == *s1) {
+		c = '.';
+		if (*++s1) {
+			s2 = s;
+			for(;;) {
+				if (*++s2 != *s1) {
+					c = 0;
+					break;
+					}
+				if (!*++s1) {
+					s = s2;
+					break;
+					}
+				}
+			}
+		}
+#endif
+	if (c == '.') {
+		c = *++s;
+		if (!nd) {
+			for(; c == '0'; c = *++s)
+				nz++;
+			if (c > '0' && c <= '9') {
+				s0 = s;
+				nf += nz;
+				nz = 0;
+				goto have_dig;
+				}
+			goto dig_done;
+			}
+		for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+			nz++;
+			if (c -= '0') {
+				nf += nz;
+				for(i = 1; i < nz; i++)
+					if (nd++ < 9)
+						y *= 10;
+					else if (nd <= DBL_DIG + 1)
+						z *= 10;
+				if (nd++ < 9)
+					y = 10*y + c;
+				else if (nd <= DBL_DIG + 1)
+					z = 10*z + c;
+				nz = 0;
+				}
+			}
+		}
+ dig_done:
+	if (nd > 64 * 1024)
+		goto ret0;
+	e = 0;
+	if (c == 'e' || c == 'E') {
+		if (!nd && !nz && !nz0) {
+			goto ret0;
+			}
+		s00 = s;
+		esign = 0;
+		switch(c = *++s) {
+			case '-':
+				esign = 1;
+			case '+':
+				c = *++s;
+			}
+		if (c >= '0' && c <= '9') {
+			while(c == '0')
+				c = *++s;
+			if (c > '0' && c <= '9') {
+				L = c - '0';
+				s1 = s;
+				while((c = *++s) >= '0' && c <= '9')
+					L = 10*L + c - '0';
+				if (s - s1 > 8 || L > 19999)
+					/* Avoid confusion from exponents
+					 * so large that e might overflow.
+					 */
+					e = 19999; /* safe for 16 bit ints */
+				else
+					e = (int)L;
+				if (esign)
+					e = -e;
+				}
+			else
+				e = 0;
+			}
+		else
+			s = s00;
+		}
+	if (!nd) {
+		if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+			/* Check for Nan and Infinity */
+			switch(c) {
+			  case 'i':
+			  case 'I':
+				if (match(&s,"nf")) {
+					--s;
+					if (!match(&s,"inity"))
+						++s;
+					word0(rv) = 0x7ff00000;
+					word1(rv) = 0;
+					goto ret;
+					}
+				break;
+			  case 'n':
+			  case 'N':
+				if (match(&s, "an")) {
+					word0(rv) = NAN_WORD0;
+					word1(rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+					if (*s == '(') /*)*/
+						hexnan(&rv, &s);
+#endif
+					goto ret;
+					}
+			  }
+#endif /* INFNAN_CHECK */
+ ret0:
+			s = s00;
+			sign = 0;
+			}
+		goto ret;
+		}
+	e1 = e -= nf;
+
+	/* Now we have nd0 digits, starting at s0, followed by a
+	 * decimal point, followed by nd-nd0 digits.  The number we're
+	 * after is the integer represented by those digits times
+	 * 10**e */
+
+	if (!nd0)
+		nd0 = nd;
+	k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+	dval(rv) = y;
+	if (k > 9) {
+#ifdef SET_INEXACT
+		if (k > DBL_DIG)
+			oldinexact = get_inexact();
+#endif
+		dval(rv) = tens[k - 9] * dval(rv) + z;
+		}
+	bd0 = 0;
+	if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+		&& Flt_Rounds == 1
+#endif
+#endif
+			) {
+		if (!e)
+			goto ret;
+		if (e > 0) {
+			if (e <= Ten_pmax) {
+#ifdef VAX
+				goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv = -rv;
+					sign = 0;
+					}
+#endif
+				/* rv = */ rounded_product(dval(rv), tens[e]);
+				goto ret;
+#endif
+				}
+			i = DBL_DIG - nd;
+			if (e <= Ten_pmax + i) {
+				/* A fancier test would sometimes let us do
+				 * this for larger i values.
+				 */
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv = -rv;
+					sign = 0;
+					}
+#endif
+				e -= i;
+				dval(rv) *= tens[i];
+#ifdef VAX
+				/* VAX exponent range is so narrow we must
+				 * worry about overflow here...
+				 */
+ vax_ovfl_check:
+				word0(rv) -= P*Exp_msk1;
+				/* rv = */ rounded_product(dval(rv), tens[e]);
+				if ((word0(rv) & Exp_mask)
+				 > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+					goto ovfl;
+				word0(rv) += P*Exp_msk1;
+#else
+				/* rv = */ rounded_product(dval(rv), tens[e]);
+#endif
+				goto ret;
+				}
+			}
+#ifndef Inaccurate_Divide
+		else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+			/* round correctly FLT_ROUNDS = 2 or 3 */
+			if (sign) {
+				rv = -rv;
+				sign = 0;
+				}
+#endif
+			/* rv = */ rounded_quotient(dval(rv), tens[-e]);
+			goto ret;
+			}
+#endif
+		}
+	e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+	inexact = 1;
+	if (k <= DBL_DIG)
+		oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+	scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if ((rounding = Flt_Rounds) >= 2) {
+		if (sign)
+			rounding = rounding == 2 ? 0 : 2;
+		else
+			if (rounding != 2)
+				rounding = 0;
+		}
+#endif
+#endif /*IEEE_Arith*/
+
+	/* Get starting approximation = rv * 10**e1 */
+
+	if (e1 > 0) {
+		if (i = e1 & 15)
+			dval(rv) *= tens[i];
+		if (e1 &= ~15) {
+			if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+#ifndef NO_ERRNO
+				PR_SetError(PR_RANGE_ERROR, 0);
+#endif
+				/* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+				switch(rounding) {
+				  case 0: /* toward 0 */
+				  case 3: /* toward -infinity */
+					word0(rv) = Big0;
+					word1(rv) = Big1;
+					break;
+				  default:
+					word0(rv) = Exp_mask;
+					word1(rv) = 0;
+				  }
+#else /*Honor_FLT_ROUNDS*/
+				word0(rv) = Exp_mask;
+				word1(rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+				/* set overflow bit */
+				dval(rv0) = 1e300;
+				dval(rv0) *= dval(rv0);
+#endif
+#else /*IEEE_Arith*/
+				word0(rv) = Big0;
+				word1(rv) = Big1;
+#endif /*IEEE_Arith*/
+				if (bd0)
+					goto retfree;
+				goto ret;
+				}
+			e1 >>= 4;
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(rv) *= bigtens[j];
+		/* The last multiplication could overflow. */
+			word0(rv) -= P*Exp_msk1;
+			dval(rv) *= bigtens[j];
+			if ((z = word0(rv) & Exp_mask)
+			 > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+				goto ovfl;
+			if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+				/* set to largest number */
+				/* (Can't trust DBL_MAX) */
+				word0(rv) = Big0;
+				word1(rv) = Big1;
+				}
+			else
+				word0(rv) += P*Exp_msk1;
+			}
+		}
+	else if (e1 < 0) {
+		e1 = -e1;
+		if (i = e1 & 15)
+			dval(rv) /= tens[i];
+		if (e1 >>= 4) {
+			if (e1 >= 1 << n_bigtens)
+				goto undfl;
+#ifdef Avoid_Underflow
+			if (e1 & Scale_Bit)
+				scale = 2*P;
+			for(j = 0; e1 > 0; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(rv) *= tinytens[j];
+			if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask)
+						>> Exp_shift)) > 0) {
+				/* scaled rv is denormal; zap j low bits */
+				if (j >= 32) {
+					word1(rv) = 0;
+					if (j >= 53)
+					 word0(rv) = (P+2)*Exp_msk1;
+					else
+					 word0(rv) &= 0xffffffff << j-32;
+					}
+				else
+					word1(rv) &= 0xffffffff << j;
+				}
+#else
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(rv) *= tinytens[j];
+			/* The last multiplication could underflow. */
+			dval(rv0) = dval(rv);
+			dval(rv) *= tinytens[j];
+			if (!dval(rv)) {
+				dval(rv) = 2.*dval(rv0);
+				dval(rv) *= tinytens[j];
+#endif
+				if (!dval(rv)) {
+ undfl:
+					dval(rv) = 0.;
+#ifndef NO_ERRNO
+					PR_SetError(PR_RANGE_ERROR, 0);
+#endif
+					if (bd0)
+						goto retfree;
+					goto ret;
+					}
+#ifndef Avoid_Underflow
+				word0(rv) = Tiny0;
+				word1(rv) = Tiny1;
+				/* The refinement below will clean
+				 * this approximation up.
+				 */
+				}
+#endif
+			}
+		}
+
+	/* Now the hard part -- adjusting rv to the correct value.*/
+
+	/* Put digits into bd: true value = bd * 10^e */
+
+	bd0 = s2b(s0, nd0, nd, y);
+
+	for(;;) {
+		bd = Balloc(bd0->k);
+		Bcopy(bd, bd0);
+		bb = d2b(dval(rv), &bbe, &bbbits);	/* rv = bb * 2^bbe */
+		bs = i2b(1);
+
+		if (e >= 0) {
+			bb2 = bb5 = 0;
+			bd2 = bd5 = e;
+			}
+		else {
+			bb2 = bb5 = -e;
+			bd2 = bd5 = 0;
+			}
+		if (bbe >= 0)
+			bb2 += bbe;
+		else
+			bd2 -= bbe;
+		bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+		if (rounding != 1)
+			bs2++;
+#endif
+#ifdef Avoid_Underflow
+		j = bbe - scale;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+		j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+		j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+		j = bbe;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+		bb2 += j;
+		bd2 += j;
+#ifdef Avoid_Underflow
+		bd2 += scale;
+#endif
+		i = bb2 < bd2 ? bb2 : bd2;
+		if (i > bs2)
+			i = bs2;
+		if (i > 0) {
+			bb2 -= i;
+			bd2 -= i;
+			bs2 -= i;
+			}
+		if (bb5 > 0) {
+			bs = pow5mult(bs, bb5);
+			bb1 = mult(bs, bb);
+			Bfree(bb);
+			bb = bb1;
+			}
+		if (bb2 > 0)
+			bb = lshift(bb, bb2);
+		if (bd5 > 0)
+			bd = pow5mult(bd, bd5);
+		if (bd2 > 0)
+			bd = lshift(bd, bd2);
+		if (bs2 > 0)
+			bs = lshift(bs, bs2);
+		delta = diff(bb, bd);
+		dsign = delta->sign;
+		delta->sign = 0;
+		i = cmp(delta, bs);
+#ifdef Honor_FLT_ROUNDS
+		if (rounding != 1) {
+			if (i < 0) {
+				/* Error is less than an ulp */
+				if (!delta->x[0] && delta->wds <= 1) {
+					/* exact */
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					break;
+					}
+				if (rounding) {
+					if (dsign) {
+						adj = 1.;
+						goto apply_adj;
+						}
+					}
+				else if (!dsign) {
+					adj = -1.;
+					if (!word1(rv)
+					 && !(word0(rv) & Frac_mask)) {
+						y = word0(rv) & Exp_mask;
+#ifdef Avoid_Underflow
+						if (!scale || y > 2*P*Exp_msk1)
+#else
+						if (y)
+#endif
+						  {
+						  delta = lshift(delta,Log2P);
+						  if (cmp(delta, bs) <= 0)
+							adj = -0.5;
+						  }
+						}
+ apply_adj:
+#ifdef Avoid_Underflow
+					if (scale && (y = word0(rv) & Exp_mask)
+						<= 2*P*Exp_msk1)
+					  word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+					if ((word0(rv) & Exp_mask) <=
+							P*Exp_msk1) {
+						word0(rv) += P*Exp_msk1;
+						dval(rv) += adj*ulp(dval(rv));
+						word0(rv) -= P*Exp_msk1;
+						}
+					else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+					dval(rv) += adj*ulp(dval(rv));
+					}
+				break;
+				}
+			adj = ratio(delta, bs);
+			if (adj < 1.)
+				adj = 1.;
+			if (adj <= 0x7ffffffe) {
+				/* adj = rounding ? ceil(adj) : floor(adj); */
+				y = adj;
+				if (y != adj) {
+					if (!((rounding>>1) ^ dsign))
+						y++;
+					adj = y;
+					}
+				}
+#ifdef Avoid_Underflow
+			if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+				word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+				word0(rv) += P*Exp_msk1;
+				adj *= ulp(dval(rv));
+				if (dsign)
+					dval(rv) += adj;
+				else
+					dval(rv) -= adj;
+				word0(rv) -= P*Exp_msk1;
+				goto cont;
+				}
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			adj *= ulp(dval(rv));
+			if (dsign)
+				dval(rv) += adj;
+			else
+				dval(rv) -= adj;
+			goto cont;
+			}
+#endif /*Honor_FLT_ROUNDS*/
+
+		if (i < 0) {
+			/* Error is less than half an ulp -- check for
+			 * special case of mantissa a power of two.
+			 */
+			if (dsign || word1(rv) || word0(rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+			 || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+			 || (word0(rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+				) {
+#ifdef SET_INEXACT
+				if (!delta->x[0] && delta->wds <= 1)
+					inexact = 0;
+#endif
+				break;
+				}
+			if (!delta->x[0] && delta->wds <= 1) {
+				/* exact result */
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			delta = lshift(delta,Log2P);
+			if (cmp(delta, bs) > 0)
+				goto drop_down;
+			break;
+			}
+		if (i == 0) {
+			/* exactly half-way between */
+			if (dsign) {
+				if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+				 &&  word1(rv) == (
+#ifdef Avoid_Underflow
+			(scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+		? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+						   0xffffffff)) {
+					/*boundary case -- increment exponent*/
+					word0(rv) = (word0(rv) & Exp_mask)
+						+ Exp_msk1
+#ifdef IBM
+						| Exp_msk1 >> 4
+#endif
+						;
+					word1(rv) = 0;
+#ifdef Avoid_Underflow
+					dsign = 0;
+#endif
+					break;
+					}
+				}
+			else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+ drop_down:
+				/* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+				L = word0(rv) & Exp_mask;
+#ifdef IBM
+				if (L <  Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+				if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+				if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+					goto undfl;
+				L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+				if (scale) {
+					L = word0(rv) & Exp_mask;
+					if (L <= (2*P+1)*Exp_msk1) {
+						if (L > (P+2)*Exp_msk1)
+							/* round even ==> */
+							/* accept rv */
+							break;
+						/* rv = smallest denormal */
+						goto undfl;
+						}
+					}
+#endif /*Avoid_Underflow*/
+				L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+				word0(rv) = L | Bndry_mask1;
+				word1(rv) = 0xffffffff;
+#ifdef IBM
+				goto cont;
+#else
+				break;
+#endif
+				}
+#ifndef ROUND_BIASED
+			if (!(word1(rv) & LSB))
+				break;
+#endif
+			if (dsign)
+				dval(rv) += ulp(dval(rv));
+#ifndef ROUND_BIASED
+			else {
+				dval(rv) -= ulp(dval(rv));
+#ifndef Sudden_Underflow
+				if (!dval(rv))
+					goto undfl;
+#endif
+				}
+#ifdef Avoid_Underflow
+			dsign = 1 - dsign;
+#endif
+#endif
+			break;
+			}
+		if ((aadj = ratio(delta, bs)) <= 2.) {
+			if (dsign)
+				aadj = aadj1 = 1.;
+			else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+				if (word1(rv) == Tiny1 && !word0(rv))
+					goto undfl;
+#endif
+				aadj = 1.;
+				aadj1 = -1.;
+				}
+			else {
+				/* special case -- power of FLT_RADIX to be */
+				/* rounded down... */
+
+				if (aadj < 2./FLT_RADIX)
+					aadj = 1./FLT_RADIX;
+				else
+					aadj *= 0.5;
+				aadj1 = -aadj;
+				}
+			}
+		else {
+			aadj *= 0.5;
+			aadj1 = dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+			switch(Rounding) {
+				case 2: /* towards +infinity */
+					aadj1 -= 0.5;
+					break;
+				case 0: /* towards 0 */
+				case 3: /* towards -infinity */
+					aadj1 += 0.5;
+				}
+#else
+			if (Flt_Rounds == 0)
+				aadj1 += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+			}
+		y = word0(rv) & Exp_mask;
+
+		/* Check for overflow */
+
+		if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+			dval(rv0) = dval(rv);
+			word0(rv) -= P*Exp_msk1;
+			adj = aadj1 * ulp(dval(rv));
+			dval(rv) += adj;
+			if ((word0(rv) & Exp_mask) >=
+					Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+				if (word0(rv0) == Big0 && word1(rv0) == Big1)
+					goto ovfl;
+				word0(rv) = Big0;
+				word1(rv) = Big1;
+				goto cont;
+				}
+			else
+				word0(rv) += P*Exp_msk1;
+			}
+		else {
+#ifdef Avoid_Underflow
+			if (scale && y <= 2*P*Exp_msk1) {
+				if (aadj <= 0x7fffffff) {
+					if ((z = aadj) <= 0)
+						z = 1;
+					aadj = z;
+					aadj1 = dsign ? aadj : -aadj;
+					}
+				dval(aadj2) = aadj1;
+				word0(aadj2) += (2*P+1)*Exp_msk1 - y;
+				aadj1 = dval(aadj2);
+				}
+			adj = aadj1 * ulp(dval(rv));
+			dval(rv) += adj;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+				dval(rv0) = dval(rv);
+				word0(rv) += P*Exp_msk1;
+				adj = aadj1 * ulp(dval(rv));
+				dval(rv) += adj;
+#ifdef IBM
+				if ((word0(rv) & Exp_mask) <  P*Exp_msk1)
+#else
+				if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+					{
+					if (word0(rv0) == Tiny0
+					 && word1(rv0) == Tiny1)
+						goto undfl;
+					word0(rv) = Tiny0;
+					word1(rv) = Tiny1;
+					goto cont;
+					}
+				else
+					word0(rv) -= P*Exp_msk1;
+				}
+			else {
+				adj = aadj1 * ulp(dval(rv));
+				dval(rv) += adj;
+				}
+#else /*Sudden_Underflow*/
+			/* Compute adj so that the IEEE rounding rules will
+			 * correctly round rv + adj in some half-way cases.
+			 * If rv * ulp(rv) is denormalized (i.e.,
+			 * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+			 * trouble from bits lost to denormalization;
+			 * example: 1.2e-307 .
+			 */
+			if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+				aadj1 = (double)(int)(aadj + 0.5);
+				if (!dsign)
+					aadj1 = -aadj1;
+				}
+			adj = aadj1 * ulp(dval(rv));
+			dval(rv) += adj;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			}
+		z = word0(rv) & Exp_mask;
+#ifndef SET_INEXACT
+#ifdef Avoid_Underflow
+		if (!scale)
+#endif
+		if (y == z) {
+			/* Can we stop now? */
+			L = (Long)aadj;
+			aadj -= L;
+			/* The tolerances below are conservative. */
+			if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+				if (aadj < .4999999 || aadj > .5000001)
+					break;
+				}
+			else if (aadj < .4999999/FLT_RADIX)
+				break;
+			}
+#endif
+ cont:
+		Bfree(bb);
+		Bfree(bd);
+		Bfree(bs);
+		Bfree(delta);
+		}
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(rv0) = Exp_1 + (70 << Exp_shift);
+			word1(rv0) = 0;
+			dval(rv0) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+	if (scale) {
+		word0(rv0) = Exp_1 - 2*P*Exp_msk1;
+		word1(rv0) = 0;
+		dval(rv) *= dval(rv0);
+#ifndef NO_ERRNO
+		/* try to avoid the bug of testing an 8087 register value */
+		if (word0(rv) == 0 && word1(rv) == 0)
+			PR_SetError(PR_RANGE_ERROR, 0);
+#endif
+		}
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+	if (inexact && !(word0(rv) & Exp_mask)) {
+		/* set underflow bit */
+		dval(rv0) = 1e-300;
+		dval(rv0) *= dval(rv0);
+		}
+#endif
+ retfree:
+	Bfree(bb);
+	Bfree(bd);
+	Bfree(bs);
+	Bfree(bd0);
+	Bfree(delta);
+ ret:
+	if (se)
+		*se = (char *)s;
+	return sign ? -dval(rv) : dval(rv);
+	}
+
+ static int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
+
+#ifndef MULTIPLE_THREADS
+ static char *dtoa_result;
+#endif
+
+ static char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ static char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	while(*t = *s++) t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ static void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ static char *
+dtoa
+#ifdef KR_headers
+	(dd, mode, ndigits, decpt, sign, rve)
+	double dd; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+	U d, d2, eps;
+	double ds;
+	char *s, *s0;
+#ifdef Honor_FLT_ROUNDS
+	int rounding;
+#endif
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+
+	dval(d) = dd;
+	if (word0(d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(d) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+	if (word0(d)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(d) && !(word0(d) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(d) += 0; /* normalize */
+#endif
+	if (!dval(d)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if ((rounding = Flt_Rounds) >= 2) {
+		if (*sign)
+			rounding = rounding == 2 ? 0 : 2;
+		else
+			if (rounding != 2)
+				rounding = 0;
+		}
+#endif
+
+	b = d2b(dval(d), &be, &bbits);
+#ifdef Sudden_Underflow
+	i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) {
+#endif
+		dval(d2) = dval(d);
+		word0(d2) &= Frac_mask1;
+		word0(d2) |= Exp_11;
+#ifdef IBM
+		if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+			dval(d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+		 *
+		 * This suggests computing an approximation k to log10(d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(d) << 64 - i | word1(d) >> i - 32
+			    : word1(d) << 32 - i;
+		dval(d2) = x;
+		word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	switch(mode) {
+		case 0:
+		case 1:
+			ilim = ilim1 = -1;
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(d2) = dval(d);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(d) /= ds;
+			}
+		else if (j1 = -k) {
+			dval(d) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(d) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(d) *= 10.;
+			ieps++;
+			}
+		dval(eps) = ieps*dval(d) + 7.;
+		word0(eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(d) -= 5.;
+			if (dval(d) > dval(eps))
+				goto one_digit;
+			if (dval(d) < -dval(eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+			for(i = 0;;) {
+				L = dval(d);
+				dval(d) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(d) < dval(eps))
+					goto ret1;
+				if (1. - dval(d) < dval(eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(eps) *= 10.;
+				dval(d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(d) *= 10.) {
+				L = (Long)(dval(d));
+				if (!(dval(d) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(d) > 0.5 + dval(eps))
+						goto bump_up;
+					else if (dval(d) < 0.5 - dval(eps)) {
+						while(*--s == '0');
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(d) = dval(d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1; i <= k+1; i++, dval(d) *= 10.) {
+			L = (Long)(dval(d) / ds);
+			dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(d) < 0) {
+				L--;
+				dval(d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(d)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(d) += dval(d);
+				if (dval(d) > ds || dval(d) == ds && L & 1) {
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				b1 = mult(mhi, b);
+				Bfree(b);
+				b = b1;
+				}
+			if (j = b5 - m5)
+				b = pow5mult(b, j);
+			}
+		else
+			b = pow5mult(b, b5);
+		}
+	S = i2b(1);
+	if (s5 > 0)
+		S = pow5mult(S, s5);
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& rounding == 1
+#endif
+				) {
+		if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(d) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)
+		i = 32 - i;
+#else
+	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+		i = 16 - i;
+#endif
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	if (b2 > 0)
+		b = lshift(b, b2);
+	if (s2 > 0)
+		S = lshift(S, s2);
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (leftright)
+				mhi = multadd(mhi, 10, 0);
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0)
+			mhi = lshift(mhi, m2);
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(d) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(d) & 1)
+#endif
+					) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					j1 = cmp(b, S);
+					if ((j1 > 0 || j1 == 0 && dig & 1)
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (mlo == mhi)
+				mlo = mhi = multadd(mhi, 10, 0);
+			else {
+				mlo = multadd(mlo, 10, 0);
+				mhi = multadd(mhi, 10, 0);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	j = cmp(b, S);
+	if (j > 0 || j == 0 && dig & 1) {
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0');
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(d) = Exp_1 + (70 << Exp_shift);
+			word1(d) = 0;
+			dval(d) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+	}
+#ifdef __cplusplus
+}
+#endif
+
+PR_IMPLEMENT(PRStatus)
+PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits,
+	PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize)
+{
+    char *result;
+    PRSize resultlen;
+    PRStatus rv = PR_FAILURE;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (mode < 0 || mode > 3) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return rv;
+    }
+    result = dtoa(d, mode, ndigits, decpt, sign, rve);
+    if (!result) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return rv;
+    }
+    resultlen = strlen(result)+1;
+    if (bufsize < resultlen) {
+        PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+    } else {
+        memcpy(buf, result, resultlen);
+        if (rve) {
+            *rve = buf + (*rve - result);
+        }
+        rv = PR_SUCCESS;
+    }
+    freedtoa(result);
+    return rv;  
+}
+
+/*
+** conversion routines for floating point
+** prcsn - number of digits of precision to generate floating
+** point value.
+** This should be reparameterized so that you can send in a
+**   prcn for the positive and negative ranges.  For now, 
+**   conform to the ECMA JavaScript spec which says numbers
+**   less than 1e-6 are in scientific notation.
+** Also, the ECMA spec says that there should always be a
+**   '+' or '-' after the 'e' in scientific notation
+*/
+PR_IMPLEMENT(void)
+PR_cnvtf(char *buf, int bufsz, int prcsn, double dfval)
+{
+    PRIntn decpt, sign, numdigits;
+    char *num, *nump;
+    char *bufp = buf;
+    char *endnum;
+    U fval;
+
+    dval(fval) = dfval;
+    /* If anything fails, we store an empty string in 'buf' */
+    num = (char*)PR_MALLOC(bufsz);
+    if (num == NULL) {
+        buf[0] = '\0';
+        return;
+    }
+    /* XXX Why use mode 1? */
+    if (PR_dtoa(dval(fval),1,prcsn,&decpt,&sign,&endnum,num,bufsz)
+            == PR_FAILURE) {
+        buf[0] = '\0';
+        goto done;
+    }
+    numdigits = endnum - num;
+    nump = num;
+
+    if (sign &&
+        !(word0(fval) == Sign_bit && word1(fval) == 0) &&
+        !((word0(fval) & Exp_mask) == Exp_mask &&
+          (word1(fval) || (word0(fval) & 0xfffff)))) {
+        *bufp++ = '-';
+    }
+
+    if (decpt == 9999) {
+        while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
+        goto done;
+    }
+
+    if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
+        *bufp++ = *nump++;
+        if (numdigits != 1) {
+            *bufp++ = '.';
+        }
+
+        while (*nump != '\0') {
+            *bufp++ = *nump++;
+        }
+        *bufp++ = 'e';
+        PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1);
+    } else if (decpt >= 0) {
+        if (decpt == 0) {
+            *bufp++ = '0';
+        } else {
+            while (decpt--) {
+                if (*nump != '\0') {
+                    *bufp++ = *nump++;
+                } else {
+                    *bufp++ = '0';
+                }
+            }
+        }
+        if (*nump != '\0') {
+            *bufp++ = '.';
+            while (*nump != '\0') {
+                *bufp++ = *nump++;
+            }
+        }
+        *bufp++ = '\0';
+    } else if (decpt < 0) {
+        *bufp++ = '0';
+        *bufp++ = '.';
+        while (decpt++) {
+            *bufp++ = '0';
+        }
+
+        while (*nump != '\0') {
+            *bufp++ = *nump++;
+        }
+        *bufp++ = '\0';
+    }
+done:
+    PR_DELETE(num);
+}
diff --git a/mozilla/nsprpub/pr/src/misc/prenv.c b/mozilla/nsprpub/pr/src/misc/prenv.c
new file mode 100644
index 0000000..e07e073
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prenv.c
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 <string.h>
+#include "primpl.h"
+
+/* Lock used to lock the environment */
+#if defined(_PR_NO_PREEMPT)
+#define _PR_NEW_LOCK_ENV()
+#define _PR_DELETE_LOCK_ENV()
+#define _PR_LOCK_ENV()
+#define _PR_UNLOCK_ENV()
+#elif defined(_PR_LOCAL_THREADS_ONLY)
+extern _PRCPU * _pr_primordialCPU;
+static PRIntn _is;
+#define _PR_NEW_LOCK_ENV()
+#define _PR_DELETE_LOCK_ENV()
+#define _PR_LOCK_ENV() if (_pr_primordialCPU) _PR_INTSOFF(_is);
+#define _PR_UNLOCK_ENV() if (_pr_primordialCPU) _PR_INTSON(_is);
+#else
+static PRLock *_pr_envLock = NULL;
+#define _PR_NEW_LOCK_ENV() {_pr_envLock = PR_NewLock();}
+#define _PR_DELETE_LOCK_ENV() \
+    { if (_pr_envLock) { PR_DestroyLock(_pr_envLock); _pr_envLock = NULL; } }
+#define _PR_LOCK_ENV() { if (_pr_envLock) PR_Lock(_pr_envLock); }
+#define _PR_UNLOCK_ENV() { if (_pr_envLock) PR_Unlock(_pr_envLock); }
+#endif
+
+/************************************************************************/
+
+void _PR_InitEnv(void)
+{
+	_PR_NEW_LOCK_ENV();
+}
+
+void _PR_CleanupEnv(void)
+{
+    _PR_DELETE_LOCK_ENV();
+}
+
+PR_IMPLEMENT(char*) PR_GetEnv(const char *var)
+{
+    char *ev;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    _PR_LOCK_ENV();
+    ev = _PR_MD_GET_ENV(var);
+    _PR_UNLOCK_ENV();
+    return ev;
+}
+
+PR_IMPLEMENT(PRStatus) PR_SetEnv(const char *string)
+{
+    PRIntn result;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if ( !strchr(string, '=')) return(PR_FAILURE);
+
+    _PR_LOCK_ENV();
+    result = _PR_MD_PUT_ENV(string);
+    _PR_UNLOCK_ENV();
+    return (result)? PR_FAILURE : PR_SUCCESS;
+}
diff --git a/mozilla/nsprpub/pr/src/misc/prerr.c b/mozilla/nsprpub/pr/src/misc/prerr.c
new file mode 100644
index 0000000..4db3113
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prerr.c
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ *
+ * prerr.c
+ * This file is automatically generated; please do not edit it.
+ */
+#include "prerror.h"
+static const struct PRErrorMessage text[] = {
+	{"PR_OUT_OF_MEMORY_ERROR",    "Memory allocation attempt failed"},
+	{"PR_BAD_DESCRIPTOR_ERROR",    "Invalid file descriptor"},
+	{"PR_WOULD_BLOCK_ERROR",    "The operation would have blocked"},
+	{"PR_ACCESS_FAULT_ERROR",    "Invalid memory address argument"},
+	{"PR_INVALID_METHOD_ERROR",    "Invalid function for file type"},
+	{"PR_ILLEGAL_ACCESS_ERROR",    "Invalid memory address argument"},
+	{"PR_UNKNOWN_ERROR",    "Some unknown error has occurred"},
+	{"PR_PENDING_INTERRUPT_ERROR",    "Operation interrupted by another thread"},
+	{"PR_NOT_IMPLEMENTED_ERROR",    "function not implemented"},
+	{"PR_IO_ERROR",    "I/O function error"},
+	{"PR_IO_TIMEOUT_ERROR",    "I/O operation timed out"},
+	{"PR_IO_PENDING_ERROR",    "I/O operation on busy file descriptor"},
+	{"PR_DIRECTORY_OPEN_ERROR",    "The directory could not be opened"},
+	{"PR_INVALID_ARGUMENT_ERROR",    "Invalid function argument"},
+	{"PR_ADDRESS_NOT_AVAILABLE_ERROR",    "Network address not available (in use?)"},
+	{"PR_ADDRESS_NOT_SUPPORTED_ERROR",    "Network address type not supported"},
+	{"PR_IS_CONNECTED_ERROR",    "Already connected"},
+	{"PR_BAD_ADDRESS_ERROR",    "Network address is invalid"},
+	{"PR_ADDRESS_IN_USE_ERROR",    "Local Network address is in use"},
+	{"PR_CONNECT_REFUSED_ERROR",    "Connection refused by peer"},
+	{"PR_NETWORK_UNREACHABLE_ERROR",    "Network address is presently unreachable"},
+	{"PR_CONNECT_TIMEOUT_ERROR",    "Connection attempt timed out"},
+	{"PR_NOT_CONNECTED_ERROR",    "Network file descriptor is not connected"},
+	{"PR_LOAD_LIBRARY_ERROR",    "Failure to load dynamic library"},
+	{"PR_UNLOAD_LIBRARY_ERROR",    "Failure to unload dynamic library"},
+	{"PR_FIND_SYMBOL_ERROR",    "Symbol not found in any of the loaded dynamic libraries"},
+	{"PR_INSUFFICIENT_RESOURCES_ERROR",    "Insufficient system resources"},
+	{"PR_DIRECTORY_LOOKUP_ERROR",    "A directory lookup on a network address has failed"},
+	{"PR_TPD_RANGE_ERROR",    "Attempt to access a TPD key that is out of range"},
+	{"PR_PROC_DESC_TABLE_FULL_ERROR",    "Process open FD table is full"},
+	{"PR_SYS_DESC_TABLE_FULL_ERROR",    "System open FD table is full"},
+	{"PR_NOT_SOCKET_ERROR",    "Network operation attempted on non-network file descriptor"},
+	{"PR_NOT_TCP_SOCKET_ERROR",    "TCP-specific function attempted on a non-TCP file descriptor"},
+	{"PR_SOCKET_ADDRESS_IS_BOUND_ERROR",    "TCP file descriptor is already bound"},
+	{"PR_NO_ACCESS_RIGHTS_ERROR",    "Access Denied"},
+	{"PR_OPERATION_NOT_SUPPORTED_ERROR",    "The requested operation is not supported by the platform"},
+	{"PR_PROTOCOL_NOT_SUPPORTED_ERROR",    "The host operating system does not support the protocol requested"},
+	{"PR_REMOTE_FILE_ERROR",    "Access to the remote file has been severed"},
+	{"PR_BUFFER_OVERFLOW_ERROR",    "The value requested is too large to be stored in the data buffer provided"},
+	{"PR_CONNECT_RESET_ERROR",    "TCP connection reset by peer"},
+	{"PR_RANGE_ERROR",    "Unused"},
+	{"PR_DEADLOCK_ERROR",    "The operation would have deadlocked"},
+	{"PR_FILE_IS_LOCKED_ERROR",    "The file is already locked"},
+	{"PR_FILE_TOO_BIG_ERROR",    "Write would result in file larger than the system allows"},
+	{"PR_NO_DEVICE_SPACE_ERROR",    "The device for storing the file is full"},
+	{"PR_PIPE_ERROR",    "Unused"},
+	{"PR_NO_SEEK_DEVICE_ERROR",    "Unused"},
+	{"PR_IS_DIRECTORY_ERROR",    "Cannot perform a normal file operation on a directory"},
+	{"PR_LOOP_ERROR",    "Symbolic link loop"},
+	{"PR_NAME_TOO_LONG_ERROR",    "File name is too long"},
+	{"PR_FILE_NOT_FOUND_ERROR",    "File not found"},
+	{"PR_NOT_DIRECTORY_ERROR",    "Cannot perform directory operation on a normal file"},
+	{"PR_READ_ONLY_FILESYSTEM_ERROR",    "Cannot write to a read-only file system"},
+	{"PR_DIRECTORY_NOT_EMPTY_ERROR",    "Cannot delete a directory that is not empty"},
+	{"PR_FILESYSTEM_MOUNTED_ERROR",    "Cannot delete or rename a file object while the file system is busy"},
+	{"PR_NOT_SAME_DEVICE_ERROR",    "Cannot rename a file to a file system on another device"},
+	{"PR_DIRECTORY_CORRUPTED_ERROR",    "The directory object in the file system is corrupted"},
+	{"PR_FILE_EXISTS_ERROR",    "Cannot create or rename a filename that already exists"},
+	{"PR_MAX_DIRECTORY_ENTRIES_ERROR",    "Directory is full.  No additional filenames may be added"},
+	{"PR_INVALID_DEVICE_STATE_ERROR",    "The required device was in an invalid state"},
+	{"PR_DEVICE_IS_LOCKED_ERROR",    "The device is locked"},
+	{"PR_NO_MORE_FILES_ERROR",    "No more entries in the directory"},
+	{"PR_END_OF_FILE_ERROR",    "Encountered end of file"},
+	{"PR_FILE_SEEK_ERROR",    "Seek error"},
+	{"PR_FILE_IS_BUSY_ERROR",    "The file is busy"},
+	{"PR_OPERATION_ABORTED_ERROR",    "The I/O operation was aborted"},
+	{"PR_IN_PROGRESS_ERROR",    "Operation is still in progress (probably a non-blocking connect)"},
+	{"PR_ALREADY_INITIATED_ERROR",    "Operation has already been initiated (probably a non-blocking connect)"},
+	{"PR_GROUP_EMPTY_ERROR",    "The wait group is empty"},
+	{"PR_INVALID_STATE_ERROR",    "Object state improper for request"},
+	{"PR_NETWORK_DOWN_ERROR",    "Network is down"},
+	{"PR_SOCKET_SHUTDOWN_ERROR",    "Socket shutdown"},
+	{"PR_CONNECT_ABORTED_ERROR",    "Connection aborted"},
+	{"PR_HOST_UNREACHABLE_ERROR",    "Host is unreachable"},
+	{"PR_LIBRARY_NOT_LOADED_ERROR",    "The library is not loaded"},
+	{"PR_CALL_ONCE_ERROR",    "The one-time function was previously called and failed. Its error code is no longer available"},
+	{"PR_MAX_ERROR",    "Placeholder for the end of the list"},
+	{0, 0}
+};
+
+static const struct PRErrorTable et = { text, "prerr", -6000L, 77 };
+
+void nspr_InitializePRErrorTable(void) {
+    PR_ErrorInstallTable(&et);
+}
diff --git a/mozilla/nsprpub/pr/src/misc/prerror.c b/mozilla/nsprpub/pr/src/misc/prerror.c
new file mode 100644
index 0000000..f578f2d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prerror.c
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+PR_IMPLEMENT(PRErrorCode) PR_GetError(void)
+{
+    PRThread *thread = PR_GetCurrentThread();
+    return thread->errorCode;
+}
+
+PR_IMPLEMENT(PRInt32) PR_GetOSError(void)
+{
+    PRThread *thread = PR_GetCurrentThread();
+    return thread->osErrorCode;
+}
+
+PR_IMPLEMENT(void) PR_SetError(PRErrorCode code, PRInt32 osErr)
+{
+    PRThread *thread = PR_GetCurrentThread();
+    thread->errorCode = code;
+    thread->osErrorCode = osErr;
+    thread->errorStringLength = 0;
+}
+
+PR_IMPLEMENT(void) PR_SetErrorText(PRIntn textLength, const char *text)
+{
+    PRThread *thread = PR_GetCurrentThread();
+
+    if (0 == textLength)
+    {
+	    if (NULL != thread->errorString)
+	        PR_DELETE(thread->errorString);
+	    thread->errorStringSize = 0;
+    }
+    else
+    {
+	    PRIntn size = textLength + 31;  /* actual length to allocate. Plus a little extra */
+        if (thread->errorStringSize < textLength+1)  /* do we have room? */
+        {
+	        if (NULL != thread->errorString)
+	            PR_DELETE(thread->errorString);
+		    thread->errorString = (char*)PR_MALLOC(size);
+            if ( NULL == thread->errorString ) {
+                thread->errorStringSize = 0;
+                thread->errorStringLength = 0;
+                return;
+            }
+            thread->errorStringSize = size;
+	    }
+        memcpy(thread->errorString, text, textLength+1 );
+    }
+    thread->errorStringLength = textLength;
+}
+
+PR_IMPLEMENT(PRInt32) PR_GetErrorTextLength(void)
+{
+    PRThread *thread = PR_GetCurrentThread();
+    return thread->errorStringLength;
+}  /* PR_GetErrorTextLength */
+
+PR_IMPLEMENT(PRInt32) PR_GetErrorText(char *text)
+{
+    PRThread *thread = PR_GetCurrentThread();
+    if (0 != thread->errorStringLength)
+        memcpy(text, thread->errorString, thread->errorStringLength+1);
+    return thread->errorStringLength;
+}  /* PR_GetErrorText */
+
+
diff --git a/mozilla/nsprpub/pr/src/misc/prerrortable.c b/mozilla/nsprpub/pr/src/misc/prerrortable.c
new file mode 100644
index 0000000..a51b4e8
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prerrortable.c
@@ -0,0 +1,240 @@
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+
+
+
+/*
+
+Copyright 1987, 1988 by the Student Information Processing Board
+	of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+*/
+
+#include <string.h>
+#ifdef SUNOS4
+#include "md/sunos4.h"  /* for strerror */
+#endif
+#include <assert.h>
+#include <errno.h>
+#include "prmem.h"
+#include "prerror.h"
+
+#define	ERRCODE_RANGE	8	/* # of bits to shift table number */
+#define	BITS_PER_CHAR	6	/* # bits to shift per character in name */
+
+#ifdef NEED_SYS_ERRLIST
+extern char const * const sys_errlist[];
+extern const int sys_nerr;
+#endif
+
+/* List of error tables */
+struct PRErrorTableList {
+    struct PRErrorTableList *next;
+    const struct PRErrorTable *table;
+    struct PRErrorCallbackTablePrivate *table_private;
+};
+static struct PRErrorTableList * Table_List = (struct PRErrorTableList *) NULL;
+
+/* Supported languages */
+static const char * default_languages[] = { "i-default", "en", 0 };
+static const char * const * callback_languages = default_languages;
+
+/* Callback info */
+static struct PRErrorCallbackPrivate *callback_private = 0;
+static PRErrorCallbackLookupFn *callback_lookup = 0;
+static PRErrorCallbackNewTableFn *callback_newtable = 0;
+
+
+static const char char_set[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+static const char *
+error_table_name (PRErrorCode num)
+{
+    static char buf[6];	/* only used if internal code problems exist */
+
+    long ch;
+    int i;
+    char *p;
+
+    /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */
+    p = buf;
+    num >>= ERRCODE_RANGE;
+    /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */
+    num &= 077777777;
+    /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */
+    for (i = 4; i >= 0; i--) {
+	ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1);
+	if (ch != 0)
+	    *p++ = char_set[ch-1];
+    }
+    *p = '\0';
+    return(buf);
+}
+
+PR_IMPLEMENT(const char *)
+PR_ErrorToString(PRErrorCode code, PRLanguageCode language)
+{
+    /* static buffer only used if code is using inconsistent error message
+     * numbers, so just ignore the possible thread contention
+     */
+    static char buffer[25];
+
+    const char *msg;
+    int offset;
+    PRErrorCode table_num;
+    struct PRErrorTableList *et;
+    int started = 0;
+    char *cp;
+
+    for (et = Table_List; et; et = et->next) {
+	if (et->table->base <= code &&
+	    et->table->base + et->table->n_msgs > code) {
+	    /* This is the right table */
+	    if (callback_lookup) {
+		msg = callback_lookup(code, language, et->table,
+		    callback_private, et->table_private);
+		if (msg) return msg;
+	    }
+    
+	    return(et->table->msgs[code - et->table->base].en_text);
+	}
+    }
+
+    if (code >= 0 && code < 256) {
+	return strerror(code);
+    }
+
+    offset = (int) (code & ((1<<ERRCODE_RANGE)-1));
+    table_num = code - offset;
+    strcpy (buffer, "Unknown code ");
+    if (table_num) {
+	strcat(buffer, error_table_name (table_num));
+	strcat(buffer, " ");
+    }
+    for (cp = buffer; *cp; cp++)
+	;
+    if (offset >= 100) {
+	*cp++ = (char)('0' + offset / 100);
+	offset %= 100;
+	started++;
+    }
+    if (started || offset >= 10) {
+	*cp++ = (char)('0' + offset / 10);
+	offset %= 10;
+    }
+    *cp++ = (char)('0' + offset);
+    *cp = '\0';
+    return(buffer);
+}
+
+PR_IMPLEMENT(const char *)
+PR_ErrorToName(PRErrorCode code)
+{
+    struct PRErrorTableList *et;
+
+    for (et = Table_List; et; et = et->next) {
+	if (et->table->base <= code &&
+	    et->table->base + et->table->n_msgs > code) {
+	    /* This is the right table */
+	    return(et->table->msgs[code - et->table->base].name);
+	}
+    }
+
+    return 0;
+}
+
+PR_IMPLEMENT(const char * const *)
+PR_ErrorLanguages(void)
+{
+    return callback_languages;
+}
+
+PR_IMPLEMENT(PRErrorCode)
+PR_ErrorInstallTable(const struct PRErrorTable *table)
+{
+    struct PRErrorTableList * new_et;
+
+    new_et = (struct PRErrorTableList *)
+					PR_Malloc(sizeof(struct PRErrorTableList));
+    if (!new_et)
+	return errno;	/* oops */
+    new_et->table = table;
+    if (callback_newtable) {
+	new_et->table_private = callback_newtable(table, callback_private);
+    } else {
+	new_et->table_private = 0;
+    }
+    new_et->next = Table_List;
+    Table_List = new_et;
+    return 0;
+}
+
+PR_IMPLEMENT(void)
+PR_ErrorInstallCallback(const char * const * languages,
+		       PRErrorCallbackLookupFn *lookup, 
+		       PRErrorCallbackNewTableFn *newtable,
+		       struct PRErrorCallbackPrivate *cb_private)
+{
+    struct PRErrorTableList *et;
+
+    assert(strcmp(languages[0], "i-default") == 0);
+    assert(strcmp(languages[1], "en") == 0);
+    
+    callback_languages = languages;
+    callback_lookup = lookup;
+    callback_newtable = newtable;
+    callback_private = cb_private;
+
+    if (callback_newtable) {
+	for (et = Table_List; et; et = et->next) {
+	    et->table_private = callback_newtable(et->table, callback_private);
+	}
+    }
+}
diff --git a/mozilla/nsprpub/pr/src/misc/prinit.c b/mozilla/nsprpub/pr/src/misc/prinit.c
new file mode 100644
index 0000000..bfac4c2
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prinit.c
@@ -0,0 +1,866 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#include <ctype.h>
+#include <string.h>
+
+PRLogModuleInfo *_pr_clock_lm;
+PRLogModuleInfo *_pr_cmon_lm;
+PRLogModuleInfo *_pr_io_lm;
+PRLogModuleInfo *_pr_cvar_lm;
+PRLogModuleInfo *_pr_mon_lm;
+PRLogModuleInfo *_pr_linker_lm;
+PRLogModuleInfo *_pr_sched_lm;
+PRLogModuleInfo *_pr_thread_lm;
+PRLogModuleInfo *_pr_gc_lm;
+PRLogModuleInfo *_pr_shm_lm;
+PRLogModuleInfo *_pr_shma_lm;
+
+PRFileDesc *_pr_stdin;
+PRFileDesc *_pr_stdout;
+PRFileDesc *_pr_stderr;
+
+#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
+
+PRCList _pr_active_local_threadQ =
+			PR_INIT_STATIC_CLIST(&_pr_active_local_threadQ);
+PRCList _pr_active_global_threadQ =
+			PR_INIT_STATIC_CLIST(&_pr_active_global_threadQ);
+
+_MDLock  _pr_cpuLock;           /* lock for the CPU Q */
+PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ);
+
+PRUint32 _pr_utid;
+
+PRInt32 _pr_userActive;
+PRInt32 _pr_systemActive;
+PRUintn _pr_maxPTDs;
+
+#ifdef _PR_LOCAL_THREADS_ONLY
+
+struct _PRCPU 	*_pr_currentCPU;
+PRThread 	*_pr_currentThread;
+PRThread 	*_pr_lastThread;
+PRInt32 	_pr_intsOff;
+
+#endif /* _PR_LOCAL_THREADS_ONLY */
+
+/* Lock protecting all "termination" condition variables of all threads */
+PRLock *_pr_terminationCVLock;
+
+#endif /* !defined(_PR_PTHREADS) */
+
+PRLock *_pr_sleeplock;  /* used in PR_Sleep(), classic and pthreads */
+
+static void _PR_InitCallOnce(void);
+
+PRBool _pr_initialized = PR_FALSE;
+
+
+PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion)
+{
+    /*
+    ** This is the secret handshake algorithm.
+    **
+    ** This release has a simple version compatibility
+    ** check algorithm.  This release is not backward
+    ** compatible with previous major releases.  It is
+    ** not compatible with future major, minor, or
+    ** patch releases.
+    */
+    int vmajor = 0, vminor = 0, vpatch = 0;
+    const char *ptr = importedVersion;
+
+    while (isdigit(*ptr)) {
+        vmajor = 10 * vmajor + *ptr - '0';
+        ptr++;
+    }
+    if (*ptr == '.') {
+        ptr++;
+        while (isdigit(*ptr)) {
+            vminor = 10 * vminor + *ptr - '0';
+            ptr++;
+        }
+        if (*ptr == '.') {
+            ptr++;
+            while (isdigit(*ptr)) {
+                vpatch = 10 * vpatch + *ptr - '0';
+                ptr++;
+            }
+        }
+    }
+
+    if (vmajor != PR_VMAJOR) {
+        return PR_FALSE;
+    }
+    if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
+        return PR_FALSE;
+    }
+    if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) {
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}  /* PR_VersionCheck */
+
+
+PR_IMPLEMENT(PRBool) PR_Initialized(void)
+{
+    return _pr_initialized;
+}
+
+PRInt32 _native_threads_only = 0;
+
+#ifdef WINNT
+static void _pr_SetNativeThreadsOnlyMode(void)
+{
+    HMODULE mainExe;
+    PRBool *globalp;
+    char *envp;
+
+    mainExe = GetModuleHandle(NULL);
+    PR_ASSERT(NULL != mainExe);
+    globalp = (PRBool *) GetProcAddress(mainExe, "nspr_native_threads_only");
+    if (globalp) {
+        _native_threads_only = (*globalp != PR_FALSE);
+    } else if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) {
+        _native_threads_only = (atoi(envp) == 1);
+    }
+}
+#endif
+
+static void _PR_InitStuff(void)
+{
+
+    if (_pr_initialized) return;
+    _pr_initialized = PR_TRUE;
+#ifdef _PR_ZONE_ALLOCATOR
+    _PR_InitZones();
+#endif
+#ifdef WINNT
+    _pr_SetNativeThreadsOnlyMode();
+#endif
+
+
+    (void) PR_GetPageSize();
+
+	_pr_clock_lm = PR_NewLogModule("clock");
+	_pr_cmon_lm = PR_NewLogModule("cmon");
+	_pr_io_lm = PR_NewLogModule("io");
+	_pr_mon_lm = PR_NewLogModule("mon");
+	_pr_linker_lm = PR_NewLogModule("linker");
+	_pr_cvar_lm = PR_NewLogModule("cvar");
+	_pr_sched_lm = PR_NewLogModule("sched");
+	_pr_thread_lm = PR_NewLogModule("thread");
+	_pr_gc_lm = PR_NewLogModule("gc");
+	_pr_shm_lm = PR_NewLogModule("shm");
+	_pr_shma_lm = PR_NewLogModule("shma");
+      
+    /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ 
+    _PR_MD_EARLY_INIT();
+
+    _PR_InitLocks();
+    _PR_InitAtomic();
+    _PR_InitSegs();
+    _PR_InitStacks();
+	_PR_InitTPD();
+    _PR_InitEnv();
+    _PR_InitLayerCache();
+    _PR_InitClock();
+
+    _pr_sleeplock = PR_NewLock();
+    PR_ASSERT(NULL != _pr_sleeplock);
+
+#ifdef GC_LEAK_DETECTOR
+    _PR_InitGarbageCollector();
+#endif
+
+    _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+    
+#ifdef WIN16
+	{
+	PRInt32 top;   /* artificial top of stack, win16 */
+    _pr_top_of_task_stack = (char *) &top;
+	}
+#endif    
+
+#ifndef _PR_GLOBAL_THREADS_ONLY
+	_PR_InitCPUs();
+#endif
+
+/*
+ * XXX: call _PR_InitMem only on those platforms for which nspr implements
+ *	malloc, for now.
+ */
+#ifdef _PR_OVERRIDE_MALLOC
+    _PR_InitMem();
+#endif
+
+    _PR_InitCMon();
+    _PR_InitIO();
+    _PR_InitNet();
+    _PR_InitTime();
+    _PR_InitLog();
+    _PR_InitLinker();
+    _PR_InitCallOnce();
+    _PR_InitDtoa();
+    _PR_InitMW();
+    _PR_InitRWLocks();
+
+    nspr_InitializePRErrorTable();
+
+    _PR_MD_FINAL_INIT();
+}
+
+void _PR_ImplicitInitialization(void)
+{
+	_PR_InitStuff();
+
+    /* Enable interrupts */
+#if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY)
+    _PR_MD_START_INTERRUPTS();
+#endif
+
+}
+
+PR_IMPLEMENT(void) PR_DisableClockInterrupts(void)
+{
+#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
+	if (!_pr_initialized) {
+		_PR_InitStuff();
+	} else {
+    	_PR_MD_DISABLE_CLOCK_INTERRUPTS();
+	}
+#endif
+}
+
+PR_IMPLEMENT(void) PR_EnableClockInterrupts(void)
+{
+#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
+	if (!_pr_initialized) {
+		_PR_InitStuff();
+	}
+    _PR_MD_ENABLE_CLOCK_INTERRUPTS();
+#endif
+}
+
+PR_IMPLEMENT(void) PR_BlockClockInterrupts(void)
+{
+#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
+    	_PR_MD_BLOCK_CLOCK_INTERRUPTS();
+#endif
+}
+
+PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void)
+{
+#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
+    	_PR_MD_UNBLOCK_CLOCK_INTERRUPTS();
+#endif
+}
+
+PR_IMPLEMENT(void) PR_Init(
+    PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
+{
+    _PR_ImplicitInitialization();
+}
+
+PR_IMPLEMENT(PRIntn) PR_Initialize(
+    PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs)
+{
+    PRIntn rv;
+    _PR_ImplicitInitialization();
+    rv = prmain(argc, argv);
+	PR_Cleanup();
+    return rv;
+}  /* PR_Initialize */
+
+/*
+ *-----------------------------------------------------------------------
+ *
+ * _PR_CleanupBeforeExit --
+ *
+ *   Perform the cleanup work before exiting the process. 
+ *   We first do the cleanup generic to all platforms.  Then
+ *   we call _PR_MD_CLEANUP_BEFORE_EXIT(), where platform-dependent
+ *   cleanup is done.  This function is used by PR_Cleanup().
+ *
+ * See also: PR_Cleanup().
+ *
+ *-----------------------------------------------------------------------
+ */
+#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
+    /* see ptthread.c */
+#else
+static void
+_PR_CleanupBeforeExit(void)
+{
+/* 
+Do not make any calls here other than to destroy resources.  For example,
+do not make any calls that eventually may end up in PR_Lock.  Because the
+thread is destroyed, can not access current thread any more.
+*/
+    _PR_CleanupTPD();
+    if (_pr_terminationCVLock)
+    /*
+     * In light of the comment above, this looks real suspicious.
+     * I'd go so far as to say it's just a problem waiting to happen.
+     */
+        PR_DestroyLock(_pr_terminationCVLock);
+
+    _PR_MD_CLEANUP_BEFORE_EXIT();
+}
+#endif /* defined(_PR_PTHREADS) */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * PR_Cleanup --
+ *
+ *   Perform a graceful shutdown of the NSPR runtime.  PR_Cleanup() may
+ *   only be called from the primordial thread, typically at the
+ *   end of the main() function.  It returns when it has completed
+ *   its platform-dependent duty and the process must not make any other
+ *   NSPR library calls prior to exiting from main().
+ *
+ *   PR_Cleanup() first blocks the primordial thread until all the
+ *   other user (non-system) threads, if any, have terminated.
+ *   Then it performs cleanup in preparation for exiting the process.
+ *   PR_Cleanup() does not exit the primordial thread (which would
+ *   in turn exit the process).
+ *   
+ *   PR_Cleanup() only responds when it is called by the primordial
+ *   thread. Calls by any other thread are silently ignored.
+ *
+ * See also: PR_ExitProcess()
+ *
+ *----------------------------------------------------------------------
+ */
+#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
+    /* see ptthread.c */
+#else
+
+PR_IMPLEMENT(PRStatus) PR_Cleanup()
+{
+    PRThread *me = PR_GetCurrentThread();
+    PR_ASSERT((NULL != me) && (me->flags & _PR_PRIMORDIAL));
+    if ((NULL != me) && (me->flags & _PR_PRIMORDIAL))
+    {
+        PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
+
+        /*
+         * No more recycling of threads
+         */
+        _pr_recycleThreads = 0;
+
+        /*
+         * Wait for all other user (non-system/daemon) threads
+         * to terminate.
+         */
+        PR_Lock(_pr_activeLock);
+        while (_pr_userActive > _pr_primordialExitCount) {
+            PR_WaitCondVar(_pr_primordialExitCVar, PR_INTERVAL_NO_TIMEOUT);
+        }
+        if (me->flags & _PR_SYSTEM) {
+            _pr_systemActive--;
+        } else {
+            _pr_userActive--;
+        }
+        PR_Unlock(_pr_activeLock);
+
+#ifdef IRIX
+		_PR_MD_PRE_CLEANUP(me);
+		/*
+		 * The primordial thread must now be running on the primordial cpu
+		 */
+    	PR_ASSERT((_PR_IS_NATIVE_THREAD(me)) || (me->cpu->id == 0));
+#endif
+
+        _PR_CleanupMW();
+        _PR_CleanupTime();
+        _PR_CleanupDtoa();
+        _PR_CleanupCallOnce();
+		_PR_ShutdownLinker();
+        _PR_CleanupNet();
+        _PR_CleanupIO();
+        /* Release the primordial thread's private data, etc. */
+        _PR_CleanupThread(me);
+
+        _PR_MD_STOP_INTERRUPTS();
+
+	    PR_LOG(_pr_thread_lm, PR_LOG_MIN,
+	            ("PR_Cleanup: clean up before destroying thread"));
+	    _PR_LogCleanup();
+
+        /*
+         * This part should look like the end of _PR_NativeRunThread
+         * and _PR_UserRunThread.
+         */
+        if (_PR_IS_NATIVE_THREAD(me)) {
+            _PR_MD_EXIT_THREAD(me);
+            _PR_NativeDestroyThread(me);
+        } else {
+            _PR_UserDestroyThread(me);
+            PR_DELETE(me->stack);
+            PR_DELETE(me);
+        }
+
+        /*
+         * XXX: We are freeing the heap memory here so that Purify won't
+         * complain, but we should also free other kinds of resources
+         * that are allocated by the _PR_InitXXX() functions.
+         * Ideally, for each _PR_InitXXX(), there should be a corresponding
+         * _PR_XXXCleanup() that we can call here.
+         */
+#ifdef WINNT
+        _PR_CleanupCPUs();
+#endif
+        _PR_CleanupThreads();
+        _PR_CleanupCMon();
+        PR_DestroyLock(_pr_sleeplock);
+        _pr_sleeplock = NULL;
+        _PR_CleanupLayerCache();
+        _PR_CleanupEnv();
+        _PR_CleanupStacks();
+        _PR_CleanupBeforeExit();
+        _pr_initialized = PR_FALSE;
+        return PR_SUCCESS;
+    }
+    return PR_FAILURE;
+}
+#endif /* defined(_PR_PTHREADS) */
+
+/*
+ *------------------------------------------------------------------------
+ * PR_ProcessExit --
+ * 
+ *   Cause an immediate, nongraceful, forced termination of the process.
+ *   It takes a PRIntn argument, which is the exit status code of the
+ *   process.
+ *   
+ * See also: PR_Cleanup()
+ *
+ *------------------------------------------------------------------------
+ */
+
+#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
+    /* see ptthread.c */
+#else
+PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
+{
+    _PR_MD_EXIT(status);
+}
+
+#endif /* defined(_PR_PTHREADS) */
+
+PR_IMPLEMENT(PRProcessAttr *)
+PR_NewProcessAttr(void)
+{
+    PRProcessAttr *attr;
+
+    attr = PR_NEWZAP(PRProcessAttr);
+    if (!attr) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    }
+    return attr;
+}
+
+PR_IMPLEMENT(void)
+PR_ResetProcessAttr(PRProcessAttr *attr)
+{
+    PR_FREEIF(attr->currentDirectory);
+    PR_FREEIF(attr->fdInheritBuffer);
+    memset(attr, 0, sizeof(*attr));
+}
+
+PR_IMPLEMENT(void)
+PR_DestroyProcessAttr(PRProcessAttr *attr)
+{
+    PR_FREEIF(attr->currentDirectory);
+    PR_FREEIF(attr->fdInheritBuffer);
+    PR_DELETE(attr);
+}
+
+PR_IMPLEMENT(void)
+PR_ProcessAttrSetStdioRedirect(
+    PRProcessAttr *attr,
+    PRSpecialFD stdioFd,
+    PRFileDesc *redirectFd)
+{
+    switch (stdioFd) {
+        case PR_StandardInput:
+            attr->stdinFd = redirectFd;
+            break;
+        case PR_StandardOutput:
+            attr->stdoutFd = redirectFd;
+            break;
+        case PR_StandardError:
+            attr->stderrFd = redirectFd;
+            break;
+        default:
+            PR_ASSERT(0);
+    }
+}
+
+/*
+ * OBSOLETE
+ */
+PR_IMPLEMENT(void)
+PR_SetStdioRedirect(
+    PRProcessAttr *attr,
+    PRSpecialFD stdioFd,
+    PRFileDesc *redirectFd)
+{
+#if defined(DEBUG)
+    static PRBool warn = PR_TRUE;
+    if (warn) {
+        warn = _PR_Obsolete("PR_SetStdioRedirect()",
+                "PR_ProcessAttrSetStdioRedirect()");
+    }
+#endif
+    PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd);
+}
+
+PR_IMPLEMENT(PRStatus)
+PR_ProcessAttrSetCurrentDirectory(
+    PRProcessAttr *attr,
+    const char *dir)
+{
+    PR_FREEIF(attr->currentDirectory);
+    attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1);
+    if (!attr->currentDirectory) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return PR_FAILURE;
+    }
+    strcpy(attr->currentDirectory, dir);
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus)
+PR_ProcessAttrSetInheritableFD(
+    PRProcessAttr *attr,
+    PRFileDesc *fd,
+    const char *name)
+{
+    /* We malloc the fd inherit buffer in multiples of this number. */
+#define FD_INHERIT_BUFFER_INCR 128
+    /* The length of "NSPR_INHERIT_FDS=" */
+#define NSPR_INHERIT_FDS_STRLEN 17
+    /* The length of osfd (PROsfd) printed in hexadecimal with 0x prefix */
+#ifdef _WIN64
+#define OSFD_STRLEN 18
+#else
+#define OSFD_STRLEN 10
+#endif
+    /* The length of fd type (PRDescType) printed in decimal */
+#define FD_TYPE_STRLEN 1
+    PRSize newSize;
+    int remainder;
+    char *newBuffer;
+    int nwritten;
+    char *cur;
+    int freeSize;
+
+    if (fd->identity != PR_NSPR_IO_LAYER) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    if (fd->secret->inheritable == _PR_TRI_UNKNOWN) {
+        _PR_MD_QUERY_FD_INHERITABLE(fd);
+    }
+    if (fd->secret->inheritable != _PR_TRI_TRUE) {
+        PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    /*
+     * We also need to account for the : separators and the
+     * terminating null byte.
+     */
+    if (NULL == attr->fdInheritBuffer) {
+        /* The first time, we print "NSPR_INHERIT_FDS=<name>:<type>:<val>" */
+        newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name)
+                + FD_TYPE_STRLEN + OSFD_STRLEN + 2 + 1;
+    } else {
+        /* At other times, we print ":<name>:<type>:<val>" */
+        newSize = attr->fdInheritBufferUsed + strlen(name)
+                + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1;
+    }
+    if (newSize > attr->fdInheritBufferSize) {
+        /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */
+        remainder = newSize % FD_INHERIT_BUFFER_INCR;
+        if (remainder != 0) {
+            newSize += (FD_INHERIT_BUFFER_INCR - remainder);
+        }
+        if (NULL == attr->fdInheritBuffer) {
+            newBuffer = (char *) PR_MALLOC(newSize);
+        } else {
+            newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize);
+        }
+        if (NULL == newBuffer) {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return PR_FAILURE;
+        }
+        attr->fdInheritBuffer = newBuffer;
+        attr->fdInheritBufferSize = newSize;
+    }
+    cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed;
+    freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed;
+    if (0 == attr->fdInheritBufferUsed) {
+        nwritten = PR_snprintf(cur, freeSize,
+                "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD,
+                name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
+    } else {
+        nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD,
+                name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
+    }
+    attr->fdInheritBufferUsed += nwritten; 
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD(
+    const char *name)
+{
+    PRFileDesc *fd;
+    const char *envVar;
+    const char *ptr;
+    int len = strlen(name);
+    PROsfd osfd;
+    int nColons;
+    PRIntn fileType;
+
+    envVar = PR_GetEnv("NSPR_INHERIT_FDS");
+    if (NULL == envVar || '\0' == envVar[0]) {
+        PR_SetError(PR_UNKNOWN_ERROR, 0);
+        return NULL;
+    }
+
+    ptr = envVar;
+    while (1) {
+        if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) {
+            ptr += len + 1;
+            PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd);
+            switch ((PRDescType)fileType) {
+                case PR_DESC_FILE:
+                    fd = PR_ImportFile(osfd);
+                    break;
+                case PR_DESC_PIPE:
+                    fd = PR_ImportPipe(osfd);
+                    break;
+                case PR_DESC_SOCKET_TCP:
+                    fd = PR_ImportTCPSocket(osfd);
+                    break;
+                case PR_DESC_SOCKET_UDP:
+                    fd = PR_ImportUDPSocket(osfd);
+                    break;
+                default:
+                    PR_ASSERT(0);
+                    PR_SetError(PR_UNKNOWN_ERROR, 0);
+                    fd = NULL;
+                    break;
+            }
+            if (fd) {
+                /*
+                 * An inherited FD is inheritable by default.
+                 * The child process needs to call PR_SetFDInheritable
+                 * to make it non-inheritable if so desired.
+                 */
+                fd->secret->inheritable = _PR_TRI_TRUE;
+            }
+            return fd;
+        }
+        /* Skip three colons */
+        nColons = 0;
+        while (*ptr) {
+            if (*ptr == ':') {
+                if (++nColons == 3) {
+                    break;
+                }
+            }
+            ptr++;
+        }
+        if (*ptr == '\0') {
+            PR_SetError(PR_UNKNOWN_ERROR, 0);
+            return NULL;
+        }
+        ptr++;
+    }
+}
+
+PR_IMPLEMENT(PRProcess*) PR_CreateProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    return _PR_MD_CREATE_PROCESS(path, argv, envp, attr);
+}  /* PR_CreateProcess */
+
+PR_IMPLEMENT(PRStatus) PR_CreateProcessDetached(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    PRProcess *process;
+    PRStatus rv;
+
+    process = PR_CreateProcess(path, argv, envp, attr);
+    if (NULL == process) {
+	return PR_FAILURE;
+    }
+    rv = PR_DetachProcess(process);
+    PR_ASSERT(PR_SUCCESS == rv);
+    if (rv == PR_FAILURE) {
+	PR_DELETE(process);
+	return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process)
+{
+    return _PR_MD_DETACH_PROCESS(process);
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode)
+{
+    return _PR_MD_WAIT_PROCESS(process, exitCode);
+}  /* PR_WaitProcess */
+
+PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process)
+{
+    return _PR_MD_KILL_PROCESS(process);
+}
+
+/*
+ ********************************************************************
+ *
+ * Module initialization
+ *
+ ********************************************************************
+ */
+
+static struct {
+    PRLock *ml;
+    PRCondVar *cv;
+} mod_init;
+
+static void _PR_InitCallOnce(void) {
+    mod_init.ml = PR_NewLock();
+    PR_ASSERT(NULL != mod_init.ml);
+    mod_init.cv = PR_NewCondVar(mod_init.ml);
+    PR_ASSERT(NULL != mod_init.cv);
+}
+
+void _PR_CleanupCallOnce()
+{
+    PR_DestroyLock(mod_init.ml);
+    mod_init.ml = NULL;
+    PR_DestroyCondVar(mod_init.cv);
+    mod_init.cv = NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CallOnce(
+    PRCallOnceType *once,
+    PRCallOnceFN    func)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (!once->initialized) {
+	if (PR_AtomicSet(&once->inProgress, 1) == 0) {
+	    once->status = (*func)();
+	    PR_Lock(mod_init.ml);
+	    once->initialized = 1;
+	    PR_NotifyAllCondVar(mod_init.cv);
+	    PR_Unlock(mod_init.ml);
+	} else {
+	    PR_Lock(mod_init.ml);
+	    while (!once->initialized) {
+		PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
+            }
+	    PR_Unlock(mod_init.ml);
+	}
+    } else {
+        if (PR_SUCCESS != once->status) {
+            PR_SetError(PR_CALL_ONCE_ERROR, 0);
+        }
+    }
+    return once->status;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg(
+    PRCallOnceType      *once,
+    PRCallOnceWithArgFN  func,
+    void                *arg)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (!once->initialized) {
+	if (PR_AtomicSet(&once->inProgress, 1) == 0) {
+	    once->status = (*func)(arg);
+	    PR_Lock(mod_init.ml);
+	    once->initialized = 1;
+	    PR_NotifyAllCondVar(mod_init.cv);
+	    PR_Unlock(mod_init.ml);
+	} else {
+	    PR_Lock(mod_init.ml);
+	    while (!once->initialized) {
+		PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
+            }
+	    PR_Unlock(mod_init.ml);
+	}
+    } else {
+        if (PR_SUCCESS != once->status) {
+            PR_SetError(PR_CALL_ONCE_ERROR, 0);
+        }
+    }
+    return once->status;
+}
+
+PRBool _PR_Obsolete(const char *obsolete, const char *preferred)
+{
+#if defined(DEBUG)
+    PR_fprintf(
+        PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n",
+        obsolete, (NULL == preferred) ? "something else" : preferred);
+#endif
+    return PR_FALSE;
+}  /* _PR_Obsolete */
+
+/* prinit.c */
+
+
diff --git a/mozilla/nsprpub/pr/src/misc/prinrval.c b/mozilla/nsprpub/pr/src/misc/prinrval.c
new file mode 100644
index 0000000..17229e8
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prinrval.c
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * file:			prinrval.c
+ * description:		implementation for the kernel interval timing functions
+ */
+
+#include "primpl.h"
+
+/*
+ *-----------------------------------------------------------------------
+ *
+ * _PR_InitClock --
+ *
+ *
+ *-----------------------------------------------------------------------
+ */
+
+void _PR_InitClock(void)
+{
+    _PR_MD_INTERVAL_INIT();
+#ifdef DEBUG
+    {
+        PRIntervalTime ticksPerSec = PR_TicksPerSecond();
+
+        PR_ASSERT(ticksPerSec >= PR_INTERVAL_MIN);
+        PR_ASSERT(ticksPerSec <= PR_INTERVAL_MAX);
+    }
+#endif /* DEBUG */
+}
+
+/*
+ * This version of interval times is based on the time of day
+ * capability offered by system. This isn't valid for two reasons:
+ * 1) The time of day is neither linear nor montonically increasing
+ * 2) The units here are milliseconds. That's not appropriate for our use.
+ */
+
+PR_IMPLEMENT(PRIntervalTime) PR_IntervalNow(void)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    return _PR_MD_GET_INTERVAL();
+}  /* PR_IntervalNow */
+
+PR_EXTERN(PRUint32) PR_TicksPerSecond(void)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    return _PR_MD_INTERVAL_PER_SEC();
+}  /* PR_TicksPerSecond */
+
+PR_IMPLEMENT(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds)
+{
+    return seconds * PR_TicksPerSecond();
+}  /* PR_SecondsToInterval */
+
+PR_IMPLEMENT(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli)
+{
+    PRIntervalTime ticks;
+    PRUint64 tock, tps, msecPerSec, rounding;
+    LL_UI2L(tock, milli);
+    LL_I2L(msecPerSec, PR_MSEC_PER_SEC);
+    LL_I2L(rounding, (PR_MSEC_PER_SEC >> 1));
+    LL_I2L(tps, PR_TicksPerSecond());
+    LL_MUL(tock, tock, tps);
+    LL_ADD(tock, tock, rounding);
+    LL_DIV(tock, tock, msecPerSec);
+    LL_L2UI(ticks, tock);
+    return ticks;
+}  /* PR_MillisecondsToInterval */
+
+PR_IMPLEMENT(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro)
+{
+    PRIntervalTime ticks;
+    PRUint64 tock, tps, usecPerSec, rounding;
+    LL_UI2L(tock, micro);
+    LL_I2L(usecPerSec, PR_USEC_PER_SEC);
+    LL_I2L(rounding, (PR_USEC_PER_SEC >> 1));
+    LL_I2L(tps, PR_TicksPerSecond());
+    LL_MUL(tock, tock, tps);
+    LL_ADD(tock, tock, rounding);
+    LL_DIV(tock, tock, usecPerSec);
+    LL_L2UI(ticks, tock);
+    return ticks;
+}  /* PR_MicrosecondsToInterval */
+
+PR_IMPLEMENT(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks)
+{
+    return ticks / PR_TicksPerSecond();
+}  /* PR_IntervalToSeconds */
+
+PR_IMPLEMENT(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks)
+{
+    PRUint32 milli;
+    PRUint64 tock, tps, msecPerSec, rounding;
+    LL_UI2L(tock, ticks);
+    LL_I2L(msecPerSec, PR_MSEC_PER_SEC);
+    LL_I2L(tps, PR_TicksPerSecond());
+    LL_USHR(rounding, tps, 1);
+    LL_MUL(tock, tock, msecPerSec);
+    LL_ADD(tock, tock, rounding);
+    LL_DIV(tock, tock, tps);
+    LL_L2UI(milli, tock);
+    return milli;
+}  /* PR_IntervalToMilliseconds */
+
+PR_IMPLEMENT(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks)
+{
+    PRUint32 micro;
+    PRUint64 tock, tps, usecPerSec, rounding;
+    LL_UI2L(tock, ticks);
+    LL_I2L(usecPerSec, PR_USEC_PER_SEC);
+    LL_I2L(tps, PR_TicksPerSecond());
+    LL_USHR(rounding, tps, 1);
+    LL_MUL(tock, tock, usecPerSec);
+    LL_ADD(tock, tock, rounding);
+    LL_DIV(tock, tock, tps);
+    LL_L2UI(micro, tock);
+    return micro;
+}  /* PR_IntervalToMicroseconds */
+
+/* prinrval.c */
+
diff --git a/mozilla/nsprpub/pr/src/misc/pripc.c b/mozilla/nsprpub/pr/src/misc/pripc.c
new file mode 100644
index 0000000..cb16aad
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/pripc.c
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+/*
+ * File: pripc.c
+ *
+ * Description: functions for IPC support
+ */
+
+#include "primpl.h"
+
+#include <string.h>
+
+/*
+ * A POSIX IPC name must begin with a '/'.
+ * A POSIX IPC name on Solaris cannot contain any '/' except
+ * the required leading '/'.
+ * A POSIX IPC name on HP-UX and OSF1 must be a valid pathname
+ * in the file system.
+ *
+ * The ftok() function for System V IPC requires a valid pathname
+ * in the file system.
+ *
+ * A Win32 IPC name cannot contain '\'.
+ */
+
+static void _pr_ConvertSemName(char *result)
+{
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#if defined(SOLARIS)
+    char *p;
+
+    /* Convert '/' to '_' except for the leading '/' */
+    for (p = result+1; *p; p++) {
+        if (*p == '/') {
+            *p = '_';
+        }
+    }
+    return;
+#else
+    return;
+#endif
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+    return;
+#elif defined(WIN32)
+    return;
+#endif
+}
+
+static void _pr_ConvertShmName(char *result)
+{
+#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY)
+#if defined(SOLARIS)
+    char *p;
+
+    /* Convert '/' to '_' except for the leading '/' */
+    for (p = result+1; *p; p++) {
+        if (*p == '/') {
+            *p = '_';
+        }
+    }
+    return;
+#else
+    return;
+#endif
+#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY)
+    return;
+#elif defined(WIN32)
+    return;
+#else
+    return;
+#endif
+}
+
+PRStatus _PR_MakeNativeIPCName(
+    const char *name,
+    char *result,
+    PRIntn size,
+    _PRIPCType type)
+{
+    if (strlen(name) >= (PRSize)size) {
+        PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+        return PR_FAILURE;
+    }
+    strcpy(result, name);
+    switch (type) {
+        case _PRIPCSem:
+            _pr_ConvertSemName(result);
+            break;
+        case _PRIPCShm:
+            _pr_ConvertShmName(result);
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
diff --git a/mozilla/nsprpub/pr/src/misc/pripcsem.c b/mozilla/nsprpub/pr/src/misc/pripcsem.c
new file mode 100644
index 0000000..c6c59ec
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/pripcsem.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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 ***** */
+
+/*
+ * File: pripcsem.c
+ *
+ * Description: implements the named semaphores API in prsemipc.h
+ * for classic NSPR.  If _PR_HAVE_NAMED_SEMAPHORES is not defined,
+ * the named semaphore functions all fail with the error code
+ * PR_NOT_IMPLEMENTED_ERROR.
+ */
+
+#include "primpl.h"
+
+#ifdef _PR_PTHREADS
+
+#error "This file should not be compiled for the pthreads version"
+
+#else
+
+#ifndef _PR_HAVE_NAMED_SEMAPHORES
+
+PRSem * _PR_MD_OPEN_SEMAPHORE(
+    const char *osname, PRIntn flags, PRIntn mode, PRUintn value)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+
+PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+#endif /* !_PR_HAVE_NAMED_SEMAPHORES */
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+    const char *name, PRIntn flags, PRIntn mode, PRUintn value)
+{
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+            == PR_FAILURE) {
+        return NULL;
+    }
+    return _PR_MD_OPEN_SEMAPHORE(osname, flags, mode, value);
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+    return _PR_MD_WAIT_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+    return _PR_MD_POST_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+    return _PR_MD_CLOSE_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+            == PR_FAILURE) {
+        return PR_FAILURE;
+    }
+    return _PR_MD_DELETE_SEMAPHORE(osname);
+}
+
+#endif /* _PR_PTHREADS */
diff --git a/mozilla/nsprpub/pr/src/misc/prlog2.c b/mozilla/nsprpub/pr/src/misc/prlog2.c
new file mode 100644
index 0000000..d1a688a
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prlog2.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "prbit.h"
+
+/*
+** Compute the log of the least power of 2 greater than or equal to n
+*/
+PR_IMPLEMENT(PRIntn) PR_CeilingLog2(PRUint32 n)
+{
+    PRIntn log2 = 0;
+
+    if (n & (n-1))
+	log2++;
+    if (n >> 16)
+	log2 += 16, n >>= 16;
+    if (n >> 8)
+	log2 += 8, n >>= 8;
+    if (n >> 4)
+	log2 += 4, n >>= 4;
+    if (n >> 2)
+	log2 += 2, n >>= 2;
+    if (n >> 1)
+	log2++;
+    return log2;
+}
+
+/*
+** Compute the log of the greatest power of 2 less than or equal to n.
+** This really just finds the highest set bit in the word.
+*/
+PR_IMPLEMENT(PRIntn) PR_FloorLog2(PRUint32 n)
+{
+    PRIntn log2 = 0;
+
+    if (n >> 16)
+	log2 += 16, n >>= 16;
+    if (n >> 8)
+	log2 += 8, n >>= 8;
+    if (n >> 4)
+	log2 += 4, n >>= 4;
+    if (n >> 2)
+	log2 += 2, n >>= 2;
+    if (n >> 1)
+	log2++;
+    return log2;
+}
diff --git a/mozilla/nsprpub/pr/src/misc/prlong.c b/mozilla/nsprpub/pr/src/misc/prlong.c
new file mode 100644
index 0000000..650d4bc
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prlong.c
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+static PRInt64 ll_zero = LL_INIT( 0x00000000,0x00000000 );
+static PRInt64 ll_maxint = LL_INIT( 0x7fffffff, 0xffffffff );
+static PRInt64 ll_minint = LL_INIT( 0x80000000, 0x00000000 );
+static PRUint64 ll_maxuint = LL_INIT( 0xffffffff, 0xffffffff );
+
+PR_IMPLEMENT(PRInt64) LL_Zero(void) { return ll_zero; }
+PR_IMPLEMENT(PRInt64) LL_MaxInt(void) { return ll_maxint; }
+PR_IMPLEMENT(PRInt64) LL_MinInt(void) { return ll_minint; }
+PR_IMPLEMENT(PRUint64) LL_MaxUint(void) { return ll_maxuint; }
+
+#ifndef HAVE_LONG_LONG
+/*
+** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1.
+*/
+static void norm_udivmod32(PRUint32 *qp, PRUint32 *rp, PRUint64 a, PRUint32 b)
+{
+    PRUint32 d1, d0, q1, q0;
+    PRUint32 r1, r0, m;
+
+    d1 = _hi16(b);
+    d0 = _lo16(b);
+    r1 = a.hi % d1;
+    q1 = a.hi / d1;
+    m = q1 * d0;
+    r1 = (r1 << 16) | _hi16(a.lo);
+    if (r1 < m) {
+        q1--, r1 += b;
+        if (r1 >= b	/* i.e., we didn't get a carry when adding to r1 */
+	    && r1 < m) {
+	    q1--, r1 += b;
+	}
+    }
+    r1 -= m;
+    r0 = r1 % d1;
+    q0 = r1 / d1;
+    m = q0 * d0;
+    r0 = (r0 << 16) | _lo16(a.lo);
+    if (r0 < m) {
+        q0--, r0 += b;
+        if (r0 >= b
+	    && r0 < m) {
+	    q0--, r0 += b;
+	}
+    }
+    *qp = (q1 << 16) | q0;
+    *rp = r0 - m;
+}
+
+static PRUint32 CountLeadingZeros(PRUint32 a)
+{
+    PRUint32 t;
+    PRUint32 r = 32;
+
+    if ((t = a >> 16) != 0)
+	r -= 16, a = t;
+    if ((t = a >> 8) != 0)
+	r -= 8, a = t;
+    if ((t = a >> 4) != 0)
+	r -= 4, a = t;
+    if ((t = a >> 2) != 0)
+	r -= 2, a = t;
+    if ((t = a >> 1) != 0)
+	r -= 1, a = t;
+    if (a & 1)
+	r--;
+    return r;
+}
+
+PR_IMPLEMENT(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b)
+{
+    PRUint32 n0, n1, n2;
+    PRUint32 q0, q1;
+    PRUint32 rsh, lsh;
+
+    n0 = a.lo;
+    n1 = a.hi;
+
+    if (b.hi == 0) {
+	if (b.lo > n1) {
+	    /* (0 q0) = (n1 n0) / (0 D0) */
+
+	    lsh = CountLeadingZeros(b.lo);
+
+	    if (lsh) {
+		/*
+		 * Normalize, i.e. make the most significant bit of the
+		 * denominator be set.
+		 */
+		b.lo = b.lo << lsh;
+		n1 = (n1 << lsh) | (n0 >> (32 - lsh));
+		n0 = n0 << lsh;
+	    }
+
+	    a.lo = n0, a.hi = n1;
+	    norm_udivmod32(&q0, &n0, a, b.lo);
+	    q1 = 0;
+
+	    /* remainder is in n0 >> lsh */
+	} else {
+	    /* (q1 q0) = (n1 n0) / (0 d0) */
+
+	    if (b.lo == 0)		/* user wants to divide by zero! */
+		b.lo = 1 / b.lo;	/* so go ahead and crash */
+
+	    lsh = CountLeadingZeros(b.lo);
+
+	    if (lsh == 0) {
+		/*
+		 * From (n1 >= b.lo)
+		 *   && (the most significant bit of b.lo is set),
+		 * conclude that
+		 *	(the most significant bit of n1 is set)
+		 *   && (the leading quotient digit q1 = 1).
+		 *
+		 * This special case is necessary, not an optimization
+		 * (Shifts counts of 32 are undefined).
+		 */
+		n1 -= b.lo;
+		q1 = 1;
+	    } else {
+		/*
+		 * Normalize.
+		 */
+		rsh = 32 - lsh;
+
+		b.lo = b.lo << lsh;
+		n2 = n1 >> rsh;
+		n1 = (n1 << lsh) | (n0 >> rsh);
+		n0 = n0 << lsh;
+
+		a.lo = n1, a.hi = n2;
+		norm_udivmod32(&q1, &n1, a, b.lo);
+	    }
+
+	    /* n1 != b.lo... */
+
+	    a.lo = n0, a.hi = n1;
+	    norm_udivmod32(&q0, &n0, a, b.lo);
+
+	    /* remainder in n0 >> lsh */
+	}
+
+	if (rp) {
+	    rp->lo = n0 >> lsh;
+	    rp->hi = 0;
+	}
+    } else {
+	if (b.hi > n1) {
+	    /* (0 0) = (n1 n0) / (D1 d0) */
+
+	    q0 = 0;
+	    q1 = 0;
+
+	    /* remainder in (n1 n0) */
+	    if (rp) {
+		rp->lo = n0;
+		rp->hi = n1;
+	    }
+	} else {
+	    /* (0 q0) = (n1 n0) / (d1 d0) */
+
+	    lsh = CountLeadingZeros(b.hi);
+	    if (lsh == 0) {
+		/*
+		 * From (n1 >= b.hi)
+		 *   && (the most significant bit of b.hi is set),
+		 * conclude that
+		 *      (the most significant bit of n1 is set)
+		 *   && (the quotient digit q0 = 0 or 1).
+		 *
+		 * This special case is necessary, not an optimization.
+		 */
+
+		/*
+		 * The condition on the next line takes advantage of that
+		 * n1 >= b.hi (true due to control flow).
+		 */
+		if (n1 > b.hi || n0 >= b.lo) {
+		    q0 = 1;
+		    a.lo = n0, a.hi = n1;
+		    LL_SUB(a, a, b);
+		} else {
+		    q0 = 0;
+		}
+		q1 = 0;
+
+		if (rp) {
+		    rp->lo = n0;
+		    rp->hi = n1;
+		}
+	    } else {
+		PRInt64 m;
+
+		/*
+		 * Normalize.
+		 */
+		rsh = 32 - lsh;
+
+		b.hi = (b.hi << lsh) | (b.lo >> rsh);
+		b.lo = b.lo << lsh;
+		n2 = n1 >> rsh;
+		n1 = (n1 << lsh) | (n0 >> rsh);
+		n0 = n0 << lsh;
+
+		a.lo = n1, a.hi = n2;
+		norm_udivmod32(&q0, &n1, a, b.hi);
+		LL_MUL32(m, q0, b.lo);
+
+		if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) {
+		    q0--;
+		    LL_SUB(m, m, b);
+		}
+
+		q1 = 0;
+
+		/* Remainder is ((n1 n0) - (m1 m0)) >> lsh */
+		if (rp) {
+		    a.lo = n0, a.hi = n1;
+		    LL_SUB(a, a, m);
+		    rp->lo = (a.hi << rsh) | (a.lo >> lsh);
+		    rp->hi = a.hi >> lsh;
+		}
+	    }
+	}
+    }
+
+    if (qp) {
+	qp->lo = q0;
+	qp->hi = q1;
+    }
+}
+#endif /* !HAVE_LONG_LONG */
diff --git a/mozilla/nsprpub/pr/src/misc/prnetdb.c b/mozilla/nsprpub/pr/src/misc/prnetdb.c
new file mode 100644
index 0000000..8a2a00c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prnetdb.c
@@ -0,0 +1,2332 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+
+/*
+ * On Unix, the error code for gethostbyname() and gethostbyaddr()
+ * is returned in the global variable h_errno, instead of the usual
+ * errno.
+ */
+#if defined(XP_UNIX)
+#if defined(_PR_NEED_H_ERRNO)
+extern int h_errno;
+#endif
+#define _MD_GETHOST_ERRNO() h_errno
+#else
+#define _MD_GETHOST_ERRNO() _MD_ERRNO()
+#endif
+
+/*
+ * The meaning of the macros related to gethostbyname, gethostbyaddr,
+ * and gethostbyname2 is defined below.
+ * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return
+ *   the result in thread specific storage.  For example, AIX, HP-UX,
+ *   and OSF1.
+ * -  _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next
+ *   two macros.
+ * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an
+ *   int.  For example, Linux glibc.
+ * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return
+ *   a struct hostent* pointer.  For example, Solaris and IRIX.
+ */
+#if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \
+    || defined(_PR_HAVE_THREADSAFE_GETHOST)
+#define _PR_NO_DNS_LOCK
+#endif
+
+#if defined(_PR_NO_DNS_LOCK)
+#define LOCK_DNS()
+#define UNLOCK_DNS()
+#else
+PRLock *_pr_dnsLock = NULL;
+#define LOCK_DNS() PR_Lock(_pr_dnsLock)
+#define UNLOCK_DNS() PR_Unlock(_pr_dnsLock)
+#endif  /* defined(_PR_NO_DNS_LOCK) */
+
+/*
+ * Some platforms have the reentrant getprotobyname_r() and
+ * getprotobynumber_r().  However, they come in three flavors.
+ * Some return a pointer to struct protoent, others return
+ * an int, and glibc's flavor takes five arguments.
+ */
+#if defined(XP_BEOS) && defined(BONE_VERSION)
+#include <arpa/inet.h>  /* pick up define for inet_addr */
+#include <sys/socket.h>
+#define _PR_HAVE_GETPROTO_R
+#define _PR_HAVE_GETPROTO_R_POINTER
+#endif
+
+#if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \
+	|| (defined(LINUX) && defined(_REENTRANT) \
+        && !(defined(__GLIBC__) && __GLIBC__ >= 2))
+#define _PR_HAVE_GETPROTO_R
+#define _PR_HAVE_GETPROTO_R_POINTER
+#endif
+
+#if defined(OSF1) \
+        || defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \
+	|| (defined(HPUX10_10) && defined(_REENTRANT)) \
+        || (defined(HPUX10_20) && defined(_REENTRANT)) \
+        || defined(OPENBSD)
+#define _PR_HAVE_GETPROTO_R
+#define _PR_HAVE_GETPROTO_R_INT
+#endif
+
+#if __FreeBSD_version >= 602000
+#define _PR_HAVE_GETPROTO_R
+#define _PR_HAVE_5_ARG_GETPROTO_R
+#endif
+
+/* BeOS has glibc but not the glibc-style getprotobyxxx_r functions. */
+#if (defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(XP_BEOS))
+#define _PR_HAVE_GETPROTO_R
+#define _PR_HAVE_5_ARG_GETPROTO_R
+#endif
+
+#if !defined(_PR_HAVE_GETPROTO_R)
+PRLock* _getproto_lock = NULL;
+#endif
+
+#if defined(_PR_INET6_PROBE)
+extern PRBool _pr_ipv6_is_present(void);
+#endif
+
+#define _PR_IN6_IS_ADDR_UNSPECIFIED(a)				\
+				(((a)->pr_s6_addr32[0] == 0) &&	\
+				((a)->pr_s6_addr32[1] == 0) &&		\
+				((a)->pr_s6_addr32[2] == 0) &&		\
+				((a)->pr_s6_addr32[3] == 0))
+ 
+#define _PR_IN6_IS_ADDR_LOOPBACK(a)					\
+               (((a)->pr_s6_addr32[0] == 0)	&&	\
+               ((a)->pr_s6_addr32[1] == 0)		&&	\
+               ((a)->pr_s6_addr32[2] == 0)		&&	\
+               ((a)->pr_s6_addr[12] == 0)		&&	\
+               ((a)->pr_s6_addr[13] == 0)		&&	\
+               ((a)->pr_s6_addr[14] == 0)		&&	\
+               ((a)->pr_s6_addr[15] == 0x1U))
+ 
+const PRIPv6Addr _pr_in6addr_any =	{{{ 0, 0, 0, 0,
+										0, 0, 0, 0,
+										0, 0, 0, 0,
+										0, 0, 0, 0 }}};
+
+const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0,
+											0, 0, 0, 0,
+											0, 0, 0, 0,
+											0, 0, 0, 0x1U }}};
+/*
+ * The values at bytes 10 and 11 are compared using pointers to
+ * 8-bit fields, and not 32-bit fields, to make the comparison work on
+ * both big-endian and little-endian systems
+ */
+
+#define _PR_IN6_IS_ADDR_V4MAPPED(a)			\
+		(((a)->pr_s6_addr32[0] == 0) 	&&	\
+		((a)->pr_s6_addr32[1] == 0)	&&	\
+		((a)->pr_s6_addr[8] == 0)		&&	\
+		((a)->pr_s6_addr[9] == 0)		&&	\
+		((a)->pr_s6_addr[10] == 0xff)	&&	\
+		((a)->pr_s6_addr[11] == 0xff))
+
+#define _PR_IN6_IS_ADDR_V4COMPAT(a)			\
+		(((a)->pr_s6_addr32[0] == 0) &&	\
+		((a)->pr_s6_addr32[1] == 0) &&		\
+		((a)->pr_s6_addr32[2] == 0))
+
+#define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3])
+
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
+
+/*
+ * The _pr_QueryNetIfs() function finds out if the system has
+ * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if
+ * and _pr_have_inet6_if accordingly.
+ *
+ * We have an implementation using SIOCGIFCONF ioctl and a
+ * default implementation that simply sets _pr_have_inet_if
+ * and _pr_have_inet6_if to true.  A better implementation
+ * would be to use the routing sockets (see Chapter 17 of
+ * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.)
+ */
+
+static PRLock *_pr_query_ifs_lock = NULL;
+static PRBool _pr_have_inet_if = PR_FALSE;
+static PRBool _pr_have_inet6_if = PR_FALSE;
+
+#undef DEBUG_QUERY_IFS
+
+#if defined(AIX) \
+    || (defined(DARWIN) && (!defined(HAVE_GETIFADDRS) \
+        || (defined(XP_MACOSX) && (!defined(MAC_OS_X_VERSION_10_2) || \
+        MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2))))
+
+/*
+ * Use SIOCGIFCONF ioctl on platforms that don't have routing
+ * sockets.  Warning: whether SIOCGIFCONF ioctl returns AF_INET6
+ * network interfaces is not portable.
+ *
+ * The _pr_QueryNetIfs() function is derived from the code in
+ * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in
+ * Section 16.6 of W. Richard Stevens' Unix Network Programming,
+ * Vol. 1, 2nd. Ed.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#ifdef DEBUG_QUERY_IFS
+static void
+_pr_PrintIfreq(struct ifreq *ifr)
+{
+    PRNetAddr addr;
+    struct sockaddr *sa;
+    const char* family;
+    char addrstr[64];
+
+    sa = &ifr->ifr_addr;
+    if (sa->sa_family == AF_INET) {
+        struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+        family = "inet";
+        memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr));
+    } else if (sa->sa_family == AF_INET6) {
+        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+        family = "inet6";
+        memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
+    } else {
+        return;  /* skip if not AF_INET or AF_INET6 */
+    }
+    addr.raw.family = sa->sa_family;
+    PR_NetAddrToString(&addr, addrstr, sizeof(addrstr));
+    printf("%s: %s %s\n", ifr->ifr_name, family, addrstr);
+}
+#endif
+
+static void
+_pr_QueryNetIfs(void)
+{
+    int sock;
+    int rv;
+    struct ifconf ifc;
+    struct ifreq *ifr;
+    struct ifreq *lifr;
+    PRUint32 len, lastlen;
+    char *buf;
+
+    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+        return;
+    }
+
+    /* Issue SIOCGIFCONF request in a loop. */
+    lastlen = 0;
+    len = 100 * sizeof(struct ifreq);  /* initial buffer size guess */
+    for (;;) {
+        buf = (char *)PR_Malloc(len);
+        if (NULL == buf) {
+            close(sock);
+            return;
+        }
+        ifc.ifc_buf = buf;
+        ifc.ifc_len = len;
+        rv = ioctl(sock, SIOCGIFCONF, &ifc);
+        if (rv < 0) {
+            if (errno != EINVAL || lastlen != 0) {
+                close(sock);
+                PR_Free(buf);
+                return;
+            }
+        } else {
+            if (ifc.ifc_len == lastlen)
+                break;  /* success, len has not changed */
+            lastlen = ifc.ifc_len;
+        }
+        len += 10 * sizeof(struct ifreq);  /* increment */
+        PR_Free(buf);
+    }
+    close(sock);
+
+    ifr = ifc.ifc_req;
+    lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
+
+    while (ifr < lifr) {
+        struct sockaddr *sa;
+        int sa_len;
+
+#ifdef DEBUG_QUERY_IFS
+        _pr_PrintIfreq(ifr);
+#endif
+        sa = &ifr->ifr_addr;
+        if (sa->sa_family == AF_INET) {
+            struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+            if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
+                _pr_have_inet_if = PR_TRUE;
+            } 
+        } else if (sa->sa_family == AF_INET6) {
+            struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+            if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)
+                    && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+                _pr_have_inet6_if = PR_TRUE;
+            } 
+        }
+
+#ifdef _PR_HAVE_SOCKADDR_LEN
+        sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr));
+#else
+        switch (sa->sa_family) {
+#ifdef AF_LINK
+        case AF_LINK:
+            sa_len = sizeof(struct sockaddr_dl);
+            break;
+#endif
+        case AF_INET6:
+            sa_len = sizeof(struct sockaddr_in6);
+            break;
+        default:
+            sa_len = sizeof(struct sockaddr);
+            break;
+        }
+#endif
+        ifr = (struct ifreq *)(((char *)sa) + sa_len);
+    }
+    PR_Free(buf);
+}
+
+#elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) || defined(FREEBSD) \
+    || defined(NETBSD) || defined(OPENBSD)
+
+/*
+ * Use the BSD getifaddrs function.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+#include <netinet/in.h>
+
+#ifdef DEBUG_QUERY_IFS
+static void
+_pr_PrintIfaddrs(struct ifaddrs *ifa)
+{
+    struct sockaddr *sa;
+    const char* family;
+    void *addrp;
+    char addrstr[64];
+
+    sa = ifa->ifa_addr;
+    if (sa->sa_family == AF_INET) {
+        struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+        family = "inet";
+        addrp = &sin->sin_addr;
+    } else if (sa->sa_family == AF_INET6) {
+        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+        family = "inet6";
+        addrp = &sin6->sin6_addr;
+    } else {
+        return;  /* skip if not AF_INET or AF_INET6 */
+    }
+    inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr));
+    printf("%s: %s %s\n", ifa->ifa_name, family, addrstr);
+}
+#endif
+
+static void
+_pr_QueryNetIfs(void)
+{
+    struct ifaddrs *ifp;
+    struct ifaddrs *ifa;
+
+    if (getifaddrs(&ifp) == -1) {
+        return;
+    }
+    for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
+        struct sockaddr *sa;
+
+#ifdef DEBUG_QUERY_IFS
+        _pr_PrintIfaddrs(ifa);
+#endif
+        sa = ifa->ifa_addr;
+        if (sa->sa_family == AF_INET) {
+            struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+            if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
+                _pr_have_inet_if = 1;
+            } 
+        } else if (sa->sa_family == AF_INET6) {
+            struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+            if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)
+                    && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+                _pr_have_inet6_if = 1;
+            } 
+        }
+    } 
+    freeifaddrs(ifp);
+}
+
+#else  /* default */
+
+/*
+ * Emulate the code in NSPR 4.2 or older.  PR_GetIPNodeByName behaves
+ * as if the system had both IPv4 and IPv6 source addresses configured.
+ */
+static void
+_pr_QueryNetIfs(void)
+{
+    _pr_have_inet_if = PR_TRUE;
+    _pr_have_inet6_if = PR_TRUE;
+}
+
+#endif
+
+#endif  /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */
+
+void _PR_InitNet(void)
+{
+#if defined(XP_UNIX)
+#ifdef HAVE_NETCONFIG
+	/*
+	 * This one-liner prevents the endless re-open's and re-read's of
+	 * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc.
+	 */
+	 (void)setnetconfig();
+#endif
+#endif
+#if !defined(_PR_NO_DNS_LOCK)
+	_pr_dnsLock = PR_NewLock();
+#endif
+#if !defined(_PR_HAVE_GETPROTO_R)
+	_getproto_lock = PR_NewLock();
+#endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
+	_pr_query_ifs_lock = PR_NewLock();
+#endif
+}
+
+void _PR_CleanupNet(void)
+{
+#if !defined(_PR_NO_DNS_LOCK)
+    if (_pr_dnsLock) {
+        PR_DestroyLock(_pr_dnsLock);
+        _pr_dnsLock = NULL;
+    }
+#endif
+#if !defined(_PR_HAVE_GETPROTO_R)
+    if (_getproto_lock) {
+        PR_DestroyLock(_getproto_lock);
+        _getproto_lock = NULL;
+    }
+#endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
+    if (_pr_query_ifs_lock) {
+        PR_DestroyLock(_pr_query_ifs_lock);
+        _pr_query_ifs_lock = NULL;
+    }
+#endif
+}
+
+/*
+** Allocate space from the buffer, aligning it to "align" before doing
+** the allocation. "align" must be a power of 2.
+*/
+static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align)
+{
+	char *buf = *bufp;
+	PRIntn buflen = *buflenp;
+
+	if (align && ((long)buf & (align - 1))) {
+		PRIntn skip = align - ((ptrdiff_t)buf & (align - 1));
+		if (buflen < skip) {
+			return 0;
+		}
+		buf += skip;
+		buflen -= skip;
+	}
+	if (buflen < amount) {
+		return 0;
+	}
+	*bufp = buf + amount;
+	*buflenp = buflen - amount;
+	return buf;
+}
+
+typedef enum _PRIPAddrConversion {
+    _PRIPAddrNoConversion,
+    _PRIPAddrIPv4Mapped,
+    _PRIPAddrIPv4Compat
+} _PRIPAddrConversion;
+
+/*
+** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6).
+*/
+static void MakeIPv4MappedAddr(const char *v4, char *v6)
+{
+    memset(v6, 0, 10);
+    memset(v6 + 10, 0xff, 2);
+    memcpy(v6 + 12, v4, 4);
+}
+
+/*
+** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6).
+*/
+static void MakeIPv4CompatAddr(const char *v4, char *v6)
+{
+    memset(v6, 0, 12);
+    memcpy(v6 + 12, v4, 4);
+}
+
+/*
+** Copy a hostent, and all of the memory that it refers to into
+** (hopefully) stacked buffers.
+*/
+static PRStatus CopyHostent(
+    struct hostent *from,
+    char **buf,
+    PRIntn *bufsize,
+    _PRIPAddrConversion conversion,
+    PRHostEnt *to)
+{
+	PRIntn len, na;
+	char **ap;
+
+	if (conversion != _PRIPAddrNoConversion
+			&& from->h_addrtype == AF_INET) {
+		PR_ASSERT(from->h_length == 4);
+		to->h_addrtype = PR_AF_INET6;
+		to->h_length = 16;
+	} else {
+#if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
+		if (AF_INET6 == from->h_addrtype)
+			to->h_addrtype = PR_AF_INET6;
+		else
+#endif
+			to->h_addrtype = from->h_addrtype;
+		to->h_length = from->h_length;
+	}
+
+	/* Copy the official name */
+	if (!from->h_name) return PR_FAILURE;
+	len = strlen(from->h_name) + 1;
+	to->h_name = Alloc(len, buf, bufsize, 0);
+	if (!to->h_name) return PR_FAILURE;
+	memcpy(to->h_name, from->h_name, len);
+
+	/* Count the aliases, then allocate storage for the pointers */
+	if (!from->h_aliases) {
+		na = 1;
+	} else {
+		for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
+	}
+	to->h_aliases = (char**)Alloc(
+	    na * sizeof(char*), buf, bufsize, sizeof(char**));
+	if (!to->h_aliases) return PR_FAILURE;
+
+	/* Copy the aliases, one at a time */
+	if (!from->h_aliases) {
+		to->h_aliases[0] = 0;
+	} else {
+		for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) {
+			len = strlen(*ap) + 1;
+			to->h_aliases[na] = Alloc(len, buf, bufsize, 0);
+			if (!to->h_aliases[na]) return PR_FAILURE;
+			memcpy(to->h_aliases[na], *ap, len);
+		}
+		to->h_aliases[na] = 0;
+	}
+
+	/* Count the addresses, then allocate storage for the pointers */
+	for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++){;} /* nothing to execute */
+	to->h_addr_list = (char**)Alloc(
+	    na * sizeof(char*), buf, bufsize, sizeof(char**));
+	if (!to->h_addr_list) return PR_FAILURE;
+
+	/* Copy the addresses, one at a time */
+	for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) {
+		to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
+		if (!to->h_addr_list[na]) return PR_FAILURE;
+		if (conversion != _PRIPAddrNoConversion
+				&& from->h_addrtype == AF_INET) {
+			if (conversion == _PRIPAddrIPv4Mapped) {
+				MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
+			} else {
+				PR_ASSERT(conversion == _PRIPAddrIPv4Compat);
+				MakeIPv4CompatAddr(*ap, to->h_addr_list[na]);
+			}
+		} else {
+			memcpy(to->h_addr_list[na], *ap, to->h_length);
+		}
+	}
+	to->h_addr_list[na] = 0;
+	return PR_SUCCESS;
+}
+
+#ifdef SYMBIAN
+/* Set p_aliases by hand because Symbian's getprotobyname() returns NULL. */
+static void AssignAliases(struct protoent *Protoent, char** aliases)
+{
+    if (NULL == Protoent->p_aliases) {
+        if (0 == strcmp(Protoent->p_name, "ip"))
+            aliases[0] = "IP";
+        else if (0 == strcmp(Protoent->p_name, "tcp"))
+            aliases[0] = "TCP";
+        else if (0 == strcmp(Protoent->p_name, "udp"))
+            aliases[0] = "UDP";
+        else
+            aliases[0] = "UNKNOWN";
+        aliases[1] = NULL;
+        Protoent->p_aliases = aliases;
+    }
+}
+#endif
+
+#if !defined(_PR_HAVE_GETPROTO_R)
+/*
+** Copy a protoent, and all of the memory that it refers to into
+** (hopefully) stacked buffers.
+*/
+static PRStatus CopyProtoent(
+    struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to)
+{
+	PRIntn len, na;
+	char **ap;
+
+	/* Do the easy stuff */
+	to->p_num = from->p_proto;
+
+	/* Copy the official name */
+	if (!from->p_name) return PR_FAILURE;
+	len = strlen(from->p_name) + 1;
+	to->p_name = Alloc(len, &buf, &bufsize, 0);
+	if (!to->p_name) return PR_FAILURE;
+	memcpy(to->p_name, from->p_name, len);
+
+	/* Count the aliases, then allocate storage for the pointers */
+	for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
+	to->p_aliases = (char**)Alloc(
+	    na * sizeof(char*), &buf, &bufsize, sizeof(char**));
+	if (!to->p_aliases) return PR_FAILURE;
+
+	/* Copy the aliases, one at a time */
+	for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) {
+		len = strlen(*ap) + 1;
+		to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0);
+		if (!to->p_aliases[na]) return PR_FAILURE;
+		memcpy(to->p_aliases[na], *ap, len);
+	}
+	to->p_aliases[na] = 0;
+
+	return PR_SUCCESS;
+}
+#endif /* !defined(_PR_HAVE_GETPROTO_R) */
+
+/*
+ * #################################################################
+ * NOTE: tmphe, tmpbuf, bufsize, h, and h_err are local variables
+ * or arguments of PR_GetHostByName, PR_GetIPNodeByName, and
+ * PR_GetHostByAddr.  DO NOT CHANGE THE NAMES OF THESE LOCAL 
+ * VARIABLES OR ARGUMENTS.
+ * #################################################################
+ */
+#if defined(_PR_HAVE_GETHOST_R_INT)
+
+#define GETHOSTBYNAME(name) \
+    (gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
+#define GETHOSTBYNAME2(name, af) \
+    (gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
+#define GETHOSTBYADDR(addr, addrlen, af) \
+    (gethostbyaddr_r(addr, addrlen, af, \
+    &tmphe, tmpbuf, bufsize, &h, &h_err), h)
+
+#elif defined(_PR_HAVE_GETHOST_R_POINTER)
+
+#define GETHOSTBYNAME(name) \
+    gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h_err)
+#define GETHOSTBYNAME2(name, af) \
+    gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h_err)
+#define GETHOSTBYADDR(addr, addrlen, af) \
+    gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize, &h_err)
+
+#else
+
+#define GETHOSTBYNAME(name) gethostbyname(name)
+#define GETHOSTBYNAME2(name, af) gethostbyname2(name, af)
+#define GETHOSTBYADDR(addr, addrlen, af) gethostbyaddr(addr, addrlen, af)
+
+#endif  /* definition of GETHOSTBYXXX */
+
+PR_IMPLEMENT(PRStatus) PR_GetHostByName(
+    const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp)
+{
+	struct hostent *h;
+	PRStatus rv = PR_FAILURE;
+#if defined(_PR_HAVE_GETHOST_R)
+    char localbuf[PR_NETDB_BUF_SIZE];
+    char *tmpbuf;
+    struct hostent tmphe;
+    int h_err;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#if defined(_PR_HAVE_GETHOST_R)
+    tmpbuf = localbuf;
+    if (bufsize > sizeof(localbuf))
+    {
+        tmpbuf = (char *)PR_Malloc(bufsize);
+        if (NULL == tmpbuf)
+        {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return rv;
+        }
+    }
+#endif
+
+	LOCK_DNS();
+
+	h = GETHOSTBYNAME(name);
+    
+	if (NULL == h)
+	{
+	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+	}
+	else
+	{
+		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+		rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
+		if (PR_SUCCESS != rv)
+		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+	}
+	UNLOCK_DNS();
+#if defined(_PR_HAVE_GETHOST_R)
+    if (tmpbuf != localbuf)
+        PR_Free(tmpbuf);
+#endif
+	return rv;
+}
+
+#if !defined(_PR_INET6) && \
+        defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
+typedef struct hostent  * (*_pr_getipnodebyname_t)(const char *, int,
+										int, int *);
+typedef struct hostent  * (*_pr_getipnodebyaddr_t)(const void *, size_t,
+													int, int *);
+typedef void (*_pr_freehostent_t)(struct hostent *);
+static void * _pr_getipnodebyname_fp;
+static void * _pr_getipnodebyaddr_fp;
+static void * _pr_freehostent_fp;
+
+/*
+ * Look up the addresses of getipnodebyname, getipnodebyaddr,
+ * and freehostent.
+ */
+PRStatus
+_pr_find_getipnodebyname(void)
+{
+    PRLibrary *lib;	
+    PRStatus rv;
+#define GETIPNODEBYNAME "getipnodebyname"
+#define GETIPNODEBYADDR "getipnodebyaddr"
+#define FREEHOSTENT     "freehostent"
+
+    _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib);
+    if (NULL != _pr_getipnodebyname_fp) {
+        _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT);
+        if (NULL != _pr_freehostent_fp) {
+            _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR);
+            if (NULL != _pr_getipnodebyaddr_fp)
+                rv = PR_SUCCESS;
+            else
+                rv = PR_FAILURE;
+        } else
+            rv = PR_FAILURE;
+        (void)PR_UnloadLibrary(lib);
+    } else
+        rv = PR_FAILURE;
+    return rv;
+}
+#endif
+
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
+/*
+** Append the V4 addresses to the end of the list
+*/
+static PRStatus AppendV4AddrsToHostent(
+    struct hostent *from,
+    char **buf,
+    PRIntn *bufsize,
+    PRHostEnt *to)
+{
+    PRIntn na, na_old;
+    char **ap;
+    char **new_addr_list;
+			
+    /* Count the addresses, then grow storage for the pointers */
+    for (na_old = 0, ap = to->h_addr_list; *ap != 0; na_old++, ap++)
+        {;} /* nothing to execute */
+    for (na = na_old + 1, ap = from->h_addr_list; *ap != 0; na++, ap++)
+        {;} /* nothing to execute */
+    new_addr_list = (char**)Alloc(
+        na * sizeof(char*), buf, bufsize, sizeof(char**));
+    if (!new_addr_list) return PR_FAILURE;
+
+    /* Copy the V6 addresses, one at a time */
+    for (na = 0, ap = to->h_addr_list; *ap != 0; na++, ap++) {
+        new_addr_list[na] = to->h_addr_list[na];
+    }
+    to->h_addr_list = new_addr_list;
+
+    /* Copy the V4 addresses, one at a time */
+    for (ap = from->h_addr_list; *ap != 0; na++, ap++) {
+        to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
+        if (!to->h_addr_list[na]) return PR_FAILURE;
+        MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
+    }
+    to->h_addr_list[na] = 0;
+    return PR_SUCCESS;
+}
+#endif
+
+PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName(
+    const char *name, PRUint16 af, PRIntn flags,
+    char *buf, PRIntn bufsize, PRHostEnt *hp)
+{
+	struct hostent *h = 0;
+	PRStatus rv = PR_FAILURE;
+#if defined(_PR_HAVE_GETHOST_R)
+    char localbuf[PR_NETDB_BUF_SIZE];
+    char *tmpbuf;
+    struct hostent tmphe;
+    int h_err;
+#endif
+#if defined(_PR_HAVE_GETIPNODEBYNAME)
+	PRUint16 md_af = af;
+	int error_num;
+	int tmp_flags = 0;
+#endif
+#if defined(_PR_HAVE_GETHOSTBYNAME2)
+    PRBool did_af_inet = PR_FALSE;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (af != PR_AF_INET && af != PR_AF_INET6) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
+    PR_Lock(_pr_query_ifs_lock);
+    /*
+     * Keep querying the presence of IPv4 and IPv6 interfaces until
+     * at least one is up.  This allows us to detect the local
+     * machine going from offline to online.
+     */
+    if (!_pr_have_inet_if && !_pr_have_inet6_if) {
+	_pr_QueryNetIfs();
+#ifdef DEBUG_QUERY_IFS
+	if (_pr_have_inet_if)
+		printf("Have IPv4 source address\n");
+	if (_pr_have_inet6_if)
+		printf("Have IPv6 source address\n");
+#endif
+    }
+    PR_Unlock(_pr_query_ifs_lock);
+#endif
+
+#if defined(_PR_HAVE_GETIPNODEBYNAME)
+	if (flags & PR_AI_V4MAPPED)
+		tmp_flags |= AI_V4MAPPED;
+	if (flags & PR_AI_ADDRCONFIG)
+		tmp_flags |= AI_ADDRCONFIG;
+	if (flags & PR_AI_ALL)
+		tmp_flags |= AI_ALL;
+    if (af == PR_AF_INET6)
+    	md_af = AF_INET6;
+	else
+    	md_af = af;
+#endif
+
+#if defined(_PR_HAVE_GETHOST_R)
+    tmpbuf = localbuf;
+    if (bufsize > sizeof(localbuf))
+    {
+        tmpbuf = (char *)PR_Malloc(bufsize);
+        if (NULL == tmpbuf)
+        {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return rv;
+        }
+    }
+#endif
+
+    /* Do not need to lock the DNS lock if getipnodebyname() is called */
+#ifdef _PR_INET6
+#ifdef _PR_HAVE_GETHOSTBYNAME2
+    LOCK_DNS();
+    if (af == PR_AF_INET6)
+    {
+        if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet6_if)
+        {
+#ifdef _PR_INET6_PROBE
+          if (_pr_ipv6_is_present())
+#endif
+            h = GETHOSTBYNAME2(name, AF_INET6); 
+        }
+        if ((NULL == h) && (flags & PR_AI_V4MAPPED)
+        && ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if))
+        {
+            did_af_inet = PR_TRUE;
+            h = GETHOSTBYNAME2(name, AF_INET);
+        }
+    }
+    else
+    {
+        if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if)
+        {
+            did_af_inet = PR_TRUE;
+            h = GETHOSTBYNAME2(name, af);
+        }
+    }
+#elif defined(_PR_HAVE_GETIPNODEBYNAME)
+    h = getipnodebyname(name, md_af, tmp_flags, &error_num);
+#else
+#error "Unknown name-to-address translation function"
+#endif	/* _PR_HAVE_GETHOSTBYNAME2 */
+#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
+    if (_pr_ipv6_is_present())
+    {
+#ifdef PR_GETIPNODE_NOT_THREADSAFE
+        LOCK_DNS();
+#endif
+    	h = (*((_pr_getipnodebyname_t)_pr_getipnodebyname_fp))(name, md_af, tmp_flags, &error_num);
+    }
+    else
+    {
+        LOCK_DNS();
+    	h = GETHOSTBYNAME(name);
+    }
+#else /* _PR_INET6 */
+    LOCK_DNS();
+    h = GETHOSTBYNAME(name);
+#endif /* _PR_INET6 */
+    
+	if (NULL == h)
+	{
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
+    	if (_pr_ipv6_is_present())
+	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+		else
+	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#else
+	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+	}
+	else
+	{
+		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+
+		if (af == PR_AF_INET6) conversion = _PRIPAddrIPv4Mapped;
+		rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
+		if (PR_SUCCESS != rv)
+		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+		freehostent(h);
+#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
+    	if (_pr_ipv6_is_present())
+			(*((_pr_freehostent_t)_pr_freehostent_fp))(h);
+#endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
+		if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED)
+				&& ((flags & PR_AI_ALL)
+				|| ((flags & PR_AI_ADDRCONFIG) && _pr_have_inet_if))
+				&& !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)) != 0) {
+			rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp);
+			if (PR_SUCCESS != rv)
+				PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+		}
+#endif
+	}
+
+    /* Must match the convoluted logic above for LOCK_DNS() */
+#ifdef _PR_INET6
+#ifdef _PR_HAVE_GETHOSTBYNAME2
+    UNLOCK_DNS();
+#endif	/* _PR_HAVE_GETHOSTBYNAME2 */
+#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
+#ifdef PR_GETIPNODE_NOT_THREADSAFE
+    UNLOCK_DNS();
+#else
+    if (!_pr_ipv6_is_present())
+        UNLOCK_DNS();
+#endif
+#else /* _PR_INET6 */
+    UNLOCK_DNS();
+#endif /* _PR_INET6 */
+
+#if defined(_PR_HAVE_GETHOST_R)
+    if (tmpbuf != localbuf)
+        PR_Free(tmpbuf);
+#endif
+
+	return rv;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
+    const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry)
+{
+	struct hostent *h;
+	PRStatus rv = PR_FAILURE;
+	const void *addr;
+	PRUint32 tmp_ip;
+	int addrlen;
+	PRInt32 af;
+#if defined(_PR_HAVE_GETHOST_R)
+    char localbuf[PR_NETDB_BUF_SIZE];
+    char *tmpbuf;
+    struct hostent tmphe;
+    int h_err;
+#endif
+#if defined(_PR_HAVE_GETIPNODEBYADDR)
+	int error_num;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+	if (hostaddr->raw.family == PR_AF_INET6)
+	{
+#if defined(_PR_INET6_PROBE)
+		af = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
+#elif defined(_PR_INET6)
+		af = AF_INET6;
+#else
+		af = AF_INET;
+#endif
+#if defined(_PR_GHBA_DISALLOW_V4MAPPED)
+		if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip))
+			af = AF_INET;
+#endif
+	}
+	else
+	{
+		PR_ASSERT(hostaddr->raw.family == AF_INET);
+		af = AF_INET;
+	}
+	if (hostaddr->raw.family == PR_AF_INET6) {
+#if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
+		if (af == AF_INET6) {
+			addr = &hostaddr->ipv6.ip;
+			addrlen = sizeof(hostaddr->ipv6.ip);
+		}
+		else
+#endif
+		{
+			PR_ASSERT(af == AF_INET);
+			if (!_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) {
+				PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+				return rv;
+			}
+			tmp_ip = _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)
+												&hostaddr->ipv6.ip);
+			addr = &tmp_ip;
+			addrlen = sizeof(tmp_ip);
+		}
+	} else {
+		PR_ASSERT(hostaddr->raw.family == AF_INET);
+		PR_ASSERT(af == AF_INET);
+		addr = &hostaddr->inet.ip;
+		addrlen = sizeof(hostaddr->inet.ip);
+	}
+
+#if defined(_PR_HAVE_GETHOST_R)
+    tmpbuf = localbuf;
+    if (bufsize > sizeof(localbuf))
+    {
+        tmpbuf = (char *)PR_Malloc(bufsize);
+        if (NULL == tmpbuf)
+        {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return rv;
+        }
+    }
+#endif
+
+    /* Do not need to lock the DNS lock if getipnodebyaddr() is called */
+#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
+	h = getipnodebyaddr(addr, addrlen, af, &error_num);
+#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
+    if (_pr_ipv6_is_present())
+    {
+#ifdef PR_GETIPNODE_NOT_THREADSAFE
+        LOCK_DNS();
+#endif
+    	h = (*((_pr_getipnodebyaddr_t)_pr_getipnodebyaddr_fp))(addr, addrlen,
+				af, &error_num);
+    }
+	else
+    {
+        LOCK_DNS();
+		h = GETHOSTBYADDR(addr, addrlen, af);
+    }
+#else	/* _PR_HAVE_GETIPNODEBYADDR */
+    LOCK_DNS();
+	h = GETHOSTBYADDR(addr, addrlen, af);
+#endif /* _PR_HAVE_GETIPNODEBYADDR */
+	if (NULL == h)
+	{
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+		PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
+    	if (_pr_ipv6_is_present())
+	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+		else
+	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#else
+		PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+	}
+	else
+	{
+		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+		if (hostaddr->raw.family == PR_AF_INET6) {
+			if (af == AF_INET) {
+				if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr*)
+												&hostaddr->ipv6.ip)) {
+					conversion = _PRIPAddrIPv4Mapped;
+				} else if (_PR_IN6_IS_ADDR_V4COMPAT((PRIPv6Addr *)
+													&hostaddr->ipv6.ip)) {
+					conversion = _PRIPAddrIPv4Compat;
+				}
+			}
+		}
+		rv = CopyHostent(h, &buf, &bufsize, conversion, hostentry);
+		if (PR_SUCCESS != rv) {
+		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+		}
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+		freehostent(h);
+#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
+    	if (_pr_ipv6_is_present())
+			(*((_pr_freehostent_t)_pr_freehostent_fp))(h);
+#endif
+	}
+
+    /* Must match the convoluted logic above for LOCK_DNS() */
+#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
+#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
+#ifdef PR_GETIPNODE_NOT_THREADSAFE
+    UNLOCK_DNS();
+#else
+    if (!_pr_ipv6_is_present())
+        UNLOCK_DNS();
+#endif
+#else	/* _PR_HAVE_GETIPNODEBYADDR */
+    UNLOCK_DNS();
+#endif /* _PR_HAVE_GETIPNODEBYADDR */
+
+#if defined(_PR_HAVE_GETHOST_R)
+    if (tmpbuf != localbuf)
+        PR_Free(tmpbuf);
+#endif
+
+	return rv;
+}
+
+/******************************************************************************/
+/*
+ * Some systems define a reentrant version of getprotobyname(). Too bad
+ * the signature isn't always the same. But hey, they tried. If there
+ * is such a definition, use it. Otherwise, grab a lock and do it here.
+ */
+/******************************************************************************/
+
+#if !defined(_PR_HAVE_GETPROTO_R)
+/*
+ * This may seem like a silly thing to do, but the compiler SHOULD
+ * complain if getprotobyname_r() is implemented on some system and
+ * we're not using it. For sure these signatures are different than
+ * any usable implementation.
+ */
+
+static struct protoent *getprotobyname_r(const char* name)
+{
+	return getprotobyname(name);
+} /* getprotobyname_r */
+
+static struct protoent *getprotobynumber_r(PRInt32 number)
+{
+	return getprotobynumber(number);
+} /* getprotobynumber_r */
+
+#endif /* !defined(_PR_HAVE_GETPROTO_R) */
+
+PR_IMPLEMENT(PRStatus) PR_GetProtoByName(
+    const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result)
+{
+	PRStatus rv = PR_SUCCESS;
+#if defined(_PR_HAVE_GETPROTO_R)
+	struct protoent* res = (struct protoent*)result;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#if defined(_PR_HAVE_GETPROTO_R_INT)
+    {
+        /*
+        ** The protoent_data has a pointer as the first field.
+        ** That implies the buffer better be aligned, and char*
+        ** doesn't promise much.
+        */
+        PRUptrdiff aligned = (PRUptrdiff)buffer;
+        if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
+        {
+            aligned += sizeof(struct protoent_data*) - 1;
+            aligned &= ~(sizeof(struct protoent_data*) - 1);
+            buflen -= (aligned - (PRUptrdiff)buffer);
+            buffer = (char*)aligned;
+        }
+    }
+#endif  /* defined(_PR_HAVE_GETPROTO_R_INT) */
+
+    if (PR_NETDB_BUF_SIZE > buflen)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+#if defined(_PR_HAVE_GETPROTO_R_POINTER)
+    if (NULL == getprotobyname_r(name, res, buffer, buflen))
+    {
+        PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+#elif defined(_PR_HAVE_GETPROTO_R_INT)
+    /*
+    ** The buffer needs to be zero'd, and it should be
+    ** at least the size of a struct protoent_data.
+    */
+    memset(buffer, 0, buflen);
+	if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer))
+    {
+        PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+#elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
+    /* The 5th argument for getprotobyname_r() cannot be NULL */
+    if (-1 == getprotobyname_r(name, res, buffer, buflen, &res))
+    {
+        PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+#else  /* do it the hard way */
+	{
+		struct protoent *staticBuf;
+		PR_Lock(_getproto_lock);
+		staticBuf = getprotobyname_r(name);
+		if (NULL == staticBuf)
+		{
+		    rv = PR_FAILURE;
+		    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        }
+		else
+		{
+#if defined(SYMBIAN)
+			char* aliases[2];
+			AssignAliases(staticBuf, aliases);
+#endif
+			rv = CopyProtoent(staticBuf, buffer, buflen, result);
+			if (PR_FAILURE == rv)
+			    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+        }
+		PR_Unlock(_getproto_lock);
+	}
+#endif  /* all that */
+    return rv;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetProtoByNumber(
+    PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result)
+{
+	PRStatus rv = PR_SUCCESS;
+#if defined(_PR_HAVE_GETPROTO_R)
+	struct protoent* res = (struct protoent*)result;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#if defined(_PR_HAVE_GETPROTO_R_INT)
+    {
+        /*
+        ** The protoent_data has a pointer as the first field.
+        ** That implies the buffer better be aligned, and char*
+        ** doesn't promise much.
+        */
+        PRUptrdiff aligned = (PRUptrdiff)buffer;
+        if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
+        {
+            aligned += sizeof(struct protoent_data*) - 1;
+            aligned &= ~(sizeof(struct protoent_data*) - 1);
+            buflen -= (aligned - (PRUptrdiff)buffer);
+            buffer = (char*)aligned;
+        }
+    }
+#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */
+
+    if (PR_NETDB_BUF_SIZE > buflen)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+#if defined(_PR_HAVE_GETPROTO_R_POINTER)
+    if (NULL == getprotobynumber_r(number, res, buffer, buflen))
+    {
+        PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+
+#elif defined(_PR_HAVE_GETPROTO_R_INT)
+    /*
+    ** The buffer needs to be zero'd for these OS's.
+    */
+    memset(buffer, 0, buflen);
+	if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer))
+    {
+        PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+#elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
+    /* The 5th argument for getprotobynumber_r() cannot be NULL */
+    if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res))
+    {
+        PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+#else  /* do it the hard way */
+	{
+		struct protoent *staticBuf;
+		PR_Lock(_getproto_lock);
+		staticBuf = getprotobynumber_r(number);
+		if (NULL == staticBuf)
+		{
+		    rv = PR_FAILURE;
+		    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
+        }
+		else
+		{
+#if defined(SYMBIAN)
+			char* aliases[2];
+			AssignAliases(staticBuf, aliases);
+#endif
+			rv = CopyProtoent(staticBuf, buffer, buflen, result);
+			if (PR_FAILURE == rv)
+			    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+        }
+		PR_Unlock(_getproto_lock);
+	}
+#endif  /* all that crap */
+    return rv;
+
+}
+
+PRUintn _PR_NetAddrSize(const PRNetAddr* addr)
+{
+    PRUintn addrsize;
+
+    /*
+     * RFC 2553 added a new field (sin6_scope_id) to
+     * struct sockaddr_in6.  PRNetAddr's ipv6 member has a
+     * scope_id field to match the new field.  In order to
+     * work with older implementations supporting RFC 2133,
+     * we take the size of struct sockaddr_in6 instead of
+     * addr->ipv6.
+     */
+    if (AF_INET == addr->raw.family)
+        addrsize = sizeof(addr->inet);
+    else if (PR_AF_INET6 == addr->raw.family)
+#if defined(_PR_INET6)
+        addrsize = sizeof(struct sockaddr_in6);
+#else
+        addrsize = sizeof(addr->ipv6);
+#endif
+#if defined(XP_UNIX) || defined(XP_OS2)
+    else if (AF_UNIX == addr->raw.family)
+        addrsize = sizeof(addr->local);
+#endif
+    else addrsize = 0;
+
+    return addrsize;
+}  /* _PR_NetAddrSize */
+
+PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt(
+    PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address)
+{
+    void *addr = hostEnt->h_addr_list[enumIndex++];
+    memset(address, 0, sizeof(PRNetAddr));
+    if (NULL == addr) enumIndex = 0;
+    else
+    {
+        address->raw.family = hostEnt->h_addrtype;
+        if (PR_AF_INET6 == hostEnt->h_addrtype)
+        {
+            address->ipv6.port = htons(port);
+        	address->ipv6.flowinfo = 0;
+        	address->ipv6.scope_id = 0;
+            memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
+        }
+        else
+        {
+            PR_ASSERT(AF_INET == hostEnt->h_addrtype);
+            address->inet.port = htons(port);
+            memcpy(&address->inet.ip, addr, hostEnt->h_length);
+        }
+    }
+    return enumIndex;
+}  /* PR_EnumerateHostEnt */
+
+PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr(
+    PRNetAddrValue val, PRUint16 port, PRNetAddr *addr)
+{
+    PRStatus rv = PR_SUCCESS;
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+	if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet));
+	addr->inet.family = AF_INET;
+	addr->inet.port = htons(port);
+	switch (val)
+	{
+	case PR_IpAddrNull:
+		break;  /* don't overwrite the address */
+	case PR_IpAddrAny:
+		addr->inet.ip = htonl(INADDR_ANY);
+		break;
+	case PR_IpAddrLoopback:
+		addr->inet.ip = htonl(INADDR_LOOPBACK);
+		break;
+	default:
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		rv = PR_FAILURE;
+	}
+    return rv;
+}  /* PR_InitializeNetAddr */
+
+PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
+    PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr)
+{
+    PRStatus rv = PR_SUCCESS;
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (af == PR_AF_INET6)
+    {
+        if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->ipv6));
+        addr->ipv6.family = af;
+        addr->ipv6.port = htons(port);
+        addr->ipv6.flowinfo = 0;
+        addr->ipv6.scope_id = 0;
+        switch (val)
+        {
+        case PR_IpAddrNull:
+            break;  /* don't overwrite the address */
+        case PR_IpAddrAny:
+            addr->ipv6.ip = _pr_in6addr_any;
+            break;
+        case PR_IpAddrLoopback:
+            addr->ipv6.ip = _pr_in6addr_loopback;
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = PR_FAILURE;
+        }
+    }
+    else
+    {
+        if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet));
+        addr->inet.family = af;
+        addr->inet.port = htons(port);
+        switch (val)
+        {
+        case PR_IpAddrNull:
+            break;  /* don't overwrite the address */
+        case PR_IpAddrAny:
+            addr->inet.ip = htonl(INADDR_ANY);
+            break;
+        case PR_IpAddrLoopback:
+            addr->inet.ip = htonl(INADDR_LOOPBACK);
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = PR_FAILURE;
+        }
+    }
+    return rv;
+}  /* PR_SetNetAddr */
+
+PR_IMPLEMENT(PRBool)
+PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val)
+{
+    if (addr->raw.family == PR_AF_INET6) {
+        if (val == PR_IpAddrAny) {
+			if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)) {
+            	return PR_TRUE;
+			} else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)
+					&& _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)
+							== htonl(INADDR_ANY)) {
+            	return PR_TRUE;
+			}
+        } else if (val == PR_IpAddrLoopback) {
+            if (_PR_IN6_IS_ADDR_LOOPBACK((PRIPv6Addr *)&addr->ipv6.ip)) {
+            	return PR_TRUE;
+			} else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)
+					&& _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)
+							== htonl(INADDR_LOOPBACK)) {
+            	return PR_TRUE;
+			}
+        } else if (val == PR_IpAddrV4Mapped
+                && _PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)) {
+            return PR_TRUE;
+        }
+    } else {
+        if (addr->raw.family == AF_INET) {
+            if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) {
+                return PR_TRUE;
+            } else if (val == PR_IpAddrLoopback
+                    && addr->inet.ip == htonl(INADDR_LOOPBACK)) {
+                return PR_TRUE;
+            }
+        }
+    }
+    return PR_FALSE;
+}
+
+extern int pr_inet_aton(const char *cp, PRUint32 *addr);
+
+#define XX 127
+static const unsigned char index_hex[256] = {
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+};
+
+/*
+ * StringToV6Addr() returns 1 if the conversion succeeds,
+ * or 0 if the input is not a valid IPv6 address string.
+ * (Same as inet_pton(AF_INET6, string, addr).)
+ */
+static int StringToV6Addr(const char *string, PRIPv6Addr *addr)
+{
+    const unsigned char *s = (const unsigned char *)string;
+    int section = 0;        /* index of the current section (a 16-bit
+                             * piece of the address */
+    int double_colon = -1;  /* index of the section after the first
+                             * 16-bit group of zeros represented by
+                             * the double colon */
+    unsigned int val;
+    int len;
+
+    /* Handle initial (double) colon */
+    if (*s == ':') {
+        if (s[1] != ':') return 0;
+        s += 2;
+        addr->pr_s6_addr16[0] = 0;
+        section = double_colon = 1;
+    }
+
+    while (*s) {
+        if (section == 8) return 0; /* too long */
+        if (*s == ':') {
+            if (double_colon != -1) return 0; /* two double colons */
+            addr->pr_s6_addr16[section++] = 0;
+            double_colon = section;
+            s++;
+            continue;
+        }
+        for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) {
+            val = (val << 4) + index_hex[*s++];
+        }
+        if (*s == '.') {
+            if (len == 0) return 0; /* nothing between : and . */
+            break;
+        }
+        if (*s == ':') {
+            s++;
+            if (!*s) return 0; /* cannot end with single colon */
+        } else if (*s) {
+            return 0; /* bad character */
+        }
+        addr->pr_s6_addr16[section++] = htons((unsigned short)val);
+    }
+    
+    if (*s == '.') {
+        /* Have a trailing v4 format address */
+        if (section > 6) return 0; /* not enough room */
+
+        /*
+         * The number before the '.' is decimal, but we parsed it
+         * as hex.  That means it is in BCD.  Check it for validity
+         * and convert it to binary.
+         */
+        if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) return 0;
+        val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf);
+        addr->pr_s6_addr[2 * section] = val;
+
+        s++;
+        val = index_hex[*s++];
+        if (val > 9) return 0;
+        while (*s >= '0' && *s <= '9') {
+            val = val * 10 + *s++ - '0';
+            if (val > 255) return 0;
+        }
+        if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
+        addr->pr_s6_addr[2 * section + 1] = val;
+        section++;
+
+        s++;
+        val = index_hex[*s++];
+        if (val > 9) return 0;
+        while (*s >= '0' && *s <= '9') {
+            val = val * 10 + *s++ - '0';
+            if (val > 255) return 0;
+        }
+        if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
+        addr->pr_s6_addr[2 * section] = val;
+
+        s++;
+        val = index_hex[*s++];
+        if (val > 9) return 0;
+        while (*s >= '0' && *s <= '9') {
+            val = val * 10 + *s++ - '0';
+            if (val > 255) return 0;
+        }
+        if (*s) return 0; /* must have exactly 4 decimal numbers */
+        addr->pr_s6_addr[2 * section + 1] = val;
+        section++;
+    }
+    
+    if (double_colon != -1) {
+        /* Stretch the double colon */
+        int tosection;
+        int ncopy = section - double_colon;
+        for (tosection = 7; ncopy--; tosection--) {
+            addr->pr_s6_addr16[tosection] = 
+                addr->pr_s6_addr16[double_colon + ncopy];
+        }
+        while (tosection >= double_colon) {
+            addr->pr_s6_addr16[tosection--] = 0;
+        }
+    } else if (section != 8) {
+        return 0; /* too short */
+    }
+    return 1;
+}
+#undef XX
+
+#ifndef _PR_HAVE_INET_NTOP
+static const char *basis_hex = "0123456789abcdef";
+
+/*
+ * V6AddrToString() returns a pointer to the buffer containing
+ * the text string if the conversion succeeds, and NULL otherwise.
+ * (Same as inet_ntop(AF_INET6, addr, buf, size), except that errno
+ * is not set on failure.)
+ */
+static const char *V6AddrToString(
+    const PRIPv6Addr *addr, char *buf, PRUint32 size)
+{
+#define STUFF(c) do { \
+    if (!size--) return NULL; \
+    *buf++ = (c); \
+} while (0)
+
+    int double_colon = -1;          /* index of the first 16-bit
+                                     * group of zeros represented
+                                     * by the double colon */
+    int double_colon_length = 1;    /* use double colon only if
+                                     * there are two or more 16-bit
+                                     * groups of zeros */
+    int zero_length;
+    int section;
+    unsigned int val;
+    const char *bufcopy = buf;
+
+    /* Scan to find the placement of the double colon */
+    for (section = 0; section < 8; section++) {
+        if (addr->pr_s6_addr16[section] == 0) {
+            zero_length = 1;
+            section++;
+            while (section < 8 && addr->pr_s6_addr16[section] == 0) {
+                zero_length++;
+                section++;
+            }
+            /* Select the longest sequence of zeros */
+            if (zero_length > double_colon_length) {
+                double_colon = section - zero_length;
+                double_colon_length = zero_length;
+            }
+        }
+    }
+
+    /* Now start converting to a string */
+    section = 0;
+
+    if (double_colon == 0) {
+        if (double_colon_length == 6 ||
+            (double_colon_length == 5 && addr->pr_s6_addr16[5] == 0xffff)) {
+            /* ipv4 format address */
+            STUFF(':');
+            STUFF(':');
+            if (double_colon_length == 5) {
+                STUFF('f');
+                STUFF('f');
+                STUFF('f');
+                STUFF('f');
+                STUFF(':');
+            }
+            if (addr->pr_s6_addr[12] > 99) STUFF(addr->pr_s6_addr[12]/100 + '0');
+            if (addr->pr_s6_addr[12] > 9) STUFF((addr->pr_s6_addr[12]%100)/10 + '0');
+            STUFF(addr->pr_s6_addr[12]%10 + '0');
+            STUFF('.');
+            if (addr->pr_s6_addr[13] > 99) STUFF(addr->pr_s6_addr[13]/100 + '0');
+            if (addr->pr_s6_addr[13] > 9) STUFF((addr->pr_s6_addr[13]%100)/10 + '0');
+            STUFF(addr->pr_s6_addr[13]%10 + '0');
+            STUFF('.');
+            if (addr->pr_s6_addr[14] > 99) STUFF(addr->pr_s6_addr[14]/100 + '0');
+            if (addr->pr_s6_addr[14] > 9) STUFF((addr->pr_s6_addr[14]%100)/10 + '0');
+            STUFF(addr->pr_s6_addr[14]%10 + '0');
+            STUFF('.');
+            if (addr->pr_s6_addr[15] > 99) STUFF(addr->pr_s6_addr[15]/100 + '0');
+            if (addr->pr_s6_addr[15] > 9) STUFF((addr->pr_s6_addr[15]%100)/10 + '0');
+            STUFF(addr->pr_s6_addr[15]%10 + '0');
+            STUFF('\0');
+            return bufcopy;
+        }
+    }
+
+    while (section < 8) {
+        if (section == double_colon) {
+            STUFF(':');
+            STUFF(':');
+            section += double_colon_length;
+            continue;
+        }
+        val = ntohs(addr->pr_s6_addr16[section]);
+        if (val > 0xfff) {
+            STUFF(basis_hex[val >> 12]);
+        }
+        if (val > 0xff) {
+            STUFF(basis_hex[(val >> 8) & 0xf]);
+        }
+        if (val > 0xf) {
+            STUFF(basis_hex[(val >> 4) & 0xf]);
+        }
+        STUFF(basis_hex[val & 0xf]);
+        section++;
+        if (section < 8 && section != double_colon) STUFF(':');
+    }
+    STUFF('\0');
+    return bufcopy;
+#undef STUFF    
+}
+#endif /* !_PR_HAVE_INET_NTOP */
+
+/*
+ * Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr
+ */
+PR_IMPLEMENT(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr)
+{
+    PRUint8 *dstp;
+    dstp = v6addr->pr_s6_addr;
+    memset(dstp, 0, 10);
+    memset(dstp + 10, 0xff, 2);
+    memcpy(dstp + 12,(char *) &v4addr, 4);
+}
+
+PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); }
+PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); }
+PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); }
+PR_IMPLEMENT(PRUint32) PR_htonl(PRUint32 n) { return htonl(n); }
+PR_IMPLEMENT(PRUint64) PR_ntohll(PRUint64 n)
+{
+#ifdef IS_BIG_ENDIAN
+    return n;
+#else
+    PRUint64 tmp;
+    PRUint32 hi, lo;
+    LL_L2UI(lo, n);
+    LL_SHR(tmp, n, 32);
+    LL_L2UI(hi, tmp);
+    hi = PR_ntohl(hi);
+    lo = PR_ntohl(lo);
+    LL_UI2L(n, lo);
+    LL_SHL(n, n, 32);
+    LL_UI2L(tmp, hi);
+    LL_ADD(n, n, tmp);
+    return n;
+#endif
+}  /* ntohll */
+
+PR_IMPLEMENT(PRUint64) PR_htonll(PRUint64 n)
+{
+#ifdef IS_BIG_ENDIAN
+    return n;
+#else
+    PRUint64 tmp;
+    PRUint32 hi, lo;
+    LL_L2UI(lo, n);
+    LL_SHR(tmp, n, 32);
+    LL_L2UI(hi, tmp);
+    hi = htonl(hi);
+    lo = htonl(lo);
+    LL_UI2L(n, lo);
+    LL_SHL(n, n, 32);
+    LL_UI2L(tmp, hi);
+    LL_ADD(n, n, tmp);
+    return n;
+#endif
+}  /* htonll */
+
+
+/*
+ * Implementation of PR_GetAddrInfoByName and friends
+ *
+ * Compile-time options:
+ *
+ *  _PR_HAVE_GETADDRINFO  Define this macro if the target system provides
+ *                        getaddrinfo. With this defined, NSPR will require
+ *                        getaddrinfo at run time. If this if not defined,
+ *                        then NSPR will attempt to dynamically resolve
+ *                        getaddrinfo, falling back to PR_GetHostByName if
+ *                        getaddrinfo does not exist on the target system.
+ *
+ * Since getaddrinfo is a relatively new system call on many systems,
+ * we are forced to dynamically resolve it at run time in most cases.
+ * The exception includes any system (such as Mac OS X) that is known to
+ * provide getaddrinfo in all versions that NSPR cares to support.
+ */
+
+#if defined(_PR_HAVE_GETADDRINFO)
+
+#if defined(_PR_INET6)
+
+typedef struct addrinfo PRADDRINFO;
+#define GETADDRINFO getaddrinfo
+#define FREEADDRINFO freeaddrinfo
+#define GETNAMEINFO getnameinfo
+
+#elif defined(_PR_INET6_PROBE)
+
+typedef struct addrinfo PRADDRINFO;
+
+/* getaddrinfo/freeaddrinfo/getnameinfo prototypes */ 
+#if defined(WIN32)
+#define FUNC_MODIFIER __stdcall
+#else
+#define FUNC_MODIFIER
+#endif
+typedef int (FUNC_MODIFIER * FN_GETADDRINFO)
+    (const char *nodename,
+     const char *servname,
+     const PRADDRINFO *hints,
+     PRADDRINFO **res);
+typedef int (FUNC_MODIFIER * FN_FREEADDRINFO)
+    (PRADDRINFO *ai);
+typedef int (FUNC_MODIFIER * FN_GETNAMEINFO)
+    (const struct sockaddr *addr, int addrlen,
+     char *host, int hostlen,
+     char *serv, int servlen, int flags);
+
+/* global state */
+static FN_GETADDRINFO   _pr_getaddrinfo   = NULL;
+static FN_FREEADDRINFO  _pr_freeaddrinfo  = NULL;
+static FN_GETNAMEINFO   _pr_getnameinfo   = NULL;
+
+#define GETADDRINFO_SYMBOL "getaddrinfo"
+#define FREEADDRINFO_SYMBOL "freeaddrinfo"
+#define GETNAMEINFO_SYMBOL "getnameinfo"
+
+PRStatus
+_pr_find_getaddrinfo(void)
+{
+    PRLibrary *lib;
+#ifdef WIN32
+    /*
+     * On windows, we need to search ws2_32.dll or wship6.dll
+     * (Microsoft IPv6 Technology Preview for Windows 2000) for
+     * getaddrinfo and freeaddrinfo.  These libraries might not
+     * be loaded yet.
+     */
+    const char *libname[] = { "ws2_32.dll", "wship6.dll" };
+    int i;
+
+    for (i = 0; i < sizeof(libname)/sizeof(libname[0]); i++) {
+        lib = PR_LoadLibrary(libname[i]);
+        if (!lib) {
+            continue;
+        }
+        _pr_getaddrinfo = (FN_GETADDRINFO)
+            PR_FindFunctionSymbol(lib, GETADDRINFO_SYMBOL);
+        if (!_pr_getaddrinfo) {
+            PR_UnloadLibrary(lib);
+            continue;
+        }
+        _pr_freeaddrinfo = (FN_FREEADDRINFO)
+            PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
+        _pr_getnameinfo = (FN_GETNAMEINFO)
+            PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL);
+        if (!_pr_freeaddrinfo || !_pr_getnameinfo) {
+            PR_UnloadLibrary(lib);
+            continue;
+        }
+        /* Keep the library loaded. */
+        return PR_SUCCESS;
+    }
+    return PR_FAILURE;
+#else
+    /*
+     * Resolve getaddrinfo by searching all loaded libraries.  Then
+     * search library containing getaddrinfo for freeaddrinfo.
+     */
+    _pr_getaddrinfo = (FN_GETADDRINFO)
+        PR_FindFunctionSymbolAndLibrary(GETADDRINFO_SYMBOL, &lib);
+    if (!_pr_getaddrinfo) {
+        return PR_FAILURE;
+    }
+    _pr_freeaddrinfo = (FN_FREEADDRINFO)
+        PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
+    _pr_getnameinfo = (FN_GETNAMEINFO)
+        PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL);
+    PR_UnloadLibrary(lib);
+    if (!_pr_freeaddrinfo || !_pr_getnameinfo) {
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+#endif
+}
+
+#define GETADDRINFO (*_pr_getaddrinfo)
+#define FREEADDRINFO (*_pr_freeaddrinfo)
+#define GETNAMEINFO (*_pr_getnameinfo)
+
+#endif /* _PR_INET6 */
+
+#endif /* _PR_HAVE_GETADDRINFO */
+
+#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE)
+/*
+ * If getaddrinfo does not exist, then we will fall back on
+ * PR_GetHostByName, which requires that we allocate a buffer for the 
+ * PRHostEnt data structure and its members.
+ */
+typedef struct PRAddrInfoFB {
+    char      buf[PR_NETDB_BUF_SIZE];
+    PRHostEnt hostent;
+    PRBool    has_cname;
+} PRAddrInfoFB;
+
+static PRAddrInfo *
+pr_GetAddrInfoByNameFB(const char  *hostname,
+                       PRUint16     af,
+                       PRIntn       flags)
+{
+    PRStatus rv;
+    PRAddrInfoFB *ai;
+    /* fallback on PR_GetHostByName */
+    ai = PR_NEW(PRAddrInfoFB);
+    if (!ai) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+    rv = PR_GetHostByName(hostname, ai->buf, sizeof ai->buf, &ai->hostent);
+    if (rv == PR_FAILURE) {
+        PR_Free(ai);
+        return NULL;
+    }
+    ai->has_cname = !(flags & PR_AI_NOCANONNAME);
+
+    return (PRAddrInfo *) ai;
+}
+#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */
+
+PR_IMPLEMENT(PRAddrInfo *) PR_GetAddrInfoByName(const char  *hostname,
+                                                PRUint16     af,
+                                                PRIntn       flags)
+{
+    /* restrict input to supported values */
+    if ((af != PR_AF_INET && af != PR_AF_UNSPEC) ||
+        (flags & ~ PR_AI_NOCANONNAME) != PR_AI_ADDRCONFIG) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return NULL;
+    }
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#if !defined(_PR_HAVE_GETADDRINFO)
+    return pr_GetAddrInfoByNameFB(hostname, af, flags);
+#else
+#if defined(_PR_INET6_PROBE)
+    if (!_pr_ipv6_is_present()) {
+        return pr_GetAddrInfoByNameFB(hostname, af, flags);
+    }
+#endif
+    {
+        PRADDRINFO *res, hints;
+        PRStatus rv;
+
+        /*
+         * we assume a RFC 2553 compliant getaddrinfo.  this may at some
+         * point need to be customized as platforms begin to adopt the
+         * RFC 3493.
+         */
+
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_flags = (flags & PR_AI_NOCANONNAME) ? 0: AI_CANONNAME;
+        hints.ai_family = (af == PR_AF_INET) ? AF_INET : AF_UNSPEC;
+
+        /*
+         * it is important to select a socket type in the hints, otherwise we
+         * will get back repetitive entries: one for each socket type.  since
+         * we do not expose ai_socktype through our API, it is okay to do this
+         * here.  the application may still choose to create a socket of some
+         * other type.
+         */
+        hints.ai_socktype = SOCK_STREAM;
+
+        rv = GETADDRINFO(hostname, NULL, &hints, &res);
+        if (rv == 0)
+            return (PRAddrInfo *) res;
+
+        PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, rv);
+    }
+    return NULL;
+#endif
+}
+
+PR_IMPLEMENT(void) PR_FreeAddrInfo(PRAddrInfo *ai)
+{
+#if defined(_PR_HAVE_GETADDRINFO)
+#if defined(_PR_INET6_PROBE)
+    if (!_pr_ipv6_is_present())
+        PR_Free((PRAddrInfoFB *) ai);
+    else
+#endif
+        FREEADDRINFO((PRADDRINFO *) ai);
+#else
+    PR_Free((PRAddrInfoFB *) ai);
+#endif
+}
+
+PR_IMPLEMENT(void *) PR_EnumerateAddrInfo(void             *iterPtr,
+                                          const PRAddrInfo *base,
+                                          PRUint16          port,
+                                          PRNetAddr        *result)
+{
+#if defined(_PR_HAVE_GETADDRINFO)
+    PRADDRINFO *ai;
+#if defined(_PR_INET6_PROBE)
+    if (!_pr_ipv6_is_present()) {
+        /* using PRAddrInfoFB */
+        PRIntn iter = (PRIntn)(PRPtrdiff) iterPtr;
+        iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
+        if (iter < 0)
+            iter = 0;
+        return (void *)(PRPtrdiff) iter;
+    }
+#endif
+
+    if (iterPtr)
+        ai = ((PRADDRINFO *) iterPtr)->ai_next;
+    else
+        ai = (PRADDRINFO *) base;
+
+    while (ai && ai->ai_addrlen > sizeof(PRNetAddr))
+        ai = ai->ai_next;
+
+    if (ai) {
+        /* copy sockaddr to PRNetAddr */
+        memcpy(result, ai->ai_addr, ai->ai_addrlen);
+        result->raw.family = ai->ai_addr->sa_family;
+#ifdef _PR_INET6
+        if (AF_INET6 == result->raw.family)
+            result->raw.family = PR_AF_INET6;
+#endif
+        if (ai->ai_addrlen < sizeof(PRNetAddr))
+            memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen);
+
+        if (result->raw.family == PR_AF_INET)
+            result->inet.port = htons(port);
+        else
+            result->ipv6.port = htons(port);
+    }
+
+    return ai;
+#else
+    /* using PRAddrInfoFB */
+    PRIntn iter = (PRIntn) iterPtr;
+    iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
+    if (iter < 0)
+        iter = 0;
+    return (void *) iter;
+#endif
+}
+
+PR_IMPLEMENT(const char *) PR_GetCanonNameFromAddrInfo(const PRAddrInfo *ai)
+{
+#if defined(_PR_HAVE_GETADDRINFO)
+#if defined(_PR_INET6_PROBE)
+    if (!_pr_ipv6_is_present()) {
+        const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
+        return fb->has_cname ? fb->hostent.h_name : NULL;
+    } 
+#endif
+    return ((const PRADDRINFO *) ai)->ai_canonname;
+#else
+    const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
+    return fb->has_cname ? fb->hostent.h_name : NULL;
+#endif
+}
+
+#if defined(_PR_HAVE_GETADDRINFO)
+static PRStatus pr_StringToNetAddrGAI(const char *string, PRNetAddr *addr)
+{
+    PRADDRINFO *res, hints;
+    int rv;  /* 0 for success, or the error code EAI_xxx */
+    PRNetAddr laddr;
+    PRStatus status = PR_SUCCESS;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_NUMERICHOST;
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    rv = GETADDRINFO(string, NULL, &hints, &res);
+    if (rv != 0)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv);
+        return PR_FAILURE;
+    }
+
+    /* pick up the first addr */
+    memcpy(&laddr, res->ai_addr, res->ai_addrlen);
+    if (AF_INET6 == res->ai_addr->sa_family)
+    {
+        addr->ipv6.family = PR_AF_INET6;
+        addr->ipv6.ip = laddr.ipv6.ip;
+        addr->ipv6.scope_id = laddr.ipv6.scope_id;
+    }
+    else if (AF_INET == res->ai_addr->sa_family)
+    {
+        addr->inet.family = PR_AF_INET;
+        addr->inet.ip = laddr.inet.ip;
+    }
+    else
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        status = PR_FAILURE;
+    }
+
+    FREEADDRINFO(res);
+    return status;
+}
+#endif  /* _PR_HAVE_GETADDRINFO */
+
+static PRStatus pr_StringToNetAddrFB(const char *string, PRNetAddr *addr)
+{
+    PRIntn rv;
+
+    rv = pr_inet_aton(string, &addr->inet.ip);
+    if (1 == rv)
+    {
+        addr->raw.family = AF_INET;
+        return PR_SUCCESS;
+    }
+
+    PR_ASSERT(0 == rv);
+    /* clean up after the failed call */
+    memset(&addr->inet.ip, 0, sizeof(addr->inet.ip));
+
+    rv = StringToV6Addr(string, &addr->ipv6.ip);
+    if (1 == rv)
+    {
+        addr->raw.family = PR_AF_INET6;
+        return PR_SUCCESS;
+    }
+
+    PR_ASSERT(0 == rv);
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (!addr || !string || !*string)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+#if !defined(_PR_HAVE_GETADDRINFO)
+    return pr_StringToNetAddrFB(string, addr);
+#else
+#if defined(_PR_INET6_PROBE)
+    if (!_pr_ipv6_is_present())
+        return pr_StringToNetAddrFB(string, addr);
+#endif
+    /*
+     * getaddrinfo with AI_NUMERICHOST is much slower than pr_inet_aton on some
+     * platforms, such as Mac OS X (bug 404399), Linux glibc 2.10 (bug 344809),
+     * and most likely others. So we only use it to convert literal IP addresses
+     * that contain IPv6 scope IDs, which pr_inet_aton cannot convert.
+     */
+    if (!strchr(string, '%'))
+        return pr_StringToNetAddrFB(string, addr);
+
+    return pr_StringToNetAddrGAI(string, addr);
+#endif
+}
+
+#if defined(_PR_HAVE_GETADDRINFO)
+static PRStatus pr_NetAddrToStringGNI(
+    const PRNetAddr *addr, char *string, PRUint32 size)
+{
+    int addrlen;
+    const PRNetAddr *addrp = addr;
+#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
+    PRUint16 md_af = addr->raw.family;
+    PRNetAddr addrcopy;
+#endif
+    int rv;  /* 0 for success, or the error code EAI_xxx */
+
+#ifdef _PR_INET6
+    if (addr->raw.family == PR_AF_INET6)
+    {
+        md_af = AF_INET6;
+#ifndef _PR_HAVE_SOCKADDR_LEN
+        addrcopy = *addr;
+        addrcopy.raw.family = AF_INET6;
+        addrp = &addrcopy;
+#endif
+    }
+#endif
+
+    addrlen = PR_NETADDR_SIZE(addr);
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    addrcopy = *addr;
+    ((struct sockaddr*)&addrcopy)->sa_len = addrlen;
+    ((struct sockaddr*)&addrcopy)->sa_family = md_af;
+    addrp = &addrcopy;
+#endif
+    rv = GETNAMEINFO((const struct sockaddr *)addrp, addrlen,
+        string, size, NULL, 0, NI_NUMERICHOST);
+    if (rv != 0)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+#endif  /* _PR_HAVE_GETADDRINFO */
+
+#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE)
+static PRStatus pr_NetAddrToStringFB(
+    const PRNetAddr *addr, char *string, PRUint32 size)
+{
+    if (PR_AF_INET6 == addr->raw.family)
+    {
+#if defined(_PR_HAVE_INET_NTOP)
+        if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size))
+#else
+        if (NULL == V6AddrToString(&addr->ipv6.ip, string, size))
+#endif
+        {
+            /* the size of the result buffer is inadequate */
+            PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+            return PR_FAILURE;
+        }
+    }
+    else
+    {
+        if (size < 16) goto failed;
+        if (AF_INET != addr->raw.family) goto failed;
+        else
+        {
+            unsigned char *byte = (unsigned char*)&addr->inet.ip;
+            PR_snprintf(string, size, "%u.%u.%u.%u",
+                byte[0], byte[1], byte[2], byte[3]);
+        }
+    }
+
+    return PR_SUCCESS;
+
+failed:
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return PR_FAILURE;
+
+}  /* pr_NetAddrToStringFB */
+#endif  /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */
+
+PR_IMPLEMENT(PRStatus) PR_NetAddrToString(
+    const PRNetAddr *addr, char *string, PRUint32 size)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#if !defined(_PR_HAVE_GETADDRINFO)
+    return pr_NetAddrToStringFB(addr, string, size);
+#else
+#if defined(_PR_INET6_PROBE)
+    if (!_pr_ipv6_is_present())
+        return pr_NetAddrToStringFB(addr, string, size);
+#endif
+    return pr_NetAddrToStringGNI(addr, string, size);
+#endif
+}  /* PR_NetAddrToString */
diff --git a/mozilla/nsprpub/pr/src/misc/prolock.c b/mozilla/nsprpub/pr/src/misc/prolock.c
new file mode 100644
index 0000000..a1d8a0f
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prolock.c
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+**  prolock.c -- NSPR Ordered Lock
+** 
+**  Implement the API defined in prolock.h
+** 
+*/
+#include "prolock.h"
+#include "prlog.h"
+#include "prerror.h"
+
+PR_IMPLEMENT(PROrderedLock *) 
+    PR_CreateOrderedLock( 
+        PRInt32 order,
+        const char *name
+)
+{
+    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+} /*  end PR_CreateOrderedLock() */
+
+
+PR_IMPLEMENT(void) 
+    PR_DestroyOrderedLock( 
+        PROrderedLock *lock 
+)
+{
+    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+} /*  end PR_DestroyOrderedLock() */
+
+
+PR_IMPLEMENT(void) 
+    PR_LockOrderedLock( 
+        PROrderedLock *lock 
+)
+{
+    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+} /*  end PR_LockOrderedLock() */
+
+
+PR_IMPLEMENT(PRStatus) 
+    PR_UnlockOrderedLock( 
+        PROrderedLock *lock 
+)
+{
+    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+} /*  end PR_UnlockOrderedLock() */
diff --git a/mozilla/nsprpub/pr/src/misc/prrng.c b/mozilla/nsprpub/pr/src/misc/prrng.c
new file mode 100644
index 0000000..6cd7e23
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prrng.c
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+/*
+ * We were not including <string.h> in optimized builds.  On AIX this
+ * caused libnspr4.so to export memcpy and some binaries linked with
+ * libnspr4.so resolved their memcpy references with libnspr4.so.  To
+ * be backward compatible with old libnspr4.so binaries, we do not
+ * include <string.h> in optimized builds for AIX.  (bug 200561)
+ */
+#if !(defined(AIX) && !defined(DEBUG))
+#include <string.h>
+#endif
+
+PRSize _pr_CopyLowBits( 
+    void *dst, 
+    PRSize dstlen, 
+    void *src, 
+    PRSize srclen )
+{
+    if (srclen <= dstlen) {
+    	memcpy(dst, src, srclen);
+	    return srclen;
+    }
+#if defined IS_BIG_ENDIAN
+    memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
+#else
+    memcpy(dst, src, dstlen);
+#endif
+    return dstlen;
+}    
+
+PR_IMPLEMENT(PRSize) PR_GetRandomNoise( 
+    void    *buf,
+    PRSize  size
+)
+{
+    return( _PR_MD_GET_RANDOM_NOISE( buf, size ));
+} /* end PR_GetRandomNoise() */
+/* end prrng.c */
diff --git a/mozilla/nsprpub/pr/src/misc/prsystem.c b/mozilla/nsprpub/pr/src/misc/prsystem.c
new file mode 100644
index 0000000..1996468
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prsystem.c
@@ -0,0 +1,360 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#include "prsystem.h"
+#include "prprf.h"
+#include "prlong.h"
+
+#if defined(BEOS)
+#include <kernel/OS.h>
+#endif
+
+#if defined(OS2)
+#define INCL_DOS
+#define INCL_DOSMISC
+#include <os2.h>
+/* define the required constant if it is not already defined in the headers */
+#ifndef QSV_NUMPROCESSORS
+#define QSV_NUMPROCESSORS 26
+#endif
+#endif
+
+/* BSD-derived systems use sysctl() to get the number of processors */
+#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
+    || defined(OPENBSD) || defined(DARWIN)
+#define _PR_HAVE_SYSCTL
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#endif
+
+#if defined(DARWIN)
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#endif
+
+#if defined(HPUX)
+#include <sys/mpctl.h>
+#include <sys/pstat.h>
+#endif
+
+#if defined(XP_UNIX)
+#include <unistd.h>
+#include <sys/utsname.h>
+#endif
+
+#if defined(AIX)
+#include <cf.h>
+#include <sys/cfgodm.h>
+#endif
+
+#if defined(WIN32)
+/* This struct is not present in VC6 headers, so declare it here */
+typedef struct {
+    DWORD dwLength;
+    DWORD dwMemoryLoad;
+    DWORDLONG ullTotalPhys;
+    DWORDLONG ullAvailPhys;
+    DWORDLONG ullToalPageFile;
+    DWORDLONG ullAvailPageFile;
+    DWORDLONG ullTotalVirtual;
+    DWORDLONG ullAvailVirtual;
+    DWORDLONG ullAvailExtendedVirtual;
+} PR_MEMORYSTATUSEX;
+
+/* Typedef for dynamic lookup of GlobalMemoryStatusEx(). */
+typedef BOOL (WINAPI *GlobalMemoryStatusExFn)(PR_MEMORYSTATUSEX *);
+#endif
+
+PR_IMPLEMENT(char) PR_GetDirectorySeparator(void)
+{
+    return PR_DIRECTORY_SEPARATOR;
+}  /* PR_GetDirectorySeparator */
+
+/*
+** OBSOLETE -- the function name is misspelled.
+*/
+PR_IMPLEMENT(char) PR_GetDirectorySepartor(void)
+{
+#if defined(DEBUG)
+    static PRBool warn = PR_TRUE;
+    if (warn) {
+        warn = _PR_Obsolete("PR_GetDirectorySepartor()",
+                "PR_GetDirectorySeparator()");
+    }
+#endif
+    return PR_GetDirectorySeparator();
+}  /* PR_GetDirectorySepartor */
+
+PR_IMPLEMENT(char) PR_GetPathSeparator(void)
+{
+    return PR_PATH_SEPARATOR;
+}  /* PR_GetPathSeparator */
+
+PR_IMPLEMENT(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen)
+{
+    PRUintn len = 0;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    switch(cmd)
+    {
+      case PR_SI_HOSTNAME:
+      case PR_SI_HOSTNAME_UNTRUNCATED:
+        if (PR_FAILURE == _PR_MD_GETHOSTNAME(buf, (PRUintn)buflen))
+            return PR_FAILURE;
+
+        if (cmd == PR_SI_HOSTNAME_UNTRUNCATED)
+            break;
+        /*
+         * On some platforms a system does not have a hostname and
+         * its IP address is returned instead.   The following code
+         * should be skipped on those platforms.
+         */
+#ifndef _PR_GET_HOST_ADDR_AS_NAME
+        /* Return the unqualified hostname */
+            while (buf[len] && (len < buflen)) {
+                if (buf[len] == '.') {
+                    buf[len] = '\0';
+                    break;
+                }
+                len += 1;
+            }    
+#endif
+         break;
+
+      case PR_SI_SYSNAME:
+        /* Return the operating system name */
+#if defined(XP_UNIX) || defined(WIN32)
+        if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen))
+            return PR_FAILURE;
+#else
+        (void)PR_snprintf(buf, buflen, _PR_SI_SYSNAME);
+#endif
+        break;
+
+      case PR_SI_RELEASE:
+        /* Return the version of the operating system */
+#if defined(XP_UNIX) || defined(WIN32)
+        if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen))
+            return PR_FAILURE;
+#endif
+#if defined(XP_OS2)
+        {
+            ULONG os2ver[2] = {0};
+            DosQuerySysInfo(QSV_VERSION_MINOR, QSV_VERSION_REVISION,
+                            &os2ver, sizeof(os2ver));
+            /* Formatting for normal usage (2.11, 3.0, 4.0, 4.5); officially,
+               Warp 4 is version 2.40.00, WSeB 2.45.00 */
+            if (os2ver[0] < 30)
+              (void)PR_snprintf(buf, buflen, "%s%lu",
+                                "2.", os2ver[0]);
+            else if (os2ver[0] < 45)
+              (void)PR_snprintf(buf, buflen, "%lu%s%lu",
+                                os2ver[0]/10, ".", os2ver[1]);
+            else
+              (void)PR_snprintf(buf, buflen, "%.1f",
+                                os2ver[0]/10.0);
+        }
+#endif /* OS2 */
+        break;
+
+      case PR_SI_ARCHITECTURE:
+        /* Return the architecture of the machine (ie. x86, mips, alpha, ...)*/
+        (void)PR_snprintf(buf, buflen, _PR_SI_ARCHITECTURE);
+        break;
+	  default:
+			PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+			return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+/*
+** PR_GetNumberOfProcessors()
+** 
+** Implementation notes:
+**   Every platform does it a bit different.
+**     numCpus is the returned value.
+**   for each platform's "if defined" section
+**     declare your local variable
+**     do your thing, assign to numCpus
+**   order of the if defined()s may be important,
+**     especially for unix variants. Do platform
+**     specific implementations before XP_UNIX.
+** 
+*/
+PR_IMPLEMENT(PRInt32) PR_GetNumberOfProcessors( void )
+{
+    PRInt32     numCpus;
+#if defined(WIN32)
+    SYSTEM_INFO     info;
+
+    GetSystemInfo( &info );
+    numCpus = info.dwNumberOfProcessors;
+#elif defined(BEOS)
+    system_info sysInfo;
+
+    get_system_info(&sysInfo);
+    numCpus = sysInfo.cpu_count;
+#elif defined(OS2)
+    DosQuerySysInfo( QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, &numCpus, sizeof(numCpus));
+#elif defined(_PR_HAVE_SYSCTL)
+    int mib[2];
+    int rc;
+    size_t len = sizeof(numCpus);
+
+    mib[0] = CTL_HW;
+    mib[1] = HW_NCPU;
+    rc = sysctl( mib, 2, &numCpus, &len, NULL, 0 );
+    if ( -1 == rc )  {
+        numCpus = -1; /* set to -1 for return value on error */
+        _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() );
+    }
+#elif defined(HPUX)
+    numCpus = mpctl( MPC_GETNUMSPUS, 0, 0 );
+    if ( numCpus < 1 )  {
+        numCpus = -1; /* set to -1 for return value on error */
+        _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() );
+    }
+#elif defined(IRIX)
+    numCpus = sysconf( _SC_NPROC_ONLN );
+#elif defined(RISCOS) || defined(SYMBIAN)
+    numCpus = 1;
+#elif defined(XP_UNIX)
+    numCpus = sysconf( _SC_NPROCESSORS_ONLN );
+#else
+#error "An implementation is required"
+#endif
+    return(numCpus);
+} /* end PR_GetNumberOfProcessors() */
+
+/*
+** PR_GetPhysicalMemorySize()
+** 
+** Implementation notes:
+**   Every platform does it a bit different.
+**     bytes is the returned value.
+**   for each platform's "if defined" section
+**     declare your local variable
+**     do your thing, assign to bytes.
+** 
+*/
+PR_IMPLEMENT(PRUint64) PR_GetPhysicalMemorySize(void)
+{
+    PRUint64 bytes = 0;
+
+#if defined(LINUX) || defined(SOLARIS)
+
+    long pageSize = sysconf(_SC_PAGESIZE);
+    long pageCount = sysconf(_SC_PHYS_PAGES);
+    bytes = (PRUint64) pageSize * pageCount;
+
+#elif defined(HPUX)
+
+    struct pst_static info;
+    int result = pstat_getstatic(&info, sizeof(info), 1, 0);
+    if (result == 1)
+        bytes = (PRUint64) info.physical_memory * info.page_size;
+
+#elif defined(DARWIN)
+
+    struct host_basic_info hInfo;
+    mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+
+    int result = host_info(mach_host_self(),
+                           HOST_BASIC_INFO,
+                           (host_info_t) &hInfo,
+                           &count);
+    if (result == KERN_SUCCESS)
+        bytes = hInfo.max_mem;
+
+#elif defined(WIN32)
+
+    /* Try to use the newer GlobalMemoryStatusEx API for Windows 2000+. */
+    GlobalMemoryStatusExFn globalMemory = (GlobalMemoryStatusExFn) NULL;
+    HMODULE module = GetModuleHandleW(L"kernel32.dll");
+
+    if (module) {
+        globalMemory = (GlobalMemoryStatusExFn)GetProcAddress(module, "GlobalMemoryStatusEx");
+
+        if (globalMemory) {
+            PR_MEMORYSTATUSEX memStat;
+            memStat.dwLength = sizeof(memStat);
+
+            if (globalMemory(&memStat))
+                bytes = memStat.ullTotalPhys;
+        }
+    }
+
+    if (!bytes) {
+        /* Fall back to the older API. */
+        MEMORYSTATUS memStat;
+        memset(&memStat, 0, sizeof(memStat));
+        GlobalMemoryStatus(&memStat);
+        bytes = memStat.dwTotalPhys;
+    }
+
+#elif defined(OS2)
+
+    ULONG ulPhysMem;
+    DosQuerySysInfo(QSV_TOTPHYSMEM,
+                    QSV_TOTPHYSMEM,
+                    &ulPhysMem,
+                    sizeof(ulPhysMem));
+    bytes = ulPhysMem;
+
+#elif defined(AIX)
+
+    if (odm_initialize() == 0) {
+        int how_many;
+        struct CuAt *obj = getattr("sys0", "realmem", 0, &how_many);
+        if (obj != NULL) {
+            bytes = (PRUint64) atoi(obj->value) * 1024;
+            free(obj);
+        }
+        odm_terminate();
+    }
+
+#else
+
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+
+#endif
+
+    return bytes;
+} /* end PR_GetPhysicalMemorySize() */
diff --git a/mozilla/nsprpub/pr/src/misc/prthinfo.c b/mozilla/nsprpub/pr/src/misc/prthinfo.c
new file mode 100644
index 0000000..6dcf9c6
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prthinfo.c
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "prlog.h"
+#include "prthread.h"
+#include "private/pprthred.h"
+#include "primpl.h"
+
+PR_IMPLEMENT(PRWord *)
+PR_GetGCRegisters(PRThread *t, int isCurrent, int *np)
+{
+    return _MD_HomeGCRegisters(t, isCurrent, np);
+}
+
+PR_IMPLEMENT(PRStatus)
+PR_ThreadScanStackPointers(PRThread* t,
+                           PRScanStackFun scanFun, void* scanClosure)
+{
+    PRThread* current = PR_GetCurrentThread();
+    PRWord *sp, *esp, *p0;
+    int n;
+    void **ptd;
+    PRStatus status;
+    PRUint32 index;
+    int stack_end;
+
+    /*
+    ** Store the thread's registers in the thread structure so the GC
+    ** can scan them. Then scan them.
+    */
+    p0 = _MD_HomeGCRegisters(t, t == current, &n);
+    status = scanFun(t, (void**)p0, n, scanClosure);
+    if (status != PR_SUCCESS)
+        return status;
+
+    /* Scan the C stack for pointers into the GC heap */
+#if defined(XP_PC) && defined(WIN16)
+    /*
+    ** Under WIN16, the stack of the current thread is always mapped into
+    ** the "task stack" (at SS:xxxx).  So, if t is the current thread, scan
+    ** the "task stack".  Otherwise, scan the "cached stack" of the inactive
+    ** thread...
+    */
+    if (t == current) {
+        sp  = (PRWord*) &stack_end;
+        esp = (PRWord*) _pr_top_of_task_stack;
+
+        PR_ASSERT(sp <= esp);
+    } else {
+        sp  = (PRWord*) PR_GetSP(t);
+        esp = (PRWord*) t->stack->stackTop;
+
+        PR_ASSERT((t->stack->stackSize == 0) ||
+                  ((sp >  (PRWord*)t->stack->stackBottom) &&
+                   (sp <= (PRWord*)t->stack->stackTop)));
+    }
+#else   /* ! WIN16 */
+#ifdef HAVE_STACK_GROWING_UP
+    if (t == current) {
+        esp = (PRWord*) &stack_end;
+    } else {
+        esp = (PRWord*) PR_GetSP(t);
+    }
+    sp = (PRWord*) t->stack->stackTop;
+    if (t->stack->stackSize) {
+        PR_ASSERT((esp > (PRWord*)t->stack->stackTop) &&
+                  (esp < (PRWord*)t->stack->stackBottom));
+    }
+#else   /* ! HAVE_STACK_GROWING_UP */
+    if (t == current) {
+        sp = (PRWord*) &stack_end;
+    } else {
+        sp = (PRWord*) PR_GetSP(t);
+    }
+    esp = (PRWord*) t->stack->stackTop;
+    if (t->stack->stackSize) {
+        PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) &&
+                  (sp < (PRWord*)t->stack->stackTop));
+    }
+#endif  /* ! HAVE_STACK_GROWING_UP */
+#endif  /* ! WIN16 */
+
+#if defined(WIN16)
+    {
+        prword_t scan;
+        prword_t limit;
+        
+        scan = (prword_t) sp;
+        limit = (prword_t) esp;
+        while (scan < limit) {
+            prword_t *test;
+
+            test = *((prword_t **)scan);
+            status = scanFun(t, (void**)&test, 1, scanClosure);
+            if (status != PR_SUCCESS)
+                return status;
+            scan += sizeof(char);
+        }
+    }
+#else
+    if (sp < esp) {
+        status = scanFun(t, (void**)sp, esp - sp, scanClosure);
+        if (status != PR_SUCCESS)
+            return status;
+    }
+#endif
+
+    /*
+    ** Mark all of the per-thread-data items attached to this thread
+    **
+    ** The execution environment better be accounted for otherwise it
+    ** will be collected
+    */
+    status = scanFun(t, (void**)&t->environment, 1, scanClosure);
+    if (status != PR_SUCCESS)
+        return status;
+
+#ifndef GC_LEAK_DETECTOR
+    /* if thread is not allocated on stack, this is redundant. */
+    ptd = t->privateData;
+    for (index = 0; index < t->tpdLength; index++, ptd++) {
+        status = scanFun(t, (void**)ptd, 1, scanClosure);
+        if (status != PR_SUCCESS)
+            return status;
+    }
+#endif
+    
+    return PR_SUCCESS;
+}
+
+/* transducer for PR_EnumerateThreads */
+typedef struct PRScanStackData {
+    PRScanStackFun      scanFun;
+    void*               scanClosure;
+} PRScanStackData;
+
+static PRStatus PR_CALLBACK
+pr_ScanStack(PRThread* t, int i, void* arg)
+{
+    PRScanStackData* data = (PRScanStackData*)arg;
+    return PR_ThreadScanStackPointers(t, data->scanFun, data->scanClosure);
+}
+
+PR_IMPLEMENT(PRStatus)
+PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure)
+{
+    PRScanStackData data;
+    data.scanFun = scanFun;
+    data.scanClosure = scanClosure;
+    return PR_EnumerateThreads(pr_ScanStack, &data);
+}
+
+PR_IMPLEMENT(PRUword)
+PR_GetStackSpaceLeft(PRThread* t)
+{
+    PRThread *current = PR_GetCurrentThread();
+    PRWord *sp, *esp;
+    int stack_end;
+
+#if defined(WIN16)
+    /*
+    ** Under WIN16, the stack of the current thread is always mapped into
+    ** the "task stack" (at SS:xxxx).  So, if t is the current thread, scan
+    ** the "task stack".  Otherwise, scan the "cached stack" of the inactive
+    ** thread...
+    */
+    if (t == current) {
+        sp  = (PRWord*) &stack_end;
+        esp = (PRWord*) _pr_top_of_task_stack;
+
+        PR_ASSERT(sp <= esp);
+    } else {
+        sp  = (PRWord*) PR_GetSP(t);
+        esp = (PRWord*) t->stack->stackTop;
+
+	PR_ASSERT((t->stack->stackSize == 0) ||
+                 ((sp >  (PRWord*)t->stack->stackBottom) &&
+		  (sp <= (PRWord*)t->stack->stackTop)));
+    }
+#else   /* ! WIN16 */
+#ifdef HAVE_STACK_GROWING_UP
+    if (t == current) {
+        esp = (PRWord*) &stack_end;
+    } else {
+        esp = (PRWord*) PR_GetSP(t);
+    }
+    sp = (PRWord*) t->stack->stackTop;
+    if (t->stack->stackSize) {
+        PR_ASSERT((esp > (PRWord*)t->stack->stackTop) &&
+                  (esp < (PRWord*)t->stack->stackBottom));
+    }
+#else   /* ! HAVE_STACK_GROWING_UP */
+    if (t == current) {
+        sp = (PRWord*) &stack_end;
+    } else {
+        sp = (PRWord*) PR_GetSP(t);
+    }
+    esp = (PRWord*) t->stack->stackTop;
+    if (t->stack->stackSize) {
+	PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) &&
+		  (sp < (PRWord*)t->stack->stackTop));
+    }
+#endif  /* ! HAVE_STACK_GROWING_UP */
+#endif  /* ! WIN16 */
+    return (PRUword)t->stack->stackSize - ((PRWord)esp - (PRWord)sp);
+}
diff --git a/mozilla/nsprpub/pr/src/misc/prtime.c b/mozilla/nsprpub/pr/src/misc/prtime.c
new file mode 100644
index 0000000..dee268c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prtime.c
@@ -0,0 +1,2042 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+ * prtime.c --
+ *
+ *     NSPR date and time functions
+ *
+ */
+
+#include "prinit.h"
+#include "prtime.h"
+#include "prlock.h"
+#include "prprf.h"
+#include "prlog.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>  /* for EINVAL */
+#include <time.h>
+
+/* 
+ * The COUNT_LEAPS macro counts the number of leap years passed by
+ * till the start of the given year Y.  At the start of the year 4
+ * A.D. the number of leap years passed by is 0, while at the start of
+ * the year 5 A.D. this count is 1. The number of years divisible by
+ * 100 but not divisible by 400 (the non-leap years) is deducted from
+ * the count to get the correct number of leap years.
+ *
+ * The COUNT_DAYS macro counts the number of days since 01/01/01 till the
+ * start of the given year Y. The number of days at the start of the year
+ * 1 is 0 while the number of days at the start of the year 2 is 365
+ * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01
+ * midnight 00:00:00.
+ */
+
+#define COUNT_LEAPS(Y)   ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 )
+#define COUNT_DAYS(Y)  ( ((Y)-1)*365 + COUNT_LEAPS(Y) )
+#define DAYS_BETWEEN_YEARS(A, B)  (COUNT_DAYS(B) - COUNT_DAYS(A))
+
+/*
+ * Static variables used by functions in this file
+ */
+
+/*
+ * The following array contains the day of year for the last day of
+ * each month, where index 1 is January, and day 0 is January 1.
+ */
+
+static const int lastDayOfMonth[2][13] = {
+    {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
+    {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}
+};
+
+/*
+ * The number of days in a month
+ */
+
+static const PRInt8 nDays[2][12] = {
+    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+};
+
+/*
+ * Declarations for internal functions defined later in this file.
+ */
+
+static void        ComputeGMT(PRTime time, PRExplodedTime *gmt);
+static int         IsLeapYear(PRInt16 year);
+static void        ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset);
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * ComputeGMT --
+ *
+ *     Caveats:
+ *     - we ignore leap seconds
+ *
+ *------------------------------------------------------------------------
+ */
+
+static void
+ComputeGMT(PRTime time, PRExplodedTime *gmt)
+{
+    PRInt32 tmp, rem;
+    PRInt32 numDays;
+    PRInt64 numDays64, rem64;
+    int isLeap;
+    PRInt64 sec;
+    PRInt64 usec;
+    PRInt64 usecPerSec;
+    PRInt64 secPerDay;
+
+    /*
+     * We first do the usec, sec, min, hour thing so that we do not
+     * have to do LL arithmetic.
+     */
+
+    LL_I2L(usecPerSec, 1000000L);
+    LL_DIV(sec, time, usecPerSec);
+    LL_MOD(usec, time, usecPerSec);
+    LL_L2I(gmt->tm_usec, usec);
+    /* Correct for weird mod semantics so the remainder is always positive */
+    if (gmt->tm_usec < 0) {
+        PRInt64 one;
+
+        LL_I2L(one, 1L);
+        LL_SUB(sec, sec, one);
+        gmt->tm_usec += 1000000L;
+    }
+
+    LL_I2L(secPerDay, 86400L);
+    LL_DIV(numDays64, sec, secPerDay);
+    LL_MOD(rem64, sec, secPerDay);
+    /* We are sure both of these numbers can fit into PRInt32 */
+    LL_L2I(numDays, numDays64);
+    LL_L2I(rem, rem64);
+    if (rem < 0) {
+        numDays--;
+        rem += 86400L;
+    }
+
+    /* Compute day of week.  Epoch started on a Thursday. */
+
+    gmt->tm_wday = (numDays + 4) % 7;
+    if (gmt->tm_wday < 0) {
+        gmt->tm_wday += 7;
+    }
+
+    /* Compute the time of day. */
+
+    gmt->tm_hour = rem / 3600;
+    rem %= 3600;
+    gmt->tm_min = rem / 60;
+    gmt->tm_sec = rem % 60;
+
+    /*
+     * Compute the year by finding the 400 year period, then working
+     * down from there.
+     *
+     * Since numDays is originally the number of days since January 1, 1970,
+     * we must change it to be the number of days from January 1, 0001.
+     */
+
+    numDays += 719162;       /* 719162 = days from year 1 up to 1970 */
+    tmp = numDays / 146097;  /* 146097 = days in 400 years */
+    rem = numDays % 146097;
+    gmt->tm_year = tmp * 400 + 1;
+
+    /* Compute the 100 year period. */
+
+    tmp = rem / 36524;    /* 36524 = days in 100 years */
+    rem %= 36524;
+    if (tmp == 4) {       /* the 400th year is a leap year */
+        tmp = 3;
+        rem = 36524;
+    }
+    gmt->tm_year += tmp * 100;
+
+    /* Compute the 4 year period. */
+
+    tmp = rem / 1461;     /* 1461 = days in 4 years */
+    rem %= 1461;
+    gmt->tm_year += tmp * 4;
+
+    /* Compute which year in the 4. */
+
+    tmp = rem / 365;
+    rem %= 365;
+    if (tmp == 4) {       /* the 4th year is a leap year */
+        tmp = 3;
+        rem = 365;
+    }
+
+    gmt->tm_year += tmp;
+    gmt->tm_yday = rem;
+    isLeap = IsLeapYear(gmt->tm_year);
+
+    /* Compute the month and day of month. */
+
+    for (tmp = 1; lastDayOfMonth[isLeap][tmp] < gmt->tm_yday; tmp++) {
+    }
+    gmt->tm_month = --tmp;
+    gmt->tm_mday = gmt->tm_yday - lastDayOfMonth[isLeap][tmp];
+
+    gmt->tm_params.tp_gmt_offset = 0;
+    gmt->tm_params.tp_dst_offset = 0;
+}
+
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_ExplodeTime --
+ *
+ *     Cf. struct tm *gmtime(const time_t *tp) and
+ *         struct tm *localtime(const time_t *tp)
+ *
+ *------------------------------------------------------------------------
+ */
+
+PR_IMPLEMENT(void)
+PR_ExplodeTime(
+        PRTime usecs,
+        PRTimeParamFn params,
+        PRExplodedTime *exploded)
+{
+    ComputeGMT(usecs, exploded);
+    exploded->tm_params = params(exploded);
+    ApplySecOffset(exploded, exploded->tm_params.tp_gmt_offset
+            + exploded->tm_params.tp_dst_offset);
+}
+
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_ImplodeTime --
+ *
+ *     Cf. time_t mktime(struct tm *tp)
+ *     Note that 1 year has < 2^25 seconds.  So an PRInt32 is large enough.
+ *
+ *------------------------------------------------------------------------
+ */
+PR_IMPLEMENT(PRTime)
+PR_ImplodeTime(const PRExplodedTime *exploded)
+{
+    PRExplodedTime copy;
+    PRTime retVal;
+    PRInt64 secPerDay, usecPerSec;
+    PRInt64 temp;
+    PRInt64 numSecs64;
+    PRInt32 numDays;
+    PRInt32 numSecs;
+
+    /* Normalize first.  Do this on our copy */
+    copy = *exploded;
+    PR_NormalizeTime(&copy, PR_GMTParameters);
+
+    numDays = DAYS_BETWEEN_YEARS(1970, copy.tm_year);
+    
+    numSecs = copy.tm_yday * 86400 + copy.tm_hour * 3600
+            + copy.tm_min * 60 + copy.tm_sec;
+
+    LL_I2L(temp, numDays);
+    LL_I2L(secPerDay, 86400);
+    LL_MUL(temp, temp, secPerDay);
+    LL_I2L(numSecs64, numSecs);
+    LL_ADD(numSecs64, numSecs64, temp);
+
+    /* apply the GMT and DST offsets */
+    LL_I2L(temp,  copy.tm_params.tp_gmt_offset);
+    LL_SUB(numSecs64, numSecs64, temp);
+    LL_I2L(temp,  copy.tm_params.tp_dst_offset);
+    LL_SUB(numSecs64, numSecs64, temp);
+
+    LL_I2L(usecPerSec, 1000000L);
+    LL_MUL(temp, numSecs64, usecPerSec);
+    LL_I2L(retVal, copy.tm_usec);
+    LL_ADD(retVal, retVal, temp);
+
+    return retVal;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * IsLeapYear --
+ *
+ *     Returns 1 if the year is a leap year, 0 otherwise.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int IsLeapYear(PRInt16 year)
+{
+    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ * 'secOffset' should be less than 86400 (i.e., a day).
+ * 'time' should point to a normalized PRExplodedTime.
+ */
+
+static void
+ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset)
+{
+    time->tm_sec += secOffset;
+
+    /* Note that in this implementation we do not count leap seconds */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0) {
+        /* Decrement mday, yday, and wday */
+        time->tm_hour += 24;
+        time->tm_mday--;
+        time->tm_yday--;
+        if (time->tm_mday < 1) {
+            time->tm_month--;
+            if (time->tm_month < 0) {
+                time->tm_month = 11;
+                time->tm_year--;
+                if (IsLeapYear(time->tm_year))
+                    time->tm_yday = 365;
+                else
+                    time->tm_yday = 364;
+            }
+            time->tm_mday = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        }
+        time->tm_wday--;
+        if (time->tm_wday < 0)
+            time->tm_wday = 6;
+    } else if (time->tm_hour > 23) {
+        /* Increment mday, yday, and wday */
+        time->tm_hour -= 24;
+        time->tm_mday++;
+        time->tm_yday++;
+        if (time->tm_mday >
+                nDays[IsLeapYear(time->tm_year)][time->tm_month]) {
+            time->tm_mday = 1;
+            time->tm_month++;
+            if (time->tm_month > 11) {
+                time->tm_month = 0;
+                time->tm_year++;
+                time->tm_yday = 0;
+            }
+        }
+        time->tm_wday++;
+        if (time->tm_wday > 6)
+            time->tm_wday = 0;
+    }
+}
+
+PR_IMPLEMENT(void)
+PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params)
+{
+    int daysInMonth;
+    PRInt32 numDays;
+
+    /* Get back to GMT */
+    time->tm_sec -= time->tm_params.tp_gmt_offset
+            + time->tm_params.tp_dst_offset;
+    time->tm_params.tp_gmt_offset = 0;
+    time->tm_params.tp_dst_offset = 0;
+
+    /* Now normalize GMT */
+
+    if (time->tm_usec < 0 || time->tm_usec >= 1000000) {
+        time->tm_sec +=  time->tm_usec / 1000000;
+        time->tm_usec %= 1000000;
+        if (time->tm_usec < 0) {
+            time->tm_usec += 1000000;
+            time->tm_sec--;
+        }
+    }
+
+    /* Note that we do not count leap seconds in this implementation */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0 || time->tm_hour >= 24) {
+        time->tm_mday += time->tm_hour / 24;
+        time->tm_hour %= 24;
+        if (time->tm_hour < 0) {
+            time->tm_hour += 24;
+            time->tm_mday--;
+        }
+    }
+
+    /* Normalize month and year before mday */
+    if (time->tm_month < 0 || time->tm_month >= 12) {
+        time->tm_year += time->tm_month / 12;
+        time->tm_month %= 12;
+        if (time->tm_month < 0) {
+            time->tm_month += 12;
+            time->tm_year--;
+        }
+    }
+
+    /* Now that month and year are in proper range, normalize mday */
+
+    if (time->tm_mday < 1) {
+        /* mday too small */
+        do {
+            /* the previous month */
+            time->tm_month--;
+            if (time->tm_month < 0) {
+                time->tm_month = 11;
+                time->tm_year--;
+            }
+            time->tm_mday += nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        } while (time->tm_mday < 1);
+    } else {
+        daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        while (time->tm_mday > daysInMonth) {
+            /* mday too large */
+            time->tm_mday -= daysInMonth;
+            time->tm_month++;
+            if (time->tm_month > 11) {
+                time->tm_month = 0;
+                time->tm_year++;
+            }
+            daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        }
+    }
+
+    /* Recompute yday and wday */
+    time->tm_yday = time->tm_mday +
+            lastDayOfMonth[IsLeapYear(time->tm_year)][time->tm_month];
+	    
+    numDays = DAYS_BETWEEN_YEARS(1970, time->tm_year) + time->tm_yday;
+    time->tm_wday = (numDays + 4) % 7;
+    if (time->tm_wday < 0) {
+        time->tm_wday += 7;
+    }
+
+    /* Recompute time parameters */
+
+    time->tm_params = params(time);
+
+    ApplySecOffset(time, time->tm_params.tp_gmt_offset
+            + time->tm_params.tp_dst_offset);
+}
+
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * PR_LocalTimeParameters --
+ * 
+ *     returns the time parameters for the local time zone
+ *
+ *     The following uses localtime() from the standard C library.
+ *     (time.h)  This is our fallback implementation.  Unix, PC, and BeOS
+ *     use this version.  A platform may have its own machine-dependent
+ *     implementation of this function.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if defined(HAVE_INT_LOCALTIME_R)
+
+/*
+ * In this case we could define the macro as
+ *     #define MT_safe_localtime(timer, result) \
+ *             (localtime_r(timer, result) == 0 ? result : NULL)
+ * I chose to compare the return value of localtime_r with -1 so 
+ * that I can catch the cases where localtime_r returns a pointer
+ * to struct tm.  The macro definition above would not be able to
+ * detect such mistakes because it is legal to compare a pointer
+ * with 0.
+ */
+
+#define MT_safe_localtime(timer, result) \
+        (localtime_r(timer, result) == -1 ? NULL: result)
+
+#elif defined(HAVE_POINTER_LOCALTIME_R)
+
+#define MT_safe_localtime localtime_r
+
+#else
+
+#define HAVE_LOCALTIME_MONITOR 1  /* We use 'monitor' to serialize our calls
+                                   * to localtime(). */
+static PRLock *monitor = NULL;
+
+static struct tm *MT_safe_localtime(const time_t *clock, struct tm *result)
+{
+    struct tm *tmPtr;
+    int needLock = PR_Initialized();  /* We need to use a lock to protect
+                                       * against NSPR threads only when the
+                                       * NSPR thread system is activated. */
+
+    if (needLock) PR_Lock(monitor);
+
+    /*
+     * Microsoft (all flavors) localtime() returns a NULL pointer if 'clock'
+     * represents a time before midnight January 1, 1970.  In
+     * that case, we also return a NULL pointer and the struct tm
+     * object pointed to by 'result' is not modified.
+     *
+     * Watcom C/C++ 11.0 localtime() treats time_t as unsigned long
+     * hence, does not recognize negative values of clock as pre-1/1/70.
+     * We have to manually check (WIN16 only) for negative value of
+     * clock and return NULL.
+     *
+     * With negative values of clock, OS/2 returns the struct tm for
+     * clock plus ULONG_MAX. So we also have to check for the invalid
+     * structs returned for timezones west of Greenwich when clock == 0.
+     */
+    
+    tmPtr = localtime(clock);
+
+#if defined(WIN16) || defined(XP_OS2)
+    if ( (PRInt32) *clock < 0 ||
+         ( (PRInt32) *clock == 0 && tmPtr->tm_year != 70))
+        result = NULL;
+    else
+        *result = *tmPtr;
+#else
+    if (tmPtr) {
+        *result = *tmPtr;
+    } else {
+        result = NULL;
+    }
+#endif /* WIN16 */
+
+    if (needLock) PR_Unlock(monitor);
+
+    return result;
+}
+
+#endif  /* definition of MT_safe_localtime() */
+
+void _PR_InitTime(void)
+{
+#ifdef HAVE_LOCALTIME_MONITOR
+    monitor = PR_NewLock();
+#endif
+#ifdef WINCE
+    _MD_InitTime();
+#endif
+}
+
+void _PR_CleanupTime(void)
+{
+#ifdef HAVE_LOCALTIME_MONITOR
+    if (monitor) {
+        PR_DestroyLock(monitor);
+        monitor = NULL;
+    }
+#endif
+#ifdef WINCE
+    _MD_CleanupTime();
+#endif
+}
+
+#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
+
+PR_IMPLEMENT(PRTimeParameters)
+PR_LocalTimeParameters(const PRExplodedTime *gmt)
+{
+
+    PRTimeParameters retVal;
+    struct tm localTime;
+    time_t secs;
+    PRTime secs64;
+    PRInt64 usecPerSec;
+    PRInt64 usecPerSec_1;
+    PRInt64 maxInt32;
+    PRInt64 minInt32;
+    PRInt32 dayOffset;
+    PRInt32 offset2Jan1970;
+    PRInt32 offsetNew;
+    int isdst2Jan1970;
+
+    /*
+     * Calculate the GMT offset.  First, figure out what is
+     * 00:00:00 Jan. 2, 1970 GMT (which is exactly a day, or 86400
+     * seconds, since the epoch) in local time.  Then we calculate
+     * the difference between local time and GMT in seconds:
+     *     gmt_offset = local_time - GMT
+     *
+     * Caveat: the validity of this calculation depends on two
+     * assumptions:
+     * 1. Daylight saving time was not in effect on Jan. 2, 1970.
+     * 2. The time zone of the geographic location has not changed
+     *    since Jan. 2, 1970.
+     */
+
+    secs = 86400L;
+    (void) MT_safe_localtime(&secs, &localTime);
+
+    /* GMT is 00:00:00, 2nd of Jan. */
+
+    offset2Jan1970 = (PRInt32)localTime.tm_sec 
+            + 60L * (PRInt32)localTime.tm_min
+            + 3600L * (PRInt32)localTime.tm_hour
+            + 86400L * (PRInt32)((PRInt32)localTime.tm_mday - 2L);
+
+    isdst2Jan1970 = localTime.tm_isdst;
+
+    /*
+     * Now compute DST offset.  We calculate the overall offset
+     * of local time from GMT, similar to above.  The overall
+     * offset has two components: gmt offset and dst offset.
+     * We subtract gmt offset from the overall offset to get
+     * the dst offset.
+     *     overall_offset = local_time - GMT
+     *     overall_offset = gmt_offset + dst_offset
+     * ==> dst_offset = local_time - GMT - gmt_offset
+     */
+
+    secs64 = PR_ImplodeTime(gmt);    /* This is still in microseconds */
+    LL_I2L(usecPerSec, PR_USEC_PER_SEC);
+    LL_I2L(usecPerSec_1, PR_USEC_PER_SEC - 1);
+    /* Convert to seconds, truncating down (3.1 -> 3 and -3.1 -> -4) */
+    if (LL_GE_ZERO(secs64)) {
+        LL_DIV(secs64, secs64, usecPerSec);
+    } else {
+        LL_NEG(secs64, secs64);
+        LL_ADD(secs64, secs64, usecPerSec_1);
+        LL_DIV(secs64, secs64, usecPerSec);
+        LL_NEG(secs64, secs64);
+    }
+    LL_I2L(maxInt32, PR_INT32_MAX);
+    LL_I2L(minInt32, PR_INT32_MIN);
+    if (LL_CMP(secs64, >, maxInt32) || LL_CMP(secs64, <, minInt32)) {
+        /* secs64 is too large or too small for time_t (32-bit integer) */
+        retVal.tp_gmt_offset = offset2Jan1970;
+        retVal.tp_dst_offset = 0;
+        return retVal;
+    }
+    LL_L2I(secs, secs64);
+
+    /*
+     * On Windows, localtime() (and our MT_safe_localtime() too)
+     * returns a NULL pointer for time before midnight January 1,
+     * 1970 GMT.  In that case, we just use the GMT offset for
+     * Jan 2, 1970 and assume that DST was not in effect.
+     */
+
+    if (MT_safe_localtime(&secs, &localTime) == NULL) {
+        retVal.tp_gmt_offset = offset2Jan1970;
+        retVal.tp_dst_offset = 0;
+        return retVal;
+    }
+
+    /*
+     * dayOffset is the offset between local time and GMT in 
+     * the day component, which can only be -1, 0, or 1.  We
+     * use the day of the week to compute dayOffset.
+     */
+
+    dayOffset = (PRInt32) localTime.tm_wday - gmt->tm_wday;
+
+    /*
+     * Need to adjust for wrapping around of day of the week from
+     * 6 back to 0.
+     */
+
+    if (dayOffset == -6) {
+        /* Local time is Sunday (0) and GMT is Saturday (6) */
+        dayOffset = 1;
+    } else if (dayOffset == 6) {
+        /* Local time is Saturday (6) and GMT is Sunday (0) */
+        dayOffset = -1;
+    }
+
+    offsetNew = (PRInt32)localTime.tm_sec - gmt->tm_sec
+            + 60L * ((PRInt32)localTime.tm_min - gmt->tm_min)
+            + 3600L * ((PRInt32)localTime.tm_hour - gmt->tm_hour)
+            + 86400L * (PRInt32)dayOffset;
+
+    if (localTime.tm_isdst <= 0) {
+        /* DST is not in effect */
+        retVal.tp_gmt_offset = offsetNew;
+        retVal.tp_dst_offset = 0;
+    } else {
+        /* DST is in effect */
+        if (isdst2Jan1970 <=0) {
+            /*
+             * DST was not in effect back in 2 Jan. 1970.
+             * Use the offset back then as the GMT offset,
+             * assuming the time zone has not changed since then.
+             */
+            retVal.tp_gmt_offset = offset2Jan1970;
+            retVal.tp_dst_offset = offsetNew - offset2Jan1970;
+        } else {
+            /*
+             * DST was also in effect back in 2 Jan. 1970.
+             * Then our clever trick (or rather, ugly hack) fails.
+             * We will just assume DST offset is an hour.
+             */
+            retVal.tp_gmt_offset = offsetNew - 3600;
+            retVal.tp_dst_offset = 3600;
+        }
+    }
+    
+    return retVal;
+}
+
+#endif    /* defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) */
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_USPacificTimeParameters --
+ *
+ *     The time parameters function for the US Pacific Time Zone.
+ *
+ *------------------------------------------------------------------------
+ */
+
+/*
+ * Returns the mday of the first sunday of the month, where
+ * mday and wday are for a given day in the month.
+ * mdays start with 1 (e.g. 1..31).  
+ * wdays start with 0 and are in the range 0..6.  0 = Sunday.
+ */
+#define firstSunday(mday, wday) (((mday - wday + 7 - 1) % 7) + 1)
+
+/*
+ * Returns the mday for the N'th Sunday of the month, where 
+ * mday and wday are for a given day in the month.
+ * mdays start with 1 (e.g. 1..31).  
+ * wdays start with 0 and are in the range 0..6.  0 = Sunday.
+ * N has the following values: 0 = first, 1 = second (etc), -1 = last.
+ * ndays is the number of days in that month, the same value as the 
+ * mday of the last day of the month.
+ */
+static PRInt32 
+NthSunday(PRInt32 mday, PRInt32 wday, PRInt32 N, PRInt32 ndays) 
+{
+    PRInt32 firstSun = firstSunday(mday, wday);
+
+    if (N < 0) 
+        N = (ndays - firstSun) / 7;
+    return firstSun + (7 * N);
+}
+
+typedef struct DSTParams {
+    PRInt8 dst_start_month;       /* 0 = January */
+    PRInt8 dst_start_Nth_Sunday;  /* N as defined above */
+    PRInt8 dst_start_month_ndays; /* ndays as defined above */
+    PRInt8 dst_end_month;         /* 0 = January */
+    PRInt8 dst_end_Nth_Sunday;    /* N as defined above */
+    PRInt8 dst_end_month_ndays;   /* ndays as defined above */
+} DSTParams;
+
+static const DSTParams dstParams[2] = {
+    /* year < 2007:  First April Sunday - Last October Sunday */
+    { 3, 0, 30, 9, -1, 31 },
+    /* year >= 2007: Second March Sunday - First November Sunday */
+    { 2, 1, 31, 10, 0, 30 }
+};
+
+PR_IMPLEMENT(PRTimeParameters)
+PR_USPacificTimeParameters(const PRExplodedTime *gmt)
+{
+    const DSTParams *dst;
+    PRTimeParameters retVal;
+    PRExplodedTime st;
+
+    /*
+     * Based on geographic location and GMT, figure out offset of
+     * standard time from GMT.  In this example implementation, we
+     * assume the local time zone is US Pacific Time.
+     */
+
+    retVal.tp_gmt_offset = -8L * 3600L;
+
+    /*
+     * Make a copy of GMT.  Note that the tm_params field of this copy
+     * is ignored.
+     */
+
+    st.tm_usec = gmt->tm_usec;
+    st.tm_sec = gmt->tm_sec;
+    st.tm_min = gmt->tm_min;
+    st.tm_hour = gmt->tm_hour;
+    st.tm_mday = gmt->tm_mday;
+    st.tm_month = gmt->tm_month;
+    st.tm_year = gmt->tm_year;
+    st.tm_wday = gmt->tm_wday;
+    st.tm_yday = gmt->tm_yday;
+
+    /* Apply the offset to GMT to obtain the local standard time */
+    ApplySecOffset(&st, retVal.tp_gmt_offset);
+
+    if (st.tm_year < 2007) { /* first April Sunday - Last October Sunday */
+	dst = &dstParams[0];
+    } else {                 /* Second March Sunday - First November Sunday */
+	dst = &dstParams[1];
+    }
+
+    /*
+     * Apply the rules on standard time or GMT to obtain daylight saving
+     * time offset.  In this implementation, we use the US DST rule.
+     */
+    if (st.tm_month < dst->dst_start_month) {
+        retVal.tp_dst_offset = 0L;
+    } else if (st.tm_month == dst->dst_start_month) {
+	int NthSun = NthSunday(st.tm_mday, st.tm_wday, 
+			       dst->dst_start_Nth_Sunday, 
+			       dst->dst_start_month_ndays);
+	if (st.tm_mday < NthSun) {              /* Before starting Sunday */
+	    retVal.tp_dst_offset = 0L;
+        } else if (st.tm_mday == NthSun) {      /* Starting Sunday */
+	    /* 01:59:59 PST -> 03:00:00 PDT */
+	    if (st.tm_hour < 2) {
+		retVal.tp_dst_offset = 0L;
+	    } else {
+		retVal.tp_dst_offset = 3600L;
+	    }
+	} else {                                /* After starting Sunday */
+	    retVal.tp_dst_offset = 3600L;
+        }
+    } else if (st.tm_month < dst->dst_end_month) {
+        retVal.tp_dst_offset = 3600L;
+    } else if (st.tm_month == dst->dst_end_month) {
+	int NthSun = NthSunday(st.tm_mday, st.tm_wday, 
+			       dst->dst_end_Nth_Sunday, 
+			       dst->dst_end_month_ndays);
+	if (st.tm_mday < NthSun) {              /* Before ending Sunday */
+	    retVal.tp_dst_offset = 3600L;
+        } else if (st.tm_mday == NthSun) {      /* Ending Sunday */
+	    /* 01:59:59 PDT -> 01:00:00 PST */
+	    if (st.tm_hour < 1) {
+		retVal.tp_dst_offset = 3600L;
+	    } else {
+		retVal.tp_dst_offset = 0L;
+	    }
+	} else {                                /* After ending Sunday */
+	    retVal.tp_dst_offset = 0L;
+        }
+    } else {
+        retVal.tp_dst_offset = 0L;
+    }
+    return retVal;
+}
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_GMTParameters --
+ *
+ *     Returns the PRTimeParameters for Greenwich Mean Time.
+ *     Trivially, both the tp_gmt_offset and tp_dst_offset fields are 0.
+ *
+ *------------------------------------------------------------------------
+ */
+
+PR_IMPLEMENT(PRTimeParameters)
+PR_GMTParameters(const PRExplodedTime *gmt)
+{
+    PRTimeParameters retVal = { 0, 0 };
+    return retVal;
+}
+
+/*
+ * The following code implements PR_ParseTimeString().  It is based on
+ * ns/lib/xp/xp_time.c, revision 1.25, by Jamie Zawinski <jwz@netscape.com>.
+ */
+
+/*
+ * We only recognize the abbreviations of a small subset of time zones
+ * in North America, Europe, and Japan.
+ *
+ * PST/PDT: Pacific Standard/Daylight Time
+ * MST/MDT: Mountain Standard/Daylight Time
+ * CST/CDT: Central Standard/Daylight Time
+ * EST/EDT: Eastern Standard/Daylight Time
+ * AST: Atlantic Standard Time
+ * NST: Newfoundland Standard Time
+ * GMT: Greenwich Mean Time
+ * BST: British Summer Time
+ * MET: Middle Europe Time
+ * EET: Eastern Europe Time
+ * JST: Japan Standard Time
+ */
+
+typedef enum
+{
+  TT_UNKNOWN,
+
+  TT_SUN, TT_MON, TT_TUE, TT_WED, TT_THU, TT_FRI, TT_SAT,
+
+  TT_JAN, TT_FEB, TT_MAR, TT_APR, TT_MAY, TT_JUN,
+  TT_JUL, TT_AUG, TT_SEP, TT_OCT, TT_NOV, TT_DEC,
+
+  TT_PST, TT_PDT, TT_MST, TT_MDT, TT_CST, TT_CDT, TT_EST, TT_EDT,
+  TT_AST, TT_NST, TT_GMT, TT_BST, TT_MET, TT_EET, TT_JST
+} TIME_TOKEN;
+
+/*
+ * This parses a time/date string into a PRTime
+ * (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ *
+ * Many formats are handled, including:
+ *
+ *   14 Apr 89 03:20:12
+ *   14 Apr 89 03:20 GMT
+ *   Fri, 17 Mar 89 4:01:33
+ *   Fri, 17 Mar 89 4:01 GMT
+ *   Mon Jan 16 16:12 PDT 1989
+ *   Mon Jan 16 16:12 +0130 1989
+ *   6 May 1992 16:41-JST (Wednesday)
+ *   22-AUG-1993 10:59:12.82
+ *   22-AUG-1993 10:59pm
+ *   22-AUG-1993 12:59am
+ *   22-AUG-1993 12:59 PM
+ *   Friday, August 04, 1995 3:54 PM
+ *   06/21/95 04:24:34 PM
+ *   20/06/95 21:07
+ *   95-06-08 19:32:48 EDT
+ *
+ * If the input string doesn't contain a description of the timezone,
+ * we consult the `default_to_gmt' to decide whether the string should
+ * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
+ * The correct value for this argument depends on what standard specified
+ * the time string which you are parsing.
+ */
+
+PR_IMPLEMENT(PRStatus)
+PR_ParseTimeStringToExplodedTime(
+        const char *string,
+        PRBool default_to_gmt,
+        PRExplodedTime *result)
+{
+  TIME_TOKEN dotw = TT_UNKNOWN;
+  TIME_TOKEN month = TT_UNKNOWN;
+  TIME_TOKEN zone = TT_UNKNOWN;
+  int zone_offset = -1;
+  int dst_offset = 0;
+  int date = -1;
+  PRInt32 year = -1;
+  int hour = -1;
+  int min = -1;
+  int sec = -1;
+
+  const char *rest = string;
+
+  int iterations = 0;
+
+  PR_ASSERT(string && result);
+  if (!string || !result) return PR_FAILURE;
+
+  while (*rest)
+        {
+
+          if (iterations++ > 1000)
+                {
+                  return PR_FAILURE;
+                }
+
+          switch (*rest)
+                {
+                case 'a': case 'A':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'p' || rest[1] == 'P') &&
+                          (rest[2] == 'r' || rest[2] == 'R'))
+                        month = TT_APR;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_AST;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'g' || rest[2] == 'G'))
+                        month = TT_AUG;
+                  break;
+                case 'b': case 'B':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 's' || rest[1] == 'S') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_BST;
+                  break;
+                case 'c': case 'C':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_CDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_CST;
+                  break;
+                case 'd': case 'D':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'c' || rest[2] == 'C'))
+                        month = TT_DEC;
+                  break;
+                case 'e': case 'E':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EET;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EST;
+                  break;
+                case 'f': case 'F':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'b' || rest[2] == 'B'))
+                        month = TT_FEB;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'r' || rest[1] == 'R') &&
+                                   (rest[2] == 'i' || rest[2] == 'I'))
+                        dotw = TT_FRI;
+                  break;
+                case 'g': case 'G':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'm' || rest[1] == 'M') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_GMT;
+                  break;
+                case 'j': case 'J':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 'n' || rest[2] == 'N'))
+                        month = TT_JAN;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_JST;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'l' || rest[2] == 'L'))
+                        month = TT_JUL;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        month = TT_JUN;
+                  break;
+                case 'm': case 'M':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 'r' || rest[2] == 'R'))
+                        month = TT_MAR;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'a' || rest[1] == 'A') &&
+                                   (rest[2] == 'y' || rest[2] == 'Y'))
+                        month = TT_MAY;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'd' || rest[1] == 'D') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MET;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'o' || rest[1] == 'O') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        dotw = TT_MON;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MST;
+                  break;
+                case 'n': case 'N':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'o' || rest[1] == 'O') &&
+                          (rest[2] == 'v' || rest[2] == 'V'))
+                        month = TT_NOV;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_NST;
+                  break;
+                case 'o': case 'O':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'c' || rest[1] == 'C') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        month = TT_OCT;
+                  break;
+                case 'p': case 'P':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_PDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_PST;
+                  break;
+                case 's': case 'S':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        dotw = TT_SAT;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 'p' || rest[2] == 'P'))
+                        month = TT_SEP;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        dotw = TT_SUN;
+                  break;
+                case 't': case 'T':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'h' || rest[1] == 'H') &&
+                          (rest[2] == 'u' || rest[2] == 'U'))
+                        dotw = TT_THU;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'e' || rest[2] == 'E'))
+                        dotw = TT_TUE;
+                  break;
+                case 'u': case 'U':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 't' || rest[1] == 'T') &&
+                          !(rest[2] >= 'A' && rest[2] <= 'Z') &&
+                          !(rest[2] >= 'a' && rest[2] <= 'z'))
+                        /* UT is the same as GMT but UTx is not. */
+                        zone = TT_GMT;
+                  break;
+                case 'w': case 'W':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'd' || rest[2] == 'D'))
+                        dotw = TT_WED;
+                  break;
+
+                case '+': case '-':
+                  {
+                        const char *end;
+                        int sign;
+                        if (zone_offset != -1)
+                          {
+                                /* already got one... */
+                                rest++;
+                                break;
+                          }
+                        if (zone != TT_UNKNOWN && zone != TT_GMT)
+                          {
+                                /* GMT+0300 is legal, but PST+0300 is not. */
+                                rest++;
+                                break;
+                          }
+
+                        sign = ((*rest == '+') ? 1 : -1);
+                        rest++; /* move over sign */
+                        end = rest;
+                        while (*end >= '0' && *end <= '9')
+                          end++;
+                        if (rest == end) /* no digits here */
+                          break;
+
+                        if ((end - rest) == 4)
+                          /* offset in HHMM */
+                          zone_offset = (((((rest[0]-'0')*10) + (rest[1]-'0')) * 60) +
+                                                         (((rest[2]-'0')*10) + (rest[3]-'0')));
+                        else if ((end - rest) == 2)
+                          /* offset in hours */
+                          zone_offset = (((rest[0]-'0')*10) + (rest[1]-'0')) * 60;
+                        else if ((end - rest) == 1)
+                          /* offset in hours */
+                          zone_offset = (rest[0]-'0') * 60;
+                        else
+                          /* 3 or >4 */
+                          break;
+
+                        zone_offset *= sign;
+                        zone = TT_GMT;
+                        break;
+                  }
+
+                case '0': case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                  {
+                        int tmp_hour = -1;
+                        int tmp_min = -1;
+                        int tmp_sec = -1;
+                        const char *end = rest + 1;
+                        while (*end >= '0' && *end <= '9')
+                          end++;
+
+                        /* end is now the first character after a range of digits. */
+
+                        if (*end == ':')
+                          {
+                                if (hour >= 0 && min >= 0) /* already got it */
+                                  break;
+
+                                /* We have seen "[0-9]+:", so this is probably HH:MM[:SS] */
+                                if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_hour = ((rest[0]-'0')*10 +
+                                                          (rest[1]-'0'));
+                                else
+                                  tmp_hour = (rest[0]-'0');
+
+                                /* move over the colon, and parse minutes */
+
+                                rest = ++end;
+                                while (*end >= '0' && *end <= '9')
+                                  end++;
+
+                                if (end == rest)
+                                  /* no digits after first colon? */
+                                  break;
+                                else if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_min = ((rest[0]-'0')*10 +
+                                                         (rest[1]-'0'));
+                                else
+                                  tmp_min = (rest[0]-'0');
+
+                                /* now go for seconds */
+                                rest = end;
+                                if (*rest == ':')
+                                  rest++;
+                                end = rest;
+                                while (*end >= '0' && *end <= '9')
+                                  end++;
+
+                                if (end == rest)
+                                  /* no digits after second colon - that's ok. */
+                                  ;
+                                else if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_sec = ((rest[0]-'0')*10 +
+                                                         (rest[1]-'0'));
+                                else
+                                  tmp_sec = (rest[0]-'0');
+
+                                /* If we made it here, we've parsed hour and min,
+                                   and possibly sec, so it worked as a unit. */
+
+                                /* skip over whitespace and see if there's an AM or PM
+                                   directly following the time.
+                                 */
+                                if (tmp_hour <= 12)
+                                  {
+                                        const char *s = end;
+                                        while (*s && (*s == ' ' || *s == '\t'))
+                                          s++;
+                                        if ((s[0] == 'p' || s[0] == 'P') &&
+                                                (s[1] == 'm' || s[1] == 'M'))
+                                          /* 10:05pm == 22:05, and 12:05pm == 12:05 */
+                                          tmp_hour = (tmp_hour == 12 ? 12 : tmp_hour + 12);
+                                        else if (tmp_hour == 12 &&
+                                                         (s[0] == 'a' || s[0] == 'A') &&
+                                                         (s[1] == 'm' || s[1] == 'M'))
+                                          /* 12:05am == 00:05 */
+                                          tmp_hour = 0;
+                                  }
+
+                                hour = tmp_hour;
+                                min = tmp_min;
+                                sec = tmp_sec;
+                                rest = end;
+                                break;
+                          }
+                        else if ((*end == '/' || *end == '-') &&
+                                         end[1] >= '0' && end[1] <= '9')
+                          {
+                                /* Perhaps this is 6/16/95, 16/6/95, 6-16-95, or 16-6-95
+                                   or even 95-06-05...
+                                   #### But it doesn't handle 1995-06-22.
+                                 */
+                                int n1, n2, n3;
+                                const char *s;
+
+                                if (month != TT_UNKNOWN)
+                                  /* if we saw a month name, this can't be. */
+                                  break;
+
+                                s = rest;
+
+                                n1 = (*s++ - '0');                                /* first 1 or 2 digits */
+                                if (*s >= '0' && *s <= '9')
+                                  n1 = n1*10 + (*s++ - '0');
+
+                                if (*s != '/' && *s != '-')                /* slash */
+                                  break;
+                                s++;
+
+                                if (*s < '0' || *s > '9')                /* second 1 or 2 digits */
+                                  break;
+                                n2 = (*s++ - '0');
+                                if (*s >= '0' && *s <= '9')
+                                  n2 = n2*10 + (*s++ - '0');
+
+                                if (*s != '/' && *s != '-')                /* slash */
+                                  break;
+                                s++;
+
+                                if (*s < '0' || *s > '9')                /* third 1, 2, 4, or 5 digits */
+                                  break;
+                                n3 = (*s++ - '0');
+                                if (*s >= '0' && *s <= '9')
+                                  n3 = n3*10 + (*s++ - '0');
+
+                                if (*s >= '0' && *s <= '9')            /* optional digits 3, 4, and 5 */
+                                  {
+                                        n3 = n3*10 + (*s++ - '0');
+                                        if (*s < '0' || *s > '9')
+                                          break;
+                                        n3 = n3*10 + (*s++ - '0');
+                                        if (*s >= '0' && *s <= '9')
+                                          n3 = n3*10 + (*s++ - '0');
+                                  }
+
+                                if ((*s >= '0' && *s <= '9') ||        /* followed by non-alphanum */
+                                        (*s >= 'A' && *s <= 'Z') ||
+                                        (*s >= 'a' && *s <= 'z'))
+                                  break;
+
+                                /* Ok, we parsed three 1-2 digit numbers, with / or -
+                                   between them.  Now decide what the hell they are
+                                   (DD/MM/YY or MM/DD/YY or YY/MM/DD.)
+                                 */
+
+                                if (n1 > 31 || n1 == 0)  /* must be YY/MM/DD */
+                                  {
+                                        if (n2 > 12) break;
+                                        if (n3 > 31) break;
+                                        year = n1;
+                                        if (year < 70)
+                                            year += 2000;
+                                        else if (year < 100)
+                                            year += 1900;
+                                        month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
+                                        date = n3;
+                                        rest = s;
+                                        break;
+                                  }
+
+                                if (n1 > 12 && n2 > 12)  /* illegal */
+                                  {
+                                        rest = s;
+                                        break;
+                                  }
+
+                                if (n3 < 70)
+                                    n3 += 2000;
+                                else if (n3 < 100)
+                                    n3 += 1900;
+
+                                if (n1 > 12)  /* must be DD/MM/YY */
+                                  {
+                                        date = n1;
+                                        month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
+                                        year = n3;
+                                  }
+                                else                  /* assume MM/DD/YY */
+                                  {
+                                        /* #### In the ambiguous case, should we consult the
+                                           locale to find out the local default? */
+                                        month = (TIME_TOKEN)(n1 + ((int)TT_JAN) - 1);
+                                        date = n2;
+                                        year = n3;
+                                  }
+                                rest = s;
+                          }
+                        else if ((*end >= 'A' && *end <= 'Z') ||
+                                         (*end >= 'a' && *end <= 'z'))
+                          /* Digits followed by non-punctuation - what's that? */
+                          ;
+                        else if ((end - rest) == 5)                /* five digits is a year */
+                          year = (year < 0
+                                          ? ((rest[0]-'0')*10000L +
+                                                 (rest[1]-'0')*1000L +
+                                                 (rest[2]-'0')*100L +
+                                                 (rest[3]-'0')*10L +
+                                                 (rest[4]-'0'))
+                                          : year);
+                        else if ((end - rest) == 4)                /* four digits is a year */
+                          year = (year < 0
+                                          ? ((rest[0]-'0')*1000L +
+                                                 (rest[1]-'0')*100L +
+                                                 (rest[2]-'0')*10L +
+                                                 (rest[3]-'0'))
+                                          : year);
+                        else if ((end - rest) == 2)                /* two digits - date or year */
+                          {
+                                int n = ((rest[0]-'0')*10 +
+                                                 (rest[1]-'0'));
+                                /* If we don't have a date (day of the month) and we see a number
+                                     less than 32, then assume that is the date.
+
+                                         Otherwise, if we have a date and not a year, assume this is the
+                                         year.  If it is less than 70, then assume it refers to the 21st
+                                         century.  If it is two digits (>= 70), assume it refers to this
+                                         century.  Otherwise, assume it refers to an unambiguous year.
+
+                                         The world will surely end soon.
+                                   */
+                                if (date < 0 && n < 32)
+                                  date = n;
+                                else if (year < 0)
+                                  {
+                                        if (n < 70)
+                                          year = 2000 + n;
+                                        else if (n < 100)
+                                          year = 1900 + n;
+                                        else
+                                          year = n;
+                                  }
+                                /* else what the hell is this. */
+                          }
+                        else if ((end - rest) == 1)                /* one digit - date */
+                          date = (date < 0 ? (rest[0]-'0') : date);
+                        /* else, three or more than five digits - what's that? */
+
+                        break;
+                  }
+                }
+
+          /* Skip to the end of this token, whether we parsed it or not.
+                 Tokens are delimited by whitespace, or ,;-/
+                 But explicitly not :+-.
+           */
+          while (*rest &&
+                         *rest != ' ' && *rest != '\t' &&
+                         *rest != ',' && *rest != ';' &&
+                         *rest != '-' && *rest != '+' &&
+                         *rest != '/' &&
+                         *rest != '(' && *rest != ')' && *rest != '[' && *rest != ']')
+                rest++;
+          /* skip over uninteresting chars. */
+        SKIP_MORE:
+          while (*rest &&
+                         (*rest == ' ' || *rest == '\t' ||
+                          *rest == ',' || *rest == ';' || *rest == '/' ||
+                          *rest == '(' || *rest == ')' || *rest == '[' || *rest == ']'))
+                rest++;
+
+          /* "-" is ignored at the beginning of a token if we have not yet
+                 parsed a year (e.g., the second "-" in "30-AUG-1966"), or if
+                 the character after the dash is not a digit. */         
+          if (*rest == '-' && ((rest > string && isalpha(rest[-1]) && year < 0)
+              || rest[1] < '0' || rest[1] > '9'))
+                {
+                  rest++;
+                  goto SKIP_MORE;
+                }
+
+        }
+
+  if (zone != TT_UNKNOWN && zone_offset == -1)
+        {
+          switch (zone)
+                {
+                case TT_PST: zone_offset = -8 * 60; break;
+                case TT_PDT: zone_offset = -8 * 60; dst_offset = 1 * 60; break;
+                case TT_MST: zone_offset = -7 * 60; break;
+                case TT_MDT: zone_offset = -7 * 60; dst_offset = 1 * 60; break;
+                case TT_CST: zone_offset = -6 * 60; break;
+                case TT_CDT: zone_offset = -6 * 60; dst_offset = 1 * 60; break;
+                case TT_EST: zone_offset = -5 * 60; break;
+                case TT_EDT: zone_offset = -5 * 60; dst_offset = 1 * 60; break;
+                case TT_AST: zone_offset = -4 * 60; break;
+                case TT_NST: zone_offset = -3 * 60 - 30; break;
+                case TT_GMT: zone_offset =  0 * 60; break;
+                case TT_BST: zone_offset =  0 * 60; dst_offset = 1 * 60; break;
+                case TT_MET: zone_offset =  1 * 60; break;
+                case TT_EET: zone_offset =  2 * 60; break;
+                case TT_JST: zone_offset =  9 * 60; break;
+                default:
+                  PR_ASSERT (0);
+                  break;
+                }
+        }
+
+  /* If we didn't find a year, month, or day-of-the-month, we can't
+         possibly parse this, and in fact, mktime() will do something random
+         (I'm seeing it return "Tue Feb  5 06:28:16 2036", which is no doubt
+         a numerologically significant date... */
+  if (month == TT_UNKNOWN || date == -1 || year == -1 || year > PR_INT16_MAX)
+      return PR_FAILURE;
+
+  memset(result, 0, sizeof(*result));
+  if (sec != -1)
+        result->tm_sec = sec;
+  if (min != -1)
+        result->tm_min = min;
+  if (hour != -1)
+        result->tm_hour = hour;
+  if (date != -1)
+        result->tm_mday = date;
+  if (month != TT_UNKNOWN)
+        result->tm_month = (((int)month) - ((int)TT_JAN));
+  if (year != -1)
+        result->tm_year = year;
+  if (dotw != TT_UNKNOWN)
+        result->tm_wday = (((int)dotw) - ((int)TT_SUN));
+  /*
+   * Mainly to compute wday and yday, but normalized time is also required
+   * by the check below that works around a Visual C++ 2005 mktime problem.
+   */
+  PR_NormalizeTime(result, PR_GMTParameters);
+  /* The remaining work is to set the gmt and dst offsets in tm_params. */
+
+  if (zone == TT_UNKNOWN && default_to_gmt)
+        {
+          /* No zone was specified, so pretend the zone was GMT. */
+          zone = TT_GMT;
+          zone_offset = 0;
+        }
+
+  if (zone_offset == -1)
+         {
+           /* no zone was specified, and we're to assume that everything
+             is local. */
+          struct tm localTime;
+          time_t secs;
+
+          PR_ASSERT(result->tm_month > -1 &&
+                    result->tm_mday > 0 &&
+                    result->tm_hour > -1 &&
+                    result->tm_min > -1 &&
+                    result->tm_sec > -1);
+
+            /*
+             * To obtain time_t from a tm structure representing the local
+             * time, we call mktime().  However, we need to see if we are
+             * on 1-Jan-1970 or before.  If we are, we can't call mktime()
+             * because mktime() will crash on win16. In that case, we
+             * calculate zone_offset based on the zone offset at 
+             * 00:00:00, 2 Jan 1970 GMT, and subtract zone_offset from the
+             * date we are parsing to transform the date to GMT.  We also
+             * do so if mktime() returns (time_t) -1 (time out of range).
+           */
+
+          /* month, day, hours, mins and secs are always non-negative
+             so we dont need to worry about them. */  
+          if(result->tm_year >= 1970)
+                {
+                  PRInt64 usec_per_sec;
+
+                  localTime.tm_sec = result->tm_sec;
+                  localTime.tm_min = result->tm_min;
+                  localTime.tm_hour = result->tm_hour;
+                  localTime.tm_mday = result->tm_mday;
+                  localTime.tm_mon = result->tm_month;
+                  localTime.tm_year = result->tm_year - 1900;
+                  /* Set this to -1 to tell mktime "I don't care".  If you set
+                     it to 0 or 1, you are making assertions about whether the
+                     date you are handing it is in daylight savings mode or not;
+                     and if you're wrong, it will "fix" it for you. */
+                  localTime.tm_isdst = -1;
+
+#if _MSC_VER == 1400  /* 1400 = Visual C++ 2005 (8.0) */
+                  /*
+                   * mktime will return (time_t) -1 if the input is a date
+                   * after 23:59:59, December 31, 3000, US Pacific Time (not
+                   * UTC as documented): 
+                   * http://msdn.microsoft.com/en-us/library/d1y53h2a(VS.80).aspx
+                   * But if the year is 3001, mktime also invokes the invalid
+                   * parameter handler, causing the application to crash.  This
+                   * problem has been reported in
+                   * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=266036.
+                   * We avoid this crash by not calling mktime if the date is
+                   * out of range.  To use a simple test that works in any time
+                   * zone, we consider year 3000 out of range as well.  (See
+                   * bug 480740.)
+                   */
+                  if (result->tm_year >= 3000) {
+                      /* Emulate what mktime would have done. */
+                      errno = EINVAL;
+                      secs = (time_t) -1;
+                  } else {
+                      secs = mktime(&localTime);
+                  }
+#else
+                  secs = mktime(&localTime);
+#endif
+                  if (secs != (time_t) -1)
+                    {
+                      PRTime usecs64;
+                      LL_I2L(usecs64, secs);
+                      LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
+                      LL_MUL(usecs64, usecs64, usec_per_sec);
+                      PR_ExplodeTime(usecs64, PR_LocalTimeParameters, result);
+                      return PR_SUCCESS;
+                    }
+                }
+                
+                /* So mktime() can't handle this case.  We assume the
+                   zone_offset for the date we are parsing is the same as
+                   the zone offset on 00:00:00 2 Jan 1970 GMT. */
+                secs = 86400;
+                (void) MT_safe_localtime(&secs, &localTime);
+                zone_offset = localTime.tm_min
+                              + 60 * localTime.tm_hour
+                              + 1440 * (localTime.tm_mday - 2);
+        }
+
+  result->tm_params.tp_gmt_offset = zone_offset * 60;
+  result->tm_params.tp_dst_offset = dst_offset * 60;
+
+  return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus)
+PR_ParseTimeString(
+        const char *string,
+        PRBool default_to_gmt,
+        PRTime *result)
+{
+  PRExplodedTime tm;
+  PRStatus rv;
+
+  rv = PR_ParseTimeStringToExplodedTime(string,
+                                        default_to_gmt,
+                                        &tm);
+  if (rv != PR_SUCCESS)
+        return rv;
+
+  *result = PR_ImplodeTime(&tm);
+
+  return PR_SUCCESS;
+}
+
+/*
+ *******************************************************************
+ *******************************************************************
+ **
+ **    OLD COMPATIBILITY FUNCTIONS
+ **
+ *******************************************************************
+ *******************************************************************
+ */
+
+
+/*
+ *-----------------------------------------------------------------------
+ *
+ * PR_FormatTime --
+ *
+ *     Format a time value into a buffer. Same semantics as strftime().
+ *
+ *-----------------------------------------------------------------------
+ */
+
+PR_IMPLEMENT(PRUint32)
+PR_FormatTime(char *buf, int buflen, const char *fmt, const PRExplodedTime *tm)
+{
+    size_t rv;
+    struct tm a;
+    struct tm *ap;
+
+    if (tm) {
+        ap = &a;
+        a.tm_sec = tm->tm_sec;
+        a.tm_min = tm->tm_min;
+        a.tm_hour = tm->tm_hour;
+        a.tm_mday = tm->tm_mday;
+        a.tm_mon = tm->tm_month;
+        a.tm_wday = tm->tm_wday;
+        a.tm_year = tm->tm_year - 1900;
+        a.tm_yday = tm->tm_yday;
+        a.tm_isdst = tm->tm_params.tp_dst_offset ? 1 : 0;
+
+        /*
+         * On some platforms, for example SunOS 4, struct tm has two
+         * additional fields: tm_zone and tm_gmtoff.
+         */
+
+#if defined(SUNOS4) || (__GLIBC__ >= 2) || defined(XP_BEOS) \
+        || defined(NETBSD) || defined(OPENBSD) || defined(FREEBSD) \
+        || defined(DARWIN) || defined(SYMBIAN)
+        a.tm_zone = NULL;
+        a.tm_gmtoff = tm->tm_params.tp_gmt_offset +
+                      tm->tm_params.tp_dst_offset;
+#endif
+    } else {
+        ap = NULL;
+    }
+
+    rv = strftime(buf, buflen, fmt, ap);
+    if (!rv && buf && buflen > 0) {
+        /*
+         * When strftime fails, the contents of buf are indeterminate.
+         * Some callers don't check the return value from this function,
+         * so store an empty string in buf in case they try to print it.
+         */
+        buf[0] = '\0';
+    }
+    return rv;
+}
+
+
+/*
+ * The following string arrays and macros are used by PR_FormatTimeUSEnglish().
+ */
+
+static const char* abbrevDays[] =
+{
+   "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
+};
+
+static const char* days[] =
+{
+   "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
+};
+
+static const char* abbrevMonths[] =
+{
+   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char* months[] =
+{ 
+    "January", "February", "March", "April", "May", "June",
+    "July", "August", "September", "October", "November", "December"
+};
+
+
+/*
+ * Add a single character to the given buffer, incrementing the buffer pointer
+ * and decrementing the buffer size. Return 0 on error.
+ */
+#define ADDCHAR( buf, bufSize, ch )             \
+do                                              \
+{                                               \
+   if( bufSize < 1 )                            \
+   {                                            \
+      *(--buf) = '\0';                          \
+      return 0;                                 \
+   }                                            \
+   *buf++ = ch;                                 \
+   bufSize--;                                   \
+}                                               \
+while(0)
+
+
+/*
+ * Add a string to the given buffer, incrementing the buffer pointer
+ * and decrementing the buffer size appropriately.  Return 0 on error.
+ */
+#define ADDSTR( buf, bufSize, str )             \
+do                                              \
+{                                               \
+   PRUint32 strSize = strlen( str );              \
+   if( strSize > bufSize )                      \
+   {                                            \
+      if( bufSize==0 )                          \
+         *(--buf) = '\0';                       \
+      else                                      \
+         *buf = '\0';                           \
+      return 0;                                 \
+   }                                            \
+   memcpy(buf, str, strSize);                   \
+   buf += strSize;                              \
+   bufSize -= strSize;                          \
+}                                               \
+while(0)
+
+/* Needed by PR_FormatTimeUSEnglish() */
+static unsigned int  pr_WeekOfYear(const PRExplodedTime* time,
+        unsigned int firstDayOfWeek);
+
+
+/***********************************************************************************
+ *
+ * Description:
+ *  This is a dumbed down version of strftime that will format the date in US
+ *  English regardless of the setting of the global locale.  This functionality is
+ *  needed to write things like MIME headers which must always be in US English.
+ *
+ **********************************************************************************/
+             
+PR_IMPLEMENT(PRUint32)
+PR_FormatTimeUSEnglish( char* buf, PRUint32 bufSize,
+                        const char* format, const PRExplodedTime* time )
+{
+   char*         bufPtr = buf;
+   const char*   fmtPtr;
+   char          tmpBuf[ 40 ];        
+   const int     tmpBufSize = sizeof( tmpBuf );
+
+   
+   for( fmtPtr=format; *fmtPtr != '\0'; fmtPtr++ )
+   {
+      if( *fmtPtr != '%' )
+      {
+         ADDCHAR( bufPtr, bufSize, *fmtPtr );
+      }
+      else
+      {
+         switch( *(++fmtPtr) )
+         {
+         case '%':
+            /* escaped '%' character */
+            ADDCHAR( bufPtr, bufSize, '%' );
+            break;
+            
+         case 'a':
+            /* abbreviated weekday name */
+            ADDSTR( bufPtr, bufSize, abbrevDays[ time->tm_wday ] );
+            break;
+               
+         case 'A':
+            /* full weekday name */
+            ADDSTR( bufPtr, bufSize, days[ time->tm_wday ] );
+            break;
+        
+         case 'b':
+            /* abbreviated month name */
+            ADDSTR( bufPtr, bufSize, abbrevMonths[ time->tm_month ] );
+            break;
+        
+         case 'B':
+            /* full month name */
+            ADDSTR(bufPtr, bufSize,  months[ time->tm_month ] );
+            break;
+        
+         case 'c':
+            /* Date and time. */
+            PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%a %b %d %H:%M:%S %Y", time );
+            ADDSTR( bufPtr, bufSize, tmpBuf );
+            break;
+        
+         case 'd':
+            /* day of month ( 01 - 31 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_mday );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+
+         case 'H':
+            /* hour ( 00 - 23 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_hour );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+        
+         case 'I':
+            /* hour ( 01 - 12 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",
+                        (time->tm_hour%12) ? time->tm_hour%12 : (PRInt32) 12 );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+        
+         case 'j':
+            /* day number of year ( 001 - 366 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.3d",time->tm_yday + 1);
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+        
+         case 'm':
+            /* month number ( 01 - 12 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_month+1);
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+        
+         case 'M':
+            /* minute ( 00 - 59 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_min );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+       
+         case 'p':
+            /* locale's equivalent of either AM or PM */
+            ADDSTR( bufPtr, bufSize, (time->tm_hour<12)?"AM":"PM" ); 
+            break;
+        
+         case 'S':
+            /* seconds ( 00 - 61 ), allows for leap seconds */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_sec );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+     
+         case 'U':
+            /* week number of year ( 00 - 53  ),  Sunday  is  the first day of week 1 */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 0 ) );
+            ADDSTR( bufPtr, bufSize, tmpBuf );
+            break;
+        
+         case 'w':
+            /* weekday number ( 0 - 6 ), Sunday = 0 */
+            PR_snprintf(tmpBuf,tmpBufSize,"%d",time->tm_wday );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+        
+         case 'W':
+            /* Week number of year ( 00 - 53  ),  Monday  is  the first day of week 1 */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 1 ) );
+            ADDSTR( bufPtr, bufSize, tmpBuf );
+            break;
+        
+         case 'x':
+            /* Date representation */
+            PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%m/%d/%y", time );
+            ADDSTR( bufPtr, bufSize, tmpBuf );
+            break;
+        
+         case 'X':
+            /* Time representation. */
+            PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%H:%M:%S", time );
+            ADDSTR( bufPtr, bufSize, tmpBuf );
+            break;
+        
+         case 'y':
+            /* year within century ( 00 - 99 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_year % 100 );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+        
+         case 'Y':
+            /* year as ccyy ( for example 1986 ) */
+            PR_snprintf(tmpBuf,tmpBufSize,"%.4d",time->tm_year );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+        
+         case 'Z':
+            /* Time zone name or no characters if  no  time  zone exists.
+             * Since time zone name is supposed to be independant of locale, we
+             * defer to PR_FormatTime() for this option.
+             */
+            PR_FormatTime( tmpBuf, tmpBufSize, "%Z", time );
+            ADDSTR( bufPtr, bufSize, tmpBuf ); 
+            break;
+
+         default:
+            /* Unknown format.  Simply copy format into output buffer. */
+            ADDCHAR( bufPtr, bufSize, '%' );
+            ADDCHAR( bufPtr, bufSize, *fmtPtr );
+            break;
+            
+         }
+      }
+   }
+
+   ADDCHAR( bufPtr, bufSize, '\0' );
+   return (PRUint32)(bufPtr - buf - 1);
+}
+
+
+
+/***********************************************************************************
+ *
+ * Description:
+ *  Returns the week number of the year (0-53) for the given time.  firstDayOfWeek
+ *  is the day on which the week is considered to start (0=Sun, 1=Mon, ...).
+ *  Week 1 starts the first time firstDayOfWeek occurs in the year.  In other words,
+ *  a partial week at the start of the year is considered week 0.  
+ *
+ **********************************************************************************/
+
+static unsigned int
+pr_WeekOfYear(const PRExplodedTime* time, unsigned int firstDayOfWeek)
+{
+   int dayOfWeek;
+   int dayOfYear;
+
+  /* Get the day of the year for the given time then adjust it to represent the
+   * first day of the week containing the given time.
+   */
+  dayOfWeek = time->tm_wday - firstDayOfWeek;
+  if (dayOfWeek < 0)
+    dayOfWeek += 7;
+  
+  dayOfYear = time->tm_yday - dayOfWeek;
+
+
+  if( dayOfYear <= 0 )
+  {
+     /* If dayOfYear is <= 0, it is in the first partial week of the year. */
+     return 0;
+  }
+  else
+  {
+     /* Count the number of full weeks ( dayOfYear / 7 ) then add a week if there
+      * are any days left over ( dayOfYear % 7 ).  Because we are only counting to
+      * the first day of the week containing the given time, rather than to the
+      * actual day representing the given time, any days in week 0 will be "absorbed"
+      * as extra days in the given week.
+      */
+     return (dayOfYear / 7) + ( (dayOfYear % 7) == 0 ? 0 : 1 );
+  }
+}
+
diff --git a/mozilla/nsprpub/pr/src/misc/prtpool.c b/mozilla/nsprpub/pr/src/misc/prtpool.c
new file mode 100644
index 0000000..e23bb9d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prtpool.c
@@ -0,0 +1,1219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-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"
+
+/*
+ * Thread pools
+ *	Thread pools create and manage threads to provide support for
+ *	scheduling jobs onto one or more threads.
+ *
+ */
+#ifdef OPT_WINNT
+#include <windows.h>
+#endif
+
+/*
+ * worker thread
+ */
+typedef struct wthread {
+	PRCList		links;
+	PRThread	*thread;
+} wthread;
+
+/*
+ * queue of timer jobs
+ */
+typedef struct timer_jobq {
+	PRCList		list;
+	PRLock		*lock;
+	PRCondVar	*cv;
+	PRInt32		cnt;
+	PRCList 	wthreads;
+} timer_jobq;
+
+/*
+ * queue of jobs
+ */
+typedef struct tp_jobq {
+	PRCList		list;
+	PRInt32		cnt;
+	PRLock		*lock;
+	PRCondVar	*cv;
+	PRCList 	wthreads;
+#ifdef OPT_WINNT
+	HANDLE		nt_completion_port;
+#endif
+} tp_jobq;
+
+/*
+ * queue of IO jobs
+ */
+typedef struct io_jobq {
+	PRCList		list;
+	PRPollDesc  *pollfds;
+	PRInt32  	npollfds;
+	PRJob		**polljobs;
+	PRLock		*lock;
+	PRInt32		cnt;
+	PRFileDesc	*notify_fd;
+	PRCList 	wthreads;
+} io_jobq;
+
+/*
+ * Threadpool
+ */
+struct PRThreadPool {
+	PRInt32		init_threads;
+	PRInt32		max_threads;
+	PRInt32		current_threads;
+	PRInt32		idle_threads;
+	PRUint32	stacksize;
+	tp_jobq		jobq;
+	io_jobq		ioq;
+	timer_jobq	timerq;
+	PRLock		*join_lock;		/* used with jobp->join_cv */
+	PRCondVar	*shutdown_cv;
+	PRBool		shutdown;
+};
+
+typedef enum io_op_type
+	{ JOB_IO_READ, JOB_IO_WRITE, JOB_IO_CONNECT, JOB_IO_ACCEPT } io_op_type;
+
+#ifdef OPT_WINNT
+typedef struct NT_notifier {
+	OVERLAPPED overlapped;		/* must be first */
+	PRJob	*jobp;
+} NT_notifier;
+#endif
+
+struct PRJob {
+	PRCList			links;		/* 	for linking jobs */
+	PRBool			on_ioq;		/* job on ioq */
+	PRBool			on_timerq;	/* job on timerq */
+	PRJobFn			job_func;
+	void 			*job_arg;
+	PRCondVar		*join_cv;
+	PRBool			join_wait;	/* == PR_TRUE, when waiting to join */
+	PRCondVar		*cancel_cv;	/* for cancelling IO jobs */
+	PRBool			cancel_io;	/* for cancelling IO jobs */
+	PRThreadPool	*tpool;		/* back pointer to thread pool */
+	PRJobIoDesc		*iod;
+	io_op_type		io_op;
+	PRInt16			io_poll_flags;
+	PRNetAddr		*netaddr;
+	PRIntervalTime	timeout;	/* relative value */
+	PRIntervalTime	absolute;
+#ifdef OPT_WINNT
+	NT_notifier		nt_notifier;	
+#endif
+};
+
+#define JOB_LINKS_PTR(_qp) \
+    ((PRJob *) ((char *) (_qp) - offsetof(PRJob, links)))
+
+#define WTHREAD_LINKS_PTR(_qp) \
+    ((wthread *) ((char *) (_qp) - offsetof(wthread, links)))
+
+#define JOINABLE_JOB(_jobp) (NULL != (_jobp)->join_cv)
+
+#define JOIN_NOTIFY(_jobp)								\
+				PR_BEGIN_MACRO							\
+				PR_Lock(_jobp->tpool->join_lock);		\
+				_jobp->join_wait = PR_FALSE;			\
+				PR_NotifyCondVar(_jobp->join_cv);		\
+				PR_Unlock(_jobp->tpool->join_lock);		\
+				PR_END_MACRO
+
+#define CANCEL_IO_JOB(jobp)								\
+				PR_BEGIN_MACRO							\
+				jobp->cancel_io = PR_FALSE;				\
+				jobp->on_ioq = PR_FALSE;				\
+				PR_REMOVE_AND_INIT_LINK(&jobp->links);	\
+				tp->ioq.cnt--;							\
+				PR_NotifyCondVar(jobp->cancel_cv);		\
+				PR_END_MACRO
+
+static void delete_job(PRJob *jobp);
+static PRThreadPool * alloc_threadpool(void);
+static PRJob * alloc_job(PRBool joinable, PRThreadPool *tp);
+static void notify_ioq(PRThreadPool *tp);
+static void notify_timerq(PRThreadPool *tp);
+
+/*
+ * locks are acquired in the following order
+ *
+ *	tp->ioq.lock,tp->timerq.lock
+ *			|
+ *			V
+ *		tp->jobq->lock		
+ */
+
+/*
+ * worker thread function
+ */
+static void wstart(void *arg)
+{
+PRThreadPool *tp = (PRThreadPool *) arg;
+PRCList *head;
+
+	/*
+	 * execute jobs until shutdown
+	 */
+	while (!tp->shutdown) {
+		PRJob *jobp;
+#ifdef OPT_WINNT
+		BOOL rv;
+		DWORD unused, shutdown;
+		LPOVERLAPPED olp;
+
+		PR_Lock(tp->jobq.lock);
+		tp->idle_threads++;
+		PR_Unlock(tp->jobq.lock);
+		rv = GetQueuedCompletionStatus(tp->jobq.nt_completion_port,
+					&unused, &shutdown, &olp, INFINITE);
+		
+		PR_ASSERT(rv);
+		if (shutdown)
+			break;
+		jobp = ((NT_notifier *) olp)->jobp;
+		PR_Lock(tp->jobq.lock);
+		tp->idle_threads--;
+		tp->jobq.cnt--;
+		PR_Unlock(tp->jobq.lock);
+#else
+
+		PR_Lock(tp->jobq.lock);
+		while (PR_CLIST_IS_EMPTY(&tp->jobq.list) && (!tp->shutdown)) {
+			tp->idle_threads++;
+			PR_WaitCondVar(tp->jobq.cv, PR_INTERVAL_NO_TIMEOUT);
+			tp->idle_threads--;
+		}	
+		if (tp->shutdown) {
+			PR_Unlock(tp->jobq.lock);
+			break;
+		}
+		head = PR_LIST_HEAD(&tp->jobq.list);
+		/*
+		 * remove job from queue
+		 */
+		PR_REMOVE_AND_INIT_LINK(head);
+		tp->jobq.cnt--;
+		jobp = JOB_LINKS_PTR(head);
+		PR_Unlock(tp->jobq.lock);
+#endif
+
+		jobp->job_func(jobp->job_arg);
+		if (!JOINABLE_JOB(jobp)) {
+			delete_job(jobp);
+		} else {
+			JOIN_NOTIFY(jobp);
+		}
+	}
+	PR_Lock(tp->jobq.lock);
+	tp->current_threads--;
+	PR_Unlock(tp->jobq.lock);
+}
+
+/*
+ * add a job to the work queue
+ */
+static void
+add_to_jobq(PRThreadPool *tp, PRJob *jobp)
+{
+	/*
+	 * add to jobq
+	 */
+#ifdef OPT_WINNT
+	PR_Lock(tp->jobq.lock);
+	tp->jobq.cnt++;
+	PR_Unlock(tp->jobq.lock);
+	/*
+	 * notify worker thread(s)
+	 */
+	PostQueuedCompletionStatus(tp->jobq.nt_completion_port, 0,
+            FALSE, &jobp->nt_notifier.overlapped);
+#else
+	PR_Lock(tp->jobq.lock);
+	PR_APPEND_LINK(&jobp->links,&tp->jobq.list);
+	tp->jobq.cnt++;
+	if ((tp->idle_threads < tp->jobq.cnt) &&
+					(tp->current_threads < tp->max_threads)) {
+		wthread *wthrp;
+		/*
+		 * increment thread count and unlock the jobq lock
+		 */
+		tp->current_threads++;
+		PR_Unlock(tp->jobq.lock);
+		/* create new worker thread */
+		wthrp = PR_NEWZAP(wthread);
+		if (wthrp) {
+			wthrp->thread = PR_CreateThread(PR_USER_THREAD, wstart,
+						tp, PR_PRIORITY_NORMAL,
+						PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,tp->stacksize);
+			if (NULL == wthrp->thread) {
+				PR_DELETE(wthrp);  /* this sets wthrp to NULL */
+			}
+		}
+		PR_Lock(tp->jobq.lock);
+		if (NULL == wthrp) {
+			tp->current_threads--;
+		} else {
+			PR_APPEND_LINK(&wthrp->links, &tp->jobq.wthreads);
+		}
+	}
+	/*
+	 * wakeup a worker thread
+	 */
+	PR_NotifyCondVar(tp->jobq.cv);
+	PR_Unlock(tp->jobq.lock);
+#endif
+}
+
+/*
+ * io worker thread function
+ */
+static void io_wstart(void *arg)
+{
+PRThreadPool *tp = (PRThreadPool *) arg;
+int pollfd_cnt, pollfds_used;
+int rv;
+PRCList *qp, *nextqp;
+PRPollDesc *pollfds;
+PRJob **polljobs;
+int poll_timeout;
+PRIntervalTime now;
+
+	/*
+	 * scan io_jobq
+	 * construct poll list
+	 * call PR_Poll
+	 * for all fds, for which poll returns true, move the job to
+	 * jobq and wakeup worker thread.
+	 */
+	while (!tp->shutdown) {
+		PRJob *jobp;
+
+		pollfd_cnt = tp->ioq.cnt + 10;
+		if (pollfd_cnt > tp->ioq.npollfds) {
+
+			/*
+			 * re-allocate pollfd array if the current one is not large
+			 * enough
+			 */
+			if (NULL != tp->ioq.pollfds)
+				PR_Free(tp->ioq.pollfds);
+			tp->ioq.pollfds = (PRPollDesc *) PR_Malloc(pollfd_cnt *
+						(sizeof(PRPollDesc) + sizeof(PRJob *)));
+			PR_ASSERT(NULL != tp->ioq.pollfds);
+			/*
+			 * array of pollfds
+			 */
+			pollfds = tp->ioq.pollfds;
+			tp->ioq.polljobs = (PRJob **) (&tp->ioq.pollfds[pollfd_cnt]);
+			/*
+			 * parallel array of jobs
+			 */
+			polljobs = tp->ioq.polljobs;
+			tp->ioq.npollfds = pollfd_cnt;
+		}
+
+		pollfds_used = 0;
+		/*
+		 * add the notify fd; used for unblocking io thread(s)
+		 */
+		pollfds[pollfds_used].fd = tp->ioq.notify_fd;
+		pollfds[pollfds_used].in_flags = PR_POLL_READ;
+		pollfds[pollfds_used].out_flags = 0;
+		polljobs[pollfds_used] = NULL;
+		pollfds_used++;
+		/*
+		 * fill in the pollfd array
+		 */
+		PR_Lock(tp->ioq.lock);
+		for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) {
+			nextqp = qp->next;
+			jobp = JOB_LINKS_PTR(qp);
+			if (jobp->cancel_io) {
+				CANCEL_IO_JOB(jobp);
+				continue;
+			}
+			if (pollfds_used == (pollfd_cnt))
+				break;
+			pollfds[pollfds_used].fd = jobp->iod->socket;
+			pollfds[pollfds_used].in_flags = jobp->io_poll_flags;
+			pollfds[pollfds_used].out_flags = 0;
+			polljobs[pollfds_used] = jobp;
+
+			pollfds_used++;
+		}
+		if (!PR_CLIST_IS_EMPTY(&tp->ioq.list)) {
+			qp = tp->ioq.list.next;
+			jobp = JOB_LINKS_PTR(qp);
+			if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout)
+				poll_timeout = PR_INTERVAL_NO_TIMEOUT;
+			else if (PR_INTERVAL_NO_WAIT == jobp->timeout)
+				poll_timeout = PR_INTERVAL_NO_WAIT;
+			else {
+				poll_timeout = jobp->absolute - PR_IntervalNow();
+				if (poll_timeout <= 0) /* already timed out */
+					poll_timeout = PR_INTERVAL_NO_WAIT;
+			}
+		} else {
+			poll_timeout = PR_INTERVAL_NO_TIMEOUT;
+		}
+		PR_Unlock(tp->ioq.lock);
+
+		/*
+		 * XXXX
+		 * should retry if more jobs have been added to the queue?
+		 *
+		 */
+		PR_ASSERT(pollfds_used <= pollfd_cnt);
+		rv = PR_Poll(tp->ioq.pollfds, pollfds_used, poll_timeout);
+
+		if (tp->shutdown) {
+			break;
+		}
+
+		if (rv > 0) {
+			/*
+			 * at least one io event is set
+			 */
+			PRStatus rval_status;
+			PRInt32 index;
+
+			PR_ASSERT(pollfds[0].fd == tp->ioq.notify_fd);
+			/*
+			 * reset the pollable event, if notified
+			 */
+			if (pollfds[0].out_flags & PR_POLL_READ) {
+				rval_status = PR_WaitForPollableEvent(tp->ioq.notify_fd);
+				PR_ASSERT(PR_SUCCESS == rval_status);
+			}
+
+			for(index = 1; index < (pollfds_used); index++) {
+                PRInt16 events = pollfds[index].in_flags;
+                PRInt16 revents = pollfds[index].out_flags;	
+				jobp = polljobs[index];	
+
+                if ((revents & PR_POLL_NVAL) ||  /* busted in all cases */
+                	(revents & PR_POLL_ERR) ||
+                			((events & PR_POLL_WRITE) &&
+							(revents & PR_POLL_HUP))) { /* write op & hup */
+					PR_Lock(tp->ioq.lock);
+					if (jobp->cancel_io) {
+						CANCEL_IO_JOB(jobp);
+						PR_Unlock(tp->ioq.lock);
+						continue;
+					}
+					PR_REMOVE_AND_INIT_LINK(&jobp->links);
+					tp->ioq.cnt--;
+					jobp->on_ioq = PR_FALSE;
+					PR_Unlock(tp->ioq.lock);
+
+					/* set error */
+                    if (PR_POLL_NVAL & revents)
+						jobp->iod->error = PR_BAD_DESCRIPTOR_ERROR;
+                    else if (PR_POLL_HUP & revents)
+						jobp->iod->error = PR_CONNECT_RESET_ERROR;
+                    else 
+						jobp->iod->error = PR_IO_ERROR;
+
+					/*
+					 * add to jobq
+					 */
+					add_to_jobq(tp, jobp);
+				} else if (revents) {
+					/*
+					 * add to jobq
+					 */
+					PR_Lock(tp->ioq.lock);
+					if (jobp->cancel_io) {
+						CANCEL_IO_JOB(jobp);
+						PR_Unlock(tp->ioq.lock);
+						continue;
+					}
+					PR_REMOVE_AND_INIT_LINK(&jobp->links);
+					tp->ioq.cnt--;
+					jobp->on_ioq = PR_FALSE;
+					PR_Unlock(tp->ioq.lock);
+
+					if (jobp->io_op == JOB_IO_CONNECT) {
+						if (PR_GetConnectStatus(&pollfds[index]) == PR_SUCCESS)
+							jobp->iod->error = 0;
+						else
+							jobp->iod->error = PR_GetError();
+					} else
+						jobp->iod->error = 0;
+
+					add_to_jobq(tp, jobp);
+				}
+			}
+		}
+		/*
+		 * timeout processing
+		 */
+		now = PR_IntervalNow();
+		PR_Lock(tp->ioq.lock);
+		for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) {
+			nextqp = qp->next;
+			jobp = JOB_LINKS_PTR(qp);
+			if (jobp->cancel_io) {
+				CANCEL_IO_JOB(jobp);
+				continue;
+			}
+			if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout)
+				break;
+			if ((PR_INTERVAL_NO_WAIT != jobp->timeout) &&
+								((PRInt32)(jobp->absolute - now) > 0))
+				break;
+			PR_REMOVE_AND_INIT_LINK(&jobp->links);
+			tp->ioq.cnt--;
+			jobp->on_ioq = PR_FALSE;
+			jobp->iod->error = PR_IO_TIMEOUT_ERROR;
+			add_to_jobq(tp, jobp);
+		}
+		PR_Unlock(tp->ioq.lock);
+	}
+}
+
+/*
+ * timer worker thread function
+ */
+static void timer_wstart(void *arg)
+{
+PRThreadPool *tp = (PRThreadPool *) arg;
+PRCList *qp;
+PRIntervalTime timeout;
+PRIntervalTime now;
+
+	/*
+	 * call PR_WaitCondVar with minimum value of all timeouts
+	 */
+	while (!tp->shutdown) {
+		PRJob *jobp;
+
+		PR_Lock(tp->timerq.lock);
+		if (PR_CLIST_IS_EMPTY(&tp->timerq.list)) {
+			timeout = PR_INTERVAL_NO_TIMEOUT;
+		} else {
+			PRCList *qp;
+
+			qp = tp->timerq.list.next;
+			jobp = JOB_LINKS_PTR(qp);
+
+			timeout = jobp->absolute - PR_IntervalNow();
+            if (timeout <= 0)
+				timeout = PR_INTERVAL_NO_WAIT;  /* already timed out */
+		}
+		if (PR_INTERVAL_NO_WAIT != timeout)
+			PR_WaitCondVar(tp->timerq.cv, timeout);
+		if (tp->shutdown) {
+			PR_Unlock(tp->timerq.lock);
+			break;
+		}
+		/*
+		 * move expired-timer jobs to jobq
+		 */
+		now = PR_IntervalNow();	
+		while (!PR_CLIST_IS_EMPTY(&tp->timerq.list)) {
+			qp = tp->timerq.list.next;
+			jobp = JOB_LINKS_PTR(qp);
+
+			if ((PRInt32)(jobp->absolute - now) > 0) {
+				break;
+			}
+			/*
+			 * job timed out
+			 */
+			PR_REMOVE_AND_INIT_LINK(&jobp->links);
+			tp->timerq.cnt--;
+			jobp->on_timerq = PR_FALSE;
+			add_to_jobq(tp, jobp);
+		}
+		PR_Unlock(tp->timerq.lock);
+	}
+}
+
+static void
+delete_threadpool(PRThreadPool *tp)
+{
+	if (NULL != tp) {
+		if (NULL != tp->shutdown_cv)
+			PR_DestroyCondVar(tp->shutdown_cv);
+		if (NULL != tp->jobq.cv)
+			PR_DestroyCondVar(tp->jobq.cv);
+		if (NULL != tp->jobq.lock)
+			PR_DestroyLock(tp->jobq.lock);
+		if (NULL != tp->join_lock)
+			PR_DestroyLock(tp->join_lock);
+#ifdef OPT_WINNT
+		if (NULL != tp->jobq.nt_completion_port)
+			CloseHandle(tp->jobq.nt_completion_port);
+#endif
+		/* Timer queue */
+		if (NULL != tp->timerq.cv)
+			PR_DestroyCondVar(tp->timerq.cv);
+		if (NULL != tp->timerq.lock)
+			PR_DestroyLock(tp->timerq.lock);
+
+		if (NULL != tp->ioq.lock)
+			PR_DestroyLock(tp->ioq.lock);
+		if (NULL != tp->ioq.pollfds)
+			PR_Free(tp->ioq.pollfds);
+		if (NULL != tp->ioq.notify_fd)
+			PR_DestroyPollableEvent(tp->ioq.notify_fd);
+		PR_Free(tp);
+	}
+	return;
+}
+
+static PRThreadPool *
+alloc_threadpool(void)
+{
+PRThreadPool *tp;
+
+	tp = (PRThreadPool *) PR_CALLOC(sizeof(*tp));
+	if (NULL == tp)
+		goto failed;
+	tp->jobq.lock = PR_NewLock();
+	if (NULL == tp->jobq.lock)
+		goto failed;
+	tp->jobq.cv = PR_NewCondVar(tp->jobq.lock);
+	if (NULL == tp->jobq.cv)
+		goto failed;
+	tp->join_lock = PR_NewLock();
+	if (NULL == tp->join_lock)
+		goto failed;
+#ifdef OPT_WINNT
+	tp->jobq.nt_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
+									NULL, 0, 0);
+	if (NULL == tp->jobq.nt_completion_port)
+		goto failed;
+#endif
+
+	tp->ioq.lock = PR_NewLock();
+	if (NULL == tp->ioq.lock)
+		goto failed;
+
+	/* Timer queue */
+
+	tp->timerq.lock = PR_NewLock();
+	if (NULL == tp->timerq.lock)
+		goto failed;
+	tp->timerq.cv = PR_NewCondVar(tp->timerq.lock);
+	if (NULL == tp->timerq.cv)
+		goto failed;
+
+	tp->shutdown_cv = PR_NewCondVar(tp->jobq.lock);
+	if (NULL == tp->shutdown_cv)
+		goto failed;
+	tp->ioq.notify_fd = PR_NewPollableEvent();
+	if (NULL == tp->ioq.notify_fd)
+		goto failed;
+	return tp;
+failed:
+	delete_threadpool(tp);
+	PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	return NULL;
+}
+
+/* Create thread pool */
+PR_IMPLEMENT(PRThreadPool *)
+PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads,
+                                PRUint32 stacksize)
+{
+PRThreadPool *tp;
+PRThread *thr;
+int i;
+wthread *wthrp;
+
+	tp = alloc_threadpool();
+	if (NULL == tp)
+		return NULL;
+
+	tp->init_threads = initial_threads;
+	tp->max_threads = max_threads;
+	tp->stacksize = stacksize;
+	PR_INIT_CLIST(&tp->jobq.list);
+	PR_INIT_CLIST(&tp->ioq.list);
+	PR_INIT_CLIST(&tp->timerq.list);
+	PR_INIT_CLIST(&tp->jobq.wthreads);
+	PR_INIT_CLIST(&tp->ioq.wthreads);
+	PR_INIT_CLIST(&tp->timerq.wthreads);
+	tp->shutdown = PR_FALSE;
+
+	PR_Lock(tp->jobq.lock);
+	for(i=0; i < initial_threads; ++i) {
+
+		thr = PR_CreateThread(PR_USER_THREAD, wstart,
+						tp, PR_PRIORITY_NORMAL,
+						PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,stacksize);
+		PR_ASSERT(thr);
+		wthrp = PR_NEWZAP(wthread);
+		PR_ASSERT(wthrp);
+		wthrp->thread = thr;
+		PR_APPEND_LINK(&wthrp->links, &tp->jobq.wthreads);
+	}
+	tp->current_threads = initial_threads;
+
+	thr = PR_CreateThread(PR_USER_THREAD, io_wstart,
+					tp, PR_PRIORITY_NORMAL,
+					PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,stacksize);
+	PR_ASSERT(thr);
+	wthrp = PR_NEWZAP(wthread);
+	PR_ASSERT(wthrp);
+	wthrp->thread = thr;
+	PR_APPEND_LINK(&wthrp->links, &tp->ioq.wthreads);
+
+	thr = PR_CreateThread(PR_USER_THREAD, timer_wstart,
+					tp, PR_PRIORITY_NORMAL,
+					PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,stacksize);
+	PR_ASSERT(thr);
+	wthrp = PR_NEWZAP(wthread);
+	PR_ASSERT(wthrp);
+	wthrp->thread = thr;
+	PR_APPEND_LINK(&wthrp->links, &tp->timerq.wthreads);
+
+	PR_Unlock(tp->jobq.lock);
+	return tp;
+}
+
+static void
+delete_job(PRJob *jobp)
+{
+	if (NULL != jobp) {
+		if (NULL != jobp->join_cv) {
+			PR_DestroyCondVar(jobp->join_cv);
+			jobp->join_cv = NULL;
+		}
+		if (NULL != jobp->cancel_cv) {
+			PR_DestroyCondVar(jobp->cancel_cv);
+			jobp->cancel_cv = NULL;
+		}
+		PR_DELETE(jobp);
+	}
+}
+
+static PRJob *
+alloc_job(PRBool joinable, PRThreadPool *tp)
+{
+	PRJob *jobp;
+
+	jobp = PR_NEWZAP(PRJob);
+	if (NULL == jobp) 
+		goto failed;
+	if (joinable) {
+		jobp->join_cv = PR_NewCondVar(tp->join_lock);
+		jobp->join_wait = PR_TRUE;
+		if (NULL == jobp->join_cv)
+			goto failed;
+	} else {
+		jobp->join_cv = NULL;
+	}
+#ifdef OPT_WINNT
+	jobp->nt_notifier.jobp = jobp;
+#endif
+	return jobp;
+failed:
+	delete_job(jobp);
+	PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	return NULL;
+}
+
+/* queue a job */
+PR_IMPLEMENT(PRJob *)
+PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable)
+{
+	PRJob *jobp;
+
+	jobp = alloc_job(joinable, tpool);
+	if (NULL == jobp)
+		return NULL;
+
+	jobp->job_func = fn;
+	jobp->job_arg = arg;
+	jobp->tpool = tpool;
+
+	add_to_jobq(tpool, jobp);
+	return jobp;
+}
+
+/* queue a job, when a socket is readable or writeable */
+static PRJob *
+queue_io_job(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg,
+				PRBool joinable, io_op_type op)
+{
+	PRJob *jobp;
+	PRIntervalTime now;
+
+	jobp = alloc_job(joinable, tpool);
+	if (NULL == jobp) {
+		return NULL;
+	}
+
+	/*
+	 * Add a new job to io_jobq
+	 * wakeup io worker thread
+	 */
+
+	jobp->job_func = fn;
+	jobp->job_arg = arg;
+	jobp->tpool = tpool;
+	jobp->iod = iod;
+	if (JOB_IO_READ == op) {
+		jobp->io_op = JOB_IO_READ;
+		jobp->io_poll_flags = PR_POLL_READ;
+	} else if (JOB_IO_WRITE == op) {
+		jobp->io_op = JOB_IO_WRITE;
+		jobp->io_poll_flags = PR_POLL_WRITE;
+	} else if (JOB_IO_ACCEPT == op) {
+		jobp->io_op = JOB_IO_ACCEPT;
+		jobp->io_poll_flags = PR_POLL_READ;
+	} else if (JOB_IO_CONNECT == op) {
+		jobp->io_op = JOB_IO_CONNECT;
+		jobp->io_poll_flags = PR_POLL_WRITE|PR_POLL_EXCEPT;
+	} else {
+		delete_job(jobp);
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return NULL;
+	}
+
+	jobp->timeout = iod->timeout;
+	if ((PR_INTERVAL_NO_TIMEOUT == iod->timeout) ||
+			(PR_INTERVAL_NO_WAIT == iod->timeout)) {
+		jobp->absolute = iod->timeout;
+	} else {
+		now = PR_IntervalNow();
+		jobp->absolute = now + iod->timeout;
+	}
+
+
+	PR_Lock(tpool->ioq.lock);
+
+	if (PR_CLIST_IS_EMPTY(&tpool->ioq.list) ||
+			(PR_INTERVAL_NO_TIMEOUT == iod->timeout)) {
+		PR_APPEND_LINK(&jobp->links,&tpool->ioq.list);
+	} else if (PR_INTERVAL_NO_WAIT == iod->timeout) {
+		PR_INSERT_LINK(&jobp->links,&tpool->ioq.list);
+	} else {
+		PRCList *qp;
+		PRJob *tmp_jobp;
+		/*
+		 * insert into the timeout-sorted ioq
+		 */
+		for (qp = tpool->ioq.list.prev; qp != &tpool->ioq.list;
+							qp = qp->prev) {
+			tmp_jobp = JOB_LINKS_PTR(qp);
+			if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) {
+				break;
+			}
+		}
+		PR_INSERT_AFTER(&jobp->links,qp);
+	}
+
+	jobp->on_ioq = PR_TRUE;
+	tpool->ioq.cnt++;
+	/*
+	 * notify io worker thread(s)
+	 */
+	PR_Unlock(tpool->ioq.lock);
+	notify_ioq(tpool);
+	return jobp;
+}
+
+/* queue a job, when a socket is readable */
+PR_IMPLEMENT(PRJob *)
+PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg,
+											PRBool joinable)
+{
+	return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_READ));
+}
+
+/* queue a job, when a socket is writeable */
+PR_IMPLEMENT(PRJob *)
+PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn,void * arg,
+										PRBool joinable)
+{
+	return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_WRITE));
+}
+
+
+/* queue a job, when a socket has a pending connection */
+PR_IMPLEMENT(PRJob *)
+PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn,
+								void * arg, PRBool joinable)
+{
+	return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_ACCEPT));
+}
+
+/* queue a job, when a socket can be connected */
+PR_IMPLEMENT(PRJob *)
+PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod,
+			const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable)
+{
+	PRStatus rv;
+	PRErrorCode err;
+
+	rv = PR_Connect(iod->socket, addr, PR_INTERVAL_NO_WAIT);
+	if ((rv == PR_FAILURE) && ((err = PR_GetError()) == PR_IN_PROGRESS_ERROR)){
+		/* connection pending */
+		return(queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_CONNECT));
+	} else {
+		/*
+		 * connection succeeded or failed; add to jobq right away
+		 */
+		if (rv == PR_FAILURE)
+			iod->error = err;
+		else
+			iod->error = 0;
+		return(PR_QueueJob(tpool, fn, arg, joinable));
+	}
+}
+
+/* queue a job, when a timer expires */
+PR_IMPLEMENT(PRJob *)
+PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout,
+							PRJobFn fn, void * arg, PRBool joinable)
+{
+	PRIntervalTime now;
+	PRJob *jobp;
+
+	if (PR_INTERVAL_NO_TIMEOUT == timeout) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return NULL;
+	}
+	if (PR_INTERVAL_NO_WAIT == timeout) {
+		/*
+		 * no waiting; add to jobq right away
+		 */
+		return(PR_QueueJob(tpool, fn, arg, joinable));
+	}
+	jobp = alloc_job(joinable, tpool);
+	if (NULL == jobp) {
+		return NULL;
+	}
+
+	/*
+	 * Add a new job to timer_jobq
+	 * wakeup timer worker thread
+	 */
+
+	jobp->job_func = fn;
+	jobp->job_arg = arg;
+	jobp->tpool = tpool;
+	jobp->timeout = timeout;
+
+	now = PR_IntervalNow();
+	jobp->absolute = now + timeout;
+
+
+	PR_Lock(tpool->timerq.lock);
+	jobp->on_timerq = PR_TRUE;
+	if (PR_CLIST_IS_EMPTY(&tpool->timerq.list))
+		PR_APPEND_LINK(&jobp->links,&tpool->timerq.list);
+	else {
+		PRCList *qp;
+		PRJob *tmp_jobp;
+		/*
+		 * insert into the sorted timer jobq
+		 */
+		for (qp = tpool->timerq.list.prev; qp != &tpool->timerq.list;
+							qp = qp->prev) {
+			tmp_jobp = JOB_LINKS_PTR(qp);
+			if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) {
+				break;
+			}
+		}
+		PR_INSERT_AFTER(&jobp->links,qp);
+	}
+	tpool->timerq.cnt++;
+	/*
+	 * notify timer worker thread(s)
+	 */
+	notify_timerq(tpool);
+	PR_Unlock(tpool->timerq.lock);
+	return jobp;
+}
+
+static void
+notify_timerq(PRThreadPool *tp)
+{
+	/*
+	 * wakeup the timer thread(s)
+	 */
+	PR_NotifyCondVar(tp->timerq.cv);
+}
+
+static void
+notify_ioq(PRThreadPool *tp)
+{
+PRStatus rval_status;
+
+	/*
+	 * wakeup the io thread(s)
+	 */
+	rval_status = PR_SetPollableEvent(tp->ioq.notify_fd);
+	PR_ASSERT(PR_SUCCESS == rval_status);
+}
+
+/*
+ * cancel a job
+ *
+ *	XXXX: is this needed? likely to be removed
+ */
+PR_IMPLEMENT(PRStatus)
+PR_CancelJob(PRJob *jobp) {
+
+	PRStatus rval = PR_FAILURE;
+	PRThreadPool *tp;
+
+	if (jobp->on_timerq) {
+		/*
+		 * now, check again while holding the timerq lock
+		 */
+		tp = jobp->tpool;
+		PR_Lock(tp->timerq.lock);
+		if (jobp->on_timerq) {
+			jobp->on_timerq = PR_FALSE;
+			PR_REMOVE_AND_INIT_LINK(&jobp->links);
+			tp->timerq.cnt--;
+			PR_Unlock(tp->timerq.lock);
+			if (!JOINABLE_JOB(jobp)) {
+				delete_job(jobp);
+			} else {
+				JOIN_NOTIFY(jobp);
+			}
+			rval = PR_SUCCESS;
+		} else
+			PR_Unlock(tp->timerq.lock);
+	} else if (jobp->on_ioq) {
+		/*
+		 * now, check again while holding the ioq lock
+		 */
+		tp = jobp->tpool;
+		PR_Lock(tp->ioq.lock);
+		if (jobp->on_ioq) {
+			jobp->cancel_cv = PR_NewCondVar(tp->ioq.lock);
+			if (NULL == jobp->cancel_cv) {
+				PR_Unlock(tp->ioq.lock);
+				PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+				return PR_FAILURE;
+			}
+			/*
+			 * mark job 'cancelled' and notify io thread(s)
+			 * XXXX:
+			 *		this assumes there is only one io thread; when there
+			 * 		are multiple threads, the io thread processing this job
+			 * 		must be notified.
+			 */
+			jobp->cancel_io = PR_TRUE;
+			PR_Unlock(tp->ioq.lock);	/* release, reacquire ioq lock */
+			notify_ioq(tp);
+			PR_Lock(tp->ioq.lock);
+			while (jobp->cancel_io)
+				PR_WaitCondVar(jobp->cancel_cv, PR_INTERVAL_NO_TIMEOUT);
+			PR_Unlock(tp->ioq.lock);
+			PR_ASSERT(!jobp->on_ioq);
+			if (!JOINABLE_JOB(jobp)) {
+				delete_job(jobp);
+			} else {
+				JOIN_NOTIFY(jobp);
+			}
+			rval = PR_SUCCESS;
+		} else
+			PR_Unlock(tp->ioq.lock);
+	}
+	if (PR_FAILURE == rval)
+		PR_SetError(PR_INVALID_STATE_ERROR, 0);
+	return rval;
+}
+
+/* join a job, wait until completion */
+PR_IMPLEMENT(PRStatus)
+PR_JoinJob(PRJob *jobp)
+{
+	if (!JOINABLE_JOB(jobp)) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return PR_FAILURE;
+	}
+	PR_Lock(jobp->tpool->join_lock);
+	while(jobp->join_wait)
+		PR_WaitCondVar(jobp->join_cv, PR_INTERVAL_NO_TIMEOUT);
+	PR_Unlock(jobp->tpool->join_lock);
+	delete_job(jobp);
+	return PR_SUCCESS;
+}
+
+/* shutdown threadpool */
+PR_IMPLEMENT(PRStatus)
+PR_ShutdownThreadPool(PRThreadPool *tpool)
+{
+PRStatus rval = PR_SUCCESS;
+
+	PR_Lock(tpool->jobq.lock);
+	tpool->shutdown = PR_TRUE;
+	PR_NotifyAllCondVar(tpool->shutdown_cv);
+	PR_Unlock(tpool->jobq.lock);
+
+	return rval;
+}
+
+/*
+ * join thread pool
+ * 	wait for termination of worker threads
+ *	reclaim threadpool resources
+ */
+PR_IMPLEMENT(PRStatus)
+PR_JoinThreadPool(PRThreadPool *tpool)
+{
+PRStatus rval = PR_SUCCESS;
+PRCList *head;
+PRStatus rval_status;
+
+	PR_Lock(tpool->jobq.lock);
+	while (!tpool->shutdown)
+		PR_WaitCondVar(tpool->shutdown_cv, PR_INTERVAL_NO_TIMEOUT);
+
+	/*
+	 * wakeup worker threads
+	 */
+#ifdef OPT_WINNT
+	/*
+	 * post shutdown notification for all threads
+	 */
+	{
+		int i;
+		for(i=0; i < tpool->current_threads; i++) {
+			PostQueuedCompletionStatus(tpool->jobq.nt_completion_port, 0,
+												TRUE, NULL);
+		}
+	}
+#else
+	PR_NotifyAllCondVar(tpool->jobq.cv);
+#endif
+
+	/*
+	 * wakeup io thread(s)
+	 */
+	notify_ioq(tpool);
+
+	/*
+	 * wakeup timer thread(s)
+	 */
+	PR_Lock(tpool->timerq.lock);
+	notify_timerq(tpool);
+	PR_Unlock(tpool->timerq.lock);
+
+	while (!PR_CLIST_IS_EMPTY(&tpool->jobq.wthreads)) {
+		wthread *wthrp;
+
+		head = PR_LIST_HEAD(&tpool->jobq.wthreads);
+		PR_REMOVE_AND_INIT_LINK(head);
+		PR_Unlock(tpool->jobq.lock);
+		wthrp = WTHREAD_LINKS_PTR(head);
+		rval_status = PR_JoinThread(wthrp->thread);
+		PR_ASSERT(PR_SUCCESS == rval_status);
+		PR_DELETE(wthrp);
+		PR_Lock(tpool->jobq.lock);
+	}
+	PR_Unlock(tpool->jobq.lock);
+	while (!PR_CLIST_IS_EMPTY(&tpool->ioq.wthreads)) {
+		wthread *wthrp;
+
+		head = PR_LIST_HEAD(&tpool->ioq.wthreads);
+		PR_REMOVE_AND_INIT_LINK(head);
+		wthrp = WTHREAD_LINKS_PTR(head);
+		rval_status = PR_JoinThread(wthrp->thread);
+		PR_ASSERT(PR_SUCCESS == rval_status);
+		PR_DELETE(wthrp);
+	}
+
+	while (!PR_CLIST_IS_EMPTY(&tpool->timerq.wthreads)) {
+		wthread *wthrp;
+
+		head = PR_LIST_HEAD(&tpool->timerq.wthreads);
+		PR_REMOVE_AND_INIT_LINK(head);
+		wthrp = WTHREAD_LINKS_PTR(head);
+		rval_status = PR_JoinThread(wthrp->thread);
+		PR_ASSERT(PR_SUCCESS == rval_status);
+		PR_DELETE(wthrp);
+	}
+
+	/*
+	 * Delete queued jobs
+	 */
+	while (!PR_CLIST_IS_EMPTY(&tpool->jobq.list)) {
+		PRJob *jobp;
+
+		head = PR_LIST_HEAD(&tpool->jobq.list);
+		PR_REMOVE_AND_INIT_LINK(head);
+		jobp = JOB_LINKS_PTR(head);
+		tpool->jobq.cnt--;
+		delete_job(jobp);
+	}
+
+	/* delete io jobs */
+	while (!PR_CLIST_IS_EMPTY(&tpool->ioq.list)) {
+		PRJob *jobp;
+
+		head = PR_LIST_HEAD(&tpool->ioq.list);
+		PR_REMOVE_AND_INIT_LINK(head);
+		tpool->ioq.cnt--;
+		jobp = JOB_LINKS_PTR(head);
+		delete_job(jobp);
+	}
+
+	/* delete timer jobs */
+	while (!PR_CLIST_IS_EMPTY(&tpool->timerq.list)) {
+		PRJob *jobp;
+
+		head = PR_LIST_HEAD(&tpool->timerq.list);
+		PR_REMOVE_AND_INIT_LINK(head);
+		tpool->timerq.cnt--;
+		jobp = JOB_LINKS_PTR(head);
+		delete_job(jobp);
+	}
+
+	PR_ASSERT(0 == tpool->jobq.cnt);
+	PR_ASSERT(0 == tpool->ioq.cnt);
+	PR_ASSERT(0 == tpool->timerq.cnt);
+
+	delete_threadpool(tpool);
+	return rval;
+}
diff --git a/mozilla/nsprpub/pr/src/misc/prtrace.c b/mozilla/nsprpub/pr/src/misc/prtrace.c
new file mode 100644
index 0000000..762dd82
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/misc/prtrace.c
@@ -0,0 +1,920 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** prtrace.c -- NSPR Trace Instrumentation
+**
+** Implement the API defined in prtrace.h
+**
+**
+**
+*/
+
+#include <string.h>
+#include "primpl.h"
+
+
+#define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 )
+#define DEFAULT_BUFFER_SEGMENTS    2
+
+/*
+** Enumerate states in a RName structure
+*/
+typedef enum TraceState
+{
+    Running = 1,
+    Suspended = 2
+} TraceState;
+
+/*
+** Define QName structure
+*/
+typedef struct QName
+{
+    PRCList link;
+    PRCList rNameList;
+    char    name[PRTRACE_NAME_MAX+1];
+} QName;
+
+/*
+** Define RName structure
+*/
+typedef struct RName
+{
+    PRCList link;
+    PRLock  *lock;
+    QName   *qName;
+    TraceState state;
+    char    name[PRTRACE_NAME_MAX+1];
+    char    desc[PRTRACE_DESC_MAX+1];
+} RName;
+
+
+/*
+** The Trace Facility database
+**
+*/
+static PRLogModuleInfo *lm;
+
+static PRLock      *traceLock;      /* Facility Lock */
+static PRCList     qNameList;       /* anchor to all QName structures */
+static TraceState traceState = Running;
+
+/*
+** in-memory trace buffer controls
+*/
+static  PRTraceEntry    *tBuf;      /* pointer to buffer */
+static  PRInt32         bufSize;    /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */
+static  volatile PRInt32  next;     /* index to next PRTraceEntry */
+static  PRInt32         last;       /* index of highest numbered trace entry */
+
+/*
+** Real-time buffer capture controls
+*/
+static PRInt32 fetchLastSeen = 0;
+static PRBool  fetchLostData = PR_FALSE;
+
+/*
+** Buffer write-to-file controls
+*/
+static  PRLock      *logLock;               /* Sync lock */
+static  PRCondVar   *logCVar;               /* Sync Condidtion Variable */
+/*
+** Inter-thread state communication.
+** Controling thread writes to logOrder under protection of logCVar
+** the logging thread reads logOrder and sets logState on Notify.
+** 
+** logSegments, logCount, logLostData must be read and written under
+** protection of logLock, logCVar.
+** 
+*/
+static  enum LogState
+{
+    LogNotRunning,  /* Initial state */
+    LogReset,       /* Causes logger to re-calc controls */
+    LogActive,      /* Logging in progress, set only by log thread */
+    LogSuspend,     /* Suspend Logging */ 
+    LogResume,      /* Resume Logging => LogActive */ 
+    LogStop         /* Stop the log thread */
+}   logOrder, logState, localState;         /* controlling state variables */
+static  PRInt32     logSegments;            /* Number of buffer segments */
+static  PRInt32     logEntries;             /* number of Trace Entries in the buffer */
+static  PRInt32     logEntriesPerSegment;   /* number of PRTraceEntries per buffer segment */
+static  PRInt32     logSegSize;             /* size of buffer segment */
+static  PRInt32     logCount;               /* number of segments pending output */
+static  PRInt32     logLostData;            /* number of lost log buffer segments */
+
+/*
+** end Trace Database
+**
+*/
+
+/*
+** _PR_InitializeTrace() -- Initialize the trace facility
+*/
+static void NewTraceBuffer( PRInt32 size )
+{
+    /*
+    ** calculate the size of the buffer
+    ** round down so that each segment has the same number of
+    ** trace entries
+    */
+    logSegments = DEFAULT_BUFFER_SEGMENTS;
+    logEntries = size / sizeof(PRTraceEntry);
+    logEntriesPerSegment = logEntries / logSegments;
+    logEntries = logSegments * logEntriesPerSegment;
+    bufSize = logEntries * sizeof(PRTraceEntry);
+    logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry);
+    PR_ASSERT( bufSize != 0);
+    PR_LOG( lm, PR_LOG_ERROR,
+        ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld",
+            logSegments, logEntries, logEntriesPerSegment, logSegSize ));
+
+
+    tBuf = PR_Malloc( bufSize );
+    if ( tBuf == NULL )
+    {
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("PRTrace: Failed to get trace buffer"));
+        PR_ASSERT( 0 );
+    } 
+    else
+    {
+        PR_LOG( lm, PR_LOG_NOTICE,
+            ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf));
+    }
+
+    next = 0;
+    last = logEntries -1;
+    logCount = 0;
+    logLostData = PR_TRUE; /* not really on first call */
+    logOrder = LogReset;
+
+} /* end NewTraceBuffer() */
+
+/*
+** _PR_InitializeTrace() -- Initialize the trace facility
+*/
+static void _PR_InitializeTrace( void )
+{
+    /* The lock pointer better be null on this call */
+    PR_ASSERT( traceLock == NULL );
+
+    traceLock = PR_NewLock();
+    PR_ASSERT( traceLock != NULL );
+
+    PR_Lock( traceLock );
+    
+    PR_INIT_CLIST( &qNameList );
+
+    lm = PR_NewLogModule("trace");
+
+    bufSize = DEFAULT_TRACE_BUFSIZE;
+    NewTraceBuffer( bufSize );
+
+    /* Initialize logging controls */
+    logLock = PR_NewLock();
+    logCVar = PR_NewCondVar( logLock );
+
+    PR_Unlock( traceLock );
+    return;    
+} /* end _PR_InitializeTrace() */
+
+/*
+** Create a Trace Handle
+*/
+PR_IMPLEMENT(PRTraceHandle)
+	PR_CreateTrace( 
+    	const char *qName,          /* QName for this trace handle */
+	    const char *rName,          /* RName for this trace handle */
+	    const char *description     /* description for this trace handle */
+)
+{
+    QName   *qnp;
+    RName   *rnp;
+    PRBool  matchQname = PR_FALSE;
+
+    /* Self initialize, if necessary */
+    if ( traceLock == NULL )
+        _PR_InitializeTrace();
+
+    /* Validate input arguments */
+    PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX );
+    PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX );
+    PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX );
+
+    PR_LOG( lm, PR_LOG_DEBUG,
+            ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName));
+
+    /* Lock the Facility */
+    PR_Lock( traceLock );
+
+    /* Do we already have a matching QName? */
+    if (!PR_CLIST_IS_EMPTY( &qNameList ))
+    {
+        qnp = (QName *) PR_LIST_HEAD( &qNameList );
+        do {
+            if ( strcmp(qnp->name, qName) == 0)
+            {
+                matchQname = PR_TRUE;
+                break;
+            }
+            qnp = (QName *)PR_NEXT_LINK( &qnp->link );
+        } while( qnp != (QName *)PR_LIST_HEAD( &qNameList ));
+    }
+    /*
+    ** If we did not find a matching QName,
+    **    allocate one and initialize it.
+    **    link it onto the qNameList.
+    **
+    */
+    if ( matchQname != PR_TRUE )
+    {
+        qnp = PR_NEWZAP( QName );
+        PR_ASSERT( qnp != NULL );
+        PR_INIT_CLIST( &qnp->link ); 
+        PR_INIT_CLIST( &qnp->rNameList ); 
+        strcpy( qnp->name, qName );
+        PR_APPEND_LINK( &qnp->link, &qNameList ); 
+    }
+
+    /* Do we already have a matching RName? */
+    if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
+    {
+        rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
+        do {
+            /*
+            ** No duplicate RNames are allowed within a QName
+            **
+            */
+            PR_ASSERT( strcmp(rnp->name, rName));
+            rnp = (RName *)PR_NEXT_LINK( &rnp->link );
+        } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList ));
+    }
+
+    /* Get a new RName structure; initialize its members */
+    rnp = PR_NEWZAP( RName );
+    PR_ASSERT( rnp != NULL );
+    PR_INIT_CLIST( &rnp->link );
+    strcpy( rnp->name, rName );
+    strcpy( rnp->desc, description );
+    rnp->lock = PR_NewLock();
+    rnp->state = Running;
+    if ( rnp->lock == NULL )
+    {
+        PR_ASSERT(0);
+    }
+
+    PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */    
+    rnp->qName = qnp;                       /* point the RName to the QName */
+
+    /* Unlock the Facility */
+    PR_Unlock( traceLock );
+    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t",
+        qName, qnp, rName, rnp ));
+
+    return((PRTraceHandle)rnp);
+} /* end  PR_CreateTrace() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_DestroyTrace( 
+		PRTraceHandle handle    /* Handle to be destroyed */
+)
+{
+    RName   *rnp = (RName *)handle;
+    QName   *qnp = rnp->qName;
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", 
+        qnp->name, rnp->name));
+
+    /* Lock the Facility */
+    PR_Lock( traceLock );
+
+    /*
+    ** Remove RName from the list of RNames in QName
+    ** and free RName
+    */
+    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", 
+        rnp->name, rnp));
+    PR_REMOVE_LINK( &rnp->link );
+    PR_Free( rnp->lock );
+    PR_DELETE( rnp );
+
+    /*
+    ** If this is the last RName within QName
+    **   remove QName from the qNameList and free it
+    */
+    if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
+    {
+        PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", 
+            qnp->name, qnp));
+        PR_REMOVE_LINK( &qnp->link );
+        PR_DELETE( qnp );
+    } 
+
+    /* Unlock the Facility */
+    PR_Unlock( traceLock );
+    return;
+} /* end PR_DestroyTrace()  */
+
+/*
+** Create a TraceEntry in the trace buffer
+*/
+PR_IMPLEMENT(void) 
+	PR_Trace( 
+    	PRTraceHandle handle,       /* use this trace handle */
+	    PRUint32    userData0,      /* User supplied data word 0 */
+	    PRUint32    userData1,      /* User supplied data word 1 */
+	    PRUint32    userData2,      /* User supplied data word 2 */
+	    PRUint32    userData3,      /* User supplied data word 3 */
+	    PRUint32    userData4,      /* User supplied data word 4 */
+	    PRUint32    userData5,      /* User supplied data word 5 */
+	    PRUint32    userData6,      /* User supplied data word 6 */
+	    PRUint32    userData7       /* User supplied data word 7 */
+)
+{
+    PRTraceEntry   *tep;
+    PRInt32         mark;
+
+    if ( (traceState == Suspended ) 
+        || ( ((RName *)handle)->state == Suspended )) 
+        return;
+
+    /*
+    ** Get the next trace entry slot w/ minimum delay
+    */
+    PR_Lock( traceLock );
+
+    tep = &tBuf[next++]; 
+    if ( next > last )
+        next = 0;
+    if ( fetchLostData == PR_FALSE && next == fetchLastSeen )
+        fetchLostData = PR_TRUE;
+    
+    mark = next;
+        
+    PR_Unlock( traceLock );
+
+    /*
+    ** We have a trace entry. Fill it in.
+    */
+    tep->thread = PR_GetCurrentThread();
+    tep->handle = handle;
+    tep->time   = PR_Now();
+    tep->userData[0] = userData0;
+    tep->userData[1] = userData1;
+    tep->userData[2] = userData2;
+    tep->userData[3] = userData3;
+    tep->userData[4] = userData4;
+    tep->userData[5] = userData5;
+    tep->userData[6] = userData6;
+    tep->userData[7] = userData7;
+
+    /* When buffer segment is full, signal trace log thread to run */
+    if (( mark % logEntriesPerSegment) == 0 )
+    {
+        PR_Lock( logLock );
+        logCount++;
+        PR_NotifyCondVar( logCVar );
+        PR_Unlock( logLock );
+        /*
+        ** Gh0D! This is awful!
+        ** Anyway, to minimize lost trace data segments,
+        ** I inserted the PR_Sleep(0) to cause a context switch
+        ** so that the log thread could run.
+        ** I know, it perturbs the universe and may cause
+        ** funny things to happen in the optimized builds.
+        ** Take it out, lose data; leave it in risk Heisenberg.
+        */
+        /* PR_Sleep(0); */
+    }
+
+    return;
+} /* end PR_Trace() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_SetTraceOption( 
+	    PRTraceOption command,  /* One of the enumerated values */
+	    void *value             /* command value or NULL */
+)
+{
+    RName * rnp;
+
+    switch ( command )
+    {
+        case PRTraceBufSize :
+            PR_Lock( traceLock );
+            PR_Free( tBuf );
+            bufSize = *(PRInt32 *)value;
+            NewTraceBuffer( bufSize );
+            PR_Unlock( traceLock );
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize));
+            break;
+        
+        case PRTraceEnable :
+            rnp = *(RName **)value;
+            rnp->state = Running;
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceEnable: %p", rnp));
+            break;
+        
+        case PRTraceDisable :
+            rnp = *(RName **)value;
+            rnp->state = Suspended;
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceDisable: %p", rnp));
+            break;
+        
+        case PRTraceSuspend :
+            traceState = Suspended;
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceSuspend"));
+            break;
+        
+        case PRTraceResume :
+            traceState = Running;
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceResume"));
+            break;
+        
+        case PRTraceSuspendRecording :
+            PR_Lock( logLock );
+            logOrder = LogSuspend;
+            PR_NotifyCondVar( logCVar );
+            PR_Unlock( logLock );
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceSuspendRecording"));
+            break;
+        
+        case PRTraceResumeRecording :
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceResumeRecording"));
+            if ( logState != LogSuspend )
+                break;
+            PR_Lock( logLock );
+            logOrder = LogResume;
+            PR_NotifyCondVar( logCVar );
+            PR_Unlock( logLock );
+            break;
+        
+        case PRTraceStopRecording :
+            PR_Lock( logLock );
+            logOrder = LogStop;
+            PR_NotifyCondVar( logCVar );
+            PR_Unlock( logLock );
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceStopRecording"));
+            break;
+
+        case PRTraceLockHandles :
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceLockTraceHandles"));
+            PR_Lock( traceLock );
+            break;
+        
+        case PRTraceUnLockHandles :
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRSetTraceOption: PRTraceUnLockHandles"));
+            PR_Unlock( traceLock );
+            break;
+
+        default:
+            PR_LOG( lm, PR_LOG_ERROR,
+                ("PRSetTraceOption: Invalid command %ld", command ));
+            PR_ASSERT( 0 );
+            break;
+    } /* end switch() */
+    return;
+} /* end  PR_SetTraceOption() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_GetTraceOption( 
+    	PRTraceOption command,  /* One of the enumerated values */
+	    void *value             /* command value or NULL */
+)
+{
+    switch ( command )
+    {
+        case PRTraceBufSize :
+            *((PRInt32 *)value) = bufSize;
+            PR_LOG( lm, PR_LOG_DEBUG,
+                ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize ));
+            break;
+        
+        default:
+            PR_LOG( lm, PR_LOG_ERROR,
+                ("PRGetTraceOption: Invalid command %ld", command ));
+            PR_ASSERT( 0 );
+            break;
+    } /* end switch() */
+    return;
+} /* end PR_GetTraceOption() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRTraceHandle) 
+	PR_GetTraceHandleFromName( 
+    	const char *qName,      /* QName search argument */
+        const char *rName       /* RName search argument */
+)
+{
+    const char    *qn, *rn, *desc;
+    PRTraceHandle     qh, rh = NULL;
+    RName   *rnp = NULL;
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t"
+        "QName: %s, RName: %s", qName, rName ));
+
+    qh = PR_FindNextTraceQname( NULL );
+    while (qh != NULL)
+    {
+        rh = PR_FindNextTraceRname( NULL, qh );
+        while ( rh != NULL )
+        {
+            PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc );
+            if ( (strcmp( qName, qn ) == 0)
+                && (strcmp( rName, rn ) == 0 ))
+            {
+                rnp = (RName *)rh;
+                goto foundIt;
+            }
+            rh = PR_FindNextTraceRname( rh, qh );
+        }
+        qh = PR_FindNextTraceQname( NULL );
+    }
+
+foundIt:
+    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
+    return(rh);
+} /* end PR_GetTraceHandleFromName() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void) 
+	PR_GetTraceNameFromHandle( 
+    	PRTraceHandle handle,       /* handle as search argument */
+	    const char **qName,         /* pointer to associated QName */
+	    const char **rName,         /* pointer to associated RName */
+    	const char **description    /* pointer to associated description */
+)
+{
+    RName   *rnp = (RName *)handle;
+    QName   *qnp = rnp->qName;
+
+    *qName = qnp->name;
+    *rName = rnp->name;
+    *description = rnp->desc;
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: "
+        "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 
+        qnp, rnp, qnp->name, rnp->name, rnp->desc ));
+
+    return;
+} /* end PR_GetTraceNameFromHandle() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRTraceHandle) 
+	PR_FindNextTraceQname( 
+        PRTraceHandle handle
+)
+{
+    QName *qnp = (QName *)handle;
+
+    if ( PR_CLIST_IS_EMPTY( &qNameList ))
+            qnp = NULL;
+    else if ( qnp == NULL )
+        qnp = (QName *)PR_LIST_HEAD( &qNameList );
+    else if ( PR_NEXT_LINK( &qnp->link ) ==  &qNameList )
+        qnp = NULL;
+    else  
+        qnp = (QName *)PR_NEXT_LINK( &qnp->link );
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", 
+        handle, qnp ));
+
+    return((PRTraceHandle)qnp);
+} /* end PR_FindNextTraceQname() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRTraceHandle) 
+	PR_FindNextTraceRname( 
+        PRTraceHandle rhandle,
+        PRTraceHandle qhandle
+)
+{
+    RName *rnp = (RName *)rhandle;
+    QName *qnp = (QName *)qhandle;
+
+
+    if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
+        rnp = NULL;
+    else if ( rnp == NULL )
+        rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
+    else if ( PR_NEXT_LINK( &rnp->link ) ==  &qnp->rNameList )
+        rnp = NULL;
+    else
+        rnp = (RName *)PR_NEXT_LINK( &rnp->link );
+
+    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 
+        rhandle, qhandle, rnp ));
+
+    return((PRTraceHandle)rnp);
+} /* end PR_FindNextTraceRname() */
+    
+/*
+**
+*/
+static PRFileDesc * InitializeRecording( void )
+{
+    char    *logFileName;
+    PRFileDesc  *logFile;
+
+    /* Self initialize, if necessary */
+    if ( traceLock == NULL )
+        _PR_InitializeTrace();
+
+    PR_LOG( lm, PR_LOG_DEBUG,
+        ("PR_RecordTraceEntries: begins"));
+
+    logLostData = 0; /* reset at entry */
+    logState = LogReset;
+
+#ifdef XP_UNIX
+    if ((getuid() != geteuid()) || (getgid() != getegid())) {
+        return NULL;
+    }
+#endif /* XP_UNIX */
+
+    /* Get the filename for the logfile from the environment */
+    logFileName = PR_GetEnv( "NSPR_TRACE_LOG" );
+    if ( logFileName == NULL )
+    {
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("RecordTraceEntries: Environment variable not defined. Exiting"));
+        return NULL;
+    }
+    
+    /* Open the logfile */
+    logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 );
+    if ( logFile == NULL )
+    {
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", 
+		logFileName, PR_GetOSError()));
+        return NULL;
+    }
+    return logFile;
+} /* end InitializeRecording() */
+
+/*
+**
+*/
+static void ProcessOrders( void )
+{
+    switch ( logOrder )
+    {
+    case LogReset :
+        logOrder = logState = localState;
+        PR_LOG( lm, PR_LOG_DEBUG,
+            ("RecordTraceEntries: LogReset"));
+        break;
+
+    case LogSuspend :
+        localState = logOrder = logState = LogSuspend;
+        PR_LOG( lm, PR_LOG_DEBUG,
+            ("RecordTraceEntries: LogSuspend"));
+        break;
+
+    case LogResume :
+        localState = logOrder = logState = LogActive;
+        PR_LOG( lm, PR_LOG_DEBUG,
+            ("RecordTraceEntries: LogResume"));
+        break;
+
+    case LogStop :
+        logOrder = logState = LogStop;
+        PR_LOG( lm, PR_LOG_DEBUG,
+            ("RecordTraceEntries: LogStop"));
+        break;
+
+    default :
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("RecordTraceEntries: Invalid logOrder: %ld", logOrder ));
+        PR_ASSERT( 0 );
+        break;
+    } /* end switch() */
+    return ;
+} /* end ProcessOrders() */
+
+/*
+**
+*/
+static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount )
+{
+    PRInt32 rc;
+
+
+    PR_LOG( lm, PR_LOG_ERROR,
+        ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount));
+    rc = PR_Write( logFile, buf , amount );
+    if ( rc == -1 )
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() ));
+    else if ( rc != amount )
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc));
+    else 
+        PR_LOG( lm, PR_LOG_DEBUG,
+            ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount));
+
+    return;
+} /* end WriteTraceSegment() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void)
+	PR_RecordTraceEntries(
+        void 
+)
+{
+    PRFileDesc  *logFile;
+    PRInt32     lostSegments;
+    PRInt32     currentSegment = 0;
+    void        *buf;
+    PRBool      doWrite;
+
+    logFile = InitializeRecording();
+    if ( logFile == NULL )
+    {
+        PR_LOG( lm, PR_LOG_DEBUG,
+            ("PR_RecordTraceEntries: Failed to initialize"));
+        return;
+    }
+
+    /* Do this until told to stop */
+    while ( logState != LogStop )
+    {
+
+        PR_Lock( logLock );
+
+        while ( (logCount == 0) && ( logOrder == logState ) )
+            PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT );
+
+        /* Handle state transitions */
+        if ( logOrder != logState )
+            ProcessOrders();
+
+        /* recalculate local controls */
+        if ( logCount )
+        {
+            lostSegments = logCount - logSegments;
+            if ( lostSegments > 0 )
+            {
+                logLostData += ( logCount - logSegments );
+                logCount = (logCount % logSegments);
+                currentSegment = logCount;
+                PR_LOG( lm, PR_LOG_DEBUG,
+                    ("PR_RecordTraceEntries: LostData segments: %ld", logLostData));
+            }
+            else
+            {
+                logCount--;
+            }
+
+            buf = tBuf + ( logEntriesPerSegment * currentSegment );
+            if (++currentSegment >= logSegments )
+                currentSegment = 0;
+            doWrite = PR_TRUE;
+        }
+        else
+            doWrite = PR_FALSE;
+
+        PR_Unlock( logLock );
+
+        if ( doWrite == PR_TRUE )
+        {
+            if ( localState != LogSuspend )
+                WriteTraceSegment( logFile, buf, logSegSize );
+            else
+                PR_LOG( lm, PR_LOG_DEBUG,
+                    ("RecordTraceEntries: PR_Write(): is suspended" ));
+        }
+
+    } /* end while(logState...) */
+
+    PR_Close( logFile );
+    PR_LOG( lm, PR_LOG_DEBUG,
+        ("RecordTraceEntries: exiting"));
+    return;
+} /* end  PR_RecordTraceEntries() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRIntn)
+    PR_GetTraceEntries(
+        PRTraceEntry    *buffer,    /* where to write output */
+        PRInt32         count,      /* number to get */
+        PRInt32         *found      /* number you got */
+)
+{
+    PRInt32 rc; 
+    PRInt32 copied = 0;
+    
+    PR_Lock( traceLock );
+    
+    /*
+    ** Depending on where the LastSeen and Next indices are,
+    ** copy the trace buffer in one or two pieces. 
+    */
+    PR_LOG( lm, PR_LOG_ERROR,
+        ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen));
+
+    if ( fetchLastSeen <= next )
+    {
+        while (( count-- > 0 ) && (fetchLastSeen < next ))
+        {
+            *(buffer + copied++) = *(tBuf + fetchLastSeen++);
+        }
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
+    }
+    else /* copy in 2 parts */
+    {
+        while ( count-- > 0  && fetchLastSeen <= last )
+        {
+            *(buffer + copied++) = *(tBuf + fetchLastSeen++);
+        }
+        fetchLastSeen = 0;
+
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
+
+        while ( count-- > 0  && fetchLastSeen < next )
+        {
+            *(buffer + copied++) = *(tBuf + fetchLastSeen++);
+        }
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
+    }
+
+    *found = copied;
+    rc = ( fetchLostData == PR_TRUE )? 1 : 0;
+    fetchLostData = PR_FALSE;
+
+    PR_Unlock( traceLock );
+    return rc;
+} /* end PR_GetTraceEntries() */
+
+/* end prtrace.c */
diff --git a/mozilla/nsprpub/pr/src/pthreads/ptio.c b/mozilla/nsprpub/pr/src/pthreads/ptio.c
new file mode 100644
index 0000000..23f415c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/pthreads/ptio.c
@@ -0,0 +1,5005 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:   ptio.c
+** Descritpion:  Implemenation of I/O methods for pthreads
+*/
+
+#if defined(_PR_PTHREADS)
+
+#if defined(_PR_POLL_WITH_SELECT)
+#if !(defined(HPUX) && defined(_USE_BIG_FDS))
+/* set fd limit for select(), before including system header files */
+#define FD_SETSIZE (16 * 1024)
+#endif
+#endif
+
+#include <pthread.h>
+#include <string.h>  /* for memset() */
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if defined(DARWIN)
+#include <sys/utsname.h> /* for uname */
+#endif
+#if defined(SOLARIS) || defined(UNIXWARE)
+#include <sys/filio.h>  /* to pick up FIONREAD */
+#endif
+#ifdef _PR_POLL_AVAILABLE
+#include <poll.h>
+#endif
+#ifdef AIX
+/* To pick up sysconf() */
+#include <unistd.h>
+#include <dlfcn.h>  /* for dlopen */
+#else
+/* To pick up getrlimit() etc. */
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+#ifdef SOLARIS
+/*
+ * Define HAVE_SENDFILEV if the system has the sendfilev() system call.
+ * Code built this way won't run on a system without sendfilev().
+ * We can define HAVE_SENDFILEV by default when the minimum release
+ * of Solaris that NSPR supports has sendfilev().
+ */
+#ifdef HAVE_SENDFILEV
+
+#include <sys/sendfile.h>
+
+#define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
+
+#else
+
+#include <dlfcn.h>  /* for dlopen */
+
+/*
+ * Match the definitions in <sys/sendfile.h>.
+ */
+typedef struct sendfilevec {
+    int sfv_fd;       /* input fd */
+    uint_t sfv_flag;  /* flags */
+    off_t sfv_off;    /* offset to start reading from */
+    size_t sfv_len;   /* amount of data */
+} sendfilevec_t;
+
+#define SFV_FD_SELF (-2)
+
+/*
+ * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
+ */
+static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
+
+#define SOLARIS_SENDFILEV(a, b, c, d) \
+        (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
+
+#endif /* HAVE_SENDFILEV */
+#endif /* SOLARIS */
+
+/*
+ * The send_file() system call is available in AIX 4.3.2 or later.
+ * If this file is compiled on an older AIX system, it attempts to
+ * look up the send_file symbol at run time to determine whether
+ * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
+ * send_file().  On AIX 4.3.2 or later, we can safely skip this
+ * runtime function dispatching and just use the send_file based
+ * implementation.
+ */
+#ifdef AIX
+#ifdef SF_CLOSE
+#define HAVE_SEND_FILE
+#endif
+
+#ifdef HAVE_SEND_FILE
+
+#define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
+
+#else /* HAVE_SEND_FILE */
+
+/*
+ * The following definitions match those in <sys/socket.h>
+ * on AIX 4.3.2.
+ */
+
+/*
+ * Structure for the send_file() system call
+ */
+struct sf_parms {
+    /* --------- header parms ---------- */
+    void      *header_data;         /* Input/Output. Points to header buf */
+    uint_t    header_length;        /* Input/Output. Length of the header */
+    /* --------- file parms ------------ */
+    int       file_descriptor;      /* Input. File descriptor of the file */
+    unsigned long long file_size;   /* Output. Size of the file */
+    unsigned long long file_offset; /* Input/Output. Starting offset */
+    long long file_bytes;           /* Input/Output. no. of bytes to send */
+    /* --------- trailer parms --------- */
+    void      *trailer_data;        /* Input/Output. Points to trailer buf */
+    uint_t    trailer_length;       /* Input/Output. Length of the trailer */
+    /* --------- return info ----------- */
+    unsigned long long bytes_sent;  /* Output. no. of bytes sent */
+};
+
+/*
+ * Flags for the send_file() system call
+ */
+#define SF_CLOSE        0x00000001      /* close the socket after completion */
+#define SF_REUSE        0x00000002      /* reuse socket. not supported */
+#define SF_DONT_CACHE   0x00000004      /* don't apply network buffer cache */
+#define SF_SYNC_CACHE   0x00000008      /* sync/update network buffer cache */
+
+/*
+ * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
+ */
+static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
+
+#define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
+
+#endif /* HAVE_SEND_FILE */
+#endif /* AIX */
+
+#ifdef LINUX
+#include <sys/sendfile.h>
+#endif
+
+#include "primpl.h"
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
+#endif
+
+#ifdef LINUX
+/* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
+#ifndef TCP_CORK
+#define TCP_CORK 3
+#endif
+#endif
+
+#ifdef _PR_IPV6_V6ONLY_PROBE
+static PRBool _pr_ipv6_v6only_on_by_default;
+#endif
+
+#if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
+#define _PRSelectFdSetArg_t int *
+#elif defined(AIX4_1)
+#define _PRSelectFdSetArg_t void *
+#elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \
+    || defined(OSF1) || defined(SOLARIS) \
+    || defined(HPUX10_30) || defined(HPUX11) \
+    || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
+    || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
+    || defined(BSDI) || defined(NTO) || defined(DARWIN) \
+    || defined(UNIXWARE) || defined(RISCOS) || defined(SYMBIAN)
+#define _PRSelectFdSetArg_t fd_set *
+#else
+#error "Cannot determine architecture"
+#endif
+
+static PRFileDesc *pt_SetMethods(
+    PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported);
+
+static PRLock *_pr_flock_lock;  /* For PR_LockFile() etc. */
+static PRCondVar *_pr_flock_cv;  /* For PR_LockFile() etc. */
+static PRLock *_pr_rename_lock;  /* For PR_Rename() */
+
+/**************************************************************************/
+
+/* These two functions are only used in assertions. */
+#if defined(DEBUG)
+
+PRBool IsValidNetAddr(const PRNetAddr *addr)
+{
+    if ((addr != NULL)
+            && (addr->raw.family != AF_UNIX)
+            && (addr->raw.family != PR_AF_INET6)
+            && (addr->raw.family != AF_INET)) {
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
+{
+    /*
+     * The definition of the length of a Unix domain socket address
+     * is not uniform, so we don't check it.
+     */
+    if ((addr != NULL)
+            && (addr->raw.family != AF_UNIX)
+            && (PR_NETADDR_SIZE(addr) != addr_len)) {
+#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
+        /*
+         * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
+         * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
+         * field and is 28 bytes.  It is possible for socket functions
+         * to return an addr_len greater than sizeof(struct sockaddr_in6).
+         * We need to allow that.  (Bugzilla bug #77264)
+         */
+        if ((PR_AF_INET6 == addr->raw.family)
+                && (sizeof(addr->ipv6) == addr_len)) {
+            return PR_TRUE;
+        }
+#endif
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+#endif /* DEBUG */
+
+/*****************************************************************************/
+/************************* I/O Continuation machinery ************************/
+/*****************************************************************************/
+
+/*
+ * The polling interval defines the maximum amount of time that a thread
+ * might hang up before an interrupt is noticed.
+ */
+#define PT_DEFAULT_POLL_MSEC 5000
+#if defined(_PR_POLL_WITH_SELECT)
+#define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC)
+#define PT_DEFAULT_SELECT_USEC							\
+		((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)
+#endif
+
+/*
+ * pt_SockLen is the type for the length of a socket address
+ * structure, used in the address length argument to bind,
+ * connect, accept, getsockname, getpeername, etc.  Posix.1g
+ * defines this type as socklen_t.  It is size_t or int on
+ * most current systems.
+ */
+#if defined(HAVE_SOCKLEN_T) \
+    || (defined(__GLIBC__) && __GLIBC__ >= 2)
+typedef socklen_t pt_SockLen;
+#elif (defined(AIX) && !defined(AIX4_1)) 
+typedef PRSize pt_SockLen;
+#else
+typedef PRIntn pt_SockLen;
+#endif
+
+typedef struct pt_Continuation pt_Continuation;
+typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);
+
+typedef enum pr_ContuationStatus
+{
+    pt_continuation_pending,
+    pt_continuation_done
+} pr_ContuationStatus;
+
+struct pt_Continuation
+{
+    /* The building of the continuation operation */
+    ContinuationFn function;                /* what function to continue */
+    union { PRIntn osfd; } arg1;            /* #1 - the op's fd */
+    union { void* buffer; } arg2;           /* #2 - primary transfer buffer */
+    union {
+        PRSize amount;                      /* #3 - size of 'buffer', or */
+        pt_SockLen *addr_len;                  /*    - length of address */
+#ifdef HPUX11
+        /*
+         * For sendfile()
+         */
+		struct file_spec {		
+        	off_t offset;                       /* offset in file to send */
+        	size_t nbytes;                      /* length of file data to send */
+        	size_t st_size;                     /* file size */
+		} file_spec;
+#endif
+    } arg3;
+    union { PRIntn flags; } arg4;           /* #4 - read/write flags */
+    union { PRNetAddr *addr; } arg5;        /* #5 - send/recv address */
+
+#ifdef HPUX11
+    /*
+     * For sendfile()
+     */
+    int filedesc;                           /* descriptor of file to send */
+    int nbytes_to_send;                     /* size of header and file */
+#endif  /* HPUX11 */
+    
+#ifdef SOLARIS
+    /*
+     * For sendfilev()
+     */
+    int nbytes_to_send;                     /* size of header and file */
+#endif  /* SOLARIS */
+
+#ifdef LINUX
+    /*
+     * For sendfile()
+     */
+    int in_fd;                              /* descriptor of file to send */
+    off_t offset;
+    size_t count;
+#endif  /* LINUX */
+ 
+    PRIntervalTime timeout;                 /* client (relative) timeout */
+
+    PRInt16 event;                           /* flags for poll()'s events */
+
+    /*
+    ** The representation and notification of the results of the operation.
+    ** These function can either return an int return code or a pointer to
+    ** some object.
+    */
+    union { PRSize code; void *object; } result;
+
+    PRIntn syserrno;                        /* in case it failed, why (errno) */
+    pr_ContuationStatus status;             /* the status of the operation */
+};
+
+#if defined(DEBUG)
+
+PTDebug pt_debug;  /* this is shared between several modules */
+
+PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
+{
+    PTDebug stats;
+    char buffer[100];
+    PRExplodedTime tod;
+    PRInt64 elapsed, aMil;
+    stats = pt_debug;  /* a copy */
+    PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
+    (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
+
+    LL_SUB(elapsed, PR_Now(), stats.timeStarted);
+    LL_I2L(aMil, 1000000);
+    LL_DIV(elapsed, elapsed, aMil);
+    
+    if (NULL != msg) PR_fprintf(debug_out, "%s", msg);
+    PR_fprintf(
+        debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
+    PR_fprintf(
+        debug_out, "\tlocks [created: %u, destroyed: %u]\n",
+        stats.locks_created, stats.locks_destroyed);
+    PR_fprintf(
+        debug_out, "\tlocks [acquired: %u, released: %u]\n",
+        stats.locks_acquired, stats.locks_released);
+    PR_fprintf(
+        debug_out, "\tcvars [created: %u, destroyed: %u]\n",
+        stats.cvars_created, stats.cvars_destroyed);
+    PR_fprintf(
+        debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
+        stats.cvars_notified, stats.delayed_cv_deletes);
+}  /* PT_FPrintStats */
+
+#else
+
+PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
+{
+    /* do nothing */
+}  /* PT_FPrintStats */
+
+#endif  /* DEBUG */
+
+#if defined(_PR_POLL_WITH_SELECT)
+/*
+ * OSF1 and HPUX report the POLLHUP event for a socket when the
+ * shutdown(SHUT_WR) operation is called for the remote end, even though
+ * the socket is still writeable. Use select(), instead of poll(), to
+ * workaround this problem.
+ */
+static void pt_poll_now_with_select(pt_Continuation *op)
+{
+    PRInt32 msecs;
+	fd_set rd, wr, *rdp, *wrp;
+	struct timeval tv;
+	PRIntervalTime epoch, now, elapsed, remaining;
+	PRBool wait_for_remaining;
+    PRThread *self = PR_GetCurrentThread();
+    
+	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
+	PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
+
+    switch (op->timeout) {
+        case PR_INTERVAL_NO_TIMEOUT:
+			tv.tv_sec = PT_DEFAULT_SELECT_SEC;
+			tv.tv_usec = PT_DEFAULT_SELECT_USEC;
+			do
+			{
+				PRIntn rv;
+
+				if (op->event & POLLIN) {
+					FD_ZERO(&rd);
+					FD_SET(op->arg1.osfd, &rd);
+					rdp = &rd;
+				} else
+					rdp = NULL;
+				if (op->event & POLLOUT) {
+					FD_ZERO(&wr);
+					FD_SET(op->arg1.osfd, &wr);
+					wrp = &wr;
+				} else
+					wrp = NULL;
+
+				rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
+
+				if (_PT_THREAD_INTERRUPTED(self))
+				{
+					self->state &= ~PT_THREAD_ABORTED;
+					op->result.code = -1;
+					op->syserrno = EINTR;
+					op->status = pt_continuation_done;
+					return;
+				}
+
+				if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
+					continue; /* go around the loop again */
+
+				if (rv > 0)
+				{
+					PRInt16 revents = 0;
+
+					if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
+						revents |= POLLIN;
+					if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
+						revents |= POLLOUT;
+						
+					if (op->function(op, revents))
+						op->status = pt_continuation_done;
+				} else if (rv == -1) {
+					op->result.code = -1;
+					op->syserrno = errno;
+					op->status = pt_continuation_done;
+				}
+				/* else, select timed out */
+			} while (pt_continuation_done != op->status);
+			break;
+        default:
+            now = epoch = PR_IntervalNow();
+            remaining = op->timeout;
+			do
+			{
+				PRIntn rv;
+
+				if (op->event & POLLIN) {
+					FD_ZERO(&rd);
+					FD_SET(op->arg1.osfd, &rd);
+					rdp = &rd;
+				} else
+					rdp = NULL;
+				if (op->event & POLLOUT) {
+					FD_ZERO(&wr);
+					FD_SET(op->arg1.osfd, &wr);
+					wrp = &wr;
+				} else
+					wrp = NULL;
+
+    			wait_for_remaining = PR_TRUE;
+    			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
+				if (msecs > PT_DEFAULT_POLL_MSEC) {
+					wait_for_remaining = PR_FALSE;
+					msecs = PT_DEFAULT_POLL_MSEC;
+				}
+				tv.tv_sec = msecs/PR_MSEC_PER_SEC;
+				tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
+				rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
+
+				if (_PT_THREAD_INTERRUPTED(self))
+				{
+					self->state &= ~PT_THREAD_ABORTED;
+					op->result.code = -1;
+					op->syserrno = EINTR;
+					op->status = pt_continuation_done;
+					return;
+				}
+
+				if (rv > 0) {
+					PRInt16 revents = 0;
+
+					if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
+						revents |= POLLIN;
+					if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
+						revents |= POLLOUT;
+						
+					if (op->function(op, revents))
+						op->status = pt_continuation_done;
+
+				} else if ((rv == 0) ||
+						((errno == EINTR) || (errno == EAGAIN))) {
+					if (rv == 0) {	/* select timed out */
+						if (wait_for_remaining)
+							now += remaining;
+						else
+							now += PR_MillisecondsToInterval(msecs);
+					} else
+						now = PR_IntervalNow();
+					elapsed = (PRIntervalTime) (now - epoch);
+					if (elapsed >= op->timeout) {
+						op->result.code = -1;
+						op->syserrno = ETIMEDOUT;
+						op->status = pt_continuation_done;
+					} else
+						remaining = op->timeout - elapsed;
+				} else {
+					op->result.code = -1;
+					op->syserrno = errno;
+					op->status = pt_continuation_done;
+				}
+			} while (pt_continuation_done != op->status);
+            break;
+    }
+
+}  /* pt_poll_now_with_select */
+
+#endif	/* _PR_POLL_WITH_SELECT */
+
+static void pt_poll_now(pt_Continuation *op)
+{
+    PRInt32 msecs;
+	PRIntervalTime epoch, now, elapsed, remaining;
+	PRBool wait_for_remaining;
+    PRThread *self = PR_GetCurrentThread();
+    
+	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
+#if defined (_PR_POLL_WITH_SELECT)
+	/*
+ 	 * If the fd is small enough call the select-based poll operation
+	 */
+	if (op->arg1.osfd < FD_SETSIZE) {
+		pt_poll_now_with_select(op);
+		return;
+	}
+#endif
+
+    switch (op->timeout) {
+        case PR_INTERVAL_NO_TIMEOUT:
+			msecs = PT_DEFAULT_POLL_MSEC;
+			do
+			{
+				PRIntn rv;
+				struct pollfd tmp_pfd;
+
+				tmp_pfd.revents = 0;
+				tmp_pfd.fd = op->arg1.osfd;
+				tmp_pfd.events = op->event;
+
+				rv = poll(&tmp_pfd, 1, msecs);
+				
+				if (_PT_THREAD_INTERRUPTED(self))
+				{
+					self->state &= ~PT_THREAD_ABORTED;
+					op->result.code = -1;
+					op->syserrno = EINTR;
+					op->status = pt_continuation_done;
+					return;
+				}
+
+				if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
+					continue; /* go around the loop again */
+
+				if (rv > 0)
+				{
+					PRInt16 events = tmp_pfd.events;
+					PRInt16 revents = tmp_pfd.revents;
+
+					if ((revents & POLLNVAL)  /* busted in all cases */
+					|| ((events & POLLOUT) && (revents & POLLHUP)))
+						/* write op & hup */
+					{
+						op->result.code = -1;
+						if (POLLNVAL & revents) op->syserrno = EBADF;
+						else if (POLLHUP & revents) op->syserrno = EPIPE;
+						op->status = pt_continuation_done;
+					} else {
+						if (op->function(op, revents))
+							op->status = pt_continuation_done;
+					}
+				} else if (rv == -1) {
+					op->result.code = -1;
+					op->syserrno = errno;
+					op->status = pt_continuation_done;
+				}
+				/* else, poll timed out */
+			} while (pt_continuation_done != op->status);
+			break;
+        default:
+            now = epoch = PR_IntervalNow();
+            remaining = op->timeout;
+			do
+			{
+				PRIntn rv;
+				struct pollfd tmp_pfd;
+
+				tmp_pfd.revents = 0;
+				tmp_pfd.fd = op->arg1.osfd;
+				tmp_pfd.events = op->event;
+
+    			wait_for_remaining = PR_TRUE;
+    			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
+				if (msecs > PT_DEFAULT_POLL_MSEC)
+				{
+					wait_for_remaining = PR_FALSE;
+					msecs = PT_DEFAULT_POLL_MSEC;
+				}
+				rv = poll(&tmp_pfd, 1, msecs);
+				
+				if (_PT_THREAD_INTERRUPTED(self))
+				{
+					self->state &= ~PT_THREAD_ABORTED;
+					op->result.code = -1;
+					op->syserrno = EINTR;
+					op->status = pt_continuation_done;
+					return;
+				}
+
+				if (rv > 0)
+				{
+					PRInt16 events = tmp_pfd.events;
+					PRInt16 revents = tmp_pfd.revents;
+
+					if ((revents & POLLNVAL)  /* busted in all cases */
+						|| ((events & POLLOUT) && (revents & POLLHUP))) 
+											/* write op & hup */
+					{
+						op->result.code = -1;
+						if (POLLNVAL & revents) op->syserrno = EBADF;
+						else if (POLLHUP & revents) op->syserrno = EPIPE;
+						op->status = pt_continuation_done;
+					} else {
+						if (op->function(op, revents))
+						{
+							op->status = pt_continuation_done;
+						}
+					}
+				} else if ((rv == 0) ||
+						((errno == EINTR) || (errno == EAGAIN))) {
+					if (rv == 0)	/* poll timed out */
+					{
+						if (wait_for_remaining)
+							now += remaining;
+						else
+							now += PR_MillisecondsToInterval(msecs);
+					}
+					else
+						now = PR_IntervalNow();
+					elapsed = (PRIntervalTime) (now - epoch);
+					if (elapsed >= op->timeout) {
+						op->result.code = -1;
+						op->syserrno = ETIMEDOUT;
+						op->status = pt_continuation_done;
+					} else
+						remaining = op->timeout - elapsed;
+				} else {
+					op->result.code = -1;
+					op->syserrno = errno;
+					op->status = pt_continuation_done;
+				}
+			} while (pt_continuation_done != op->status);
+            break;
+    }
+
+}  /* pt_poll_now */
+
+static PRIntn pt_Continue(pt_Continuation *op)
+{
+    op->status = pt_continuation_pending;  /* set default value */
+	/*
+	 * let each thread call poll directly
+	 */
+	pt_poll_now(op);
+	PR_ASSERT(pt_continuation_done == op->status);
+    return op->result.code;
+}  /* pt_Continue */
+
+/*****************************************************************************/
+/*********************** specific continuation functions *********************/
+/*****************************************************************************/
+static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
+{
+    op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
+    if (op->syserrno != 0) {
+        op->result.code = -1;
+    } else {
+        op->result.code = 0;
+    }
+    return PR_TRUE; /* this one is cooked */
+}  /* pt_connect_cont */
+
+static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents)
+{
+    op->syserrno = 0;
+    op->result.code = accept(
+        op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
+    if (-1 == op->result.code)
+    {
+        op->syserrno = errno;
+        if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno)
+            return PR_FALSE;  /* do nothing - this one ain't finished */
+    }
+    return PR_TRUE;
+}  /* pt_accept_cont */
+
+static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents)
+{
+    /*
+     * Any number of bytes will complete the operation. It need
+     * not (and probably will not) satisfy the request. The only
+     * error we continue is EWOULDBLOCK|EAGAIN.
+     */
+    op->result.code = read(
+        op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
+    op->syserrno = errno;
+    return ((-1 == op->result.code) && 
+            (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
+        PR_FALSE : PR_TRUE;
+}  /* pt_read_cont */
+
+static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents)
+{
+    /*
+     * Any number of bytes will complete the operation. It need
+     * not (and probably will not) satisfy the request. The only
+     * error we continue is EWOULDBLOCK|EAGAIN.
+     */
+#if defined(SOLARIS)
+    if (0 == op->arg4.flags)
+        op->result.code = read(
+            op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
+    else
+        op->result.code = recv(
+            op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
+#else
+    op->result.code = recv(
+        op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
+#endif
+    op->syserrno = errno;
+    return ((-1 == op->result.code) && 
+            (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
+        PR_FALSE : PR_TRUE;
+}  /* pt_recv_cont */
+
+static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents)
+{
+    PRIntn bytes;
+#if defined(SOLARIS)
+    PRInt32 tmp_amount = op->arg3.amount;
+#endif
+    /*
+     * We want to write the entire amount out, no matter how many
+     * tries it takes. Keep advancing the buffer and the decrementing
+     * the amount until the amount goes away. Return the total bytes
+     * (which should be the original amount) when finished (or an
+     * error).
+     */
+#if defined(SOLARIS)
+retry:
+    bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
+#else
+    bytes = send(
+        op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
+#endif
+    op->syserrno = errno;
+
+#if defined(SOLARIS)
+    /*
+     * The write system call has been reported to return the ERANGE error
+     * on occasion. Try to write in smaller chunks to workaround this bug.
+     */
+    if ((bytes == -1) && (op->syserrno == ERANGE))
+    {
+        if (tmp_amount > 1)
+        {
+            tmp_amount = tmp_amount/2;  /* half the bytes */
+            goto retry;
+        }
+    }
+#endif
+
+    if (bytes >= 0)  /* this is progress */
+    {
+        char *bp = (char*)op->arg2.buffer;
+        bp += bytes;  /* adjust the buffer pointer */
+        op->arg2.buffer = bp;
+        op->result.code += bytes;  /* accumulate the number sent */
+        op->arg3.amount -= bytes;  /* and reduce the required count */
+        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
+    }
+    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
+    {
+        op->result.code = -1;
+        return PR_TRUE;
+    }
+    else return PR_FALSE;
+}  /* pt_send_cont */
+
+static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents)
+{
+    PRIntn bytes;
+    /*
+     * We want to write the entire amount out, no matter how many
+     * tries it takes. Keep advancing the buffer and the decrementing
+     * the amount until the amount goes away. Return the total bytes
+     * (which should be the original amount) when finished (or an
+     * error).
+     */
+    bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
+    op->syserrno = errno;
+    if (bytes >= 0)  /* this is progress */
+    {
+        char *bp = (char*)op->arg2.buffer;
+        bp += bytes;  /* adjust the buffer pointer */
+        op->arg2.buffer = bp;
+        op->result.code += bytes;  /* accumulate the number sent */
+        op->arg3.amount -= bytes;  /* and reduce the required count */
+        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
+    }
+    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
+    {
+        op->result.code = -1;
+        return PR_TRUE;
+    }
+    else return PR_FALSE;
+}  /* pt_write_cont */
+
+static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents)
+{
+    PRIntn bytes;
+    struct iovec *iov = (struct iovec*)op->arg2.buffer;
+    /*
+     * Same rules as write, but continuing seems to be a bit more
+     * complicated. As the number of bytes sent grows, we have to
+     * redefine the vector we're pointing at. We might have to
+     * modify an individual vector parms or we might have to eliminate
+     * a pair altogether.
+     */
+    bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
+    op->syserrno = errno;
+    if (bytes >= 0)  /* this is progress */
+    {
+        PRIntn iov_index;
+        op->result.code += bytes;  /* accumulate the number sent */
+        for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index)
+        {
+            /* how much progress did we make in the i/o vector? */
+            if (bytes < iov[iov_index].iov_len)
+            {
+                /* this element's not done yet */
+                char **bp = (char**)&(iov[iov_index].iov_base);
+                iov[iov_index].iov_len -= bytes;  /* there's that much left */
+                *bp += bytes;  /* starting there */
+                break;  /* go off and do that */
+            }
+            bytes -= iov[iov_index].iov_len;  /* that element's consumed */
+        }
+        op->arg2.buffer = &iov[iov_index];  /* new start of array */
+        op->arg3.amount -= iov_index;  /* and array length */
+        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
+    }
+    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
+    {
+        op->result.code = -1;
+        return PR_TRUE;
+    }
+    else return PR_FALSE;
+}  /* pt_writev_cont */
+
+static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents)
+{
+    PRIntn bytes = sendto(
+        op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
+        (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
+    op->syserrno = errno;
+    if (bytes >= 0)  /* this is progress */
+    {
+        char *bp = (char*)op->arg2.buffer;
+        bp += bytes;  /* adjust the buffer pointer */
+        op->arg2.buffer = bp;
+        op->result.code += bytes;  /* accumulate the number sent */
+        op->arg3.amount -= bytes;  /* and reduce the required count */
+        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
+    }
+    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
+    {
+        op->result.code = -1;
+        return PR_TRUE;
+    }
+    else return PR_FALSE;
+}  /* pt_sendto_cont */
+
+static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
+{
+    pt_SockLen addr_len = sizeof(PRNetAddr);
+    op->result.code = recvfrom(
+        op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
+        op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
+    op->syserrno = errno;
+    return ((-1 == op->result.code) && 
+            (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
+        PR_FALSE : PR_TRUE;
+}  /* pt_recvfrom_cont */
+
+#ifdef AIX
+static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
+{
+    struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
+    ssize_t rv;
+	unsigned long long saved_file_offset;
+	long long saved_file_bytes;
+
+	saved_file_offset = sf_struct->file_offset;
+	saved_file_bytes = sf_struct->file_bytes;
+	sf_struct->bytes_sent = 0;
+
+	if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
+	PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
+									sf_struct->file_size);
+    rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
+    op->syserrno = errno;
+
+    if (rv != -1) {
+        op->result.code += sf_struct->bytes_sent;
+		/*
+		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
+		 * being updated. So, 'file_bytes' is maintained by NSPR to
+		 * avoid conflict when this bug is fixed in AIX, in the future.
+		 */
+		if (saved_file_bytes != -1)
+			saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
+		sf_struct->file_bytes = saved_file_bytes;
+    } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
+        op->result.code = -1;
+    } else {
+        return PR_FALSE;
+    }
+
+    if (rv == 1) {    /* more data to send */
+        return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+#endif  /* AIX */
+
+#ifdef HPUX11
+static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
+{
+    struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
+    int count;
+
+    count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
+			op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
+    PR_ASSERT(count <= op->nbytes_to_send);
+    op->syserrno = errno;
+
+    if (count != -1) {
+        op->result.code += count;
+    } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
+        op->result.code = -1;
+    } else {
+        return PR_FALSE;
+    }
+    if (count != -1 && count < op->nbytes_to_send) {
+        if (count < hdtrl[0].iov_len) {
+			/* header not sent */
+
+            hdtrl[0].iov_base = ((char *) hdtrl[0].iov_base) + count;
+            hdtrl[0].iov_len -= count;
+
+        } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
+			/* header sent, file not sent */
+            PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
+
+            hdtrl[0].iov_base = NULL;
+            hdtrl[0].iov_len = 0;
+
+            op->arg3.file_spec.offset += file_nbytes_sent;
+            op->arg3.file_spec.nbytes -= file_nbytes_sent;
+        } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
+											hdtrl[1].iov_len)) {
+            PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
+                                         op->arg3.file_spec.nbytes);
+
+			/* header sent, file sent, trailer not sent */
+
+            hdtrl[0].iov_base = NULL;
+            hdtrl[0].iov_len = 0;
+			/*
+			 * set file offset and len so that no more file data is
+			 * sent
+			 */
+            op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
+            op->arg3.file_spec.nbytes = 0;
+
+            hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
+            hdtrl[1].iov_len -= trailer_nbytes_sent;
+		}
+        op->nbytes_to_send -= count;
+        return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+#endif  /* HPUX11 */
+
+#ifdef SOLARIS  
+static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents)
+{
+    struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer;
+    size_t xferred;
+    ssize_t count;
+
+    count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
+    op->syserrno = errno;
+    PR_ASSERT((count == -1) || (count == xferred));
+
+    if (count == -1) {
+        if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN
+                && op->syserrno != EINTR) {
+            op->result.code = -1;
+            return PR_TRUE;
+        }
+        count = xferred;
+    } else if (count == 0) {
+        /* 
+         * We are now at EOF. The file was truncated. Solaris sendfile is
+         * supposed to return 0 and no error in this case, though some versions
+         * may return -1 and EINVAL .
+         */
+        op->result.code = -1;
+        op->syserrno = 0; /* will be treated as EOF */
+        return PR_TRUE;
+    }
+    PR_ASSERT(count <= op->nbytes_to_send);
+    
+    op->result.code += count;
+    if (count < op->nbytes_to_send) {
+        op->nbytes_to_send -= count;
+
+        while (count >= vec->sfv_len) {
+            count -= vec->sfv_len;
+            vec++;
+            op->arg3.amount--;
+        }
+        PR_ASSERT(op->arg3.amount > 0);
+
+        vec->sfv_off += count;
+        vec->sfv_len -= count;
+        PR_ASSERT(vec->sfv_len > 0);
+        op->arg2.buffer = vec;
+
+        return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+#endif  /* SOLARIS */
+
+#ifdef LINUX 
+static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
+{
+    ssize_t rv;
+    off_t oldoffset;
+
+    oldoffset = op->offset;
+    rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
+    op->syserrno = errno;
+
+    if (rv == -1) {
+        if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
+            op->result.code = -1;
+            return PR_TRUE;
+        }
+        rv = 0;
+    }
+    PR_ASSERT(rv == op->offset - oldoffset);
+    op->result.code += rv;
+    if (rv < op->count) {
+        op->count -= rv;
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+#endif  /* LINUX */
+
+void _PR_InitIO(void)
+{
+#if defined(DEBUG)
+    memset(&pt_debug, 0, sizeof(PTDebug));
+    pt_debug.timeStarted = PR_Now();
+#endif
+
+    _pr_flock_lock = PR_NewLock();
+    PR_ASSERT(NULL != _pr_flock_lock);
+    _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
+    PR_ASSERT(NULL != _pr_flock_cv);
+    _pr_rename_lock = PR_NewLock();
+    PR_ASSERT(NULL != _pr_rename_lock); 
+
+    _PR_InitFdCache();  /* do that */   
+
+    _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
+    _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
+    _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
+    PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
+
+#ifdef _PR_IPV6_V6ONLY_PROBE
+    /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
+     * is turned on by default, contrary to what RFC 3493, Section
+     * 5.3 says.  So we have to turn it off.  Find out whether we
+     * are running on such a system.
+     */
+    {
+        int osfd;
+        osfd = socket(AF_INET6, SOCK_STREAM, 0);
+        if (osfd != -1) {
+            int on;
+            int optlen = sizeof(on);
+            if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
+                    &on, &optlen) == 0) {
+                _pr_ipv6_v6only_on_by_default = on;
+            }
+            close(osfd);
+        }
+    }
+#endif
+}  /* _PR_InitIO */
+
+void _PR_CleanupIO(void)
+{
+    _PR_Putfd(_pr_stdin);
+    _pr_stdin = NULL;
+    _PR_Putfd(_pr_stdout);
+    _pr_stdout = NULL;
+    _PR_Putfd(_pr_stderr); 
+    _pr_stderr = NULL;
+
+    _PR_CleanupFdCache();
+    
+    if (_pr_flock_cv)
+    {
+        PR_DestroyCondVar(_pr_flock_cv);
+        _pr_flock_cv = NULL;
+    }
+    if (_pr_flock_lock)
+    {
+        PR_DestroyLock(_pr_flock_lock);
+        _pr_flock_lock = NULL;
+    }
+    if (_pr_rename_lock)
+    {
+        PR_DestroyLock(_pr_rename_lock);
+        _pr_rename_lock = NULL;
+    }
+}  /* _PR_CleanupIO */
+
+PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
+{
+    PRFileDesc *result = NULL;
+    PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    
+    switch (osfd)
+    {
+        case PR_StandardInput: result = _pr_stdin; break;
+        case PR_StandardOutput: result = _pr_stdout; break;
+        case PR_StandardError: result = _pr_stderr; break;
+        default:
+            (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    }
+    return result;
+}  /* PR_GetSpecialFD */
+
+/*****************************************************************************/
+/***************************** I/O private methods ***************************/
+/*****************************************************************************/
+
+static PRBool pt_TestAbort(void)
+{
+    PRThread *me = PR_GetCurrentThread();
+    if(_PT_THREAD_INTERRUPTED(me))
+    {
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        me->state &= ~PT_THREAD_ABORTED;
+        return PR_TRUE;
+    }
+    return PR_FALSE;
+}  /* pt_TestAbort */
+
+static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
+{
+    switch (syserrno)
+    {
+        case EINTR:
+            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break;
+        case ETIMEDOUT:
+            PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break;
+        default:
+            mapper(syserrno);
+    }
+}  /* pt_MapError */
+
+static PRStatus pt_Close(PRFileDesc *fd)
+{
+    if ((NULL == fd) || (NULL == fd->secret)
+        || ((_PR_FILEDESC_OPEN != fd->secret->state)
+        && (_PR_FILEDESC_CLOSED != fd->secret->state)))
+    {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    if (_PR_FILEDESC_OPEN == fd->secret->state)
+    {
+        if (-1 == close(fd->secret->md.osfd))
+        {
+#ifdef OSF1
+            /*
+             * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close()
+             * system call, when called to close a TCP socket, may
+             * return -1 with errno set to EINVAL but the system call
+             * does close the socket successfully.  An application
+             * may safely ignore the EINVAL error.  This bug is fixed
+             * on Tru64 UNIX V5.1A and later.  The defect tracking
+             * number is QAR 81431.
+             */
+            if (PR_DESC_SOCKET_TCP != fd->methods->file_type
+            || EINVAL != errno)
+            {
+                pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
+                return PR_FAILURE;
+            }
+#else
+            pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
+            return PR_FAILURE;
+#endif
+        }
+        fd->secret->state = _PR_FILEDESC_CLOSED;
+    }
+    _PR_Putfd(fd);
+    return PR_SUCCESS;
+}  /* pt_Close */
+
+static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+    PRInt32 syserrno, bytes = -1;
+
+    if (pt_TestAbort()) return bytes;
+
+    bytes = read(fd->secret->md.osfd, buf, amount);
+    syserrno = errno;
+
+    if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
+        && (!fd->secret->nonblocking))
+    {
+        pt_Continuation op;
+        op.arg1.osfd = fd->secret->md.osfd;
+        op.arg2.buffer = buf;
+        op.arg3.amount = amount;
+        op.timeout = PR_INTERVAL_NO_TIMEOUT;
+        op.function = pt_read_cont;
+        op.event = POLLIN | POLLPRI;
+        bytes = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+    if (bytes < 0)
+        pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
+    return bytes;
+}  /* pt_Read */
+
+static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+    PRInt32 syserrno, bytes = -1;
+    PRBool fNeedContinue = PR_FALSE;
+
+    if (pt_TestAbort()) return bytes;
+
+    bytes = write(fd->secret->md.osfd, buf, amount);
+    syserrno = errno;
+
+    if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
+    {
+        buf = (char *) buf + bytes;
+        amount -= bytes;
+        fNeedContinue = PR_TRUE;
+    }
+    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
+        && (!fd->secret->nonblocking) )
+    {
+        bytes = 0;
+        fNeedContinue = PR_TRUE;
+    }
+
+    if (fNeedContinue == PR_TRUE)
+    {
+        pt_Continuation op;
+        op.arg1.osfd = fd->secret->md.osfd;
+        op.arg2.buffer = (void*)buf;
+        op.arg3.amount = amount;
+        op.timeout = PR_INTERVAL_NO_TIMEOUT;
+        op.result.code = bytes;  /* initialize the number sent */
+        op.function = pt_write_cont;
+        op.event = POLLOUT | POLLPRI;
+        bytes = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+    if (bytes == -1)
+        pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
+    return bytes;
+}  /* pt_Write */
+
+static PRInt32 pt_Writev(
+    PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
+{
+    PRIntn iov_index;
+    PRBool fNeedContinue = PR_FALSE;
+    PRInt32 syserrno, bytes, rv = -1;
+    struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
+    int osiov_len;
+
+    if (pt_TestAbort()) return rv;
+
+    /* Ensured by PR_Writev */
+    PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
+
+    /*
+     * We can't pass iov to writev because PRIOVec and struct iovec
+     * may not be binary compatible.  Make osiov a copy of iov and
+     * pass osiov to writev.  We can modify osiov if we need to
+     * continue the operation.
+     */
+    osiov = osiov_local;
+    osiov_len = iov_len;
+    for (iov_index = 0; iov_index < osiov_len; iov_index++)
+    {
+        osiov[iov_index].iov_base = iov[iov_index].iov_base;
+        osiov[iov_index].iov_len = iov[iov_index].iov_len;
+    }
+
+    rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
+    syserrno = errno;
+
+    if (!fd->secret->nonblocking)
+    {
+        if (bytes >= 0)
+        {
+            /*
+             * If we moved some bytes, how does that implicate the
+             * i/o vector list?  In other words, exactly where are
+             * we within that array?  What are the parameters for
+             * resumption?  Maybe we're done!
+             */
+            for ( ;osiov_len > 0; osiov++, osiov_len--)
+            {
+                if (bytes < osiov->iov_len)
+                {
+                    /* this one's not done yet */
+                    osiov->iov_base = (char*)osiov->iov_base + bytes;
+                    osiov->iov_len -= bytes;
+                    break;  /* go off and do that */
+                }
+                bytes -= osiov->iov_len;  /* this one's done cooked */
+            }
+            PR_ASSERT(osiov_len > 0 || bytes == 0);
+            if (osiov_len > 0)
+            {
+                if (PR_INTERVAL_NO_WAIT == timeout)
+                {
+                    rv = -1;
+                    syserrno = ETIMEDOUT;
+                }
+                else fNeedContinue = PR_TRUE;
+            }
+        }
+        else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
+        {
+            if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+            else
+            {
+                rv = 0;
+                fNeedContinue = PR_TRUE;
+            }
+        }
+    }
+
+    if (fNeedContinue == PR_TRUE)
+    {
+        pt_Continuation op;
+
+        op.arg1.osfd = fd->secret->md.osfd;
+        op.arg2.buffer = (void*)osiov;
+        op.arg3.amount = osiov_len;
+        op.timeout = timeout;
+        op.result.code = rv;
+        op.function = pt_writev_cont;
+        op.event = POLLOUT | POLLPRI;
+        rv = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+    if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
+    return rv;
+}  /* pt_Writev */
+
+static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
+{
+    return _PR_MD_LSEEK(fd, offset, whence);
+}  /* pt_Seek */
+
+static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
+{
+    return _PR_MD_LSEEK64(fd, offset, whence);
+}  /* pt_Seek64 */
+
+static PRInt32 pt_Available_f(PRFileDesc *fd)
+{
+    PRInt32 result, cur, end;
+
+    cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
+
+    if (cur >= 0)
+        end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
+
+    if ((cur < 0) || (end < 0)) {
+        return -1;
+    }
+
+    result = end - cur;
+    _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
+
+    return result;
+}  /* pt_Available_f */
+
+static PRInt64 pt_Available64_f(PRFileDesc *fd)
+{
+    PRInt64 result, cur, end;
+    PRInt64 minus_one;
+
+    LL_I2L(minus_one, -1);
+    cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
+
+    if (LL_GE_ZERO(cur))
+        end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
+
+    if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
+
+    LL_SUB(result, end, cur);
+    (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
+
+    return result;
+}  /* pt_Available64_f */
+
+static PRInt32 pt_Available_s(PRFileDesc *fd)
+{
+    PRInt32 rv, bytes = -1;
+    if (pt_TestAbort()) return bytes;
+
+    rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
+
+    if (rv == -1)
+        pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
+    return bytes;
+}  /* pt_Available_s */
+
+static PRInt64 pt_Available64_s(PRFileDesc *fd)
+{
+    PRInt64 rv;
+    LL_I2L(rv, pt_Available_s(fd));
+    return rv;
+}  /* pt_Available64_s */
+
+static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info)
+{
+    PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
+    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
+}  /* pt_FileInfo */
+
+static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
+{
+    PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
+    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
+}  /* pt_FileInfo64 */
+
+static PRStatus pt_Synch(PRFileDesc *fd)
+{
+    return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
+} /* pt_Synch */
+
+static PRStatus pt_Fsync(PRFileDesc *fd)
+{
+    PRIntn rv = -1;
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    rv = fsync(fd->secret->md.osfd);
+    if (rv < 0) {
+        pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}  /* pt_Fsync */
+
+static PRStatus pt_Connect(
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PRIntn rv = -1, syserrno;
+    pt_SockLen addr_len;
+	const PRNetAddr *addrp = addr;
+#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
+	PRUint16 md_af = addr->raw.family;
+    PRNetAddr addrCopy;
+#endif
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+    addr_len = PR_NETADDR_SIZE(addr);
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		md_af = AF_INET6;
+#ifndef _PR_HAVE_SOCKADDR_LEN
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+#endif
+	}
+#endif
+
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    addrCopy = *addr;
+    ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
+    ((struct sockaddr*)&addrCopy)->sa_family = md_af;
+    addrp = &addrCopy;
+#endif
+    rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
+    syserrno = errno;
+    if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking))
+    {
+        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+        else
+        {
+            pt_Continuation op;
+            op.arg1.osfd = fd->secret->md.osfd;
+            op.arg2.buffer = (void*)addrp;
+            op.arg3.amount = addr_len;
+            op.timeout = timeout;
+            op.function = pt_connect_cont;
+            op.event = POLLOUT | POLLPRI;
+            rv = pt_Continue(&op);
+            syserrno = op.syserrno;
+        }
+    }
+    if (-1 == rv) {
+        pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}  /* pt_Connect */
+
+static PRStatus pt_ConnectContinue(
+    PRFileDesc *fd, PRInt16 out_flags)
+{
+    int err;
+    PRInt32 osfd;
+
+    if (out_flags & PR_POLL_NVAL)
+    {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+    if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0)
+    {
+        PR_ASSERT(out_flags == 0);
+        PR_SetError(PR_IN_PROGRESS_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    osfd = fd->secret->md.osfd;
+
+    err = _MD_unix_get_nonblocking_connect_error(osfd);
+    if (err != 0)
+    {
+        _PR_MD_MAP_CONNECT_ERROR(err);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}  /* pt_ConnectContinue */
+
+PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
+{
+    /* Find the NSPR layer and invoke its connectcontinue method */
+    PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+
+    if (NULL == bottom)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    return pt_ConnectContinue(bottom, pd->out_flags);
+}  /* PR_GetConnectStatus */
+
+static PRFileDesc* pt_Accept(
+    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PRFileDesc *newfd = NULL;
+    PRIntn syserrno, osfd = -1;
+    pt_SockLen addr_len = sizeof(PRNetAddr);
+#ifdef SYMBIAN
+    PRNetAddr dummy_addr;
+#endif
+
+    if (pt_TestAbort()) return newfd;
+
+#ifdef SYMBIAN
+    /* On Symbian OS, accept crashes if addr is NULL. */
+    if (!addr)
+        addr = &dummy_addr;
+#endif
+
+#ifdef _PR_STRICT_ADDR_LEN
+    if (addr)
+    {
+        /*
+         * Set addr->raw.family just so that we can use the
+         * PR_NETADDR_SIZE macro.
+         */
+        addr->raw.family = fd->secret->af;
+        addr_len = PR_NETADDR_SIZE(addr);
+    }
+#endif
+
+    osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
+    syserrno = errno;
+
+    if (osfd == -1)
+    {
+        if (fd->secret->nonblocking) goto failed;
+
+        if (EWOULDBLOCK != syserrno && EAGAIN != syserrno
+        && ECONNABORTED != syserrno)
+            goto failed;
+        else
+        {
+            if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+            else
+            {
+                pt_Continuation op;
+                op.arg1.osfd = fd->secret->md.osfd;
+                op.arg2.buffer = addr;
+                op.arg3.addr_len = &addr_len;
+                op.timeout = timeout;
+                op.function = pt_accept_cont;
+                op.event = POLLIN | POLLPRI;
+                osfd = pt_Continue(&op);
+                syserrno = op.syserrno;
+            }
+            if (osfd < 0) goto failed;
+        }
+    }
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    /* ignore the sa_len field of struct sockaddr */
+    if (addr)
+    {
+        addr->raw.family = ((struct sockaddr*)addr)->sa_family;
+    }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+#ifdef _PR_INET6
+	if (addr && (AF_INET6 == addr->raw.family))
+        addr->raw.family = PR_AF_INET6;
+#endif
+    newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
+    if (newfd == NULL) close(osfd);  /* $$$ whoops! this doesn't work $$$ */
+    else
+    {
+        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+        PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
+#ifdef LINUX
+        /*
+         * On Linux, experiments showed that the accepted sockets
+         * inherit the TCP_NODELAY socket option of the listening
+         * socket.
+         */
+        newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
+#endif
+    }
+    return newfd;
+
+failed:
+    pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
+    return NULL;
+}  /* pt_Accept */
+
+static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr)
+{
+    PRIntn rv;
+    pt_SockLen addr_len;
+	const PRNetAddr *addrp = addr;
+#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
+	PRUint16 md_af = addr->raw.family;
+    PRNetAddr addrCopy;
+#endif
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+    if (addr->raw.family == AF_UNIX)
+    {
+        /* Disallow relative pathnames */
+        if (addr->local.path[0] != '/')
+        {
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            return PR_FAILURE;
+        }
+    }
+
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		md_af = AF_INET6;
+#ifndef _PR_HAVE_SOCKADDR_LEN
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+#endif
+	}
+#endif
+
+    addr_len = PR_NETADDR_SIZE(addr);
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    addrCopy = *addr;
+    ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
+    ((struct sockaddr*)&addrCopy)->sa_family = md_af;
+    addrp = &addrCopy;
+#endif
+    rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
+
+    if (rv == -1) {
+        pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}  /* pt_Bind */
+
+static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog)
+{
+    PRIntn rv;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    rv = listen(fd->secret->md.osfd, backlog);
+    if (rv == -1) {
+        pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}  /* pt_Listen */
+
+static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how)
+{
+    PRIntn rv = -1;
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    rv = shutdown(fd->secret->md.osfd, how);
+
+    if (rv == -1) {
+        pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}  /* pt_Shutdown */
+
+static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+    *out_flags = 0;
+    return in_flags;
+}  /* pt_Poll */
+
+static PRInt32 pt_Recv(
+    PRFileDesc *fd, void *buf, PRInt32 amount,
+    PRIntn flags, PRIntervalTime timeout)
+{
+    PRInt32 syserrno, bytes = -1;
+    PRIntn osflags;
+
+    if (0 == flags)
+        osflags = 0;
+    else if (PR_MSG_PEEK == flags)
+    {
+#ifdef SYMBIAN
+        /* MSG_PEEK doesn't work as expected. */
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return bytes;
+#else
+        osflags = MSG_PEEK;
+#endif
+    }
+    else
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return bytes;
+    }
+
+    if (pt_TestAbort()) return bytes;
+
+    /* recv() is a much slower call on pre-2.6 Solaris than read(). */
+#if defined(SOLARIS)
+    if (0 == osflags)
+        bytes = read(fd->secret->md.osfd, buf, amount);
+    else
+        bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
+#else
+    bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
+#endif
+    syserrno = errno;
+
+    if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
+        && (!fd->secret->nonblocking))
+    {
+        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+        else
+        {
+            pt_Continuation op;
+            op.arg1.osfd = fd->secret->md.osfd;
+            op.arg2.buffer = buf;
+            op.arg3.amount = amount;
+            op.arg4.flags = osflags;
+            op.timeout = timeout;
+            op.function = pt_recv_cont;
+            op.event = POLLIN | POLLPRI;
+            bytes = pt_Continue(&op);
+            syserrno = op.syserrno;
+        }
+    }
+    if (bytes < 0)
+        pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
+    return bytes;
+}  /* pt_Recv */
+
+static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+    return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}  /* pt_SocketRead */
+
+static PRInt32 pt_Send(
+    PRFileDesc *fd, const void *buf, PRInt32 amount,
+    PRIntn flags, PRIntervalTime timeout)
+{
+    PRInt32 syserrno, bytes = -1;
+    PRBool fNeedContinue = PR_FALSE;
+#if defined(SOLARIS)
+	PRInt32 tmp_amount = amount;
+#endif
+
+    /*
+     * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
+     * which has the following:
+     *     #  define send        cma_send
+     *     extern int  cma_send (int , void *, int, int );
+     * So we need to cast away the 'const' of argument #2 for send().
+     */
+#if defined (HPUX) && defined(_PR_DCETHREADS)
+#define PT_SENDBUF_CAST (void *)
+#else
+#define PT_SENDBUF_CAST
+#endif
+
+    if (pt_TestAbort()) return bytes;
+
+    /*
+     * On pre-2.6 Solaris, send() is much slower than write().
+     * On 2.6 and beyond, with in-kernel sockets, send() and
+     * write() are fairly equivalent in performance.
+     */
+#if defined(SOLARIS)
+    PR_ASSERT(0 == flags);
+retry:
+    bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount);
+#else
+    bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
+#endif
+    syserrno = errno;
+
+#if defined(SOLARIS)
+    /*
+     * The write system call has been reported to return the ERANGE error
+     * on occasion. Try to write in smaller chunks to workaround this bug.
+     */
+    if ((bytes == -1) && (syserrno == ERANGE))
+    {
+        if (tmp_amount > 1)
+        {
+            tmp_amount = tmp_amount/2;  /* half the bytes */
+            goto retry;
+        }
+    }
+#endif
+
+    if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
+    {
+        if (PR_INTERVAL_NO_WAIT == timeout)
+        {
+            bytes = -1;
+            syserrno = ETIMEDOUT;
+        }
+        else
+        {
+            buf = (char *) buf + bytes;
+            amount -= bytes;
+            fNeedContinue = PR_TRUE;
+        }
+    }
+    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
+        && (!fd->secret->nonblocking) )
+    {
+        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+        else
+        {
+            bytes = 0;
+            fNeedContinue = PR_TRUE;
+        }
+    }
+
+    if (fNeedContinue == PR_TRUE)
+    {
+        pt_Continuation op;
+        op.arg1.osfd = fd->secret->md.osfd;
+        op.arg2.buffer = (void*)buf;
+        op.arg3.amount = amount;
+        op.arg4.flags = flags;
+        op.timeout = timeout;
+        op.result.code = bytes;  /* initialize the number sent */
+        op.function = pt_send_cont;
+        op.event = POLLOUT | POLLPRI;
+        bytes = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+    if (bytes == -1)
+        pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
+    return bytes;
+}  /* pt_Send */
+
+static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+    return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}  /* pt_SocketWrite */
+
+static PRInt32 pt_SendTo(
+    PRFileDesc *fd, const void *buf,
+    PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
+    PRIntervalTime timeout)
+{
+    PRInt32 syserrno, bytes = -1;
+    PRBool fNeedContinue = PR_FALSE;
+    pt_SockLen addr_len;
+	const PRNetAddr *addrp = addr;
+#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
+	PRUint16 md_af = addr->raw.family;
+    PRNetAddr addrCopy;
+#endif
+
+    if (pt_TestAbort()) return bytes;
+
+    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		md_af = AF_INET6;
+#ifndef _PR_HAVE_SOCKADDR_LEN
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+#endif
+	}
+#endif
+
+    addr_len = PR_NETADDR_SIZE(addr);
+#ifdef _PR_HAVE_SOCKADDR_LEN
+    addrCopy = *addr;
+    ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
+    ((struct sockaddr*)&addrCopy)->sa_family = md_af;
+    addrp = &addrCopy;
+#endif
+    bytes = sendto(
+        fd->secret->md.osfd, buf, amount, flags,
+        (struct sockaddr*)addrp, addr_len);
+    syserrno = errno;
+    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
+        && (!fd->secret->nonblocking) )
+    {
+        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+        else fNeedContinue = PR_TRUE;
+    }
+    if (fNeedContinue == PR_TRUE)
+    {
+        pt_Continuation op;
+        op.arg1.osfd = fd->secret->md.osfd;
+        op.arg2.buffer = (void*)buf;
+        op.arg3.amount = amount;
+        op.arg4.flags = flags;
+        op.arg5.addr = (PRNetAddr*)addrp;
+        op.timeout = timeout;
+        op.result.code = 0;  /* initialize the number sent */
+        op.function = pt_sendto_cont;
+        op.event = POLLOUT | POLLPRI;
+        bytes = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+    if (bytes < 0)
+        pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
+    return bytes;
+}  /* pt_SendTo */
+
+static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+    PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
+{
+    PRBool fNeedContinue = PR_FALSE;
+    PRInt32 syserrno, bytes = -1;
+    pt_SockLen addr_len = sizeof(PRNetAddr);
+
+    if (pt_TestAbort()) return bytes;
+
+    bytes = recvfrom(
+        fd->secret->md.osfd, buf, amount, flags,
+        (struct sockaddr*)addr, &addr_len);
+    syserrno = errno;
+
+    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
+        && (!fd->secret->nonblocking) )
+    {
+        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+        else fNeedContinue = PR_TRUE;
+    }
+
+    if (fNeedContinue == PR_TRUE)
+    {
+        pt_Continuation op;
+        op.arg1.osfd = fd->secret->md.osfd;
+        op.arg2.buffer = buf;
+        op.arg3.amount = amount;
+        op.arg4.flags = flags;
+        op.arg5.addr = addr;
+        op.timeout = timeout;
+        op.function = pt_recvfrom_cont;
+        op.event = POLLIN | POLLPRI;
+        bytes = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+    if (bytes >= 0)
+    {
+#ifdef _PR_HAVE_SOCKADDR_LEN
+        /* ignore the sa_len field of struct sockaddr */
+        if (addr)
+        {
+            addr->raw.family = ((struct sockaddr*)addr)->sa_family;
+        }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+#ifdef _PR_INET6
+        if (addr && (AF_INET6 == addr->raw.family))
+            addr->raw.family = PR_AF_INET6;
+#endif
+    }
+    else
+        pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
+    return bytes;
+}  /* pt_RecvFrom */
+
+#ifdef AIX
+#ifndef HAVE_SEND_FILE
+static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
+
+static void pt_aix_sendfile_init_routine(void)
+{
+    void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
+    pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file");
+    dlclose(handle);
+}
+
+/* 
+ * pt_AIXDispatchSendFile
+ */
+static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+	  PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    int rv;
+
+    rv = pthread_once(&pt_aix_sendfile_once_block,
+            pt_aix_sendfile_init_routine);
+    PR_ASSERT(0 == rv);
+    if (pt_aix_sendfile_fptr) {
+        return pt_AIXSendFile(sd, sfd, flags, timeout);
+    } else {
+        return PR_EmulateSendFile(sd, sfd, flags, timeout);
+    }
+}
+#endif /* !HAVE_SEND_FILE */
+
+
+/*
+ * pt_AIXSendFile
+ *
+ *    Send file sfd->fd across socket sd. If specified, header and trailer
+ *    buffers are sent before and after the file, respectively. 
+ *
+ *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
+ *    
+ *    return number of bytes sent or -1 on error
+ *
+ *      This implementation takes advantage of the send_file() system
+ *      call available in AIX 4.3.2.
+ */
+
+static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
+		PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    struct sf_parms sf_struct;
+    uint_t send_flags;
+    ssize_t rv;
+    int syserrno;
+    PRInt32 count;
+	unsigned long long saved_file_offset;
+	long long saved_file_bytes;
+
+    sf_struct.header_data = (void *) sfd->header;  /* cast away the 'const' */
+    sf_struct.header_length = sfd->hlen;
+    sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
+    sf_struct.file_size = 0;
+    sf_struct.file_offset = sfd->file_offset;
+    if (sfd->file_nbytes == 0)
+    	sf_struct.file_bytes = -1;
+	else
+    	sf_struct.file_bytes = sfd->file_nbytes;
+    sf_struct.trailer_data = (void *) sfd->trailer;
+    sf_struct.trailer_length = sfd->tlen;
+    sf_struct.bytes_sent = 0;
+
+	saved_file_offset = sf_struct.file_offset;
+    saved_file_bytes = sf_struct.file_bytes;
+
+    send_flags = 0;			/* flags processed at the end */
+
+    /* The first argument to send_file() is int*. */
+    PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
+    do {
+        rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
+    } while (rv == -1 && (syserrno = errno) == EINTR);
+
+    if (rv == -1) {
+        if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
+            count = 0; /* Not a real error.  Need to continue. */
+        } else {
+            count = -1;
+        }
+    } else {
+        count = sf_struct.bytes_sent;
+		/*
+		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
+		 * being updated. So, 'file_bytes' is maintained by NSPR to
+		 * avoid conflict when this bug is fixed in AIX, in the future.
+		 */
+		if (saved_file_bytes != -1)
+			saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
+		sf_struct.file_bytes = saved_file_bytes;
+    }
+
+    if ((rv == 1) || ((rv == -1) && (count == 0))) {
+        pt_Continuation op;
+
+        op.arg1.osfd = sd->secret->md.osfd;
+        op.arg2.buffer = &sf_struct;
+        op.arg4.flags = send_flags;
+        op.result.code = count;
+        op.timeout = timeout;
+        op.function = pt_aix_sendfile_cont;
+        op.event = POLLOUT | POLLPRI;
+        count = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+
+    if (count == -1) {
+        pt_MapError(_MD_aix_map_sendfile_error, syserrno);
+        return -1;
+    }
+    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
+        PR_Close(sd);
+    }
+	PR_ASSERT(count == (sfd->hlen + sfd->tlen +
+						((sfd->file_nbytes ==  0) ?
+						sf_struct.file_size - sfd->file_offset :
+						sfd->file_nbytes)));
+    return count;
+}
+#endif /* AIX */
+
+#ifdef HPUX11
+/*
+ * pt_HPUXSendFile
+ *
+ *    Send file sfd->fd across socket sd. If specified, header and trailer
+ *    buffers are sent before and after the file, respectively.
+ *
+ *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
+ *    
+ *    return number of bytes sent or -1 on error
+ *
+ *      This implementation takes advantage of the sendfile() system
+ *      call available in HP-UX B.11.00.
+ */
+
+static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
+		PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    struct stat statbuf;
+    size_t nbytes_to_send, file_nbytes_to_send;
+    struct iovec hdtrl[2];  /* optional header and trailer buffers */
+    int send_flags;
+    PRInt32 count;
+    int syserrno;
+
+    if (sfd->file_nbytes == 0) {
+        /* Get file size */
+        if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
+            _PR_MD_MAP_FSTAT_ERROR(errno);
+            return -1;
+        } 		
+        file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
+    } else {
+        file_nbytes_to_send = sfd->file_nbytes;
+    }
+    nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
+
+    hdtrl[0].iov_base = (void *) sfd->header;  /* cast away the 'const' */
+    hdtrl[0].iov_len = sfd->hlen;
+    hdtrl[1].iov_base = (void *) sfd->trailer;
+    hdtrl[1].iov_len = sfd->tlen;
+    /*
+     * SF_DISCONNECT seems to close the socket even if sendfile()
+     * only does a partial send on a nonblocking socket.  This
+     * would prevent the subsequent sendfile() calls on that socket
+     * from working.  So we don't use the SD_DISCONNECT flag.
+     */
+    send_flags = 0;
+
+    do {
+        count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
+                sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
+    } while (count == -1 && (syserrno = errno) == EINTR);
+
+    if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
+        count = 0;
+    }
+    if (count != -1 && count < nbytes_to_send) {
+        pt_Continuation op;
+
+        if (count < sfd->hlen) {
+			/* header not sent */
+
+            hdtrl[0].iov_base = ((char *) sfd->header) + count;
+            hdtrl[0].iov_len = sfd->hlen - count;
+            op.arg3.file_spec.offset = sfd->file_offset;
+            op.arg3.file_spec.nbytes = file_nbytes_to_send;
+        } else if (count < (sfd->hlen + file_nbytes_to_send)) {
+			/* header sent, file not sent */
+
+            hdtrl[0].iov_base = NULL;
+            hdtrl[0].iov_len = 0;
+
+            op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
+            op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
+        } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
+			PRUint32 trailer_nbytes_sent;
+
+			/* header sent, file sent, trailer not sent */
+
+            hdtrl[0].iov_base = NULL;
+            hdtrl[0].iov_len = 0;
+			/*
+			 * set file offset and len so that no more file data is
+			 * sent
+			 */
+            op.arg3.file_spec.offset = statbuf.st_size;
+            op.arg3.file_spec.nbytes = 0;
+
+			trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
+            hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent;
+            hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
+		}
+
+        op.arg1.osfd = sd->secret->md.osfd;
+        op.filedesc = sfd->fd->secret->md.osfd;
+        op.arg2.buffer = hdtrl;
+        op.arg3.file_spec.st_size = statbuf.st_size;
+        op.arg4.flags = send_flags;
+        op.nbytes_to_send = nbytes_to_send - count;
+        op.result.code = count;
+        op.timeout = timeout;
+        op.function = pt_hpux_sendfile_cont;
+        op.event = POLLOUT | POLLPRI;
+        count = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+
+    if (count == -1) {
+        pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
+        return -1;
+    }
+    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
+        PR_Close(sd);
+    }
+    PR_ASSERT(count == nbytes_to_send);
+    return count;
+}
+
+#endif  /* HPUX11 */
+
+#ifdef SOLARIS 
+
+/*
+ *    pt_SolarisSendFile
+ *
+ *    Send file sfd->fd across socket sd. If specified, header and trailer
+ *    buffers are sent before and after the file, respectively.
+ *
+ *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
+ *
+ *    return number of bytes sent or -1 on error
+ *
+ *    This implementation takes advantage of the sendfilev() system
+ *    call available in Solaris 8.
+ */
+
+static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+                PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    struct stat statbuf;
+    size_t nbytes_to_send, file_nbytes_to_send;	
+    struct sendfilevec sfv_struct[3];  
+    int sfvcnt = 0;	
+    size_t xferred;
+    PRInt32 count;
+    int syserrno;
+
+    if (sfd->file_nbytes == 0) {
+        /* Get file size */
+        if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
+            _PR_MD_MAP_FSTAT_ERROR(errno);
+            return -1;
+        } 		
+        file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
+    } else {
+        file_nbytes_to_send = sfd->file_nbytes;
+    }
+
+    nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
+
+    if (sfd->hlen != 0) {
+        sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
+        sfv_struct[sfvcnt].sfv_flag = 0;
+        sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header; 
+        sfv_struct[sfvcnt].sfv_len = sfd->hlen;
+        sfvcnt++;
+    }
+
+    if (file_nbytes_to_send != 0) {
+        sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
+        sfv_struct[sfvcnt].sfv_flag = 0;
+        sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
+        sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
+        sfvcnt++;
+    }
+
+    if (sfd->tlen != 0) {
+        sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
+        sfv_struct[sfvcnt].sfv_flag = 0;
+        sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer; 
+        sfv_struct[sfvcnt].sfv_len = sfd->tlen;
+        sfvcnt++;
+    }
+
+    if (0 == sfvcnt) {
+        count = 0;
+        goto done;
+    }
+   	   
+    /*
+     * Strictly speaking, we may have sent some bytes when the
+     * sendfilev() is interrupted and we should retry it from an
+     * updated offset.  We are not doing that here.
+     */
+    count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct,
+            sfvcnt, &xferred);
+
+    PR_ASSERT((count == -1) || (count == xferred));
+
+    if (count == -1) {
+        syserrno = errno;
+        if (syserrno == EINTR
+                || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
+            count = xferred;
+        }
+    } else if (count == 0) {
+        /*
+         * We are now at EOF. The file was truncated. Solaris sendfile is
+         * supposed to return 0 and no error in this case, though some versions
+         * may return -1 and EINVAL .
+         */
+        count = -1;
+        syserrno = 0;  /* will be treated as EOF */
+    }
+
+    if (count != -1 && count < nbytes_to_send) {
+        pt_Continuation op;
+        struct sendfilevec *vec = sfv_struct;
+        PRInt32 rem = count;
+
+        while (rem >= vec->sfv_len) {
+            rem -= vec->sfv_len;
+            vec++;
+            sfvcnt--;
+        }
+        PR_ASSERT(sfvcnt > 0);
+
+        vec->sfv_off += rem;
+        vec->sfv_len -= rem;
+        PR_ASSERT(vec->sfv_len > 0);
+
+        op.arg1.osfd = sd->secret->md.osfd;
+        op.arg2.buffer = vec;
+        op.arg3.amount = sfvcnt;
+        op.arg4.flags = 0;
+        op.nbytes_to_send = nbytes_to_send - count;
+        op.result.code = count;
+        op.timeout = timeout;
+        op.function = pt_solaris_sendfile_cont;
+        op.event = POLLOUT | POLLPRI;
+        count = pt_Continue(&op);
+        syserrno = op.syserrno;
+    }
+
+done:
+    if (count == -1) {
+        pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
+        return -1;
+    }
+    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
+        PR_Close(sd);
+    }
+    PR_ASSERT(count == nbytes_to_send);
+    return count;
+}
+
+#ifndef HAVE_SENDFILEV
+static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
+
+static void pt_solaris_sendfilev_init_routine(void)
+{
+    void *handle;
+    PRBool close_it = PR_FALSE;
+ 
+    /*
+     * We do not want to unload libsendfile.so.  This handle is leaked
+     * intentionally.
+     */
+    handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
+    PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
+        ("dlopen(libsendfile.so) returns %p", handle));
+
+    if (NULL == handle) {
+        /*
+         * The dlopen(0, mode) call is to allow for the possibility that
+         * sendfilev() may become part of a standard system library in a
+         * future Solaris release.
+         */
+        handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
+        PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
+            ("dlopen(0) returns %p", handle));
+        close_it = PR_TRUE;
+    }
+    pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev");
+    PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
+        ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
+    
+    if (close_it) {
+        dlclose(handle);
+    }
+}
+
+/* 
+ * pt_SolarisDispatchSendFile
+ */
+static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+	  PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    int rv;
+
+    rv = pthread_once(&pt_solaris_sendfilev_once_block,
+            pt_solaris_sendfilev_init_routine);
+    PR_ASSERT(0 == rv);
+    if (pt_solaris_sendfilev_fptr) {
+        return pt_SolarisSendFile(sd, sfd, flags, timeout);
+    } else {
+        return PR_EmulateSendFile(sd, sfd, flags, timeout);
+    }
+}
+#endif /* !HAVE_SENDFILEV */
+
+#endif  /* SOLARIS */
+
+#ifdef LINUX
+/*
+ * pt_LinuxSendFile
+ *
+ *    Send file sfd->fd across socket sd. If specified, header and trailer
+ *    buffers are sent before and after the file, respectively.
+ *
+ *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
+ *    
+ *    return number of bytes sent or -1 on error
+ *
+ *      This implementation takes advantage of the sendfile() system
+ *      call available in Linux kernel 2.2 or higher.
+ */
+
+static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+                PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    struct stat statbuf;
+    size_t file_nbytes_to_send;	
+    PRInt32 count = 0;
+    ssize_t rv;
+    int syserrno;
+    off_t offset;
+    PRBool tcp_cork_enabled = PR_FALSE;
+    int tcp_cork;
+
+    if (sfd->file_nbytes == 0) {
+        /* Get file size */
+        if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
+            _PR_MD_MAP_FSTAT_ERROR(errno);
+            return -1;
+        } 		
+        file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
+    } else {
+        file_nbytes_to_send = sfd->file_nbytes;
+    }
+
+    if ((sfd->hlen != 0 || sfd->tlen != 0)
+            && sd->secret->md.tcp_nodelay == 0) {
+        tcp_cork = 1;
+        if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
+                &tcp_cork, sizeof tcp_cork) == 0) {
+            tcp_cork_enabled = PR_TRUE;
+        } else {
+            syserrno = errno;
+            if (syserrno != EINVAL) {
+                _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
+                return -1;
+            }
+            /*
+             * The most likely reason for the EINVAL error is that
+             * TCP_NODELAY is set (with a function other than
+             * PR_SetSocketOption).  This is not fatal, so we keep
+             * on going.
+             */
+            PR_LOG(_pr_io_lm, PR_LOG_WARNING,
+                ("pt_LinuxSendFile: "
+                "setsockopt(TCP_CORK) failed with EINVAL\n"));
+        }
+    }
+
+    if (sfd->hlen != 0) {
+        count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
+        if (count == -1) {
+            goto failed;
+        }
+    }
+
+    if (file_nbytes_to_send != 0) {
+        offset = sfd->file_offset;
+        do {
+            rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
+                &offset, file_nbytes_to_send);
+        } while (rv == -1 && (syserrno = errno) == EINTR);
+        if (rv == -1) {
+            if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
+                _MD_linux_map_sendfile_error(syserrno);
+                count = -1;
+                goto failed;
+            }
+            rv = 0;
+        }
+        PR_ASSERT(rv == offset - sfd->file_offset);
+        count += rv;
+
+        if (rv < file_nbytes_to_send) {
+            pt_Continuation op;
+
+            op.arg1.osfd = sd->secret->md.osfd;
+            op.in_fd = sfd->fd->secret->md.osfd;
+            op.offset = offset;
+            op.count = file_nbytes_to_send - rv;
+            op.result.code = count;
+            op.timeout = timeout;
+            op.function = pt_linux_sendfile_cont;
+            op.event = POLLOUT | POLLPRI;
+            count = pt_Continue(&op);
+            syserrno = op.syserrno;
+            if (count == -1) {
+                pt_MapError(_MD_linux_map_sendfile_error, syserrno);
+                goto failed;
+            }
+        }
+    }
+
+    if (sfd->tlen != 0) {
+        rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
+        if (rv == -1) {
+            count = -1;
+            goto failed;
+        }
+        count += rv;
+    }
+
+failed:
+    if (tcp_cork_enabled) {
+        tcp_cork = 0;
+        if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
+                &tcp_cork, sizeof tcp_cork) == -1 && count != -1) {
+            _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
+            count = -1;
+        }
+    }
+    if (count != -1) {
+        if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
+            PR_Close(sd);
+        }
+        PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
+    }
+    return count;
+}
+#endif  /* LINUX */
+
+#ifdef AIX
+extern	int _pr_aix_send_file_use_disabled;
+#endif
+
+static PRInt32 pt_SendFile(
+    PRFileDesc *sd, PRSendFileData *sfd,
+    PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+    if (pt_TestAbort()) return -1;
+    /* The socket must be in blocking mode. */
+    if (sd->secret->nonblocking)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return -1;
+    }
+#ifdef HPUX11
+    return(pt_HPUXSendFile(sd, sfd, flags, timeout));
+#elif defined(AIX)
+#ifdef HAVE_SEND_FILE
+	/*
+	 * A bug in AIX 4.3.2 results in corruption of data transferred by
+	 * send_file(); AIX patch PTF U463956 contains the fix.  A user can
+	 * disable the use of send_file function in NSPR, when this patch is
+	 * not installed on the system, by setting the envionment variable
+	 * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
+	 */
+	if (_pr_aix_send_file_use_disabled)
+		return(PR_EmulateSendFile(sd, sfd, flags, timeout));
+	else
+    	return(pt_AIXSendFile(sd, sfd, flags, timeout));
+#else
+	return(PR_EmulateSendFile(sd, sfd, flags, timeout));
+    /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
+#endif /* HAVE_SEND_FILE */
+#elif defined(SOLARIS)
+#ifdef HAVE_SENDFILEV
+    	return(pt_SolarisSendFile(sd, sfd, flags, timeout));
+#else
+	return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
+#endif /* HAVE_SENDFILEV */
+#elif defined(LINUX)
+    	return(pt_LinuxSendFile(sd, sfd, flags, timeout));
+#else
+	return(PR_EmulateSendFile(sd, sfd, flags, timeout));
+#endif
+}
+
+static PRInt32 pt_TransmitFile(
+    PRFileDesc *sd, PRFileDesc *fd, const void *headers,
+    PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+	PRSendFileData sfd;
+
+	sfd.fd = fd;
+	sfd.file_offset = 0;
+	sfd.file_nbytes = 0;
+	sfd.header = headers;
+	sfd.hlen = hlen;
+	sfd.trailer = NULL;
+	sfd.tlen = 0;
+
+	return(pt_SendFile(sd, &sfd, flags, timeout));
+}  /* pt_TransmitFile */
+
+static PRInt32 pt_AcceptRead(
+    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
+    void *buf, PRInt32 amount, PRIntervalTime timeout)
+{
+    PRInt32 rv = -1;
+
+    if (pt_TestAbort()) return rv;
+    /* The socket must be in blocking mode. */
+    if (sd->secret->nonblocking)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return rv;
+    }
+
+    rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
+    return rv;
+}  /* pt_AcceptRead */
+
+static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
+{
+    PRIntn rv = -1;
+    pt_SockLen addr_len = sizeof(PRNetAddr);
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    rv = getsockname(
+        fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
+    if (rv == -1) {
+        pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
+        return PR_FAILURE;
+    } else {
+#ifdef _PR_HAVE_SOCKADDR_LEN
+        /* ignore the sa_len field of struct sockaddr */
+        if (addr)
+        {
+            addr->raw.family = ((struct sockaddr*)addr)->sa_family;
+        }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+#ifdef _PR_INET6
+		if (AF_INET6 == addr->raw.family)
+			addr->raw.family = PR_AF_INET6;
+#endif
+        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+        PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
+        return PR_SUCCESS;
+    }
+}  /* pt_GetSockName */
+
+static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
+{
+    PRIntn rv = -1;
+    pt_SockLen addr_len = sizeof(PRNetAddr);
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    rv = getpeername(
+        fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
+
+    if (rv == -1) {
+        pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
+        return PR_FAILURE;
+    } else {
+#ifdef _PR_HAVE_SOCKADDR_LEN
+        /* ignore the sa_len field of struct sockaddr */
+        if (addr)
+        {
+            addr->raw.family = ((struct sockaddr*)addr)->sa_family;
+        }
+#endif /* _PR_HAVE_SOCKADDR_LEN */
+#ifdef _PR_INET6
+		if (AF_INET6 == addr->raw.family)
+        	addr->raw.family = PR_AF_INET6;
+#endif
+        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+        PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
+        return PR_SUCCESS;
+    }
+}  /* pt_GetPeerName */
+
+static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
+{
+    PRIntn rv;
+    pt_SockLen length;
+    PRInt32 level, name;
+
+    /*
+     * PR_SockOpt_Nonblocking is a special case that does not
+     * translate to a getsockopt() call
+     */
+    if (PR_SockOpt_Nonblocking == data->option)
+    {
+        data->value.non_blocking = fd->secret->nonblocking;
+        return PR_SUCCESS;
+    }
+
+    rv = _PR_MapOptionName(data->option, &level, &name);
+    if (PR_SUCCESS == rv)
+    {
+        switch (data->option)
+        {
+            case PR_SockOpt_Linger:
+            {
+                struct linger linger;
+                length = sizeof(linger);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name, (char *) &linger, &length);
+                PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
+                data->value.linger.polarity =
+                    (linger.l_onoff) ? PR_TRUE : PR_FALSE;
+                data->value.linger.linger =
+                    PR_SecondsToInterval(linger.l_linger);
+                break;
+            }
+            case PR_SockOpt_Reuseaddr:
+            case PR_SockOpt_Keepalive:
+            case PR_SockOpt_NoDelay:
+            case PR_SockOpt_Broadcast:
+            {
+                PRIntn value;
+                length = sizeof(PRIntn);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name, (char*)&value, &length);
+                PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
+                data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
+                break;
+            }
+            case PR_SockOpt_McastLoopback:
+            {
+                PRUint8 xbool;
+                length = sizeof(xbool);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&xbool, &length);
+                PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
+                data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
+                break;
+            }
+            case PR_SockOpt_RecvBufferSize:
+            case PR_SockOpt_SendBufferSize:
+            case PR_SockOpt_MaxSegment:
+            {
+                PRIntn value;
+                length = sizeof(PRIntn);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name, (char*)&value, &length);
+                PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
+                data->value.recv_buffer_size = value;
+                break;
+            }
+            case PR_SockOpt_IpTimeToLive:
+            case PR_SockOpt_IpTypeOfService:
+            {
+                length = sizeof(PRUintn);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&data->value.ip_ttl, &length);
+                PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
+                break;
+            }
+            case PR_SockOpt_McastTimeToLive:
+            {
+                PRUint8 ttl;
+                length = sizeof(ttl);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&ttl, &length);
+                PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
+                data->value.mcast_ttl = ttl;
+                break;
+            }
+            case PR_SockOpt_AddMember:
+            case PR_SockOpt_DropMember:
+            {
+                struct ip_mreq mreq;
+                length = sizeof(mreq);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name, (char*)&mreq, &length);
+                PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
+                data->value.add_member.mcaddr.inet.ip =
+                    mreq.imr_multiaddr.s_addr;
+                data->value.add_member.ifaddr.inet.ip =
+                    mreq.imr_interface.s_addr;
+                break;
+            }
+            case PR_SockOpt_McastInterface:
+            {
+                length = sizeof(data->value.mcast_if.inet.ip);
+                rv = getsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&data->value.mcast_if.inet.ip, &length);
+                PR_ASSERT((-1 == rv)
+                    || (sizeof(data->value.mcast_if.inet.ip) == length));
+                break;
+            }
+            default:
+                PR_NOT_REACHED("Unknown socket option");
+                break;
+        }
+        if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
+    }
+    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
+}  /* pt_GetSocketOption */
+
+static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
+{
+    PRIntn rv;
+    PRInt32 level, name;
+
+    /*
+     * PR_SockOpt_Nonblocking is a special case that does not
+     * translate to a setsockopt call.
+     */
+    if (PR_SockOpt_Nonblocking == data->option)
+    {
+        fd->secret->nonblocking = data->value.non_blocking;
+        return PR_SUCCESS;
+    }
+
+    rv = _PR_MapOptionName(data->option, &level, &name);
+    if (PR_SUCCESS == rv)
+    {
+        switch (data->option)
+        {
+            case PR_SockOpt_Linger:
+            {
+                struct linger linger;
+                linger.l_onoff = data->value.linger.polarity;
+                linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
+                break;
+            }
+            case PR_SockOpt_Reuseaddr:
+            case PR_SockOpt_Keepalive:
+            case PR_SockOpt_NoDelay:
+            case PR_SockOpt_Broadcast:
+            {
+                PRIntn value = (data->value.reuse_addr) ? 1 : 0;
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&value, sizeof(PRIntn));
+#ifdef LINUX
+                /* for pt_LinuxSendFile */
+                if (name == TCP_NODELAY && rv == 0) {
+                    fd->secret->md.tcp_nodelay = value;
+                }
+#endif
+                break;
+            }
+            case PR_SockOpt_McastLoopback:
+            {
+                PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&xbool, sizeof(xbool));
+                break;
+            }
+            case PR_SockOpt_RecvBufferSize:
+            case PR_SockOpt_SendBufferSize:
+            case PR_SockOpt_MaxSegment:
+            {
+                PRIntn value = data->value.recv_buffer_size;
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&value, sizeof(PRIntn));
+                break;
+            }
+            case PR_SockOpt_IpTimeToLive:
+            case PR_SockOpt_IpTypeOfService:
+            {
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&data->value.ip_ttl, sizeof(PRUintn));
+                break;
+            }
+            case PR_SockOpt_McastTimeToLive:
+            {
+                PRUint8 ttl = data->value.mcast_ttl;
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&ttl, sizeof(ttl));
+                break;
+            }
+            case PR_SockOpt_AddMember:
+            case PR_SockOpt_DropMember:
+            {
+                struct ip_mreq mreq;
+                mreq.imr_multiaddr.s_addr =
+                    data->value.add_member.mcaddr.inet.ip;
+                mreq.imr_interface.s_addr =
+                    data->value.add_member.ifaddr.inet.ip;
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&mreq, sizeof(mreq));
+                break;
+            }
+            case PR_SockOpt_McastInterface:
+            {
+                rv = setsockopt(
+                    fd->secret->md.osfd, level, name,
+                    (char*)&data->value.mcast_if.inet.ip,
+                    sizeof(data->value.mcast_if.inet.ip));
+                break;
+            }
+            default:
+                PR_NOT_REACHED("Unknown socket option");
+                break;
+        }
+        if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
+    }
+    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
+}  /* pt_SetSocketOption */
+
+/*****************************************************************************/
+/****************************** I/O method objects ***************************/
+/*****************************************************************************/
+
+static PRIOMethods _pr_file_methods = {
+    PR_DESC_FILE,
+    pt_Close,
+    pt_Read,
+    pt_Write,
+    pt_Available_f,
+    pt_Available64_f,
+    pt_Fsync,
+    pt_Seek,
+    pt_Seek64,
+    pt_FileInfo,
+    pt_FileInfo64,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+    pt_Poll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRIOMethods _pr_pipe_methods = {
+    PR_DESC_PIPE,
+    pt_Close,
+    pt_Read,
+    pt_Write,
+    pt_Available_s,
+    pt_Available64_s,
+    pt_Synch,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+    pt_Poll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRIOMethods _pr_tcp_methods = {
+    PR_DESC_SOCKET_TCP,
+    pt_Close,
+    pt_SocketRead,
+    pt_SocketWrite,
+    pt_Available_s,
+    pt_Available64_s,
+    pt_Synch,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    pt_Writev,
+    pt_Connect,
+    pt_Accept,
+    pt_Bind,
+    pt_Listen,
+    pt_Shutdown,
+    pt_Recv,
+    pt_Send,
+    (PRRecvfromFN)_PR_InvalidInt,
+    (PRSendtoFN)_PR_InvalidInt,
+    pt_Poll,
+    pt_AcceptRead,
+    pt_TransmitFile,
+    pt_GetSockName,
+    pt_GetPeerName,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt,
+    pt_GetSocketOption,
+    pt_SetSocketOption,
+    pt_SendFile, 
+    pt_ConnectContinue,
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRIOMethods _pr_udp_methods = {
+    PR_DESC_SOCKET_UDP,
+    pt_Close,
+    pt_SocketRead,
+    pt_SocketWrite,
+    pt_Available_s,
+    pt_Available64_s,
+    pt_Synch,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    pt_Writev,
+    pt_Connect,
+    (PRAcceptFN)_PR_InvalidDesc,
+    pt_Bind,
+    pt_Listen,
+    pt_Shutdown,
+    pt_Recv,
+    pt_Send,
+    pt_RecvFrom,
+    pt_SendTo,
+    pt_Poll,
+    (PRAcceptreadFN)_PR_InvalidInt,
+    (PRTransmitfileFN)_PR_InvalidInt,
+    pt_GetSockName,
+    pt_GetPeerName,
+    (PRReservedFN)_PR_InvalidInt,
+    (PRReservedFN)_PR_InvalidInt,
+    pt_GetSocketOption,
+    pt_SetSocketOption,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRIOMethods _pr_socketpollfd_methods = {
+    (PRDescType) 0,
+    (PRCloseFN)_PR_InvalidStatus,
+    (PRReadFN)_PR_InvalidInt,
+    (PRWriteFN)_PR_InvalidInt,
+    (PRAvailableFN)_PR_InvalidInt,
+    (PRAvailable64FN)_PR_InvalidInt64,
+    (PRFsyncFN)_PR_InvalidStatus,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+	pt_Poll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+#if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
+    || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
+    || defined(AIX) || defined(FREEBSD) || defined(NETBSD) \
+    || defined(OPENBSD) || defined(BSDI) || defined(NTO) \
+    || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS) \
+    || defined(SYMBIAN)
+#define _PR_FCNTL_FLAGS O_NONBLOCK
+#else
+#error "Can't determine architecture"
+#endif
+
+/*
+ * Put a Unix file descriptor in non-blocking mode.
+ */
+static void pt_MakeFdNonblock(PRIntn osfd)
+{
+    PRIntn flags;
+    flags = fcntl(osfd, F_GETFL, 0);
+    flags |= _PR_FCNTL_FLAGS;
+    (void)fcntl(osfd, F_SETFL, flags);
+}
+
+/*
+ * Put a Unix socket fd in non-blocking mode that can
+ * ideally be inherited by an accepted socket.
+ *
+ * Why doesn't pt_MakeFdNonblock do?  This is to deal with
+ * the special case of HP-UX.  HP-UX has three kinds of
+ * non-blocking modes for sockets: the fcntl() O_NONBLOCK
+ * and O_NDELAY flags and ioctl() FIOSNBIO request.  Only
+ * the ioctl() FIOSNBIO form of non-blocking mode is
+ * inherited by an accepted socket.
+ *
+ * Other platforms just use the generic pt_MakeFdNonblock
+ * to put a socket in non-blocking mode.
+ */
+#ifdef HPUX
+static void pt_MakeSocketNonblock(PRIntn osfd)
+{
+    PRIntn one = 1;
+    (void)ioctl(osfd, FIOSNBIO, &one);
+}
+#else
+#define pt_MakeSocketNonblock pt_MakeFdNonblock
+#endif
+
+static PRFileDesc *pt_SetMethods(
+    PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
+{
+    PRFileDesc *fd = _PR_Getfd();
+    
+    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    else
+    {
+        fd->secret->md.osfd = osfd;
+        fd->secret->state = _PR_FILEDESC_OPEN;
+        if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN;
+        else
+        {
+            /* By default, a Unix fd is not closed on exec. */
+#ifdef DEBUG
+            PRIntn flags;
+            flags = fcntl(osfd, F_GETFD, 0);
+            PR_ASSERT(0 == flags);
+#endif
+            fd->secret->inheritable = _PR_TRI_TRUE;
+        }
+        switch (type)
+        {
+            case PR_DESC_FILE:
+                fd->methods = PR_GetFileMethods();
+                break;
+            case PR_DESC_SOCKET_TCP:
+                fd->methods = PR_GetTCPMethods();
+#ifdef _PR_ACCEPT_INHERIT_NONBLOCK
+                if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
+#else
+                pt_MakeSocketNonblock(osfd);
+#endif
+                break;
+            case PR_DESC_SOCKET_UDP:
+                fd->methods = PR_GetUDPMethods();
+                pt_MakeFdNonblock(osfd);
+                break;
+            case PR_DESC_PIPE:
+                fd->methods = PR_GetPipeMethods();
+                pt_MakeFdNonblock(osfd);
+                break;
+            default:
+                break;
+        }
+    }
+    return fd;
+}  /* pt_SetMethods */
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
+{
+    return &_pr_file_methods;
+}  /* PR_GetFileMethods */
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
+{
+    return &_pr_pipe_methods;
+}  /* PR_GetPipeMethods */
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
+{
+    return &_pr_tcp_methods;
+}  /* PR_GetTCPMethods */
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void)
+{
+    return &_pr_udp_methods;
+}  /* PR_GetUDPMethods */
+
+static const PRIOMethods* PR_GetSocketPollFdMethods(void)
+{
+    return &_pr_socketpollfd_methods;
+}  /* PR_GetSocketPollFdMethods */
+
+PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
+    PRInt32 osfd, const PRIOMethods *methods)
+{
+    PRFileDesc *fd = _PR_Getfd();
+
+    if (NULL == fd) goto failed;
+
+    fd->methods = methods;
+    fd->secret->md.osfd = osfd;
+    /* Make fd non-blocking */
+    if (osfd > 2)
+    {
+        /* Don't mess around with stdin, stdout or stderr */
+        if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd);
+        else pt_MakeFdNonblock(osfd);
+    }
+    fd->secret->state = _PR_FILEDESC_OPEN;
+    fd->secret->inheritable = _PR_TRI_UNKNOWN;
+    return fd;
+    
+failed:
+    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    return fd;
+}  /* PR_AllocFileDesc */
+
+#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
+PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
+#if defined(_PR_INET6_PROBE)
+extern PRBool _pr_ipv6_is_present(void);
+PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
+{
+PRInt32 osfd;
+
+#if defined(DARWIN)
+    /*
+     * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
+     * lesser versions is not ready for general use (see bug 222031).
+     */
+    {
+        struct utsname u;
+        if (uname(&u) != 0 || atoi(u.release) < 7)
+            return PR_FALSE;
+    }
+#endif
+
+    /*
+     * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
+     * suggests that we call open("/dev/ip6", O_RDWR) to determine
+     * whether IPv6 APIs and the IPv6 stack are on the system.
+     * Our portable test below seems to work fine, so I am using it.
+     */
+    osfd = socket(AF_INET6, SOCK_STREAM, 0);
+    if (osfd != -1) {
+        close(osfd);
+        return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+#endif	/* _PR_INET6_PROBE */
+#endif
+
+PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
+{
+    PRIntn osfd;
+    PRDescType ftype;
+    PRFileDesc *fd = NULL;
+	PRInt32 tmp_domain = domain;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (pt_TestAbort()) return NULL;
+
+    if (PF_INET != domain
+        && PR_AF_INET6 != domain
+        && PF_UNIX != domain)
+    {
+        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+        return fd;
+    }
+	if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
+	else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
+	else
+	{
+		(void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return fd;
+	}
+#if defined(_PR_INET6_PROBE)
+	if (PR_AF_INET6 == domain)
+		domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
+#elif defined(_PR_INET6) 
+	if (PR_AF_INET6 == domain)
+		domain = AF_INET6;
+#else
+	if (PR_AF_INET6 == domain)
+		domain = AF_INET;
+#endif
+
+    osfd = socket(domain, type, proto);
+    if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
+    else
+    {
+#ifdef _PR_IPV6_V6ONLY_PROBE
+        if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default)
+        {
+            int on = 0;
+            (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
+                    &on, sizeof(on));
+        }
+#endif
+        fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
+        if (fd == NULL) close(osfd);
+    }
+#ifdef _PR_NEED_SECRET_AF
+    if (fd != NULL) fd->secret->af = domain;
+#endif
+#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
+	if (fd != NULL) {
+		/*
+		 * For platforms with no support for IPv6 
+		 * create layered socket for IPv4-mapped IPv6 addresses
+		 */
+		if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
+			if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
+				PR_Close(fd);
+				fd = NULL;
+			}
+		}
+	}
+#endif
+    return fd;
+}  /* PR_Socket */
+
+/*****************************************************************************/
+/****************************** I/O public methods ***************************/
+/*****************************************************************************/
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
+    const char *name, PRIntn flags, PRIntn mode)
+{
+    PRFileDesc *fd = NULL;
+    PRIntn syserrno, osfd = -1, osflags = 0;;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (pt_TestAbort()) return NULL;
+
+    if (flags & PR_RDONLY) osflags |= O_RDONLY;
+    if (flags & PR_WRONLY) osflags |= O_WRONLY;
+    if (flags & PR_RDWR) osflags |= O_RDWR;
+    if (flags & PR_APPEND) osflags |= O_APPEND;
+    if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
+    if (flags & PR_EXCL) osflags |= O_EXCL;
+    if (flags & PR_SYNC)
+    {
+#if defined(O_SYNC)
+        osflags |= O_SYNC;
+#elif defined(O_FSYNC)
+        osflags |= O_FSYNC;
+#else
+#error "Neither O_SYNC nor O_FSYNC is defined on this platform"
+#endif
+    }
+
+    /*
+    ** We have to hold the lock across the creation in order to
+    ** enforce the sematics of PR_Rename(). (see the latter for
+    ** more details)
+    */
+    if (flags & PR_CREATE_FILE)
+    {
+        osflags |= O_CREAT;
+        if (NULL !=_pr_rename_lock)
+            PR_Lock(_pr_rename_lock);
+    }
+
+    osfd = _md_iovector._open64(name, osflags, mode);
+    syserrno = errno;
+
+    if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
+        PR_Unlock(_pr_rename_lock);
+
+    if (osfd == -1)
+        pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
+    else
+    {
+        fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
+        if (fd == NULL) close(osfd);  /* $$$ whoops! this is bad $$$ */
+    }
+    return fd;
+}  /* PR_OpenFile */
+
+PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
+{
+    return PR_OpenFile(name, flags, mode);
+}  /* PR_Open */
+
+PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
+{
+    PRIntn rv = -1;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    rv = unlink(name);
+
+    if (rv == -1) {
+        pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
+        return PR_FAILURE;
+    } else
+        return PR_SUCCESS;
+}  /* PR_Delete */
+
+PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
+{
+    PRIntn rv;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    switch (how)
+    {
+    case PR_ACCESS_READ_OK:
+        rv =  access(name, R_OK);
+        break;
+    case PR_ACCESS_WRITE_OK:
+        rv = access(name, W_OK);
+        break;
+    case PR_ACCESS_EXISTS:
+    default:
+        rv = access(name, F_OK);
+    }
+    if (0 == rv) return PR_SUCCESS;
+    pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
+    return PR_FAILURE;
+    
+}  /* PR_Access */
+
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
+{
+    PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
+    return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
+}  /* PR_GetFileInfo */
+
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
+{
+    PRInt32 rv;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    rv = _PR_MD_GETFILEINFO64(fn, info);
+    return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
+}  /* PR_GetFileInfo64 */
+
+PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
+{
+    PRIntn rv = -1;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    /*
+    ** We have to acquire a lock here to stiffle anybody trying to create
+    ** a new file at the same time. And we have to hold that lock while we
+    ** test to see if the file exists and do the rename. The other place
+    ** where the lock is held is in PR_Open() when possibly creating a 
+    ** new file.
+    */
+
+    PR_Lock(_pr_rename_lock);
+    rv = access(to, F_OK);
+    if (0 == rv)
+    {
+        PR_SetError(PR_FILE_EXISTS_ERROR, 0);
+        rv = -1;
+    }
+    else
+    {
+        rv = rename(from, to);
+        if (rv == -1)
+            pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
+    }
+    PR_Unlock(_pr_rename_lock);
+    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
+}  /* PR_Rename */
+
+PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
+{
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    if (NULL != dir->md.d)
+    {
+        if (closedir(dir->md.d) == -1)
+        {
+            _PR_MD_MAP_CLOSEDIR_ERROR(errno);
+            return PR_FAILURE;
+        }
+        dir->md.d = NULL;
+        PR_DELETE(dir);
+    }
+    return PR_SUCCESS;
+}  /* PR_CloseDir */
+
+PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
+{
+    PRInt32 rv = -1;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    /*
+    ** This lock is used to enforce rename semantics as described
+    ** in PR_Rename.
+    */
+    if (NULL !=_pr_rename_lock)
+        PR_Lock(_pr_rename_lock);
+    rv = mkdir(name, mode);
+    if (-1 == rv)
+        pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
+    if (NULL !=_pr_rename_lock)
+        PR_Unlock(_pr_rename_lock);
+
+    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
+}  /* PR_Makedir */
+
+PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
+{
+    return PR_MakeDir(name, mode);
+}  /* PR_Mkdir */
+
+PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
+{
+    PRInt32 rv;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    rv = rmdir(name);
+    if (0 == rv) {
+    return PR_SUCCESS;
+    } else {
+    pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
+    return PR_FAILURE;
+    }
+}  /* PR_Rmdir */
+
+
+PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
+{
+    DIR *osdir;
+    PRDir *dir = NULL;
+
+    if (pt_TestAbort()) return dir;
+
+    osdir = opendir(name);
+    if (osdir == NULL)
+        pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
+    else
+    {
+        dir = PR_NEWZAP(PRDir);
+        if (dir)
+            dir->md.d = osdir;
+        else
+            (void)closedir(osdir);
+    }
+    return dir;
+}  /* PR_OpenDir */
+
+static PRInt32 _pr_poll_with_poll(
+    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+    PRInt32 ready = 0;
+    /*
+     * For restarting poll() if it is interrupted by a signal.
+     * We use these variables to figure out how much time has
+     * elapsed and how much of the timeout still remains.
+     */
+    PRIntervalTime start, elapsed, remaining;
+
+    if (pt_TestAbort()) return -1;
+
+    if (0 == npds) PR_Sleep(timeout);
+    else
+    {
+#define STACK_POLL_DESC_COUNT 64
+        struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
+        struct pollfd *syspoll;
+        PRIntn index, msecs;
+
+        if (npds <= STACK_POLL_DESC_COUNT)
+        {
+            syspoll = stack_syspoll;
+        }
+        else
+        {
+            PRThread *me = PR_GetCurrentThread();
+            if (npds > me->syspoll_count)
+            {
+                PR_Free(me->syspoll_list);
+                me->syspoll_list =
+                    (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
+                if (NULL == me->syspoll_list)
+                {
+                    me->syspoll_count = 0;
+                    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+                    return -1;
+                }
+                me->syspoll_count = npds;
+            }
+            syspoll = me->syspoll_list;
+        }
+
+        for (index = 0; index < npds; ++index)
+        {
+            PRInt16 in_flags_read = 0, in_flags_write = 0;
+            PRInt16 out_flags_read = 0, out_flags_write = 0;
+
+            if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
+            {
+                if (pds[index].in_flags & PR_POLL_READ)
+                {
+                    in_flags_read = (pds[index].fd->methods->poll)(
+                        pds[index].fd,
+                        pds[index].in_flags & ~PR_POLL_WRITE,
+                        &out_flags_read);
+                }
+                if (pds[index].in_flags & PR_POLL_WRITE)
+                {
+                    in_flags_write = (pds[index].fd->methods->poll)(
+                        pds[index].fd,
+                        pds[index].in_flags & ~PR_POLL_READ,
+                        &out_flags_write);
+                }
+                if ((0 != (in_flags_read & out_flags_read))
+                || (0 != (in_flags_write & out_flags_write)))
+                {
+                    /* this one is ready right now */
+                    if (0 == ready)
+                    {
+                        /*
+                         * We will return without calling the system
+                         * poll function.  So zero the out_flags
+                         * fields of all the poll descriptors before
+                         * this one.
+                         */
+                        int i;
+                        for (i = 0; i < index; i++)
+                        {
+                            pds[i].out_flags = 0;
+                        }
+                    }
+                    ready += 1;
+                    pds[index].out_flags = out_flags_read | out_flags_write;
+                }
+                else
+                {
+                    /* now locate the NSPR layer at the bottom of the stack */
+                    PRFileDesc *bottom = PR_GetIdentitiesLayer(
+                        pds[index].fd, PR_NSPR_IO_LAYER);
+                    PR_ASSERT(NULL != bottom);  /* what to do about that? */
+                    pds[index].out_flags = 0;  /* pre-condition */
+                    if ((NULL != bottom)
+                    && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                    {
+                        if (0 == ready)
+                        {
+                            syspoll[index].fd = bottom->secret->md.osfd;
+                            syspoll[index].events = 0;
+                            if (in_flags_read & PR_POLL_READ)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_READ_SYS_READ;
+                                syspoll[index].events |= POLLIN;
+                            }
+                            if (in_flags_read & PR_POLL_WRITE)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_READ_SYS_WRITE;
+                                syspoll[index].events |= POLLOUT;
+                            }
+                            if (in_flags_write & PR_POLL_READ)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_WRITE_SYS_READ;
+                                syspoll[index].events |= POLLIN;
+                            }
+                            if (in_flags_write & PR_POLL_WRITE)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_WRITE_SYS_WRITE;
+                                syspoll[index].events |= POLLOUT;
+                            }
+                            if (pds[index].in_flags & PR_POLL_EXCEPT)
+                                syspoll[index].events |= POLLPRI;
+                        }
+                    }
+                    else
+                    {
+                        if (0 == ready)
+                        {
+                            int i;
+                            for (i = 0; i < index; i++)
+                            {
+                                pds[i].out_flags = 0;
+                            }
+                        }
+                        ready += 1;  /* this will cause an abrupt return */
+                        pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
+                    }
+                }
+            }
+            else
+            {
+                /* make poll() ignore this entry */
+                syspoll[index].fd = -1;
+                syspoll[index].events = 0;
+                pds[index].out_flags = 0;
+            }
+        }
+        if (0 == ready)
+        {
+            switch (timeout)
+            {
+            case PR_INTERVAL_NO_WAIT: msecs = 0; break;
+            case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
+            default:
+                msecs = PR_IntervalToMilliseconds(timeout);
+                start = PR_IntervalNow();
+            }
+
+retry:
+            ready = poll(syspoll, npds, msecs);
+            if (-1 == ready)
+            {
+                PRIntn oserror = errno;
+
+                if (EINTR == oserror)
+                {
+                    if (timeout == PR_INTERVAL_NO_TIMEOUT)
+                        goto retry;
+                    else if (timeout == PR_INTERVAL_NO_WAIT)
+                        ready = 0;  /* don't retry, just time out */
+                    else
+                    {
+                        elapsed = (PRIntervalTime) (PR_IntervalNow()
+                                - start);
+                        if (elapsed > timeout)
+                            ready = 0;  /* timed out */
+                        else
+                        {
+                            remaining = timeout - elapsed;
+                            msecs = PR_IntervalToMilliseconds(remaining);
+                            goto retry;
+                        }
+                    }
+                }
+                else
+                {
+                    _PR_MD_MAP_POLL_ERROR(oserror);
+                }
+            }
+            else if (ready > 0)
+            {
+                for (index = 0; index < npds; ++index)
+                {
+                    PRInt16 out_flags = 0;
+                    if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
+                    {
+                        if (0 != syspoll[index].revents)
+                        {
+                            if (syspoll[index].revents & POLLIN)
+                            {
+                                if (pds[index].out_flags
+                                & _PR_POLL_READ_SYS_READ)
+                                {
+                                    out_flags |= PR_POLL_READ;
+                                }
+                                if (pds[index].out_flags
+                                & _PR_POLL_WRITE_SYS_READ)
+                                {
+                                    out_flags |= PR_POLL_WRITE;
+                                }
+                            }
+                            if (syspoll[index].revents & POLLOUT)
+                            {
+                                if (pds[index].out_flags
+                                & _PR_POLL_READ_SYS_WRITE)
+                                {
+                                    out_flags |= PR_POLL_READ;
+                                }
+                                if (pds[index].out_flags
+                                & _PR_POLL_WRITE_SYS_WRITE)
+                                {
+                                    out_flags |= PR_POLL_WRITE;
+                                }
+                            }
+                            if (syspoll[index].revents & POLLPRI)
+                                out_flags |= PR_POLL_EXCEPT;
+                            if (syspoll[index].revents & POLLERR)
+                                out_flags |= PR_POLL_ERR;
+                            if (syspoll[index].revents & POLLNVAL)
+                                out_flags |= PR_POLL_NVAL;
+                            if (syspoll[index].revents & POLLHUP)
+                                out_flags |= PR_POLL_HUP;
+                        }
+                    }
+                    pds[index].out_flags = out_flags;
+                }
+            }
+        }
+    }
+    return ready;
+
+} /* _pr_poll_with_poll */
+
+#if defined(_PR_POLL_WITH_SELECT)
+/*
+ * OSF1 and HPUX report the POLLHUP event for a socket when the
+ * shutdown(SHUT_WR) operation is called for the remote end, even though
+ * the socket is still writeable. Use select(), instead of poll(), to
+ * workaround this problem.
+ */
+static PRInt32 _pr_poll_with_select(
+    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+    PRInt32 ready = 0;
+    /*
+     * For restarting select() if it is interrupted by a signal.
+     * We use these variables to figure out how much time has
+     * elapsed and how much of the timeout still remains.
+     */
+    PRIntervalTime start, elapsed, remaining;
+
+    if (pt_TestAbort()) return -1;
+
+    if (0 == npds) PR_Sleep(timeout);
+    else
+    {
+#define STACK_POLL_DESC_COUNT 64
+        int stack_selectfd[STACK_POLL_DESC_COUNT];
+        int *selectfd;
+		fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
+		struct timeval tv, *tvp;
+        PRIntn index, msecs, maxfd = 0;
+
+        if (npds <= STACK_POLL_DESC_COUNT)
+        {
+            selectfd = stack_selectfd;
+        }
+        else
+        {
+            PRThread *me = PR_GetCurrentThread();
+            if (npds > me->selectfd_count)
+            {
+                PR_Free(me->selectfd_list);
+                me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int));
+                if (NULL == me->selectfd_list)
+                {
+                    me->selectfd_count = 0;
+                    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+                    return -1;
+                }
+                me->selectfd_count = npds;
+            }
+            selectfd = me->selectfd_list;
+        }
+		FD_ZERO(&rd);
+		FD_ZERO(&wr);
+		FD_ZERO(&ex);
+
+        for (index = 0; index < npds; ++index)
+        {
+            PRInt16 in_flags_read = 0, in_flags_write = 0;
+            PRInt16 out_flags_read = 0, out_flags_write = 0;
+
+            if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
+            {
+                if (pds[index].in_flags & PR_POLL_READ)
+                {
+                    in_flags_read = (pds[index].fd->methods->poll)(
+                        pds[index].fd,
+                        pds[index].in_flags & ~PR_POLL_WRITE,
+                        &out_flags_read);
+                }
+                if (pds[index].in_flags & PR_POLL_WRITE)
+                {
+                    in_flags_write = (pds[index].fd->methods->poll)(
+                        pds[index].fd,
+                        pds[index].in_flags & ~PR_POLL_READ,
+                        &out_flags_write);
+                }
+                if ((0 != (in_flags_read & out_flags_read))
+                || (0 != (in_flags_write & out_flags_write)))
+                {
+                    /* this one is ready right now */
+                    if (0 == ready)
+                    {
+                        /*
+                         * We will return without calling the system
+                         * poll function.  So zero the out_flags
+                         * fields of all the poll descriptors before
+                         * this one.
+                         */
+                        int i;
+                        for (i = 0; i < index; i++)
+                        {
+                            pds[i].out_flags = 0;
+                        }
+                    }
+                    ready += 1;
+                    pds[index].out_flags = out_flags_read | out_flags_write;
+                }
+                else
+                {
+                    /* now locate the NSPR layer at the bottom of the stack */
+                    PRFileDesc *bottom = PR_GetIdentitiesLayer(
+                        pds[index].fd, PR_NSPR_IO_LAYER);
+                    PR_ASSERT(NULL != bottom);  /* what to do about that? */
+                    pds[index].out_flags = 0;  /* pre-condition */
+                    if ((NULL != bottom)
+                    && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                    {
+                        if (0 == ready)
+                        {
+                            PRBool add_to_rd = PR_FALSE;
+                            PRBool add_to_wr = PR_FALSE;
+                            PRBool add_to_ex = PR_FALSE;
+
+                            selectfd[index] = bottom->secret->md.osfd;
+                            if (in_flags_read & PR_POLL_READ)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_READ_SYS_READ;
+                                add_to_rd = PR_TRUE;
+                            }
+                            if (in_flags_read & PR_POLL_WRITE)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_READ_SYS_WRITE;
+                                add_to_wr = PR_TRUE;
+                            }
+                            if (in_flags_write & PR_POLL_READ)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_WRITE_SYS_READ;
+                                add_to_rd = PR_TRUE;
+                            }
+                            if (in_flags_write & PR_POLL_WRITE)
+                            {
+                                pds[index].out_flags |=
+                                    _PR_POLL_WRITE_SYS_WRITE;
+                                add_to_wr = PR_TRUE;
+                            }
+                            if (pds[index].in_flags & PR_POLL_EXCEPT)
+                            {
+                                add_to_ex = PR_TRUE;
+                            }
+                            if ((selectfd[index] > maxfd) &&
+                                    (add_to_rd || add_to_wr || add_to_ex))
+                            {
+                                maxfd = selectfd[index];
+                                /*
+                                 * If maxfd is too large to be used with
+                                 * select, fall back to calling poll.
+                                 */
+                                if (maxfd >= FD_SETSIZE)
+                                    break;
+                            }
+                            if (add_to_rd)
+                            {
+                                FD_SET(bottom->secret->md.osfd, &rd);
+                                rdp = &rd;
+                            }
+                            if (add_to_wr)
+                            {
+                                FD_SET(bottom->secret->md.osfd, &wr);
+                                wrp = &wr;
+                            }
+                            if (add_to_ex)
+                            {
+                                FD_SET(bottom->secret->md.osfd, &ex);
+                                exp = &ex;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (0 == ready)
+                        {
+                            int i;
+                            for (i = 0; i < index; i++)
+                            {
+                                pds[i].out_flags = 0;
+                            }
+                        }
+                        ready += 1;  /* this will cause an abrupt return */
+                        pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
+                    }
+                }
+            }
+            else
+            {
+                pds[index].out_flags = 0;
+            }
+        }
+        if (0 == ready)
+        {
+			if (maxfd >= FD_SETSIZE)
+			{
+				/*
+				 * maxfd too large to be used with select, fall back to
+				 * calling poll
+				 */
+				return(_pr_poll_with_poll(pds, npds, timeout));
+			}
+            switch (timeout)
+            {
+            case PR_INTERVAL_NO_WAIT:
+				tv.tv_sec = 0;
+				tv.tv_usec = 0;
+				tvp = &tv;
+				break;
+            case PR_INTERVAL_NO_TIMEOUT:
+				tvp = NULL;
+				break;
+            default:
+                msecs = PR_IntervalToMilliseconds(timeout);
+				tv.tv_sec = msecs/PR_MSEC_PER_SEC;
+				tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
+				tvp = &tv;
+                start = PR_IntervalNow();
+            }
+
+retry:
+            ready = select(maxfd + 1, rdp, wrp, exp, tvp);
+            if (-1 == ready)
+            {
+                PRIntn oserror = errno;
+
+                if ((EINTR == oserror) || (EAGAIN == oserror))
+                {
+                    if (timeout == PR_INTERVAL_NO_TIMEOUT)
+                        goto retry;
+                    else if (timeout == PR_INTERVAL_NO_WAIT)
+                        ready = 0;  /* don't retry, just time out */
+                    else
+                    {
+                        elapsed = (PRIntervalTime) (PR_IntervalNow()
+                                - start);
+                        if (elapsed > timeout)
+                            ready = 0;  /* timed out */
+                        else
+                        {
+                            remaining = timeout - elapsed;
+                            msecs = PR_IntervalToMilliseconds(remaining);
+							tv.tv_sec = msecs/PR_MSEC_PER_SEC;
+							tv.tv_usec = (msecs % PR_MSEC_PER_SEC) *
+													PR_USEC_PER_MSEC;
+                            goto retry;
+                        }
+                    }
+                } else if (EBADF == oserror)
+                {
+					/* find all the bad fds */
+					ready = 0;
+                	for (index = 0; index < npds; ++index)
+					{
+                    	pds[index].out_flags = 0;
+            			if ((NULL != pds[index].fd) &&
+											(0 != pds[index].in_flags))
+						{
+							if (fcntl(selectfd[index], F_GETFL, 0) == -1)
+							{
+                    			pds[index].out_flags = PR_POLL_NVAL;
+								ready++;
+							}
+						}
+					}
+                } else 
+                    _PR_MD_MAP_SELECT_ERROR(oserror);
+            }
+            else if (ready > 0)
+            {
+                for (index = 0; index < npds; ++index)
+                {
+                    PRInt16 out_flags = 0;
+                    if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
+                    {
+						if (FD_ISSET(selectfd[index], &rd))
+						{
+							if (pds[index].out_flags
+							& _PR_POLL_READ_SYS_READ)
+							{
+								out_flags |= PR_POLL_READ;
+							}
+							if (pds[index].out_flags
+							& _PR_POLL_WRITE_SYS_READ)
+							{
+								out_flags |= PR_POLL_WRITE;
+							}
+						}
+						if (FD_ISSET(selectfd[index], &wr))
+						{
+							if (pds[index].out_flags
+							& _PR_POLL_READ_SYS_WRITE)
+							{
+								out_flags |= PR_POLL_READ;
+							}
+							if (pds[index].out_flags
+							& _PR_POLL_WRITE_SYS_WRITE)
+							{
+								out_flags |= PR_POLL_WRITE;
+							}
+						}
+						if (FD_ISSET(selectfd[index], &ex))
+							out_flags |= PR_POLL_EXCEPT;
+                    }
+                    pds[index].out_flags = out_flags;
+                }
+            }
+        }
+    }
+    return ready;
+
+} /* _pr_poll_with_select */
+#endif	/* _PR_POLL_WITH_SELECT */
+
+PR_IMPLEMENT(PRInt32) PR_Poll(
+    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+#if defined(_PR_POLL_WITH_SELECT)
+	return(_pr_poll_with_select(pds, npds, timeout));
+#else
+	return(_pr_poll_with_poll(pds, npds, timeout));
+#endif
+}
+
+PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
+{
+    struct dirent *dp;
+
+    if (pt_TestAbort()) return NULL;
+
+    for (;;)
+    {
+        errno = 0;
+        dp = readdir(dir->md.d);
+        if (NULL == dp)
+        {
+            pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
+            return NULL;
+        }
+        if ((flags & PR_SKIP_DOT)
+            && ('.' == dp->d_name[0])
+            && (0 == dp->d_name[1])) continue;
+        if ((flags & PR_SKIP_DOT_DOT)
+            && ('.' == dp->d_name[0])
+            && ('.' == dp->d_name[1])
+            && (0 == dp->d_name[2])) continue;
+        if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
+            continue;
+        break;
+    }
+    dir->d.name = dp->d_name;
+    return &dir->d;
+}  /* PR_ReadDir */
+
+PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
+{
+    PRIntn domain = PF_INET;
+
+    return PR_Socket(domain, SOCK_DGRAM, 0);
+}  /* PR_NewUDPSocket */
+
+PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void)
+{
+    PRIntn domain = PF_INET;
+
+    return PR_Socket(domain, SOCK_STREAM, 0);
+}  /* PR_NewTCPSocket */
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
+{
+    return PR_Socket(af, SOCK_DGRAM, 0);
+}  /* PR_NewUDPSocket */
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
+{
+    return PR_Socket(af, SOCK_STREAM, 0);
+}  /* PR_NewTCPSocket */
+
+PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
+{
+#ifdef SYMBIAN
+    /*
+     * For the platforms that don't have socketpair.
+     *
+     * Copied from prsocket.c, with the parameter f[] renamed fds[] and the
+     * _PR_CONNECT_DOES_NOT_BIND code removed.
+     */
+    PRFileDesc *listenSock;
+    PRNetAddr selfAddr, peerAddr;
+    PRUint16 port;
+
+    fds[0] = fds[1] = NULL;
+    listenSock = PR_NewTCPSocket();
+    if (listenSock == NULL) {
+        goto failed;
+    }
+    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
+    if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    port = ntohs(selfAddr.inet.port);
+    if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+        goto failed;
+    }
+    fds[0] = PR_NewTCPSocket();
+    if (fds[0] == NULL) {
+        goto failed;
+    }
+    PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
+
+    /*
+     * Only a thread is used to do the connect and accept.
+     * I am relying on the fact that PR_Connect returns
+     * successfully as soon as the connect request is put
+     * into the listen queue (but before PR_Accept is called).
+     * This is the behavior of the BSD socket code.  If
+     * connect does not return until accept is called, we
+     * will need to create another thread to call connect.
+     */
+    if (PR_Connect(fds[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
+            == PR_FAILURE) {
+        goto failed;
+    }
+    /*
+     * A malicious local process may connect to the listening
+     * socket, so we need to verify that the accepted connection
+     * is made from our own socket fds[0].
+     */
+    if (PR_GetSockName(fds[0], &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    fds[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
+    if (fds[1] == NULL) {
+        goto failed;
+    }
+    if (peerAddr.inet.port != selfAddr.inet.port) {
+        /* the connection we accepted is not from fds[0] */
+        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+        goto failed;
+    }
+    PR_Close(listenSock);
+    return PR_SUCCESS;
+
+failed:
+    if (listenSock) {
+        PR_Close(listenSock);
+    }
+    if (fds[0]) {
+        PR_Close(fds[0]);
+    }
+    if (fds[1]) {
+        PR_Close(fds[1]);
+    }
+    return PR_FAILURE;
+#else
+    PRInt32 osfd[2];
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
+        pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
+        return PR_FAILURE;
+    }
+
+    fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
+    if (fds[0] == NULL) {
+        close(osfd[0]);
+        close(osfd[1]);
+        return PR_FAILURE;
+    }
+    fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
+    if (fds[1] == NULL) {
+        PR_Close(fds[0]);
+        close(osfd[1]);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+#endif
+}  /* PR_NewTCPSocketPair */
+
+PR_IMPLEMENT(PRStatus) PR_CreatePipe(
+    PRFileDesc **readPipe,
+    PRFileDesc **writePipe
+)
+{
+    int pipefd[2];
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    if (pipe(pipefd) == -1)
+    {
+    /* XXX map pipe error */
+        PR_SetError(PR_UNKNOWN_ERROR, errno);
+        return PR_FAILURE;
+    }
+    *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
+    if (NULL == *readPipe)
+    {
+        close(pipefd[0]);
+        close(pipefd[1]);
+        return PR_FAILURE;
+    }
+    *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
+    if (NULL == *writePipe)
+    {
+        PR_Close(*readPipe);
+        close(pipefd[1]);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+/*
+** Set the inheritance attribute of a file descriptor.
+*/
+PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
+    PRFileDesc *fd,
+    PRBool inheritable)
+{
+    /*
+     * Only a non-layered, NSPR file descriptor can be inherited
+     * by a child process.
+     */
+    if (fd->identity != PR_NSPR_IO_LAYER)
+    {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    if (fd->secret->inheritable != inheritable)
+    {
+        if (fcntl(fd->secret->md.osfd, F_SETFD,
+        inheritable ? 0 : FD_CLOEXEC) == -1)
+        {
+            _PR_MD_MAP_DEFAULT_ERROR(errno);
+            return PR_FAILURE;
+        }
+        fd->secret->inheritable = (_PRTriStateBool) inheritable;
+    }
+    return PR_SUCCESS;
+}
+
+/*****************************************************************************/
+/***************************** I/O friends methods ***************************/
+/*****************************************************************************/
+
+PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
+{
+    PRFileDesc *fd;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
+    if (NULL == fd) close(osfd);
+    return fd;
+}  /* PR_ImportFile */
+
+PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd)
+{
+    PRFileDesc *fd;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
+    if (NULL == fd) close(osfd);
+    return fd;
+}  /* PR_ImportPipe */
+
+PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
+{
+    PRFileDesc *fd;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
+    if (NULL == fd) close(osfd);
+#ifdef _PR_NEED_SECRET_AF
+    if (NULL != fd) fd->secret->af = PF_INET;
+#endif
+    return fd;
+}  /* PR_ImportTCPSocket */
+
+PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
+{
+    PRFileDesc *fd;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
+    if (NULL != fd) close(osfd);
+    return fd;
+}  /* PR_ImportUDPSocket */
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
+{
+    PRFileDesc *fd;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    fd = _PR_Getfd();
+
+    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    else
+    {
+        fd->secret->md.osfd = osfd;
+        fd->secret->inheritable = _PR_TRI_FALSE;
+    	fd->secret->state = _PR_FILEDESC_OPEN;
+        fd->methods = PR_GetSocketPollFdMethods();
+    }
+
+    return fd;
+}  /* PR_CreateSocketPollFD */
+
+PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
+{
+    if (NULL == fd)
+    {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+    fd->secret->state = _PR_FILEDESC_CLOSED;
+    _PR_Putfd(fd);
+    return PR_SUCCESS;
+}  /* PR_DestroySocketPollFd */
+
+PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom)
+{
+    PRInt32 osfd = -1;
+    bottom = (NULL == bottom) ?
+        NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
+    if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    else osfd = bottom->secret->md.osfd;
+    return osfd;
+}  /* PR_FileDesc2NativeHandle */
+
+PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
+    PRInt32 handle)
+{
+    if (fd) fd->secret->md.osfd = handle;
+}  /*  PR_ChangeFileDescNativeHandle*/
+
+PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
+{
+    PRStatus status = PR_SUCCESS;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    PR_Lock(_pr_flock_lock);
+    while (-1 == fd->secret->lockCount)
+        PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
+    if (0 == fd->secret->lockCount)
+    {
+        fd->secret->lockCount = -1;
+        PR_Unlock(_pr_flock_lock);
+        status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
+        PR_Lock(_pr_flock_lock);
+        fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
+        PR_NotifyAllCondVar(_pr_flock_cv);
+    }
+    else
+    {
+        fd->secret->lockCount += 1;
+    }
+    PR_Unlock(_pr_flock_lock);
+ 
+    return status;
+}  /* PR_LockFile */
+
+PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
+{
+    PRStatus status = PR_SUCCESS;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    PR_Lock(_pr_flock_lock);
+    if (0 == fd->secret->lockCount)
+    {
+        status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
+        if (PR_SUCCESS == status) fd->secret->lockCount = 1;
+    }
+    else fd->secret->lockCount += 1;
+    PR_Unlock(_pr_flock_lock);
+ 
+    return status;
+}  /* PR_TLockFile */
+
+PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
+{
+    PRStatus status = PR_SUCCESS;
+
+    if (pt_TestAbort()) return PR_FAILURE;
+
+    PR_Lock(_pr_flock_lock);
+    if (fd->secret->lockCount == 1)
+    {
+        status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
+        if (PR_SUCCESS == status) fd->secret->lockCount = 0;
+    }
+    else fd->secret->lockCount -= 1;
+    PR_Unlock(_pr_flock_lock);
+
+    return status;
+}
+
+/*
+ * The next two entry points should not be in the API, but they are
+ * defined here for historical (or hysterical) reasons.
+ */
+
+PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
+{
+#if defined(AIX) || defined(SYMBIAN)
+    return sysconf(_SC_OPEN_MAX);
+#else
+    struct rlimit rlim;
+
+    if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) 
+       return -1;
+
+    return rlim.rlim_max;
+#endif
+}
+
+PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size)
+{
+#if defined(AIX) || defined(SYMBIAN)
+    return -1;
+#else
+    struct rlimit rlim;
+    PRInt32 tableMax = PR_GetSysfdTableMax();
+
+    if (tableMax < 0) return -1;
+    rlim.rlim_max = tableMax;
+
+    /* Grow as much as we can; even if too big */
+    if ( rlim.rlim_max < table_size )
+        rlim.rlim_cur = rlim.rlim_max;
+    else
+        rlim.rlim_cur = table_size;
+
+    if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) 
+        return -1;
+
+    return rlim.rlim_cur;
+#endif
+}
+
+/*
+ * PR_Stat is supported for backward compatibility; some existing Java
+ * code uses it.  New code should use PR_GetFileInfo.
+ */
+
+#ifndef NO_NSPR_10_SUPPORT
+PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
+{
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
+
+    if (pt_TestAbort()) return -1;
+
+    if (-1 == stat(name, buf)) {
+        pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
+        return -1;
+    } else {
+        return 0;
+    }
+}
+#endif /* ! NO_NSPR_10_SUPPORT */
+
+
+PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
+{
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
+    memset(set, 0, sizeof(PR_fd_set));
+}
+
+PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
+{
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
+    PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
+
+    set->harray[set->hsize++] = fh;
+}
+
+PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
+{
+    PRUint32 index, index2;
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
+
+    for (index = 0; index<set->hsize; index++)
+       if (set->harray[index] == fh) {
+           for (index2=index; index2 < (set->hsize-1); index2++) {
+               set->harray[index2] = set->harray[index2+1];
+           }
+           set->hsize--;
+           break;
+       }
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
+{
+    PRUint32 index;
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
+    for (index = 0; index<set->hsize; index++)
+       if (set->harray[index] == fh) {
+           return 1;
+       }
+    return 0;
+}
+
+PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
+{
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
+    PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
+
+    set->narray[set->nsize++] = fd;
+}
+
+PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
+{
+    PRUint32 index, index2;
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
+
+    for (index = 0; index<set->nsize; index++)
+       if (set->narray[index] == fd) {
+           for (index2=index; index2 < (set->nsize-1); index2++) {
+               set->narray[index2] = set->narray[index2+1];
+           }
+           set->nsize--;
+           break;
+       }
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
+{
+    PRUint32 index;
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
+    for (index = 0; index<set->nsize; index++)
+       if (set->narray[index] == fd) {
+           return 1;
+       }
+    return 0;
+}
+
+#include <sys/types.h>
+#include <sys/time.h>
+#if !defined(SUNOS4) && !defined(HPUX) \
+    && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__)
+#include <sys/select.h>
+#endif
+
+static PRInt32
+_PR_getset(PR_fd_set *pr_set, fd_set *set)
+{
+    PRUint32 index;
+    PRInt32 max = 0;
+
+    if (!pr_set)
+        return 0;
+   
+    FD_ZERO(set);
+
+    /* First set the pr file handle osfds */
+    for (index=0; index<pr_set->hsize; index++) {
+        FD_SET(pr_set->harray[index]->secret->md.osfd, set);
+        if (pr_set->harray[index]->secret->md.osfd > max)
+            max = pr_set->harray[index]->secret->md.osfd;
+    }
+    /* Second set the native osfds */
+    for (index=0; index<pr_set->nsize; index++) {
+        FD_SET(pr_set->narray[index], set);
+        if (pr_set->narray[index] > max)
+            max = pr_set->narray[index];
+    }
+    return max;
+}
+
+static void
+_PR_setset(PR_fd_set *pr_set, fd_set *set)
+{
+    PRUint32 index, last_used;
+
+    if (!pr_set)
+        return;
+
+    for (last_used=0, index=0; index<pr_set->hsize; index++) {
+        if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
+            pr_set->harray[last_used++] = pr_set->harray[index];
+        }
+    }
+    pr_set->hsize = last_used;
+
+    for (last_used=0, index=0; index<pr_set->nsize; index++) {
+        if ( FD_ISSET(pr_set->narray[index], set) ) {
+            pr_set->narray[last_used++] = pr_set->narray[index];
+        }
+    }
+    pr_set->nsize = last_used;
+}
+
+PR_IMPLEMENT(PRInt32) PR_Select(
+    PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
+    PR_fd_set *pr_ex, PRIntervalTime timeout)
+{
+    fd_set rd, wr, ex;
+    struct timeval tv, *tvp;
+    PRInt32 max, max_fd;
+    PRInt32 rv;
+    /*
+     * For restarting select() if it is interrupted by a Unix signal.
+     * We use these variables to figure out how much time has elapsed
+     * and how much of the timeout still remains.
+     */
+    PRIntervalTime start, elapsed, remaining;
+
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
+
+    FD_ZERO(&rd);
+    FD_ZERO(&wr);
+    FD_ZERO(&ex);
+
+    max_fd = _PR_getset(pr_rd, &rd);
+    max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
+    max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
+
+    if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+        tvp = NULL;
+    } else {
+        tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
+        tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
+                timeout - PR_SecondsToInterval(tv.tv_sec));
+        tvp = &tv;
+        start = PR_IntervalNow();
+    }
+
+retry:
+    rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
+        (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
+
+    if (rv == -1 && errno == EINTR) {
+        if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+            goto retry;
+        } else {
+            elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
+            if (elapsed > timeout) {
+                rv = 0;  /* timed out */
+            } else {
+                remaining = timeout - elapsed;
+                tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
+                tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
+                        remaining - PR_SecondsToInterval(tv.tv_sec));
+                goto retry;
+            }
+        }
+    }
+
+    if (rv > 0) {
+        _PR_setset(pr_rd, &rd);
+        _PR_setset(pr_wr, &wr);
+        _PR_setset(pr_ex, &ex);
+    } else if (rv == -1) {
+        pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
+    }
+    return rv;
+}
+#endif /* defined(_PR_PTHREADS) */
+
+#ifdef MOZ_UNICODE 
+/* ================ UTF16 Interfaces ================================ */
+PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
+    const PRUnichar *name, PRIntn flags, PRIntn mode)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+
+PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+/* ================ UTF16 Interfaces ================================ */
+#endif /* MOZ_UNICODE */
+
+/* ptio.c */
diff --git a/mozilla/nsprpub/pr/src/pthreads/ptmisc.c b/mozilla/nsprpub/pr/src/pthreads/ptmisc.c
new file mode 100644
index 0000000..920d00d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/pthreads/ptmisc.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:   ptmisc.c
+** Descritpion:  Implemenation of miscellaneous methods for pthreads
+*/
+
+#if defined(_PR_PTHREADS)
+
+#include "primpl.h"
+
+#include <stdio.h>
+#ifdef SOLARIS
+#include <thread.h>
+#endif
+
+#define PT_LOG(f)
+
+void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")}
+void _PR_InitStacks(void) {PT_LOG("_PR_InitStacks")}
+
+PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs) 
+{
+#ifdef SOLARIS
+	thr_setconcurrency(numCPUs);	
+#else
+	PT_LOG("PR_SetConcurrency");
+#endif
+}
+
+PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 flag)
+    {PT_LOG("PR_SetThreadRecycleMode")}
+
+#endif /* defined(_PR_PTHREADS) */
+
+/* ptmisc.c */
diff --git a/mozilla/nsprpub/pr/src/pthreads/ptsynch.c b/mozilla/nsprpub/pr/src/pthreads/ptsynch.c
new file mode 100644
index 0000000..8b141cd
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/pthreads/ptsynch.c
@@ -0,0 +1,1157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:            ptsynch.c
+** Descritpion:        Implemenation for thread synchronization using pthreads
+** Exports:            prlock.h, prcvar.h, prmon.h, prcmon.h
+*/
+
+#if defined(_PR_PTHREADS)
+
+#include "primpl.h"
+#include "obsolete/prsem.h"
+
+#include <string.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+static pthread_mutexattr_t _pt_mattr;
+static pthread_condattr_t _pt_cvar_attr;
+
+#if defined(DEBUG)
+extern PTDebug pt_debug;  /* this is shared between several modules */
+
+#if defined(_PR_DCETHREADS)
+static pthread_t pt_zero_tid;  /* a null pthread_t (pthread_t is a struct
+                                * in DCE threads) to compare with */
+#endif  /* defined(_PR_DCETHREADS) */
+#endif  /* defined(DEBUG) */
+
+#if defined(FREEBSD)
+/*
+ * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK.
+ * Newer versions return EBUSY.  We still need to support both.
+ */
+static int
+pt_pthread_mutex_is_locked(pthread_mutex_t *m)
+{
+    int rv = pthread_mutex_trylock(m);
+    return (EBUSY == rv || EDEADLK == rv);
+}
+#endif
+
+/**************************************************************/
+/**************************************************************/
+/*****************************LOCKS****************************/
+/**************************************************************/
+/**************************************************************/
+
+void _PR_InitLocks(void)
+{
+    int rv;
+    rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr); 
+    PR_ASSERT(0 == rv);
+
+#ifdef LINUX
+#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
+    rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
+    PR_ASSERT(0 == rv);
+#endif
+#endif
+
+    rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr);
+    PR_ASSERT(0 == rv);
+}
+
+static void pt_PostNotifies(PRLock *lock, PRBool unlock)
+{
+    PRIntn index, rv;
+    _PT_Notified post;
+    _PT_Notified *notified, *prev = NULL;
+    /*
+     * Time to actually notify any conditions that were affected
+     * while the lock was held. Get a copy of the list that's in
+     * the lock structure and then zero the original. If it's
+     * linked to other such structures, we own that storage.
+     */
+    post = lock->notified;  /* a safe copy; we own the lock */
+
+#if defined(DEBUG)
+    memset(&lock->notified, 0, sizeof(_PT_Notified));  /* reset */
+#else
+    lock->notified.length = 0;  /* these are really sufficient */
+    lock->notified.link = NULL;
+#endif
+
+    /* should (may) we release lock before notifying? */
+    if (unlock)
+    {
+        rv = pthread_mutex_unlock(&lock->mutex);
+        PR_ASSERT(0 == rv);
+    }
+
+    notified = &post;  /* this is where we start */
+    do
+    {
+        for (index = 0; index < notified->length; ++index)
+        {
+            PRCondVar *cv = notified->cv[index].cv;
+            PR_ASSERT(NULL != cv);
+            PR_ASSERT(0 != notified->cv[index].times);
+            if (-1 == notified->cv[index].times)
+            {
+                rv = pthread_cond_broadcast(&cv->cv);
+                PR_ASSERT(0 == rv);
+            }
+            else
+            {
+                while (notified->cv[index].times-- > 0)
+                {
+                    rv = pthread_cond_signal(&cv->cv);
+                    PR_ASSERT(0 == rv);
+                }
+            }
+#if defined(DEBUG)
+            pt_debug.cvars_notified += 1;
+            if (0 > PR_AtomicDecrement(&cv->notify_pending))
+            {
+                pt_debug.delayed_cv_deletes += 1;
+                PR_DestroyCondVar(cv);
+            }
+#else  /* defined(DEBUG) */
+            if (0 > PR_AtomicDecrement(&cv->notify_pending))
+                PR_DestroyCondVar(cv);
+#endif  /* defined(DEBUG) */
+        }
+        prev = notified;
+        notified = notified->link;
+        if (&post != prev) PR_DELETE(prev);
+    } while (NULL != notified);
+}  /* pt_PostNotifies */
+
+PR_IMPLEMENT(PRLock*) PR_NewLock(void)
+{
+    PRIntn rv;
+    PRLock *lock;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    lock = PR_NEWZAP(PRLock);
+    if (lock != NULL)
+    {
+        rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr); 
+        PR_ASSERT(0 == rv);
+    }
+#if defined(DEBUG)
+    pt_debug.locks_created += 1;
+#endif
+    return lock;
+}  /* PR_NewLock */
+
+PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock)
+{
+    PRIntn rv;
+    PR_ASSERT(NULL != lock);
+    PR_ASSERT(PR_FALSE == lock->locked);
+    PR_ASSERT(0 == lock->notified.length);
+    PR_ASSERT(NULL == lock->notified.link);
+    rv = pthread_mutex_destroy(&lock->mutex);
+    PR_ASSERT(0 == rv);
+#if defined(DEBUG)
+    memset(lock, 0xaf, sizeof(PRLock));
+    pt_debug.locks_destroyed += 1;
+#endif
+    PR_DELETE(lock);
+}  /* PR_DestroyLock */
+
+PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
+{
+    PRIntn rv;
+    PR_ASSERT(lock != NULL);
+    rv = pthread_mutex_lock(&lock->mutex);
+    PR_ASSERT(0 == rv);
+    PR_ASSERT(0 == lock->notified.length);
+    PR_ASSERT(NULL == lock->notified.link);
+    PR_ASSERT(PR_FALSE == lock->locked);
+    /* Nb: the order of the next two statements is not critical to
+     * the correctness of PR_AssertCurrentThreadOwnsLock(), but 
+     * this particular order makes the assertion more likely to
+     * catch errors. */
+    lock->owner = pthread_self();
+    lock->locked = PR_TRUE;
+#if defined(DEBUG)
+    pt_debug.locks_acquired += 1;
+#endif
+}  /* PR_Lock */
+
+PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
+{
+    PRIntn rv;
+
+    PR_ASSERT(lock != NULL);
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex));
+    PR_ASSERT(PR_TRUE == lock->locked);
+    PR_ASSERT(pthread_equal(lock->owner, pthread_self()));
+
+    if (!lock->locked || !pthread_equal(lock->owner, pthread_self()))
+        return PR_FAILURE;
+
+    lock->locked = PR_FALSE;
+    if (0 == lock->notified.length)  /* shortcut */
+    {
+        rv = pthread_mutex_unlock(&lock->mutex);
+        PR_ASSERT(0 == rv);
+    }
+    else pt_PostNotifies(lock, PR_TRUE);
+
+#if defined(DEBUG)
+    pt_debug.locks_released += 1;
+#endif
+    return PR_SUCCESS;
+}  /* PR_Unlock */
+
+PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock)
+{
+    /* Nb: the order of the |locked| and |owner==me| checks is not critical 
+     * to the correctness of PR_AssertCurrentThreadOwnsLock(), but 
+     * this particular order makes the assertion more likely to
+     * catch errors. */
+    PR_ASSERT(lock->locked && pthread_equal(lock->owner, pthread_self()));
+}
+
+/**************************************************************/
+/**************************************************************/
+/***************************CONDITIONS*************************/
+/**************************************************************/
+/**************************************************************/
+
+
+/*
+ * This code is used to compute the absolute time for the wakeup.
+ * It's moderately ugly, so it's defined here and called in a
+ * couple of places.
+ */
+#define PT_NANOPERMICRO 1000UL
+#define PT_BILLION 1000000000UL
+
+static PRIntn pt_TimedWait(
+    pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout)
+{
+    int rv;
+    struct timeval now;
+    struct timespec tmo;
+    PRUint32 ticks = PR_TicksPerSecond();
+
+    tmo.tv_sec = (PRInt32)(timeout / ticks);
+    tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks));
+    tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec);
+
+    /* pthreads wants this in absolute time, off we go ... */
+    (void)GETTIMEOFDAY(&now);
+    /* that one's usecs, this one's nsecs - grrrr! */
+    tmo.tv_sec += now.tv_sec;
+    tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
+    tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
+    tmo.tv_nsec %= PT_BILLION;
+
+    rv = pthread_cond_timedwait(cv, ml, &tmo);
+
+    /* NSPR doesn't report timeouts */
+#ifdef _PR_DCETHREADS
+    if (rv == -1) return (errno == EAGAIN) ? 0 : errno;
+    else return rv;
+#else
+    return (rv == ETIMEDOUT) ? 0 : rv;
+#endif
+}  /* pt_TimedWait */
+
+
+/*
+ * Notifies just get posted to the protecting mutex. The
+ * actual notification is done when the lock is released so that
+ * MP systems don't contend for a lock that they can't have.
+ */
+static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast)
+{
+    PRIntn index = 0;
+    _PT_Notified *notified = &cvar->lock->notified;
+
+    PR_ASSERT(PR_TRUE == cvar->lock->locked);
+    PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
+
+    while (1)
+    {
+        for (index = 0; index < notified->length; ++index)
+        {
+            if (notified->cv[index].cv == cvar)
+            {
+                if (broadcast)
+                    notified->cv[index].times = -1;
+                else if (-1 != notified->cv[index].times)
+                    notified->cv[index].times += 1;
+                goto finished;  /* we're finished */
+            }
+        }
+        /* if not full, enter new CV in this array */
+        if (notified->length < PT_CV_NOTIFIED_LENGTH) break;
+
+        /* if there's no link, create an empty array and link it */
+        if (NULL == notified->link)
+            notified->link = PR_NEWZAP(_PT_Notified);
+        notified = notified->link;
+    }
+
+    /* A brand new entry in the array */
+    (void)PR_AtomicIncrement(&cvar->notify_pending);
+    notified->cv[index].times = (broadcast) ? -1 : 1;
+    notified->cv[index].cv = cvar;
+    notified->length += 1;
+
+finished:
+    PR_ASSERT(PR_TRUE == cvar->lock->locked);
+    PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
+}  /* pt_PostNotifyToCvar */
+
+PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
+{
+    PRCondVar *cv = PR_NEW(PRCondVar);
+    PR_ASSERT(lock != NULL);
+    if (cv != NULL)
+    {
+        int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); 
+        PR_ASSERT(0 == rv);
+        cv->lock = lock;
+        cv->notify_pending = 0;
+#if defined(DEBUG)
+        pt_debug.cvars_created += 1;
+#endif
+    }
+    return cv;
+}  /* PR_NewCondVar */
+
+PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
+{
+    if (0 > PR_AtomicDecrement(&cvar->notify_pending))
+    {
+        PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
+#if defined(DEBUG)
+        memset(cvar, 0xaf, sizeof(PRCondVar));
+        pt_debug.cvars_destroyed += 1;
+#endif
+        PR_DELETE(cvar);
+    }
+}  /* PR_DestroyCondVar */
+
+PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
+{
+    PRIntn rv;
+    PRThread *thred = PR_GetCurrentThread();
+
+    PR_ASSERT(cvar != NULL);
+    /* We'd better be locked */
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
+    PR_ASSERT(PR_TRUE == cvar->lock->locked);
+    /* and it better be by us */
+    PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
+
+    if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
+
+    /*
+     * The thread waiting is used for PR_Interrupt
+     */
+    thred->waiting = cvar;  /* this is where we're waiting */
+
+    /*
+     * If we have pending notifies, post them now.
+     *
+     * This is not optimal. We're going to post these notifies
+     * while we're holding the lock. That means on MP systems
+     * that they are going to collide for the lock that we will
+     * hold until we actually wait.
+     */
+    if (0 != cvar->lock->notified.length)
+        pt_PostNotifies(cvar->lock, PR_FALSE);
+
+    /*
+     * We're surrendering the lock, so clear out the locked field.
+     */
+    cvar->lock->locked = PR_FALSE;
+
+    if (timeout == PR_INTERVAL_NO_TIMEOUT)
+        rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex);
+    else
+        rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout);
+
+    /* We just got the lock back - this better be empty */
+    PR_ASSERT(PR_FALSE == cvar->lock->locked);
+    cvar->lock->locked = PR_TRUE;
+    cvar->lock->owner = pthread_self();
+
+    PR_ASSERT(0 == cvar->lock->notified.length);
+    thred->waiting = NULL;  /* and now we're not */
+    if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
+    if (rv != 0)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(rv);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+
+aborted:
+    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    thred->state &= ~PT_THREAD_ABORTED;
+    return PR_FAILURE;
+}  /* PR_WaitCondVar */
+
+PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
+{
+    PR_ASSERT(cvar != NULL);   
+    pt_PostNotifyToCvar(cvar, PR_FALSE);
+    return PR_SUCCESS;
+}  /* PR_NotifyCondVar */
+
+PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
+{
+    PR_ASSERT(cvar != NULL);
+    pt_PostNotifyToCvar(cvar, PR_TRUE);
+    return PR_SUCCESS;
+}  /* PR_NotifyAllCondVar */
+
+/**************************************************************/
+/**************************************************************/
+/***************************MONITORS***************************/
+/**************************************************************/
+/**************************************************************/
+
+PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void)
+{
+    PRMonitor *mon;
+    PRCondVar *cvar;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    cvar = PR_NEWZAP(PRCondVar);
+    if (NULL == cvar)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+    mon = PR_NEWZAP(PRMonitor);
+    if (mon != NULL)
+    {
+        int rv;
+        rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr); 
+        PR_ASSERT(0 == rv);
+
+        _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
+
+        mon->cvar = cvar;
+        rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr); 
+        PR_ASSERT(0 == rv);
+        mon->entryCount = 0;
+        mon->cvar->lock = &mon->lock;
+        if (0 != rv)
+        {
+            PR_DELETE(mon);
+            PR_DELETE(cvar);
+            mon = NULL;
+        }
+    }
+    return mon;
+}  /* PR_NewMonitor */
+
+PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
+{
+    PRMonitor* mon = PR_NewMonitor();
+    if (mon)
+        mon->name = name;
+    return mon;
+}
+
+PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
+{
+    int rv;
+    PR_ASSERT(mon != NULL);
+    PR_DestroyCondVar(mon->cvar);
+    rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv);
+#if defined(DEBUG)
+        memset(mon, 0xaf, sizeof(PRMonitor));
+#endif
+    PR_DELETE(mon);    
+}  /* PR_DestroyMonitor */
+
+
+/* The GC uses this; it is quite arguably a bad interface.  I'm just 
+ * duplicating it for now - XXXMB
+ */
+PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
+{
+    pthread_t self = pthread_self();
+    if (pthread_equal(mon->owner, self))
+        return mon->entryCount;
+    return 0;
+}
+
+PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
+{
+    PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(&mon->lock);
+}
+
+PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
+{
+    pthread_t self = pthread_self();
+
+    PR_ASSERT(mon != NULL);
+    /*
+     * This is safe only if mon->owner (a pthread_t) can be
+     * read in one instruction.  Perhaps mon->owner should be
+     * a "PRThread *"?
+     */
+    if (!pthread_equal(mon->owner, self))
+    {
+        PR_Lock(&mon->lock);
+        /* and now I have the lock */
+        PR_ASSERT(0 == mon->entryCount);
+        PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner));
+        _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner);
+    }
+    mon->entryCount += 1;
+}  /* PR_EnterMonitor */
+
+PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
+{
+    pthread_t self = pthread_self();
+
+    PR_ASSERT(mon != NULL);
+    /* The lock better be that - locked */
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
+    /* we'd better be the owner */
+    PR_ASSERT(pthread_equal(mon->owner, self));
+    if (!pthread_equal(mon->owner, self))
+        return PR_FAILURE;
+
+    /* if it's locked and we have it, then the entries should be > 0 */
+    PR_ASSERT(mon->entryCount > 0);
+    mon->entryCount -= 1;  /* reduce by one */
+    if (mon->entryCount == 0)
+    {
+        /* and if it transitioned to zero - unlock */
+        _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);  /* make the owner unknown */
+        PR_Unlock(&mon->lock);
+    }
+    return PR_SUCCESS;
+}  /* PR_ExitMonitor */
+
+PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout)
+{
+    PRStatus rv;
+    PRInt16 saved_entries;
+    pthread_t saved_owner;
+
+    PR_ASSERT(mon != NULL);
+    /* we'd better be locked */
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
+    /* and the entries better be positive */
+    PR_ASSERT(mon->entryCount > 0);
+    /* and it better be by us */
+    PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
+
+    /* tuck these away 'till later */
+    saved_entries = mon->entryCount; 
+    mon->entryCount = 0;
+    _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner);
+    _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
+    
+    rv = PR_WaitCondVar(mon->cvar, timeout);
+
+    /* reinstate the intresting information */
+    mon->entryCount = saved_entries;
+    _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner);
+
+    return rv;
+}  /* PR_Wait */
+
+PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
+{
+    PR_ASSERT(NULL != mon);
+    /* we'd better be locked */
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
+    /* and the entries better be positive */
+    PR_ASSERT(mon->entryCount > 0);
+    /* and it better be by us */
+    PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
+
+    pt_PostNotifyToCvar(mon->cvar, PR_FALSE);
+
+    return PR_SUCCESS;
+}  /* PR_Notify */
+
+PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
+{
+    PR_ASSERT(mon != NULL);
+    /* we'd better be locked */
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
+    /* and the entries better be positive */
+    PR_ASSERT(mon->entryCount > 0);
+    /* and it better be by us */
+    PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
+
+    pt_PostNotifyToCvar(mon->cvar, PR_TRUE);
+
+    return PR_SUCCESS;
+}  /* PR_NotifyAll */
+
+/**************************************************************/
+/**************************************************************/
+/**************************SEMAPHORES**************************/
+/**************************************************************/
+/**************************************************************/
+PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore)
+{
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete(
+        "PR_PostSem", "locks & condition variables");
+	PR_Lock(semaphore->cvar->lock);
+	PR_NotifyCondVar(semaphore->cvar);
+	semaphore->count += 1;
+	PR_Unlock(semaphore->cvar->lock);
+}  /* PR_PostSem */
+
+PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore)
+{
+	PRStatus status = PR_SUCCESS;
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete(
+        "PR_WaitSem", "locks & condition variables");
+	PR_Lock(semaphore->cvar->lock);
+	while ((semaphore->count == 0) && (PR_SUCCESS == status))
+		status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT);
+	if (PR_SUCCESS == status) semaphore->count -= 1;
+	PR_Unlock(semaphore->cvar->lock);
+	return status;
+}  /* PR_WaitSem */
+
+PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore)
+{
+    static PRBool unwarned = PR_TRUE;
+    if (unwarned) unwarned = _PR_Obsolete(
+        "PR_DestroySem", "locks & condition variables");
+    PR_DestroyLock(semaphore->cvar->lock);
+    PR_DestroyCondVar(semaphore->cvar);
+    PR_DELETE(semaphore);
+}  /* PR_DestroySem */
+
+PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
+{
+    PRSemaphore *semaphore;
+    static PRBool unwarned = PR_TRUE;
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (unwarned) unwarned = _PR_Obsolete(
+        "PR_NewSem", "locks & condition variables");
+
+    semaphore = PR_NEWZAP(PRSemaphore);
+    if (NULL != semaphore)
+    {
+        PRLock *lock = PR_NewLock();
+        if (NULL != lock)
+        {
+            semaphore->cvar = PR_NewCondVar(lock);
+            if (NULL != semaphore->cvar)
+            {
+                semaphore->count = value;
+                return semaphore;
+            }
+            PR_DestroyLock(lock);
+        }
+        PR_DELETE(semaphore);
+    }
+    return NULL;
+}
+
+/*
+ * Define the interprocess named semaphore functions.
+ * There are three implementations:
+ * 1. POSIX semaphore based;
+ * 2. System V semaphore based;
+ * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR).
+ */
+
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#include <fcntl.h>
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+    const char *name,
+    PRIntn flags,
+    PRIntn mode,
+    PRUintn value)
+{
+    PRSem *sem;
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+        == PR_FAILURE)
+    {
+        return NULL;
+    }
+
+    sem = PR_NEW(PRSem);
+    if (NULL == sem)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+
+    if (flags & PR_SEM_CREATE)
+    {
+        int oflag = O_CREAT;
+
+        if (flags & PR_SEM_EXCL) oflag |= O_EXCL;
+        sem->sem = sem_open(osname, oflag, mode, value);
+    }
+    else
+    {
+#ifdef HPUX
+        /* Pass 0 as the mode and value arguments to work around a bug. */
+        sem->sem = sem_open(osname, 0, 0, 0);
+#else
+        sem->sem = sem_open(osname, 0);
+#endif
+    }
+    if ((sem_t *) -1 == sem->sem)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        PR_DELETE(sem);
+        return NULL;
+    }
+    return sem;
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+    int rv;
+    rv = sem_wait(sem->sem);
+    if (0 != rv)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+    int rv;
+    rv = sem_post(sem->sem);
+    if (0 != rv)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+    int rv;
+    rv = sem_close(sem->sem);
+    if (0 != rv)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    PR_DELETE(sem);
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+    int rv;
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+        == PR_FAILURE)
+    {
+        return PR_FAILURE;
+    }
+    rv = sem_unlink(osname);
+    if (0 != rv)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+    
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+
+#include <fcntl.h>
+#include <sys/sem.h>
+
+/*
+ * From the semctl(2) man page in glibc 2.0
+ */
+#if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \
+    || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \
+    || defined(DARWIN) || defined(SYMBIAN)
+/* union semun is defined by including <sys/sem.h> */
+#else
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+    int val;
+    struct semid_ds *buf;
+    unsigned short  *array;
+};
+#endif
+
+/*
+ * 'a' (97) is the final closing price of NSCP stock.
+ */
+#define NSPR_IPC_KEY_ID 'a'  /* the id argument for ftok() */
+
+#define NSPR_SEM_MODE 0666
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+    const char *name,
+    PRIntn flags,
+    PRIntn mode,
+    PRUintn value)
+{
+    PRSem *sem;
+    key_t key;
+    union semun arg;
+    struct sembuf sop;
+    struct semid_ds seminfo;
+#define MAX_TRIES 60
+    PRIntn i;
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+        == PR_FAILURE)
+    {
+        return NULL;
+    }
+
+    /* Make sure the file exists before calling ftok. */
+    if (flags & PR_SEM_CREATE)
+    {
+        int osfd = open(osname, O_RDWR|O_CREAT, mode);
+        if (-1 == osfd)
+        {
+            _PR_MD_MAP_OPEN_ERROR(errno);
+            return NULL;
+        }
+        if (close(osfd) == -1)
+        {
+            _PR_MD_MAP_CLOSE_ERROR(errno);
+            return NULL;
+        }
+    }
+    key = ftok(osname, NSPR_IPC_KEY_ID);
+    if ((key_t)-1 == key)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return NULL;
+    }
+
+    sem = PR_NEW(PRSem);
+    if (NULL == sem)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+
+    if (flags & PR_SEM_CREATE)
+    {
+        sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL);
+        if (sem->semid >= 0)
+        {
+            /* creator of a semaphore is responsible for initializing it */
+            arg.val = 0;
+            if (semctl(sem->semid, 0, SETVAL, arg) == -1)
+            {
+                _PR_MD_MAP_DEFAULT_ERROR(errno);
+                PR_DELETE(sem);
+                return NULL;
+            }
+            /* call semop to set sem_otime to nonzero */
+            sop.sem_num = 0;
+            sop.sem_op = value;
+            sop.sem_flg = 0;
+            if (semop(sem->semid, &sop, 1) == -1)
+            {
+                _PR_MD_MAP_DEFAULT_ERROR(errno);
+                PR_DELETE(sem);
+                return NULL;
+            }
+            return sem;
+        }
+
+        if (errno != EEXIST || flags & PR_SEM_EXCL)
+        {
+            _PR_MD_MAP_DEFAULT_ERROR(errno);
+            PR_DELETE(sem);
+            return NULL;
+        }
+    }
+
+    sem->semid = semget(key, 1, NSPR_SEM_MODE);
+    if (sem->semid == -1)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        PR_DELETE(sem);
+        return NULL;
+    }
+    for (i = 0; i < MAX_TRIES; i++)
+    {
+        arg.buf = &seminfo;
+        semctl(sem->semid, 0, IPC_STAT, arg);
+        if (seminfo.sem_otime != 0) break;
+        sleep(1);
+    }
+    if (i == MAX_TRIES)
+    {
+        PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+        PR_DELETE(sem);
+        return NULL;
+    }
+    return sem;
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+    struct sembuf sop;
+
+    sop.sem_num = 0;
+    sop.sem_op = -1;
+    sop.sem_flg = 0;
+    if (semop(sem->semid, &sop, 1) == -1)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+    struct sembuf sop;
+
+    sop.sem_num = 0;
+    sop.sem_op = 1;
+    sop.sem_flg = 0;
+    if (semop(sem->semid, &sop, 1) == -1)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+    PR_DELETE(sem);
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+    key_t key;
+    int semid;
+    /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */
+    union semun unused;
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+        == PR_FAILURE)
+    {
+        return PR_FAILURE;
+    }
+    key = ftok(osname, NSPR_IPC_KEY_ID);
+    if ((key_t) -1 == key)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    if (unlink(osname) == -1)
+    {
+        _PR_MD_MAP_UNLINK_ERROR(errno);
+        return PR_FAILURE;
+    }
+    semid = semget(key, 1, NSPR_SEM_MODE);
+    if (-1 == semid)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    unused.val = 0;
+    if (semctl(semid, 0, IPC_RMID, unused) == -1)
+    { 
+        _PR_MD_MAP_DEFAULT_ERROR(errno);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+#else /* neither POSIX nor System V semaphores are available */
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+    const char *name,
+    PRIntn flags,
+    PRIntn mode,
+    PRUintn value)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+#endif /* end of interprocess named semaphore functions */
+
+/**************************************************************/
+/**************************************************************/
+/******************ROUTINES FOR DCE EMULATION******************/
+/**************************************************************/
+/**************************************************************/
+
+#include "prpdce.h"
+
+PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
+{
+    PRIntn rv = pthread_mutex_trylock(&lock->mutex);
+    if (rv == PT_TRYLOCK_SUCCESS)
+    {
+        PR_ASSERT(PR_FALSE == lock->locked);
+        lock->locked = PR_TRUE;
+        lock->owner = pthread_self();
+    }
+    /* XXX set error code? */
+    return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE;
+}  /* PRP_TryLock */
+
+PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
+{
+    PRCondVar *cv;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    cv = PR_NEW(PRCondVar);
+    if (cv != NULL)
+    {
+        int rv;
+        rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); 
+        PR_ASSERT(0 == rv);
+        cv->lock = _PR_NAKED_CV_LOCK;
+    }
+    return cv;
+}  /* PRP_NewNakedCondVar */
+
+PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
+{
+    int rv;
+    rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
+#if defined(DEBUG)
+        memset(cvar, 0xaf, sizeof(PRCondVar));
+#endif
+    PR_DELETE(cvar);
+}  /* PRP_DestroyNakedCondVar */
+
+PR_IMPLEMENT(PRStatus) PRP_NakedWait(
+    PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout)
+{
+    PRIntn rv;
+    PR_ASSERT(cvar != NULL);
+    /* XXX do we really want to assert this in a naked wait? */
+    PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex));
+    if (timeout == PR_INTERVAL_NO_TIMEOUT)
+        rv = pthread_cond_wait(&cvar->cv, &ml->mutex);
+    else
+        rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout);
+    if (rv != 0)
+    {
+        _PR_MD_MAP_DEFAULT_ERROR(rv);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}  /* PRP_NakedWait */
+
+PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
+{
+    int rv;
+    PR_ASSERT(cvar != NULL);
+    rv = pthread_cond_signal(&cvar->cv);
+    PR_ASSERT(0 == rv);
+    return PR_SUCCESS;
+}  /* PRP_NakedNotify */
+
+PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
+{
+    int rv;
+    PR_ASSERT(cvar != NULL);
+    rv = pthread_cond_broadcast(&cvar->cv);
+    PR_ASSERT(0 == rv);
+    return PR_SUCCESS;
+}  /* PRP_NakedBroadcast */
+
+#endif  /* defined(_PR_PTHREADS) */
+
+/* ptsynch.c */
diff --git a/mozilla/nsprpub/pr/src/pthreads/ptthread.c b/mozilla/nsprpub/pr/src/pthreads/ptthread.c
new file mode 100644
index 0000000..271ecfe
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/pthreads/ptthread.c
@@ -0,0 +1,1668 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** File:            ptthread.c
+** Descritpion:        Implemenation for threds using pthreds
+** Exports:            ptthread.h
+*/
+
+#if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS)
+
+#include "prlog.h"
+#include "primpl.h"
+#include "prpdce.h"
+
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+
+#ifdef SYMBIAN
+/* In Open C sched_get_priority_min/max do not work properly, so we undefine
+ * _POSIX_THREAD_PRIORITY_SCHEDULING here.
+ */
+#undef _POSIX_THREAD_PRIORITY_SCHEDULING
+#endif
+
+/*
+ * Record whether or not we have the privilege to set the scheduling
+ * policy and priority of threads.  0 means that privilege is available.
+ * EPERM means that privilege is not available.
+ */
+
+static PRIntn pt_schedpriv = 0;
+extern PRLock *_pr_sleeplock;
+
+static struct _PT_Bookeeping
+{
+    PRLock *ml;                 /* a lock to protect ourselves */
+    PRCondVar *cv;              /* used to signal global things */
+    PRInt32 system, user;       /* a count of the two different types */
+    PRUintn this_many;          /* number of threads allowed for exit */
+    pthread_key_t key;          /* private private data key */
+    PRThread *first, *last;     /* list of threads we know about */
+#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+    PRInt32 minPrio, maxPrio;   /* range of scheduling priorities */
+#endif
+} pt_book = {0};
+
+static void _pt_thread_death(void *arg);
+static void _pt_thread_death_internal(void *arg, PRBool callDestructors);
+static void init_pthread_gc_support(void);
+
+#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+static PRIntn pt_PriorityMap(PRThreadPriority pri)
+{
+#ifdef NTO
+    /* This priority algorithm causes lots of problems on Neutrino
+     * for now I have just hard coded everything to run at priority 10
+     * until I can come up with a new algorithm.
+     *     Jerry.Kirk@Nexwarecorp.com
+     */
+    return 10;
+#else
+    return pt_book.minPrio +
+	    pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST;
+#endif
+}
+#endif
+
+#if defined(GC_LEAK_DETECTOR) && (__GLIBC__ >= 2) && defined(__i386__) 
+
+#include <setjmp.h>
+
+typedef struct stack_frame stack_frame;
+
+struct stack_frame {
+    stack_frame* next;
+    void* pc;
+};
+
+static stack_frame* GetStackFrame()
+{
+    jmp_buf jb;
+    stack_frame* currentFrame;
+    setjmp(jb);
+    currentFrame = (stack_frame*)(jb[0].__jmpbuf[JB_BP]);
+    currentFrame = currentFrame->next;
+    return currentFrame;
+}
+
+static void* GetStackTop()
+{
+    stack_frame* frame;
+    frame = GetStackFrame();
+    while (frame != NULL)
+    {
+        ptrdiff_t pc = (ptrdiff_t)frame->pc;
+        if ((pc < 0x08000000) || (pc > 0x7fffffff) || (frame->next < frame))
+            return frame;
+        frame = frame->next;
+    }
+    return NULL;
+}
+#endif /* GC_LEAK_DETECTOR && (__GLIBC__ >= 2) && __i386__ */
+
+/*
+** Initialize a stack for a native pthread thread
+*/
+static void _PR_InitializeStack(PRThreadStack *ts)
+{
+    if( ts && (ts->stackTop == 0) ) {
+        ts->allocBase = (char *) &ts;
+        ts->allocSize = ts->stackSize;
+
+        /*
+        ** Setup stackTop and stackBottom values.
+        */
+#ifdef HAVE_STACK_GROWING_UP
+        ts->stackBottom = ts->allocBase + ts->stackSize;
+        ts->stackTop = ts->allocBase;
+#else
+#ifdef GC_LEAK_DETECTOR
+        ts->stackTop    = GetStackTop();
+        ts->stackBottom = ts->stackTop - ts->stackSize;
+#else
+        ts->stackTop    = ts->allocBase;
+        ts->stackBottom = ts->allocBase - ts->stackSize;
+#endif
+#endif
+    }
+}
+
+static void *_pt_root(void *arg)
+{
+    PRIntn rv;
+    PRThread *thred = (PRThread*)arg;
+    PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE;
+
+    /*
+     * Both the parent thread and this new thread set thred->id.
+     * The new thread must ensure that thred->id is set before
+     * it executes its startFunc.  The parent thread must ensure
+     * that thred->id is set before PR_CreateThread() returns.
+     * Both threads set thred->id without holding a lock.  Since
+     * they are writing the same value, this unprotected double
+     * write should be safe.
+     */
+    thred->id = pthread_self();
+
+    /*
+    ** DCE Threads can't detach during creation, so do it late.
+    ** I would like to do it only here, but that doesn't seem
+    ** to work.
+    */
+#if defined(_PR_DCETHREADS)
+    if (detached)
+    {
+        /* pthread_detach() modifies its argument, so we must pass a copy */
+        pthread_t self = thred->id;
+        rv = pthread_detach(&self);
+        PR_ASSERT(0 == rv);
+    }
+#endif /* defined(_PR_DCETHREADS) */
+
+    /* Set up the thread stack information */
+    _PR_InitializeStack(thred->stack);
+
+    /*
+     * Set within the current thread the pointer to our object.
+     * This object will be deleted when the thread termintates,
+     * whether in a join or detached (see _PR_InitThreads()).
+     */
+    rv = pthread_setspecific(pt_book.key, thred);
+    PR_ASSERT(0 == rv);
+
+    /* make the thread visible to the rest of the runtime */
+    PR_Lock(pt_book.ml);
+
+    /* If this is a GCABLE thread, set its state appropriately */
+    if (thred->suspend & PT_THREAD_SETGCABLE)
+	    thred->state |= PT_THREAD_GCABLE;
+    thred->suspend = 0;
+
+    thred->prev = pt_book.last;
+    if (pt_book.last)
+        pt_book.last->next = thred;
+    else
+        pt_book.first = thred;
+    thred->next = NULL;
+    pt_book.last = thred;
+    PR_Unlock(pt_book.ml);
+
+    thred->startFunc(thred->arg);  /* make visible to the client */
+
+    /* unhook the thread from the runtime */
+    PR_Lock(pt_book.ml);
+    /*
+     * At this moment, PR_CreateThread() may not have set thred->id yet.
+     * It is safe for a detached thread to free thred only after
+     * PR_CreateThread() has set thred->id.
+     */
+    if (detached)
+    {
+        while (!thred->okToDelete)
+            PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
+    }
+
+    if (thred->state & PT_THREAD_SYSTEM)
+        pt_book.system -= 1;
+    else if (--pt_book.user == pt_book.this_many)
+        PR_NotifyAllCondVar(pt_book.cv);
+    if (NULL == thred->prev)
+        pt_book.first = thred->next;
+    else
+        thred->prev->next = thred->next;
+    if (NULL == thred->next)
+        pt_book.last = thred->prev;
+    else
+        thred->next->prev = thred->prev;
+    PR_Unlock(pt_book.ml);
+
+    /*
+    * Here we set the pthread's backpointer to the PRThread to NULL.
+    * Otherwise the destructor would get called eagerly as the thread
+    * returns to the pthread runtime. The joining thread would them be
+    * the proud possessor of a dangling reference. However, this is the
+    * last chance to delete the object if the thread is detached, so
+    * just let the destructor do the work.
+    */
+    if (PR_FALSE == detached)
+    {
+        /* Call TPD destructors on this thread. */
+        _PR_DestroyThreadPrivate(thred);
+        rv = pthread_setspecific(pt_book.key, NULL);
+        PR_ASSERT(0 == rv);
+    }
+
+    return NULL;
+}  /* _pt_root */
+
+static PRThread* pt_AttachThread(void)
+{
+    PRThread *thred = NULL;
+
+    /*
+     * NSPR must have been initialized when PR_AttachThread is called.
+     * We cannot have PR_AttachThread call implicit initialization
+     * because if multiple threads call PR_AttachThread simultaneously,
+     * NSPR may be initialized more than once.
+     * We can't call any function that calls PR_GetCurrentThread()
+     * either (e.g., PR_SetError()) as that will result in infinite
+     * recursion.
+     */
+    if (!_pr_initialized) return NULL;
+
+    /* PR_NEWZAP must not call PR_GetCurrentThread() */
+    thred = PR_NEWZAP(PRThread);
+    if (NULL != thred)
+    {
+        int rv;
+
+        thred->priority = PR_PRIORITY_NORMAL;
+        thred->id = pthread_self();
+        rv = pthread_setspecific(pt_book.key, thred);
+        PR_ASSERT(0 == rv);
+
+        thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN;
+        PR_Lock(pt_book.ml);
+
+        /* then put it into the list */
+        thred->prev = pt_book.last;
+        if (pt_book.last)
+            pt_book.last->next = thred;
+        else
+            pt_book.first = thred;
+        thred->next = NULL;
+        pt_book.last = thred;
+        PR_Unlock(pt_book.ml);
+
+    }
+    return thred;  /* may be NULL */
+}  /* pt_AttachThread */
+
+static PRThread* _PR_CreateThread(
+    PRThreadType type, void (*start)(void *arg),
+    void *arg, PRThreadPriority priority, PRThreadScope scope,
+    PRThreadState state, PRUint32 stackSize, PRBool isGCAble)
+{
+    int rv;
+    PRThread *thred;
+    pthread_attr_t tattr;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)
+        priority = PR_PRIORITY_FIRST;
+    else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
+        priority = PR_PRIORITY_LAST;
+
+    rv = _PT_PTHREAD_ATTR_INIT(&tattr);
+    PR_ASSERT(0 == rv);
+
+    if (EPERM != pt_schedpriv)
+    {
+#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+        struct sched_param schedule;
+#endif
+
+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+        rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
+        PR_ASSERT(0 == rv);
+#endif
+
+        /* Use the default scheduling policy */
+
+#if defined(_PR_DCETHREADS)
+        rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));
+        PR_ASSERT(0 == rv);
+#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+        rv = pthread_attr_getschedparam(&tattr, &schedule);
+        PR_ASSERT(0 == rv);
+        schedule.sched_priority = pt_PriorityMap(priority);
+        rv = pthread_attr_setschedparam(&tattr, &schedule);
+        PR_ASSERT(0 == rv);
+#ifdef NTO
+        rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */
+        PR_ASSERT(0 == rv);
+#endif
+#endif /* !defined(_PR_DCETHREADS) */
+    }
+
+    /*
+     * DCE threads can't set detach state before creating the thread.
+     * AIX can't set detach late. Why can't we all just get along?
+     */
+#if !defined(_PR_DCETHREADS)
+    rv = pthread_attr_setdetachstate(&tattr,
+        ((PR_JOINABLE_THREAD == state) ?
+            PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
+    PR_ASSERT(0 == rv);
+#endif /* !defined(_PR_DCETHREADS) */
+
+    /*
+     * If stackSize is 0, we use the default pthread stack size.
+     */
+    if (stackSize)
+    {
+#ifdef _MD_MINIMUM_STACK_SIZE
+        if (stackSize < _MD_MINIMUM_STACK_SIZE)
+            stackSize = _MD_MINIMUM_STACK_SIZE;
+#endif
+        rv = pthread_attr_setstacksize(&tattr, stackSize);
+        PR_ASSERT(0 == rv);
+    }
+
+    thred = PR_NEWZAP(PRThread);
+    if (NULL == thred)
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno);
+        goto done;
+    }
+    else
+    {
+        pthread_t id;
+
+        thred->arg = arg;
+        thred->startFunc = start;
+        thred->priority = priority;
+        if (PR_UNJOINABLE_THREAD == state)
+            thred->state |= PT_THREAD_DETACHED;
+
+        if (PR_LOCAL_THREAD == scope)
+        	scope = PR_GLOBAL_THREAD;
+			
+        if (PR_GLOBAL_BOUND_THREAD == scope) {
+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+    		rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
+			if (rv) {
+				/*
+				 * system scope not supported
+				 */
+        		scope = PR_GLOBAL_THREAD;
+				/*
+				 * reset scope
+				 */
+    			rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);
+    			PR_ASSERT(0 == rv);
+			}
+#endif
+		}
+        if (PR_GLOBAL_THREAD == scope)
+            thred->state |= PT_THREAD_GLOBAL;
+        else if (PR_GLOBAL_BOUND_THREAD == scope)
+            thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND);
+		else	/* force it global */
+            thred->state |= PT_THREAD_GLOBAL;
+        if (PR_SYSTEM_THREAD == type)
+            thred->state |= PT_THREAD_SYSTEM;
+
+        thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;
+
+        thred->stack = PR_NEWZAP(PRThreadStack);
+        if (thred->stack == NULL) {
+            PRIntn oserr = errno;
+            PR_Free(thred);  /* all that work ... poof! */
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr);
+            thred = NULL;  /* and for what? */
+            goto done;
+        }
+        thred->stack->stackSize = stackSize;
+        thred->stack->thr = thred;
+
+#ifdef PT_NO_SIGTIMEDWAIT
+        pthread_mutex_init(&thred->suspendResumeMutex,NULL);
+        pthread_cond_init(&thred->suspendResumeCV,NULL);
+#endif
+
+        /* make the thread counted to the rest of the runtime */
+        PR_Lock(pt_book.ml);
+        if (PR_SYSTEM_THREAD == type)
+            pt_book.system += 1;
+        else pt_book.user += 1;
+        PR_Unlock(pt_book.ml);
+
+        /*
+         * We pass a pointer to a local copy (instead of thred->id)
+         * to pthread_create() because who knows what wacky things
+         * pthread_create() may be doing to its argument.
+         */
+        rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
+
+#if !defined(_PR_DCETHREADS)
+        if (EPERM == rv)
+        {
+#if defined(IRIX)
+        	if (PR_GLOBAL_BOUND_THREAD == scope) {
+				/*
+				 * SCOPE_SYSTEM requires appropriate privilege
+				 * reset to process scope and try again
+				 */
+    			rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);
+    			PR_ASSERT(0 == rv);
+            	thred->state &= ~PT_THREAD_BOUND;
+			}
+#else
+            /* Remember that we don't have thread scheduling privilege. */
+            pt_schedpriv = EPERM;
+            PR_LOG(_pr_thread_lm, PR_LOG_MIN,
+                ("_PR_CreateThread: no thread scheduling privilege"));
+            /* Try creating the thread again without setting priority. */
+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+            rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED);
+            PR_ASSERT(0 == rv);
+#endif
+#endif	/* IRIX */
+            rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
+        }
+#endif
+
+        if (0 != rv)
+        {
+#if defined(_PR_DCETHREADS)
+            PRIntn oserr = errno;
+#else
+            PRIntn oserr = rv;
+#endif
+            PR_Lock(pt_book.ml);
+            if (thred->state & PT_THREAD_SYSTEM)
+                pt_book.system -= 1;
+            else if (--pt_book.user == pt_book.this_many)
+                PR_NotifyAllCondVar(pt_book.cv);
+            PR_Unlock(pt_book.ml);
+
+            PR_Free(thred->stack);
+            PR_Free(thred);  /* all that work ... poof! */
+            PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr);
+            thred = NULL;  /* and for what? */
+            goto done;
+        }
+
+        /*
+         * Both the parent thread and this new thread set thred->id.
+         * The parent thread must ensure that thred->id is set before
+         * PR_CreateThread() returns.  (See comments in _pt_root().)
+         */
+        thred->id = id;
+
+        /*
+         * If the new thread is detached, tell it that PR_CreateThread()
+         * has set thred->id so it's ok to delete thred.
+         */
+        if (PR_UNJOINABLE_THREAD == state)
+        {
+            PR_Lock(pt_book.ml);
+            thred->okToDelete = PR_TRUE;
+            PR_NotifyAllCondVar(pt_book.cv);
+            PR_Unlock(pt_book.ml);
+        }
+    }
+
+done:
+    rv = _PT_PTHREAD_ATTR_DESTROY(&tattr);
+    PR_ASSERT(0 == rv);
+
+    return thred;
+}  /* _PR_CreateThread */
+
+PR_IMPLEMENT(PRThread*) PR_CreateThread(
+    PRThreadType type, void (*start)(void *arg), void *arg,
+    PRThreadPriority priority, PRThreadScope scope,
+    PRThreadState state, PRUint32 stackSize)
+{
+    return _PR_CreateThread(
+        type, start, arg, priority, scope, state, stackSize, PR_FALSE);
+} /* PR_CreateThread */
+
+PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(
+    PRThreadType type, void (*start)(void *arg), void *arg, 
+    PRThreadPriority priority, PRThreadScope scope,
+    PRThreadState state, PRUint32 stackSize)
+{
+    return _PR_CreateThread(
+        type, start, arg, priority, scope, state, stackSize, PR_TRUE);
+}  /* PR_CreateThreadGCAble */
+
+PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred)
+{
+    return thred->environment;
+}  /* GetExecutionEnvironment */
+ 
+PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env)
+{
+    thred->environment = env;
+}  /* SetExecutionEnvironment */
+
+PR_IMPLEMENT(PRThread*) PR_AttachThread(
+    PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
+{
+    return PR_GetCurrentThread();
+}  /* PR_AttachThread */
+
+
+PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)
+{
+    int rv = -1;
+    void *result = NULL;
+    PR_ASSERT(thred != NULL);
+
+    if ((0xafafafaf == thred->state)
+    || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state))
+    || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state)))
+    {
+        /*
+         * This might be a bad address, but if it isn't, the state should
+         * either be an unjoinable thread or it's already had the object
+         * deleted. However, the client that called join on a detached
+         * thread deserves all the rath I can muster....
+         */
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        PR_LogPrint(
+            "PR_JoinThread: %p not joinable | already smashed\n", thred);
+    }
+    else
+    {
+        pthread_t id = thred->id;
+        rv = pthread_join(id, &result);
+        PR_ASSERT(rv == 0 && result == NULL);
+        if (0 == rv)
+        {
+#ifdef _PR_DCETHREADS
+            rv = pthread_detach(&id);
+            PR_ASSERT(0 == rv);
+#endif
+            /*
+             * PR_FALSE, because the thread already called the TPD
+             * destructors before exiting _pt_root.
+             */
+            _pt_thread_death_internal(thred, PR_FALSE);
+        }
+        else
+        {
+            PRErrorCode prerror;
+            switch (rv)
+            {
+                case EINVAL:  /* not a joinable thread */
+                case ESRCH:   /* no thread with given ID */
+                    prerror = PR_INVALID_ARGUMENT_ERROR;
+                    break;
+                case EDEADLK: /* a thread joining with itself */
+                    prerror = PR_DEADLOCK_ERROR;
+                    break;
+                default:
+                    prerror = PR_UNKNOWN_ERROR;
+                    break;
+            }
+            PR_SetError(prerror, rv);
+        }
+    }
+    return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
+}  /* PR_JoinThread */
+
+PR_IMPLEMENT(void) PR_DetachThread(void)
+{
+    void *thred;
+    int rv;
+
+    _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
+    if (NULL == thred) return;
+    _pt_thread_death(thred);
+    rv = pthread_setspecific(pt_book.key, NULL);
+    PR_ASSERT(0 == rv);
+}  /* PR_DetachThread */
+
+PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void)
+{
+    void *thred;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
+    if (NULL == thred) thred = pt_AttachThread();
+    PR_ASSERT(NULL != thred);
+    return (PRThread*)thred;
+}  /* PR_GetCurrentThread */
+
+PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred)
+{
+    return (thred->state & PT_THREAD_BOUND) ?
+        PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD;
+}  /* PR_GetThreadScope() */
+
+PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred)
+{
+    return (thred->state & PT_THREAD_SYSTEM) ?
+        PR_SYSTEM_THREAD : PR_USER_THREAD;
+}
+
+PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred)
+{
+    return (thred->state & PT_THREAD_DETACHED) ?
+        PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
+}  /* PR_GetThreadState */
+
+PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred)
+{
+    PR_ASSERT(thred != NULL);
+    return thred->priority;
+}  /* PR_GetThreadPriority */
+
+PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri)
+{
+    PRIntn rv = -1;
+
+    PR_ASSERT(NULL != thred);
+
+    if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)
+        newPri = PR_PRIORITY_FIRST;
+    else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)
+        newPri = PR_PRIORITY_LAST;
+
+#if defined(_PR_DCETHREADS)
+    rv = pthread_setprio(thred->id, pt_PriorityMap(newPri));
+    /* pthread_setprio returns the old priority */
+#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+    if (EPERM != pt_schedpriv)
+    {
+        int policy;
+        struct sched_param schedule;
+
+        rv = pthread_getschedparam(thred->id, &policy, &schedule);
+        if(0 == rv) {
+			schedule.sched_priority = pt_PriorityMap(newPri);
+			rv = pthread_setschedparam(thred->id, policy, &schedule);
+			if (EPERM == rv)
+			{
+				pt_schedpriv = EPERM;
+				PR_LOG(_pr_thread_lm, PR_LOG_MIN,
+					("PR_SetThreadPriority: no thread scheduling privilege"));
+			}
+		}
+		if (rv != 0)
+			rv = -1;
+    }
+#endif
+
+    thred->priority = newPri;
+}  /* PR_SetThreadPriority */
+
+PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred)
+{
+    /*
+    ** If the target thread indicates that it's waiting,
+    ** find the condition and broadcast to it. Broadcast
+    ** since we don't know which thread (if there are more
+    ** than one). This sounds risky, but clients must
+    ** test their invariants when resumed from a wait and
+    ** I don't expect very many threads to be waiting on
+    ** a single condition and I don't expect interrupt to
+    ** be used very often.
+    **
+    ** I don't know why I thought this would work. Must have
+    ** been one of those weaker momements after I'd been
+    ** smelling the vapors.
+    **
+    ** Even with the followng changes it is possible that
+    ** the pointer to the condition variable is pointing
+    ** at a bogus value. Will the unerlying code detect
+    ** that?
+    */
+    PRCondVar *cv;
+    PR_ASSERT(NULL != thred);
+    if (NULL == thred) return PR_FAILURE;
+
+    thred->state |= PT_THREAD_ABORTED;
+
+    cv = thred->waiting;
+    if ((NULL != cv) && !thred->interrupt_blocked)
+    {
+        PRIntn rv;
+        (void)PR_AtomicIncrement(&cv->notify_pending);
+        rv = pthread_cond_broadcast(&cv->cv);
+        PR_ASSERT(0 == rv);
+        if (0 > PR_AtomicDecrement(&cv->notify_pending))
+            PR_DestroyCondVar(cv);
+    }
+    return PR_SUCCESS;
+}  /* PR_Interrupt */
+
+PR_IMPLEMENT(void) PR_ClearInterrupt(void)
+{
+    PRThread *me = PR_GetCurrentThread();
+    me->state &= ~PT_THREAD_ABORTED;
+}  /* PR_ClearInterrupt */
+
+PR_IMPLEMENT(void) PR_BlockInterrupt(void)
+{
+    PRThread *me = PR_GetCurrentThread();
+    _PT_THREAD_BLOCK_INTERRUPT(me);
+}  /* PR_BlockInterrupt */
+
+PR_IMPLEMENT(void) PR_UnblockInterrupt(void)
+{
+    PRThread *me = PR_GetCurrentThread();
+    _PT_THREAD_UNBLOCK_INTERRUPT(me);
+}  /* PR_UnblockInterrupt */
+
+PR_IMPLEMENT(PRStatus) PR_Yield(void)
+{
+    static PRBool warning = PR_TRUE;
+    if (warning) warning = _PR_Obsolete(
+        "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
+    return PR_Sleep(PR_INTERVAL_NO_WAIT);
+}
+
+PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks)
+{
+    PRStatus rv = PR_SUCCESS;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (PR_INTERVAL_NO_WAIT == ticks)
+    {
+        _PT_PTHREAD_YIELD();
+    }
+    else
+    {
+        PRCondVar *cv;
+        PRIntervalTime timein;
+
+        timein = PR_IntervalNow();
+        cv = PR_NewCondVar(_pr_sleeplock);
+        PR_ASSERT(cv != NULL);
+        PR_Lock(_pr_sleeplock);
+        do
+        {
+            PRIntervalTime now = PR_IntervalNow();
+            PRIntervalTime delta = now - timein;
+            if (delta > ticks) break;
+            rv = PR_WaitCondVar(cv, ticks - delta);
+        } while (PR_SUCCESS == rv);
+        PR_Unlock(_pr_sleeplock);
+        PR_DestroyCondVar(cv);
+    }
+    return rv;
+}  /* PR_Sleep */
+
+static void _pt_thread_death(void *arg)
+{
+    /* PR_TRUE for: call destructors */ 
+    _pt_thread_death_internal(arg, PR_TRUE);
+}
+
+static void _pt_thread_death_internal(void *arg, PRBool callDestructors)
+{
+    PRThread *thred = (PRThread*)arg;
+
+    if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD))
+    {
+        PR_Lock(pt_book.ml);
+        if (NULL == thred->prev)
+            pt_book.first = thred->next;
+        else
+            thred->prev->next = thred->next;
+        if (NULL == thred->next)
+            pt_book.last = thred->prev;
+        else
+            thred->next->prev = thred->prev;
+        PR_Unlock(pt_book.ml);
+    }
+    if (callDestructors)
+        _PR_DestroyThreadPrivate(thred);
+    PR_Free(thred->privateData);
+    if (NULL != thred->errorString)
+        PR_Free(thred->errorString);
+    PR_Free(thred->stack);
+    if (NULL != thred->syspoll_list)
+        PR_Free(thred->syspoll_list);
+#if defined(_PR_POLL_WITH_SELECT)
+    if (NULL != thred->selectfd_list)
+        PR_Free(thred->selectfd_list);
+#endif
+#if defined(DEBUG)
+    memset(thred, 0xaf, sizeof(PRThread));
+#endif /* defined(DEBUG) */
+    PR_Free(thred);
+}  /* _pt_thread_death */
+
+void _PR_InitThreads(
+    PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
+{
+    int rv;
+    PRThread *thred;
+
+#ifdef _PR_NEED_PTHREAD_INIT
+    /*
+     * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily
+     * initialized, but pthread_self() fails to initialize
+     * pthreads and hence returns a null thread ID if invoked
+     * by the primordial thread before any other pthread call.
+     * So we explicitly initialize pthreads here.
+     */
+    pthread_init();
+#endif
+
+#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if defined(FREEBSD)
+    {
+    pthread_attr_t attr;
+    int policy;
+    /* get the min and max priorities of the default policy */
+    pthread_attr_init(&attr);
+    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+    pthread_attr_getschedpolicy(&attr, &policy);
+    pt_book.minPrio = sched_get_priority_min(policy);
+    PR_ASSERT(-1 != pt_book.minPrio);
+    pt_book.maxPrio = sched_get_priority_max(policy);
+    PR_ASSERT(-1 != pt_book.maxPrio);
+    pthread_attr_destroy(&attr);
+    }
+#else
+    /*
+    ** These might be function evaluations
+    */
+    pt_book.minPrio = PT_PRIO_MIN;
+    pt_book.maxPrio = PT_PRIO_MAX;
+#endif
+#endif
+    
+    PR_ASSERT(NULL == pt_book.ml);
+    pt_book.ml = PR_NewLock();
+    PR_ASSERT(NULL != pt_book.ml);
+    pt_book.cv = PR_NewCondVar(pt_book.ml);
+    PR_ASSERT(NULL != pt_book.cv);
+    thred = PR_NEWZAP(PRThread);
+    PR_ASSERT(NULL != thred);
+    thred->arg = NULL;
+    thred->startFunc = NULL;
+    thred->priority = priority;
+    thred->id = pthread_self();
+
+    thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD);
+    if (PR_SYSTEM_THREAD == type)
+    {
+        thred->state |= PT_THREAD_SYSTEM;
+        pt_book.system += 1;
+	    pt_book.this_many = 0;
+    }
+    else
+    {
+	    pt_book.user += 1;
+	    pt_book.this_many = 1;
+    }
+    thred->next = thred->prev = NULL;
+    pt_book.first = pt_book.last = thred;
+
+    thred->stack = PR_NEWZAP(PRThreadStack);
+    PR_ASSERT(thred->stack != NULL);
+    thred->stack->stackSize = 0;
+    thred->stack->thr = thred;
+	_PR_InitializeStack(thred->stack);
+
+    /*
+     * Create a key for our use to store a backpointer in the pthread
+     * to our PRThread object. This object gets deleted when the thread
+     * returns from its root in the case of a detached thread. Other
+     * threads delete the objects in Join.
+     *
+     * NB: The destructor logic seems to have a bug so it isn't used.
+     * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998.
+     * More info - the problem is that pthreads calls the destructor
+     * eagerly as the thread returns from its root, rather than lazily
+     * after the thread is joined. Therefore, threads that are joining
+     * and holding PRThread references are actually holding pointers to
+     * nothing.
+     */
+    rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death);
+    PR_ASSERT(0 == rv);
+    rv = pthread_setspecific(pt_book.key, thred);
+    PR_ASSERT(0 == rv);    
+    PR_SetThreadPriority(thred, priority);
+}  /* _PR_InitThreads */
+
+#ifdef __GNUC__
+/*
+ * GCC supports the constructor and destructor attributes as of
+ * version 2.5.
+ */
+static void _PR_Fini(void) __attribute__ ((destructor));
+#elif defined(__SUNPRO_C)
+/*
+ * Sun Studio compiler
+ */
+#pragma fini(_PR_Fini)
+static void _PR_Fini(void);
+#elif defined(HPUX)
+/*
+ * Current versions of HP C compiler define __HP_cc.
+ * HP C compiler A.11.01.20 doesn't define __HP_cc.
+ */
+#if defined(__ia64) || defined(_LP64)
+#pragma FINI "_PR_Fini"
+static void _PR_Fini(void);
+#else
+/*
+ * Only HP-UX 10.x style initializers are supported in 32-bit links.
+ * Need to use the +I PR_HPUX10xInit linker option.
+ */
+#include <dl.h>
+
+static void _PR_Fini(void);
+
+void PR_HPUX10xInit(shl_t handle, int loading)
+{
+    /*
+     * This function is called when a shared library is loaded as well
+     * as when the shared library is unloaded.  Note that it may not
+     * be called when the user's program terminates.
+     *
+     * handle is the shl_load API handle for the shared library being
+     * initialized.
+     *
+     * loading is non-zero at startup and zero at termination.
+     */
+    if (loading) {
+	/* ... do some initializations ... */
+    } else {
+	_PR_Fini();
+    }
+}
+#endif
+#elif defined(AIX)
+/* Need to use the -binitfini::_PR_Fini linker option. */
+#endif
+
+void _PR_Fini(void)
+{
+    void *thred;
+    int rv;
+
+    if (!_pr_initialized) return;
+
+    _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
+    if (NULL != thred)
+    {
+        /*
+         * PR_FALSE, because it is unsafe to call back to the 
+         * thread private data destructors at final cleanup.
+         */
+        _pt_thread_death_internal(thred, PR_FALSE);
+        rv = pthread_setspecific(pt_book.key, NULL);
+        PR_ASSERT(0 == rv);
+    }
+    /* TODO: free other resources used by NSPR */
+    /* _pr_initialized = PR_FALSE; */
+}  /* _PR_Fini */
+
+PR_IMPLEMENT(PRStatus) PR_Cleanup(void)
+{
+    PRThread *me = PR_GetCurrentThread();
+    int rv;
+    PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
+    PR_ASSERT(me->state & PT_THREAD_PRIMORD);
+    if (me->state & PT_THREAD_PRIMORD)
+    {
+        PR_Lock(pt_book.ml);
+        while (pt_book.user > pt_book.this_many)
+            PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
+        if (me->state & PT_THREAD_SYSTEM)
+            pt_book.system -= 1;
+        else
+            pt_book.user -= 1;
+        PR_Unlock(pt_book.ml);
+
+        _PR_CleanupMW();
+        _PR_CleanupTime();
+        _PR_CleanupDtoa();
+        _PR_CleanupCallOnce();
+        _PR_ShutdownLinker();
+        _PR_LogCleanup();
+        _PR_CleanupNet();
+        /* Close all the fd's before calling _PR_CleanupIO */
+        _PR_CleanupIO();
+        _PR_CleanupCMon();
+
+        _pt_thread_death(me);
+        rv = pthread_setspecific(pt_book.key, NULL);
+        PR_ASSERT(0 == rv);
+        /*
+         * I am not sure if it's safe to delete the cv and lock here,
+         * since there may still be "system" threads around. If this
+         * call isn't immediately prior to exiting, then there's a
+         * problem.
+         */
+        if (0 == pt_book.system)
+        {
+            PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
+            PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
+        }
+        PR_DestroyLock(_pr_sleeplock);
+        _pr_sleeplock = NULL;
+        _PR_CleanupLayerCache();
+        _PR_CleanupEnv();
+#ifdef _PR_ZONE_ALLOCATOR
+        _PR_DestroyZones();
+#endif
+        _pr_initialized = PR_FALSE;
+        return PR_SUCCESS;
+    }
+    return PR_FAILURE;
+}  /* PR_Cleanup */
+
+PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
+{
+    _exit(status);
+}
+
+PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred)
+{
+#if defined(_PR_DCETHREADS)
+    return (PRUint32)&thred->id;  /* this is really a sham! */
+#else
+    return (PRUint32)thred->id;  /* and I don't know what they will do with it */
+#endif
+}
+
+/*
+ * $$$
+ * The following two thread-to-processor affinity functions are not
+ * yet implemented for pthreads.  By the way, these functions should return
+ * PRStatus rather than PRInt32 to indicate the success/failure status.
+ * $$$
+ */
+
+PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
+{
+    return 0;  /* not implemented */
+}
+
+PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
+{
+    return 0;  /* not implemented */
+}
+
+PR_IMPLEMENT(void)
+PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)
+{
+    thread->dump = dump;
+    thread->dumpArg = arg;
+}
+
+/* 
+ * Garbage collection support follows.
+ */
+
+#if defined(_PR_DCETHREADS)
+
+/*
+ * statics for Garbage Collection support.  We don't need to protect these
+ * signal masks since the garbage collector itself is protected by a lock
+ * and multiple threads will not be garbage collecting at the same time.
+ */
+static sigset_t javagc_vtalarm_sigmask;
+static sigset_t javagc_intsoff_sigmask;
+
+#else /* defined(_PR_DCETHREADS) */
+
+/* a bogus signal mask for forcing a timed wait */
+/* Not so bogus in AIX as we really do a sigwait */
+static sigset_t sigwait_set;
+
+static struct timespec onemillisec = {0, 1000000L};
+#ifndef PT_NO_SIGTIMEDWAIT
+static struct timespec hundredmillisec = {0, 100000000L};
+#endif
+
+static void suspend_signal_handler(PRIntn sig);
+
+#ifdef PT_NO_SIGTIMEDWAIT
+static void null_signal_handler(PRIntn sig);
+#endif
+
+#endif /* defined(_PR_DCETHREADS) */
+
+/*
+ * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which
+ * conflict with the use of these two signals in our GC support.
+ * So we don't know how to support GC on Linux pthreads.
+ */
+static void init_pthread_gc_support(void)
+{
+#ifndef SYMBIAN
+    PRIntn rv;
+
+#if defined(_PR_DCETHREADS)
+	rv = sigemptyset(&javagc_vtalarm_sigmask);
+    PR_ASSERT(0 == rv);
+	rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);
+    PR_ASSERT(0 == rv);
+#else  /* defined(_PR_DCETHREADS) */
+	{
+	    struct sigaction sigact_usr2;
+
+	    sigact_usr2.sa_handler = suspend_signal_handler;
+	    sigact_usr2.sa_flags = SA_RESTART;
+	    sigemptyset (&sigact_usr2.sa_mask);
+
+        rv = sigaction (SIGUSR2, &sigact_usr2, NULL);
+        PR_ASSERT(0 == rv);
+
+        sigemptyset (&sigwait_set);
+#if defined(PT_NO_SIGTIMEDWAIT)
+        sigaddset (&sigwait_set, SIGUSR1);
+#else
+        sigaddset (&sigwait_set, SIGUSR2);
+#endif  /* defined(PT_NO_SIGTIMEDWAIT) */
+	}
+#if defined(PT_NO_SIGTIMEDWAIT)
+	{
+	    struct sigaction sigact_null;
+	    sigact_null.sa_handler = null_signal_handler;
+	    sigact_null.sa_flags = SA_RESTART;
+	    sigemptyset (&sigact_null.sa_mask);
+        rv = sigaction (SIGUSR1, &sigact_null, NULL);
+	    PR_ASSERT(0 ==rv); 
+    }
+#endif  /* defined(PT_NO_SIGTIMEDWAIT) */
+#endif /* defined(_PR_DCETHREADS) */
+#endif /* SYMBIAN */
+}
+
+PR_IMPLEMENT(void) PR_SetThreadGCAble(void)
+{
+    PR_Lock(pt_book.ml);
+	PR_GetCurrentThread()->state |= PT_THREAD_GCABLE;
+    PR_Unlock(pt_book.ml);
+}
+
+PR_IMPLEMENT(void) PR_ClearThreadGCAble(void)
+{
+    PR_Lock(pt_book.ml);
+	PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE);
+    PR_Unlock(pt_book.ml);
+}
+
+#if defined(DEBUG)
+static PRBool suspendAllOn = PR_FALSE;
+#endif
+
+static PRBool suspendAllSuspended = PR_FALSE;
+
+PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
+{
+    PRIntn count = 0;
+    PRStatus rv = PR_SUCCESS;
+    PRThread* thred = pt_book.first;
+
+#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
+#if !defined(_PR_DCETHREADS)
+    PRThread *me = PR_GetCurrentThread();
+#endif
+#endif
+
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n"));
+    /*
+     * $$$
+     * Need to suspend all threads other than me before doing this.
+     * This is really a gross and disgusting thing to do. The only
+     * good thing is that since all other threads are suspended, holding
+     * the lock during a callback seems like child's play.
+     * $$$
+     */
+    PR_ASSERT(suspendAllOn);
+
+    while (thred != NULL)
+    {
+        /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
+         * qp->next after applying the function "func".  In particular, "func"
+         * might remove the thread from the queue and put it into another one in
+         * which case qp->next no longer points to the next entry in the original
+         * queue.
+         *
+         * To get around this problem, we save qp->next in qp_next before applying
+         * "func" and use that saved value as the next value after applying "func".
+         */
+        PRThread* next = thred->next;
+
+        if (_PT_IS_GCABLE_THREAD(thred))
+        {
+#if !defined(_PR_DCETHREADS)
+            PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));
+#endif
+            PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+                   ("In PR_EnumerateThreads callback thread %p thid = %X\n", 
+                    thred, thred->id));
+
+            rv = func(thred, count++, arg);
+            if (rv != PR_SUCCESS)
+                return rv;
+        }
+        thred = next;
+    }
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+	   ("End PR_EnumerateThreads count = %d \n", count));
+    return rv;
+}  /* PR_EnumerateThreads */
+
+/*
+ * PR_SuspendAll and PR_ResumeAll are called during garbage collection.  The strategy 
+ * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend.
+ * The signal handler will record the stack pointer and will block until resumed by
+ * the resume call.  Since the signal handler is the last routine called for the
+ * suspended thread, the stack pointer will also serve as a place where all the
+ * registers have been saved on the stack for the previously executing routines.
+ *
+ * Through global variables, we also make sure that PR_Suspend and PR_Resume does not
+ * proceed until the thread is suspended or resumed.
+ */
+
+#if !defined(_PR_DCETHREADS)
+
+/*
+ * In the signal handler, we can not use condition variable notify or wait.
+ * This does not work consistently across all pthread platforms.  We also can not 
+ * use locking since that does not seem to work reliably across platforms.
+ * Only thing we can do is yielding while testing for a global condition
+ * to change.  This does work on pthread supported platforms.  We may have
+ * to play with priortities if there are any problems detected.
+ */
+
+ /* 
+  * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps
+  * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no
+  * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually
+  * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java,
+  * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal
+  * handler as all synchronization mechanisms just break down. 
+  */
+
+#if defined(PT_NO_SIGTIMEDWAIT)
+static void null_signal_handler(PRIntn sig)
+{
+	return;
+}
+#endif
+
+static void suspend_signal_handler(PRIntn sig)
+{
+	PRThread *me = PR_GetCurrentThread();
+
+	PR_ASSERT(me != NULL);
+	PR_ASSERT(_PT_IS_GCABLE_THREAD(me));
+	PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0);
+
+	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+        ("Begin suspend_signal_handler thred %p thread id = %X\n", 
+		me, me->id));
+
+	/*
+	 * save stack pointer
+	 */
+	me->sp = &me;
+
+	/* 
+	   At this point, the thread's stack pointer has been saved,
+	   And it is going to enter a wait loop until it is resumed.
+	   So it is _really_ suspended 
+	*/
+
+	me->suspend |= PT_THREAD_SUSPENDED;
+
+	/*
+	 * now, block current thread
+	 */
+#if defined(PT_NO_SIGTIMEDWAIT)
+	pthread_cond_signal(&me->suspendResumeCV);
+	while (me->suspend & PT_THREAD_SUSPENDED)
+	{
+#if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \
+    && !defined(BSDI) && !defined(UNIXWARE) \
+    && !defined(DARWIN) && !defined(RISCOS) \
+    && !defined(SYMBIAN) /*XXX*/
+        PRIntn rv;
+	    sigwait(&sigwait_set, &rv);
+#endif
+	}
+	me->suspend |= PT_THREAD_RESUMED;
+	pthread_cond_signal(&me->suspendResumeCV);
+#else /* defined(PT_NO_SIGTIMEDWAIT) */
+	while (me->suspend & PT_THREAD_SUSPENDED)
+	{
+		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec);
+    	PR_ASSERT(-1 == rv);
+	}
+	me->suspend |= PT_THREAD_RESUMED;
+#endif
+
+    /*
+     * At this point, thread has been resumed, so set a global condition.
+     * The ResumeAll needs to know that this has really been resumed. 
+     * So the signal handler sets a flag which PR_ResumeAll will reset. 
+     * The PR_ResumeAll must reset this flag ...
+     */
+
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+        ("End suspend_signal_handler thred = %p tid = %X\n", me, me->id));
+}  /* suspend_signal_handler */
+
+static void pt_SuspendSet(PRThread *thred)
+{
+    PRIntn rv;
+
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+	   ("pt_SuspendSet thred %p thread id = %X\n", thred, thred->id));
+
+
+    /*
+     * Check the thread state and signal the thread to suspend
+     */
+
+    PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0);
+
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+	   ("doing pthread_kill in pt_SuspendSet thred %p tid = %X\n",
+	   thred, thred->id));
+#if defined(SYMBIAN)
+    /* All signal group functions are not implemented in Symbian OS */
+    rv = 0;
+#else
+    rv = pthread_kill (thred->id, SIGUSR2);
+#endif
+    PR_ASSERT(0 == rv);
+}
+
+static void pt_SuspendTest(PRThread *thred)
+{
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+	   ("Begin pt_SuspendTest thred %p thread id = %X\n", thred, thred->id));
+
+
+    /*
+     * Wait for the thread to be really suspended. This happens when the
+     * suspend signal handler stores the stack pointer and sets the state
+     * to suspended. 
+     */
+
+#if defined(PT_NO_SIGTIMEDWAIT)
+    pthread_mutex_lock(&thred->suspendResumeMutex);
+    while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
+    {
+	    pthread_cond_timedwait(
+	        &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
+	}
+	pthread_mutex_unlock(&thred->suspendResumeMutex);
+#else
+    while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
+    {
+		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
+    	PR_ASSERT(-1 == rv);
+	}
+#endif
+
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
+        ("End pt_SuspendTest thred %p tid %X\n", thred, thred->id));
+}  /* pt_SuspendTest */
+
+static void pt_ResumeSet(PRThread *thred)
+{
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+	   ("pt_ResumeSet thred %p thread id = %X\n", thred, thred->id));
+
+    /*
+     * Clear the global state and set the thread state so that it will
+     * continue past yield loop in the suspend signal handler
+     */
+
+    PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED);
+
+
+    thred->suspend &= ~PT_THREAD_SUSPENDED;
+
+#if defined(PT_NO_SIGTIMEDWAIT)
+#if defined(SYMBIAN) 
+	/* All signal group functions are not implemented in Symbian OS */
+#else
+	pthread_kill(thred->id, SIGUSR1);
+#endif
+#endif
+
+}  /* pt_ResumeSet */
+
+static void pt_ResumeTest(PRThread *thred)
+{
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+	   ("Begin pt_ResumeTest thred %p thread id = %X\n", thred, thred->id));
+
+    /*
+     * Wait for the threads resume state to change
+     * to indicate it is really resumed 
+     */
+#if defined(PT_NO_SIGTIMEDWAIT)
+    pthread_mutex_lock(&thred->suspendResumeMutex);
+    while ((thred->suspend & PT_THREAD_RESUMED) == 0)
+    {
+	    pthread_cond_timedwait(
+	        &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
+    }
+    pthread_mutex_unlock(&thred->suspendResumeMutex);
+#else
+    while ((thred->suspend & PT_THREAD_RESUMED) == 0) {
+		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
+    	PR_ASSERT(-1 == rv);
+	}
+#endif
+
+    thred->suspend &= ~PT_THREAD_RESUMED;
+
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (
+        "End pt_ResumeTest thred %p tid %X\n", thred, thred->id));
+}  /* pt_ResumeTest */
+
+static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT;
+
+PR_IMPLEMENT(void) PR_SuspendAll(void)
+{
+#ifdef DEBUG
+    PRIntervalTime stime, etime;
+#endif
+    PRThread* thred = pt_book.first;
+    PRThread *me = PR_GetCurrentThread();
+    int rv;
+
+    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
+    PR_ASSERT(0 == rv);
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
+    /*
+     * Stop all threads which are marked GC able.
+     */
+    PR_Lock(pt_book.ml);
+#ifdef DEBUG
+    suspendAllOn = PR_TRUE;
+    stime = PR_IntervalNow();
+#endif
+    while (thred != NULL)
+    {
+	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
+    		pt_SuspendSet(thred);
+        thred = thred->next;
+    }
+
+    /* Wait till they are really suspended */
+    thred = pt_book.first;
+    while (thred != NULL)
+    {
+	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
+            pt_SuspendTest(thred);
+        thred = thred->next;
+    }
+
+    suspendAllSuspended = PR_TRUE;
+
+#ifdef DEBUG
+    etime = PR_IntervalNow();
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\
+        ("End PR_SuspendAll (time %dms)\n",
+        PR_IntervalToMilliseconds(etime - stime)));
+#endif
+}  /* PR_SuspendAll */
+
+PR_IMPLEMENT(void) PR_ResumeAll(void)
+{
+#ifdef DEBUG
+    PRIntervalTime stime, etime;
+#endif
+    PRThread* thred = pt_book.first;
+    PRThread *me = PR_GetCurrentThread();
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
+    /*
+     * Resume all previously suspended GC able threads.
+     */
+    suspendAllSuspended = PR_FALSE;
+#ifdef DEBUG
+    stime = PR_IntervalNow();
+#endif
+
+    while (thred != NULL)
+    {
+	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
+    	    pt_ResumeSet(thred);
+        thred = thred->next;
+    }
+
+    thred = pt_book.first;
+    while (thred != NULL)
+    {
+	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
+    	    pt_ResumeTest(thred);
+        thred = thred->next;
+    }
+
+    PR_Unlock(pt_book.ml);
+#ifdef DEBUG
+    suspendAllOn = PR_FALSE;
+    etime = PR_IntervalNow();
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
+        ("End PR_ResumeAll (time %dms)\n",
+        PR_IntervalToMilliseconds(etime - stime)));
+#endif
+}  /* PR_ResumeAll */
+
+/* Return the stack pointer for the given thread- used by the GC */
+PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred)
+{
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
+	    ("in PR_GetSP thred %p thid = %X, sp = %p\n", 
+	    thred, thred->id, thred->sp));
+    return thred->sp;
+}  /* PR_GetSP */
+
+#else /* !defined(_PR_DCETHREADS) */
+
+static pthread_once_t pt_gc_support_control = pthread_once_init;
+
+/*
+ * For DCE threads, there is no pthread_kill or a way of suspending or resuming a
+ * particular thread.  We will just disable the preemption (virtual timer alarm) and
+ * let the executing thread finish the garbage collection.  This stops all other threads
+ * (GC able or not) and is very inefficient but there is no other choice.
+ */
+PR_IMPLEMENT(void) PR_SuspendAll()
+{
+    PRIntn rv;
+
+    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
+    PR_ASSERT(0 == rv);  /* returns -1 on failure */
+#ifdef DEBUG
+    suspendAllOn = PR_TRUE;
+#endif
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
+    /* 
+     * turn off preemption - i.e add virtual alarm signal to the set of 
+     * blocking signals 
+     */
+    rv = sigprocmask(
+        SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask);
+    PR_ASSERT(0 == rv);
+    suspendAllSuspended = PR_TRUE;
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n"));
+}  /* PR_SuspendAll */
+
+PR_IMPLEMENT(void) PR_ResumeAll()
+{
+    PRIntn rv;
+    
+    suspendAllSuspended = PR_FALSE;
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
+    /* turn on preemption - i.e re-enable virtual alarm signal */
+
+    rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL);
+    PR_ASSERT(0 == rv);
+#ifdef DEBUG
+    suspendAllOn = PR_FALSE;
+#endif
+
+    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n"));
+}  /* PR_ResumeAll */
+
+/* Return the stack pointer for the given thread- used by the GC */
+PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred)
+{
+	pthread_t tid = thred->id;
+	char *thread_tcb, *top_sp;
+
+	/*
+	 * For HPUX DCE threads, pthread_t is a struct with the
+	 * following three fields (see pthread.h, dce/cma.h):
+	 *     cma_t_address       field1;
+	 *     short int           field2;
+	 *     short int           field3;
+	 * where cma_t_address is typedef'd to be either void*
+	 * or char*.
+	 */
+	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n"));
+	thread_tcb = (char*)tid.field1;
+	top_sp = *(char**)(thread_tcb + 128);
+	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %p \n", top_sp));
+	return top_sp;
+}  /* PR_GetSP */
+
+#endif /* !defined(_PR_DCETHREADS) */
+
+#endif  /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
+
+/* ptthread.c */
diff --git a/mozilla/nsprpub/pr/src/threads/combined/prucpu.c b/mozilla/nsprpub/pr/src/threads/combined/prucpu.c
new file mode 100644
index 0000000..3a3596b
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/combined/prucpu.c
@@ -0,0 +1,437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+_PRCPU *_pr_primordialCPU = NULL;
+
+PRInt32 _pr_md_idle_cpus;       /* number of idle cpus */
+/*
+ * The idle threads in MxN models increment/decrement _pr_md_idle_cpus.
+ * If _PR_HAVE_ATOMIC_OPS is not defined, they can't use the atomic
+ * increment/decrement routines (which are based on PR_Lock/PR_Unlock),
+ * because PR_Lock asserts that the calling thread is not an idle thread.
+ * So we use a _MDLock to protect _pr_md_idle_cpus.
+ */
+#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
+#ifndef _PR_HAVE_ATOMIC_OPS
+static _MDLock _pr_md_idle_cpus_lock;
+#endif
+#endif
+PRUintn _pr_numCPU;
+PRInt32 _pr_cpus_exit;
+PRInt32 _pr_cpu_affinity_mask = 0;
+
+#if !defined (_PR_GLOBAL_THREADS_ONLY)
+
+static PRUintn _pr_cpuID;
+
+static void PR_CALLBACK _PR_CPU_Idle(void *);
+
+static _PRCPU *_PR_CreateCPU(void);
+static PRStatus _PR_StartCPU(_PRCPU *cpu, PRThread *thread);
+
+#if !defined(_PR_LOCAL_THREADS_ONLY)
+static void _PR_RunCPU(void *arg);
+#endif
+
+void  _PR_InitCPUs()
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (_native_threads_only)
+        return;
+
+    _pr_cpuID = 0;
+    _MD_NEW_LOCK( &_pr_cpuLock);
+#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
+#ifndef _PR_HAVE_ATOMIC_OPS
+    _MD_NEW_LOCK(&_pr_md_idle_cpus_lock);
+#endif
+#endif
+
+#ifdef _PR_LOCAL_THREADS_ONLY
+
+#ifdef HAVE_CUSTOM_USER_THREADS
+    _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me);
+#endif
+
+    /* Now start the first CPU. */
+    _pr_primordialCPU = _PR_CreateCPU();
+    _pr_numCPU = 1;
+    _PR_StartCPU(_pr_primordialCPU, me);
+
+    _PR_MD_SET_CURRENT_CPU(_pr_primordialCPU);
+
+    /* Initialize cpu for current thread (could be different from me) */
+    _PR_MD_CURRENT_THREAD()->cpu = _pr_primordialCPU;
+
+    _PR_MD_SET_LAST_THREAD(me);
+
+#else /* Combined MxN model */
+
+    _pr_primordialCPU = _PR_CreateCPU();
+    _pr_numCPU = 1;
+    _PR_CreateThread(PR_SYSTEM_THREAD,
+                     _PR_RunCPU,
+                     _pr_primordialCPU,
+                     PR_PRIORITY_NORMAL,
+                     PR_GLOBAL_THREAD,
+                     PR_UNJOINABLE_THREAD,
+                     0,
+                     _PR_IDLE_THREAD);
+
+#endif /* _PR_LOCAL_THREADS_ONLY */
+
+    _PR_MD_INIT_CPUS();
+}
+
+#ifdef WINNT
+/*
+ * Right now this function merely stops the CPUs and does
+ * not do any other cleanup.
+ *
+ * It is only implemented for WINNT because bug 161998 only
+ * affects the WINNT version of NSPR, but it would be nice
+ * to implement this function for other platforms too.
+ */
+void _PR_CleanupCPUs(void)
+{
+    PRUintn i;
+    PRCList *qp;
+    _PRCPU *cpu;
+
+    _pr_cpus_exit = 1;
+    for (i = 0; i < _pr_numCPU; i++) {
+        _PR_MD_WAKEUP_WAITER(NULL);
+    }
+    for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
+        cpu = _PR_CPU_PTR(qp);
+        _PR_MD_JOIN_THREAD(&cpu->thread->md);
+    }
+}
+#endif
+
+static _PRCPUQueue *_PR_CreateCPUQueue(void)
+{
+    PRInt32 index;
+    _PRCPUQueue *cpuQueue;
+    cpuQueue = PR_NEWZAP(_PRCPUQueue);
+ 
+    _MD_NEW_LOCK( &cpuQueue->runQLock );
+    _MD_NEW_LOCK( &cpuQueue->sleepQLock );
+    _MD_NEW_LOCK( &cpuQueue->miscQLock );
+
+    for (index = 0; index < PR_PRIORITY_LAST + 1; index++)
+        PR_INIT_CLIST( &(cpuQueue->runQ[index]) );
+    PR_INIT_CLIST( &(cpuQueue->sleepQ) );
+    PR_INIT_CLIST( &(cpuQueue->pauseQ) );
+    PR_INIT_CLIST( &(cpuQueue->suspendQ) );
+    PR_INIT_CLIST( &(cpuQueue->waitingToJoinQ) );
+
+    cpuQueue->numCPUs = 1;
+
+    return cpuQueue;
+}
+
+/*
+ * Create a new CPU.
+ *
+ * This function initializes enough of the _PRCPU structure so
+ * that it can be accessed safely by a global thread or another
+ * CPU.  This function does not create the native thread that
+ * will run the CPU nor does it initialize the parts of _PRCPU
+ * that must be initialized by that native thread.
+ *
+ * The reason we cannot simply have the native thread create
+ * and fully initialize a new CPU is that we need to be able to
+ * create a usable _pr_primordialCPU in _PR_InitCPUs without
+ * assuming that the primordial CPU thread we created can run
+ * during NSPR initialization.  For example, on Windows while
+ * new threads can be created by DllMain, they won't be able
+ * to run during DLL initialization.  If NSPR is initialized
+ * by DllMain, the primordial CPU thread won't run until DLL
+ * initialization is finished.
+ */
+static _PRCPU *_PR_CreateCPU(void)
+{
+    _PRCPU *cpu;
+
+    cpu = PR_NEWZAP(_PRCPU);
+    if (cpu) {
+        cpu->queue = _PR_CreateCPUQueue();
+        if (!cpu->queue) {
+            PR_DELETE(cpu);
+            return NULL;
+        }
+    }
+    return cpu;
+}
+
+/*
+ * Start a new CPU.
+ *
+ * 'cpu' is a _PRCPU structure created by _PR_CreateCPU().
+ * 'thread' is the native thread that will run the CPU.
+ *
+ * If this function fails, 'cpu' is destroyed.
+ */
+static PRStatus _PR_StartCPU(_PRCPU *cpu, PRThread *thread)
+{
+    /*
+    ** Start a new cpu. The assumption this code makes is that the
+    ** underlying operating system creates a stack to go with the new
+    ** native thread. That stack will be used by the cpu when pausing.
+    */
+
+    PR_ASSERT(!_native_threads_only);
+
+    cpu->last_clock = PR_IntervalNow();
+
+    /* Before we create any threads on this CPU we have to
+     * set the current CPU 
+     */
+    _PR_MD_SET_CURRENT_CPU(cpu);
+    _PR_MD_INIT_RUNNING_CPU(cpu);
+    thread->cpu = cpu;
+
+    cpu->idle_thread = _PR_CreateThread(PR_SYSTEM_THREAD,
+                                        _PR_CPU_Idle,
+                                        (void *)cpu,
+                                        PR_PRIORITY_NORMAL,
+                                        PR_LOCAL_THREAD,
+                                        PR_UNJOINABLE_THREAD,
+                                        0,
+                                        _PR_IDLE_THREAD);
+
+    if (!cpu->idle_thread) {
+        /* didn't clean up CPU queue XXXMB */
+        PR_DELETE(cpu);
+        return PR_FAILURE;
+    } 
+    PR_ASSERT(cpu->idle_thread->cpu == cpu);
+
+    cpu->idle_thread->no_sched = 0;
+
+    cpu->thread = thread;
+
+    if (_pr_cpu_affinity_mask)
+        PR_SetThreadAffinityMask(thread, _pr_cpu_affinity_mask);
+
+    /* Created and started a new CPU */
+    _PR_CPU_LIST_LOCK();
+    cpu->id = _pr_cpuID++;
+    PR_APPEND_LINK(&cpu->links, &_PR_CPUQ());
+    _PR_CPU_LIST_UNLOCK();
+
+    return PR_SUCCESS;
+}
+
+#if !defined(_PR_GLOBAL_THREADS_ONLY) && !defined(_PR_LOCAL_THREADS_ONLY)
+/*
+** This code is used during a cpu's initial creation.
+*/
+static void _PR_RunCPU(void *arg)
+{
+    _PRCPU *cpu = (_PRCPU *)arg;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    PR_ASSERT(NULL != me);
+
+    /*
+     * _PR_StartCPU calls _PR_CreateThread to create the
+     * idle thread.  Because _PR_CreateThread calls PR_Lock,
+     * the current thread has to remain a global thread
+     * during the _PR_StartCPU call so that it can wait for
+     * the lock if the lock is held by another thread.  If
+     * we clear the _PR_GLOBAL_SCOPE flag in
+     * _PR_MD_CREATE_PRIMORDIAL_THREAD, the current thread
+     * will be treated as a local thread and have trouble
+     * waiting for the lock because the CPU is not fully
+     * constructed yet.
+     *
+     * After the CPU is started, it is safe to mark the
+     * current thread as a local thread.
+     */
+
+#ifdef HAVE_CUSTOM_USER_THREADS
+    _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me);
+#endif
+
+    me->no_sched = 1;
+    _PR_StartCPU(cpu, me);
+
+#ifdef HAVE_CUSTOM_USER_THREADS
+    me->flags &= (~_PR_GLOBAL_SCOPE);
+#endif
+
+    _PR_MD_SET_CURRENT_CPU(cpu);
+    _PR_MD_SET_CURRENT_THREAD(cpu->thread);
+    me->cpu = cpu;
+
+    while(1) {
+        PRInt32 is;
+        if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+	    _PR_MD_START_INTERRUPTS();
+        _PR_MD_SWITCH_CONTEXT(me);
+    }
+}
+#endif
+
+static void PR_CALLBACK _PR_CPU_Idle(void *_cpu)
+{
+    _PRCPU *cpu = (_PRCPU *)_cpu;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    PR_ASSERT(NULL != me);
+
+    me->cpu = cpu;
+    cpu->idle_thread = me;
+    if (_MD_LAST_THREAD())
+        _MD_LAST_THREAD()->no_sched = 0;
+    if (!_PR_IS_NATIVE_THREAD(me)) _PR_MD_SET_INTSOFF(0);
+    while(1) {
+        PRInt32 is;
+        PRIntervalTime timeout;
+        if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+
+        _PR_RUNQ_LOCK(cpu);
+#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
+#ifdef _PR_HAVE_ATOMIC_OPS
+        _PR_MD_ATOMIC_INCREMENT(&_pr_md_idle_cpus);
+#else
+        _PR_MD_LOCK(&_pr_md_idle_cpus_lock);
+        _pr_md_idle_cpus++;
+        _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock);
+#endif /* _PR_HAVE_ATOMIC_OPS */
+#endif
+        /* If someone on runq; do a nonblocking PAUSECPU */
+        if (_PR_RUNQREADYMASK(me->cpu) != 0) {
+            _PR_RUNQ_UNLOCK(cpu);
+            timeout = PR_INTERVAL_NO_WAIT;
+        } else {
+            _PR_RUNQ_UNLOCK(cpu);
+
+            _PR_SLEEPQ_LOCK(cpu);
+            if (PR_CLIST_IS_EMPTY(&_PR_SLEEPQ(me->cpu))) {
+                timeout = PR_INTERVAL_NO_TIMEOUT;
+            } else {
+                PRThread *wakeThread;
+                wakeThread = _PR_THREAD_PTR(_PR_SLEEPQ(me->cpu).next);
+                timeout = wakeThread->sleep;
+            }
+            _PR_SLEEPQ_UNLOCK(cpu);
+        }
+
+        /* Wait for an IO to complete */
+        (void)_PR_MD_PAUSE_CPU(timeout);
+
+#ifdef WINNT
+        if (_pr_cpus_exit) {
+            /* _PR_CleanupCPUs tells us to exit */
+            _PR_MD_END_THREAD();
+        }
+#endif
+
+#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
+#ifdef _PR_HAVE_ATOMIC_OPS
+        _PR_MD_ATOMIC_DECREMENT(&_pr_md_idle_cpus);
+#else
+        _PR_MD_LOCK(&_pr_md_idle_cpus_lock);
+        _pr_md_idle_cpus--;
+        _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock);
+#endif /* _PR_HAVE_ATOMIC_OPS */
+#endif
+
+		_PR_ClockInterrupt();
+
+		/* Now schedule any thread that is on the runq
+		 * INTS must be OFF when calling PR_Schedule()
+		 */
+		me->state = _PR_RUNNABLE;
+		_PR_MD_SWITCH_CONTEXT(me);
+		if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is);
+    }
+}
+#endif /* _PR_GLOBAL_THREADS_ONLY */
+
+PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs)
+{
+#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_LOCAL_THREADS_ONLY)
+
+    /* do nothing */
+
+#else /* combined, MxN thread model */
+
+    PRUintn newCPU;
+    _PRCPU *cpu;
+    PRThread *thr;
+
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+	if (_native_threads_only)
+		return;
+    
+    _PR_CPU_LIST_LOCK();
+    if (_pr_numCPU < numCPUs) {
+        newCPU = numCPUs - _pr_numCPU;
+        _pr_numCPU = numCPUs;
+    } else newCPU = 0;
+    _PR_CPU_LIST_UNLOCK();
+
+    for (; newCPU; newCPU--) {
+        cpu = _PR_CreateCPU();
+        thr = _PR_CreateThread(PR_SYSTEM_THREAD,
+                              _PR_RunCPU,
+                              cpu,
+                              PR_PRIORITY_NORMAL,
+                              PR_GLOBAL_THREAD,
+                              PR_UNJOINABLE_THREAD,
+                              0,
+                              _PR_IDLE_THREAD);
+    }
+#endif
+}
+
+PR_IMPLEMENT(_PRCPU *) _PR_GetPrimordialCPU(void)
+{
+    if (_pr_primordialCPU)
+        return _pr_primordialCPU;
+    else
+        return _PR_MD_CURRENT_CPU();
+}
diff --git a/mozilla/nsprpub/pr/src/threads/combined/prucv.c b/mozilla/nsprpub/pr/src/threads/combined/prucv.c
new file mode 100644
index 0000000..6d5d668
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/combined/prucv.c
@@ -0,0 +1,677 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#include "prinrval.h"
+#include "prtypes.h"
+
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths 
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+** 
+*/
+#pragma warning(disable : 4101)
+#endif
+
+
+/*
+** Notify one thread that it has finished waiting on a condition variable
+** Caller must hold the _PR_CVAR_LOCK(cv)
+*/
+PRBool _PR_NotifyThread (PRThread *thread, PRThread *me)
+{
+    PRBool rv;
+
+    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
+
+    _PR_THREAD_LOCK(thread);
+    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
+        if (thread->wait.cvar != NULL) {
+            thread->wait.cvar = NULL;
+
+            _PR_SLEEPQ_LOCK(thread->cpu);
+            /* The notify and timeout can collide; in which case both may
+             * attempt to delete from the sleepQ; only let one do it.
+             */
+            if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
+                _PR_DEL_SLEEPQ(thread, PR_TRUE);
+            _PR_SLEEPQ_UNLOCK(thread->cpu);
+
+	    if (thread->flags & _PR_SUSPENDING) {
+		/*
+		 * set thread state to SUSPENDED; a Resume operation
+		 * on the thread will move it to the runQ
+		 */
+            	thread->state = _PR_SUSPENDED;
+		_PR_MISCQ_LOCK(thread->cpu);
+		_PR_ADD_SUSPENDQ(thread, thread->cpu);
+		_PR_MISCQ_UNLOCK(thread->cpu);
+            	_PR_THREAD_UNLOCK(thread);
+	    } else {
+            	/* Make thread runnable */
+            	thread->state = _PR_RUNNABLE;
+            	_PR_THREAD_UNLOCK(thread);
+
+                _PR_AddThreadToRunQ(me, thread);
+                _PR_MD_WAKEUP_WAITER(thread);
+            }
+
+            rv = PR_TRUE;
+        } else {
+            /* Thread has already been notified */
+            _PR_THREAD_UNLOCK(thread);
+            rv = PR_FALSE;
+        }
+    } else { /* If the thread is a native thread */
+        if (thread->wait.cvar) {
+            thread->wait.cvar = NULL;
+
+	    if (thread->flags & _PR_SUSPENDING) {
+		/*
+		 * set thread state to SUSPENDED; a Resume operation
+		 * on the thread will enable the thread to run
+		 */
+            	thread->state = _PR_SUSPENDED;
+	     } else
+            	thread->state = _PR_RUNNING;
+            _PR_THREAD_UNLOCK(thread);
+            _PR_MD_WAKEUP_WAITER(thread);
+            rv = PR_TRUE;
+        } else {
+            _PR_THREAD_UNLOCK(thread);
+            rv = PR_FALSE;
+        }    
+    }    
+
+    return rv;
+}
+
+/*
+ * Notify thread waiting on cvar; called when thread is interrupted
+ * 	The thread lock is held on entry and released before return
+ */
+void _PR_NotifyLockedThread (PRThread *thread)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRCondVar *cvar;
+    PRThreadPriority pri;
+
+    if ( !_PR_IS_NATIVE_THREAD(me))
+    	PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
+
+    cvar = thread->wait.cvar;
+    thread->wait.cvar = NULL;
+    _PR_THREAD_UNLOCK(thread);
+
+    _PR_CVAR_LOCK(cvar);
+    _PR_THREAD_LOCK(thread);
+
+    if (!_PR_IS_NATIVE_THREAD(thread)) {
+            _PR_SLEEPQ_LOCK(thread->cpu);
+            /* The notify and timeout can collide; in which case both may
+             * attempt to delete from the sleepQ; only let one do it.
+             */
+            if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
+                _PR_DEL_SLEEPQ(thread, PR_TRUE);
+            _PR_SLEEPQ_UNLOCK(thread->cpu);
+
+	    /* Make thread runnable */
+	    pri = thread->priority;
+	    thread->state = _PR_RUNNABLE;
+
+	    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+
+            _PR_AddThreadToRunQ(me, thread);
+            _PR_THREAD_UNLOCK(thread);
+
+            _PR_MD_WAKEUP_WAITER(thread);
+    } else {
+	    if (thread->flags & _PR_SUSPENDING) {
+		/*
+		 * set thread state to SUSPENDED; a Resume operation
+		 * on the thread will enable the thread to run
+		 */
+            	thread->state = _PR_SUSPENDED;
+	     } else
+            	thread->state = _PR_RUNNING;
+            _PR_THREAD_UNLOCK(thread);
+            _PR_MD_WAKEUP_WAITER(thread);
+    }    
+
+    _PR_CVAR_UNLOCK(cvar);
+    return;
+}
+
+/*
+** Make the given thread wait for the given condition variable
+*/
+PRStatus _PR_WaitCondVar(
+    PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
+{
+    PRIntn is;
+    PRStatus rv = PR_SUCCESS;
+
+    PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
+    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+
+#ifdef _PR_GLOBAL_THREADS_ONLY
+    if (_PR_PENDING_INTERRUPT(thread)) {
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        thread->flags &= ~_PR_INTERRUPT;
+        return PR_FAILURE;
+    }
+
+    thread->wait.cvar = cvar;
+    lock->owner = NULL;
+    _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout);
+    thread->wait.cvar = NULL;
+    lock->owner = thread;
+    if (_PR_PENDING_INTERRUPT(thread)) {
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        thread->flags &= ~_PR_INTERRUPT;
+        return PR_FAILURE;
+    }
+
+    return PR_SUCCESS;
+#else  /* _PR_GLOBAL_THREADS_ONLY */
+
+    if ( !_PR_IS_NATIVE_THREAD(thread))
+    	_PR_INTSOFF(is);
+
+    _PR_CVAR_LOCK(cvar);
+    _PR_THREAD_LOCK(thread);
+
+    if (_PR_PENDING_INTERRUPT(thread)) {
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        thread->flags &= ~_PR_INTERRUPT;
+    	_PR_CVAR_UNLOCK(cvar);
+    	_PR_THREAD_UNLOCK(thread);
+    	if ( !_PR_IS_NATIVE_THREAD(thread))
+    		_PR_INTSON(is);
+        return PR_FAILURE;
+    }
+
+    thread->state = _PR_COND_WAIT;
+    thread->wait.cvar = cvar;
+
+    /*
+    ** Put the caller thread on the condition variable's wait Q
+    */
+    PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ);
+
+    /* Note- for global scope threads, we don't put them on the
+     *       global sleepQ, so each global thread must put itself
+     *       to sleep only for the time it wants to.
+     */
+    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
+        _PR_SLEEPQ_LOCK(thread->cpu);
+        _PR_ADD_SLEEPQ(thread, timeout);
+        _PR_SLEEPQ_UNLOCK(thread->cpu);
+    }
+    _PR_CVAR_UNLOCK(cvar);
+    _PR_THREAD_UNLOCK(thread);
+   
+    /* 
+    ** Release lock protecting the condition variable and thereby giving time 
+    ** to the next thread which can potentially notify on the condition variable
+    */
+    PR_Unlock(lock);
+
+    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
+	   ("PR_Wait: cvar=%p waiting for %d", cvar, timeout));
+
+    rv = _PR_MD_WAIT(thread, timeout);
+
+    _PR_CVAR_LOCK(cvar);
+    PR_REMOVE_LINK(&thread->waitQLinks);
+    _PR_CVAR_UNLOCK(cvar);
+
+    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
+	   ("PR_Wait: cvar=%p done waiting", cvar));
+
+    if ( !_PR_IS_NATIVE_THREAD(thread))
+    	_PR_INTSON(is);
+
+    /* Acquire lock again that we had just relinquished */
+    PR_Lock(lock);
+
+    if (_PR_PENDING_INTERRUPT(thread)) {
+        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        thread->flags &= ~_PR_INTERRUPT;
+        return PR_FAILURE;
+    }
+
+    return rv;
+#endif  /* _PR_GLOBAL_THREADS_ONLY */
+}
+
+void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me)
+{
+#ifdef _PR_GLOBAL_THREADS_ONLY
+    _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock);
+#else  /* _PR_GLOBAL_THREADS_ONLY */
+
+    PRCList *q;
+    PRIntn is;
+
+    if ( !_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSOFF(is);
+    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
+
+    _PR_CVAR_LOCK(cvar);
+    q = cvar->condQ.next;
+    while (q != &cvar->condQ) {
+        PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar));
+        if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar)  {
+            if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE)
+                break;
+        }
+        q = q->next;
+    }
+    _PR_CVAR_UNLOCK(cvar);
+
+    if ( !_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSON(is);
+
+#endif  /* _PR_GLOBAL_THREADS_ONLY */
+}
+
+/*
+** Cndition variable debugging log info.
+*/
+PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen)
+{
+    PRUint32 nb;
+
+    if (cvar->lock->owner) {
+	nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]",
+			 cvar, cvar->lock->owner->id, cvar->lock->owner);
+    } else {
+	nb = PR_snprintf(buf, buflen, "[%p]", cvar);
+    }
+    return nb;
+}
+
+/*
+** Expire condition variable waits that are ready to expire. "now" is the current
+** time.
+*/
+void _PR_ClockInterrupt(void)
+{
+    PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
+    _PRCPU *cpu = me->cpu;
+    PRIntervalTime elapsed, now;
+ 
+    PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
+    /* Figure out how much time elapsed since the last clock tick */
+    now = PR_IntervalNow();
+    elapsed = now - cpu->last_clock;
+    cpu->last_clock = now;
+
+    PR_LOG(_pr_clock_lm, PR_LOG_MAX,
+	   ("ExpireWaits: elapsed=%lld usec", elapsed));
+
+    while(1) {
+        _PR_SLEEPQ_LOCK(cpu);
+        if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) {
+            _PR_SLEEPQ_UNLOCK(cpu);
+            break;
+        }
+
+        thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next);
+        PR_ASSERT(thread->cpu == cpu);
+
+        if (elapsed < thread->sleep) {
+            thread->sleep -= elapsed;
+            _PR_SLEEPQMAX(thread->cpu) -= elapsed;
+            _PR_SLEEPQ_UNLOCK(cpu);
+            break;
+        }
+        _PR_SLEEPQ_UNLOCK(cpu);
+
+        PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
+
+        _PR_THREAD_LOCK(thread);
+
+        if (thread->cpu != cpu) {
+            /*
+            ** The thread was switched to another CPU
+            ** between the time we unlocked the sleep
+            ** queue and the time we acquired the thread
+            ** lock, so it is none of our business now.
+            */
+            _PR_THREAD_UNLOCK(thread);
+            continue;
+        }
+
+        /*
+        ** Consume this sleeper's amount of elapsed time from the elapsed
+        ** time value. The next remaining piece of elapsed time will be
+        ** available for the next sleeping thread's timer.
+        */
+        _PR_SLEEPQ_LOCK(cpu);
+        PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ));
+        if (thread->flags & _PR_ON_SLEEPQ) {
+            _PR_DEL_SLEEPQ(thread, PR_FALSE);
+            elapsed -= thread->sleep;
+            _PR_SLEEPQ_UNLOCK(cpu);
+        } else {
+            /* Thread was already handled; Go get another one */
+            _PR_SLEEPQ_UNLOCK(cpu);
+            _PR_THREAD_UNLOCK(thread);
+            continue;
+        }
+
+        /* Notify the thread waiting on the condition variable */
+        if (thread->flags & _PR_SUSPENDING) {
+		PR_ASSERT((thread->state == _PR_IO_WAIT) ||
+				(thread->state == _PR_COND_WAIT));
+            /*
+            ** Thread is suspended and its condition timeout
+            ** expired. Transfer thread from sleepQ to suspendQ.
+            */
+            thread->wait.cvar = NULL;
+            _PR_MISCQ_LOCK(cpu);
+            thread->state = _PR_SUSPENDED;
+            _PR_ADD_SUSPENDQ(thread, cpu);
+            _PR_MISCQ_UNLOCK(cpu);
+        } else {
+            if (thread->wait.cvar) {
+                PRThreadPriority pri;
+
+                /* Do work very similar to what _PR_NotifyThread does */
+                PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) );
+
+                /* Make thread runnable */
+                pri = thread->priority;
+                thread->state = _PR_RUNNABLE;
+                PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+
+                PR_ASSERT(thread->cpu == cpu);
+                _PR_RUNQ_LOCK(cpu);
+                _PR_ADD_RUNQ(thread, cpu, pri);
+                _PR_RUNQ_UNLOCK(cpu);
+
+                if (pri > me->priority)
+                    _PR_SET_RESCHED_FLAG();
+
+                thread->wait.cvar = NULL;
+
+                _PR_MD_WAKEUP_WAITER(thread);
+
+            } else if (thread->io_pending == PR_TRUE) {
+                /* Need to put IO sleeper back on runq */
+                int pri = thread->priority;
+
+                thread->io_suspended = PR_TRUE;
+#ifdef WINNT
+				/*
+				 * For NT, record the cpu on which I/O was issued
+				 * I/O cancellation is done on the same cpu
+				 */
+                thread->md.thr_bound_cpu = cpu;
+#endif
+
+				PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+                PR_ASSERT(thread->cpu == cpu);
+                thread->state = _PR_RUNNABLE;
+                _PR_RUNQ_LOCK(cpu);
+                _PR_ADD_RUNQ(thread, cpu, pri);
+                _PR_RUNQ_UNLOCK(cpu);
+            }
+        }
+        _PR_THREAD_UNLOCK(thread);
+    }
+}
+
+/************************************************************************/
+
+/*
+** Create a new condition variable.
+** 	"lock" is the lock to use with the condition variable.
+**
+** Condition variables are synchronization objects that threads can use
+** to wait for some condition to occur.
+**
+** This may fail if memory is tight or if some operating system resource
+** is low.
+*/
+PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
+{
+    PRCondVar *cvar;
+
+    PR_ASSERT(lock != NULL);
+
+    cvar = PR_NEWZAP(PRCondVar);
+    if (cvar) {
+#ifdef _PR_GLOBAL_THREADS_ONLY
+	if(_PR_MD_NEW_CV(&cvar->md)) {
+		PR_DELETE(cvar);
+		PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+		return NULL;
+	}
+#endif
+        if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) {
+		PR_DELETE(cvar);
+		PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+		return NULL;
+	}
+    cvar->lock = lock;
+	PR_INIT_CLIST(&cvar->condQ);
+
+    } else {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    }
+    return cvar;
+}
+
+/*
+** Destroy a condition variable. There must be no thread
+** waiting on the condvar. The caller is responsible for guaranteeing
+** that the condvar is no longer in use.
+**
+*/
+PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
+{
+    PR_ASSERT(cvar->condQ.next == &cvar->condQ);
+
+#ifdef _PR_GLOBAL_THREADS_ONLY
+    _PR_MD_FREE_CV(&cvar->md);
+#endif
+    _PR_MD_FREE_LOCK(&(cvar->ilock));
+ 
+    PR_DELETE(cvar);
+}
+
+/*
+** Wait for a notify on the condition variable. Sleep for "tiemout" amount
+** of ticks (if "timeout" is zero then the sleep is indefinite). While
+** the thread is waiting it unlocks lock. When the wait has
+** finished the thread regains control of the condition variable after
+** locking the associated lock.
+**
+** The thread waiting on the condvar will be resumed when the condvar is
+** notified (assuming the thread is the next in line to receive the
+** notify) or when the timeout elapses.
+**
+** Returns PR_FAILURE if the caller has not locked the lock associated
+** with the condition variable or the thread has been interrupted.
+*/
+extern PRThread *suspendAllThread;
+PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	PR_ASSERT(cvar->lock->owner == me);
+	PR_ASSERT(me != suspendAllThread);
+    	if (cvar->lock->owner != me) return PR_FAILURE;
+
+	return _PR_WaitCondVar(me, cvar, cvar->lock, timeout);
+}
+
+/*
+** Notify the highest priority thread waiting on the condition
+** variable. If a thread is waiting on the condition variable (using
+** PR_Wait) then it is awakened and begins waiting on the lock.
+*/
+PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    PR_ASSERT(cvar->lock->owner == me);
+    PR_ASSERT(me != suspendAllThread);
+    if (cvar->lock->owner != me) return PR_FAILURE;
+
+    _PR_NotifyCondVar(cvar, me);
+    return PR_SUCCESS;
+}
+
+/*
+** Notify all of the threads waiting on the condition variable. All of
+** threads are notified in turn. The highest priority thread will
+** probably acquire the lock.
+*/
+PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
+{
+    PRCList *q;
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    PR_ASSERT(cvar->lock->owner == me);
+    if (cvar->lock->owner != me) return PR_FAILURE;
+
+#ifdef _PR_GLOBAL_THREADS_ONLY
+    _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock);
+    return PR_SUCCESS;
+#else  /* _PR_GLOBAL_THREADS_ONLY */
+    if ( !_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSOFF(is);
+    _PR_CVAR_LOCK(cvar);
+    q = cvar->condQ.next;
+    while (q != &cvar->condQ) {
+		PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
+		_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
+		q = q->next;
+    }
+    _PR_CVAR_UNLOCK(cvar);
+    if (!_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSON(is);
+
+    return PR_SUCCESS;
+#endif  /* _PR_GLOBAL_THREADS_ONLY */
+}
+
+
+/*********************************************************************/
+/*********************************************************************/
+/********************ROUTINES FOR DCE EMULATION***********************/
+/*********************************************************************/
+/*********************************************************************/
+#include "prpdce.h"
+
+PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
+{
+    PRCondVar *cvar = PR_NEWZAP(PRCondVar);
+    if (NULL != cvar)
+    {
+        if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE)
+        {
+		    PR_DELETE(cvar); cvar = NULL;
+	    }
+	    else
+	    {
+	        PR_INIT_CLIST(&cvar->condQ);
+            cvar->lock = _PR_NAKED_CV_LOCK;
+	    }
+
+    }
+    return cvar;
+}
+
+PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
+{
+    PR_ASSERT(cvar->condQ.next == &cvar->condQ);
+    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
+
+    _PR_MD_FREE_LOCK(&(cvar->ilock));
+ 
+    PR_DELETE(cvar);
+}
+
+PR_IMPLEMENT(PRStatus) PRP_NakedWait(
+	PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
+	return _PR_WaitCondVar(me, cvar, lock, timeout);
+}  /* PRP_NakedWait */
+
+PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
+
+    _PR_NotifyCondVar(cvar, me);
+
+    return PR_SUCCESS;
+}  /* PRP_NakedNotify */
+
+PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
+{
+    PRCList *q;
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
+
+    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+	_PR_MD_LOCK( &(cvar->ilock) );
+    q = cvar->condQ.next;
+    while (q != &cvar->condQ) {
+		PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
+		_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
+		q = q->next;
+    }
+	_PR_MD_UNLOCK( &(cvar->ilock) );
+    if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
+
+    return PR_SUCCESS;
+}  /* PRP_NakedBroadcast */
+
diff --git a/mozilla/nsprpub/pr/src/threads/combined/prulock.c b/mozilla/nsprpub/pr/src/threads/combined/prulock.c
new file mode 100644
index 0000000..b188ed5
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/combined/prulock.c
@@ -0,0 +1,465 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths 
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+** 
+*/
+#pragma warning(disable : 4101)
+#endif
+
+
+void _PR_InitLocks(void)
+{
+	_PR_MD_INIT_LOCKS();
+}
+
+/*
+** Deal with delayed interrupts/requested reschedule during interrupt
+** re-enables.
+*/
+void _PR_IntsOn(_PRCPU *cpu)
+{
+    PRUintn missed, pri, i;
+    _PRInterruptTable *it;
+    PRThread *me;
+
+    PR_ASSERT(cpu);   /* Global threads don't have CPUs */
+    PR_ASSERT(_PR_MD_GET_INTSOFF() > 0);
+	me = _PR_MD_CURRENT_THREAD();
+    PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
+
+    /*
+    ** Process delayed interrupts. This logic is kinda scary because we
+    ** need to avoid losing an interrupt (it's ok to delay an interrupt
+    ** until later).
+    **
+    ** There are two missed state words. _pr_ints.where indicates to the
+    ** interrupt handler which state word is currently safe for
+    ** modification.
+    **
+    ** This code scans both interrupt state words, using the where flag
+    ** to indicate to the interrupt which state word is safe for writing.
+    ** If an interrupt comes in during a scan the other word will be
+    ** modified. This modification will be noticed during the next
+    ** iteration of the loop or during the next call to this routine.
+    */
+    for (i = 0; i < 2; i++) {
+        cpu->where = (1 - i);
+        missed = cpu->u.missed[i];
+        if (missed != 0) {
+            cpu->u.missed[i] = 0;
+            for (it = _pr_interruptTable; it->name; it++) {
+                if (missed & it->missed_bit) {
+                    PR_LOG(_pr_sched_lm, PR_LOG_MIN,
+                           ("IntsOn[0]: %s intr", it->name));
+                    (*it->handler)();
+                }
+            }
+        }
+    }
+
+    if (cpu->u.missed[3] != 0) {
+        _PRCPU *cpu;
+
+		_PR_THREAD_LOCK(me);
+        me->state = _PR_RUNNABLE;
+        pri = me->priority;
+
+        cpu = me->cpu;
+		_PR_RUNQ_LOCK(cpu);
+        _PR_ADD_RUNQ(me, cpu, pri);
+		_PR_RUNQ_UNLOCK(cpu);
+		_PR_THREAD_UNLOCK(me);
+        _PR_MD_SWITCH_CONTEXT(me);
+    }
+}
+
+/*
+** Unblock the first runnable waiting thread. Skip over
+** threads that are trying to be suspended
+** Note: Caller must hold _PR_LOCK_LOCK()
+*/
+void _PR_UnblockLockWaiter(PRLock *lock)
+{
+    PRThread *t = NULL;
+    PRThread *me;
+    PRCList *q;
+
+    q = lock->waitQ.next;
+    PR_ASSERT(q != &lock->waitQ);
+    while (q != &lock->waitQ) {
+        /* Unblock first waiter */
+        t = _PR_THREAD_CONDQ_PTR(q);
+
+		/* 
+		** We are about to change the thread's state to runnable and for local
+		** threads, we are going to assign a cpu to it.  So, protect thread's
+		** data structure.
+		*/
+        _PR_THREAD_LOCK(t);
+
+        if (t->flags & _PR_SUSPENDING) {
+            q = q->next;
+            _PR_THREAD_UNLOCK(t);
+            continue;
+        }
+
+        /* Found a runnable thread */
+	    PR_ASSERT(t->state == _PR_LOCK_WAIT);
+	    PR_ASSERT(t->wait.lock == lock);
+        t->wait.lock = 0;
+        PR_REMOVE_LINK(&t->waitQLinks);         /* take it off lock's waitQ */
+
+		/*
+		** If this is a native thread, nothing else to do except to wake it
+		** up by calling the machine dependent wakeup routine.
+		**
+		** If this is a local thread, we need to assign it a cpu and
+		** put the thread on that cpu's run queue.  There are two cases to
+		** take care of.  If the currently running thread is also a local
+		** thread, we just assign our own cpu to that thread and put it on
+		** the cpu's run queue.  If the the currently running thread is a
+		** native thread, we assign the primordial cpu to it (on NT,
+		** MD_WAKEUP handles the cpu assignment).  
+		*/
+		
+        if ( !_PR_IS_NATIVE_THREAD(t) ) {
+
+            t->state = _PR_RUNNABLE;
+
+            me = _PR_MD_CURRENT_THREAD();
+
+            _PR_AddThreadToRunQ(me, t);
+            _PR_THREAD_UNLOCK(t);
+        } else {
+            t->state = _PR_RUNNING;
+            _PR_THREAD_UNLOCK(t);
+        }
+        _PR_MD_WAKEUP_WAITER(t);
+        break;
+    }
+    return;
+}
+
+/************************************************************************/
+
+
+PR_IMPLEMENT(PRLock*) PR_NewLock(void)
+{
+    PRLock *lock;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    lock = PR_NEWZAP(PRLock);
+    if (lock) {
+        if (_PR_MD_NEW_LOCK(&lock->ilock) == PR_FAILURE) {
+		PR_DELETE(lock);
+		return(NULL);
+	}
+        PR_INIT_CLIST(&lock->links);
+        PR_INIT_CLIST(&lock->waitQ);
+    }
+    return lock;
+}
+
+/*
+** Destroy the given lock "lock". There is no point in making this race
+** free because if some other thread has the pointer to this lock all
+** bets are off.
+*/
+PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock)
+{
+    PR_ASSERT(lock->owner == 0);
+	_PR_MD_FREE_LOCK(&lock->ilock);
+    PR_DELETE(lock);
+}
+
+extern PRThread *suspendAllThread;
+/*
+** Lock the lock.
+*/
+PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRIntn is;
+    PRThread *t;
+    PRCList *q;
+
+    PR_ASSERT(me != suspendAllThread); 
+    PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
+    PR_ASSERT(lock != NULL);
+#ifdef _PR_GLOBAL_THREADS_ONLY 
+    PR_ASSERT(lock->owner != me);
+    _PR_MD_LOCK(&lock->ilock);
+    lock->owner = me;
+    return;
+#else  /* _PR_GLOBAL_THREADS_ONLY */
+
+	if (_native_threads_only) {
+		PR_ASSERT(lock->owner != me);
+		_PR_MD_LOCK(&lock->ilock);
+		lock->owner = me;
+		return;
+	}
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSOFF(is);
+
+    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
+
+retry:
+    _PR_LOCK_LOCK(lock);
+    if (lock->owner == 0) {
+        /* Just got the lock */
+        lock->owner = me;
+        lock->priority = me->priority;
+		/* Add the granted lock to this owning thread's lock list */
+        PR_APPEND_LINK(&lock->links, &me->lockList);
+        _PR_LOCK_UNLOCK(lock);
+    	if (!_PR_IS_NATIVE_THREAD(me))
+        	_PR_FAST_INTSON(is);
+        return;
+    }
+
+    /* If this thread already owns this lock, then it is a deadlock */
+    PR_ASSERT(lock->owner != me);
+
+    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
+
+#if 0
+    if (me->priority > lock->owner->priority) {
+        /*
+        ** Give the lock owner a priority boost until we get the
+        ** lock. Record the priority we boosted it to.
+        */
+        lock->boostPriority = me->priority;
+        _PR_SetThreadPriority(lock->owner, me->priority);
+    }
+#endif
+
+    /* 
+    Add this thread to the asked for lock's list of waiting threads.  We
+    add this thread thread in the right priority order so when the unlock
+    occurs, the thread with the higher priority will get the lock.
+    */
+    q = lock->waitQ.next;
+    if (q == &lock->waitQ || _PR_THREAD_CONDQ_PTR(q)->priority ==
+      	_PR_THREAD_CONDQ_PTR(lock->waitQ.prev)->priority) {
+		/*
+		 * If all the threads in the lock waitQ have the same priority,
+		 * then avoid scanning the list:  insert the element at the end.
+		 */
+		q = &lock->waitQ;
+    } else {
+		/* Sort thread into lock's waitQ at appropriate point */
+		/* Now scan the list for where to insert this entry */
+		while (q != &lock->waitQ) {
+			t = _PR_THREAD_CONDQ_PTR(lock->waitQ.next);
+			if (me->priority > t->priority) {
+				/* Found a lower priority thread to insert in front of */
+				break;
+			}
+			q = q->next;
+		}
+	}
+    PR_INSERT_BEFORE(&me->waitQLinks, q);
+
+	/* 
+	Now grab the threadLock since we are about to change the state.  We have
+	to do this since a PR_Suspend or PR_SetThreadPriority type call that takes
+	a PRThread* as an argument could be changing the state of this thread from
+	a thread running on a different cpu.
+	*/
+
+    _PR_THREAD_LOCK(me);
+    me->state = _PR_LOCK_WAIT;
+    me->wait.lock = lock;
+    _PR_THREAD_UNLOCK(me);
+
+    _PR_LOCK_UNLOCK(lock);
+
+    _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
+	goto retry;
+
+#endif  /* _PR_GLOBAL_THREADS_ONLY */
+}
+
+/*
+** Unlock the lock.
+*/
+PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
+{
+    PRCList *q;
+    PRThreadPriority pri, boost;
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    PR_ASSERT(lock != NULL);
+    PR_ASSERT(lock->owner == me);
+    PR_ASSERT(me != suspendAllThread); 
+    PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
+    if (lock->owner != me) {
+        return PR_FAILURE;
+    }
+
+#ifdef _PR_GLOBAL_THREADS_ONLY 
+    lock->owner = 0;
+    _PR_MD_UNLOCK(&lock->ilock);
+    return PR_SUCCESS;
+#else  /* _PR_GLOBAL_THREADS_ONLY */
+
+	if (_native_threads_only) {
+		lock->owner = 0;
+		_PR_MD_UNLOCK(&lock->ilock);
+		return PR_SUCCESS;
+	}
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSOFF(is);
+    _PR_LOCK_LOCK(lock);
+
+	/* Remove the lock from the owning thread's lock list */
+    PR_REMOVE_LINK(&lock->links);
+    pri = lock->priority;
+    boost = lock->boostPriority;
+    if (boost > pri) {
+        /*
+        ** We received a priority boost during the time we held the lock.
+        ** We need to figure out what priority to move to by scanning
+        ** down our list of lock's that we are still holding and using
+        ** the highest boosted priority found.
+        */
+        q = me->lockList.next;
+        while (q != &me->lockList) {
+            PRLock *ll = _PR_LOCK_PTR(q);
+            if (ll->boostPriority > pri) {
+                pri = ll->boostPriority;
+            }
+            q = q->next;
+        }
+        if (pri != me->priority) {
+            _PR_SetThreadPriority(me, pri);
+        }
+    }
+
+    /* Unblock the first waiting thread */
+    q = lock->waitQ.next;
+    if (q != &lock->waitQ)
+        _PR_UnblockLockWaiter(lock);
+    lock->boostPriority = PR_PRIORITY_LOW;
+    lock->owner = 0;
+    _PR_LOCK_UNLOCK(lock);
+    if (!_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSON(is);
+    return PR_SUCCESS;
+#endif  /* _PR_GLOBAL_THREADS_ONLY */
+}
+
+/*
+**  If the current thread owns |lock|, this assertion is guaranteed to
+**  succeed.  Otherwise, the behavior of this function is undefined.
+*/
+PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PR_ASSERT(lock->owner == me);
+}
+
+/*
+** Test and then lock the lock if it's not already locked by some other
+** thread. Return PR_FALSE if some other thread owned the lock at the
+** time of the call.
+*/
+PR_IMPLEMENT(PRBool) PR_TestAndLock(PRLock *lock)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRBool rv = PR_FALSE;
+    PRIntn is;
+
+#ifdef _PR_GLOBAL_THREADS_ONLY 
+    is = _PR_MD_TEST_AND_LOCK(&lock->ilock);
+    if (is == 0) {
+        lock->owner = me;
+        return PR_TRUE;
+    }
+    return PR_FALSE;
+#else  /* _PR_GLOBAL_THREADS_ONLY */
+
+#ifndef _PR_LOCAL_THREADS_ONLY
+	if (_native_threads_only) {
+		is = _PR_MD_TEST_AND_LOCK(&lock->ilock);
+		if (is == 0) {
+			lock->owner = me;
+			return PR_TRUE;
+		}
+    	return PR_FALSE;
+	}
+#endif
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSOFF(is);
+
+    _PR_LOCK_LOCK(lock);
+    if (lock->owner == 0) {
+        /* Just got the lock */
+        lock->owner = me;
+        lock->priority = me->priority;
+		/* Add the granted lock to this owning thread's lock list */
+        PR_APPEND_LINK(&lock->links, &me->lockList);
+        rv = PR_TRUE;
+    }
+    _PR_LOCK_UNLOCK(lock);
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+    	_PR_INTSON(is);
+    return rv;
+#endif  /* _PR_GLOBAL_THREADS_ONLY */
+}
+
+/************************************************************************/
+/************************************************************************/
+/***********************ROUTINES FOR DCE EMULATION***********************/
+/************************************************************************/
+/************************************************************************/
+PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
+    { return (PR_TestAndLock(lock)) ? PR_SUCCESS : PR_FAILURE; }
diff --git a/mozilla/nsprpub/pr/src/threads/combined/prustack.c b/mozilla/nsprpub/pr/src/threads/combined/prustack.c
new file mode 100644
index 0000000..fe15843
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/combined/prustack.c
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+/* List of free stack virtual memory chunks */
+PRLock *_pr_stackLock;
+PRCList _pr_freeStacks = PR_INIT_STATIC_CLIST(&_pr_freeStacks);
+PRIntn _pr_numFreeStacks;
+PRIntn _pr_maxFreeStacks = 4;
+
+#ifdef DEBUG
+/*
+** A variable that can be set via the debugger...
+*/
+PRBool _pr_debugStacks = PR_FALSE;
+#endif
+
+/* How much space to leave between the stacks, at each end */
+#define REDZONE		(2 << _pr_pageShift)
+
+#define _PR_THREAD_STACK_PTR(_qp) \
+    ((PRThreadStack*) ((char*) (_qp) - offsetof(PRThreadStack,links)))
+
+void _PR_InitStacks(void)
+{
+    _pr_stackLock = PR_NewLock();
+}
+
+void _PR_CleanupStacks(void)
+{
+    if (_pr_stackLock) {
+        PR_DestroyLock(_pr_stackLock);
+        _pr_stackLock = NULL;
+    }
+}
+
+/*
+** Allocate a stack for a thread.
+*/
+PRThreadStack *_PR_NewStack(PRUint32 stackSize)
+{
+    PRCList *qp;
+    PRThreadStack *ts;
+    PRThread *thr;
+
+    /*
+    ** Trim the list of free stacks. Trim it backwards, tossing out the
+    ** oldest stack found first (this way more recent stacks have a
+    ** chance of being present in the data cache).
+    */
+    PR_Lock(_pr_stackLock);
+    qp = _pr_freeStacks.prev;
+    while ((_pr_numFreeStacks > _pr_maxFreeStacks) && (qp != &_pr_freeStacks)) {
+	ts = _PR_THREAD_STACK_PTR(qp);
+	thr = _PR_THREAD_STACK_TO_PTR(ts);
+	qp = qp->prev;
+	/*
+	 * skip stacks which are still being used
+	 */
+	if (thr->no_sched)
+		continue;
+	PR_REMOVE_LINK(&ts->links);
+
+	/* Give platform OS to clear out the stack for debugging */
+	_PR_MD_CLEAR_STACK(ts);
+
+	_pr_numFreeStacks--;
+	_PR_DestroySegment(ts->seg);
+	PR_DELETE(ts);
+    }
+
+    /*
+    ** Find a free thread stack. This searches the list of free'd up
+    ** virtually mapped thread stacks.
+    */
+    qp = _pr_freeStacks.next;
+    ts = 0;
+    while (qp != &_pr_freeStacks) {
+	ts = _PR_THREAD_STACK_PTR(qp);
+	thr = _PR_THREAD_STACK_TO_PTR(ts);
+	qp = qp->next;
+	/*
+	 * skip stacks which are still being used
+	 */
+	if ((!(thr->no_sched)) && ((ts->allocSize - 2*REDZONE) >= stackSize)) {
+	    /*
+	    ** Found a stack that is not in use and is big enough. Change
+	    ** stackSize to fit it.
+	    */
+	    stackSize = ts->allocSize - 2*REDZONE;
+	    PR_REMOVE_LINK(&ts->links);
+	    _pr_numFreeStacks--;
+	    ts->links.next = 0;
+	    ts->links.prev = 0;
+	    PR_Unlock(_pr_stackLock);
+	    goto done;
+	}
+	ts = 0;
+    }
+    PR_Unlock(_pr_stackLock);
+
+    if (!ts) {
+	/* Make a new thread stack object. */
+	ts = PR_NEWZAP(PRThreadStack);
+	if (!ts) {
+	    return NULL;
+	}
+
+	/*
+	** Assign some of the virtual space to the new stack object. We
+	** may not get that piece of VM, but if nothing else we will
+	** advance the pointer so we don't collide (unless the OS screws
+	** up).
+	*/
+	ts->allocSize = stackSize + 2*REDZONE;
+	ts->seg = _PR_NewSegment(ts->allocSize, 0);
+	if (!ts->seg) {
+	    PR_DELETE(ts);
+	    return NULL;
+	}
+	}
+
+  done:
+    ts->allocBase = (char*)ts->seg->vaddr;
+    ts->flags = _PR_STACK_MAPPED;
+    ts->stackSize = stackSize;
+
+#ifdef HAVE_STACK_GROWING_UP
+    ts->stackTop = ts->allocBase + REDZONE;
+    ts->stackBottom = ts->stackTop + stackSize;
+#else
+    ts->stackBottom = ts->allocBase + REDZONE;
+    ts->stackTop = ts->stackBottom + stackSize;
+#endif
+
+    PR_LOG(_pr_thread_lm, PR_LOG_NOTICE,
+	   ("thread stack: base=0x%x limit=0x%x bottom=0x%x top=0x%x\n",
+	    ts->allocBase, ts->allocBase + ts->allocSize - 1,
+	    ts->allocBase + REDZONE,
+	    ts->allocBase + REDZONE + stackSize - 1));
+	    
+    _PR_MD_INIT_STACK(ts,REDZONE);
+
+    return ts;
+}
+
+/*
+** Free the stack for the current thread
+*/
+void _PR_FreeStack(PRThreadStack *ts)
+{
+    if (!ts) {
+	return;
+    }
+    if (ts->flags & _PR_STACK_PRIMORDIAL) {
+	PR_DELETE(ts);
+	return;
+    }
+
+    /*
+    ** Put the stack on the free list. This is done because we are still
+    ** using the stack. Next time a thread is created we will trim the
+    ** list down; it's safe to do it then because we will have had to
+    ** context switch to a live stack before another thread can be
+    ** created.
+    */
+    PR_Lock(_pr_stackLock);
+    PR_APPEND_LINK(&ts->links, _pr_freeStacks.prev);
+    _pr_numFreeStacks++;
+    PR_Unlock(_pr_stackLock);
+}
diff --git a/mozilla/nsprpub/pr/src/threads/combined/pruthr.c b/mozilla/nsprpub/pr/src/threads/combined/pruthr.c
new file mode 100644
index 0000000..9609d4d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/combined/pruthr.c
@@ -0,0 +1,1895 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#include <signal.h>
+#include <string.h>
+
+#if defined(WIN95)                                                                         
+/*
+** Some local variables report warnings on Win95 because the code paths
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+**
+*/
+#pragma warning(disable : 4101)
+#endif          
+
+/* _pr_activeLock protects the following global variables */
+PRLock *_pr_activeLock;
+PRInt32 _pr_primordialExitCount;   /* In PR_Cleanup(), the primordial thread
+                    * waits until all other user (non-system)
+                    * threads have terminated before it exits.
+                    * So whenever we decrement _pr_userActive,
+                    * it is compared with
+                    * _pr_primordialExitCount.
+                    * If the primordial thread is a system
+                    * thread, then _pr_primordialExitCount
+                    * is 0.  If the primordial thread is
+                    * itself a user thread, then 
+                    * _pr_primordialThread is 1.
+                    */
+PRCondVar *_pr_primordialExitCVar; /* When _pr_userActive is decremented to
+                    * _pr_primordialExitCount, this condition
+                    * variable is notified.
+                    */
+
+PRLock *_pr_deadQLock;
+PRUint32 _pr_numNativeDead;
+PRUint32 _pr_numUserDead;
+PRCList _pr_deadNativeQ;
+PRCList _pr_deadUserQ;
+
+PRUint32 _pr_join_counter;
+
+PRUint32 _pr_local_threads;
+PRUint32 _pr_global_threads;
+
+PRBool suspendAllOn = PR_FALSE;
+PRThread *suspendAllThread = NULL;
+
+extern PRCList _pr_active_global_threadQ;
+extern PRCList _pr_active_local_threadQ;
+
+static void _PR_DecrActiveThreadCount(PRThread *thread);
+static PRThread *_PR_AttachThread(PRThreadType, PRThreadPriority, PRThreadStack *);
+static void _PR_InitializeNativeStack(PRThreadStack *ts);
+static void _PR_InitializeRecycledThread(PRThread *thread);
+static void _PR_UserRunThread(void);
+
+void _PR_InitThreads(PRThreadType type, PRThreadPriority priority,
+    PRUintn maxPTDs)
+{
+    PRThread *thread;
+    PRThreadStack *stack;
+
+    _pr_terminationCVLock = PR_NewLock();
+    _pr_activeLock = PR_NewLock();
+
+#ifndef HAVE_CUSTOM_USER_THREADS
+    stack = PR_NEWZAP(PRThreadStack);
+#ifdef HAVE_STACK_GROWING_UP
+    stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift)
+                  << _pr_pageShift);
+#else
+#if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS)
+    stack->stackTop = (char*) &thread;
+#else
+    stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1)
+                >> _pr_pageShift) << _pr_pageShift);
+#endif
+#endif
+#else
+    /* If stack is NULL, we're using custom user threads like NT fibers. */
+    stack = PR_NEWZAP(PRThreadStack);
+    if (stack) {
+        stack->stackSize = 0;
+        _PR_InitializeNativeStack(stack);
+    }
+#endif /* HAVE_CUSTOM_USER_THREADS */
+
+    thread = _PR_AttachThread(type, priority, stack);
+    if (thread) {
+        _PR_MD_SET_CURRENT_THREAD(thread);
+
+        if (type == PR_SYSTEM_THREAD) {
+            thread->flags = _PR_SYSTEM;
+            _pr_systemActive++;
+            _pr_primordialExitCount = 0;
+        } else {
+            _pr_userActive++;
+            _pr_primordialExitCount = 1;
+        }
+    thread->no_sched = 1;
+    _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock);
+    }
+
+    if (!thread) PR_Abort();
+#ifdef _PR_LOCAL_THREADS_ONLY
+    thread->flags |= _PR_PRIMORDIAL;
+#else
+    thread->flags |= _PR_PRIMORDIAL | _PR_GLOBAL_SCOPE;
+#endif
+
+    /*
+     * Needs _PR_PRIMORDIAL flag set before calling
+     * _PR_MD_INIT_THREAD()
+     */
+    if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
+        /*
+         * XXX do what?
+         */
+    }
+
+    if (_PR_IS_NATIVE_THREAD(thread)) {
+        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
+        _pr_global_threads++;
+    } else {
+        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
+        _pr_local_threads++;
+    }
+
+    _pr_recycleThreads = 0;
+    _pr_deadQLock = PR_NewLock();
+    _pr_numNativeDead = 0;
+    _pr_numUserDead = 0;
+    PR_INIT_CLIST(&_pr_deadNativeQ);
+    PR_INIT_CLIST(&_pr_deadUserQ);
+}
+
+void _PR_CleanupThreads(void)
+{
+    if (_pr_terminationCVLock) {
+        PR_DestroyLock(_pr_terminationCVLock);
+        _pr_terminationCVLock = NULL;
+    }
+    if (_pr_activeLock) {
+        PR_DestroyLock(_pr_activeLock);
+        _pr_activeLock = NULL;
+    }
+    if (_pr_primordialExitCVar) {
+        PR_DestroyCondVar(_pr_primordialExitCVar);
+        _pr_primordialExitCVar = NULL;
+    }
+    /* TODO _pr_dead{Native,User}Q need to be deleted */
+    if (_pr_deadQLock) {
+        PR_DestroyLock(_pr_deadQLock);
+        _pr_deadQLock = NULL;
+    }
+}
+
+/*
+** Initialize a stack for a native thread
+*/
+static void _PR_InitializeNativeStack(PRThreadStack *ts)
+{
+    if( ts && (ts->stackTop == 0) ) {
+        ts->allocSize = ts->stackSize;
+
+        /*
+        ** Setup stackTop and stackBottom values.
+        */
+#ifdef HAVE_STACK_GROWING_UP
+    ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift)
+                  << _pr_pageShift);
+        ts->stackBottom = ts->allocBase + ts->stackSize;
+        ts->stackTop = ts->allocBase;
+#else
+        ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1)
+                >> _pr_pageShift) << _pr_pageShift);
+        ts->stackTop    = ts->allocBase;
+        ts->stackBottom = ts->allocBase - ts->stackSize;
+#endif
+    }
+}
+
+void _PR_NotifyJoinWaiters(PRThread *thread)
+{
+    /*
+    ** Handle joinable threads.  Change the state to waiting for join.
+    ** Remove from our run Q and put it on global waiting to join Q.
+    ** Notify on our "termination" condition variable so that joining
+    ** thread will know about our termination.  Switch our context and
+    ** come back later on to continue the cleanup.
+    */    
+    PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
+    if (thread->term != NULL) {
+        PR_Lock(_pr_terminationCVLock);
+        _PR_THREAD_LOCK(thread);
+        thread->state = _PR_JOIN_WAIT;
+        if ( !_PR_IS_NATIVE_THREAD(thread) ) {
+            _PR_MISCQ_LOCK(thread->cpu);
+            _PR_ADD_JOINQ(thread, thread->cpu);
+            _PR_MISCQ_UNLOCK(thread->cpu);
+        }
+        _PR_THREAD_UNLOCK(thread);
+        PR_NotifyCondVar(thread->term);
+        PR_Unlock(_pr_terminationCVLock);
+        _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
+        PR_ASSERT(thread->state != _PR_JOIN_WAIT);
+    }
+
+}
+
+/*
+ * Zero some of the data members of a recycled thread.
+ *
+ * Note that we can do this either when a dead thread is added to
+ * the dead thread queue or when it is reused.  Here, we are doing
+ * this lazily, when the thread is reused in _PR_CreateThread().
+ */
+static void _PR_InitializeRecycledThread(PRThread *thread)
+{
+    /*
+     * Assert that the following data members are already zeroed
+     * by _PR_CleanupThread().
+     */
+#ifdef DEBUG
+    if (thread->privateData) {
+        unsigned int i;
+        for (i = 0; i < thread->tpdLength; i++) {
+            PR_ASSERT(thread->privateData[i] == NULL);
+        }
+    }
+#endif
+    PR_ASSERT(thread->dumpArg == 0 && thread->dump == 0);
+    PR_ASSERT(thread->errorString == 0 && thread->errorStringSize == 0);
+    PR_ASSERT(thread->errorStringLength == 0);
+
+    /* Reset data members in thread structure */
+    thread->errorCode = thread->osErrorCode = 0;
+    thread->io_pending = thread->io_suspended = PR_FALSE;
+    thread->environment = 0;
+    PR_INIT_CLIST(&thread->lockList);
+}
+
+PRStatus _PR_RecycleThread(PRThread *thread)
+{
+    if ( _PR_IS_NATIVE_THREAD(thread) &&
+            _PR_NUM_DEADNATIVE < _pr_recycleThreads) {
+        _PR_DEADQ_LOCK;
+        PR_APPEND_LINK(&thread->links, &_PR_DEADNATIVEQ);
+        _PR_INC_DEADNATIVE;
+        _PR_DEADQ_UNLOCK;
+    return (PR_SUCCESS);
+    } else if ( !_PR_IS_NATIVE_THREAD(thread) &&
+                _PR_NUM_DEADUSER < _pr_recycleThreads) {
+        _PR_DEADQ_LOCK;
+        PR_APPEND_LINK(&thread->links, &_PR_DEADUSERQ);
+        _PR_INC_DEADUSER;
+        _PR_DEADQ_UNLOCK;
+    return (PR_SUCCESS);
+    }
+    return (PR_FAILURE);
+}
+
+/*
+ * Decrement the active thread count, either _pr_systemActive or
+ * _pr_userActive, depending on whether the thread is a system thread
+ * or a user thread.  If all the user threads, except possibly
+ * the primordial thread, have terminated, we notify the primordial
+ * thread of this condition.
+ *
+ * Since this function will lock _pr_activeLock, do not call this
+ * function while holding the _pr_activeLock lock, as this will result
+ * in a deadlock.
+ */
+
+static void
+_PR_DecrActiveThreadCount(PRThread *thread)
+{
+    PR_Lock(_pr_activeLock);
+    if (thread->flags & _PR_SYSTEM) {
+        _pr_systemActive--;
+    } else {
+        _pr_userActive--;
+        if (_pr_userActive == _pr_primordialExitCount) {
+            PR_NotifyCondVar(_pr_primordialExitCVar);
+        }
+    }
+    PR_Unlock(_pr_activeLock);
+}
+
+/*
+** Detach thread structure
+*/
+static void
+_PR_DestroyThread(PRThread *thread)
+{
+    _PR_MD_FREE_LOCK(&thread->threadLock);
+    PR_DELETE(thread);
+}
+
+void
+_PR_NativeDestroyThread(PRThread *thread)
+{
+    if(thread->term) {
+        PR_DestroyCondVar(thread->term);
+        thread->term = 0;
+    }
+    if (NULL != thread->privateData) {
+        PR_ASSERT(0 != thread->tpdLength);
+        PR_DELETE(thread->privateData);
+        thread->tpdLength = 0;
+    }
+    PR_DELETE(thread->stack);
+    _PR_DestroyThread(thread);
+}
+
+void
+_PR_UserDestroyThread(PRThread *thread)
+{
+    if(thread->term) {
+        PR_DestroyCondVar(thread->term);
+        thread->term = 0;
+    }
+    if (NULL != thread->privateData) {
+        PR_ASSERT(0 != thread->tpdLength);
+        PR_DELETE(thread->privateData);
+        thread->tpdLength = 0;
+    }
+    _PR_MD_FREE_LOCK(&thread->threadLock);
+    if (thread->threadAllocatedOnStack == 1) {
+        _PR_MD_CLEAN_THREAD(thread);
+        /*
+         *  Because the no_sched field is set, this thread/stack will
+         *  will not be re-used until the flag is cleared by the thread
+         *  we will context switch to.
+         */
+        _PR_FreeStack(thread->stack);
+    } else {
+#ifdef WINNT
+        _PR_MD_CLEAN_THREAD(thread);
+#else
+        /*
+         * This assertion does not apply to NT.  On NT, every fiber
+         * has its threadAllocatedOnStack equal to 0.  Elsewhere,
+         * only the primordial thread has its threadAllocatedOnStack
+         * equal to 0.
+         */
+        PR_ASSERT(thread->flags & _PR_PRIMORDIAL);
+#endif
+    }
+}
+
+
+/*
+** Run a thread's start function. When the start function returns the
+** thread is done executing and no longer needs the CPU. If there are no
+** more user threads running then we can exit the program.
+*/
+void _PR_NativeRunThread(void *arg)
+{
+    PRThread *thread = (PRThread *)arg;
+
+    _PR_MD_SET_CURRENT_THREAD(thread);
+
+    _PR_MD_SET_CURRENT_CPU(NULL);
+
+    /* Set up the thread stack information */
+    _PR_InitializeNativeStack(thread->stack);
+
+    /* Set up the thread md information */
+    if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
+        /*
+         * thread failed to initialize itself, possibly due to
+         * failure to allocate per-thread resources
+         */
+        return;
+    }
+
+    while(1) {
+        thread->state = _PR_RUNNING;
+
+        /*
+         * Add to list of active threads
+         */
+        PR_Lock(_pr_activeLock);
+        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
+        _pr_global_threads++;
+        PR_Unlock(_pr_activeLock);
+
+        (*thread->startFunc)(thread->arg);
+
+        /*
+         * The following two assertions are meant for NT asynch io.
+         *
+         * The thread should have no asynch io in progress when it
+         * exits, otherwise the overlapped buffer, which is part of
+         * the thread structure, would become invalid.
+         */
+        PR_ASSERT(thread->io_pending == PR_FALSE);
+        /*
+         * This assertion enforces the programming guideline that
+         * if an io function times out or is interrupted, the thread
+         * should close the fd to force the asynch io to abort
+         * before it exits.  Right now, closing the fd is the only
+         * way to clear the io_suspended flag.
+         */
+        PR_ASSERT(thread->io_suspended == PR_FALSE);
+
+        /*
+         * remove thread from list of active threads
+         */
+        PR_Lock(_pr_activeLock);
+        PR_REMOVE_LINK(&thread->active);
+        _pr_global_threads--;
+        PR_Unlock(_pr_activeLock);
+
+        PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));
+
+        /* All done, time to go away */
+        _PR_CleanupThread(thread);
+
+        _PR_NotifyJoinWaiters(thread);
+
+        _PR_DecrActiveThreadCount(thread);
+
+        thread->state = _PR_DEAD_STATE;
+
+        if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
+                        PR_FAILURE)) {
+            /*
+             * thread not recycled
+             * platform-specific thread exit processing
+             *        - for stuff like releasing native-thread resources, etc.
+             */
+            _PR_MD_EXIT_THREAD(thread);
+            /*
+             * Free memory allocated for the thread
+             */
+            _PR_NativeDestroyThread(thread);
+            /*
+             * thread gone, cannot de-reference thread now
+             */
+            return;
+        }
+
+        /* Now wait for someone to activate us again... */
+        _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
+    }
+}
+
+static void _PR_UserRunThread(void)
+{
+    PRThread *thread = _PR_MD_CURRENT_THREAD();
+    PRIntn is;
+
+    if (_MD_LAST_THREAD())
+    _MD_LAST_THREAD()->no_sched = 0;
+
+#ifdef HAVE_CUSTOM_USER_THREADS
+    if (thread->stack == NULL) {
+        thread->stack = PR_NEWZAP(PRThreadStack);
+        _PR_InitializeNativeStack(thread->stack);
+    }
+#endif /* HAVE_CUSTOM_USER_THREADS */
+
+    while(1) {
+        /* Run thread main */
+        if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_MD_SET_INTSOFF(0);
+
+    /*
+     * Add to list of active threads
+     */
+    if (!(thread->flags & _PR_IDLE_THREAD)) {
+        PR_Lock(_pr_activeLock);
+        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
+        _pr_local_threads++;
+        PR_Unlock(_pr_activeLock);
+    }
+
+        (*thread->startFunc)(thread->arg);
+
+        /*
+         * The following two assertions are meant for NT asynch io.
+         *
+         * The thread should have no asynch io in progress when it
+         * exits, otherwise the overlapped buffer, which is part of
+         * the thread structure, would become invalid.
+         */
+        PR_ASSERT(thread->io_pending == PR_FALSE);
+        /*
+         * This assertion enforces the programming guideline that
+         * if an io function times out or is interrupted, the thread
+         * should close the fd to force the asynch io to abort
+         * before it exits.  Right now, closing the fd is the only
+         * way to clear the io_suspended flag.
+         */
+        PR_ASSERT(thread->io_suspended == PR_FALSE);
+
+        PR_Lock(_pr_activeLock);
+    /*
+     * remove thread from list of active threads
+     */
+    if (!(thread->flags & _PR_IDLE_THREAD)) {
+           PR_REMOVE_LINK(&thread->active);
+        _pr_local_threads--;
+    }
+    PR_Unlock(_pr_activeLock);
+        PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));
+
+        /* All done, time to go away */
+        _PR_CleanupThread(thread);
+
+        _PR_INTSOFF(is);    
+
+        _PR_NotifyJoinWaiters(thread);
+
+    _PR_DecrActiveThreadCount(thread);
+
+        thread->state = _PR_DEAD_STATE;
+
+        if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
+                        PR_FAILURE)) {
+            /*
+            ** Destroy the thread resources
+            */
+        _PR_UserDestroyThread(thread);
+        }
+
+        /*
+        ** Find another user thread to run. This cpu has finished the
+        ** previous threads main and is now ready to run another thread.
+        */
+        {
+            PRInt32 is;
+            _PR_INTSOFF(is);
+            _PR_MD_SWITCH_CONTEXT(thread);
+        }
+
+        /* Will land here when we get scheduled again if we are recycling... */
+    }
+}
+
+void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRIntn is;
+
+    if ( _PR_IS_NATIVE_THREAD(thread) ) {
+        _PR_MD_SET_PRIORITY(&(thread->md), newPri);
+        return;
+    }
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+    _PR_INTSOFF(is);
+    _PR_THREAD_LOCK(thread);
+    if (newPri != thread->priority) {
+    _PRCPU *cpu = thread->cpu;
+
+    switch (thread->state) {
+      case _PR_RUNNING:
+        /* Change my priority */
+
+            _PR_RUNQ_LOCK(cpu);
+        thread->priority = newPri;
+        if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) {
+            if (!_PR_IS_NATIVE_THREAD(me))
+                    _PR_SET_RESCHED_FLAG();
+        }
+            _PR_RUNQ_UNLOCK(cpu);
+        break;
+
+      case _PR_RUNNABLE:
+
+        _PR_RUNQ_LOCK(cpu);
+            /* Move to different runQ */
+            _PR_DEL_RUNQ(thread);
+            thread->priority = newPri;
+            PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+            _PR_ADD_RUNQ(thread, cpu, newPri);
+        _PR_RUNQ_UNLOCK(cpu);
+
+            if (newPri > me->priority) {
+            if (!_PR_IS_NATIVE_THREAD(me))
+                    _PR_SET_RESCHED_FLAG();
+            }
+
+        break;
+
+      case _PR_LOCK_WAIT:
+      case _PR_COND_WAIT:
+      case _PR_IO_WAIT:
+      case _PR_SUSPENDED:
+
+        thread->priority = newPri;
+        break;
+    }
+    }
+    _PR_THREAD_UNLOCK(thread);
+    if (!_PR_IS_NATIVE_THREAD(me))
+    _PR_INTSON(is);
+}
+
+/*
+** Suspend the named thread and copy its gc registers into regBuf
+*/
+static void _PR_Suspend(PRThread *thread)
+{
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    PR_ASSERT(thread != me);
+    PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu));
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+        _PR_INTSOFF(is);
+    _PR_THREAD_LOCK(thread);
+    switch (thread->state) {
+      case _PR_RUNNABLE:
+        if (!_PR_IS_NATIVE_THREAD(thread)) {
+            _PR_RUNQ_LOCK(thread->cpu);
+            _PR_DEL_RUNQ(thread);
+            _PR_RUNQ_UNLOCK(thread->cpu);
+
+            _PR_MISCQ_LOCK(thread->cpu);
+            _PR_ADD_SUSPENDQ(thread, thread->cpu);
+            _PR_MISCQ_UNLOCK(thread->cpu);
+        } else {
+            /*
+             * Only LOCAL threads are suspended by _PR_Suspend
+             */
+             PR_ASSERT(0);
+        }
+        thread->state = _PR_SUSPENDED;
+        break;
+
+      case _PR_RUNNING:
+        /*
+         * The thread being suspended should be a LOCAL thread with
+         * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
+         */
+        PR_ASSERT(0);
+        break;
+
+      case _PR_LOCK_WAIT:
+      case _PR_IO_WAIT:
+      case _PR_COND_WAIT:
+        if (_PR_IS_NATIVE_THREAD(thread)) {
+            _PR_MD_SUSPEND_THREAD(thread);
+    }
+        thread->flags |= _PR_SUSPENDING;
+        break;
+
+      default:
+        PR_Abort();
+    }
+    _PR_THREAD_UNLOCK(thread);
+    if (!_PR_IS_NATIVE_THREAD(me))
+    _PR_INTSON(is);
+}
+
+static void _PR_Resume(PRThread *thread)
+{
+    PRThreadPriority pri;
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+    _PR_INTSOFF(is);
+    _PR_THREAD_LOCK(thread);
+    switch (thread->state) {
+      case _PR_SUSPENDED:
+        thread->state = _PR_RUNNABLE;
+        thread->flags &= ~_PR_SUSPENDING;
+        if (!_PR_IS_NATIVE_THREAD(thread)) {
+            _PR_MISCQ_LOCK(thread->cpu);
+            _PR_DEL_SUSPENDQ(thread);
+            _PR_MISCQ_UNLOCK(thread->cpu);
+
+            pri = thread->priority;
+
+            _PR_RUNQ_LOCK(thread->cpu);
+            _PR_ADD_RUNQ(thread, thread->cpu, pri);
+            _PR_RUNQ_UNLOCK(thread->cpu);
+
+            if (pri > _PR_MD_CURRENT_THREAD()->priority) {
+                if (!_PR_IS_NATIVE_THREAD(me))
+                    _PR_SET_RESCHED_FLAG();
+            }
+        } else {
+            PR_ASSERT(0);
+        }
+        break;
+
+      case _PR_IO_WAIT:
+      case _PR_COND_WAIT:
+        thread->flags &= ~_PR_SUSPENDING;
+/*      PR_ASSERT(thread->wait.monitor->stickyCount == 0); */
+        break;
+
+      case _PR_LOCK_WAIT: 
+      {
+        PRLock *wLock = thread->wait.lock;
+
+        thread->flags &= ~_PR_SUSPENDING;
+ 
+        _PR_LOCK_LOCK(wLock);
+        if (thread->wait.lock->owner == 0) {
+            _PR_UnblockLockWaiter(thread->wait.lock);
+        }
+        _PR_LOCK_UNLOCK(wLock);
+        break;
+      }
+      case _PR_RUNNABLE:
+        break;
+      case _PR_RUNNING:
+        /*
+         * The thread being suspended should be a LOCAL thread with
+         * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
+         */
+        PR_ASSERT(0);
+        break;
+
+      default:
+    /*
+     * thread should have been in one of the above-listed blocked states
+     * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE)
+     */
+        PR_Abort();
+    }
+    _PR_THREAD_UNLOCK(thread);
+    if (!_PR_IS_NATIVE_THREAD(me))
+        _PR_INTSON(is);
+
+}
+
+#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
+static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus)
+{
+    PRThread *thread;
+    PRIntn pri;
+    PRUint32 r;
+    PRCList *qp;
+    PRIntn priMin, priMax;
+
+    _PR_RUNQ_LOCK(cpu);
+    r = _PR_RUNQREADYMASK(cpu);
+    if (r==0) {
+        priMin = priMax = PR_PRIORITY_FIRST;
+    } else if (r == (1<<PR_PRIORITY_NORMAL) ) {
+        priMin = priMax = PR_PRIORITY_NORMAL;
+    } else {
+        priMin = PR_PRIORITY_FIRST;
+        priMax = PR_PRIORITY_LAST;
+    }
+    thread = NULL;
+    for (pri = priMax; pri >= priMin ; pri-- ) {
+    if (r & (1 << pri)) {
+            for (qp = _PR_RUNQ(cpu)[pri].next; 
+                 qp != &_PR_RUNQ(cpu)[pri];
+                 qp = qp->next) {
+                thread = _PR_THREAD_PTR(qp);
+                /*
+                * skip non-schedulable threads
+                */
+                PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+                if (thread->no_sched) {
+                    thread = NULL;
+                    /*
+                     * Need to wakeup cpus to avoid missing a
+                     * runnable thread
+                     * Waking up all CPU's need happen only once.
+                     */
+
+                    *wakeup_cpus = PR_TRUE;
+                    continue;
+                } else if (thread->flags & _PR_BOUND_THREAD) {
+                    /*
+                     * Thread bound to cpu 0
+                     */
+
+                    thread = NULL;
+#ifdef IRIX
+					_PR_MD_WAKEUP_PRIMORDIAL_CPU();
+#endif
+                    continue;
+                } else if (thread->io_pending == PR_TRUE) {
+                    /*
+                     * A thread that is blocked for I/O needs to run
+                     * on the same cpu on which it was blocked. This is because
+                     * the cpu's ioq is accessed without lock protection and scheduling
+                     * the thread on a different cpu would preclude this optimization.
+                     */
+                    thread = NULL;
+                    continue;
+                } else {
+                    /* Pull thread off of its run queue */
+                    _PR_DEL_RUNQ(thread);
+                    _PR_RUNQ_UNLOCK(cpu);
+                    return(thread);
+                }
+            }
+        }
+        thread = NULL;
+    }
+    _PR_RUNQ_UNLOCK(cpu);
+    return(thread);
+}
+#endif /* !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) */
+
+/*
+** Schedule this native thread by finding the highest priority nspr
+** thread that is ready to run.
+**
+** Note- everyone really needs to call _PR_MD_SWITCH_CONTEXT (which calls
+**       PR_Schedule() rather than calling PR_Schedule.  Otherwise if there
+**       is initialization required for switching from SWITCH_CONTEXT,
+**       it will not get done!
+*/
+void _PR_Schedule(void)
+{
+    PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
+    _PRCPU *cpu = _PR_MD_CURRENT_CPU();
+    PRIntn pri;
+    PRUint32 r;
+    PRCList *qp;
+    PRIntn priMin, priMax;
+#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
+    PRBool wakeup_cpus;
+#endif
+
+    /* Interrupts must be disabled */
+    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
+
+    /* Since we are rescheduling, we no longer want to */
+    _PR_CLEAR_RESCHED_FLAG();
+
+    /*
+    ** Find highest priority thread to run. Bigger priority numbers are
+    ** higher priority threads
+    */
+    _PR_RUNQ_LOCK(cpu);
+    /*
+     *  if we are in SuspendAll mode, can schedule only the thread
+     *    that called PR_SuspendAll
+     *
+     *  The thread may be ready to run now, after completing an I/O
+     *  operation, for example
+     */
+    if ((thread = suspendAllThread) != 0) {
+    if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) {
+            /* Pull thread off of its run queue */
+            _PR_DEL_RUNQ(thread);
+            _PR_RUNQ_UNLOCK(cpu);
+            goto found_thread;
+    } else {
+            thread = NULL;
+            _PR_RUNQ_UNLOCK(cpu);
+            goto idle_thread;
+    }
+    }
+    r = _PR_RUNQREADYMASK(cpu);
+    if (r==0) {
+        priMin = priMax = PR_PRIORITY_FIRST;
+    } else if (r == (1<<PR_PRIORITY_NORMAL) ) {
+        priMin = priMax = PR_PRIORITY_NORMAL;
+    } else {
+        priMin = PR_PRIORITY_FIRST;
+        priMax = PR_PRIORITY_LAST;
+    }
+    thread = NULL;
+    for (pri = priMax; pri >= priMin ; pri-- ) {
+    if (r & (1 << pri)) {
+            for (qp = _PR_RUNQ(cpu)[pri].next; 
+                 qp != &_PR_RUNQ(cpu)[pri];
+                 qp = qp->next) {
+                thread = _PR_THREAD_PTR(qp);
+                /*
+                * skip non-schedulable threads
+                */
+                PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
+                if ((thread->no_sched) && (me != thread)){
+                    thread = NULL;
+                    continue;
+                } else {
+                    /* Pull thread off of its run queue */
+                    _PR_DEL_RUNQ(thread);
+                    _PR_RUNQ_UNLOCK(cpu);
+                    goto found_thread;
+                }
+            }
+        }
+        thread = NULL;
+    }
+    _PR_RUNQ_UNLOCK(cpu);
+
+#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
+
+    wakeup_cpus = PR_FALSE;
+    _PR_CPU_LIST_LOCK();
+    for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
+        if (cpu != _PR_CPU_PTR(qp)) {
+            if ((thread = get_thread(_PR_CPU_PTR(qp), &wakeup_cpus))
+                                        != NULL) {
+                thread->cpu = cpu;
+                _PR_CPU_LIST_UNLOCK();
+                if (wakeup_cpus == PR_TRUE)
+                    _PR_MD_WAKEUP_CPUS();
+                goto found_thread;
+            }
+        }
+    }
+    _PR_CPU_LIST_UNLOCK();
+    if (wakeup_cpus == PR_TRUE)
+        _PR_MD_WAKEUP_CPUS();
+
+#endif        /* _PR_LOCAL_THREADS_ONLY */
+
+idle_thread:
+   /*
+    ** There are no threads to run. Switch to the idle thread
+    */
+    PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("pausing"));
+    thread = _PR_MD_CURRENT_CPU()->idle_thread;
+
+found_thread:
+    PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) &&
+                    (!(thread->no_sched))));
+
+    /* Resume the thread */
+    PR_LOG(_pr_sched_lm, PR_LOG_MAX,
+       ("switching to %d[%p]", thread->id, thread));
+    PR_ASSERT(thread->state != _PR_RUNNING);
+    thread->state = _PR_RUNNING;
+ 
+    /* If we are on the runq, it just means that we went to sleep on some
+     * resource, and by the time we got here another real native thread had
+     * already given us the resource and put us back on the runqueue 
+     */
+	PR_ASSERT(thread->cpu == _PR_MD_CURRENT_CPU());
+    if (thread != me) 
+        _PR_MD_RESTORE_CONTEXT(thread);
+#if 0
+    /* XXXMB; with setjmp/longjmp it is impossible to land here, but 
+     * it is not with fibers... Is this a bad thing?  I believe it is 
+     * still safe.
+     */
+    PR_NOT_REACHED("impossible return from schedule");
+#endif
+}
+
+/*
+** Attaches a thread.  
+** Does not set the _PR_MD_CURRENT_THREAD.  
+** Does not specify the scope of the thread.
+*/
+static PRThread *
+_PR_AttachThread(PRThreadType type, PRThreadPriority priority,
+    PRThreadStack *stack)
+{
+    PRThread *thread;
+    char *mem;
+
+    if (priority > PR_PRIORITY_LAST) {
+        priority = PR_PRIORITY_LAST;
+    } else if (priority < PR_PRIORITY_FIRST) {
+        priority = PR_PRIORITY_FIRST;
+    }
+
+    mem = (char*) PR_CALLOC(sizeof(PRThread));
+    if (mem) {
+        thread = (PRThread*) mem;
+        thread->priority = priority;
+        thread->stack = stack;
+        thread->state = _PR_RUNNING;
+        PR_INIT_CLIST(&thread->lockList);
+        if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
+        PR_DELETE(thread);
+        return 0;
+    }
+
+        return thread;
+    }
+    return 0;
+}
+
+
+
+PR_IMPLEMENT(PRThread*) 
+_PR_NativeCreateThread(PRThreadType type,
+                     void (*start)(void *arg),
+                     void *arg,
+                     PRThreadPriority priority,
+                     PRThreadScope scope,
+                     PRThreadState state,
+                     PRUint32 stackSize,
+                     PRUint32 flags)
+{
+    PRThread *thread;
+
+    thread = _PR_AttachThread(type, priority, NULL);
+
+    if (thread) {
+        PR_Lock(_pr_activeLock);
+        thread->flags = (flags | _PR_GLOBAL_SCOPE);
+        thread->id = ++_pr_utid;
+        if (type == PR_SYSTEM_THREAD) {
+            thread->flags |= _PR_SYSTEM;
+            _pr_systemActive++;
+        } else {
+            _pr_userActive++;
+        }
+        PR_Unlock(_pr_activeLock);
+
+        thread->stack = PR_NEWZAP(PRThreadStack);
+        if (!thread->stack) {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            goto done;
+        }
+        thread->stack->stackSize = stackSize?stackSize:_MD_DEFAULT_STACK_SIZE;
+        thread->stack->thr = thread;
+        thread->startFunc = start;
+        thread->arg = arg;
+
+        /* 
+          Set thread flags related to scope and joinable state. If joinable
+          thread, allocate a "termination" conidition variable.
+         */
+        if (state == PR_JOINABLE_THREAD) {
+            thread->term = PR_NewCondVar(_pr_terminationCVLock);
+        if (thread->term == NULL) {
+        PR_DELETE(thread->stack);
+        goto done;
+        }
+        }
+
+    thread->state = _PR_RUNNING;
+        if (_PR_MD_CREATE_THREAD(thread, _PR_NativeRunThread, priority,
+            scope,state,stackSize) == PR_SUCCESS) {
+            return thread;
+        }
+        if (thread->term) {
+            PR_DestroyCondVar(thread->term);
+            thread->term = NULL;
+        }
+    PR_DELETE(thread->stack);
+    }
+
+done:
+    if (thread) {
+    _PR_DecrActiveThreadCount(thread);
+        _PR_DestroyThread(thread);
+    }
+    return NULL;
+}
+
+/************************************************************************/
+
+PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type,
+                     void (*start)(void *arg),
+                     void *arg,
+                     PRThreadPriority priority,
+                     PRThreadScope scope,
+                     PRThreadState state,
+                     PRUint32 stackSize,
+                     PRUint32 flags)
+{
+    PRThread *me;
+    PRThread *thread = NULL;
+    PRThreadStack *stack;
+    char *top;
+    PRIntn is;
+    PRIntn native = 0;
+    PRIntn useRecycled = 0;
+    PRBool status;
+
+    /* 
+    First, pin down the priority.  Not all compilers catch passing out of
+    range enum here.  If we let bad values thru, priority queues won't work.
+    */
+    if (priority > PR_PRIORITY_LAST) {
+        priority = PR_PRIORITY_LAST;
+    } else if (priority < PR_PRIORITY_FIRST) {
+        priority = PR_PRIORITY_FIRST;
+    }
+        
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (! (flags & _PR_IDLE_THREAD))
+        me = _PR_MD_CURRENT_THREAD();
+
+#if    defined(_PR_GLOBAL_THREADS_ONLY)
+	/*
+	 * can create global threads only
+	 */
+    if (scope == PR_LOCAL_THREAD)
+    	scope = PR_GLOBAL_THREAD;
+#endif
+
+	if (_native_threads_only)
+		scope = PR_GLOBAL_THREAD;
+
+    native = (((scope == PR_GLOBAL_THREAD)|| (scope == PR_GLOBAL_BOUND_THREAD))
+							&& _PR_IS_NATIVE_THREAD_SUPPORTED());
+
+    _PR_ADJUST_STACKSIZE(stackSize);
+
+    if (native) {
+    /*
+     * clear the IDLE_THREAD flag which applies to LOCAL
+     * threads only
+     */
+    flags &= ~_PR_IDLE_THREAD;
+        flags |= _PR_GLOBAL_SCOPE;
+        if (_PR_NUM_DEADNATIVE > 0) {
+            _PR_DEADQ_LOCK;
+
+            if (_PR_NUM_DEADNATIVE == 0) { /* Thread safe check */
+                _PR_DEADQ_UNLOCK;
+            } else {
+                thread = _PR_THREAD_PTR(_PR_DEADNATIVEQ.next);
+                PR_REMOVE_LINK(&thread->links);
+                _PR_DEC_DEADNATIVE;
+                _PR_DEADQ_UNLOCK;
+
+                _PR_InitializeRecycledThread(thread);
+                thread->startFunc = start;
+                thread->arg = arg;
+            thread->flags = (flags | _PR_GLOBAL_SCOPE);
+            if (type == PR_SYSTEM_THREAD)
+            {
+                thread->flags |= _PR_SYSTEM;
+                PR_AtomicIncrement(&_pr_systemActive);
+            }
+            else PR_AtomicIncrement(&_pr_userActive);
+
+            if (state == PR_JOINABLE_THREAD) {
+                if (!thread->term) 
+                       thread->term = PR_NewCondVar(_pr_terminationCVLock);
+            }
+        else {
+                if(thread->term) {
+                    PR_DestroyCondVar(thread->term);
+                        thread->term = 0;
+            }
+            }
+
+                thread->priority = priority;
+        _PR_MD_SET_PRIORITY(&(thread->md), priority);
+        /* XXX what about stackSize? */
+        thread->state = _PR_RUNNING;
+                _PR_MD_WAKEUP_WAITER(thread);
+        return thread;
+            }
+        }
+        thread = _PR_NativeCreateThread(type, start, arg, priority, 
+                                            scope, state, stackSize, flags);
+    } else {
+        if (_PR_NUM_DEADUSER > 0) {
+            _PR_DEADQ_LOCK;
+
+            if (_PR_NUM_DEADUSER == 0) {  /* thread safe check */
+                _PR_DEADQ_UNLOCK;
+            } else {
+                PRCList *ptr;
+
+                /* Go down list checking for a recycled thread with a 
+                 * large enough stack.  XXXMB - this has a bad degenerate case.
+                 */
+                ptr = _PR_DEADUSERQ.next;
+                while( ptr != &_PR_DEADUSERQ ) {
+                    thread = _PR_THREAD_PTR(ptr);
+                    if ((thread->stack->stackSize >= stackSize) &&
+                (!thread->no_sched)) {
+                        PR_REMOVE_LINK(&thread->links);
+                        _PR_DEC_DEADUSER;
+                        break;
+                    } else {
+                        ptr = ptr->next;
+                        thread = NULL;
+                    }
+                } 
+
+                _PR_DEADQ_UNLOCK;
+
+               if (thread) {
+                    _PR_InitializeRecycledThread(thread);
+                    thread->startFunc = start;
+                    thread->arg = arg;
+                    thread->priority = priority;
+            if (state == PR_JOINABLE_THREAD) {
+            if (!thread->term) 
+               thread->term = PR_NewCondVar(_pr_terminationCVLock);
+            } else {
+            if(thread->term) {
+               PR_DestroyCondVar(thread->term);
+                thread->term = 0;
+            }
+            }
+                    useRecycled++;
+                }
+            }
+        } 
+        if (thread == NULL) {
+#ifndef HAVE_CUSTOM_USER_THREADS
+            stack = _PR_NewStack(stackSize);
+            if (!stack) {
+                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+                return NULL;
+            }
+
+            /* Allocate thread object and per-thread data off the top of the stack*/
+            top = stack->stackTop;
+#ifdef HAVE_STACK_GROWING_UP
+            thread = (PRThread*) top;
+            top = top + sizeof(PRThread);
+            /*
+             * Make stack 64-byte aligned
+             */
+            if ((PRUptrdiff)top & 0x3f) {
+                top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f);
+            }
+#else
+            top = top - sizeof(PRThread);
+            thread = (PRThread*) top;
+            /*
+             * Make stack 64-byte aligned
+             */
+            if ((PRUptrdiff)top & 0x3f) {
+                top = (char*)((PRUptrdiff)top & ~0x3f);
+            }
+#endif
+#if defined(GC_LEAK_DETECTOR)
+            /*
+             * sorry, it is not safe to allocate the thread on the stack,
+             * because we assign to this object before the GC can learn
+             * about this thread. we'll just leak thread objects instead.
+             */
+            thread = PR_NEW(PRThread);
+#endif
+            stack->thr = thread;
+            memset(thread, 0, sizeof(PRThread));
+            thread->threadAllocatedOnStack = 1;
+#else
+            thread = _PR_MD_CREATE_USER_THREAD(stackSize, start, arg);
+            if (!thread) {
+                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+                return NULL;
+            }
+            thread->threadAllocatedOnStack = 0;
+            stack = NULL;
+            top = NULL;
+#endif
+
+            /* Initialize thread */
+            thread->tpdLength = 0;
+            thread->privateData = NULL;
+            thread->stack = stack;
+            thread->priority = priority;
+            thread->startFunc = start;
+            thread->arg = arg;
+            PR_INIT_CLIST(&thread->lockList);
+
+            if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
+                if (thread->threadAllocatedOnStack == 1)
+                    _PR_FreeStack(thread->stack);
+                else {
+                    PR_DELETE(thread);
+                }
+                PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+                return NULL;
+            }
+
+            if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
+                if (thread->threadAllocatedOnStack == 1)
+                    _PR_FreeStack(thread->stack);
+                else {
+                    PR_DELETE(thread->privateData);
+                    PR_DELETE(thread);
+                }
+                PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+                return NULL;
+            }
+
+            _PR_MD_INIT_CONTEXT(thread, top, _PR_UserRunThread, &status);
+
+            if (status == PR_FALSE) {
+                _PR_MD_FREE_LOCK(&thread->threadLock);
+                if (thread->threadAllocatedOnStack == 1)
+                    _PR_FreeStack(thread->stack);
+                else {
+                    PR_DELETE(thread->privateData);
+                    PR_DELETE(thread);
+                }
+                return NULL;
+            }
+
+            /* 
+              Set thread flags related to scope and joinable state. If joinable
+              thread, allocate a "termination" condition variable.
+            */
+            if (state == PR_JOINABLE_THREAD) {
+                thread->term = PR_NewCondVar(_pr_terminationCVLock);
+                if (thread->term == NULL) {
+                    _PR_MD_FREE_LOCK(&thread->threadLock);
+                    if (thread->threadAllocatedOnStack == 1)
+                        _PR_FreeStack(thread->stack);
+                    else {
+                        PR_DELETE(thread->privateData);
+                        PR_DELETE(thread);
+                    }
+                    return NULL;
+                }
+            }
+  
+        }
+  
+        /* Update thread type counter */
+        PR_Lock(_pr_activeLock);
+        thread->flags = flags;
+        thread->id = ++_pr_utid;
+        if (type == PR_SYSTEM_THREAD) {
+            thread->flags |= _PR_SYSTEM;
+            _pr_systemActive++;
+        } else {
+            _pr_userActive++;
+        }
+
+        /* Make thread runnable */
+        thread->state = _PR_RUNNABLE;
+    /*
+     * Add to list of active threads
+     */
+        PR_Unlock(_pr_activeLock);
+
+        if ((! (thread->flags & _PR_IDLE_THREAD)) && _PR_IS_NATIVE_THREAD(me) )
+            thread->cpu = _PR_GetPrimordialCPU();
+        else
+            thread->cpu = _PR_MD_CURRENT_CPU();
+
+        PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
+
+        if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me)) {
+            _PR_INTSOFF(is);
+            _PR_RUNQ_LOCK(thread->cpu);
+            _PR_ADD_RUNQ(thread, thread->cpu, priority);
+            _PR_RUNQ_UNLOCK(thread->cpu);
+        }
+
+        if (thread->flags & _PR_IDLE_THREAD) {
+            /*
+            ** If the creating thread is a kernel thread, we need to
+            ** awaken the user thread idle thread somehow; potentially
+            ** it could be sleeping in its idle loop, and we need to poke
+            ** it.  To do so, wake the idle thread...  
+            */
+            _PR_MD_WAKEUP_WAITER(NULL);
+        } else if (_PR_IS_NATIVE_THREAD(me)) {
+            _PR_MD_WAKEUP_WAITER(thread);
+        }
+        if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) )
+            _PR_INTSON(is);
+    }
+
+    return thread;
+}
+
+PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type,
+                     void (*start)(void *arg),
+                     void *arg,
+                     PRThreadPriority priority,
+                     PRThreadScope scope,
+                     PRThreadState state,
+                     PRUint32 stackSize)
+{
+    return _PR_CreateThread(type, start, arg, priority, scope, state, 
+                            stackSize, 0);
+}
+
+/*
+** Associate a thread object with an existing native thread.
+**     "type" is the type of thread object to attach
+**     "priority" is the priority to assign to the thread
+**     "stack" defines the shape of the threads stack
+**
+** This can return NULL if some kind of error occurs, or if memory is
+** tight.
+**
+** This call is not normally needed unless you create your own native
+** thread. PR_Init does this automatically for the primordial thread.
+*/
+PRThread* _PRI_AttachThread(PRThreadType type,
+    PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags)
+{
+    PRThread *thread;
+
+    if ((thread = _PR_MD_GET_ATTACHED_THREAD()) != NULL) {
+        return thread;
+    }
+    _PR_MD_SET_CURRENT_THREAD(NULL);
+
+    /* Clear out any state if this thread was attached before */
+    _PR_MD_SET_CURRENT_CPU(NULL);
+
+    thread = _PR_AttachThread(type, priority, stack);
+    if (thread) {
+        PRIntn is;
+
+        _PR_MD_SET_CURRENT_THREAD(thread);
+
+        thread->flags = flags | _PR_GLOBAL_SCOPE | _PR_ATTACHED;
+
+        if (!stack) {
+            thread->stack = PR_NEWZAP(PRThreadStack);
+            if (!thread->stack) {
+                _PR_DestroyThread(thread);
+                return NULL;
+            }
+            thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE;
+        }
+        PR_INIT_CLIST(&thread->links);
+
+        if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) {
+                PR_DELETE(thread->stack);
+                _PR_DestroyThread(thread);
+                return NULL;
+        }
+
+        _PR_MD_SET_CURRENT_CPU(NULL);
+
+        if (_PR_MD_CURRENT_CPU()) {
+            _PR_INTSOFF(is);
+            PR_Lock(_pr_activeLock);
+        }
+        if (type == PR_SYSTEM_THREAD) {
+            thread->flags |= _PR_SYSTEM;
+            _pr_systemActive++;
+        } else {
+            _pr_userActive++;
+        }
+        if (_PR_MD_CURRENT_CPU()) {
+            PR_Unlock(_pr_activeLock);
+            _PR_INTSON(is);
+        }
+    }
+    return thread;
+}
+
+PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type,
+    PRThreadPriority priority, PRThreadStack *stack)
+{
+    return PR_GetCurrentThread();
+}
+
+PR_IMPLEMENT(void) PR_DetachThread(void)
+{
+    /*
+     * On IRIX, Solaris, and Windows, foreign threads are detached when
+     * they terminate.
+     */
+#if !defined(IRIX) && !defined(WIN32) \
+        && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY))
+    PRThread *me;
+    if (_pr_initialized) {
+        me = _PR_MD_GET_ATTACHED_THREAD();
+        if ((me != NULL) && (me->flags & _PR_ATTACHED))
+            _PRI_DetachThread();
+    }
+#endif
+}
+
+void _PRI_DetachThread(void)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (me->flags & _PR_PRIMORDIAL) {
+		/*
+		 * ignore, if primordial thread
+		 */
+		return;
+	}
+    PR_ASSERT(me->flags & _PR_ATTACHED);
+    PR_ASSERT(_PR_IS_NATIVE_THREAD(me));
+    _PR_CleanupThread(me);
+    PR_DELETE(me->privateData);
+
+    _PR_DecrActiveThreadCount(me);
+
+    _PR_MD_CLEAN_THREAD(me);
+    _PR_MD_SET_CURRENT_THREAD(NULL);
+    if (!me->threadAllocatedOnStack) 
+        PR_DELETE(me->stack);
+    _PR_MD_FREE_LOCK(&me->threadLock);
+    PR_DELETE(me);
+}
+
+/*
+** Wait for thread termination:
+**     "thread" is the target thread 
+**
+** This can return PR_FAILURE if no joinable thread could be found 
+** corresponding to the specified target thread.
+**
+** The calling thread is suspended until the target thread completes.
+** Several threads cannot wait for the same thread to complete; one thread
+** will complete successfully and others will terminate with an error PR_FAILURE.
+** The calling thread will not be blocked if the target thread has already
+** terminated.
+*/
+PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread)
+{
+    PRIntn is;
+    PRCondVar *term;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (!_PR_IS_NATIVE_THREAD(me))
+        _PR_INTSOFF(is);
+    term = thread->term;
+    /* can't join a non-joinable thread */
+    if (term == NULL) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        goto ErrorExit;
+    }
+
+    /* multiple threads can't wait on the same joinable thread */
+    if (term->condQ.next != &term->condQ) {
+        goto ErrorExit;
+    }
+    if (!_PR_IS_NATIVE_THREAD(me))
+        _PR_INTSON(is);
+
+    /* wait for the target thread's termination cv invariant */
+    PR_Lock (_pr_terminationCVLock);
+    while (thread->state != _PR_JOIN_WAIT) {
+        (void) PR_WaitCondVar(term, PR_INTERVAL_NO_TIMEOUT);
+    }
+    (void) PR_Unlock (_pr_terminationCVLock);
+    
+    /* 
+     Remove target thread from global waiting to join Q; make it runnable
+     again and put it back on its run Q.  When it gets scheduled later in
+     _PR_RunThread code, it will clean up its stack.
+    */    
+    if (!_PR_IS_NATIVE_THREAD(me))
+        _PR_INTSOFF(is);
+    thread->state = _PR_RUNNABLE;
+    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
+        _PR_THREAD_LOCK(thread);
+
+        _PR_MISCQ_LOCK(thread->cpu);
+        _PR_DEL_JOINQ(thread);
+        _PR_MISCQ_UNLOCK(thread->cpu);
+
+        _PR_AddThreadToRunQ(me, thread);
+        _PR_THREAD_UNLOCK(thread);
+    }
+    if (!_PR_IS_NATIVE_THREAD(me))
+        _PR_INTSON(is);
+
+    _PR_MD_WAKEUP_WAITER(thread);
+
+    return PR_SUCCESS;
+
+ErrorExit:
+    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
+    return PR_FAILURE;   
+}
+
+PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread,
+    PRThreadPriority newPri)
+{
+
+    /* 
+    First, pin down the priority.  Not all compilers catch passing out of
+    range enum here.  If we let bad values thru, priority queues won't work.
+    */
+    if ((PRIntn)newPri > (PRIntn)PR_PRIORITY_LAST) {
+        newPri = PR_PRIORITY_LAST;
+    } else if ((PRIntn)newPri < (PRIntn)PR_PRIORITY_FIRST) {
+        newPri = PR_PRIORITY_FIRST;
+    }
+        
+    if ( _PR_IS_NATIVE_THREAD(thread) ) {
+        thread->priority = newPri;
+        _PR_MD_SET_PRIORITY(&(thread->md), newPri);
+    } else _PR_SetThreadPriority(thread, newPri);
+}
+
+
+/*
+** This routine prevents all other threads from running. This call is needed by 
+** the garbage collector.
+*/
+PR_IMPLEMENT(void) PR_SuspendAll(void)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRCList *qp;
+
+    /*
+     * Stop all user and native threads which are marked GC able.
+     */
+    PR_Lock(_pr_activeLock);
+    suspendAllOn = PR_TRUE;
+    suspendAllThread = _PR_MD_CURRENT_THREAD();
+    _PR_MD_BEGIN_SUSPEND_ALL();
+    for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
+        qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
+        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && 
+            _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) {
+            _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp));
+                PR_ASSERT((_PR_ACTIVE_THREAD_PTR(qp))->state != _PR_RUNNING);
+            }
+    }
+    for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
+        qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
+        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
+            _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
+            /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */
+                _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); 
+    }
+    _PR_MD_END_SUSPEND_ALL();
+}
+
+/*
+** This routine unblocks all other threads that were suspended from running by 
+** PR_SuspendAll(). This call is needed by the garbage collector.
+*/
+PR_IMPLEMENT(void) PR_ResumeAll(void)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRCList *qp;
+
+    /*
+     * Resume all user and native threads which are marked GC able.
+     */
+    _PR_MD_BEGIN_RESUME_ALL();
+    for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
+        qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
+        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && 
+            _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
+            _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp));
+    }
+    for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
+        qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
+        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
+            _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
+                _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp));
+    }
+    _PR_MD_END_RESUME_ALL();
+    suspendAllThread = NULL;
+    suspendAllOn = PR_FALSE;
+    PR_Unlock(_pr_activeLock);
+}
+
+PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
+{
+    PRCList *qp, *qp_next;
+    PRIntn i = 0;
+    PRStatus rv = PR_SUCCESS;
+    PRThread* t;
+
+    /*
+    ** Currently Enumerate threads happen only with suspension and
+    ** pr_activeLock held
+    */
+    PR_ASSERT(suspendAllOn);
+
+    /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
+     * qp->next after applying the function "func".  In particular, "func"
+     * might remove the thread from the queue and put it into another one in
+     * which case qp->next no longer points to the next entry in the original
+     * queue.
+     *
+     * To get around this problem, we save qp->next in qp_next before applying
+     * "func" and use that saved value as the next value after applying "func".
+     */
+
+    /*
+     * Traverse the list of local and global threads
+     */
+    for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
+         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp_next)
+    {
+        qp_next = qp->next;
+        t = _PR_ACTIVE_THREAD_PTR(qp);
+        if (_PR_IS_GCABLE_THREAD(t))
+        {
+            rv = (*func)(t, i, arg);
+            if (rv != PR_SUCCESS)
+                return rv;
+            i++;
+        }
+    }
+    for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
+         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp_next)
+    {
+        qp_next = qp->next;
+        t = _PR_ACTIVE_THREAD_PTR(qp);
+        if (_PR_IS_GCABLE_THREAD(t))
+        {
+            rv = (*func)(t, i, arg);
+            if (rv != PR_SUCCESS)
+                return rv;
+            i++;
+        }
+    }
+    return rv;
+}
+
+/* FUNCTION: _PR_AddSleepQ
+** DESCRIPTION:
+**    Adds a thread to the sleep/pauseQ.
+** RESTRICTIONS:
+**    Caller must have the RUNQ lock.
+**    Caller must be a user level thread
+*/
+PR_IMPLEMENT(void)
+_PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout)
+{
+    _PRCPU *cpu = thread->cpu;
+
+    if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+        /* append the thread to the global pause Q */
+        PR_APPEND_LINK(&thread->links, &_PR_PAUSEQ(thread->cpu));
+        thread->flags |= _PR_ON_PAUSEQ;
+    } else {
+        PRIntervalTime sleep;
+        PRCList *q;
+        PRThread *t;
+
+        /* sort onto global sleepQ */
+        sleep = timeout;
+
+        /* Check if we are longest timeout */
+        if (timeout >= _PR_SLEEPQMAX(cpu)) {
+            PR_INSERT_BEFORE(&thread->links, &_PR_SLEEPQ(cpu));
+            thread->sleep = timeout - _PR_SLEEPQMAX(cpu);
+            _PR_SLEEPQMAX(cpu) = timeout;
+        } else {
+            /* Sort thread into global sleepQ at appropriate point */
+            q = _PR_SLEEPQ(cpu).next;
+
+            /* Now scan the list for where to insert this entry */
+            while (q != &_PR_SLEEPQ(cpu)) {
+                t = _PR_THREAD_PTR(q);
+                if (sleep < t->sleep) {
+                    /* Found sleeper to insert in front of */
+                    break;
+                }
+                sleep -= t->sleep;
+                q = q->next;
+            }
+            thread->sleep = sleep;
+            PR_INSERT_BEFORE(&thread->links, q);
+
+            /*
+            ** Subtract our sleep time from the sleeper that follows us (there
+            ** must be one) so that they remain relative to us.
+            */
+            PR_ASSERT (thread->links.next != &_PR_SLEEPQ(cpu));
+          
+            t = _PR_THREAD_PTR(thread->links.next);
+            PR_ASSERT(_PR_THREAD_PTR(t->links.prev) == thread);
+            t->sleep -= sleep;
+        }
+
+        thread->flags |= _PR_ON_SLEEPQ;
+    }
+}
+
+/* FUNCTION: _PR_DelSleepQ
+** DESCRIPTION:
+**    Removes a thread from the sleep/pauseQ.
+** INPUTS:
+**    If propogate_time is true, then the thread following the deleted
+**    thread will be get the time from the deleted thread.  This is used
+**    when deleting a sleeper that has not timed out.
+** RESTRICTIONS:
+**    Caller must have the RUNQ lock.
+**    Caller must be a user level thread
+*/
+PR_IMPLEMENT(void)
+_PR_DelSleepQ(PRThread *thread, PRBool propogate_time)
+{
+    _PRCPU *cpu = thread->cpu;
+
+    /* Remove from pauseQ/sleepQ */
+    if (thread->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
+        if (thread->flags & _PR_ON_SLEEPQ) {
+            PRCList *q = thread->links.next;
+            if (q != &_PR_SLEEPQ(cpu)) {
+                if (propogate_time == PR_TRUE) {
+                    PRThread *after = _PR_THREAD_PTR(q);
+                    after->sleep += thread->sleep;
+                } else 
+                    _PR_SLEEPQMAX(cpu) -= thread->sleep;
+            } else {
+                /* Check if prev is the beggining of the list; if so,
+                 * we are the only element on the list.  
+                 */
+                if (thread->links.prev != &_PR_SLEEPQ(cpu))
+                    _PR_SLEEPQMAX(cpu) -= thread->sleep;
+                else
+                    _PR_SLEEPQMAX(cpu) = 0;
+            }
+            thread->flags &= ~_PR_ON_SLEEPQ;
+        } else {
+            thread->flags &= ~_PR_ON_PAUSEQ;
+        }
+        PR_REMOVE_LINK(&thread->links);
+    } else 
+        PR_ASSERT(0);
+}
+
+void
+_PR_AddThreadToRunQ(
+    PRThread *me,     /* the current thread */
+    PRThread *thread) /* the local thread to be added to a run queue */
+{
+    PRThreadPriority pri = thread->priority;
+    _PRCPU *cpu = thread->cpu;
+
+    PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
+
+#if defined(WINNT)
+    /*
+     * On NT, we can only reliably know that the current CPU
+     * is not idle.  We add the awakened thread to the run
+     * queue of its CPU if its CPU is the current CPU.
+     * For any other CPU, we don't really know whether it
+     * is busy or idle.  So in all other cases, we just
+     * "post" the awakened thread to the IO completion port
+     * for the next idle CPU to execute (this is done in
+     * _PR_MD_WAKEUP_WAITER).
+	 * Threads with a suspended I/O operation remain bound to
+	 * the same cpu until I/O is cancelled
+     *
+     * NOTE: the boolean expression below must be the exact
+     * opposite of the corresponding boolean expression in
+     * _PR_MD_WAKEUP_WAITER.
+     */
+    if ((!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) ||
+					(thread->md.thr_bound_cpu)) {
+		PR_ASSERT(!thread->md.thr_bound_cpu ||
+							(thread->md.thr_bound_cpu == cpu));
+        _PR_RUNQ_LOCK(cpu);
+        _PR_ADD_RUNQ(thread, cpu, pri);
+        _PR_RUNQ_UNLOCK(cpu);
+    }
+#else
+    _PR_RUNQ_LOCK(cpu);
+    _PR_ADD_RUNQ(thread, cpu, pri);
+    _PR_RUNQ_UNLOCK(cpu);
+    if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) {
+        if (pri > me->priority) {
+            _PR_SET_RESCHED_FLAG();
+        }
+    }
+#endif
+}
diff --git a/mozilla/nsprpub/pr/src/threads/prcmon.c b/mozilla/nsprpub/pr/src/threads/prcmon.c
new file mode 100644
index 0000000..67aee4c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/prcmon.c
@@ -0,0 +1,463 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+
+/* Lock used to lock the monitor cache */
+#ifdef _PR_NO_PREEMPT
+#define _PR_NEW_LOCK_MCACHE()
+#define _PR_DESTROY_LOCK_MCACHE()
+#define _PR_LOCK_MCACHE()
+#define _PR_UNLOCK_MCACHE()
+#else
+#ifdef _PR_LOCAL_THREADS_ONLY
+#define _PR_NEW_LOCK_MCACHE()
+#define _PR_DESTROY_LOCK_MCACHE()
+#define _PR_LOCK_MCACHE() { PRIntn _is; _PR_INTSOFF(_is)
+#define _PR_UNLOCK_MCACHE() _PR_INTSON(_is); }
+#else
+PRLock *_pr_mcacheLock;
+#define _PR_NEW_LOCK_MCACHE() (_pr_mcacheLock = PR_NewLock())
+#define _PR_DESTROY_LOCK_MCACHE()               \
+    PR_BEGIN_MACRO                              \
+        if (_pr_mcacheLock) {                   \
+            PR_DestroyLock(_pr_mcacheLock);     \
+            _pr_mcacheLock = NULL;              \
+        }                                       \
+    PR_END_MACRO
+#define _PR_LOCK_MCACHE() PR_Lock(_pr_mcacheLock)
+#define _PR_UNLOCK_MCACHE() PR_Unlock(_pr_mcacheLock)
+#endif
+#endif
+
+/************************************************************************/
+
+typedef struct MonitorCacheEntryStr MonitorCacheEntry;
+
+struct MonitorCacheEntryStr {
+    MonitorCacheEntry*  next;
+    void*               address;
+    PRMonitor*          mon;
+    long                cacheEntryCount;
+};
+
+/*
+** An array of MonitorCacheEntry's, plus a pointer to link these
+** arrays together.
+*/
+
+typedef struct MonitorCacheEntryBlockStr MonitorCacheEntryBlock;
+
+struct MonitorCacheEntryBlockStr {
+    MonitorCacheEntryBlock* next;
+    MonitorCacheEntry entries[1];
+};
+
+static PRUint32 hash_mask;
+static PRUintn num_hash_buckets;
+static PRUintn num_hash_buckets_log2;
+static MonitorCacheEntry **hash_buckets;
+static MonitorCacheEntry *free_entries;
+static PRUintn num_free_entries;
+static PRBool expanding;
+static MonitorCacheEntryBlock *mcache_blocks;
+
+static void (*OnMonitorRecycle)(void *address);
+
+#define HASH(address)                               \
+    ((PRUint32) ( ((PRUptrdiff)(address) >> 2) ^    \
+                  ((PRUptrdiff)(address) >> 10) )   \
+     & hash_mask)
+
+/*
+** Expand the monitor cache. This grows the hash buckets and allocates a
+** new chunk of cache entries and throws them on the free list. We keep
+** as many hash buckets as there are entries.
+**
+** Because we call malloc and malloc may need the monitor cache, we must
+** ensure that there are several free monitor cache entries available for
+** malloc to get. FREE_THRESHOLD is used to prevent monitor cache
+** starvation during monitor cache expansion.
+*/
+
+#define FREE_THRESHOLD  5
+
+static PRStatus ExpandMonitorCache(PRUintn new_size_log2)
+{
+    MonitorCacheEntry **old_hash_buckets, *p;
+    PRUintn i, entries, old_num_hash_buckets, added;
+    MonitorCacheEntry **new_hash_buckets;
+    MonitorCacheEntryBlock *new_block;
+
+    entries = 1L << new_size_log2;
+
+    /*
+    ** Expand the monitor-cache-entry free list
+    */
+    new_block = (MonitorCacheEntryBlock*)
+        PR_CALLOC(sizeof(MonitorCacheEntryBlock)
+        + (entries - 1) * sizeof(MonitorCacheEntry));
+    if (NULL == new_block) return PR_FAILURE;
+
+    /*
+    ** Allocate system monitors for the new monitor cache entries. If we
+    ** run out of system monitors, break out of the loop.
+    */
+    for (i = 0, p = new_block->entries; i < entries; i++, p++) {
+        p->mon = PR_NewMonitor();
+        if (!p->mon)
+            break;
+    }
+    added = i;
+    if (added != entries) {
+        MonitorCacheEntryBlock *realloc_block;
+
+        if (added == 0) {
+            /* Totally out of system monitors. Lossage abounds */
+            PR_DELETE(new_block);
+            return PR_FAILURE;
+        }
+
+        /*
+        ** We were able to allocate some of the system monitors. Use
+        ** realloc to shrink down the new_block memory. If that fails,
+        ** carry on with the too-large new_block.
+        */
+        realloc_block = (MonitorCacheEntryBlock*)
+            PR_REALLOC(new_block, sizeof(MonitorCacheEntryBlock)
+            + (added - 1) * sizeof(MonitorCacheEntry));
+        if (realloc_block)
+            new_block = realloc_block;
+    }
+
+    /*
+    ** Now that we have allocated all of the system monitors, build up
+    ** the new free list. We can just update the free_list because we own
+    ** the mcache-lock and we aren't calling anyone who might want to use
+    ** it.
+    */
+    for (i = 0, p = new_block->entries; i < added - 1; i++, p++)
+        p->next = p + 1;
+    p->next = free_entries;
+    free_entries = new_block->entries;
+    num_free_entries += added;
+    new_block->next = mcache_blocks;
+    mcache_blocks = new_block;
+
+    /* Try to expand the hash table */
+    new_hash_buckets = (MonitorCacheEntry**)
+        PR_CALLOC(entries * sizeof(MonitorCacheEntry*));
+    if (NULL == new_hash_buckets) {
+        /*
+        ** Partial lossage. In this situation we don't get any more hash
+        ** buckets, which just means that the table lookups will take
+        ** longer. This is bad, but not fatal
+        */
+        PR_LOG(_pr_cmon_lm, PR_LOG_WARNING,
+               ("unable to grow monitor cache hash buckets"));
+        return PR_SUCCESS;
+    }
+
+    /*
+    ** Compute new hash mask value. This value is used to mask an address
+    ** until it's bits are in the right spot for indexing into the hash
+    ** table.
+    */
+    hash_mask = entries - 1;
+
+    /*
+    ** Expand the hash table. We have to rehash everything in the old
+    ** table into the new table.
+    */
+    old_hash_buckets = hash_buckets;
+    old_num_hash_buckets = num_hash_buckets;
+    for (i = 0; i < old_num_hash_buckets; i++) {
+        p = old_hash_buckets[i];
+        while (p) {
+            MonitorCacheEntry *next = p->next;
+
+            /* Hash based on new table size, and then put p in the new table */
+            PRUintn hash = HASH(p->address);
+            p->next = new_hash_buckets[hash];
+            new_hash_buckets[hash] = p;
+
+            p = next;
+        }
+    }
+
+    /*
+    ** Switch over to new hash table and THEN call free of the old
+    ** table. Since free might re-enter _pr_mcache_lock, things would
+    ** break terribly if it used the old hash table.
+    */
+    hash_buckets = new_hash_buckets;
+    num_hash_buckets = entries;
+    num_hash_buckets_log2 = new_size_log2;
+    PR_DELETE(old_hash_buckets);
+
+    PR_LOG(_pr_cmon_lm, PR_LOG_NOTICE,
+           ("expanded monitor cache to %d (buckets %d)",
+            num_free_entries, entries));
+
+    return PR_SUCCESS;
+}  /* ExpandMonitorCache */
+
+/*
+** Lookup a monitor cache entry by address. Return a pointer to the
+** pointer to the monitor cache entry on success, null on failure.
+*/
+static MonitorCacheEntry **LookupMonitorCacheEntry(void *address)
+{
+    PRUintn hash;
+    MonitorCacheEntry **pp, *p;
+
+    hash = HASH(address);
+    pp = hash_buckets + hash;
+    while ((p = *pp) != 0) {
+        if (p->address == address) {
+            if (p->cacheEntryCount > 0)
+                return pp;
+            return NULL;
+        }
+        pp = &p->next;
+    }
+    return NULL;
+}
+
+/*
+** Try to create a new cached monitor. If it's already in the cache,
+** great - return it. Otherwise get a new free cache entry and set it
+** up. If the cache free space is getting low, expand the cache.
+*/
+static PRMonitor *CreateMonitor(void *address)
+{
+    PRUintn hash;
+    MonitorCacheEntry **pp, *p;
+
+    hash = HASH(address);
+    pp = hash_buckets + hash;
+    while ((p = *pp) != 0) {
+        if (p->address == address) goto gotit;
+
+        pp = &p->next;
+    }
+
+    /* Expand the monitor cache if we have run out of free slots in the table */
+    if (num_free_entries < FREE_THRESHOLD) {
+        /* Expand monitor cache */
+
+        /*
+        ** This function is called with the lock held. So what's the 'expanding'
+        ** boolean all about? Seems a bit redundant.
+        */
+        if (!expanding) {
+            PRStatus rv;
+
+            expanding = PR_TRUE;
+            rv = ExpandMonitorCache(num_hash_buckets_log2 + 1);
+            expanding = PR_FALSE;
+            if (PR_FAILURE == rv)  return NULL;
+
+            /* redo the hash because it'll be different now */
+            hash = HASH(address);
+        } else {
+            /*
+            ** We are in process of expanding and we need a cache
+            ** monitor.  Make sure we have enough!
+            */
+            PR_ASSERT(num_free_entries > 0);
+        }
+    }
+
+    /* Make a new monitor */
+    p = free_entries;
+    free_entries = p->next;
+    num_free_entries--;
+    if (OnMonitorRecycle && p->address)
+        OnMonitorRecycle(p->address);
+    p->address = address;
+    p->next = hash_buckets[hash];
+    hash_buckets[hash] = p;
+    PR_ASSERT(p->cacheEntryCount == 0);
+
+  gotit:
+    p->cacheEntryCount++;
+    return p->mon;
+}
+
+/*
+** Initialize the monitor cache
+*/
+void _PR_InitCMon(void)
+{
+    _PR_NEW_LOCK_MCACHE();
+    ExpandMonitorCache(3);
+}
+
+/*
+** Destroy the monitor cache
+*/
+void _PR_CleanupCMon(void)
+{
+    _PR_DESTROY_LOCK_MCACHE();
+
+    while (free_entries) {
+        PR_DestroyMonitor(free_entries->mon);
+        free_entries = free_entries->next;
+    }
+    num_free_entries = 0;
+
+    while (mcache_blocks) {
+        MonitorCacheEntryBlock *block;
+
+        block = mcache_blocks;
+        mcache_blocks = block->next;
+        PR_DELETE(block);
+    }
+
+    PR_DELETE(hash_buckets);
+    hash_mask = 0;
+    num_hash_buckets = 0;
+    num_hash_buckets_log2 = 0;
+
+    expanding = PR_FALSE;
+    OnMonitorRecycle = NULL;
+}
+
+/*
+** Create monitor for address. Don't enter the monitor while we have the
+** mcache locked because we might block!
+*/
+PR_IMPLEMENT(PRMonitor*) PR_CEnterMonitor(void *address)
+{
+    PRMonitor *mon;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    _PR_LOCK_MCACHE();
+    mon = CreateMonitor(address);
+    _PR_UNLOCK_MCACHE();
+
+    if (!mon) return NULL;
+
+    PR_EnterMonitor(mon);
+    return mon;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CExitMonitor(void *address)
+{
+    MonitorCacheEntry **pp, *p;
+    PRStatus status = PR_SUCCESS;
+
+    _PR_LOCK_MCACHE();
+    pp = LookupMonitorCacheEntry(address);
+    if (pp != NULL) {
+        p = *pp;
+        if (--p->cacheEntryCount == 0) {
+            /*
+            ** Nobody is using the system monitor. Put it on the cached free
+            ** list. We are safe from somebody trying to use it because we
+            ** have the mcache locked.
+            */
+            p->address = 0;             /* defensive move */
+            *pp = p->next;              /* unlink from hash_buckets */
+            p->next = free_entries;     /* link into free list */
+            free_entries = p;
+            num_free_entries++;         /* count it as free */
+        }
+        status = PR_ExitMonitor(p->mon);
+    } else {
+        status = PR_FAILURE;
+    }
+    _PR_UNLOCK_MCACHE();
+
+    return status;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CWait(void *address, PRIntervalTime ticks)
+{
+    MonitorCacheEntry **pp;
+    PRMonitor *mon;
+
+    _PR_LOCK_MCACHE();
+    pp = LookupMonitorCacheEntry(address);
+    mon = pp ? ((*pp)->mon) : NULL;
+    _PR_UNLOCK_MCACHE();
+
+    if (mon == NULL)
+        return PR_FAILURE;
+    return PR_Wait(mon, ticks);
+}
+
+PR_IMPLEMENT(PRStatus) PR_CNotify(void *address)
+{
+    MonitorCacheEntry **pp;
+    PRMonitor *mon;
+
+    _PR_LOCK_MCACHE();
+    pp = LookupMonitorCacheEntry(address);
+    mon = pp ? ((*pp)->mon) : NULL;
+    _PR_UNLOCK_MCACHE();
+
+    if (mon == NULL)
+        return PR_FAILURE;
+    return PR_Notify(mon);
+}
+
+PR_IMPLEMENT(PRStatus) PR_CNotifyAll(void *address)
+{
+    MonitorCacheEntry **pp;
+    PRMonitor *mon;
+
+    _PR_LOCK_MCACHE();
+    pp = LookupMonitorCacheEntry(address);
+    mon = pp ? ((*pp)->mon) : NULL;
+    _PR_UNLOCK_MCACHE();
+
+    if (mon == NULL)
+        return PR_FAILURE;
+    return PR_NotifyAll(mon);
+}
+
+PR_IMPLEMENT(void)
+PR_CSetOnMonitorRecycle(void (*callback)(void *address))
+{
+    OnMonitorRecycle = callback;
+}
diff --git a/mozilla/nsprpub/pr/src/threads/prcthr.c b/mozilla/nsprpub/pr/src/threads/prcthr.c
new file mode 100644
index 0000000..7c3e627
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/prcthr.c
@@ -0,0 +1,426 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths 
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+** 
+*/
+#pragma warning(disable : 4101)
+#endif
+
+
+extern PRLock *_pr_sleeplock;  /* allocated and initialized in prinit */
+/* 
+** Routines common to both native and user threads.
+**
+**
+** Clean up a thread object, releasing all of the attached data. Do not
+** free the object itself (it may not have been malloc'd)
+*/
+void _PR_CleanupThread(PRThread *thread)
+{
+    /* Free up per-thread-data */
+    _PR_DestroyThreadPrivate(thread);
+
+    /* Free any thread dump procs */
+    if (thread->dumpArg) {
+        PR_DELETE(thread->dumpArg);
+    }
+    thread->dump = 0;
+
+    PR_DELETE(thread->errorString);
+    thread->errorStringSize = 0;
+    thread->errorStringLength = 0;
+    thread->environment = NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_Yield()
+{
+    static PRBool warning = PR_TRUE;
+    if (warning) warning = _PR_Obsolete(
+        "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
+    return (PR_Sleep(PR_INTERVAL_NO_WAIT));
+}
+
+/*
+** Make the current thread sleep until "timeout" ticks amount of time
+** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is
+** equivalent to a yield. Waiting for an infinite amount of time is
+** allowed in the expectation that another thread will interrupt().
+**
+** A single lock is used for all threads calling sleep. Each caller
+** does get its own condition variable since each is expected to have
+** a unique 'timeout'.
+*/
+PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout)
+{
+    PRStatus rv = PR_SUCCESS;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (PR_INTERVAL_NO_WAIT == timeout)
+    {
+        /*
+        ** This is a simple yield, nothing more, nothing less.
+        */
+        PRIntn is;
+        PRThread *me = PR_GetCurrentThread();
+        PRUintn pri = me->priority;
+        _PRCPU *cpu = _PR_MD_CURRENT_CPU();
+
+        if ( _PR_IS_NATIVE_THREAD(me) ) _PR_MD_YIELD();
+        else
+        {
+            _PR_INTSOFF(is);
+            _PR_RUNQ_LOCK(cpu);
+            if (_PR_RUNQREADYMASK(cpu) >> pri) {
+                me->cpu = cpu;
+                me->state = _PR_RUNNABLE;
+                _PR_ADD_RUNQ(me, cpu, pri);
+                _PR_RUNQ_UNLOCK(cpu);
+
+                PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: yielding"));
+                _PR_MD_SWITCH_CONTEXT(me);
+                PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: done"));
+
+                _PR_FAST_INTSON(is);
+            }
+            else
+            {
+                _PR_RUNQ_UNLOCK(cpu);
+                _PR_INTSON(is);
+            }
+        }
+    }
+    else
+    {
+        /*
+        ** This is waiting for some finite period of time.
+        ** A thread in this state is interruptible (PR_Interrupt()),
+        ** but the lock and cvar used are local to the implementation
+        ** and not visible to the caller, therefore not notifiable.
+        */
+        PRCondVar *cv;
+        PRIntervalTime timein;
+
+        timein = PR_IntervalNow();
+        cv = PR_NewCondVar(_pr_sleeplock);
+        PR_ASSERT(cv != NULL);
+        PR_Lock(_pr_sleeplock);
+        do
+        {
+            PRIntervalTime delta = PR_IntervalNow() - timein;
+            if (delta > timeout) break;
+            rv = PR_WaitCondVar(cv, timeout - delta);
+        } while (rv == PR_SUCCESS);
+        PR_Unlock(_pr_sleeplock);
+        PR_DestroyCondVar(cv);
+    }
+    return rv;
+}
+
+PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thread)
+{
+    return thread->id;
+}
+
+PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread)
+{
+    return (PRThreadPriority) thread->priority;
+}
+
+PR_IMPLEMENT(PRThread *) PR_GetCurrentThread()
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    return _PR_MD_CURRENT_THREAD();
+}
+
+/*
+** Set the interrupt flag for a thread. The thread will be unable to
+** block in i/o functions when this happens. Also, any PR_Wait's in
+** progress will be undone. The interrupt remains in force until
+** PR_ClearInterrupt is called.
+*/
+PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thread)
+{
+#ifdef _PR_GLOBAL_THREADS_ONLY
+    PRCondVar *victim;
+
+    _PR_THREAD_LOCK(thread);
+    thread->flags |= _PR_INTERRUPT;
+    victim = thread->wait.cvar;
+    _PR_THREAD_UNLOCK(thread);
+    if ((NULL != victim) && (!(thread->flags & _PR_INTERRUPT_BLOCKED))) {
+        int haveLock = (victim->lock->owner == _PR_MD_CURRENT_THREAD());
+
+        if (!haveLock) PR_Lock(victim->lock);
+        PR_NotifyAllCondVar(victim);
+        if (!haveLock) PR_Unlock(victim->lock);
+    }
+    return PR_SUCCESS;
+#else  /* ! _PR_GLOBAL_THREADS_ONLY */
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+            if (!_PR_IS_NATIVE_THREAD(me))
+            	_PR_INTSOFF(is);
+
+            _PR_THREAD_LOCK(thread);
+            thread->flags |= _PR_INTERRUPT;
+        switch (thread->state) {
+                case _PR_COND_WAIT:
+                        /*
+                         * call is made with thread locked;
+                         * on return lock is released
+                         */
+						if (!(thread->flags & _PR_INTERRUPT_BLOCKED))
+                        	_PR_NotifyLockedThread(thread);
+                        break;
+                case _PR_IO_WAIT:
+                        /*
+                         * Need to hold the thread lock when calling
+                         * _PR_Unblock_IO_Wait().  On return lock is
+                         * released. 
+                         */
+#if defined(XP_UNIX) || defined(WINNT) || defined(WIN16)
+						if (!(thread->flags & _PR_INTERRUPT_BLOCKED))
+                        	_PR_Unblock_IO_Wait(thread);
+#else
+                        _PR_THREAD_UNLOCK(thread);
+#endif
+                        break;
+                case _PR_RUNNING:
+                case _PR_RUNNABLE:
+                case _PR_LOCK_WAIT:
+                default:
+                            _PR_THREAD_UNLOCK(thread);
+                        break;
+        }
+            if (!_PR_IS_NATIVE_THREAD(me))
+            	_PR_INTSON(is);
+            return PR_SUCCESS;
+#endif  /* _PR_GLOBAL_THREADS_ONLY */
+}
+
+/*
+** Clear the interrupt flag for self.
+*/
+PR_IMPLEMENT(void) PR_ClearInterrupt()
+{
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+        if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+    _PR_THREAD_LOCK(me);
+         me->flags &= ~_PR_INTERRUPT;
+    _PR_THREAD_UNLOCK(me);
+        if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
+}
+
+PR_IMPLEMENT(void) PR_BlockInterrupt()
+{
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+    _PR_THREAD_LOCK(me);
+    _PR_THREAD_BLOCK_INTERRUPT(me);
+    _PR_THREAD_UNLOCK(me);
+    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
+}  /* PR_BlockInterrupt */
+
+PR_IMPLEMENT(void) PR_UnblockInterrupt()
+{
+    PRIntn is;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+    _PR_THREAD_LOCK(me);
+    _PR_THREAD_UNBLOCK_INTERRUPT(me);
+    _PR_THREAD_UNLOCK(me);
+    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
+}  /* PR_UnblockInterrupt */
+
+/*
+** Return the thread stack pointer of the given thread.
+*/
+PR_IMPLEMENT(void *) PR_GetSP(PRThread *thread)
+{
+        return (void *)_PR_MD_GET_SP(thread);
+}
+
+PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thread)
+{
+        return thread->environment;
+}
+
+PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env)
+{
+        thread->environment = env;
+}
+
+
+PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
+{
+#ifdef HAVE_THREAD_AFFINITY
+    return _PR_MD_GETTHREADAFFINITYMASK(thread, mask);
+#else
+    return 0;
+#endif
+}
+
+PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
+{
+#ifdef HAVE_THREAD_AFFINITY
+#ifndef IRIX
+    return _PR_MD_SETTHREADAFFINITYMASK(thread, mask);
+#else
+	return 0;
+#endif
+#else
+    return 0;
+#endif
+}
+
+/* This call is thread unsafe if another thread is calling SetConcurrency()
+ */
+PR_IMPLEMENT(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask)
+{
+#ifdef HAVE_THREAD_AFFINITY
+    PRCList *qp;
+    extern PRUint32 _pr_cpu_affinity_mask;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    _pr_cpu_affinity_mask = mask;
+
+    qp = _PR_CPUQ().next;
+    while(qp != &_PR_CPUQ()) {
+        _PRCPU *cpu;
+
+        cpu = _PR_CPU_PTR(qp);
+        PR_SetThreadAffinityMask(cpu->thread, mask);
+
+        qp = qp->next;
+    }
+#endif
+
+    return 0;
+}
+
+PRUint32 _pr_recycleThreads = 0;
+PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count)
+{
+    _pr_recycleThreads = count;
+}
+
+PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(PRThreadType type,
+                                     void (*start)(void *arg),
+                                     void *arg,
+                                     PRThreadPriority priority,
+                                     PRThreadScope scope,
+                                     PRThreadState state,
+                                     PRUint32 stackSize)
+{
+    return _PR_CreateThread(type, start, arg, priority, scope, state, 
+                            stackSize, _PR_GCABLE_THREAD);
+}
+
+#ifdef SOLARIS
+PR_IMPLEMENT(PRThread*) PR_CreateThreadBound(PRThreadType type,
+                                     void (*start)(void *arg),
+                                     void *arg,
+                                     PRUintn priority,
+                                     PRThreadScope scope,
+                                     PRThreadState state,
+                                     PRUint32 stackSize)
+{
+    return _PR_CreateThread(type, start, arg, priority, scope, state, 
+                            stackSize, _PR_BOUND_THREAD);
+}
+#endif
+
+
+PR_IMPLEMENT(PRThread*) PR_AttachThreadGCAble(
+    PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
+{
+    /* $$$$ not sure how to finese this one */
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+
+PR_IMPLEMENT(void) PR_SetThreadGCAble()
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    PR_Lock(_pr_activeLock);
+        _PR_MD_CURRENT_THREAD()->flags |= _PR_GCABLE_THREAD;
+        PR_Unlock(_pr_activeLock);        
+}
+
+PR_IMPLEMENT(void) PR_ClearThreadGCAble()
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    PR_Lock(_pr_activeLock);
+        _PR_MD_CURRENT_THREAD()->flags &= (~_PR_GCABLE_THREAD);
+        PR_Unlock(_pr_activeLock);
+}
+
+PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thread)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (_PR_IS_NATIVE_THREAD(thread)) {
+    	return (thread->flags & _PR_BOUND_THREAD) ? PR_GLOBAL_BOUND_THREAD :
+										PR_GLOBAL_THREAD;
+    } else
+        return PR_LOCAL_THREAD;
+}
+
+PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thread)
+{
+    return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD;
+}
+
+PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thread)
+{
+    return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
+}  /* PR_GetThreadState */
diff --git a/mozilla/nsprpub/pr/src/threads/prdump.c b/mozilla/nsprpub/pr/src/threads/prdump.c
new file mode 100644
index 0000000..3ea884d
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/prdump.c
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths 
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+** 
+*/
+#pragma warning(disable : 4101)
+#endif
+
+/* XXX use unbuffered nspr stdio */
+
+PRFileDesc *_pr_dumpOut;
+
+PRUint32 _PR_DumpPrintf(PRFileDesc *fd, const char *fmt, ...)
+{
+    char buf[100];
+    PRUint32 nb;
+    va_list ap;
+
+    va_start(ap, fmt);
+    nb = PR_vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    PR_Write(fd, buf, nb);
+
+    return nb;
+}
+
+void _PR_DumpThread(PRFileDesc *fd, PRThread *thread)
+{
+
+#ifndef _PR_GLOBAL_THREADS_ONLY
+    _PR_DumpPrintf(fd, "%05d[%08p] pri=%2d flags=0x%02x",
+                   thread->id, thread, thread->priority, thread->flags);
+    switch (thread->state) {
+      case _PR_RUNNABLE:
+      case _PR_RUNNING:
+        break;
+      case _PR_LOCK_WAIT:
+        _PR_DumpPrintf(fd, " lock=%p", thread->wait.lock);
+        break;
+      case _PR_COND_WAIT:
+        _PR_DumpPrintf(fd, " condvar=%p sleep=%lldms",
+                       thread->wait.cvar, thread->sleep);
+        break;
+      case _PR_SUSPENDED:
+        _PR_DumpPrintf(fd, " suspended");
+        break;
+    }
+    PR_Write(fd, "\n", 1);
+#endif
+
+    /* Now call dump routine */
+    if (thread->dump) {
+	thread->dump(fd, thread, thread->dumpArg);
+    }
+}
+
+static void DumpThreadQueue(PRFileDesc *fd, PRCList *list)
+{
+#ifndef _PR_GLOBAL_THREADS_ONLY
+    PRCList *q;
+
+    q = list->next;
+    while (q != list) {
+        PRThread *t = _PR_THREAD_PTR(q);
+        _PR_DumpThread(fd, t);
+        q = q->next;
+    }
+#endif
+}
+
+void _PR_DumpThreads(PRFileDesc *fd)
+{
+    PRThread *t;
+    PRIntn i;
+
+    _PR_DumpPrintf(fd, "Current Thread:\n");
+    t = _PR_MD_CURRENT_THREAD();
+    _PR_DumpThread(fd, t);
+
+    _PR_DumpPrintf(fd, "Runnable Threads:\n");
+    for (i = 0; i < 32; i++) {
+        DumpThreadQueue(fd, &_PR_RUNQ(t->cpu)[i]);
+    }
+
+    _PR_DumpPrintf(fd, "CondVar timed wait Threads:\n");
+    DumpThreadQueue(fd, &_PR_SLEEPQ(t->cpu));
+
+    _PR_DumpPrintf(fd, "CondVar wait Threads:\n");
+    DumpThreadQueue(fd, &_PR_PAUSEQ(t->cpu));
+
+    _PR_DumpPrintf(fd, "Suspended Threads:\n");
+    DumpThreadQueue(fd, &_PR_SUSPENDQ(t->cpu));
+}
+
+PR_IMPLEMENT(void) PR_ShowStatus(void)
+{
+    PRIntn is;
+
+    if ( _PR_MD_CURRENT_THREAD()
+    && !_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) _PR_INTSOFF(is);
+    _pr_dumpOut = _pr_stderr;
+    _PR_DumpThreads(_pr_dumpOut);
+    if ( _PR_MD_CURRENT_THREAD()
+    && !_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) _PR_FAST_INTSON(is);
+}
+
+PR_IMPLEMENT(void)
+PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)
+{
+    thread->dump = dump;
+    thread->dumpArg = arg;
+}
diff --git a/mozilla/nsprpub/pr/src/threads/prmon.c b/mozilla/nsprpub/pr/src/threads/prmon.c
new file mode 100644
index 0000000..dc8a32c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/prmon.c
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+/************************************************************************/
+
+/*
+** Create a new monitor.
+*/
+PR_IMPLEMENT(PRMonitor*) PR_NewMonitor()
+{
+    PRMonitor *mon;
+	PRCondVar *cvar;
+	PRLock *lock;
+
+    mon = PR_NEWZAP(PRMonitor);
+    if (mon) {
+		lock = PR_NewLock();
+	    if (!lock) {
+			PR_DELETE(mon);
+			return 0;
+    	}
+
+	    cvar = PR_NewCondVar(lock);
+	    if (!cvar) {
+	    	PR_DestroyLock(lock);
+			PR_DELETE(mon);
+			return 0;
+    	}
+    	mon->cvar = cvar;
+	mon->name = NULL;
+    }
+    return mon;
+}
+
+PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
+{
+    PRMonitor* mon = PR_NewMonitor();
+    if (mon)
+        mon->name = name;
+    return mon;
+}
+
+/*
+** Destroy a monitor. There must be no thread waiting on the monitor's
+** condition variable. The caller is responsible for guaranteeing that the
+** monitor is no longer in use.
+*/
+PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
+{
+	PR_DestroyLock(mon->cvar->lock);
+    PR_DestroyCondVar(mon->cvar);
+    PR_DELETE(mon);
+}
+
+/*
+** Enter the lock associated with the monitor.
+*/
+PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
+{
+    if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) {
+		mon->entryCount++;
+    } else {
+		PR_Lock(mon->cvar->lock);
+		mon->entryCount = 1;
+    }
+}
+
+/*
+** Test and then enter the lock associated with the monitor if it's not
+** already entered by some other thread. Return PR_FALSE if some other
+** thread owned the lock at the time of the call.
+*/
+PR_IMPLEMENT(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon)
+{
+    if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) {
+		mon->entryCount++;
+		return PR_TRUE;
+    } else {
+		if (PR_TestAndLock(mon->cvar->lock)) {
+	    	mon->entryCount = 1;
+	   	 	return PR_TRUE;
+		}
+    }
+    return PR_FALSE;
+}
+
+/*
+** Exit the lock associated with the monitor once.
+*/
+PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
+{
+    if (mon->cvar->lock->owner != _PR_MD_CURRENT_THREAD()) {
+        return PR_FAILURE;
+    }
+    if (--mon->entryCount == 0) {
+		return PR_Unlock(mon->cvar->lock);
+    }
+    return PR_SUCCESS;
+}
+
+/*
+** Return the number of times that the current thread has entered the
+** lock. Returns zero if the current thread has not entered the lock.
+*/
+PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
+{
+    return (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) ?
+        mon->entryCount : 0;
+}
+
+/*
+** If the current thread is in |mon|, this assertion is guaranteed to
+** succeed.  Otherwise, the behavior of this function is undefined.
+*/
+PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
+{
+    PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(mon->cvar->lock);
+}
+
+/*
+** Wait for a notify on the condition variable. Sleep for "ticks" amount
+** of time (if "tick" is 0 then the sleep is indefinite). While
+** the thread is waiting it exits the monitors lock (as if it called
+** PR_ExitMonitor as many times as it had called PR_EnterMonitor).  When
+** the wait has finished the thread regains control of the monitors lock
+** with the same entry count as before the wait began.
+**
+** The thread waiting on the monitor will be resumed when the monitor is
+** notified (assuming the thread is the next in line to receive the
+** notify) or when the "ticks" elapses.
+**
+** Returns PR_FAILURE if the caller has not locked the lock associated
+** with the condition variable.
+** This routine can return PR_PENDING_INTERRUPT if the waiting thread 
+** has been interrupted.
+*/
+PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks)
+{
+    PRUintn entryCount;
+	PRStatus status;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (mon->cvar->lock->owner != me) return PR_FAILURE;
+
+    entryCount = mon->entryCount;
+    mon->entryCount = 0;
+
+	status = _PR_WaitCondVar(me, mon->cvar, mon->cvar->lock, ticks);
+
+    mon->entryCount = entryCount;
+
+    return status;
+}
+
+/*
+** Notify the highest priority thread waiting on the condition
+** variable. If a thread is waiting on the condition variable (using
+** PR_Wait) then it is awakened and begins waiting on the monitor's lock.
+*/
+PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    if (mon->cvar->lock->owner != me) return PR_FAILURE;
+    PR_NotifyCondVar(mon->cvar);
+    return PR_SUCCESS;
+}
+
+/*
+** Notify all of the threads waiting on the condition variable. All of
+** threads are notified in turn. The highest priority thread will
+** probably acquire the monitor first when the monitor is exited.
+*/
+PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    if (mon->cvar->lock->owner != me) return PR_FAILURE;
+    PR_NotifyAllCondVar(mon->cvar);
+    return PR_SUCCESS;
+}
+
+/************************************************************************/
+
+PRUint32 _PR_MonitorToString(PRMonitor *mon, char *buf, PRUint32 buflen)
+{
+    PRUint32 nb;
+
+    if (mon->cvar->lock->owner) {
+	nb = PR_snprintf(buf, buflen, "[%p] owner=%d[%p] count=%ld",
+			 mon, mon->cvar->lock->owner->id,
+			 mon->cvar->lock->owner, mon->entryCount);
+    } else {
+	nb = PR_snprintf(buf, buflen, "[%p]", mon);
+    }
+    return nb;
+}
diff --git a/mozilla/nsprpub/pr/src/threads/prrwlock.c b/mozilla/nsprpub/pr/src/threads/prrwlock.c
new file mode 100644
index 0000000..35e0e3e
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/prrwlock.c
@@ -0,0 +1,512 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+
+#include <string.h>
+
+#if defined(HPUX) && defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
+
+#include <pthread.h>
+#define HAVE_UNIX98_RWLOCK
+#define RWLOCK_T pthread_rwlock_t
+#define RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
+#define RWLOCK_DESTROY(lock) pthread_rwlock_destroy(lock)
+#define RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
+#define RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
+#define RWLOCK_UNLOCK(lock) pthread_rwlock_unlock(lock)
+
+#elif defined(SOLARIS) && (defined(_PR_PTHREADS) \
+        || defined(_PR_GLOBAL_THREADS_ONLY))
+
+#include <synch.h>
+#define HAVE_UI_RWLOCK
+#define RWLOCK_T rwlock_t
+#define RWLOCK_INIT(lock) rwlock_init(lock, USYNC_THREAD, NULL)
+#define RWLOCK_DESTROY(lock) rwlock_destroy(lock)
+#define RWLOCK_RDLOCK(lock) rw_rdlock(lock)
+#define RWLOCK_WRLOCK(lock) rw_wrlock(lock)
+#define RWLOCK_UNLOCK(lock) rw_unlock(lock)
+
+#endif
+
+/*
+ * Reader-writer lock
+ */
+struct PRRWLock {
+	char			*rw_name;			/* lock name					*/
+	PRUint32		rw_rank;			/* rank of the lock				*/
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	RWLOCK_T		rw_lock;
+#else
+    PRLock			*rw_lock;
+	PRInt32			rw_lock_cnt;		/* ==  0, if unlocked			*/
+										/* == -1, if write-locked		*/
+										/* > 0	, # of read locks		*/
+	PRUint32		rw_reader_cnt;		/* number of waiting readers	*/
+	PRUint32		rw_writer_cnt;		/* number of waiting writers	*/
+	PRCondVar   	*rw_reader_waitq;	/* cvar for readers 			*/
+	PRCondVar   	*rw_writer_waitq;	/* cvar for writers				*/
+#ifdef DEBUG
+    PRThread 		*rw_owner;			/* lock owner for write-lock	*/
+#endif
+#endif
+};
+
+#ifdef DEBUG
+#define _PR_RWLOCK_RANK_ORDER_DEBUG	/* enable deadlock detection using
+									   rank-order for locks
+									*/
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+
+static PRUintn	pr_thread_rwlock_key;			/* TPD key for lock stack */
+static PRUintn	pr_thread_rwlock_alloc_failed;
+
+#define	_PR_RWLOCK_RANK_ORDER_LIMIT	10
+
+typedef struct thread_rwlock_stack {
+	PRInt32		trs_index;									/* top of stack */
+	PRRWLock	*trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT];	/* stack of lock
+														 	   pointers */
+
+} thread_rwlock_stack;
+
+static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
+static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void);
+static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
+static void _PR_RELEASE_LOCK_STACK(void *lock_stack);
+
+#endif
+
+/*
+ * Reader/Writer Locks
+ */
+
+/*
+ * PR_NewRWLock
+ *		Create a reader-writer lock, with the given lock rank and lock name
+ *	
+ */
+
+PR_IMPLEMENT(PRRWLock *)
+PR_NewRWLock(PRUint32 lock_rank, const char *lock_name)
+{
+    PRRWLock *rwlock;
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	int err;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    rwlock = PR_NEWZAP(PRRWLock);
+    if (rwlock == NULL)
+		return NULL;
+
+	rwlock->rw_rank = lock_rank;
+	if (lock_name != NULL) {
+		rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
+    	if (rwlock->rw_name == NULL) {
+			PR_DELETE(rwlock);
+			return(NULL);
+		}
+		strcpy(rwlock->rw_name, lock_name);
+	} else {
+		rwlock->rw_name = NULL;
+	}
+	
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_INIT(&rwlock->rw_lock);
+	if (err != 0) {
+		PR_SetError(PR_UNKNOWN_ERROR, err);
+		PR_Free(rwlock->rw_name);
+		PR_DELETE(rwlock);
+		return NULL;
+	}
+	return rwlock;
+#else
+	rwlock->rw_lock = PR_NewLock();
+    if (rwlock->rw_lock == NULL) {
+		goto failed;
+	}
+	rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock);
+    if (rwlock->rw_reader_waitq == NULL) {
+		goto failed;
+	}
+	rwlock->rw_writer_waitq = PR_NewCondVar(rwlock->rw_lock);
+    if (rwlock->rw_writer_waitq == NULL) {
+		goto failed;
+	}
+	rwlock->rw_reader_cnt = 0;
+	rwlock->rw_writer_cnt = 0;
+	rwlock->rw_lock_cnt = 0;
+	return rwlock;
+
+failed:
+	if (rwlock->rw_reader_waitq != NULL) {
+		PR_DestroyCondVar(rwlock->rw_reader_waitq);	
+	}
+	if (rwlock->rw_lock != NULL) {
+		PR_DestroyLock(rwlock->rw_lock);
+	}
+	PR_Free(rwlock->rw_name);
+	PR_DELETE(rwlock);
+	return NULL;
+#endif
+}
+
+/*
+** Destroy the given RWLock "lock".
+*/
+PR_IMPLEMENT(void)
+PR_DestroyRWLock(PRRWLock *rwlock)
+{
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	int err;
+	err = RWLOCK_DESTROY(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_ASSERT(rwlock->rw_reader_cnt == 0);
+	PR_DestroyCondVar(rwlock->rw_reader_waitq);	
+	PR_DestroyCondVar(rwlock->rw_writer_waitq);	
+	PR_DestroyLock(rwlock->rw_lock);
+#endif
+	if (rwlock->rw_name != NULL)
+		PR_Free(rwlock->rw_name);
+    PR_DELETE(rwlock);
+}
+
+/*
+** Read-lock the RWLock.
+*/
+PR_IMPLEMENT(void)
+PR_RWLock_Rlock(PRRWLock *rwlock)
+{
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+int err;
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * assert that rank ordering is not violated; the rank of 'rwlock' should
+	 * be equal to or greater than the highest rank of all the locks held by
+	 * the thread.
+	 */
+	PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || 
+					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
+#endif
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_RDLOCK(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_Lock(rwlock->rw_lock);
+	/*
+	 * wait if write-locked or if a writer is waiting; preference for writers
+	 */
+	while ((rwlock->rw_lock_cnt < 0) ||
+			(rwlock->rw_writer_cnt > 0)) {
+		rwlock->rw_reader_cnt++;
+		PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
+		rwlock->rw_reader_cnt--;
+	}
+	/*
+	 * Increment read-lock count
+	 */
+	rwlock->rw_lock_cnt++;
+
+	PR_Unlock(rwlock->rw_lock);
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * update thread's lock rank
+	 */
+	_PR_SET_THREAD_RWLOCK_RANK(rwlock);
+#endif
+}
+
+/*
+** Write-lock the RWLock.
+*/
+PR_IMPLEMENT(void)
+PR_RWLock_Wlock(PRRWLock *rwlock)
+{
+#if defined(DEBUG)
+PRThread *me = PR_GetCurrentThread();
+#endif
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+int err;
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * assert that rank ordering is not violated; the rank of 'rwlock' should
+	 * be equal to or greater than the highest rank of all the locks held by
+	 * the thread.
+	 */
+	PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || 
+					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
+#endif
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_WRLOCK(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_Lock(rwlock->rw_lock);
+	/*
+	 * wait if read locked
+	 */
+	while (rwlock->rw_lock_cnt != 0) {
+		rwlock->rw_writer_cnt++;
+		PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
+		rwlock->rw_writer_cnt--;
+	}
+	/*
+	 * apply write lock
+	 */
+	rwlock->rw_lock_cnt--;
+	PR_ASSERT(rwlock->rw_lock_cnt == -1);
+#ifdef DEBUG
+	PR_ASSERT(me != NULL);
+	rwlock->rw_owner = me;
+#endif
+	PR_Unlock(rwlock->rw_lock);
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * update thread's lock rank
+	 */
+	_PR_SET_THREAD_RWLOCK_RANK(rwlock);
+#endif
+}
+
+/*
+** Unlock the RW lock.
+*/
+PR_IMPLEMENT(void)
+PR_RWLock_Unlock(PRRWLock *rwlock)
+{
+#if defined(DEBUG)
+PRThread *me = PR_GetCurrentThread();
+#endif
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+int err;
+#endif
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_UNLOCK(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_Lock(rwlock->rw_lock);
+	/*
+	 * lock must be read or write-locked
+	 */
+	PR_ASSERT(rwlock->rw_lock_cnt != 0);
+	if (rwlock->rw_lock_cnt > 0) {
+
+		/*
+		 * decrement read-lock count
+		 */
+		rwlock->rw_lock_cnt--;
+		if (rwlock->rw_lock_cnt == 0) {
+			/*
+			 * lock is not read-locked anymore; wakeup a waiting writer
+			 */
+			if (rwlock->rw_writer_cnt > 0)
+				PR_NotifyCondVar(rwlock->rw_writer_waitq);
+		}
+	} else {
+		PR_ASSERT(rwlock->rw_lock_cnt == -1);
+
+		rwlock->rw_lock_cnt = 0;
+#ifdef DEBUG
+    	PR_ASSERT(rwlock->rw_owner == me);
+    	rwlock->rw_owner = NULL;
+#endif
+		/*
+		 * wakeup a writer, if present; preference for writers
+		 */
+		if (rwlock->rw_writer_cnt > 0)
+			PR_NotifyCondVar(rwlock->rw_writer_waitq);
+		/*
+		 * else, wakeup all readers, if any
+		 */
+		else if (rwlock->rw_reader_cnt > 0)
+			PR_NotifyAllCondVar(rwlock->rw_reader_waitq);
+	}
+	PR_Unlock(rwlock->rw_lock);
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * update thread's lock rank
+	 */
+	_PR_UNSET_THREAD_RWLOCK_RANK(rwlock);
+#endif
+	return;
+}
+
+#ifndef _PR_RWLOCK_RANK_ORDER_DEBUG
+
+void _PR_InitRWLocks(void) { }
+
+#else
+
+void _PR_InitRWLocks(void)
+{
+	/*
+	 * allocated thread-private-data index for rwlock list
+	 */
+	if (PR_NewThreadPrivateIndex(&pr_thread_rwlock_key,
+			_PR_RELEASE_LOCK_STACK) == PR_FAILURE) {
+		pr_thread_rwlock_alloc_failed = 1;
+		return;
+	}
+}
+
+/*
+ * _PR_SET_THREAD_RWLOCK_RANK
+ *		Set a thread's lock rank, which is the highest of the ranks of all
+ *		the locks held by the thread. Pointers to the locks are added to a
+ *		per-thread list, which is anchored off a thread-private data key.
+ */
+
+static void
+_PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
+{
+thread_rwlock_stack *lock_stack;
+PRStatus rv;
+
+	/*
+	 * allocate a lock stack
+	 */
+	if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) {
+		lock_stack = (thread_rwlock_stack *)
+						PR_CALLOC(1 * sizeof(thread_rwlock_stack));
+		if (lock_stack) {
+			rv = PR_SetThreadPrivate(pr_thread_rwlock_key, lock_stack);
+			if (rv == PR_FAILURE) {
+				PR_DELETE(lock_stack);
+				pr_thread_rwlock_alloc_failed = 1;
+				return;
+			}
+		} else {
+			pr_thread_rwlock_alloc_failed = 1;
+			return;
+		}
+	}
+	/*
+	 * add rwlock to lock stack, if limit is not exceeded
+	 */
+	if (lock_stack) {
+		if (lock_stack->trs_index < _PR_RWLOCK_RANK_ORDER_LIMIT)
+			lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;	
+	}
+}
+
+static void
+_PR_RELEASE_LOCK_STACK(void *lock_stack)
+{
+	PR_ASSERT(lock_stack);
+	PR_DELETE(lock_stack);
+}
+
+/*
+ * _PR_GET_THREAD_RWLOCK_RANK
+ *
+ *		return thread's lock rank. If thread-private-data for the lock
+ *		stack is not allocated, return PR_RWLOCK_RANK_NONE.
+ */
+	
+static PRUint32
+_PR_GET_THREAD_RWLOCK_RANK(void)
+{
+	thread_rwlock_stack *lock_stack;
+
+	if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL)
+		return (PR_RWLOCK_RANK_NONE);
+	else
+		return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
+}
+
+/*
+ * _PR_UNSET_THREAD_RWLOCK_RANK
+ *
+ *		remove the rwlock from the lock stack. Since locks may not be
+ *		unlocked in a FIFO order, the entire lock stack is searched.
+ */
+	
+static void
+_PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
+{
+	thread_rwlock_stack *lock_stack;
+	int new_index = 0, index, done = 0;
+
+	lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
+
+	PR_ASSERT(lock_stack != NULL);
+
+	index = lock_stack->trs_index - 1;
+	while (index-- >= 0) {
+		if ((lock_stack->trs_stack[index] == rwlock) && !done)  {
+			/*
+			 * reset the slot for rwlock
+			 */
+			lock_stack->trs_stack[index] = NULL;
+			done = 1;
+		}
+		/*
+		 * search for the lowest-numbered empty slot, above which there are
+		 * no non-empty slots
+		 */
+		if ((lock_stack->trs_stack[index] != NULL) && !new_index)
+			new_index = index + 1;
+		if (done && new_index)
+			break;
+	}
+	/*
+	 * set top of stack to highest numbered empty slot
+	 */
+	lock_stack->trs_index = new_index;
+
+}
+
+#endif 	/* _PR_RWLOCK_RANK_ORDER_DEBUG */
diff --git a/mozilla/nsprpub/pr/src/threads/prsem.c b/mozilla/nsprpub/pr/src/threads/prsem.c
new file mode 100644
index 0000000..d26897c
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/prsem.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 "primpl.h"
+#include "obsolete/prsem.h"
+
+/************************************************************************/
+
+/*
+** Create a new semaphore.
+*/
+PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
+{
+    PRSemaphore *sem;
+    PRCondVar *cvar;
+    PRLock *lock;
+
+    sem = PR_NEWZAP(PRSemaphore);
+    if (sem) {
+#ifdef HAVE_CVAR_BUILT_ON_SEM
+        _PR_MD_NEW_SEM(&sem->md, value);
+#else
+        lock = PR_NewLock();
+        if (!lock) {
+            PR_DELETE(sem);
+            return NULL;
+    	}
+
+        cvar = PR_NewCondVar(lock);
+        if (!cvar) {
+            PR_DestroyLock(lock);
+            PR_DELETE(sem);
+            return NULL;
+    	}
+    	sem->cvar = cvar;
+    	sem->count = value;
+#endif
+    }
+    return sem;
+}
+
+/*
+** Destroy a semaphore. There must be no thread waiting on the semaphore.
+** The caller is responsible for guaranteeing that the semaphore is
+** no longer in use.
+*/
+PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *sem)
+{
+#ifdef HAVE_CVAR_BUILT_ON_SEM
+    _PR_MD_DESTROY_SEM(&sem->md);
+#else
+    PR_ASSERT(sem->waiters == 0);
+
+    PR_DestroyLock(sem->cvar->lock);
+    PR_DestroyCondVar(sem->cvar);
+#endif
+    PR_DELETE(sem);
+}
+
+/*
+** Wait on a Semaphore.
+** 
+** This routine allows a calling thread to wait or proceed depending upon the 
+** state of the semahore sem. The thread can proceed only if the counter value 
+** of the semaphore sem is currently greater than 0. If the value of semaphore 
+** sem is positive, it is decremented by one and the routine returns immediately 
+** allowing the calling thread to continue. If the value of semaphore sem is 0, 
+** the calling thread blocks awaiting the semaphore to be released by another 
+** thread.
+** 
+** This routine can return PR_PENDING_INTERRUPT if the waiting thread 
+** has been interrupted.
+*/
+PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *sem)
+{
+	PRStatus status = PR_SUCCESS;
+
+#ifdef HAVE_CVAR_BUILT_ON_SEM
+	return _PR_MD_WAIT_SEM(&sem->md);
+#else
+	PR_Lock(sem->cvar->lock);
+	while (sem->count == 0) {
+		sem->waiters++;
+		status = PR_WaitCondVar(sem->cvar, PR_INTERVAL_NO_TIMEOUT);
+		sem->waiters--;
+		if (status != PR_SUCCESS)
+			break;
+	}
+	if (status == PR_SUCCESS)
+		sem->count--;
+	PR_Unlock(sem->cvar->lock);
+#endif
+	
+	return (status);
+}
+
+/*
+** This routine increments the counter value of the semaphore. If other threads 
+** are blocked for the semaphore, then the scheduler will determine which ONE 
+** thread will be unblocked.
+*/
+PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *sem)
+{
+#ifdef HAVE_CVAR_BUILT_ON_SEM
+	_PR_MD_POST_SEM(&sem->md);
+#else
+	PR_Lock(sem->cvar->lock);
+	if (sem->waiters)
+		PR_NotifyCondVar(sem->cvar);
+	sem->count++;
+	PR_Unlock(sem->cvar->lock);
+#endif
+}
+
+#if DEBUG
+/*
+** Returns the value of the semaphore referenced by sem without affecting
+** the state of the semaphore.  The value represents the semaphore vaule
+** at the time of the call, but may not be the actual value when the
+** caller inspects it. (FOR DEBUGGING ONLY)
+*/
+PR_IMPLEMENT(PRUintn) PR_GetValueSem(PRSemaphore *sem)
+{
+	PRUintn rv;
+
+#ifdef HAVE_CVAR_BUILT_ON_SEM
+	rv = _PR_MD_GET_VALUE_SEM(&sem->md);
+#else
+	PR_Lock(sem->cvar->lock);
+	rv = sem->count;
+	PR_Unlock(sem->cvar->lock);
+#endif
+	
+	return rv;
+}
+#endif
diff --git a/mozilla/nsprpub/pr/src/threads/prtpd.c b/mozilla/nsprpub/pr/src/threads/prtpd.c
new file mode 100644
index 0000000..168c660
--- /dev/null
+++ b/mozilla/nsprpub/pr/src/threads/prtpd.c
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+/*
+** Thread Private Data
+**
+** There is an aribitrary limit on the number of keys that will be allocated
+** by the runtime. It's largish, so it is intended to be a sanity check, not
+** an impediment.
+**
+** There is a counter, initialized to zero and incremented every time a
+** client asks for a new key, that holds the high water mark for keys. All
+** threads logically have the same high water mark and are permitted to
+** ask for TPD up to that key value.
+**
+** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is
+** called. The size of the vector will be some value greater than or equal
+** to the current high water mark. Each thread has its own TPD length and
+** vector.
+**
+** Threads that get private data for keys they have not set (or perhaps
+** don't even exist for that thread) get a NULL return. If the key is
+** beyond the high water mark, an error will be returned.
+*/
+
+/*
+** As of this time, BeOS has its own TPD implementation.  Integrating
+** this standard one is a TODO for anyone with a bit of spare time on
+** their hand.  For now, we just #ifdef out this whole file and use
+** the routines in pr/src/btthreads/
+*/
+
+#ifndef XP_BEOS
+
+#include "primpl.h"
+
+#include <string.h>
+
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths 
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+** 
+*/
+#pragma warning(disable : 4101)
+#endif
+
+#define _PR_TPD_LIMIT 128               /* arbitary limit on the TPD slots */
+static PRInt32 _pr_tpd_length = 0;      /* current length of destructor vector */
+static PRInt32 _pr_tpd_highwater = 0;   /* next TPD key to be assigned */
+static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL;
+                                        /* the destructors are associated with
+                                            the keys, therefore asserting that
+                                            the TPD key depicts the data's 'type' */
+
+/*
+** Initialize the thread private data manipulation
+*/
+void _PR_InitTPD(void)
+{
+    _pr_tpd_destructors = (PRThreadPrivateDTOR*)
+        PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*));
+    PR_ASSERT(NULL != _pr_tpd_destructors);
+    _pr_tpd_length = _PR_TPD_LIMIT;
+}
+
+/*
+** Clean up the thread private data manipulation
+*/
+void _PR_CleanupTPD(void)
+{
+}  /* _PR_CleanupTPD */
+
+/*
+** This routine returns a new index for per-thread-private data table. 
+** The index is visible to all threads within a process. This index can 
+** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 
+** to save and retrieve data associated with the index for a thread.
+**
+** The index independently maintains specific values for each binding thread. 
+** A thread can only get access to its own thread-specific-data.
+**
+** Upon a new index return the value associated with the index for all threads
+** is NULL, and upon thread creation the value associated with all indices for 
+** that thread is NULL. 
+**
+**     "dtor" is the destructor function to invoke when the private
+**       data is set or destroyed
+**
+** Returns PR_FAILURE if the total number of indices will exceed the maximun 
+** allowed.
+*/
+
+PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex(
+    PRUintn *newIndex, PRThreadPrivateDTOR dtor)
+{
+    PRStatus rv;
+    PRInt32 index;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    PR_ASSERT(NULL != newIndex);
+    PR_ASSERT(NULL != _pr_tpd_destructors);
+
+    index = PR_AtomicIncrement(&_pr_tpd_highwater) - 1;  /* allocate index */
+    if (_PR_TPD_LIMIT <= index)
+    {
+        PR_SetError(PR_TPD_RANGE_ERROR, 0);
+        rv = PR_FAILURE;  /* that's just wrong */
+    }
+    else
+    {
+        _pr_tpd_destructors[index] = dtor;  /* record destructor @index */
+        *newIndex = (PRUintn)index;  /* copy into client's location */
+        rv = PR_SUCCESS;  /* that's okay */
+    }
+
+    return rv;
+}
+
+/*
+** Define some per-thread-private data.
+**     "index" is an index into the per-thread private data table
+**     "priv" is the per-thread-private data 
+**
+** If the per-thread private data table has a previously registered
+** destructor function and a non-NULL per-thread-private data value,
+** the destructor function is invoked.
+**
+** This can return PR_FAILURE if index is invalid (ie., beyond the current
+** high water mark) or memory is insufficient to allocate an exanded vector.
+*/
+
+PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv)
+{
+    PRThread *self = PR_GetCurrentThread();
+
+    /*
+    ** The index being set might not have a sufficient vector in this
+    ** thread. But if the index has been allocated, it's okay to go
+    ** ahead and extend this one now.
+    */
+    if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater))
+    {
+        PR_SetError(PR_TPD_RANGE_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength))
+        || ((NULL != self->privateData) && (0 != self->tpdLength)));
+
+    if ((NULL == self->privateData) || (self->tpdLength <= index))
+    {
+        void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
+        if (NULL == extension)
+        {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return PR_FAILURE;
+        }
+        if (self->privateData) {
+            (void)memcpy(
+                extension, self->privateData,
+                self->tpdLength * sizeof(void*));
+            PR_DELETE(self->privateData);
+        }
+        self->tpdLength = _pr_tpd_length;
+        self->privateData = (void**)extension;
+    }
+    /*
+    ** There wasn't much chance of having to call the destructor
+    ** unless the slot already existed.
+    */
+    else if (self->privateData[index] && _pr_tpd_destructors[index])
+    {
+        void *data = self->privateData[index];
+        self->privateData[index] = NULL;
+        (*_pr_tpd_destructors[index])(data);
+    }
+
+    PR_ASSERT(index < self->tpdLength);
+    self->privateData[index] = priv;
+
+    return PR_SUCCESS;
+}
+
+/*
+** Recover the per-thread-private data for the current thread. "index" is
+** the index into the per-thread private data table. 
+**
+** The returned value may be NULL which is indistinguishable from an error 
+** condition.
+**
+*/
+
+PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index)
+{
+    PRThread *self = PR_GetCurrentThread();
+    void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ?
+        NULL : self->privateData[index];
+
+    return tpd;
+}
+
+/*
+** Destroy the thread's private data, if any exists. This is called at
+** thread termination time only. There should be no threading issues
+** since this is being called by the thread itself.
+*/
+void _PR_DestroyThreadPrivate(PRThread* self)
+{
+#define _PR_TPD_DESTRUCTOR_ITERATIONS 4
+
+    if (NULL != self->privateData)  /* we have some */
+    {
+        PRBool clean;
+        PRUint32 index;
+        PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS;
+        PR_ASSERT(0 != self->tpdLength);
+        do
+        {
+            clean = PR_TRUE;
+            for (index = 0; index < self->tpdLength; ++index)
+            {
+                void *priv = self->privateData[index];  /* extract */
+                if (NULL != priv)  /* we have data at this index */
+                {
+                    if (NULL != _pr_tpd_destructors[index])
+                    {
+                        self->privateData[index] = NULL;  /* precondition */
+                        (*_pr_tpd_destructors[index])(priv);  /* destroy */
+                        clean = PR_FALSE;  /* unknown side effects */
+                    }
+                }
+            }
+        } while ((--passes > 0) && !clean);  /* limit # of passes */
+        /*
+        ** We give up after a fixed number of passes. Any non-NULL
+        ** thread-private data value with a registered destructor
+        ** function is not destroyed.
+        */
+        memset(self->privateData, 0, self->tpdLength * sizeof(void*));
+    }
+}  /* _PR_DestroyThreadPrivate */
+
+#endif /* !XP_BEOS */
diff --git a/mozilla/security/nss/lib/base/arena.c b/mozilla/security/nss/lib/base/arena.c
new file mode 100644
index 0000000..1fb8df4
--- /dev/null
+++ b/mozilla/security/nss/lib/base/arena.c
@@ -0,0 +1,1156 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: arena.c,v $ $Revision: 1.12 $ $Date: 2008/05/13 01:22:35 $";
+#endif /* DEBUG */
+
+/*
+ * arena.c
+ *
+ * This contains the implementation of NSS's thread-safe arenas.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#ifdef ARENA_THREADMARK
+#include "prthread.h"
+#endif /* ARENA_THREADMARK */
+
+#include "prlock.h"
+#include "plarena.h"
+
+#include <string.h>
+
+/*
+ * NSSArena
+ *
+ * This is based on NSPR's arena code, but it is threadsafe.
+ *
+ * The public methods relating to this type are:
+ *
+ *  NSSArena_Create  -- constructor
+ *  NSSArena_Destroy
+ *
+ * The nonpublic methods relating to this type are:
+ *
+ *  nssArena_Create  -- constructor
+ *  nssArena_Destroy
+ *  nssArena_Mark
+ *  nssArena_Release
+ *  nssArena_Unmark
+ * 
+ *  nss_ZAlloc
+ *  nss_ZFreeIf
+ *  nss_ZRealloc
+ *
+ * In debug builds, the following calls are available:
+ *
+ *  nssArena_verifyPointer
+ *  nssArena_registerDestructor
+ *  nssArena_deregisterDestructor
+ */
+
+struct NSSArenaStr {
+  PLArenaPool pool;
+  PRLock *lock;
+#ifdef ARENA_THREADMARK
+  PRThread *marking_thread;
+  nssArenaMark *first_mark;
+  nssArenaMark *last_mark;
+#endif /* ARENA_THREADMARK */
+#ifdef ARENA_DESTRUCTOR_LIST
+  struct arena_destructor_node *first_destructor;
+  struct arena_destructor_node *last_destructor;
+#endif /* ARENA_DESTRUCTOR_LIST */
+};
+
+/*
+ * nssArenaMark
+ *
+ * This type is used to mark the current state of an NSSArena.
+ */
+
+struct nssArenaMarkStr {
+  PRUint32 magic;
+  void *mark;
+#ifdef ARENA_THREADMARK
+  nssArenaMark *next;
+#endif /* ARENA_THREADMARK */
+#ifdef ARENA_DESTRUCTOR_LIST
+  struct arena_destructor_node *next_destructor;
+  struct arena_destructor_node *prev_destructor;
+#endif /* ARENA_DESTRUCTOR_LIST */
+};
+
+#define MARK_MAGIC 0x4d41524b /* "MARK" how original */
+
+/*
+ * But first, the pointer-tracking code
+ */
+#ifdef DEBUG
+extern const NSSError NSS_ERROR_INTERNAL_ERROR;
+
+static nssPointerTracker arena_pointer_tracker;
+
+static PRStatus
+arena_add_pointer
+(
+  const NSSArena *arena
+)
+{
+  PRStatus rv;
+
+  rv = nssPointerTracker_initialize(&arena_pointer_tracker);
+  if( PR_SUCCESS != rv ) {
+    return rv;
+  }
+
+  rv = nssPointerTracker_add(&arena_pointer_tracker, arena);
+  if( PR_SUCCESS != rv ) {
+    NSSError e = NSS_GetError();
+    if( NSS_ERROR_NO_MEMORY != e ) {
+      nss_SetError(NSS_ERROR_INTERNAL_ERROR);
+    }
+
+    return rv;
+  }
+
+  return PR_SUCCESS;
+}
+
+static PRStatus
+arena_remove_pointer
+(
+  const NSSArena *arena
+)
+{
+  PRStatus rv;
+
+  rv = nssPointerTracker_remove(&arena_pointer_tracker, arena);
+  if( PR_SUCCESS != rv ) {
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR);
+  }
+
+  return rv;
+}
+
+/*
+ * nssArena_verifyPointer
+ *
+ * This method is only present in debug builds.
+ *
+ * If the specified pointer is a valid pointer to an NSSArena object,
+ * this routine will return PR_SUCCESS.  Otherwise, it will put an
+ * error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *
+ * Return value:
+ *  PR_SUCCESS if the pointer is valid
+ *  PR_FAILURE if it isn't
+ */
+
+NSS_IMPLEMENT PRStatus
+nssArena_verifyPointer
+(
+  const NSSArena *arena
+)
+{
+  PRStatus rv;
+
+  rv = nssPointerTracker_initialize(&arena_pointer_tracker);
+  if( PR_SUCCESS != rv ) {
+    /*
+     * This is a little disingenious.  We have to initialize the
+     * tracker, because someone could "legitimately" try to verify
+     * an arena pointer before one is ever created.  And this step
+     * might fail, due to lack of memory.  But the only way that
+     * this step can fail is if it's doing the call_once stuff,
+     * (later calls just no-op).  And if it didn't no-op, there
+     * aren't any valid arenas.. so the argument certainly isn't one.
+     */
+    nss_SetError(NSS_ERROR_INVALID_ARENA);
+    return PR_FAILURE;
+  }
+
+  rv = nssPointerTracker_verify(&arena_pointer_tracker, arena);
+  if( PR_SUCCESS != rv ) {
+    nss_SetError(NSS_ERROR_INVALID_ARENA);
+    return PR_FAILURE;
+  }
+
+  return PR_SUCCESS;
+}
+#endif /* DEBUG */
+
+#ifdef ARENA_DESTRUCTOR_LIST
+
+struct arena_destructor_node {
+  struct arena_destructor_node *next;
+  struct arena_destructor_node *prev;
+  void (*destructor)(void *argument);
+  void *arg;
+};
+
+/*
+ * nssArena_registerDestructor
+ *
+ * This routine stores a pointer to a callback and an arbitrary
+ * pointer-sized argument in the arena, at the current point in
+ * the mark stack.  If the arena is destroyed, or an "earlier"
+ * mark is released, then this destructor will be called at that
+ * time.  Note that the destructor will be called with the arena
+ * locked, which means the destructor may free memory in that
+ * arena, but it may not allocate or cause to be allocated any
+ * memory.  This callback facility was included to support our
+ * debug-version pointer-tracker feature; overuse runs counter to
+ * the the original intent of arenas.  This routine returns a 
+ * PRStatus value; if successful, it will return PR_SUCCESS.  If 
+ * unsuccessful, it will set an error on the error stack and 
+ * return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssArena_registerDestructor
+(
+  NSSArena *arena,
+  void (*destructor)(void *argument),
+  void *arg
+)
+{
+  struct arena_destructor_node *it;
+
+#ifdef NSSDEBUG
+  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+    return PR_FAILURE;
+  }
+#endif /* NSSDEBUG */
+  
+  it = nss_ZNEW(arena, struct arena_destructor_node);
+  if( (struct arena_destructor_node *)NULL == it ) {
+    return PR_FAILURE;
+  }
+
+  it->prev = arena->last_destructor;
+  arena->last_destructor->next = it;
+  arena->last_destructor = it;
+  it->destructor = destructor;
+  it->arg = arg;
+
+  if( (nssArenaMark *)NULL != arena->last_mark ) {
+    arena->last_mark->prev_destructor = it->prev;
+    arena->last_mark->next_destructor = it->next;
+  }
+
+  return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssArena_deregisterDestructor
+(
+  NSSArena *arena,
+  void (*destructor)(void *argument),
+  void *arg
+)
+{
+  struct arena_destructor_node *it;
+
+#ifdef NSSDEBUG
+  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+    return PR_FAILURE;
+  }
+#endif /* NSSDEBUG */
+
+  for( it = arena->first_destructor; it; it = it->next ) {
+    if( (it->destructor == destructor) && (it->arg == arg) ) {
+      break;
+    }
+  }
+
+  if( (struct arena_destructor_node *)NULL == it ) {
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+  }
+
+  if( it == arena->first_destructor ) {
+    arena->first_destructor = it->next;
+  }
+
+  if( it == arena->last_destructor ) {
+    arena->last_destructor = it->prev;
+  }
+
+  if( (struct arena_destructor_node *)NULL != it->prev ) {
+    it->prev->next = it->next;
+  }
+
+  if( (struct arena_destructor_node *)NULL != it->next ) {
+    it->next->prev = it->prev;
+  }
+
+  {
+    nssArenaMark *m;
+    for( m = arena->first_mark; m; m = m->next ) {
+      if( m->next_destructor == it ) {
+        m->next_destructor = it->next;
+      }
+      if( m->prev_destructor == it ) {
+        m->prev_destructor = it->prev;
+      }
+    }
+  }
+
+  nss_ZFreeIf(it);
+  return PR_SUCCESS;
+}
+
+static void
+nss_arena_call_destructor_chain
+(
+  struct arena_destructor_node *it
+)
+{
+  for( ; it ; it = it->next ) {
+    (*(it->destructor))(it->arg);
+  }
+}
+
+#endif /* ARENA_DESTRUCTOR_LIST */
+
+/*
+ * NSSArena_Create
+ *
+ * This routine creates a new memory arena.  This routine may return
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The top-level error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSArena upon success
+ */
+
+NSS_IMPLEMENT NSSArena *
+NSSArena_Create
+(
+  void
+)
+{
+  nss_ClearErrorStack();
+  return nssArena_Create();
+}
+
+/*
+ * nssArena_Create
+ *
+ * This routine creates a new memory arena.  This routine may return
+ * NULL upon error, in which case it will have set an error on the 
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSArena upon success
+ */
+
+NSS_IMPLEMENT NSSArena *
+nssArena_Create
+(
+  void
+)
+{
+  NSSArena *rv = (NSSArena *)NULL;
+
+  rv = nss_ZNEW((NSSArena *)NULL, NSSArena);
+  if( (NSSArena *)NULL == rv ) {
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return (NSSArena *)NULL;
+  }
+
+  rv->lock = PR_NewLock();
+  if( (PRLock *)NULL == rv->lock ) {
+    (void)nss_ZFreeIf(rv);
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return (NSSArena *)NULL;
+  }
+
+  /*
+   * Arena sizes.  The current security code has 229 occurrences of
+   * PORT_NewArena.  The default chunksizes specified break down as
+   *
+   *  Size    Mult.   Specified as
+   *   512       1    512
+   *  1024       7    1024
+   *  2048       5    2048
+   *  2048       5    CRMF_DEFAULT_ARENA_SIZE
+   *  2048     190    DER_DEFAULT_CHUNKSIZE
+   *  2048      20    SEC_ASN1_DEFAULT_ARENA_SIZE
+   *  4096       1    4096
+   *
+   * Obviously this "default chunksize" flexibility isn't very 
+   * useful to us, so I'll just pick 2048.
+   */
+
+  PL_InitArenaPool(&rv->pool, "NSS", 2048, sizeof(double));
+
+#ifdef DEBUG
+  {
+    PRStatus st;
+    st = arena_add_pointer(rv);
+    if( PR_SUCCESS != st ) {
+      PL_FinishArenaPool(&rv->pool);
+      PR_DestroyLock(rv->lock);
+      (void)nss_ZFreeIf(rv);
+      return (NSSArena *)NULL;
+    }
+  }
+#endif /* DEBUG */
+
+  return rv;
+}
+
+/*
+ * NSSArena_Destroy
+ *
+ * This routine will destroy the specified arena, freeing all memory
+ * allocated from it.  This routine returns a PRStatus value; if 
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * create an error stack and return PR_FAILURE.
+ *
+ * The top-level error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure
+ */
+
+NSS_IMPLEMENT PRStatus
+NSSArena_Destroy
+(
+  NSSArena *arena
+)
+{
+  nss_ClearErrorStack();
+
+#ifdef DEBUG
+  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+    return PR_FAILURE;
+  }
+#endif /* DEBUG */
+
+  return nssArena_Destroy(arena);
+}
+
+/*
+ * nssArena_Destroy
+ *
+ * This routine will destroy the specified arena, freeing all memory
+ * allocated from it.  This routine returns a PRStatus value; if 
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * set an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssArena_Destroy
+(
+  NSSArena *arena
+)
+{
+  PRLock *lock;
+
+#ifdef NSSDEBUG
+  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+    return PR_FAILURE;
+  }
+#endif /* NSSDEBUG */
+
+  if( (PRLock *)NULL == arena->lock ) {
+    /* Just got destroyed */
+    nss_SetError(NSS_ERROR_INVALID_ARENA);
+    return PR_FAILURE;
+  }
+  PR_Lock(arena->lock);
+  
+#ifdef DEBUG
+  if( PR_SUCCESS != arena_remove_pointer(arena) ) {
+    PR_Unlock(arena->lock);
+    return PR_FAILURE;
+  }
+#endif /* DEBUG */
+
+#ifdef ARENA_DESTRUCTOR_LIST
+  /* Note that the arena is locked at this time */
+  nss_arena_call_destructor_chain(arena->first_destructor);
+#endif /* ARENA_DESTRUCTOR_LIST */
+
+  PL_FinishArenaPool(&arena->pool);
+  lock = arena->lock;
+  arena->lock = (PRLock *)NULL;
+  PR_Unlock(lock);
+  PR_DestroyLock(lock);
+  (void)nss_ZFreeIf(arena);
+  return PR_SUCCESS;
+}
+
+static void *nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size);
+
+/*
+ * nssArena_Mark
+ *
+ * This routine "marks" the current state of an arena.  Space
+ * allocated after the arena has been marked can be freed by
+ * releasing the arena back to the mark with nssArena_Release,
+ * or committed by calling nssArena_Unmark.  When successful, 
+ * this routine returns a valid nssArenaMark pointer.  This 
+ * routine may return NULL upon error, in which case it will 
+ * have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  NULL upon failure
+ *  An nssArenaMark pointer upon success
+ */
+
+NSS_IMPLEMENT nssArenaMark *
+nssArena_Mark
+(
+  NSSArena *arena
+)
+{
+  nssArenaMark *rv;
+  void *p;
+
+#ifdef NSSDEBUG
+  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+    return (nssArenaMark *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  if( (PRLock *)NULL == arena->lock ) {
+    /* Just got destroyed */
+    nss_SetError(NSS_ERROR_INVALID_ARENA);
+    return (nssArenaMark *)NULL;
+  }
+  PR_Lock(arena->lock);
+
+#ifdef ARENA_THREADMARK
+  if( (PRThread *)NULL == arena->marking_thread ) {
+    /* Unmarked.  Store our thread ID */
+    arena->marking_thread = PR_GetCurrentThread();
+    /* This call never fails. */
+  } else {
+    /* Marked.  Verify it's the current thread */
+    if( PR_GetCurrentThread() != arena->marking_thread ) {
+      PR_Unlock(arena->lock);
+      nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
+      return (nssArenaMark *)NULL;
+    }
+  }
+#endif /* ARENA_THREADMARK */
+
+  p = PL_ARENA_MARK(&arena->pool);
+  /* No error possible */
+
+  /* Do this after the mark */
+  rv = (nssArenaMark *)nss_zalloc_arena_locked(arena, sizeof(nssArenaMark));
+  if( (nssArenaMark *)NULL == rv ) {
+    PR_Unlock(arena->lock);
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return (nssArenaMark *)NULL;
+  }
+
+#ifdef ARENA_THREADMARK
+  if ( (nssArenaMark *)NULL == arena->first_mark) {
+    arena->first_mark = rv;
+    arena->last_mark = rv;
+  } else {
+    arena->last_mark->next = rv;
+    arena->last_mark = rv;
+  }
+#endif /* ARENA_THREADMARK */
+
+  rv->mark = p;
+  rv->magic = MARK_MAGIC;
+
+#ifdef ARENA_DESTRUCTOR_LIST
+  rv->prev_destructor = arena->last_destructor;
+#endif /* ARENA_DESTRUCTOR_LIST */
+
+  PR_Unlock(arena->lock);
+
+  return rv;
+}
+
+/*
+ * nss_arena_unmark_release
+ *
+ * This static routine implements the routines nssArena_Release
+ * ans nssArena_Unmark, which are almost identical.
+ */
+
+static PRStatus
+nss_arena_unmark_release
+(
+  NSSArena *arena,
+  nssArenaMark *arenaMark,
+  PRBool release
+)
+{
+  void *inner_mark;
+
+#ifdef NSSDEBUG
+  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+    return PR_FAILURE;
+  }
+#endif /* NSSDEBUG */
+
+  if( MARK_MAGIC != arenaMark->magic ) {
+    nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
+    return PR_FAILURE;
+  }
+
+  if( (PRLock *)NULL == arena->lock ) {
+    /* Just got destroyed */
+    nss_SetError(NSS_ERROR_INVALID_ARENA);
+    return PR_FAILURE;
+  }
+  PR_Lock(arena->lock);
+
+#ifdef ARENA_THREADMARK
+  if( (PRThread *)NULL != arena->marking_thread ) {
+    if( PR_GetCurrentThread() != arena->marking_thread ) {
+      PR_Unlock(arena->lock);
+      nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
+      return PR_FAILURE;
+    }
+  }
+#endif /* ARENA_THREADMARK */
+
+  if( MARK_MAGIC != arenaMark->magic ) {
+    /* Just got released */
+    PR_Unlock(arena->lock);
+    nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
+    return PR_FAILURE;
+  }
+
+  arenaMark->magic = 0;
+  inner_mark = arenaMark->mark;
+
+#ifdef ARENA_THREADMARK
+  {
+    nssArenaMark **pMark = &arena->first_mark;
+    nssArenaMark *rest;
+    nssArenaMark *last = (nssArenaMark *)NULL;
+
+    /* Find this mark */
+    while( *pMark != arenaMark ) {
+      last = *pMark;
+      pMark = &(*pMark)->next;
+    }
+
+    /* Remember the pointer, then zero it */
+    rest = (*pMark)->next;
+    *pMark = (nssArenaMark *)NULL;
+
+    arena->last_mark = last;
+
+    /* Invalidate any later marks being implicitly released */
+    for( ; (nssArenaMark *)NULL != rest; rest = rest->next ) {
+      rest->magic = 0;
+    }
+
+    /* If we just got rid of the first mark, clear the thread ID */
+    if( (nssArenaMark *)NULL == arena->first_mark ) {
+      arena->marking_thread = (PRThread *)NULL;
+    }
+  }
+#endif /* ARENA_THREADMARK */
+
+  if( release ) {
+#ifdef ARENA_DESTRUCTOR_LIST
+    if( (struct arena_destructor_node *)NULL != arenaMark->prev_destructor ) {
+      arenaMark->prev_destructor->next = (struct arena_destructor_node *)NULL;
+    }
+    arena->last_destructor = arenaMark->prev_destructor;
+
+    /* Note that the arena is locked at this time */
+    nss_arena_call_destructor_chain(arenaMark->next_destructor);
+#endif /* ARENA_DESTRUCTOR_LIST */
+
+    PR_ARENA_RELEASE(&arena->pool, inner_mark);
+    /* No error return */
+  }
+
+  PR_Unlock(arena->lock);
+  return PR_SUCCESS;
+}
+
+/*
+ * nssArena_Release
+ *
+ * This routine invalidates and releases all memory allocated from
+ * the specified arena after the point at which the specified mark
+ * was obtained.  This routine returns a PRStatus value; if successful,
+ * it will return PR_SUCCESS.  If unsuccessful, it will set an error
+ * on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_INVALID_ARENA_MARK
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssArena_Release
+(
+  NSSArena *arena,
+  nssArenaMark *arenaMark
+)
+{
+  return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);
+}
+
+/*
+ * nssArena_Unmark
+ *
+ * This routine "commits" the indicated mark and any marks after
+ * it, making them unreleasable.  Note that any earlier marks can
+ * still be released, and such a release will invalidate these
+ * later unmarked regions.  If an arena is to be safely shared by
+ * more than one thread, all marks must be either released or
+ * unmarked.  This routine returns a PRStatus value; if successful,
+ * it will return PR_SUCCESS.  If unsuccessful, it will set an error
+ * on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_INVALID_ARENA_MARK
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssArena_Unmark
+(
+  NSSArena *arena,
+  nssArenaMark *arenaMark
+)
+{
+  return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);
+}
+
+/*
+ * We prefix this header to all allocated blocks.  It is a multiple
+ * of the alignment size.  Note that this usage of a header may make
+ * purify spew bogus warnings about "potentially leaked blocks" of
+ * memory; if that gets too annoying we can add in a pointer to the
+ * header in the header itself.  There's not a lot of safety here;
+ * maybe we should add a magic value?
+ */
+struct pointer_header {
+  NSSArena *arena;
+  PRUint32 size;
+};
+
+static void *
+nss_zalloc_arena_locked
+(
+  NSSArena *arena,
+  PRUint32 size
+)
+{
+  void *p;
+  void *rv;
+  struct pointer_header *h;
+  PRUint32 my_size = size + sizeof(struct pointer_header);
+  PR_ARENA_ALLOCATE(p, &arena->pool, my_size);
+  if( (void *)NULL == p ) {
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return (void *)NULL;
+  }
+  /* 
+   * Do this before we unlock.  This way if the user is using
+   * an arena in one thread while destroying it in another, he'll
+   * fault/FMR in his code, not ours.
+   */
+  h = (struct pointer_header *)p;
+  h->arena = arena;
+  h->size = size;
+  rv = (void *)((char *)h + sizeof(struct pointer_header));
+  (void)nsslibc_memset(rv, 0, size);
+  return rv;
+}
+
+/*
+ * nss_ZAlloc
+ *
+ * This routine allocates and zeroes a section of memory of the 
+ * size, and returns to the caller a pointer to that memory.  If
+ * the optional arena argument is non-null, the memory will be
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in
+ * which case it will have set an error upon the error stack.  The
+ * value specified for size may be zero; in which case a valid 
+ * zero-length block of memory will be allocated.  This block may
+ * be expanded by calling nss_ZRealloc.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the new segment of zeroed memory
+ */
+
+NSS_IMPLEMENT void *
+nss_ZAlloc
+(
+  NSSArena *arenaOpt,
+  PRUint32 size
+)
+{
+  struct pointer_header *h;
+  PRUint32 my_size = size + sizeof(struct pointer_header);
+
+  if( my_size < sizeof(struct pointer_header) ) {
+    /* Wrapped */
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return (void *)NULL;
+  }
+
+  if( (NSSArena *)NULL == arenaOpt ) {
+    /* Heap allocation, no locking required. */
+    h = (struct pointer_header *)PR_Calloc(1, my_size);
+    if( (struct pointer_header *)NULL == h ) {
+      nss_SetError(NSS_ERROR_NO_MEMORY);
+      return (void *)NULL;
+    }
+
+    h->arena = (NSSArena *)NULL;
+    h->size = size;
+    /* We used calloc: it's already zeroed */
+
+    return (void *)((char *)h + sizeof(struct pointer_header));
+  } else {
+    void *rv;
+    /* Arena allocation */
+#ifdef NSSDEBUG
+    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
+      return (void *)NULL;
+    }
+#endif /* NSSDEBUG */
+
+    if( (PRLock *)NULL == arenaOpt->lock ) {
+      /* Just got destroyed */
+      nss_SetError(NSS_ERROR_INVALID_ARENA);
+      return (void *)NULL;
+    }
+    PR_Lock(arenaOpt->lock);
+
+#ifdef ARENA_THREADMARK
+    if( (PRThread *)NULL != arenaOpt->marking_thread ) {
+      if( PR_GetCurrentThread() != arenaOpt->marking_thread ) {
+        nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
+        PR_Unlock(arenaOpt->lock);
+        return (void *)NULL;
+      }
+    }
+#endif /* ARENA_THREADMARK */
+
+    rv = nss_zalloc_arena_locked(arenaOpt, size);
+
+    PR_Unlock(arenaOpt->lock);
+    return rv;
+  }
+  /*NOTREACHED*/
+}
+
+/*
+ * nss_ZFreeIf
+ *
+ * If the specified pointer is non-null, then the region of memory 
+ * to which it points -- which must have been allocated with 
+ * nss_ZAlloc -- will be zeroed and released.  This routine 
+ * returns a PRStatus value; if successful, it will return PR_SUCCESS.
+ * If unsuccessful, it will set an error on the error stack and return 
+ * PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nss_ZFreeIf
+(
+  void *pointer
+)
+{
+  struct pointer_header *h;
+
+  if( (void *)NULL == pointer ) {
+    return PR_SUCCESS;
+  }
+
+  h = (struct pointer_header *)((char *)pointer
+    - sizeof(struct pointer_header));
+
+  /* Check any magic here */
+
+  if( (NSSArena *)NULL == h->arena ) {
+    /* Heap */
+    (void)nsslibc_memset(pointer, 0, h->size);
+    PR_Free(h);
+    return PR_SUCCESS;
+  } else {
+    /* Arena */
+#ifdef NSSDEBUG
+    if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {
+      return PR_FAILURE;
+    }
+#endif /* NSSDEBUG */
+
+    if( (PRLock *)NULL == h->arena->lock ) {
+      /* Just got destroyed.. so this pointer is invalid */
+      nss_SetError(NSS_ERROR_INVALID_POINTER);
+      return PR_FAILURE;
+    }
+    PR_Lock(h->arena->lock);
+
+    (void)nsslibc_memset(pointer, 0, h->size);
+
+    /* No way to "free" it within an NSPR arena. */
+
+    PR_Unlock(h->arena->lock);
+    return PR_SUCCESS;
+  }
+  /*NOTREACHED*/
+}
+
+/*
+ * nss_ZRealloc
+ *
+ * This routine reallocates a block of memory obtained by calling
+ * nss_ZAlloc or nss_ZRealloc.  The portion of memory 
+ * between the new and old sizes -- which is either being newly
+ * obtained or released -- is in either case zeroed.  This routine 
+ * may return NULL upon failure, in which case it will have placed 
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the replacement segment of memory
+ */
+
+NSS_EXTERN void *
+nss_ZRealloc
+(
+  void *pointer,
+  PRUint32 newSize
+)
+{
+  struct pointer_header *h, *new_h;
+  PRUint32 my_newSize = newSize + sizeof(struct pointer_header);
+  void *rv;
+
+  if( my_newSize < sizeof(struct pointer_header) ) {
+    /* Wrapped */
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return (void *)NULL;
+  }
+
+  if( (void *)NULL == pointer ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return (void *)NULL;
+  }
+
+  h = (struct pointer_header *)((char *)pointer
+    - sizeof(struct pointer_header));
+
+  /* Check any magic here */
+
+  if( newSize == h->size ) {
+    /* saves thrashing */
+    return pointer;
+  }
+
+  if( (NSSArena *)NULL == h->arena ) {
+    /* Heap */
+    new_h = (struct pointer_header *)PR_Calloc(1, my_newSize);
+    if( (struct pointer_header *)NULL == new_h ) {
+      nss_SetError(NSS_ERROR_NO_MEMORY);
+      return (void *)NULL;
+    }
+
+    new_h->arena = (NSSArena *)NULL;
+    new_h->size = newSize;
+    rv = (void *)((char *)new_h + sizeof(struct pointer_header));
+
+    if( newSize > h->size ) {
+      (void)nsslibc_memcpy(rv, pointer, h->size);
+      (void)nsslibc_memset(&((char *)rv)[ h->size ], 
+                           0, (newSize - h->size));
+    } else {
+      (void)nsslibc_memcpy(rv, pointer, newSize);
+    }
+
+    (void)nsslibc_memset(pointer, 0, h->size);
+    h->size = 0;
+    PR_Free(h);
+
+    return rv;
+  } else {
+    void *p;
+    /* Arena */
+#ifdef NSSDEBUG
+    if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {
+      return (void *)NULL;
+    }
+#endif /* NSSDEBUG */
+
+    if( (PRLock *)NULL == h->arena->lock ) {
+      /* Just got destroyed.. so this pointer is invalid */
+      nss_SetError(NSS_ERROR_INVALID_POINTER);
+      return (void *)NULL;
+    }
+    PR_Lock(h->arena->lock);
+
+#ifdef ARENA_THREADMARK
+    if( (PRThread *)NULL != h->arena->marking_thread ) {
+      if( PR_GetCurrentThread() != h->arena->marking_thread ) {
+        PR_Unlock(h->arena->lock);
+        nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
+        return (void *)NULL;
+      }
+    }
+#endif /* ARENA_THREADMARK */
+
+    if( newSize < h->size ) {
+      /*
+       * We have no general way of returning memory to the arena
+       * (mark/release doesn't work because things may have been
+       * allocated after this object), so the memory is gone
+       * anyway.  We might as well just return the same pointer to
+       * the user, saying "yeah, uh-hunh, you can only use less of
+       * it now."  We'll zero the leftover part, of course.  And
+       * in fact we might as well *not* adjust h->size-- this way,
+       * if the user reallocs back up to something not greater than
+       * the original size, then voila, there's the memory!  This
+       * way a thrash big/small/big/small doesn't burn up the arena.
+       */
+      char *extra = &((char *)pointer)[ newSize ];
+      (void)nsslibc_memset(extra, 0, (h->size - newSize));
+      PR_Unlock(h->arena->lock);
+      return pointer;
+    }
+
+    PR_ARENA_ALLOCATE(p, &h->arena->pool, my_newSize);
+    if( (void *)NULL == p ) {
+      PR_Unlock(h->arena->lock);
+      nss_SetError(NSS_ERROR_NO_MEMORY);
+      return (void *)NULL;
+    }
+
+    new_h = (struct pointer_header *)p;
+    new_h->arena = h->arena;
+    new_h->size = newSize;
+    rv = (void *)((char *)new_h + sizeof(struct pointer_header));
+    if (rv != pointer) {
+	(void)nsslibc_memcpy(rv, pointer, h->size);
+	(void)nsslibc_memset(pointer, 0, h->size);
+    }
+    (void)nsslibc_memset(&((char *)rv)[ h->size ], 0, (newSize - h->size));
+    h->arena = (NSSArena *)NULL;
+    h->size = 0;
+    PR_Unlock(new_h->arena->lock);
+    return rv;
+  }
+  /*NOTREACHED*/
+}
+
+PRStatus 
+nssArena_Shutdown(void)
+{
+  PRStatus rv = PR_SUCCESS;
+#ifdef DEBUG
+  rv = nssPointerTracker_finalize(&arena_pointer_tracker);
+#endif
+  return rv;
+}
diff --git a/mozilla/security/nss/lib/base/base.h b/mozilla/security/nss/lib/base/base.h
new file mode 100644
index 0000000..01be186
--- /dev/null
+++ b/mozilla/security/nss/lib/base/base.h
@@ -0,0 +1,1430 @@
+/* ***** 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 ***** */
+
+#ifndef BASE_H
+#define BASE_H
+
+#ifdef DEBUG
+static const char BASE_CVS_ID[] = "@(#) $RCSfile: base.h,v $ $Revision: 1.20 $ $Date: 2008/05/10 01:03:14 $";
+#endif /* DEBUG */
+
+/*
+ * base.h
+ *
+ * This header file contains basic prototypes and preprocessor 
+ * definitions used throughout nss but not available publicly.
+ */
+
+#ifndef BASET_H
+#include "baset.h"
+#endif /* BASET_H */
+
+#ifndef NSSBASE_H
+#include "nssbase.h"
+#endif /* NSSBASE_H */
+
+#include "plhash.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSArena
+ *
+ * The nonpublic methods relating to this type are:
+ *
+ *  nssArena_Create  -- constructor
+ *  nssArena_Destroy
+ *  nssArena_Mark
+ *  nssArena_Release
+ *  nssArena_Unmark
+ *
+ *  nss_ZAlloc
+ *  nss_ZFreeIf
+ *  nss_ZRealloc
+ *
+ * Additionally, there are some preprocessor macros:
+ *
+ *  nss_ZNEW
+ *  nss_ZNEWARRAY
+ *
+ * In debug builds, the following calls are available:
+ *
+ *  nssArena_verifyPointer
+ *  nssArena_registerDestructor
+ *  nssArena_deregisterDestructor
+ *
+ * The following preprocessor macro is also always available:
+ *
+ *  nssArena_VERIFYPOINTER
+ *
+ * A constant PLHashAllocOps structure is available for users
+ * of the NSPL PLHashTable routines.
+ *
+ *  nssArenaHashAllocOps
+ */
+
+/*
+ * nssArena_Create
+ *
+ * This routine creates a new memory arena.  This routine may return
+ * NULL upon error, in which case it will have set an error on the 
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSArena upon success
+ */
+
+/*
+ * XXX fgmr
+ * Arenas can be named upon creation; this is mostly of use when
+ * debugging.  Should we expose that here, allowing an optional
+ * "const char *name" argument?  Should the public version of this
+ * call (NSSArena_Create) have it too?
+ */
+
+NSS_EXTERN NSSArena *
+nssArena_Create
+(
+  void
+);
+
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * nssArena_Destroy
+ *
+ * This routine will destroy the specified arena, freeing all memory
+ * allocated from it.  This routine returns a PRStatus value; if 
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * set an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_EXTERN PRStatus
+nssArena_Destroy
+(
+  NSSArena *arena
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+
+/*
+ * nssArena_Mark
+ *
+ * This routine "marks" the current state of an arena.  Space
+ * allocated after the arena has been marked can be freed by
+ * releasing the arena back to the mark with nssArena_Release,
+ * or committed by calling nssArena_Unmark.  When successful, 
+ * this routine returns a valid nssArenaMark pointer.  This 
+ * routine may return NULL upon error, in which case it will 
+ * have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  NULL upon failure
+ *  An nssArenaMark pointer upon success
+ */
+
+NSS_EXTERN nssArenaMark *
+nssArena_Mark
+(
+  NSSArena *arena
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD;
+
+/*
+ * nssArena_Release
+ *
+ * This routine invalidates and releases all memory allocated from
+ * the specified arena after the point at which the specified mark
+ * was obtained.  This routine returns a PRStatus value; if successful,
+ * it will return PR_SUCCESS.  If unsuccessful, it will set an error
+ * on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_INVALID_ARENA_MARK
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_EXTERN PRStatus
+nssArena_Release
+(
+  NSSArena *arena,
+  nssArenaMark *arenaMark
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_INVALID_ARENA_MARK;
+
+/*
+ * nssArena_Unmark
+ *
+ * This routine "commits" the indicated mark and any marks after
+ * it, making them unreleasable.  Note that any earlier marks can
+ * still be released, and such a release will invalidate these
+ * later unmarked regions.  If an arena is to be safely shared by
+ * more than one thread, all marks must be either released or
+ * unmarked.  This routine returns a PRStatus value; if successful,
+ * it will return PR_SUCCESS.  If unsuccessful, it will set an error
+ * on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_INVALID_ARENA_MARK
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_EXTERN PRStatus
+nssArena_Unmark
+(
+  NSSArena *arena,
+  nssArenaMark *arenaMark
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_INVALID_ARENA_MARK;
+extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD;
+
+#ifdef ARENA_DESTRUCTOR_LIST
+
+/*
+ * nssArena_registerDestructor
+ *
+ * This routine stores a pointer to a callback and an arbitrary
+ * pointer-sized argument in the arena, at the current point in
+ * the mark stack.  If the arena is destroyed, or an "earlier"
+ * mark is released, then this destructor will be called at that
+ * time.  Note that the destructor will be called with the arena
+ * locked, which means the destructor may free memory in that
+ * arena, but it may not allocate or cause to be allocated any
+ * memory.  This callback facility was included to support our
+ * debug-version pointer-tracker feature; overuse runs counter to
+ * the the original intent of arenas.  This routine returns a 
+ * PRStatus value; if successful, it will return PR_SUCCESS.  If 
+ * unsuccessful, it will set an error on the error stack and 
+ * return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_EXTERN PRStatus
+nssArena_registerDestructor
+(
+  NSSArena *arena,
+  void (*destructor)(void *argument),
+  void *arg
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * nssArena_deregisterDestructor
+ *
+ * This routine will remove the first destructor in the specified
+ * arena which has the specified destructor and argument values.
+ * The destructor will not be called.  This routine returns a
+ * PRStatus value; if successful, it will return PR_SUCCESS.  If 
+ * unsuccessful, it will set an error on the error stack and 
+ * return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NOT_FOUND
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_EXTERN PRStatus
+nssArena_deregisterDestructor
+(
+  NSSArena *arena,
+  void (*destructor)(void *argument),
+  void *arg
+);
+
+extern const NSSError NSS_ERROR_INVALID_ITEM;
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+#endif /* ARENA_DESTRUCTOR_LIST */
+
+/*
+ * nss_ZAlloc
+ *
+ * This routine allocates and zeroes a section of memory of the 
+ * size, and returns to the caller a pointer to that memory.  If
+ * the optional arena argument is non-null, the memory will be
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in
+ * which case it will have set an error upon the error stack.  The
+ * value specified for size may be zero; in which case a valid 
+ * zero-length block of memory will be allocated.  This block may
+ * be expanded by calling nss_ZRealloc.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the new segment of zeroed memory
+ */
+
+NSS_EXTERN void *
+nss_ZAlloc
+(
+  NSSArena *arenaOpt,
+  PRUint32 size
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD;
+
+/*
+ * nss_ZFreeIf
+ *
+ * If the specified pointer is non-null, then the region of memory 
+ * to which it points -- which must have been allocated with 
+ * nss_ZAlloc -- will be zeroed and released.  This routine 
+ * returns a PRStatus value; if successful, it will return PR_SUCCESS.
+ * If unsuccessful, it will set an error on the error stack and return 
+ * PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_EXTERN PRStatus
+nss_ZFreeIf
+(
+  void *pointer
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+
+/*
+ * nss_ZRealloc
+ *
+ * This routine reallocates a block of memory obtained by calling
+ * nss_ZAlloc or nss_ZRealloc.  The portion of memory 
+ * between the new and old sizes -- which is either being newly
+ * obtained or released -- is in either case zeroed.  This routine 
+ * may return NULL upon failure, in which case it will have placed 
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the replacement segment of memory
+ */
+
+NSS_EXTERN void *
+nss_ZRealloc
+(
+  void *pointer,
+  PRUint32 newSize
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD;
+
+/*
+ * nss_ZNEW
+ *
+ * This preprocessor macro will allocate memory for a new object
+ * of the specified type with nss_ZAlloc, and will cast the
+ * return value appropriately.  If the optional arena argument is 
+ * non-null, the memory will be obtained from that arena; otherwise, 
+ * the memory will be obtained from the heap.  This routine may 
+ * return NULL upon error, in which case it will have set an error 
+ * upon the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the new segment of zeroed memory
+ */
+
+/* The following line exceeds 72 characters, but emacs screws up if I split it. */
+#define nss_ZNEW(arenaOpt, type) ((type *)nss_ZAlloc((arenaOpt), sizeof(type)))
+
+/*
+ * nss_ZNEWARRAY
+ *
+ * This preprocessor macro will allocate memory for an array of
+ * new objects, and will cast the return value appropriately.
+ * If the optional arena argument is non-null, the memory will 
+ * be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon 
+ * error, in which case it will have set an error upon the error 
+ * stack.  The array size may be specified as zero.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the new segment of zeroed memory
+ */
+
+/* The following line exceeds 72 characters, but emacs screws up if I split it. */
+#define nss_ZNEWARRAY(arenaOpt, type, quantity) ((type *)nss_ZAlloc((arenaOpt), sizeof(type) * (quantity)))
+
+/*
+ * nss_ZREALLOCARRAY
+ *
+ * This preprocessor macro will reallocate memory for an array of
+ * new objects, and will cast the return value appropriately.
+ * This routine may return NULL upon error, in which case it will 
+ *  have set an error upon the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the replacement segment of memory
+ */
+#define nss_ZREALLOCARRAY(p, type, quantity) ((type *)nss_ZRealloc((p), sizeof(type) * (quantity)))
+
+/*
+ * nssArena_verifyPointer
+ *
+ * This method is only present in debug builds.
+ *
+ * If the specified pointer is a valid pointer to an NSSArena object,
+ * this routine will return PR_SUCCESS.  Otherwise, it will put an
+ * error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *
+ * Return value:
+ *  PR_SUCCESS if the pointer is valid
+ *  PR_FAILURE if it isn't
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssArena_verifyPointer
+(
+  const NSSArena *arena
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+#endif /* DEBUG */
+
+/*
+ * nssArena_VERIFYPOINTER
+ *
+ * This macro is always available.  In debug builds it will call
+ * nssArena_verifyPointer; in non-debug builds, it will merely
+ * check that the pointer is not null.  Note that in non-debug
+ * builds it cannot place an error on the error stack.
+ *
+ * Return value:
+ *  PR_SUCCESS if the pointer is valid
+ *  PR_FAILURE if it isn't
+ */
+
+#ifdef DEBUG
+#define nssArena_VERIFYPOINTER(p) nssArena_verifyPointer(p)
+#else /* DEBUG */
+/* The following line exceeds 72 characters, but emacs screws up if I split it. */
+#define nssArena_VERIFYPOINTER(p) (((NSSArena *)NULL == (p))?PR_FAILURE:PR_SUCCESS)
+#endif /* DEBUG */
+
+/*
+ * Private function to be called by NSS_Shutdown to cleanup nssArena 
+ * bookkeeping.
+ */
+extern PRStatus
+nssArena_Shutdown(void);
+
+/*
+ * nssArenaHashAllocOps
+ *
+ * This constant structure contains allocation callbacks designed for
+ * use with the NSPL routine PL_NewHashTable.  For example:
+ *
+ *  NSSArena *hashTableArena = nssArena_Create();
+ *  PLHashTable *t = PL_NewHashTable(n, hasher, key_compare, 
+ *    value_compare, nssArenaHashAllocOps, hashTableArena);
+ */
+
+NSS_EXTERN_DATA PLHashAllocOps nssArenaHashAllocOps;
+
+/*
+ * The error stack
+ *
+ * The nonpublic methods relating to the error stack are:
+ *
+ *  nss_SetError
+ *  nss_ClearErrorStack
+ */
+
+/*
+ * nss_SetError
+ *
+ * This routine places a new error code on the top of the calling 
+ * thread's error stack.  Calling this routine wiht an error code
+ * of zero will clear the error stack.
+ */
+
+NSS_EXTERN void
+nss_SetError
+(
+  PRUint32 error
+);
+
+/*
+ * nss_ClearErrorStack
+ *
+ * This routine clears the calling thread's error stack.
+ */
+
+NSS_EXTERN void
+nss_ClearErrorStack
+(
+  void
+);
+
+/*
+ * nss_DestroyErrorStack
+ *
+ * This routine frees the calling thread's error stack.
+ */
+
+NSS_EXTERN void
+nss_DestroyErrorStack
+(
+  void
+);
+
+/*
+ * NSSItem
+ *
+ * nssItem_Create
+ * nssItem_Duplicate
+ * nssItem_Equal
+ */
+
+NSS_EXTERN NSSItem *
+nssItem_Create
+(
+  NSSArena *arenaOpt,
+  NSSItem *rvOpt,
+  PRUint32 length,
+  const void *data
+);
+
+NSS_EXTERN void
+nssItem_Destroy
+(
+  NSSItem *item
+);
+
+NSS_EXTERN NSSItem *
+nssItem_Duplicate
+(
+  NSSItem *obj,
+  NSSArena *arenaOpt,
+  NSSItem *rvOpt
+);
+
+NSS_EXTERN PRBool
+nssItem_Equal
+(
+  const NSSItem *one,
+  const NSSItem *two,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSUTF8
+ *
+ *  nssUTF8_CaseIgnoreMatch
+ *  nssUTF8_Duplicate
+ *  nssUTF8_Size
+ *  nssUTF8_Length
+ *  nssUTF8_CopyIntoFixedBuffer
+ */
+
+/*
+ * nssUTF8_CaseIgnoreMatch
+ * 
+ * Returns true if the two UTF8-encoded strings pointed to by the 
+ * two specified NSSUTF8 pointers differ only in typcase.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_TRUE if the strings match, ignoring case
+ *  PR_FALSE if they don't
+ *  PR_FALSE upon error
+ */
+
+NSS_EXTERN PRBool
+nssUTF8_CaseIgnoreMatch
+(
+  const NSSUTF8 *a,
+  const NSSUTF8 *b,
+  PRStatus *statusOpt
+);
+
+/*
+ * nssUTF8_Duplicate
+ *
+ * This routine duplicates the UTF8-encoded string pointed to by the
+ * specified NSSUTF8 pointer.  If the optional arenaOpt argument is
+ * not null, the memory required will be obtained from that arena;
+ * otherwise, the memory required will be obtained from the heap.
+ * A pointer to the new string will be returned.  In case of error,
+ * an error will be placed on the error stack and NULL will be 
+ * returned.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssUTF8_Duplicate
+(
+  const NSSUTF8 *s,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssUTF8_PrintableMatch
+ *
+ * Returns true if the two Printable strings pointed to by the 
+ * two specified NSSUTF8 pointers match when compared with the 
+ * rules for Printable String (leading and trailing spaces are 
+ * disregarded, extents of whitespace match irregardless of length, 
+ * and case is not significant), then PR_TRUE will be returned.
+ * Otherwise, PR_FALSE will be returned.  Upon failure, PR_FALSE
+ * will be returned.  If the optional statusOpt argument is not
+ * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that
+ * location.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_TRUE if the strings match, ignoring case
+ *  PR_FALSE if they don't
+ *  PR_FALSE upon error
+ */
+
+NSS_EXTERN PRBool
+nssUTF8_PrintableMatch
+(
+  const NSSUTF8 *a,
+  const NSSUTF8 *b,
+  PRStatus *statusOpt
+);
+
+/*
+ * nssUTF8_Size
+ *
+ * This routine returns the length in bytes (including the terminating
+ * null) of the UTF8-encoded string pointed to by the specified
+ * NSSUTF8 pointer.  Zero is returned on error.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_VALUE_TOO_LARGE
+ *
+ * Return value:
+ *  nonzero size of the string
+ *  0 on error
+ */
+
+NSS_EXTERN PRUint32
+nssUTF8_Size
+(
+  const NSSUTF8 *s,
+  PRStatus *statusOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+extern const NSSError NSS_ERROR_VALUE_TOO_LARGE;
+
+/*
+ * nssUTF8_Length
+ *
+ * This routine returns the length in characters (not including the
+ * terminating null) of the UTF8-encoded string pointed to by the
+ * specified NSSUTF8 pointer.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_VALUE_TOO_LARGE
+ *  NSS_ERROR_INVALID_STRING
+ *
+ * Return value:
+ *  length of the string (which may be zero)
+ *  0 on error
+ */
+
+NSS_EXTERN PRUint32
+nssUTF8_Length
+(
+  const NSSUTF8 *s,
+  PRStatus *statusOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+extern const NSSError NSS_ERROR_VALUE_TOO_LARGE;
+extern const NSSError NSS_ERROR_INVALID_STRING;
+
+/*
+ * nssUTF8_Create
+ *
+ * This routine creates a UTF8 string from a string in some other
+ * format.  Some types of string may include embedded null characters,
+ * so for them the length parameter must be used.  For string types
+ * that are null-terminated, the length parameter is optional; if it
+ * is zero, it will be ignored.  If the optional arena argument is
+ * non-null, the memory used for the new string will be obtained from
+ * that arena, otherwise it will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have
+ * placed an error on the error stack.
+ *
+ * The error may be one of the following:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_UNSUPPORTED_TYPE
+ *
+ * Return value:
+ *  NULL upon error
+ *  A non-null pointer to a new UTF8 string otherwise
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssUTF8_Create
+(
+  NSSArena *arenaOpt,
+  nssStringType type,
+  const void *inputString,
+  PRUint32 size /* in bytes, not characters */
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+extern const NSSError NSS_ERROR_UNSUPPORTED_TYPE;
+
+NSS_EXTERN NSSItem *
+nssUTF8_GetEncoding
+(
+  NSSArena *arenaOpt,
+  NSSItem *rvOpt,
+  nssStringType type,
+  NSSUTF8 *string
+);
+
+/*
+ * nssUTF8_CopyIntoFixedBuffer
+ *
+ * This will copy a UTF8 string into a fixed-length buffer, making 
+ * sure that the all characters are valid.  Any remaining space will
+ * be padded with the specified ASCII character, typically either 
+ * null or space.
+ *
+ * Blah, blah, blah.
+ */
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
+
+NSS_EXTERN PRStatus
+nssUTF8_CopyIntoFixedBuffer
+(
+  NSSUTF8 *string,
+  char *buffer,
+  PRUint32 bufferSize,
+  char pad
+);
+
+/*
+ * nssUTF8_Equal
+ *
+ */
+
+NSS_EXTERN PRBool
+nssUTF8_Equal
+(
+  const NSSUTF8 *a,
+  const NSSUTF8 *b,
+  PRStatus *statusOpt
+);
+
+/*
+ * nssList
+ *
+ * The goal is to provide a simple, optionally threadsafe, linked list
+ * class.  Since NSS did not seem to use the circularity of PRCList
+ * much before, this provides a list that appears to be a linear,
+ * NULL-terminated list.
+ */
+
+/*
+ * nssList_Create
+ *
+ * If threadsafe is true, the list will be locked during modifications
+ * and traversals.
+ */
+NSS_EXTERN nssList *
+nssList_Create
+(
+  NSSArena *arenaOpt,
+  PRBool threadSafe
+);
+
+/*
+ * nssList_Destroy
+ */
+NSS_EXTERN PRStatus
+nssList_Destroy
+(
+  nssList *list
+);
+
+NSS_EXTERN void
+nssList_Clear
+(
+  nssList *list, 
+  nssListElementDestructorFunc destructor
+);
+
+/*
+ * nssList_SetCompareFunction
+ *
+ * By default, two list elements will be compared by comparing their
+ * data pointers.  By setting this function, the user can control
+ * how elements are compared.
+ */
+NSS_EXTERN void
+nssList_SetCompareFunction
+(
+  nssList *list, 
+  nssListCompareFunc compareFunc
+);
+
+/*
+ * nssList_SetSortFunction
+ *
+ * Sort function to use for an ordered list.
+ */
+NSS_EXTERN void
+nssList_SetSortFunction
+(
+  nssList *list, 
+  nssListSortFunc sortFunc
+);
+
+/*
+ * nssList_Add
+ */
+NSS_EXTERN PRStatus
+nssList_Add
+(
+  nssList *list, 
+  void *data
+);
+
+/*
+ * nssList_AddUnique
+ *
+ * This will use the compare function to see if the element is already
+ * in the list.
+ */
+NSS_EXTERN PRStatus
+nssList_AddUnique
+(
+  nssList *list, 
+  void *data
+);
+
+/*
+ * nssList_Remove
+ *
+ * Uses the compare function to locate the element and remove it.
+ */
+NSS_EXTERN PRStatus
+nssList_Remove(nssList *list, void *data);
+
+/*
+ * nssList_Get
+ *
+ * Uses the compare function to locate an element.  Also serves as
+ * nssList_Exists.
+ */
+NSS_EXTERN void *
+nssList_Get
+(
+  nssList *list, 
+  void *data
+);
+
+/*
+ * nssList_Count
+ */
+NSS_EXTERN PRUint32
+nssList_Count
+(
+  nssList *list
+);
+
+/*
+ * nssList_GetArray
+ *
+ * Fill rvArray, up to maxElements, with elements in the list.  The
+ * array is NULL-terminated, so its allocated size must be maxElements + 1.
+ */
+NSS_EXTERN PRStatus
+nssList_GetArray
+(
+  nssList *list, 
+  void **rvArray, 
+  PRUint32 maxElements
+);
+
+/*
+ * nssList_CreateIterator
+ *
+ * Create an iterator for list traversal.
+ */
+NSS_EXTERN nssListIterator *
+nssList_CreateIterator
+(
+  nssList *list
+);
+
+NSS_EXTERN nssList *
+nssList_Clone
+(
+  nssList *list
+);
+
+/*
+ * nssListIterator_Destroy
+ */
+NSS_EXTERN void
+nssListIterator_Destroy
+(
+  nssListIterator *iter
+);
+
+/*
+ * nssListIterator_Start
+ *
+ * Begin a list iteration.  After this call, if the list is threadSafe,
+ * the list is *locked*.
+ */
+NSS_EXTERN void *
+nssListIterator_Start
+(
+  nssListIterator *iter
+);
+
+/*
+ * nssListIterator_Next
+ *
+ * Continue a list iteration.
+ */
+NSS_EXTERN void *
+nssListIterator_Next
+(
+  nssListIterator *iter
+);
+
+/*
+ * nssListIterator_Finish
+ *
+ * Complete a list iteration.  This *must* be called in order for the
+ * lock to be released.
+ */
+NSS_EXTERN PRStatus
+nssListIterator_Finish
+(
+  nssListIterator *iter
+);
+
+/*
+ * nssHash
+ *
+ *  nssHash_Create
+ *  nssHash_Destroy
+ *  nssHash_Add
+ *  nssHash_Remove
+ *  nssHash_Count
+ *  nssHash_Exists
+ *  nssHash_Lookup
+ *  nssHash_Iterate
+ */
+
+/*
+ * nssHash_Create
+ *
+ */
+
+NSS_EXTERN nssHash *
+nssHash_Create
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets,
+  PLHashFunction keyHash,
+  PLHashComparator keyCompare,
+  PLHashComparator valueCompare
+);
+
+NSS_EXTERN nssHash *
+nssHash_CreatePointer
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+);
+
+NSS_EXTERN nssHash *
+nssHash_CreateString
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+);
+
+NSS_EXTERN nssHash *
+nssHash_CreateItem
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+);
+
+/*
+ * nssHash_Destroy
+ *
+ */
+NSS_EXTERN void
+nssHash_Destroy
+(
+  nssHash *hash
+);
+
+/*
+ * nssHash_Add
+ *
+ */
+
+extern const NSSError NSS_ERROR_HASH_COLLISION;
+
+NSS_EXTERN PRStatus
+nssHash_Add
+(
+  nssHash *hash,
+  const void *key,
+  const void *value
+);
+
+/*
+ * nssHash_Remove
+ *
+ */
+NSS_EXTERN void
+nssHash_Remove
+(
+  nssHash *hash,
+  const void *it
+);
+
+/*
+ * nssHash_Count
+ *
+ */
+NSS_EXTERN PRUint32
+nssHash_Count
+(
+  nssHash *hash
+);
+
+/*
+ * nssHash_Exists
+ *
+ */
+NSS_EXTERN PRBool
+nssHash_Exists
+(
+  nssHash *hash,
+  const void *it
+);
+
+/*
+ * nssHash_Lookup
+ *
+ */
+NSS_EXTERN void *
+nssHash_Lookup
+(
+  nssHash *hash,
+  const void *it
+);
+
+/*
+ * nssHash_Iterate
+ *
+ */
+NSS_EXTERN void
+nssHash_Iterate
+(
+  nssHash *hash,
+  nssHashIterator fcn,
+  void *closure
+);
+
+
+/*
+ * nssPointerTracker
+ *
+ * This type and these methods are only present in debug builds.
+ * 
+ * The nonpublic methods relating to this type are:
+ *
+ *  nssPointerTracker_initialize
+ *  nssPointerTracker_finalize
+ *  nssPointerTracker_add
+ *  nssPointerTracker_remove
+ *  nssPointerTracker_verify
+ */
+
+/*
+ * nssPointerTracker_initialize
+ *
+ * This method is only present in debug builds.
+ * 
+ * This routine initializes an nssPointerTracker object.  Note that
+ * the object must have been declared *static* to guarantee that it
+ * is in a zeroed state initially.  This routine is idempotent, and
+ * may even be safely called by multiple threads simultaneously with 
+ * the same argument.  This routine returns a PRStatus value; if 
+ * successful, it will return PR_SUCCESS.  On failure it will set an 
+ * error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssPointerTracker_initialize
+(
+  nssPointerTracker *tracker
+);
+
+extern const NSSError NSS_ERROR_NO_MEMORY;
+#endif /* DEBUG */
+
+/*
+ * nssPointerTracker_finalize
+ *
+ * This method is only present in debug builds.
+ * 
+ * This routine returns the nssPointerTracker object to the pre-
+ * initialized state, releasing all resources used by the object.
+ * It will *NOT* destroy the objects being tracked by the pointer
+ * (should any remain), and therefore cannot be used to "sweep up"
+ * remaining objects.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCES.  On failure it will set an
+ * error on the error stack and return PR_FAILURE.  If any objects
+ * remain in the tracker when it is finalized, that will be treated
+ * as an error.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_TRACKER_NOT_EMPTY
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssPointerTracker_finalize
+(
+  nssPointerTracker *tracker
+);
+
+extern const NSSError NSS_ERROR_TRACKER_NOT_EMPTY;
+#endif /* DEBUG */
+
+/*
+ * nssPointerTracker_add
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine adds the specified pointer to the nssPointerTracker
+ * object.  It should be called in constructor objects to register
+ * new valid objects.  The nssPointerTracker is threadsafe, but this
+ * call is not idempotent.  This routine returns a PRStatus value;
+ * if successful it will return PR_SUCCESS.  On failure it will set
+ * an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_TRACKER_NOT_INITIALIZED
+ *  NSS_ERROR_DUPLICATE_POINTER
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssPointerTracker_add
+(
+  nssPointerTracker *tracker,
+  const void *pointer
+);
+
+extern const NSSError NSS_ERROR_NO_MEMORY;
+extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED;
+extern const NSSError NSS_ERROR_DUPLICATE_POINTER;
+#endif /* DEBUG */
+
+/*
+ * nssPointerTracker_remove
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine removes the specified pointer from the 
+ * nssPointerTracker object.  It does not call any destructor for the
+ * object; rather, this should be called from the object's destructor.
+ * The nssPointerTracker is threadsafe, but this call is not 
+ * idempotent.  This routine returns a PRStatus value; if successful 
+ * it will return PR_SUCCESS.  On failure it will set an error on the 
+ * error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_TRACKER_NOT_INITIALIZED
+ *  NSS_ERROR_POINTER_NOT_REGISTERED
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssPointerTracker_remove
+(
+  nssPointerTracker *tracker,
+  const void *pointer
+);
+
+extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED;
+extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED;
+#endif /* DEBUG */
+
+/*
+ * nssPointerTracker_verify
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine verifies that the specified pointer has been registered
+ * with the nssPointerTracker object.  The nssPointerTracker object is
+ * threadsafe, and this call may be safely called from multiple threads
+ * simultaneously with the same arguments.  This routine returns a
+ * PRStatus value; if the pointer is registered this will return 
+ * PR_SUCCESS.  Otherwise it will set an error on the error stack and 
+ * return PR_FAILURE.  Although the error is suitable for leaving on 
+ * the stack, callers may wish to augment the information available by 
+ * placing a more type-specific error on the stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_POINTER_NOT_REGISTERED
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILRUE
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssPointerTracker_verify
+(
+  nssPointerTracker *tracker,
+  const void *pointer
+);
+
+extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED;
+#endif /* DEBUG */
+
+/*
+ * libc
+ *
+ * nsslibc_memcpy
+ * nsslibc_memset
+ * nsslibc_offsetof
+ */
+
+/*
+ * nsslibc_memcpy
+ *
+ * Errors:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  NULL on error
+ *  The destination pointer on success
+ */
+
+NSS_EXTERN void *
+nsslibc_memcpy
+(
+  void *dest,
+  const void *source,
+  PRUint32 n
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+
+/*
+ * nsslibc_memset
+ *
+ * Errors:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  NULL on error
+ *  The destination pointer on success
+ */
+
+NSS_EXTERN void *
+nsslibc_memset
+(
+  void *dest,
+  PRUint8 byte,
+  PRUint32 n
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+
+/*
+ * nsslibc_memequal
+ *
+ * Errors:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_TRUE if they match
+ *  PR_FALSE if they don't
+ *  PR_FALSE upon error
+ */
+
+NSS_EXTERN PRBool
+nsslibc_memequal
+(
+  const void *a,
+  const void *b,
+  PRUint32 len,
+  PRStatus *statusOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+
+#define nsslibc_offsetof(str, memb) ((PRPtrdiff)(&(((str *)0)->memb)))
+
+PR_END_EXTERN_C
+
+#endif /* BASE_H */
diff --git a/mozilla/security/nss/lib/base/baset.h b/mozilla/security/nss/lib/base/baset.h
new file mode 100644
index 0000000..a87887a
--- /dev/null
+++ b/mozilla/security/nss/lib/base/baset.h
@@ -0,0 +1,161 @@
+/* ***** 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 ***** */
+
+#ifndef BASET_H
+#define BASET_H
+
+#ifdef DEBUG
+static const char BASET_CVS_ID[] = "@(#) $RCSfile: baset.h,v $ $Revision: 1.8 $ $Date: 2005/01/20 02:25:45 $";
+#endif /* DEBUG */
+
+/*
+ * baset.h
+ *
+ * This file contains definitions for the basic types used throughout
+ * nss but not available publicly.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+#include "plhash.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * nssArenaMark
+ *
+ * This type is used to mark the current state of an NSSArena.
+ */
+
+struct nssArenaMarkStr;
+typedef struct nssArenaMarkStr nssArenaMark;
+
+#ifdef DEBUG
+/*
+ * ARENA_THREADMARK
+ * 
+ * Optionally, this arena implementation can be compiled with some
+ * runtime checking enabled, which will catch the situation where
+ * one thread "marks" the arena, another thread allocates memory,
+ * and then the mark is released.  Usually this is a surprise to
+ * the second thread, and this leads to weird runtime errors.
+ * Define ARENA_THREADMARK to catch these cases; we define it for all
+ * (internal and external) debug builds.
+ */
+#define ARENA_THREADMARK
+
+/*
+ * ARENA_DESTRUCTOR_LIST
+ *
+ * Unfortunately, our pointer-tracker facility, used in debug
+ * builds to agressively fight invalid pointers, requries that
+ * pointers be deregistered when objects are destroyed.  This
+ * conflicts with the standard arena usage where "memory-only"
+ * objects (that don't hold onto resources outside the arena)
+ * can be allocated in an arena, and never destroyed other than
+ * when the arena is destroyed.  Therefore we have added a
+ * destructor-registratio facility to our arenas.  This was not
+ * a simple decision, since we're getting ever-further away from
+ * the original arena philosophy.  However, it was felt that
+ * adding this in debug builds wouldn't be so bad; as it would
+ * discourage them from being used for "serious" purposes.
+ * This facility requires ARENA_THREADMARK to be defined.
+ */
+#ifdef ARENA_THREADMARK
+#define ARENA_DESTRUCTOR_LIST
+#endif /* ARENA_THREADMARK */
+
+#endif /* DEBUG */
+
+typedef struct nssListStr nssList;
+typedef struct nssListIteratorStr nssListIterator;
+typedef PRBool (* nssListCompareFunc)(void *a, void *b);
+typedef PRIntn (* nssListSortFunc)(void *a, void *b);
+typedef void (* nssListElementDestructorFunc)(void *el);
+
+typedef struct nssHashStr nssHash;
+typedef void (PR_CALLBACK *nssHashIterator)(const void *key, 
+                                            void *value, 
+                                            void *arg);
+
+/*
+ * nssPointerTracker
+ *
+ * This type is used in debug builds (both external and internal) to
+ * track our object pointers.  Objects of this type must be statically
+ * allocated, which means the structure size must be available to the
+ * compiler.  Therefore we must expose the contents of this structure.
+ * But please don't access elements directly; use the accessors.
+ */
+
+#ifdef DEBUG
+struct nssPointerTrackerStr {
+  PRCallOnceType once;
+  PZLock *lock;
+  PLHashTable *table;
+};
+typedef struct nssPointerTrackerStr nssPointerTracker;
+#endif /* DEBUG */
+
+/*
+ * nssStringType
+ *
+ * There are several types of strings in the real world.  We try to
+ * use only UTF8 and avoid the rest, but that's not always possible.
+ * So we have a couple converter routines to go to and from the other
+ * string types.  We have to be able to specify those string types,
+ * so we have this enumeration.
+ */
+
+enum nssStringTypeEnum {
+  nssStringType_DirectoryString,
+  nssStringType_TeletexString, /* Not "teletext" with trailing 't' */
+  nssStringType_PrintableString,
+  nssStringType_UniversalString,
+  nssStringType_BMPString,
+  nssStringType_UTF8String,
+  nssStringType_PHGString,
+  nssStringType_GeneralString,
+
+  nssStringType_Unknown = -1
+};
+typedef enum nssStringTypeEnum nssStringType;
+
+PR_END_EXTERN_C
+
+#endif /* BASET_H */
diff --git a/mozilla/security/nss/lib/base/error.c b/mozilla/security/nss/lib/base/error.c
new file mode 100644
index 0000000..a0a3297
--- /dev/null
+++ b/mozilla/security/nss/lib/base/error.c
@@ -0,0 +1,305 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: error.c,v $ $Revision: 1.9 $ $Date: 2008/05/17 03:44:39 $";
+#endif /* DEBUG */
+
+/*
+ * error.c
+ *
+ * This file contains the code implementing the per-thread error 
+ * stacks upon which most NSS routines report their errors.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+#include <limits.h> /* for UINT_MAX */
+#include <string.h> /* for memmove */
+
+#define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */
+
+/*
+ * The stack itself has a header, and a sequence of integers.
+ * The header records the amount of space (as measured in stack
+ * slots) already allocated for the stack, and the count of the
+ * number of records currently being used.
+ */
+
+struct stack_header_str {
+  PRUint16 space;
+  PRUint16 count;
+};
+
+struct error_stack_str {
+  struct stack_header_str header;
+  PRInt32 stack[1];
+};
+typedef struct error_stack_str error_stack;
+
+/*
+ * error_stack_index
+ *
+ * Thread-private data must be indexed.  This is that index.
+ * See PR_NewThreadPrivateIndex for more information.
+ *
+ * Thread-private data indexes are in the range [0, 127].
+ */
+
+#define INVALID_TPD_INDEX UINT_MAX
+static PRUintn error_stack_index = INVALID_TPD_INDEX;
+
+/*
+ * call_once
+ *
+ * The thread-private index must be obtained (once!) at runtime.
+ * This block is used for that one-time call.
+ */
+
+static PRCallOnceType error_call_once;
+
+/*
+ * error_once_function
+ *
+ * This is the once-called callback.
+ */
+static PRStatus
+error_once_function ( void)
+{
+  return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
+}
+
+/*
+ * error_get_my_stack
+ *
+ * This routine returns the calling thread's error stack, creating
+ * it if necessary.  It may return NULL upon error, which implicitly
+ * means that it ran out of memory.
+ */
+
+static error_stack *
+error_get_my_stack ( void)
+{
+  PRStatus st;
+  error_stack *rv;
+  PRUintn new_size;
+  PRUint32 new_bytes;
+  error_stack *new_stack;
+
+  if( INVALID_TPD_INDEX == error_stack_index ) {
+    st = PR_CallOnce(&error_call_once, error_once_function);
+    if( PR_SUCCESS != st ) {
+      return (error_stack *)NULL;
+    }
+  }
+
+  rv = (error_stack *)PR_GetThreadPrivate(error_stack_index);
+  if( (error_stack *)NULL == rv ) {
+    /* Doesn't exist; create one */
+    new_size = 16;
+  } else if( rv->header.count == rv->header.space  &&
+             rv->header.count  < NSS_MAX_ERROR_STACK_COUNT ) {
+    /* Too small, expand it */
+    new_size = PR_MIN( rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT);
+  } else {
+    /* Okay, return it */
+    return rv;
+  }
+
+  new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack);
+  /* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */
+  new_stack = PR_Calloc(1, new_bytes);
+  
+  if( (error_stack *)NULL != new_stack ) {
+    if( (error_stack *)NULL != rv ) {
+	(void)nsslibc_memcpy(new_stack,rv,rv->header.space);
+    }
+    new_stack->header.space = new_size;
+  }
+
+  /* Set the value, whether or not the allocation worked */
+  PR_SetThreadPrivate(error_stack_index, new_stack);
+  return new_stack;
+}
+
+/*
+ * The error stack
+ *
+ * The public methods relating to the error stack are:
+ *
+ *  NSS_GetError
+ *  NSS_GetErrorStack
+ *
+ * The nonpublic methods relating to the error stack are:
+ *
+ *  nss_SetError
+ *  nss_ClearErrorStack
+ *
+ */
+
+/*
+ * NSS_GetError
+ *
+ * This routine returns the highest-level (most general) error set
+ * by the most recent NSS library routine called by the same thread
+ * calling this routine.
+ *
+ * This routine cannot fail.  However, it may return zero, which
+ * indicates that the previous NSS library call did not set an error.
+ *
+ * Return value:
+ *  0 if no error has been set
+ *  A nonzero error number
+ */
+
+NSS_IMPLEMENT PRInt32
+NSS_GetError ( void)
+{
+  error_stack *es = error_get_my_stack();
+
+  if( (error_stack *)NULL == es ) {
+    return NSS_ERROR_NO_MEMORY; /* Good guess! */
+  }
+
+  if( 0 == es->header.count ) {
+    return 0;
+  }
+
+  return es->stack[ es->header.count-1 ];
+}
+
+/*
+ * NSS_GetErrorStack
+ *
+ * This routine returns a pointer to an array of integers, containing
+ * the entire sequence or "stack" of errors set by the most recent NSS
+ * library routine called by the same thread calling this routine.
+ * NOTE: the caller DOES NOT OWN the memory pointed to by the return
+ * value.  The pointer will remain valid until the calling thread
+ * calls another NSS routine.  The lowest-level (most specific) error 
+ * is first in the array, and the highest-level is last.  The array is
+ * zero-terminated.  This routine may return NULL upon error; this
+ * indicates a low-memory situation.
+ *
+ * Return value:
+ *  NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
+ *  A NON-caller-owned pointer to an array of integers
+ */
+
+NSS_IMPLEMENT PRInt32 *
+NSS_GetErrorStack ( void)
+{
+  error_stack *es = error_get_my_stack();
+
+  if( (error_stack *)NULL == es ) {
+    return (PRInt32 *)NULL;
+  }
+
+  /* Make sure it's terminated */
+  es->stack[ es->header.count ] = 0;
+
+  return es->stack;
+}
+
+/*
+ * nss_SetError
+ *
+ * This routine places a new error code on the top of the calling 
+ * thread's error stack.  Calling this routine wiht an error code
+ * of zero will clear the error stack.
+ */
+
+NSS_IMPLEMENT void
+nss_SetError ( PRUint32 error)
+{
+  error_stack *es;
+
+  if( 0 == error ) {
+    nss_ClearErrorStack();
+    return;
+  }
+
+  es = error_get_my_stack();
+  if( (error_stack *)NULL == es ) {
+    /* Oh, well. */
+    return;
+  }
+
+  if (es->header.count < es->header.space) {
+    es->stack[ es->header.count++ ] = error;
+  } else {
+    memmove(es->stack, es->stack + 1, 
+		(es->header.space - 1) * (sizeof es->stack[0]));
+    es->stack[ es->header.space - 1 ] = error;
+  }
+  return;
+}
+
+/*
+ * nss_ClearErrorStack
+ *
+ * This routine clears the calling thread's error stack.
+ */
+
+NSS_IMPLEMENT void
+nss_ClearErrorStack ( void)
+{
+  error_stack *es = error_get_my_stack();
+  if( (error_stack *)NULL == es ) {
+    /* Oh, well. */
+    return;
+  }
+
+  es->header.count = 0;
+  es->stack[0] = 0;
+  return;
+}
+
+/*
+ * nss_DestroyErrorStack
+ *
+ * This routine frees the calling thread's error stack.
+ */
+
+NSS_IMPLEMENT void
+nss_DestroyErrorStack ( void)
+{
+  if( INVALID_TPD_INDEX != error_stack_index ) {
+    PR_SetThreadPrivate(error_stack_index, NULL);
+  }
+  return;
+}
diff --git a/mozilla/security/nss/lib/base/errorval.c b/mozilla/security/nss/lib/base/errorval.c
new file mode 100644
index 0000000..11767eb
--- /dev/null
+++ b/mozilla/security/nss/lib/base/errorval.c
@@ -0,0 +1,98 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: errorval.c,v $ $Revision: 1.12 $ $Date: 2007/08/09 22:36:15 $";
+#endif /* DEBUG */
+
+/*
+ * errorval.c
+ *
+ * This file contains the actual error constants used in NSS.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+const NSSError NSS_ERROR_NO_ERROR                       =  0;
+const NSSError NSS_ERROR_INTERNAL_ERROR                 =  1;
+const NSSError NSS_ERROR_NO_MEMORY                      =  2;
+const NSSError NSS_ERROR_INVALID_POINTER                =  3;
+const NSSError NSS_ERROR_INVALID_ARENA                  =  4;
+const NSSError NSS_ERROR_INVALID_ARENA_MARK             =  5;
+const NSSError NSS_ERROR_DUPLICATE_POINTER              =  6;
+const NSSError NSS_ERROR_POINTER_NOT_REGISTERED         =  7;
+const NSSError NSS_ERROR_TRACKER_NOT_EMPTY              =  8;
+const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED        =  9;
+const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD = 10;
+const NSSError NSS_ERROR_VALUE_TOO_LARGE                = 11;
+const NSSError NSS_ERROR_UNSUPPORTED_TYPE               = 12;
+const NSSError NSS_ERROR_BUFFER_TOO_SHORT               = 13;
+const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT           = 14;
+const NSSError NSS_ERROR_INVALID_BASE64                 = 15;
+const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT           = 16;
+const NSSError NSS_ERROR_INVALID_ITEM                   = 17;
+const NSSError NSS_ERROR_INVALID_STRING                 = 18;
+const NSSError NSS_ERROR_INVALID_ASN1ENCODER            = 19;
+const NSSError NSS_ERROR_INVALID_ASN1DECODER            = 20;
+
+const NSSError NSS_ERROR_INVALID_BER                    = 21;
+const NSSError NSS_ERROR_INVALID_ATAV                   = 22;
+const NSSError NSS_ERROR_INVALID_ARGUMENT               = 23;
+const NSSError NSS_ERROR_INVALID_UTF8                   = 24;
+const NSSError NSS_ERROR_INVALID_NSSOID                 = 25;
+const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE              = 26;
+
+const NSSError NSS_ERROR_NOT_FOUND                      = 27;
+
+const NSSError NSS_ERROR_INVALID_PASSWORD               = 28;
+const NSSError NSS_ERROR_USER_CANCELED                  = 29;
+
+const NSSError NSS_ERROR_MAXIMUM_FOUND                  = 30;
+
+const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND   = 31;
+
+const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE           = 32;
+
+const NSSError NSS_ERROR_HASH_COLLISION                 = 33;
+const NSSError NSS_ERROR_DEVICE_ERROR                   = 34;
+const NSSError NSS_ERROR_INVALID_CERTIFICATE            = 35;
+const NSSError NSS_ERROR_BUSY                           = 36;
+const NSSError NSS_ERROR_ALREADY_INITIALIZED            = 37;
+
+const NSSError NSS_ERROR_PKCS11                         = 38;
+
diff --git a/mozilla/security/nss/lib/base/hash.c b/mozilla/security/nss/lib/base/hash.c
new file mode 100644
index 0000000..389c296
--- /dev/null
+++ b/mozilla/security/nss/lib/base/hash.c
@@ -0,0 +1,409 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: hash.c,v $ $Revision: 1.11 $ $Date: 2008/02/03 01:59:48 $";
+#endif /* DEBUG */
+
+/*
+ * hash.c
+ *
+ * This is merely a couple wrappers around NSPR's PLHashTable, using
+ * the identity hash and arena-aware allocators.
+ * This is a copy of ckfw/hash.c, with modifications to use NSS types
+ * (not Cryptoki types).  Would like for this to be a single implementation,
+ * but doesn't seem like it will work.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#include "prbit.h"
+
+/*
+ * nssHash
+ *
+ *  nssHash_Create
+ *  nssHash_Destroy
+ *  nssHash_Add
+ *  nssHash_Remove
+ *  nssHash_Count
+ *  nssHash_Exists
+ *  nssHash_Lookup
+ *  nssHash_Iterate
+ */
+
+struct nssHashStr {
+  NSSArena *arena;
+  PRBool i_alloced_arena;
+  PRLock *mutex;
+
+  /*
+   * The invariant that mutex protects is:
+   *   The count accurately reflects the hashtable state.
+   */
+
+  PLHashTable *plHashTable;
+  PRUint32 count;
+};
+
+static PLHashNumber
+nss_identity_hash
+(
+  const void *key
+)
+{
+  PRUint32 i = (PRUint32)key;
+  PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32));
+  return (PLHashNumber)i;
+}
+
+static PLHashNumber
+nss_item_hash
+(
+  const void *key
+)
+{
+  unsigned int i;
+  PLHashNumber h;
+  NSSItem *it = (NSSItem *)key;
+  h = 0;
+  for (i=0; i<it->size; i++)
+    h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)it->data)[i];
+  return h;
+}
+
+static int
+nss_compare_items(const void *v1, const void *v2)
+{
+  PRStatus ignore;
+  return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore);
+}
+
+/*
+ * nssHash_create
+ *
+ */
+NSS_IMPLEMENT nssHash *
+nssHash_Create
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets,
+  PLHashFunction keyHash,
+  PLHashComparator keyCompare,
+  PLHashComparator valueCompare
+)
+{
+  nssHash *rv;
+  NSSArena *arena;
+  PRBool i_alloced;
+
+#ifdef NSSDEBUG
+  if( arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return (nssHash *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  if (arenaOpt) {
+    arena = arenaOpt;
+    i_alloced = PR_FALSE;
+  } else {
+    arena = nssArena_Create();
+    i_alloced = PR_TRUE;
+  }
+
+  rv = nss_ZNEW(arena, nssHash);
+  if( (nssHash *)NULL == rv ) {
+    goto loser;
+  }
+
+  rv->mutex = PZ_NewLock(nssILockOther);
+  if( (PZLock *)NULL == rv->mutex ) {
+    goto loser;
+  }
+
+  rv->plHashTable = PL_NewHashTable(numBuckets, 
+                                    keyHash, keyCompare, valueCompare,
+                                    &nssArenaHashAllocOps, arena);
+  if( (PLHashTable *)NULL == rv->plHashTable ) {
+    (void)PZ_DestroyLock(rv->mutex);
+    goto loser;
+  }
+
+  rv->count = 0;
+  rv->arena = arena;
+  rv->i_alloced_arena = i_alloced;
+
+  return rv;
+loser:
+  (void)nss_ZFreeIf(rv);
+  return (nssHash *)NULL;
+}
+
+/*
+ * nssHash_CreatePointer
+ *
+ */
+NSS_IMPLEMENT nssHash *
+nssHash_CreatePointer
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+)
+{
+  return nssHash_Create(arenaOpt, numBuckets, 
+                        nss_identity_hash, PL_CompareValues, PL_CompareValues);
+}
+
+/*
+ * nssHash_CreateString
+ *
+ */
+NSS_IMPLEMENT nssHash *
+nssHash_CreateString
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+)
+{
+  return nssHash_Create(arenaOpt, numBuckets, 
+                        PL_HashString, PL_CompareStrings, PL_CompareStrings);
+}
+
+/*
+ * nssHash_CreateItem
+ *
+ */
+NSS_IMPLEMENT nssHash *
+nssHash_CreateItem
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+)
+{
+  return nssHash_Create(arenaOpt, numBuckets, 
+                        nss_item_hash, nss_compare_items, PL_CompareValues);
+}
+
+/*
+ * nssHash_Destroy
+ *
+ */
+NSS_IMPLEMENT void
+nssHash_Destroy
+(
+  nssHash *hash
+)
+{
+  (void)PZ_DestroyLock(hash->mutex);
+  PL_HashTableDestroy(hash->plHashTable);
+  if (hash->i_alloced_arena) {
+    nssArena_Destroy(hash->arena);
+  } else {
+    nss_ZFreeIf(hash);
+  }
+}
+
+/*
+ * nssHash_Add
+ *
+ */
+NSS_IMPLEMENT PRStatus
+nssHash_Add
+(
+  nssHash *hash,
+  const void *key,
+  const void *value
+)
+{
+  PRStatus error = PR_FAILURE;
+  PLHashEntry *he;
+
+  PZ_Lock(hash->mutex);
+  
+  he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
+  if( (PLHashEntry *)NULL == he ) {
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+  } else if (he->value != value) {
+    nss_SetError(NSS_ERROR_HASH_COLLISION);
+  } else {
+    hash->count++;
+    error = PR_SUCCESS;
+  }
+
+  (void)PZ_Unlock(hash->mutex);
+
+  return error;
+}
+
+/*
+ * nssHash_Remove
+ *
+ */
+NSS_IMPLEMENT void
+nssHash_Remove
+(
+  nssHash *hash,
+  const void *it
+)
+{
+  PRBool found;
+
+  PZ_Lock(hash->mutex);
+
+  found = PL_HashTableRemove(hash->plHashTable, it);
+  if( found ) {
+    hash->count--;
+  }
+
+  (void)PZ_Unlock(hash->mutex);
+  return;
+}
+
+/*
+ * nssHash_Count
+ *
+ */
+NSS_IMPLEMENT PRUint32
+nssHash_Count
+(
+  nssHash *hash
+)
+{
+  PRUint32 count;
+
+  PZ_Lock(hash->mutex);
+
+  count = hash->count;
+
+  (void)PZ_Unlock(hash->mutex);
+
+  return count;
+}
+
+/*
+ * nssHash_Exists
+ *
+ */
+NSS_IMPLEMENT PRBool
+nssHash_Exists
+(
+  nssHash *hash,
+  const void *it
+)
+{
+  void *value;
+
+  PZ_Lock(hash->mutex);
+
+  value = PL_HashTableLookup(hash->plHashTable, it);
+
+  (void)PZ_Unlock(hash->mutex);
+
+  if( (void *)NULL == value ) {
+    return PR_FALSE;
+  } else {
+    return PR_TRUE;
+  }
+}
+
+/*
+ * nssHash_Lookup
+ *
+ */
+NSS_IMPLEMENT void *
+nssHash_Lookup
+(
+  nssHash *hash,
+  const void *it
+)
+{
+  void *rv;
+
+  PZ_Lock(hash->mutex);
+
+  rv = PL_HashTableLookup(hash->plHashTable, it);
+
+  (void)PZ_Unlock(hash->mutex);
+
+  return rv;
+}
+
+struct arg_str {
+  nssHashIterator fcn;
+  void *closure;
+};
+
+static PRIntn
+nss_hash_enumerator
+(
+  PLHashEntry *he,
+  PRIntn index,
+  void *arg
+)
+{
+  struct arg_str *as = (struct arg_str *)arg;
+  as->fcn(he->key, he->value, as->closure);
+  return HT_ENUMERATE_NEXT;
+}
+
+/*
+ * nssHash_Iterate
+ *
+ * NOTE that the iteration function will be called with the hashtable locked.
+ */
+NSS_IMPLEMENT void
+nssHash_Iterate
+(
+  nssHash *hash,
+  nssHashIterator fcn,
+  void *closure
+)
+{
+  struct arg_str as;
+  as.fcn = fcn;
+  as.closure = closure;
+
+  PZ_Lock(hash->mutex);
+
+  PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as);
+
+  (void)PZ_Unlock(hash->mutex);
+
+  return;
+}
diff --git a/mozilla/security/nss/lib/base/hashops.c b/mozilla/security/nss/lib/base/hashops.c
new file mode 100644
index 0000000..b1158da
--- /dev/null
+++ b/mozilla/security/nss/lib/base/hashops.c
@@ -0,0 +1,120 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: hashops.c,v $ $Revision: 1.6 $ $Date: 2005/01/20 02:25:45 $";
+#endif /* DEBUG */
+
+/*
+ * hashops.c
+ *
+ * This file includes a set of PLHashAllocOps that use NSSArenas.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+static void * PR_CALLBACK
+nss_arena_hash_alloc_table
+(
+  void *pool,
+  PRSize size
+)
+{
+  NSSArena *arena = (NSSArena *)NULL;
+
+#ifdef NSSDEBUG
+  if( (void *)NULL != arena ) {
+    if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+      return (void *)NULL;
+    }
+  }
+#endif /* NSSDEBUG */
+
+  return nss_ZAlloc(arena, size);
+}
+
+static void PR_CALLBACK
+nss_arena_hash_free_table
+(
+  void *pool, 
+  void *item
+)
+{
+  (void)nss_ZFreeIf(item);
+}
+
+static PLHashEntry * PR_CALLBACK
+nss_arena_hash_alloc_entry
+(
+  void *pool,
+  const void *key
+)
+{
+  NSSArena *arena = NULL;
+
+#ifdef NSSDEBUG
+  if( (void *)NULL != arena ) {
+    if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
+      return (void *)NULL;
+    }
+  }
+#endif /* NSSDEBUG */
+
+  return nss_ZNEW(arena, PLHashEntry);
+}
+
+static void PR_CALLBACK
+nss_arena_hash_free_entry
+(
+  void *pool,
+  PLHashEntry *he,
+  PRUintn flag
+)
+{
+  if( HT_FREE_ENTRY == flag ) {
+    (void)nss_ZFreeIf(he);
+  }
+}
+
+NSS_IMPLEMENT_DATA PLHashAllocOps 
+nssArenaHashAllocOps = {
+  nss_arena_hash_alloc_table,
+  nss_arena_hash_free_table,
+  nss_arena_hash_alloc_entry,
+  nss_arena_hash_free_entry
+};
diff --git a/mozilla/security/nss/lib/base/item.c b/mozilla/security/nss/lib/base/item.c
new file mode 100644
index 0000000..9713f36
--- /dev/null
+++ b/mozilla/security/nss/lib/base/item.c
@@ -0,0 +1,244 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: item.c,v $ $Revision: 1.4 $ $Date: 2005/01/20 02:25:45 $";
+#endif /* DEBUG */
+
+/*
+ * item.c
+ *
+ * This contains some item-manipulation code.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+/*
+ * nssItem_Create
+ *
+ * -- fgmr comments --
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *  NSS_ERROR_INVALID_POINTER
+ *  
+ * Return value:
+ *  A pointer to an NSSItem upon success
+ *  NULL upon failure
+ */
+
+NSS_IMPLEMENT NSSItem *
+nssItem_Create
+(
+  NSSArena *arenaOpt,
+  NSSItem *rvOpt,
+  PRUint32 length,
+  const void *data
+)
+{
+  NSSItem *rv = (NSSItem *)NULL;
+
+#ifdef DEBUG
+  if( (NSSArena *)NULL != arenaOpt ) {
+    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
+      return (NSSItem *)NULL;
+    }
+  }
+
+  if( (const void *)NULL == data ) {
+    if( length > 0 ) {
+      nss_SetError(NSS_ERROR_INVALID_POINTER);
+      return (NSSItem *)NULL;
+    }
+  }
+#endif /* DEBUG */
+
+  if( (NSSItem *)NULL == rvOpt ) {
+    rv = (NSSItem *)nss_ZNEW(arenaOpt, NSSItem);
+    if( (NSSItem *)NULL == rv ) {
+      goto loser;
+    }
+  } else {
+    rv = rvOpt;
+  }
+
+  rv->size = length;
+  rv->data = nss_ZAlloc(arenaOpt, length);
+  if( (void *)NULL == rv->data ) {
+    goto loser;
+  }
+
+  if( length > 0 ) {
+    (void)nsslibc_memcpy(rv->data, data, length);
+  }
+
+  return rv;
+
+ loser:
+  if( rv != rvOpt ) {
+    nss_ZFreeIf(rv);
+  }
+
+  return (NSSItem *)NULL;
+}
+
+NSS_IMPLEMENT void
+nssItem_Destroy
+(
+  NSSItem *item
+)
+{
+  nss_ClearErrorStack();
+
+  nss_ZFreeIf(item->data);
+  nss_ZFreeIf(item);
+
+}
+
+/*
+ * nssItem_Duplicate
+ *
+ * -- fgmr comments --
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
+ *  NSS_ERROR_INVALID_ITEM
+ *  
+ * Return value:
+ *  A pointer to an NSSItem upon success
+ *  NULL upon failure
+ */
+
+NSS_IMPLEMENT NSSItem *
+nssItem_Duplicate
+(
+  NSSItem *obj,
+  NSSArena *arenaOpt,
+  NSSItem *rvOpt
+)
+{
+#ifdef DEBUG
+  if( (NSSArena *)NULL != arenaOpt ) {
+    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
+      return (NSSItem *)NULL;
+    }
+  }
+
+  if( (NSSItem *)NULL == obj ) {
+    nss_SetError(NSS_ERROR_INVALID_ITEM);
+    return (NSSItem *)NULL;
+  }
+#endif /* DEBUG */
+
+  return nssItem_Create(arenaOpt, rvOpt, obj->size, obj->data);
+}
+
+#ifdef DEBUG
+/*
+ * nssItem_verifyPointer
+ *
+ * -- fgmr comments --
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ITEM
+ *
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure
+ */
+
+NSS_IMPLEMENT PRStatus
+nssItem_verifyPointer
+(
+  const NSSItem *item
+)
+{
+  if( ((const NSSItem *)NULL == item) ||
+      (((void *)NULL == item->data) && (item->size > 0)) ) {
+    nss_SetError(NSS_ERROR_INVALID_ITEM);
+    return PR_FAILURE;
+  }
+
+  return PR_SUCCESS;
+}
+#endif /* DEBUG */
+
+/*
+ * nssItem_Equal
+ *
+ * -- fgmr comments --
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ITEM
+ *
+ * Return value:
+ *  PR_TRUE if the items are identical
+ *  PR_FALSE if they aren't
+ *  PR_FALSE upon error
+ */
+
+NSS_IMPLEMENT PRBool
+nssItem_Equal
+(
+  const NSSItem *one,
+  const NSSItem *two,
+  PRStatus *statusOpt
+)
+{
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_SUCCESS;
+  }
+
+  if( ((const NSSItem *)NULL == one) && ((const NSSItem *)NULL == two) ) {
+    return PR_TRUE;
+  }
+
+  if( ((const NSSItem *)NULL == one) || ((const NSSItem *)NULL == two) ) {
+    return PR_FALSE;
+  }
+
+  if( one->size != two->size ) {
+    return PR_FALSE;
+  }
+
+  return nsslibc_memequal(one->data, two->data, one->size, statusOpt);
+}
diff --git a/mozilla/security/nss/lib/base/libc.c b/mozilla/security/nss/lib/base/libc.c
new file mode 100644
index 0000000..14d49fd
--- /dev/null
+++ b/mozilla/security/nss/lib/base/libc.c
@@ -0,0 +1,200 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: libc.c,v $ $Revision: 1.3 $ $Date: 2005/01/20 02:25:45 $";
+#endif /* DEBUG */
+
+/*
+ * libc.c
+ *
+ * This file contains our wrappers/reimplementations for "standard" 
+ * libc functions.  Things like "memcpy."  We add to this as we need 
+ * it.  Oh, and let's keep it in alphabetical order, should it ever 
+ * get large.  Most string/character stuff should be in utf8.c, not 
+ * here.  This file (and maybe utf8.c) should be the only ones in
+ * NSS to include files with angle brackets.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#include <string.h> /* memcpy, memset */
+
+/*
+ * nsslibc_memcpy
+ * nsslibc_memset
+ * nsslibc_offsetof
+ * nsslibc_memequal
+ */
+
+/*
+ * nsslibc_memcpy
+ *
+ * Errors:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  NULL on error
+ *  The destination pointer on success
+ */
+
+NSS_IMPLEMENT void *
+nsslibc_memcpy
+(
+  void *dest,
+  const void *source,
+  PRUint32 n
+)
+{
+#ifdef NSSDEBUG
+  if( ((void *)NULL == dest) || ((const void *)NULL == source) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return (void *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  return memcpy(dest, source, (size_t)n);
+}
+
+/*
+ * nsslibc_memset
+ *
+ * Errors:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  NULL on error
+ *  The destination pointer on success
+ */
+
+NSS_IMPLEMENT void *
+nsslibc_memset
+(
+  void *dest,
+  PRUint8 byte,
+  PRUint32 n
+)
+{
+#ifdef NSSDEBUG
+  if( ((void *)NULL == dest) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return (void *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  return memset(dest, (int)byte, (size_t)n);
+}
+
+/*
+ * nsslibc_memequal
+ *
+ * Errors:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_TRUE if they match
+ *  PR_FALSE if they don't
+ *  PR_FALSE upon error
+ */
+
+NSS_IMPLEMENT PRBool
+nsslibc_memequal
+(
+  const void *a,
+  const void *b,
+  PRUint32 len,
+  PRStatus *statusOpt
+)
+{
+#ifdef NSSDEBUG
+  if( (((void *)NULL == a) || ((void *)NULL == b)) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    if( (PRStatus *)NULL != statusOpt ) {
+      *statusOpt = PR_FAILURE;
+    }
+    return PR_FALSE;
+  }
+#endif /* NSSDEBUG */
+
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_SUCCESS;
+  }
+
+  if( 0 == memcmp(a, b, len) ) {
+    return PR_TRUE;
+  } else {
+    return PR_FALSE;
+  }
+}
+
+/*
+ * nsslibc_memcmp
+ */
+
+NSS_IMPLEMENT PRInt32
+nsslibc_memcmp
+(
+  const void *a,
+  const void *b,
+  PRUint32 len,
+  PRStatus *statusOpt
+)
+{
+  int v;
+
+#ifdef NSSDEBUG
+  if( (((void *)NULL == a) || ((void *)NULL == b)) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    if( (PRStatus *)NULL != statusOpt ) {
+      *statusOpt = PR_FAILURE;
+    }
+    return -2;
+  }
+#endif /* NSSDEBUG */
+
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_SUCCESS;
+  }
+
+  v = memcmp(a, b, len);
+  return (PRInt32)v;
+}
+
+/*
+ * offsetof is a preprocessor definition
+ */
diff --git a/mozilla/security/nss/lib/base/list.c b/mozilla/security/nss/lib/base/list.c
new file mode 100644
index 0000000..19ce8b9
--- /dev/null
+++ b/mozilla/security/nss/lib/base/list.c
@@ -0,0 +1,437 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: list.c,v $ $Revision: 1.20 $ $Date: 2006/09/29 20:13:30 $";
+#endif /* DEBUG */
+
+/*
+ * list.c
+ *
+ * This contains the implementation of NSS's thread-safe linked list.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+struct nssListElementStr {
+    PRCList  link;
+    void    *data;
+};
+
+typedef struct nssListElementStr nssListElement;
+
+struct nssListStr {
+    NSSArena       *arena;
+    PZLock         *lock;
+    nssListElement *head;
+    PRUint32        count;
+    nssListCompareFunc compareFunc;
+    nssListSortFunc    sortFunc;
+    PRBool i_alloced_arena;
+};
+
+struct nssListIteratorStr {
+    PZLock *lock;
+    nssList *list;
+    nssListElement *current;
+};
+
+#define NSSLIST_LOCK_IF(list) \
+    if ((list)->lock) PZ_Lock((list)->lock)
+
+#define NSSLIST_UNLOCK_IF(list) \
+    if ((list)->lock) PZ_Unlock((list)->lock)
+
+static PRBool
+pointer_compare(void *a, void *b)
+{
+    return (PRBool)(a == b);
+}
+
+static nssListElement *
+nsslist_get_matching_element(nssList *list, void *data)
+{
+    PRCList *link;
+    nssListElement *node;
+    node = list->head;
+    if (!node) {
+	return NULL;
+    }
+    link = &node->link;
+    while (node) {
+	/* using a callback slows things down when it's just compare ... */
+	if (list->compareFunc(node->data, data)) {
+	    break;
+	}
+	link = &node->link;
+	if (link == PR_LIST_TAIL(&list->head->link)) {
+	    node = NULL;
+	    break;
+	}
+	node = (nssListElement *)PR_NEXT_LINK(&node->link);
+    }
+    return node;
+}
+
+NSS_IMPLEMENT nssList *
+nssList_Create
+(
+  NSSArena *arenaOpt,
+  PRBool threadSafe
+)
+{
+    NSSArena *arena;
+    nssList *list;
+    PRBool i_alloced;
+    if (arenaOpt) {
+	arena = arenaOpt;
+	i_alloced = PR_FALSE;
+    } else {
+	arena = nssArena_Create();
+	i_alloced = PR_TRUE;
+    }
+    if (!arena) {
+	return (nssList *)NULL;
+    }
+    list = nss_ZNEW(arena, nssList);
+    if (!list) {
+	if (!arenaOpt) {
+	    NSSArena_Destroy(arena);
+	}
+	return (nssList *)NULL;
+    }
+    if (threadSafe) {
+	list->lock = PZ_NewLock(nssILockOther);
+	if (!list->lock) {
+	    if (arenaOpt) {
+		nss_ZFreeIf(list);
+	    } else {
+		NSSArena_Destroy(arena);
+	    }
+	    return (nssList *)NULL;
+	}
+    }
+    list->arena = arena;
+    list->i_alloced_arena = i_alloced;
+    list->compareFunc = pointer_compare;
+    return list;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_Destroy(nssList *list)
+{
+    if (!list->i_alloced_arena) {
+	nssList_Clear(list, NULL);
+    }
+    if (list->lock) {
+	(void)PZ_DestroyLock(list->lock);
+    }
+    if (list->i_alloced_arena) {
+	NSSArena_Destroy(list->arena);
+	list = NULL;
+    }
+    nss_ZFreeIf(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void
+nssList_SetCompareFunction(nssList *list, nssListCompareFunc compareFunc)
+{
+    list->compareFunc = compareFunc;
+}
+
+NSS_IMPLEMENT void
+nssList_SetSortFunction(nssList *list, nssListSortFunc sortFunc)
+{
+    /* XXX if list already has elements, sort them */
+    list->sortFunc = sortFunc;
+}
+
+NSS_IMPLEMENT nssListCompareFunc
+nssList_GetCompareFunction(nssList *list)
+{
+    return list->compareFunc;
+}
+
+NSS_IMPLEMENT void
+nssList_Clear(nssList *list, nssListElementDestructorFunc destructor)
+{
+    PRCList *link;
+    nssListElement *node, *tmp;
+    NSSLIST_LOCK_IF(list);
+    node = list->head;
+    list->head = NULL;
+    while (node && list->count > 0) {
+	if (destructor) (*destructor)(node->data);
+	link = &node->link;
+	tmp = (nssListElement *)PR_NEXT_LINK(link);
+	PR_REMOVE_LINK(link);
+	nss_ZFreeIf(node);
+	node = tmp;
+	--list->count;
+    }
+    NSSLIST_UNLOCK_IF(list);
+}
+
+static PRStatus
+nsslist_add_element(nssList *list, void *data)
+{
+    nssListElement *node = nss_ZNEW(list->arena, nssListElement);
+    if (!node) {
+	return PR_FAILURE;
+    }
+    PR_INIT_CLIST(&node->link);
+    node->data = data;
+    if (list->head) {
+	if (list->sortFunc) {
+	    PRCList *link;
+	    nssListElement *currNode;
+	    currNode = list->head;
+	    /* insert in ordered list */
+	    while (currNode) {
+		link = &currNode->link;
+		if (list->sortFunc(data, currNode->data) <= 0) {
+		    /* new element goes before current node */
+		    PR_INSERT_BEFORE(&node->link, link);
+		    /* reset head if this is first */
+		    if (currNode == list->head) list->head = node;
+		    break;
+		}
+		if (link == PR_LIST_TAIL(&list->head->link)) {
+		    /* reached end of list, append */
+		    PR_INSERT_AFTER(&node->link, link);
+		    break;
+		}
+		currNode = (nssListElement *)PR_NEXT_LINK(&currNode->link);
+	    }
+	} else {
+	    /* not sorting */
+	    PR_APPEND_LINK(&node->link, &list->head->link);
+	}
+    } else {
+	list->head = node;
+    }
+    ++list->count;
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_Add(nssList *list, void *data)
+{
+    PRStatus nssrv;
+    NSSLIST_LOCK_IF(list);
+    nssrv = nsslist_add_element(list, data);
+    NSSLIST_UNLOCK_IF(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_AddUnique(nssList *list, void *data)
+{
+    PRStatus nssrv;
+    nssListElement *node;
+    NSSLIST_LOCK_IF(list);
+    node = nsslist_get_matching_element(list, data);
+    if (node) {
+	/* already in, finish */
+	NSSLIST_UNLOCK_IF(list);
+	return PR_SUCCESS;
+    }
+    nssrv = nsslist_add_element(list, data);
+    NSSLIST_UNLOCK_IF(list);
+    return nssrv;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_Remove(nssList *list, void *data)
+{
+    nssListElement *node;
+    NSSLIST_LOCK_IF(list);
+    node = nsslist_get_matching_element(list, data);
+    if (node) {
+	if (node == list->head) {
+	    list->head = (nssListElement *)PR_NEXT_LINK(&node->link);
+	}
+	PR_REMOVE_LINK(&node->link);
+	nss_ZFreeIf(node);
+	if (--list->count == 0) {
+	    list->head = NULL;
+	}
+    }
+    NSSLIST_UNLOCK_IF(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void *
+nssList_Get(nssList *list, void *data)
+{
+    nssListElement *node;
+    NSSLIST_LOCK_IF(list);
+    node = nsslist_get_matching_element(list, data);
+    NSSLIST_UNLOCK_IF(list);
+    return (node) ? node->data : NULL;
+}
+
+NSS_IMPLEMENT PRUint32
+nssList_Count(nssList *list)
+{
+    return list->count;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_GetArray(nssList *list, void **rvArray, PRUint32 maxElements)
+{
+    nssListElement *node;
+    PRUint32 i = 0;
+    PR_ASSERT(maxElements > 0);
+    node = list->head;
+    if (!node) {
+	return PR_SUCCESS;
+    }
+    NSSLIST_LOCK_IF(list);
+    while (node) {
+	rvArray[i++] = node->data;
+	if (i == maxElements) break;
+	node = (nssListElement *)PR_NEXT_LINK(&node->link);
+	if (node == list->head) {
+	    break;
+	}
+    }
+    NSSLIST_UNLOCK_IF(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT nssList *
+nssList_Clone(nssList *list)
+{
+    nssList *rvList;
+    nssListElement *node;
+    rvList = nssList_Create(NULL, (list->lock != NULL));
+    if (!rvList) {
+	return NULL;
+    }
+    NSSLIST_LOCK_IF(list);
+    if (list->count > 0) {
+	node = list->head;
+	while (PR_TRUE) {
+	    nssList_Add(rvList, node->data);
+	    node = (nssListElement *)PR_NEXT_LINK(&node->link);
+	    if (node == list->head) {
+		break;
+	    }
+	}
+    }
+    NSSLIST_UNLOCK_IF(list);
+    return rvList;
+}
+
+NSS_IMPLEMENT nssListIterator *
+nssList_CreateIterator(nssList *list)
+{
+    nssListIterator *rvIterator;
+    rvIterator = nss_ZNEW(NULL, nssListIterator);
+    if (!rvIterator) {
+	return NULL;
+    }
+    rvIterator->list = nssList_Clone(list);
+    if (!rvIterator->list) {
+	nss_ZFreeIf(rvIterator);
+	return NULL;
+    }
+    rvIterator->current = rvIterator->list->head;
+    if (list->lock) {
+	rvIterator->lock = PZ_NewLock(nssILockOther);
+	if (!rvIterator->lock) {
+	    nssList_Destroy(rvIterator->list);
+	    nss_ZFreeIf(rvIterator);
+	    rvIterator = NULL;
+	}
+    }
+    return rvIterator;
+}
+
+NSS_IMPLEMENT void
+nssListIterator_Destroy(nssListIterator *iter)
+{
+    if (iter->lock) {
+	(void)PZ_DestroyLock(iter->lock);
+    }
+    nssList_Destroy(iter->list);
+    nss_ZFreeIf(iter);
+}
+
+NSS_IMPLEMENT void *
+nssListIterator_Start(nssListIterator *iter)
+{
+    NSSLIST_LOCK_IF(iter);
+    if (iter->list->count == 0) {
+	return NULL;
+    }
+    iter->current = iter->list->head;
+    return iter->current->data;
+}
+
+NSS_IMPLEMENT void *
+nssListIterator_Next(nssListIterator *iter)
+{
+    nssListElement *node;
+    PRCList *link;
+    if (iter->list->count == 1 || iter->current == NULL) {
+	/* Reached the end of the list.  Don't change the state, force to
+	 * user to call nssList_Finish to clean up.
+	 */
+	return NULL;
+    }
+    node = (nssListElement *)PR_NEXT_LINK(&iter->current->link);
+    link = &node->link;
+    if (link == PR_LIST_TAIL(&iter->list->head->link)) {
+	/* Signal the end of the list. */
+	iter->current = NULL;
+	return node->data;
+    }
+    iter->current = node;
+    return node->data;
+}
+
+NSS_IMPLEMENT PRStatus
+nssListIterator_Finish(nssListIterator *iter)
+{
+    iter->current = iter->list->head;
+    return (iter->lock) ? PZ_Unlock(iter->lock) : PR_SUCCESS;
+}
+
diff --git a/mozilla/security/nss/lib/base/nssbase.h b/mozilla/security/nss/lib/base/nssbase.h
new file mode 100644
index 0000000..435952e
--- /dev/null
+++ b/mozilla/security/nss/lib/base/nssbase.h
@@ -0,0 +1,170 @@
+/* ***** 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 ***** */
+
+#ifndef NSSBASE_H
+#define NSSBASE_H
+
+#ifdef DEBUG
+static const char NSSBASE_CVS_ID[] = "@(#) $RCSfile: nssbase.h,v $ $Revision: 1.3 $ $Date: 2005/01/20 02:25:45 $";
+#endif /* DEBUG */
+
+/*
+ * nssbase.h
+ *
+ * This header file contains the prototypes of the basic public
+ * NSS routines.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSArena
+ *
+ * The public methods relating to this type are:
+ *
+ *  NSSArena_Create  -- constructor
+ *  NSSArena_Destroy
+ */
+
+/*
+ * NSSArena_Create
+ *
+ * This routine creates a new memory arena.  This routine may return
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The top-level error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSArena upon success
+ */
+
+NSS_EXTERN NSSArena *
+NSSArena_Create
+(
+  void
+);
+
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSArena_Destroy
+ *
+ * This routine will destroy the specified arena, freeing all memory
+ * allocated from it.  This routine returns a PRStatus value; if 
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * create an error stack and return PR_FAILURE.
+ *
+ * The top-level error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure
+ */
+
+NSS_EXTERN PRStatus
+NSSArena_Destroy
+(
+  NSSArena *arena
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+
+/*
+ * The error stack
+ *
+ * The public methods relating to the error stack are:
+ *
+ *  NSS_GetError
+ *  NSS_GetErrorStack
+ */
+
+/*
+ * NSS_GetError
+ *
+ * This routine returns the highest-level (most general) error set
+ * by the most recent NSS library routine called by the same thread
+ * calling this routine.
+ *
+ * This routine cannot fail.  It may return NSS_ERROR_NO_ERROR, which
+ * indicates that the previous NSS library call did not set an error.
+ *
+ * Return value:
+ *  0 if no error has been set
+ *  A nonzero error number
+ */
+
+NSS_EXTERN NSSError
+NSS_GetError
+(
+  void
+);
+
+extern const NSSError NSS_ERROR_NO_ERROR;
+
+/*
+ * NSS_GetErrorStack
+ *
+ * This routine returns a pointer to an array of NSSError values, 
+ * containingthe entire sequence or "stack" of errors set by the most 
+ * recent NSS library routine called by the same thread calling this 
+ * routine.  NOTE: the caller DOES NOT OWN the memory pointed to by 
+ * the return value.  The pointer will remain valid until the calling 
+ * thread calls another NSS routine.  The lowest-level (most specific) 
+ * error is first in the array, and the highest-level is last.  The 
+ * array is zero-terminated.  This routine may return NULL upon error; 
+ * this indicates a low-memory situation.
+ *
+ * Return value:
+ *  NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
+ *  A NON-caller-owned pointer to an array of NSSError values
+ */
+
+NSS_EXTERN NSSError *
+NSS_GetErrorStack
+(
+  void
+);
+
+PR_END_EXTERN_C
+
+#endif /* NSSBASE_H */
diff --git a/mozilla/security/nss/lib/base/nssbaset.h b/mozilla/security/nss/lib/base/nssbaset.h
new file mode 100644
index 0000000..a359b80
--- /dev/null
+++ b/mozilla/security/nss/lib/base/nssbaset.h
@@ -0,0 +1,155 @@
+/* ***** 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 ***** */
+
+#ifndef NSSBASET_H
+#define NSSBASET_H
+
+#ifdef DEBUG
+static const char NSSBASET_CVS_ID[] = "@(#) $RCSfile: nssbaset.h,v $ $Revision: 1.8 $ $Date: 2009/04/07 23:52:05 $";
+#endif /* DEBUG */
+
+/*
+ * nssbaset.h
+ *
+ * This file contains the most low-level, fundamental public types.
+ */
+
+#include "nspr.h"
+#include "nssilock.h"
+
+/*
+ * NSS_EXTERN, NSS_IMPLEMENT, NSS_EXTERN_DATA, NSS_IMPLEMENT_DATA
+ *
+ * NSS has its own versions of these NSPR macros, in a form which
+ * does not confuse ctags and other related utilities.  NSPR 
+ * defines these macros to take the type as an argument, because
+ * of certain OS requirements on platforms not supported by NSS.
+ */
+
+#define DUMMY	/* dummy */
+#define NSS_EXTERN         extern
+#define NSS_EXTERN_DATA    extern
+#define NSS_IMPLEMENT      
+#define NSS_IMPLEMENT_DATA 
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSError
+ *
+ * Calls to NSS routines may result in one or more errors being placed
+ * on the calling thread's "error stack."  Every possible error that
+ * may be returned from a function is declared where the function is 
+ * prototyped.  All errors are of the following type.
+ */
+
+typedef PRInt32 NSSError;
+
+/*
+ * NSSArena
+ *
+ * Arenas are logical sets of heap memory, from which memory may be
+ * allocated.  When an arena is destroyed, all memory allocated within
+ * that arena is implicitly freed.  These arenas are thread-safe: 
+ * an arena pointer may be used by multiple threads simultaneously.
+ * However, as they are not backed by shared memory, they may only be
+ * used within one process.
+ */
+
+struct NSSArenaStr;
+typedef struct NSSArenaStr NSSArena;
+
+/*
+ * NSSItem
+ *
+ * This is the basic type used to refer to an unconstrained datum of
+ * arbitrary size.
+ */
+
+struct NSSItemStr {
+  void *data;
+  PRUint32 size;
+};
+typedef struct NSSItemStr NSSItem;
+
+
+/*
+ * NSSBER
+ *
+ * Data packed according to the Basic Encoding Rules of ASN.1.
+ */
+
+typedef NSSItem NSSBER;
+
+/*
+ * NSSDER
+ *
+ * Data packed according to the Distinguished Encoding Rules of ASN.1;
+ * this form is also known as the Canonical Encoding Rules form (CER).
+ */
+
+typedef NSSBER NSSDER;
+
+/*
+ * NSSBitString
+ *
+ * Some ASN.1 types use "bit strings," which are passed around as
+ * octet strings but whose length is counted in bits.  We use this
+ * typedef of NSSItem to point out the occasions when the length
+ * is counted in bits, not octets.
+ */
+
+typedef NSSItem NSSBitString;
+
+/*
+ * NSSUTF8
+ *
+ * Character strings encoded in UTF-8, as defined by RFC 2279.
+ */
+
+typedef char NSSUTF8;
+
+/*
+ * NSSASCII7
+ *
+ * Character strings guaranteed to be 7-bit ASCII.
+ */
+
+typedef char NSSASCII7;
+
+PR_END_EXTERN_C
+
+#endif /* NSSBASET_H */
diff --git a/mozilla/security/nss/lib/base/nssutf8.c b/mozilla/security/nss/lib/base/nssutf8.c
new file mode 100644
index 0000000..e850ee8
--- /dev/null
+++ b/mozilla/security/nss/lib/base/nssutf8.c
@@ -0,0 +1,762 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: utf8.c,v $ $Revision: 1.7 $ $Date: 2005/01/20 02:25:45 $";
+#endif /* DEBUG */
+
+/*
+ * utf8.c
+ *
+ * This file contains some additional utility routines required for
+ * handling UTF8 strings.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#include "plstr.h"
+
+/*
+ * NOTES:
+ *
+ * There's an "is hex string" function in pki1/atav.c.  If we need
+ * it in more places, pull that one out.
+ */
+
+/*
+ * nssUTF8_CaseIgnoreMatch
+ * 
+ * Returns true if the two UTF8-encoded strings pointed to by the 
+ * two specified NSSUTF8 pointers differ only in typcase.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_TRUE if the strings match, ignoring case
+ *  PR_FALSE if they don't
+ *  PR_FALSE upon error
+ */
+
+NSS_IMPLEMENT PRBool
+nssUTF8_CaseIgnoreMatch
+(
+  const NSSUTF8 *a,
+  const NSSUTF8 *b,
+  PRStatus *statusOpt
+)
+{
+#ifdef NSSDEBUG
+  if( ((const NSSUTF8 *)NULL == a) ||
+      ((const NSSUTF8 *)NULL == b) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    if( (PRStatus *)NULL != statusOpt ) {
+      *statusOpt = PR_FAILURE;
+    }
+    return PR_FALSE;
+  }
+#endif /* NSSDEBUG */
+
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_SUCCESS;
+  }
+
+  /*
+   * XXX fgmr
+   *
+   * This is, like, so wrong!
+   */
+  if( 0 == PL_strcasecmp((const char *)a, (const char *)b) ) {
+    return PR_TRUE;
+  } else {
+    return PR_FALSE;
+  }
+}
+
+/*
+ * nssUTF8_PrintableMatch
+ *
+ * Returns true if the two Printable strings pointed to by the 
+ * two specified NSSUTF8 pointers match when compared with the 
+ * rules for Printable String (leading and trailing spaces are 
+ * disregarded, extents of whitespace match irregardless of length, 
+ * and case is not significant), then PR_TRUE will be returned.
+ * Otherwise, PR_FALSE will be returned.  Upon failure, PR_FALSE
+ * will be returned.  If the optional statusOpt argument is not
+ * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that
+ * location.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *
+ * Return value:
+ *  PR_TRUE if the strings match, ignoring case
+ *  PR_FALSE if they don't
+ *  PR_FALSE upon error
+ */
+
+NSS_IMPLEMENT PRBool
+nssUTF8_PrintableMatch
+(
+  const NSSUTF8 *a,
+  const NSSUTF8 *b,
+  PRStatus *statusOpt
+)
+{
+  PRUint8 *c;
+  PRUint8 *d;
+
+#ifdef NSSDEBUG
+  if( ((const NSSUTF8 *)NULL == a) ||
+      ((const NSSUTF8 *)NULL == b) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    if( (PRStatus *)NULL != statusOpt ) {
+      *statusOpt = PR_FAILURE;
+    }
+    return PR_FALSE;
+  }
+#endif /* NSSDEBUG */
+
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_SUCCESS;
+  }
+
+  c = (PRUint8 *)a;
+  d = (PRUint8 *)b;
+
+  while( ' ' == *c ) {
+    c++;
+  }
+
+  while( ' ' == *d ) {
+    d++;
+  }
+
+  while( ('\0' != *c) && ('\0' != *d) ) {
+    PRUint8 e, f;
+
+    e = *c;
+    f = *d;
+    
+    if( ('a' <= e) && (e <= 'z') ) {
+      e -= ('a' - 'A');
+    }
+
+    if( ('a' <= f) && (f <= 'z') ) {
+      f -= ('a' - 'A');
+    }
+
+    if( e != f ) {
+      return PR_FALSE;
+    }
+
+    c++;
+    d++;
+
+    if( ' ' == *c ) {
+      while( ' ' == *c ) {
+        c++;
+      }
+      c--;
+    }
+
+    if( ' ' == *d ) {
+      while( ' ' == *d ) {
+        d++;
+      }
+      d--;
+    }
+  }
+
+  while( ' ' == *c ) {
+    c++;
+  }
+
+  while( ' ' == *d ) {
+    d++;
+  }
+
+  if( *c == *d ) {
+    /* And both '\0', btw */
+    return PR_TRUE;
+  } else {
+    return PR_FALSE;
+  }
+}
+
+/*
+ * nssUTF8_Duplicate
+ *
+ * This routine duplicates the UTF8-encoded string pointed to by the
+ * specified NSSUTF8 pointer.  If the optional arenaOpt argument is
+ * not null, the memory required will be obtained from that arena;
+ * otherwise, the memory required will be obtained from the heap.
+ * A pointer to the new string will be returned.  In case of error,
+ * an error will be placed on the error stack and NULL will be 
+ * returned.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_NO_MEMORY
+ */
+
+NSS_IMPLEMENT NSSUTF8 *
+nssUTF8_Duplicate
+(
+  const NSSUTF8 *s,
+  NSSArena *arenaOpt
+)
+{
+  NSSUTF8 *rv;
+  PRUint32 len;
+
+#ifdef NSSDEBUG
+  if( (const NSSUTF8 *)NULL == s ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return (NSSUTF8 *)NULL;
+  }
+
+  if( (NSSArena *)NULL != arenaOpt ) {
+    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
+      return (NSSUTF8 *)NULL;
+    }
+  }
+#endif /* NSSDEBUG */
+
+  len = PL_strlen((const char *)s);
+#ifdef PEDANTIC
+  if( '\0' != ((const char *)s)[ len ] ) {
+    /* must have wrapped, e.g., too big for PRUint32 */
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return (NSSUTF8 *)NULL;
+  }
+#endif /* PEDANTIC */
+  len++; /* zero termination */
+
+  rv = nss_ZAlloc(arenaOpt, len);
+  if( (void *)NULL == rv ) {
+    return (NSSUTF8 *)NULL;
+  }
+
+  (void)nsslibc_memcpy(rv, s, len);
+  return rv;
+}
+
+/*
+ * nssUTF8_Size
+ *
+ * This routine returns the length in bytes (including the terminating
+ * null) of the UTF8-encoded string pointed to by the specified
+ * NSSUTF8 pointer.  Zero is returned on error.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_VALUE_TOO_LARGE
+ *
+ * Return value:
+ *  0 on error
+ *  nonzero length of the string.
+ */
+
+NSS_IMPLEMENT PRUint32
+nssUTF8_Size
+(
+  const NSSUTF8 *s,
+  PRStatus *statusOpt
+)
+{
+  PRUint32 sv;
+
+#ifdef NSSDEBUG
+  if( (const NSSUTF8 *)NULL == s ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    if( (PRStatus *)NULL != statusOpt ) {
+      *statusOpt = PR_FAILURE;
+    }
+    return 0;
+  }
+#endif /* NSSDEBUG */
+
+  sv = PL_strlen((const char *)s) + 1;
+#ifdef PEDANTIC
+  if( '\0' != ((const char *)s)[ sv-1 ] ) {
+    /* wrapped */
+    nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
+    if( (PRStatus *)NULL != statusOpt ) {
+      *statusOpt = PR_FAILURE;
+    }
+    return 0;
+  }
+#endif /* PEDANTIC */
+
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_SUCCESS;
+  }
+
+  return sv;
+}
+
+/*
+ * nssUTF8_Length
+ *
+ * This routine returns the length in characters (not including the
+ * terminating null) of the UTF8-encoded string pointed to by the
+ * specified NSSUTF8 pointer.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_VALUE_TOO_LARGE
+ *  NSS_ERROR_INVALID_STRING
+ *
+ * Return value:
+ *  length of the string (which may be zero)
+ *  0 on error
+ */
+
+NSS_IMPLEMENT PRUint32
+nssUTF8_Length
+(
+  const NSSUTF8 *s,
+  PRStatus *statusOpt
+)
+{
+  PRUint32 l = 0;
+  const PRUint8 *c = (const PRUint8 *)s;
+
+#ifdef NSSDEBUG
+  if( (const NSSUTF8 *)NULL == s ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    goto loser;
+  }
+#endif /* NSSDEBUG */
+
+  /*
+   * From RFC 2044:
+   *
+   * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+   * 0000 0000-0000 007F   0xxxxxxx
+   * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+   * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
+   * 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+   * 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+   * 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
+   */  
+
+  while( 0 != *c ) {
+    PRUint32 incr;
+    if( (*c & 0x80) == 0 ) {
+      incr = 1;
+    } else if( (*c & 0xE0) == 0xC0 ) {
+      incr = 2;
+    } else if( (*c & 0xF0) == 0xE0 ) {
+      incr = 3;
+    } else if( (*c & 0xF8) == 0xF0 ) {
+      incr = 4;
+    } else if( (*c & 0xFC) == 0xF8 ) {
+      incr = 5;
+    } else if( (*c & 0xFE) == 0xFC ) {
+      incr = 6;
+    } else {
+      nss_SetError(NSS_ERROR_INVALID_STRING);
+      goto loser;
+    }
+
+    l += incr;
+
+#ifdef PEDANTIC
+    if( l < incr ) {
+      /* Wrapped-- too big */
+      nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
+      goto loser;
+    }
+
+    {
+      PRUint8 *d;
+      for( d = &c[1]; d < &c[incr]; d++ ) {
+        if( (*d & 0xC0) != 0xF0 ) {
+          nss_SetError(NSS_ERROR_INVALID_STRING);
+          goto loser;
+        }
+      }
+    }
+#endif /* PEDANTIC */
+
+    c += incr;
+  }
+
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_SUCCESS;
+  }
+
+  return l;
+
+ loser:
+  if( (PRStatus *)NULL != statusOpt ) {
+    *statusOpt = PR_FAILURE;
+  }
+
+  return 0;
+}
+
+
+/*
+ * nssUTF8_Create
+ *
+ * This routine creates a UTF8 string from a string in some other
+ * format.  Some types of string may include embedded null characters,
+ * so for them the length parameter must be used.  For string types
+ * that are null-terminated, the length parameter is optional; if it
+ * is zero, it will be ignored.  If the optional arena argument is
+ * non-null, the memory used for the new string will be obtained from
+ * that arena, otherwise it will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have
+ * placed an error on the error stack.
+ *
+ * The error may be one of the following:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_UNSUPPORTED_TYPE
+ *
+ * Return value:
+ *  NULL upon error
+ *  A non-null pointer to a new UTF8 string otherwise
+ */
+
+extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */
+
+NSS_IMPLEMENT NSSUTF8 *
+nssUTF8_Create
+(
+  NSSArena *arenaOpt,
+  nssStringType type,
+  const void *inputString,
+  PRUint32 size /* in bytes, not characters */
+)
+{
+  NSSUTF8 *rv = NULL;
+
+#ifdef NSSDEBUG
+  if( (NSSArena *)NULL != arenaOpt ) {
+    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
+      return (NSSUTF8 *)NULL;
+    }
+  }
+
+  if( (const void *)NULL == inputString ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return (NSSUTF8 *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  switch( type ) {
+  case nssStringType_DirectoryString:
+    /* This is a composite type requiring BER */
+    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
+    break;
+  case nssStringType_TeletexString:
+    /*
+     * draft-ietf-pkix-ipki-part1-11 says in part:
+     *
+     * In addition, many legacy implementations support names encoded 
+     * in the ISO 8859-1 character set (Latin1String) but tag them as 
+     * TeletexString.  The Latin1String includes characters used in 
+     * Western European countries which are not part of the 
+     * TeletexString charcter set.  Implementations that process 
+     * TeletexString SHOULD be prepared to handle the entire ISO 
+     * 8859-1 character set.[ISO 8859-1].
+     */
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_PrintableString:
+    /*
+     * PrintableString consists of A-Za-z0-9 ,()+,-./:=?
+     * This is a subset of ASCII, which is a subset of UTF8.
+     * So we can just duplicate the string over.
+     */
+
+    if( 0 == size ) {
+      rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
+    } else {
+      rv = nss_ZAlloc(arenaOpt, size+1);
+      if( (NSSUTF8 *)NULL == rv ) {
+        return (NSSUTF8 *)NULL;
+      }
+
+      (void)nsslibc_memcpy(rv, inputString, size);
+    }
+
+    break;
+  case nssStringType_UniversalString:
+    /* 4-byte unicode */
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_BMPString:
+    /* Base Multilingual Plane of Unicode */
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_UTF8String:
+    if( 0 == size ) {
+      rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
+    } else {
+      rv = nss_ZAlloc(arenaOpt, size+1);
+      if( (NSSUTF8 *)NULL == rv ) {
+        return (NSSUTF8 *)NULL;
+      }
+
+      (void)nsslibc_memcpy(rv, inputString, size);
+    }
+
+    break;
+  case nssStringType_PHGString:
+    /* 
+     * PHGString is an IA5String (with case-insensitive comparisons).
+     * IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has
+     * currency symbol.
+     */
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_GeneralString:
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  default:
+    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
+    break;
+  }
+
+  return rv;
+}
+
+NSS_IMPLEMENT NSSItem *
+nssUTF8_GetEncoding
+(
+  NSSArena *arenaOpt,
+  NSSItem *rvOpt,
+  nssStringType type,
+  NSSUTF8 *string
+)
+{
+  NSSItem *rv = (NSSItem *)NULL;
+  PRStatus status = PR_SUCCESS;
+
+#ifdef NSSDEBUG
+  if( (NSSArena *)NULL != arenaOpt ) {
+    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
+      return (NSSItem *)NULL;
+    }
+  }
+
+  if( (NSSUTF8 *)NULL == string ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return (NSSItem *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  switch( type ) {
+  case nssStringType_DirectoryString:
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_TeletexString:
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_PrintableString:
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_UniversalString:
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_BMPString:
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  case nssStringType_UTF8String:
+    {
+      NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt);
+      if( (NSSUTF8 *)NULL == dup ) {
+        return (NSSItem *)NULL;
+      }
+
+      if( (NSSItem *)NULL == rvOpt ) {
+        rv = nss_ZNEW(arenaOpt, NSSItem);
+        if( (NSSItem *)NULL == rv ) {
+          (void)nss_ZFreeIf(dup);
+          return (NSSItem *)NULL;
+        }
+      } else {
+        rv = rvOpt;
+      }
+
+      rv->data = dup;
+      dup = (NSSUTF8 *)NULL;
+      rv->size = nssUTF8_Size(rv->data, &status);
+      if( (0 == rv->size) && (PR_SUCCESS != status) ) {
+        if( (NSSItem *)NULL == rvOpt ) {
+          (void)nss_ZFreeIf(rv);
+        }
+        return (NSSItem *)NULL;
+      }
+    }
+    break;
+  case nssStringType_PHGString:
+    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
+    break;
+  default:
+    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
+    break;
+  }
+
+  return rv;
+}
+
+/*
+ * nssUTF8_CopyIntoFixedBuffer
+ *
+ * This will copy a UTF8 string into a fixed-length buffer, making 
+ * sure that the all characters are valid.  Any remaining space will
+ * be padded with the specified ASCII character, typically either 
+ * null or space.
+ *
+ * Blah, blah, blah.
+ */
+
+NSS_IMPLEMENT PRStatus
+nssUTF8_CopyIntoFixedBuffer
+(
+  NSSUTF8 *string,
+  char *buffer,
+  PRUint32 bufferSize,
+  char pad
+)
+{
+  PRUint32 stringSize = 0;
+
+#ifdef NSSDEBUG
+  if( (char *)NULL == buffer ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return PR_FALSE;
+  }
+
+  if( 0 == bufferSize ) {
+    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+    return PR_FALSE;
+  }
+
+  if( (pad & 0x80) != 0x00 ) {
+    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+    return PR_FALSE;
+  }
+#endif /* NSSDEBUG */
+
+  if( (NSSUTF8 *)NULL == string ) {
+    string = (NSSUTF8 *) "";
+  }
+
+  stringSize = nssUTF8_Size(string, (PRStatus *)NULL);
+  stringSize--; /* don't count the trailing null */
+  if( stringSize > bufferSize ) {
+    PRUint32 bs = bufferSize;
+    (void)nsslibc_memcpy(buffer, string, bufferSize);
+    
+    if( (            ((buffer[ bs-1 ] & 0x80) == 0x00)) ||
+        ((bs > 1) && ((buffer[ bs-2 ] & 0xE0) == 0xC0)) ||
+        ((bs > 2) && ((buffer[ bs-3 ] & 0xF0) == 0xE0)) ||
+        ((bs > 3) && ((buffer[ bs-4 ] & 0xF8) == 0xF0)) ||
+        ((bs > 4) && ((buffer[ bs-5 ] & 0xFC) == 0xF8)) ||
+        ((bs > 5) && ((buffer[ bs-6 ] & 0xFE) == 0xFC)) ) {
+      /* It fit exactly */
+      return PR_SUCCESS;
+    }
+
+    /* Too long.  We have to trim the last character */
+    for( /*bs*/; bs != 0; bs-- ) {
+      if( (buffer[bs-1] & 0xC0) != 0x80 ) {
+        buffer[bs-1] = pad;
+        break;
+      } else {
+        buffer[bs-1] = pad;
+      }
+    }      
+  } else {
+    (void)nsslibc_memset(buffer, pad, bufferSize);
+    (void)nsslibc_memcpy(buffer, string, stringSize);
+  }
+
+  return PR_SUCCESS;
+}
+
+/*
+ * nssUTF8_Equal
+ *
+ */
+
+NSS_IMPLEMENT PRBool
+nssUTF8_Equal
+(
+  const NSSUTF8 *a,
+  const NSSUTF8 *b,
+  PRStatus *statusOpt
+)
+{
+  PRUint32 la, lb;
+
+#ifdef NSSDEBUG
+  if( ((const NSSUTF8 *)NULL == a) ||
+      ((const NSSUTF8 *)NULL == b) ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    if( (PRStatus *)NULL != statusOpt ) {
+      *statusOpt = PR_FAILURE;
+    }
+    return PR_FALSE;
+  }
+#endif /* NSSDEBUG */
+
+  la = nssUTF8_Size(a, statusOpt);
+  if( 0 == la ) {
+    return PR_FALSE;
+  }
+
+  lb = nssUTF8_Size(b, statusOpt);
+  if( 0 == lb ) {
+    return PR_FALSE;
+  }
+
+  if( la != lb ) {
+    return PR_FALSE;
+  }
+
+  return nsslibc_memequal(a, b, la, statusOpt);
+}
diff --git a/mozilla/security/nss/lib/base/tracker.c b/mozilla/security/nss/lib/base/tracker.c
new file mode 100644
index 0000000..3e62896
--- /dev/null
+++ b/mozilla/security/nss/lib/base/tracker.c
@@ -0,0 +1,447 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: tracker.c,v $ $Revision: 1.7 $ $Date: 2008/02/23 05:29:24 $";
+#endif /* DEBUG */
+
+/*
+ * tracker.c
+ * 
+ * This file contains the code used by the pointer-tracking calls used
+ * in the debug builds to catch bad pointers.  The entire contents are
+ * only available in debug builds (both internal and external builds).
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#ifdef DEBUG
+/*
+ * identity_hash
+ *
+ * This static callback is a PLHashFunction as defined in plhash.h
+ * It merely returns the value of the object pointer as its hash.
+ * There are no possible errors.
+ */
+
+static PLHashNumber PR_CALLBACK
+identity_hash
+(
+  const void *key
+)
+{
+  return (PLHashNumber)key;
+}
+
+/*
+ * trackerOnceFunc
+ *
+ * This function is called once, using the nssCallOnce function above.
+ * It creates a new pointer tracker object; initialising its hash
+ * table and protective lock.
+ */
+
+static PRStatus
+trackerOnceFunc
+(
+  void *arg
+)
+{
+  nssPointerTracker *tracker = (nssPointerTracker *)arg;
+
+  tracker->lock = PZ_NewLock(nssILockOther);
+  if( (PZLock *)NULL == tracker->lock ) {
+    return PR_FAILURE;
+  }
+
+  tracker->table = PL_NewHashTable(0, 
+                                   identity_hash, 
+                                   PL_CompareValues,
+                                   PL_CompareValues,
+                                   (PLHashAllocOps *)NULL, 
+                                   (void *)NULL);
+  if( (PLHashTable *)NULL == tracker->table ) {
+    PZ_DestroyLock(tracker->lock);
+    tracker->lock = (PZLock *)NULL;
+    return PR_FAILURE;
+  }
+
+  return PR_SUCCESS;
+}
+
+/*
+ * nssPointerTracker_initialize
+ *
+ * This method is only present in debug builds.
+ * 
+ * This routine initializes an nssPointerTracker object.  Note that
+ * the object must have been declared *static* to guarantee that it
+ * is in a zeroed state initially.  This routine is idempotent, and
+ * may even be safely called by multiple threads simultaneously with 
+ * the same argument.  This routine returns a PRStatus value; if 
+ * successful, it will return PR_SUCCESS.  On failure it will set an 
+ * error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssPointerTracker_initialize
+(
+  nssPointerTracker *tracker
+)
+{
+  PRStatus rv = PR_CallOnceWithArg(&tracker->once, trackerOnceFunc, tracker);
+  if( PR_SUCCESS != rv ) {
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+  }
+
+  return rv;
+}
+
+#ifdef DONT_DESTROY_EMPTY_TABLES
+/* See same #ifdef below */
+/*
+ * count_entries
+ *
+ * This static routine is a PLHashEnumerator, as defined in plhash.h.
+ * It merely causes the enumeration function to count the number of
+ * entries.
+ */
+
+static PRIntn PR_CALLBACK
+count_entries
+(
+  PLHashEntry *he,
+  PRIntn index,
+  void *arg
+)
+{
+  return HT_ENUMERATE_NEXT;
+}
+#endif /* DONT_DESTROY_EMPTY_TABLES */
+
+/*
+ * zero_once
+ *
+ * This is a guaranteed zeroed once block.  It's used to help clear
+ * the tracker.
+ */
+
+static const PRCallOnceType zero_once;
+
+/*
+ * nssPointerTracker_finalize
+ *
+ * This method is only present in debug builds.
+ * 
+ * This routine returns the nssPointerTracker object to the pre-
+ * initialized state, releasing all resources used by the object.
+ * It will *NOT* destroy the objects being tracked by the pointer
+ * (should any remain), and therefore cannot be used to "sweep up"
+ * remaining objects.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCES.  On failure it will set an
+ * error on the error stack and return PR_FAILURE.  If any objects
+ * remain in the tracker when it is finalized, that will be treated
+ * as an error.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_TRACKER_NOT_INITIALIZED
+ *  NSS_ERROR_TRACKER_NOT_EMPTY
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssPointerTracker_finalize
+(
+  nssPointerTracker *tracker
+)
+{
+  PZLock *lock;
+
+  if( (nssPointerTracker *)NULL == tracker ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return PR_FAILURE;
+  }
+
+  if( (PZLock *)NULL == tracker->lock ) {
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+  lock = tracker->lock;
+  PZ_Lock(lock);
+
+  if( (PLHashTable *)NULL == tracker->table ) {
+    PZ_Unlock(lock);
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+#ifdef DONT_DESTROY_EMPTY_TABLES
+  /*
+   * I changed my mind; I think we don't want this after all.
+   * Comments?
+   */
+  count = PL_HashTableEnumerateEntries(tracker->table, 
+                                       count_entries,
+                                       (void *)NULL);
+
+  if( 0 != count ) {
+    PZ_Unlock(lock);
+    nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY);
+    return PR_FAILURE;
+  }
+#endif /* DONT_DESTROY_EMPTY_TABLES */
+
+  PL_HashTableDestroy(tracker->table);
+  /* memset(tracker, 0, sizeof(nssPointerTracker)); */
+  tracker->once = zero_once;
+  tracker->lock = (PZLock *)NULL;
+  tracker->table = (PLHashTable *)NULL;
+
+  PZ_Unlock(lock);
+  PZ_DestroyLock(lock);
+
+  return PR_SUCCESS;
+}
+
+/*
+ * nssPointerTracker_add
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine adds the specified pointer to the nssPointerTracker
+ * object.  It should be called in constructor objects to register
+ * new valid objects.  The nssPointerTracker is threadsafe, but this
+ * call is not idempotent.  This routine returns a PRStatus value;
+ * if successful it will return PR_SUCCESS.  On failure it will set
+ * an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_TRACKER_NOT_INITIALIZED
+ *  NSS_ERROR_DUPLICATE_POINTER
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssPointerTracker_add
+(
+  nssPointerTracker *tracker,
+  const void *pointer
+)
+{
+  void *check;
+  PLHashEntry *entry;
+
+  if( (nssPointerTracker *)NULL == tracker ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return PR_FAILURE;
+  }
+
+  if( (PZLock *)NULL == tracker->lock ) {
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+  PZ_Lock(tracker->lock);
+
+  if( (PLHashTable *)NULL == tracker->table ) {
+    PZ_Unlock(tracker->lock);
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+  check = PL_HashTableLookup(tracker->table, pointer);
+  if( (void *)NULL != check ) {
+    PZ_Unlock(tracker->lock);
+    nss_SetError(NSS_ERROR_DUPLICATE_POINTER);
+    return PR_FAILURE;
+  }
+
+  entry = PL_HashTableAdd(tracker->table, pointer, (void *)pointer);
+
+  PZ_Unlock(tracker->lock);
+
+  if( (PLHashEntry *)NULL == entry ) {
+    nss_SetError(NSS_ERROR_NO_MEMORY);
+    return PR_FAILURE;
+  }
+
+  return PR_SUCCESS;
+}
+  
+/*
+ * nssPointerTracker_remove
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine removes the specified pointer from the 
+ * nssPointerTracker object.  It does not call any destructor for the
+ * object; rather, this should be called from the object's destructor.
+ * The nssPointerTracker is threadsafe, but this call is not 
+ * idempotent.  This routine returns a PRStatus value; if successful 
+ * it will return PR_SUCCESS.  On failure it will set an error on the 
+ * error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_TRACKER_NOT_INITIALIZED
+ *  NSS_ERROR_POINTER_NOT_REGISTERED
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILURE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssPointerTracker_remove
+(
+  nssPointerTracker *tracker,
+  const void *pointer
+)
+{
+  PRBool registered;
+
+  if( (nssPointerTracker *)NULL == tracker ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return PR_FAILURE;
+  }
+
+  if( (PZLock *)NULL == tracker->lock ) {
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+  PZ_Lock(tracker->lock);
+
+  if( (PLHashTable *)NULL == tracker->table ) {
+    PZ_Unlock(tracker->lock);
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+  registered = PL_HashTableRemove(tracker->table, pointer);
+  PZ_Unlock(tracker->lock);
+
+  if( !registered ) {
+    nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
+    return PR_FAILURE;
+  }
+
+  return PR_SUCCESS;
+}
+
+/*
+ * nssPointerTracker_verify
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine verifies that the specified pointer has been registered
+ * with the nssPointerTracker object.  The nssPointerTracker object is
+ * threadsafe, and this call may be safely called from multiple threads
+ * simultaneously with the same arguments.  This routine returns a
+ * PRStatus value; if the pointer is registered this will return 
+ * PR_SUCCESS.  Otherwise it will set an error on the error stack and 
+ * return PR_FAILURE.  Although the error is suitable for leaving on 
+ * the stack, callers may wish to augment the information available by 
+ * placing a more type-specific error on the stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_TRACKER_NOT_INITIALIZED
+ *  NSS_ERROR_POINTER_NOT_REGISTERED
+ *
+ * Return value:
+ *  PR_SUCCESS
+ *  PR_FAILRUE
+ */
+
+NSS_IMPLEMENT PRStatus
+nssPointerTracker_verify
+(
+  nssPointerTracker *tracker,
+  const void *pointer
+)
+{
+  void *check;
+
+  if( (nssPointerTracker *)NULL == tracker ) {
+    nss_SetError(NSS_ERROR_INVALID_POINTER);
+    return PR_FAILURE;
+  }
+
+  if( (PZLock *)NULL == tracker->lock ) {
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+  PZ_Lock(tracker->lock);
+
+  if( (PLHashTable *)NULL == tracker->table ) {
+    PZ_Unlock(tracker->lock);
+    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
+    return PR_FAILURE;
+  }
+
+  check = PL_HashTableLookup(tracker->table, pointer);
+  PZ_Unlock(tracker->lock);
+
+  if( (void *)NULL == check ) {
+    nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
+    return PR_FAILURE;
+  }
+
+  return PR_SUCCESS;
+}
+
+#endif /* DEBUG */
diff --git a/mozilla/security/nss/lib/certdb/alg1485.c b/mozilla/security/nss/lib/certdb/alg1485.c
new file mode 100644
index 0000000..5fc2029
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/alg1485.c
@@ -0,0 +1,1578 @@
+/* alg1485.c - implementation of RFCs 1485, 1779 and 2253.
+ *
+ * ***** 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 "prprf.h"
+#include "cert.h"
+#include "certi.h"
+#include "xconst.h"
+#include "genname.h"
+#include "secitem.h"
+#include "secerr.h"
+
+typedef struct NameToKindStr {
+    const char * name;
+    unsigned int maxLen; /* max bytes in UTF8 encoded string value */
+    SECOidTag    kind;
+    int		 valueType;
+} NameToKind;
+
+/* local type for directory string--could be printable_string or utf8 */
+#define SEC_ASN1_DS SEC_ASN1_HIGH_TAG_NUMBER
+
+/* Add new entries to this table, and maybe to function ParseRFC1485AVA */
+static const NameToKind name2kinds[] = {
+/* IANA registered type names
+ * (See: http://www.iana.org/assignments/ldap-parameters) 
+ */
+/* RFC 3280, 4630 MUST SUPPORT */
+    { "CN",             64, SEC_OID_AVA_COMMON_NAME,    SEC_ASN1_DS},
+    { "ST",            128, SEC_OID_AVA_STATE_OR_PROVINCE,
+							SEC_ASN1_DS},
+    { "O",              64, SEC_OID_AVA_ORGANIZATION_NAME,
+							SEC_ASN1_DS},
+    { "OU",             64, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
+                                                        SEC_ASN1_DS},
+    { "dnQualifier", 32767, SEC_OID_AVA_DN_QUALIFIER, SEC_ASN1_PRINTABLE_STRING},
+    { "C",               2, SEC_OID_AVA_COUNTRY_NAME, SEC_ASN1_PRINTABLE_STRING},
+    { "serialNumber",   64, SEC_OID_AVA_SERIAL_NUMBER,SEC_ASN1_PRINTABLE_STRING},
+
+/* RFC 3280, 4630 SHOULD SUPPORT */
+    { "L",             128, SEC_OID_AVA_LOCALITY,       SEC_ASN1_DS},
+    { "title",          64, SEC_OID_AVA_TITLE,          SEC_ASN1_DS},
+    { "SN",             64, SEC_OID_AVA_SURNAME,        SEC_ASN1_DS},
+    { "givenName",      64, SEC_OID_AVA_GIVEN_NAME,     SEC_ASN1_DS},
+    { "initials",       64, SEC_OID_AVA_INITIALS,       SEC_ASN1_DS},
+    { "generationQualifier",
+                        64, SEC_OID_AVA_GENERATION_QUALIFIER,
+                                                        SEC_ASN1_DS},
+/* RFC 3280, 4630 MAY SUPPORT */
+    { "DC",            128, SEC_OID_AVA_DC,             SEC_ASN1_IA5_STRING},
+    { "MAIL",          256, SEC_OID_RFC1274_MAIL,       SEC_ASN1_IA5_STRING},
+    { "UID",           256, SEC_OID_RFC1274_UID,        SEC_ASN1_DS},
+
+/* ------------------ "strict" boundary ---------------------------------
+ * In strict mode, cert_NameToAscii does not encode any of the attributes
+ * below this line. The first SECOidTag below this line must be used to
+ * conditionally define the "endKind" in function AppendAVA() below.
+ * Most new attribute names should be added below this line.
+ * Maybe this line should be up higher?  Say, after the 3280 MUSTs and 
+ * before the 3280 SHOULDs?
+ */
+
+/* values from draft-ietf-ldapbis-user-schema-05 (not in RFC 3280) */
+    { "postalAddress", 128, SEC_OID_AVA_POSTAL_ADDRESS, SEC_ASN1_DS},
+    { "postalCode",     40, SEC_OID_AVA_POSTAL_CODE,    SEC_ASN1_DS},
+    { "postOfficeBox",  40, SEC_OID_AVA_POST_OFFICE_BOX,SEC_ASN1_DS},
+    { "houseIdentifier",64, SEC_OID_AVA_HOUSE_IDENTIFIER,SEC_ASN1_DS},
+/* end of IANA registered type names */
+
+/* legacy keywords */
+    { "E",             128, SEC_OID_PKCS9_EMAIL_ADDRESS,SEC_ASN1_IA5_STRING},
+
+#if 0 /* removed.  Not yet in any IETF draft or RFC. */
+    { "pseudonym",      64, SEC_OID_AVA_PSEUDONYM,      SEC_ASN1_DS},
+#endif
+
+    { 0,           256, SEC_OID_UNKNOWN                      , 0},
+};
+
+/* Table facilitates conversion of ASCII hex to binary. */
+static const PRInt16 x2b[256] = {
+/* #0x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #1x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #2x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #3x */  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, 
+/* #4x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #5x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #6x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #7x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #8x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #9x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #ax */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #bx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #cx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #dx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #ex */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+/* #fx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+#define IS_HEX(c) (x2b[(PRUint8)(c)] >= 0)
+
+#define C_DOUBLE_QUOTE '\042'
+
+#define C_BACKSLASH '\134'
+
+#define C_EQUAL '='
+
+#define OPTIONAL_SPACE(c) \
+    (((c) == ' ') || ((c) == '\r') || ((c) == '\n'))
+
+#define SPECIAL_CHAR(c)						\
+    (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) ||	\
+     ((c) == '\r') || ((c) == '\n') || ((c) == '+') ||		\
+     ((c) == '<') || ((c) == '>') || ((c) == '#') ||		\
+     ((c) == ';') || ((c) == C_BACKSLASH))
+
+
+#define IS_PRINTABLE(c)						\
+    ((((c) >= 'a') && ((c) <= 'z')) ||				\
+     (((c) >= 'A') && ((c) <= 'Z')) ||				\
+     (((c) >= '0') && ((c) <= '9')) ||				\
+     ((c) == ' ') ||						\
+     ((c) == '\'') ||						\
+     ((c) == '\050') ||				/* ( */		\
+     ((c) == '\051') ||				/* ) */		\
+     (((c) >= '+') && ((c) <= '/')) ||		/* + , - . / */	\
+     ((c) == ':') ||						\
+     ((c) == '=') ||						\
+     ((c) == '?'))
+
+/* RFC 2253 says we must escape ",+\"\\<>;=" EXCEPT inside a quoted string.
+ * Inside a quoted string, we only need to escape " and \
+ * We choose to quote strings containing any of those special characters,
+ * so we only need to escape " and \
+ */
+#define NEEDS_ESCAPE(c) \
+    (c == C_DOUBLE_QUOTE || c == C_BACKSLASH)
+
+#define NEEDS_HEX_ESCAPE(c) \
+    ((PRUint8)c < 0x20 || c == 0x7f)
+
+int
+cert_AVAOidTagToMaxLen(SECOidTag tag)
+{
+    const NameToKind *n2k = name2kinds;
+
+    while (n2k->kind != tag && n2k->kind != SEC_OID_UNKNOWN) {
+	++n2k;
+    }
+    return (n2k->kind != SEC_OID_UNKNOWN) ? n2k->maxLen : -1;
+}
+
+static PRBool
+IsPrintable(unsigned char *data, unsigned len)
+{
+    unsigned char ch, *end;
+
+    end = data + len;
+    while (data < end) {
+	ch = *data++;
+	if (!IS_PRINTABLE(ch)) {
+	    return PR_FALSE;
+	}
+    }
+    return PR_TRUE;
+}
+
+static void
+skipSpace(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;
+}
+
+/* Returns the number of bytes in the value. 0 means failure. */
+static int
+scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize)  
+{
+    char *bp, *valBufp;
+    int vallen = 0;
+    PRBool isQuoted;
+    
+    PORT_Assert(valBufSize > 0);
+    
+    /* skip optional leading space */
+    skipSpace(pbp, endptr);
+    if(*pbp == endptr) {
+	/* nothing left */
+	return 0;
+    }
+    
+    bp = *pbp;
+    
+    /* quoted? */
+    if (*bp == C_DOUBLE_QUOTE) {
+	isQuoted = PR_TRUE;
+	/* skip over it */
+	bp++;
+    } else {
+	isQuoted = PR_FALSE;
+    }
+    
+    valBufp = valBuf;
+    while (bp < endptr) {
+	char c = *bp;
+	if (c == C_BACKSLASH) {
+	    /* escape character */
+	    bp++;
+	    if (bp >= endptr) {
+		/* escape charater must appear with paired char */
+		*pbp = bp;
+		return 0;
+	    }
+	    c = *bp;
+	    if (IS_HEX(c) && (endptr - bp) >= 2 && IS_HEX(bp[1])) {
+		bp++;
+		c = (char)((x2b[(PRUint8)c] << 4) | x2b[(PRUint8)*bp]); 
+	    }
+	} else if (c == '#' && bp == *pbp) {
+	    /* ignore leading #, quotation not required for it. */
+	} else if (!isQuoted && SPECIAL_CHAR(c)) {
+	    /* unescaped special and not within quoted value */
+	    break;
+	} else if (c == C_DOUBLE_QUOTE) {
+	    /* reached unescaped double quote */
+	    break;
+	}
+	/* append character */
+        vallen++;
+	if (vallen >= valBufSize) {
+	    *pbp = bp;
+	    return 0;
+	}
+	*valBufp++ = c;
+	bp++;
+    }
+    
+    /* strip trailing spaces from unquoted values */
+    if (!isQuoted) {
+	while (valBufp > valBuf) {
+	    char c = valBufp[-1];
+	    if (! OPTIONAL_SPACE(c))
+	        break;
+	    --valBufp;
+	}
+	vallen = valBufp - valBuf;
+    }
+    
+    if (isQuoted) {
+	/* insist that we stopped on a double quote */
+	if (*bp != C_DOUBLE_QUOTE) {
+	    *pbp = bp;
+	    return 0;
+	}
+	/* skip over the quote and skip optional space */
+	bp++;
+	skipSpace(&bp, endptr);
+    }
+    
+    *pbp = bp;
+    
+    /* null-terminate valBuf -- guaranteed at least one space left */
+    *valBufp = 0;
+    
+    return vallen;
+}
+
+/* Caller must set error code upon failure */
+static SECStatus
+hexToBin(PLArenaPool *pool, SECItem * destItem, const char * src, int len)
+{
+    PRUint8 * dest;
+
+    destItem->data = NULL; 
+    if (len <= 0 || (len & 1)) {
+	goto loser;
+    }
+    len >>= 1;
+    if (!SECITEM_AllocItem(pool, destItem, len))
+	goto loser;
+    dest = destItem->data;
+    for (; len > 0; len--, src += 2) {
+	PRInt16 bin = (x2b[(PRUint8)src[0]] << 4) | x2b[(PRUint8)src[1]]; 
+	if (bin < 0)
+	    goto loser;
+	*dest++ = (PRUint8)bin;
+    }
+    return SECSuccess;
+loser:
+    if (!pool)
+    	SECITEM_FreeItem(destItem, PR_FALSE);
+    return SECFailure;
+}
+
+/* Parses one AVA, starting at *pbp.  Stops at endptr.
+ * Advances *pbp past parsed AVA and trailing separator (if present).
+ * On any error, returns NULL and *pbp is undefined.
+ * On success, returns CERTAVA allocated from arena, and (*pbp)[-1] was 
+ * the last character parsed.  *pbp is either equal to endptr or 
+ * points to first character after separator.
+ */
+static CERTAVA *
+ParseRFC1485AVA(PRArenaPool *arena, char **pbp, char *endptr)
+{
+    CERTAVA *a;
+    const NameToKind *n2k;
+    char *bp;
+    int       vt = -1;
+    int       valLen;
+    SECOidTag kind  = SEC_OID_UNKNOWN;
+    SECStatus rv    = SECFailure;
+    SECItem   derOid = { 0, NULL, 0 };
+    SECItem   derVal = { 0, NULL, 0};
+    char      sep   = 0;
+
+    char tagBuf[32];
+    char valBuf[384];
+
+    PORT_Assert(arena);
+    if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) ||
+	!(valLen    = scanVal(pbp, endptr, valBuf, sizeof valBuf))) {
+	goto loser;
+    }
+
+    bp = *pbp;
+    if (bp < endptr) {
+	sep = *bp++; /* skip over separator */
+    }
+    *pbp = bp;
+    /* if we haven't finished, insist that we've stopped on a separator */
+    if (sep && sep != ',' && sep != ';' && sep != '+') {
+	goto loser;
+    }
+
+    /* is this a dotted decimal OID attribute type ? */
+    if (!PL_strncasecmp("oid.", tagBuf, 4)) {
+        rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf));
+    } else {
+	for (n2k = name2kinds; n2k->name; n2k++) {
+	    SECOidData *oidrec;
+	    if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) {
+		kind = n2k->kind;
+		vt   = n2k->valueType;
+		oidrec = SECOID_FindOIDByTag(kind);
+		if (oidrec == NULL)
+		    goto loser;
+		derOid = oidrec->oid;
+		break;
+	    }
+	}
+    }
+    if (kind == SEC_OID_UNKNOWN && rv != SECSuccess) 
+	goto loser;
+
+    /* Is this a hex encoding of a DER attribute value ? */
+    if ('#' == valBuf[0]) {
+    	/* convert attribute value from hex to binary */
+	rv = hexToBin(arena, &derVal, valBuf + 1, valLen - 1);
+	if (rv)
+	    goto loser;
+	a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
+    } else {
+	if (kind == SEC_OID_UNKNOWN)
+	    goto loser;
+	if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2)
+	    goto loser;
+	if (vt == SEC_ASN1_PRINTABLE_STRING &&
+	    !IsPrintable((unsigned char*) valBuf, valLen)) 
+	    goto loser;
+	if (vt == SEC_ASN1_DS) {
+	    /* RFC 4630: choose PrintableString or UTF8String */
+	    if (IsPrintable((unsigned char*) valBuf, valLen))
+		vt = SEC_ASN1_PRINTABLE_STRING;
+	    else 
+		vt = SEC_ASN1_UTF8_STRING;
+	}
+
+	derVal.data = valBuf;
+	derVal.len  = valLen;
+	a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal);
+    }
+    return a;
+
+loser:
+    /* matched no kind -- invalid tag */
+    PORT_SetError(SEC_ERROR_INVALID_AVA);
+    return 0;
+}
+
+static CERTName *
+ParseRFC1485Name(char *buf, int len)
+{
+    SECStatus rv;
+    CERTName *name;
+    char *bp, *e;
+    CERTAVA *ava;
+    CERTRDN *rdn = NULL;
+
+    name = CERT_CreateName(NULL);
+    if (name == NULL) {
+	return NULL;
+    }
+    
+    e = buf + len;
+    bp = buf;
+    while (bp < e) {
+	ava = ParseRFC1485AVA(name->arena, &bp, e);
+	if (ava == 0) 
+	    goto loser;
+	if (!rdn) {
+	    rdn = CERT_CreateRDN(name->arena, ava, (CERTAVA *)0);
+	    if (rdn == 0) 
+		goto loser;
+	    rv = CERT_AddRDN(name, rdn);
+	} else {
+	    rv = CERT_AddAVA(name->arena, rdn, ava);
+	}
+	if (rv) 
+	    goto loser;
+	if (bp[-1] != '+')
+	    rdn = NULL; /* done with this RDN */
+	skipSpace(&bp, e);
+    }
+
+    if (name->rdns[0] == 0) {
+	/* empty name -- illegal */
+	goto loser;
+    }
+
+    /* Reverse order of RDNS to comply with RFC */
+    {
+	CERTRDN **firstRdn;
+	CERTRDN **lastRdn;
+	CERTRDN *tmp;
+	
+	/* get first one */
+	firstRdn = name->rdns;
+	
+	/* find last one */
+	lastRdn = name->rdns;
+	while (*lastRdn) lastRdn++;
+	lastRdn--;
+	
+	/* reverse list */
+	for ( ; firstRdn < lastRdn; firstRdn++, lastRdn--) {
+	    tmp = *firstRdn;
+	    *firstRdn = *lastRdn;
+	    *lastRdn = tmp;
+	}
+    }
+    
+    /* return result */
+    return name;
+    
+  loser:
+    CERT_DestroyName(name);
+    return NULL;
+}
+
+CERTName *
+CERT_AsciiToName(char *string)
+{
+    CERTName *name;
+    name = ParseRFC1485Name(string, PORT_Strlen(string));
+    return name;
+}
+
+/************************************************************************/
+
+typedef struct stringBufStr {
+    char *buffer;
+    unsigned offset;
+    unsigned size;
+} stringBuf;
+
+#define DEFAULT_BUFFER_SIZE 200
+
+static SECStatus
+AppendStr(stringBuf *bufp, char *str)
+{
+    char *buf;
+    unsigned bufLen, bufSize, len;
+    int size = 0;
+
+    /* Figure out how much to grow buf by (add in the '\0') */
+    buf = bufp->buffer;
+    bufLen = bufp->offset;
+    len = PORT_Strlen(str);
+    bufSize = bufLen + len;
+    if (!buf) {
+	bufSize++;
+	size = PR_MAX(DEFAULT_BUFFER_SIZE,bufSize*2);
+	buf = (char *) PORT_Alloc(size);
+	bufp->size = size;
+    } else if (bufp->size < bufSize) {
+	size = bufSize*2;
+	buf =(char *) PORT_Realloc(buf,size);
+	bufp->size = size;
+    }
+    if (!buf) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    bufp->buffer = buf;
+    bufp->offset = bufSize;
+
+    /* Concatenate str onto buf */
+    buf = buf + bufLen;
+    if (bufLen) buf--;			/* stomp on old '\0' */
+    PORT_Memcpy(buf, str, len+1);		/* put in new null */
+    return SECSuccess;
+}
+
+typedef enum {
+    minimalEscape = 0,		/* only hex escapes, and " and \ */
+    minimalEscapeAndQuote,	/* as above, plus quoting        */
+    fullEscape                  /* no quoting, full escaping     */
+} EQMode;
+
+/* Some characters must be escaped as a hex string, e.g. c -> \nn .
+ * Others must be escaped by preceeding with a '\', e.g. c -> \c , but
+ * there are certain "special characters" that may be handled by either
+ * escaping them, or by enclosing the entire attribute value in quotes.
+ * A NULL value for pEQMode implies selecting minimalEscape mode.
+ * Some callers will do quoting when needed, others will not.
+ * If a caller selects minimalEscapeAndQuote, and the string does not
+ * need quoting, then this function changes it to minimalEscape.
+ */
+static int
+cert_RFC1485_GetRequiredLen(const char *src, int srclen, EQMode *pEQMode)
+{
+    int i, reqLen=0;
+    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
+    PRBool needsQuoting = PR_FALSE;
+    char lastC = 0;
+
+    /* need to make an initial pass to determine if quoting is needed */
+    for (i = 0; i < srclen; i++) {
+	char c = src[i];
+	reqLen++;
+	if (NEEDS_HEX_ESCAPE(c)) {      /* c -> \xx  */
+	    reqLen += 2;
+	} else if (NEEDS_ESCAPE(c)) {   /* c -> \c   */
+	    reqLen++;
+	} else if (SPECIAL_CHAR(c)) {
+	    if (mode == minimalEscapeAndQuote) /* quoting is allowed */
+		needsQuoting = PR_TRUE; /* entirety will need quoting */
+	    else if (mode == fullEscape)
+	    	reqLen++;               /* MAY escape this character */
+	} else if (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)) {
+	    if (mode == minimalEscapeAndQuote) /* quoting is allowed */
+		needsQuoting = PR_TRUE; /* entirety will need quoting */
+	}
+	lastC = c;
+    }
+    /* if it begins or ends in optional space it needs quoting */
+    if (!needsQuoting && srclen > 0 && mode == minimalEscapeAndQuote && 
+	(OPTIONAL_SPACE(src[srclen-1]) || OPTIONAL_SPACE(src[0]))) {
+	needsQuoting = PR_TRUE;
+    }
+
+    if (needsQuoting) 
+    	reqLen += 2;
+    if (pEQMode && mode == minimalEscapeAndQuote && !needsQuoting)
+    	*pEQMode = minimalEscape;
+    return reqLen;
+}
+
+static const char hexChars[16] = { "0123456789abcdef" };
+
+static SECStatus
+escapeAndQuote(char *dst, int dstlen, char *src, int srclen, EQMode *pEQMode)
+{
+    int i, reqLen=0;
+    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
+
+    /* space for terminal null */
+    reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &mode) + 1;
+    if (reqLen > dstlen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return SECFailure;
+    }
+
+    if (mode == minimalEscapeAndQuote)
+        *dst++ = C_DOUBLE_QUOTE;
+    for (i = 0; i < srclen; i++) {
+	char c = src[i];
+	if (NEEDS_HEX_ESCAPE(c)) {
+	    *dst++ = C_BACKSLASH;
+	    *dst++ = hexChars[ (c >> 4) & 0x0f ];
+	    *dst++ = hexChars[  c       & 0x0f ];
+	} else {
+	    if (NEEDS_ESCAPE(c) || (SPECIAL_CHAR(c) && mode == fullEscape)) {
+		*dst++ = C_BACKSLASH;
+	    }
+	    *dst++ = c;
+	}
+    }
+    if (mode == minimalEscapeAndQuote)
+    	*dst++ = C_DOUBLE_QUOTE;
+    *dst++ = 0;
+    if (pEQMode)
+    	*pEQMode = mode;
+    return SECSuccess;
+}
+
+SECStatus
+CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen)
+{
+    EQMode mode = minimalEscapeAndQuote;
+    return escapeAndQuote(dst, dstlen, src, srclen, &mode);
+}
+
+
+/* convert an OID to dotted-decimal representation */
+/* Returns a string that must be freed with PR_smprintf_free(), */
+char *
+CERT_GetOidString(const SECItem *oid)
+{
+    PRUint8 *stop;   /* points to first byte after OID string */
+    PRUint8 *first;  /* byte of an OID component integer      */
+    PRUint8 *last;   /* byte of an OID component integer      */
+    char *rvString   = NULL;
+    char *prefix     = NULL;
+
+#define MAX_OID_LEN 1024 /* bytes */
+
+    if (oid->len > MAX_OID_LEN) {
+    	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	return NULL;
+    }
+
+    /* first will point to the next sequence of bytes to decode */
+    first = (PRUint8 *)oid->data;
+    /* stop points to one past the legitimate data */
+    stop = &first[ oid->len ];
+
+    /*
+     * Check for our pseudo-encoded single-digit OIDs
+     */
+    if ((*first == 0x80) && (2 == oid->len)) {
+	/* Funky encoding.  The second byte is the number */
+	rvString = PR_smprintf("%lu", (PRUint32)first[1]);
+	if (!rvString) {
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	}
+	return rvString;
+    }
+
+    for (; first < stop; first = last + 1) {
+    	unsigned int bytesBeforeLast;
+    
+	for (last = first; last < stop; last++) {
+	    if (0 == (*last & 0x80)) {
+		break;
+	    }
+	}
+	bytesBeforeLast = (unsigned int)(last - first);
+	if (bytesBeforeLast <= 3U) {        /* 0-28 bit number */
+	    PRUint32 n = 0;
+	    PRUint32 c;
+
+#define CGET(i, m) \
+		c  = last[-i] & m; \
+		n |= c << (7 * i)
+
+#define CASE(i, m) \
+	    case i:                      \
+		CGET(i, m);              \
+		if (!n) goto unsupported \
+		/* fall-through */
+
+	    switch (bytesBeforeLast) {
+	    CASE(3, 0x7f);
+	    CASE(2, 0x7f);
+	    CASE(1, 0x7f);
+	    case 0: n |= last[0] & 0x7f;
+		break;
+	    }
+	    if (last[0] & 0x80)
+	    	goto unsupported;
+      
+	    if (!rvString) {
+		/* This is the first number.. decompose it */
+		PRUint32 one = PR_MIN(n/40, 2); /* never > 2 */
+		PRUint32 two = n - (one * 40);
+        
+		rvString = PR_smprintf("OID.%lu.%lu", one, two);
+	    } else {
+		prefix = rvString;
+		rvString = PR_smprintf("%s.%lu", prefix, n);
+	    }
+	} else if (bytesBeforeLast <= 9U) { /* 29-64 bit number */
+	    PRUint64 n = 0;
+	    PRUint64 c;
+
+	    switch (bytesBeforeLast) {
+	    CASE(9, 0x01);
+	    CASE(8, 0x7f);
+	    CASE(7, 0x7f);
+	    CASE(6, 0x7f);
+	    CASE(5, 0x7f);
+	    CASE(4, 0x7f);
+	    CGET(3, 0x7f);
+	    CGET(2, 0x7f);
+	    CGET(1, 0x7f);
+	    CGET(0, 0x7f);
+		break;
+	    }
+	    if (last[0] & 0x80)
+	    	goto unsupported;
+      
+	    if (!rvString) {
+		/* This is the first number.. decompose it */
+		PRUint64 one = PR_MIN(n/40, 2); /* never > 2 */
+		PRUint64 two = n - (one * 40);
+        
+		rvString = PR_smprintf("OID.%llu.%llu", one, two);
+	    } else {
+		prefix = rvString;
+		rvString = PR_smprintf("%s.%llu", prefix, n);
+	    }
+	} else {
+	    /* More than a 64-bit number, or not minimal encoding. */
+unsupported:
+	    if (!rvString)
+		rvString = PR_smprintf("OID.UNSUPPORTED");
+	    else {
+		prefix = rvString;
+		rvString = PR_smprintf("%s.UNSUPPORTED", prefix);
+	    }
+	}
+
+	if (prefix) {
+	    PR_smprintf_free(prefix);
+	    prefix = NULL;
+	}
+	if (!rvString) {
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    break;
+	}
+    }
+    return rvString;
+}
+
+/* convert DER-encoded hex to a string */
+static SECItem *
+get_hex_string(SECItem *data)
+{
+    SECItem *rv;
+    unsigned int i, j;
+    static const char hex[] = { "0123456789ABCDEF" };
+
+    /* '#' + 2 chars per octet + terminator */
+    rv = SECITEM_AllocItem(NULL, NULL, data->len*2 + 2);
+    if (!rv) {
+	return NULL;
+    }
+    rv->data[0] = '#';
+    rv->len = 1 + 2 * data->len;
+    for (i=0; i<data->len; i++) {
+	j = data->data[i];
+	rv->data[2*i+1] = hex[j >> 4];
+	rv->data[2*i+2] = hex[j & 15];
+    }
+    rv->data[rv->len] = 0;
+    return rv;
+}
+
+/* For compliance with RFC 2253, RFC 3280 and RFC 4630, we choose to 
+ * use the NAME=STRING form, rather than the OID.N.N=#hexXXXX form, 
+ * when both of these conditions are met:
+ *  1) The attribute name OID (kind) has a known name string that is 
+ *     defined in one of those RFCs, or in RFCs that they cite, AND
+ *  2) The attribute's value encoding is RFC compliant for the kind
+ *     (e.g., the value's encoding tag is correct for the kind, and
+ *     the value's length is in the range allowed for the kind, and
+ *     the value's contents are appropriate for the encoding tag).
+ *  Otherwise, we use the OID.N.N=#hexXXXX form.
+ *
+ *  If the caller prefers maximum human readability to RFC compliance,
+ *  then 
+ *  - We print the kind in NAME= string form if we know the name
+ *    string for the attribute type OID, regardless of whether the 
+ *    value is correctly encoded or not. else we use the OID.N.N= form.
+ *  - We use the non-hex STRING form for the attribute value if the
+ *    value can be represented in such a form.  Otherwise, we use 
+ *    the hex string form.
+ *  This implies that, for maximum human readability, in addition to 
+ *  the two forms allowed by the RFC, we allow two other forms of output:
+ *  - the OID.N.N=STRING form, and 
+ *  - the NAME=#hexXXXX form
+ *  When the caller prefers maximum human readability, we do not allow
+ *  the value of any attribute to exceed the length allowed by the RFC.
+ *  If the attribute value exceeds the allowed length, we truncate it to 
+ *  the allowed length and append "...".
+ *  Also in this case, we arbitrarily impose a limit on the length of the 
+ *  entire AVA encoding, regardless of the form, of 384 bytes per AVA.
+ *  This limit includes the trailing NULL character.  If the encoded 
+ *  AVA length exceeds that limit, this function reports failure to encode
+ *  the AVA.
+ *
+ *  An ASCII representation of an AVA is said to be "invertible" if 
+ *  conversion back to DER reproduces the original DER encoding exactly.
+ *  The RFC 2253 rules do not ensure that all ASCII AVAs derived according
+ *  to its rules are invertible. That is because the RFCs allow some 
+ *  attribute values to be encoded in any of a number of encodings,
+ *  and the encoding type information is lost in the non-hex STRING form.
+ *  This is particularly true of attributes of type DirectoryString.
+ *  The encoding type information is always preserved in the hex string 
+ *  form, because the hex includes the entire DER encoding of the value.
+ *
+ *  So, when the caller perfers maximum invertibility, we apply the 
+ *  RFC compliance rules stated above, and add a third required 
+ *  condition on the use of the NAME=STRING form.  
+ *   3) The attribute's kind is not is allowed to be encoded in any of 
+ *      several different encodings, such as DirectoryStrings.
+ *
+ * The chief difference between CERT_N2A_STRICT and CERT_N2A_INVERTIBLE
+ * is that the latter forces DirectoryStrings to be hex encoded.
+ *
+ * As a simplification, we assume the value is correctly encoded for 
+ * its encoding type.  That is, we do not test that all the characters
+ * in a string encoded type are allowed by that type.  We assume it.
+ */
+static SECStatus
+AppendAVA(stringBuf *bufp, CERTAVA *ava, CertStrictnessLevel strict)
+{
+#define TMPBUF_LEN 384
+    const NameToKind *pn2k   = name2kinds;
+    SECItem     *avaValue    = NULL;
+    char        *unknownTag  = NULL;
+    char        *encodedAVA  = NULL;
+    PRBool       useHex      = PR_FALSE;  /* use =#hexXXXX form */
+    PRBool       truncateName  = PR_FALSE;
+    PRBool       truncateValue = PR_FALSE;
+    SECOidTag    endKind;
+    SECStatus    rv;
+    unsigned int len;
+    unsigned int nameLen, valueLen;
+    unsigned int maxName, maxValue;
+    EQMode       mode        = minimalEscapeAndQuote;
+    NameToKind   n2k         = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS };
+    char         tmpBuf[TMPBUF_LEN];
+
+#define tagName  n2k.name    /* non-NULL means use NAME= form */
+#define maxBytes n2k.maxLen
+#define tag      n2k.kind
+#define vt       n2k.valueType
+
+    /* READABLE mode recognizes more names from the name2kinds table
+     * than do STRICT or INVERTIBLE modes.  This assignment chooses the
+     * point in the table where the attribute type name scanning stops.
+     */
+    endKind = (strict == CERT_N2A_READABLE) ? SEC_OID_UNKNOWN
+                                            : SEC_OID_AVA_POSTAL_ADDRESS;
+    tag = CERT_GetAVATag(ava);
+    while (pn2k->kind != tag && pn2k->kind != endKind) {
+        ++pn2k;
+    }
+
+    if (pn2k->kind != endKind ) {
+        n2k = *pn2k;
+    } else if (strict != CERT_N2A_READABLE) {
+        useHex = PR_TRUE;
+    }
+    /* For invertable form, force Directory Strings to use hex form. */
+    if (strict == CERT_N2A_INVERTIBLE && vt == SEC_ASN1_DS) {
+	tagName = NULL;      /* must use OID.N form */
+	useHex = PR_TRUE;    /* must use hex string */
+    }
+    if (!useHex) {
+	avaValue = CERT_DecodeAVAValue(&ava->value);
+	if (!avaValue) {
+	    useHex = PR_TRUE;
+	    if (strict != CERT_N2A_READABLE) {
+		tagName = NULL;  /* must use OID.N form */
+	    }
+	}
+    }
+    if (!tagName) {
+	/* handle unknown attribute types per RFC 2253 */
+	tagName = unknownTag = CERT_GetOidString(&ava->type);
+	if (!tagName) {
+	    if (avaValue)
+		SECITEM_FreeItem(avaValue, PR_TRUE);
+	    return SECFailure;
+	}
+    }
+    if (useHex) {
+	avaValue = get_hex_string(&ava->value);
+	if (!avaValue) {
+	    if (unknownTag) 
+	    	PR_smprintf_free(unknownTag);
+	    return SECFailure;
+	}
+    }
+
+    nameLen  = strlen(tagName);
+    valueLen = (useHex ? avaValue->len : 
+		cert_RFC1485_GetRequiredLen(avaValue->data, avaValue->len, 
+					    &mode));
+    len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */
+
+    maxName  = nameLen;
+    maxValue = valueLen;
+    if (len <= sizeof(tmpBuf)) {
+    	encodedAVA = tmpBuf;
+    } else if (strict != CERT_N2A_READABLE) {
+	encodedAVA = PORT_Alloc(len);
+	if (!encodedAVA) {
+	    SECITEM_FreeItem(avaValue, PR_TRUE);
+	    if (unknownTag) 
+		PR_smprintf_free(unknownTag);
+	    return SECFailure;
+	}
+    } else {
+	/* Must make output fit in tmpbuf */
+	unsigned int fair = (sizeof tmpBuf)/2 - 1; /* for = and \0 */
+
+	if (nameLen < fair) {
+	    /* just truncate the value */
+	    maxValue = (sizeof tmpBuf) - (nameLen + 6); /* for "=...\0",
+                                                           and possibly '"' */
+	} else if (valueLen < fair) {
+	    /* just truncate the name */
+	    maxName  = (sizeof tmpBuf) - (valueLen + 5); /* for "=...\0" */
+	} else {
+	    /* truncate both */
+	    maxName = maxValue = fair - 3;  /* for "..." */
+	}
+	if (nameLen > maxName) {
+	    PORT_Assert(unknownTag && unknownTag == tagName);
+	    truncateName = PR_TRUE;
+	    nameLen = maxName;
+	}
+    	encodedAVA = tmpBuf;
+    }
+
+    memcpy(encodedAVA, tagName, nameLen);
+    if (truncateName) {
+	/* If tag name is too long, we know it is an OID form that was 
+	 * allocated from the heap, so we can modify it in place 
+	 */
+	encodedAVA[nameLen-1] = '.';
+	encodedAVA[nameLen-2] = '.';
+	encodedAVA[nameLen-3] = '.';
+    }
+    encodedAVA[nameLen++] = '=';
+    if (unknownTag) 
+    	PR_smprintf_free(unknownTag);
+
+    if (strict == CERT_N2A_READABLE && maxValue > maxBytes)
+	maxValue = maxBytes;
+    if (valueLen > maxValue) {
+    	valueLen = maxValue;
+	truncateValue = PR_TRUE;
+    }
+    /* escape and quote as necessary - don't quote hex strings */
+    if (useHex) {
+	char * end = encodedAVA + nameLen + valueLen;
+	memcpy(encodedAVA + nameLen, (char *)avaValue->data, valueLen);
+	end[0] = '\0';
+	if (truncateValue) {
+	    end[-1] = '.';
+	    end[-2] = '.';
+	    end[-3] = '.';
+	}
+	rv = SECSuccess;
+    } else if (!truncateValue) {
+	rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen, 
+			    (char *)avaValue->data, avaValue->len, &mode);
+    } else {
+	/* must truncate the escaped and quoted value */
+	char bigTmpBuf[TMPBUF_LEN * 3 + 3];
+	rv = escapeAndQuote(bigTmpBuf, sizeof bigTmpBuf,
+			    (char *)avaValue->data, valueLen, &mode);
+
+	bigTmpBuf[valueLen--] = '\0'; /* hard stop here */
+	/* See if we're in the middle of a multi-byte UTF8 character */
+	while (((bigTmpBuf[valueLen] & 0xc0) == 0x80) && valueLen > 0) {
+	    bigTmpBuf[valueLen--] = '\0';
+	}
+	/* add ellipsis to signify truncation. */
+	bigTmpBuf[++valueLen] = '.';
+	bigTmpBuf[++valueLen] = '.';
+	bigTmpBuf[++valueLen] = '.';
+	if (bigTmpBuf[0] == '"')
+	    bigTmpBuf[++valueLen] = '"';
+	bigTmpBuf[++valueLen] = '\0';
+	PORT_Assert(nameLen + valueLen <= (sizeof tmpBuf) - 1);
+	memcpy(encodedAVA + nameLen, bigTmpBuf, valueLen+1);
+    }
+
+    SECITEM_FreeItem(avaValue, PR_TRUE);
+    if (rv == SECSuccess)
+	rv = AppendStr(bufp, encodedAVA);
+    if (encodedAVA != tmpBuf)
+    	PORT_Free(encodedAVA);
+    return rv;
+}
+
+#undef tagName
+#undef maxBytes
+#undef tag
+#undef vt
+
+char *
+CERT_NameToAsciiInvertible(CERTName *name, CertStrictnessLevel strict)
+{
+    CERTRDN** rdns;
+    CERTRDN** lastRdn;
+    CERTRDN** rdn;
+    PRBool first = PR_TRUE;
+    stringBuf strBuf = { NULL, 0, 0 };
+    
+    rdns = name->rdns;
+    if (rdns == NULL) {
+	return NULL;
+    }
+    
+    /* find last RDN */
+    lastRdn = rdns;
+    while (*lastRdn) lastRdn++;
+    lastRdn--;
+    
+    /*
+     * Loop over name contents in _reverse_ RDN order appending to string
+     */
+    for (rdn = lastRdn; rdn >= rdns; rdn--) {
+	CERTAVA** avas = (*rdn)->avas;
+	CERTAVA* ava;
+	PRBool newRDN = PR_TRUE;
+
+	/* 
+	 * XXX Do we need to traverse the AVAs in reverse order, too?
+	 */
+	while (avas && (ava = *avas++) != NULL) {
+	    SECStatus rv;
+	    /* Put in comma or plus separator */
+	    if (!first) {
+		/* Use of spaces is deprecated in RFC 2253. */
+		rv = AppendStr(&strBuf, newRDN ? "," : "+");
+		if (rv) goto loser;
+	    } else {
+		first = PR_FALSE;
+	    }
+	    
+	    /* Add in tag type plus value into strBuf */
+	    rv = AppendAVA(&strBuf, ava, strict);
+	    if (rv) goto loser;
+	    newRDN = PR_FALSE;
+	}
+    }
+    return strBuf.buffer;
+loser:
+    if (strBuf.buffer) {
+	PORT_Free(strBuf.buffer);
+    }
+    return NULL;
+}
+
+char *
+CERT_NameToAscii(CERTName *name)
+{
+    return CERT_NameToAsciiInvertible(name, CERT_N2A_READABLE);
+}
+
+/*
+ * Return the string representation of a DER encoded distinguished name
+ * "dername" - The DER encoded name to convert
+ */
+char *
+CERT_DerNameToAscii(SECItem *dername)
+{
+    int rv;
+    PRArenaPool *arena = NULL;
+    CERTName name;
+    char *retstr = NULL;
+    
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    
+    if ( arena == NULL) {
+	goto loser;
+    }
+    
+    rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, dername);
+    
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+
+    retstr = CERT_NameToAscii(&name);
+
+loser:
+    if ( arena != NULL ) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    
+    return(retstr);
+}
+
+static char *
+avaToString(PRArenaPool *arena, CERTAVA *ava)
+{
+    char *    buf       = NULL;
+    SECItem*  avaValue;
+    int       valueLen;
+
+    avaValue = CERT_DecodeAVAValue(&ava->value);
+    if(!avaValue) {
+	return buf;
+    }
+    valueLen = cert_RFC1485_GetRequiredLen(avaValue->data, avaValue->len, 
+					   NULL) + 1;
+    if (arena) {
+	buf = (char *)PORT_ArenaZAlloc(arena, valueLen);
+    } else {
+	buf = (char *)PORT_ZAlloc(valueLen);
+    }
+    if (buf) {
+	SECStatus rv = escapeAndQuote(buf, valueLen, (char *)avaValue->data, 
+	                              avaValue->len, NULL);
+	if (rv != SECSuccess) {
+	    if (!arena)
+		PORT_Free(buf);
+	    buf = NULL;
+	}
+    }
+    SECITEM_FreeItem(avaValue, PR_TRUE);
+    return buf;
+}
+
+/* RDNs are sorted from most general to most specific.
+ * This code returns the FIRST one found, the most general one found.
+ */
+static char *
+CERT_GetNameElement(PRArenaPool *arena, CERTName *name, int wantedTag)
+{
+    CERTRDN** rdns = name->rdns;
+    CERTRDN*  rdn;
+    CERTAVA*  ava  = NULL;
+
+    while (rdns && (rdn = *rdns++) != 0) {
+	CERTAVA** avas = rdn->avas;
+	while (avas && (ava = *avas++) != 0) {
+	    int tag = CERT_GetAVATag(ava);
+	    if ( tag == wantedTag ) {
+		avas = NULL;
+		rdns = NULL; /* break out of all loops */
+	    }
+	}
+    }
+    return ava ? avaToString(arena, ava) : NULL;
+}
+
+/* RDNs are sorted from most general to most specific.
+ * This code returns the LAST one found, the most specific one found.
+ * This is particularly appropriate for Common Name.  See RFC 2818.
+ */
+static char *
+CERT_GetLastNameElement(PRArenaPool *arena, CERTName *name, int wantedTag)
+{
+    CERTRDN** rdns    = name->rdns;
+    CERTRDN*  rdn;
+    CERTAVA*  lastAva = NULL;
+    
+    while (rdns && (rdn = *rdns++) != 0) {
+	CERTAVA** avas = rdn->avas;
+	CERTAVA*  ava;
+	while (avas && (ava = *avas++) != 0) {
+	    int tag = CERT_GetAVATag(ava);
+	    if ( tag == wantedTag ) {
+		lastAva = ava;
+	    }
+	}
+    }
+    return lastAva ? avaToString(arena, lastAva) : NULL;
+}
+
+char *
+CERT_GetCertificateEmailAddress(CERTCertificate *cert)
+{
+    char *rawEmailAddr = NULL;
+    SECItem subAltName;
+    SECStatus rv;
+    CERTGeneralName *nameList = NULL;
+    CERTGeneralName *current;
+    PRArenaPool *arena = NULL;
+    int i;
+    
+    subAltName.data = NULL;
+
+    rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject),
+						 SEC_OID_PKCS9_EMAIL_ADDRESS);
+    if ( rawEmailAddr == NULL ) {
+	rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject), 
+							SEC_OID_RFC1274_MAIL);
+    }
+    if ( rawEmailAddr == NULL) {
+
+	rv = CERT_FindCertExtension(cert,  SEC_OID_X509_SUBJECT_ALT_NAME, 
+								&subAltName);
+	if (rv != SECSuccess) {
+	    goto finish;
+	}
+	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+	if (!arena) {
+	    goto finish;
+	}
+	nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
+	if (!nameList ) {
+	    goto finish;
+	}
+	if (nameList != NULL) {
+	    do {
+		if (current->type == certDirectoryName) {
+		    rawEmailAddr = CERT_GetNameElement(cert->arena,
+			&(current->name.directoryName), 
+					       SEC_OID_PKCS9_EMAIL_ADDRESS);
+		    if ( rawEmailAddr == NULL ) {
+			rawEmailAddr = CERT_GetNameElement(cert->arena,
+			  &(current->name.directoryName), SEC_OID_RFC1274_MAIL);
+		    }
+		} else if (current->type == certRFC822Name) {
+		    rawEmailAddr = (char*)PORT_ArenaZAlloc(cert->arena,
+						current->name.other.len + 1);
+		    if (!rawEmailAddr) {
+			goto finish;
+		    }
+		    PORT_Memcpy(rawEmailAddr, current->name.other.data, 
+				current->name.other.len);
+		    rawEmailAddr[current->name.other.len] = '\0';
+		}
+		if (rawEmailAddr) {
+		    break;
+		}
+		current = CERT_GetNextGeneralName(current);
+	    } while (current != nameList);
+	}
+    }
+    if (rawEmailAddr) {
+	for (i = 0; i <= (int) PORT_Strlen(rawEmailAddr); i++) {
+	    rawEmailAddr[i] = tolower(rawEmailAddr[i]);
+	}
+    } 
+
+finish:
+
+    /* Don't free nameList, it's part of the arena. */
+
+    if (arena) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+
+    if ( subAltName.data ) {
+	SECITEM_FreeItem(&subAltName, PR_FALSE);
+    }
+
+    return(rawEmailAddr);
+}
+
+static char *
+appendStringToBuf(char *dest, char *src, PRUint32 *pRemaining)
+{
+    PRUint32 len;
+    if (dest && src && src[0] && *pRemaining > (len = PL_strlen(src))) {
+	PRUint32 i;
+	for (i = 0; i < len; ++i)
+	    dest[i] = tolower(src[i]);
+	dest[len] = 0;
+	dest        += len + 1;
+	*pRemaining -= len + 1;
+    }
+    return dest;
+}
+
+#undef NEEDS_HEX_ESCAPE
+#define NEEDS_HEX_ESCAPE(c) (c < 0x20)
+
+static char *
+appendItemToBuf(char *dest, SECItem *src, PRUint32 *pRemaining)
+{
+    if (dest && src && src->data && src->len && src->data[0]) {
+	PRUint32 len = src->len;
+	PRUint32 i;
+	PRUint32 reqLen = len + 1;
+	/* are there any embedded control characters ? */
+	for (i = 0; i < len; i++) {
+	    if (NEEDS_HEX_ESCAPE(src->data[i]))
+	    	reqLen += 2;   
+	}
+	if (*pRemaining > reqLen) {
+	    for (i = 0; i < len; ++i) {
+		PRUint8 c = src->data[i];
+		if (NEEDS_HEX_ESCAPE(c)) {
+		    *dest++ = C_BACKSLASH;
+		    *dest++ = hexChars[ (c >> 4) & 0x0f ];
+		    *dest++ = hexChars[  c       & 0x0f ];
+		} else {
+		    *dest++ = tolower(c);
+	    	}
+	    }
+	    *dest++ = '\0';
+	    *pRemaining -= reqLen;
+	}
+    }
+    return dest;
+}
+
+/* Returns a pointer to an environment-like string, a series of 
+** null-terminated strings, terminated by a zero-length string.
+** This function is intended to be internal to NSS.
+*/
+char *
+cert_GetCertificateEmailAddresses(CERTCertificate *cert)
+{
+    char *           rawEmailAddr = NULL;
+    char *           addrBuf      = NULL;
+    char *           pBuf         = NULL;
+    PRArenaPool *    tmpArena     = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    PRUint32         maxLen       = 0;
+    PRInt32          finalLen     = 0;
+    SECStatus        rv;
+    SECItem          subAltName;
+    
+    if (!tmpArena) 
+    	return addrBuf;
+
+    subAltName.data = NULL;
+    maxLen = cert->derCert.len;
+    PORT_Assert(maxLen);
+    if (!maxLen) 
+	maxLen = 2000;  /* a guess, should never happen */
+
+    pBuf = addrBuf = (char *)PORT_ArenaZAlloc(tmpArena, maxLen + 1);
+    if (!addrBuf) 
+    	goto loser;
+
+    rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject,
+				       SEC_OID_PKCS9_EMAIL_ADDRESS);
+    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
+
+    rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject, 
+				       SEC_OID_RFC1274_MAIL);
+    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
+
+    rv = CERT_FindCertExtension(cert,  SEC_OID_X509_SUBJECT_ALT_NAME, 
+				&subAltName);
+    if (rv == SECSuccess && subAltName.data) {
+	CERTGeneralName *nameList     = NULL;
+
+	if (!!(nameList = CERT_DecodeAltNameExtension(tmpArena, &subAltName))) {
+	    CERTGeneralName *current = nameList;
+	    do {
+		if (current->type == certDirectoryName) {
+		    rawEmailAddr = CERT_GetNameElement(tmpArena,
+			                       &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_GetNextGeneralName(current);
+	    } while (current != nameList);
+	}
+	SECITEM_FreeItem(&subAltName, PR_FALSE);
+	/* Don't free nameList, it's part of the tmpArena. */
+    }
+    /* now copy superstring to cert's arena */
+    finalLen = (pBuf - addrBuf) + 1;
+    pBuf = NULL;
+    if (finalLen > 1) {
+	pBuf = PORT_ArenaAlloc(cert->arena, finalLen);
+	if (pBuf) {
+	    PORT_Memcpy(pBuf, addrBuf, finalLen);
+	}
+    }
+loser:
+    if (tmpArena)
+	PORT_FreeArena(tmpArena, PR_FALSE);
+
+    return pBuf;
+}
+
+/* returns pointer to storage in cert's arena.  Storage remains valid
+** as long as cert's reference count doesn't go to zero.
+** Caller should strdup or otherwise copy.
+*/
+const char *	/* const so caller won't muck with it. */
+CERT_GetFirstEmailAddress(CERTCertificate * cert)
+{
+    if (cert && cert->emailAddr && cert->emailAddr[0])
+    	return (const char *)cert->emailAddr;
+    return NULL;
+}
+
+/* returns pointer to storage in cert's arena.  Storage remains valid
+** as long as cert's reference count doesn't go to zero.
+** Caller should strdup or otherwise copy.
+*/
+const char *	/* const so caller won't muck with it. */
+CERT_GetNextEmailAddress(CERTCertificate * cert, const char * prev)
+{
+    if (cert && prev && prev[0]) {
+    	PRUint32 len = PL_strlen(prev);
+	prev += len + 1;
+	if (prev && prev[0])
+	    return prev;
+    }
+    return NULL;
+}
+
+/* This is seriously bogus, now that certs store their email addresses in
+** subject Alternative Name extensions. 
+** Returns a string allocated by PORT_StrDup, which the caller must free.
+*/
+char *
+CERT_GetCertEmailAddress(CERTName *name)
+{
+    char *rawEmailAddr;
+    char *emailAddr;
+
+    
+    rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_PKCS9_EMAIL_ADDRESS);
+    if ( rawEmailAddr == NULL ) {
+	rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_MAIL);
+    }
+    emailAddr = CERT_FixupEmailAddr(rawEmailAddr);
+    if ( rawEmailAddr ) {
+	PORT_Free(rawEmailAddr);
+    }
+    return(emailAddr);
+}
+
+/* The return value must be freed with PORT_Free. */
+char *
+CERT_GetCommonName(CERTName *name)
+{
+    return(CERT_GetLastNameElement(NULL, name, SEC_OID_AVA_COMMON_NAME));
+}
+
+char *
+CERT_GetCountryName(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_COUNTRY_NAME));
+}
+
+char *
+CERT_GetLocalityName(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_LOCALITY));
+}
+
+char *
+CERT_GetStateName(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_STATE_OR_PROVINCE));
+}
+
+char *
+CERT_GetOrgName(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATION_NAME));
+}
+
+char *
+CERT_GetDomainComponentName(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DC));
+}
+
+char *
+CERT_GetOrgUnitName(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME));
+}
+
+char *
+CERT_GetDnQualifier(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DN_QUALIFIER));
+}
+
+char *
+CERT_GetCertUid(CERTName *name)
+{
+    return(CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_UID));
+}
+
diff --git a/mozilla/security/nss/lib/certdb/cert.h b/mozilla/security/nss/lib/certdb/cert.h
new file mode 100644
index 0000000..a23a85d
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/cert.h
@@ -0,0 +1,1677 @@
+/* ***** 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 ***** */
+
+/*
+ * cert.h - public data structures and prototypes for the certificate library
+ *
+ * $Id: cert.h,v 1.79 2010/01/14 22:15:23 alexei.volkov.bugs%sun.com Exp $
+ */
+
+#ifndef _CERT_H_
+#define _CERT_H_
+
+#include "utilrename.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.
+** Returns a string that must be freed with PORT_Free().
+** This version produces a string for maximum human readability,
+** not for strict RFC compliance.
+*/
+extern char *CERT_NameToAscii(CERTName *name);
+
+/*
+** Convert an CERTName into its RFC1485 encoded equivalent.
+** Returns a string that must be freed with PORT_Free().
+** Caller chooses encoding rules.
+*/
+extern char *CERT_NameToAsciiInvertible(CERTName *name, 
+                                        CertStrictnessLevel strict);
+
+extern CERTAVA *CERT_CopyAVA(PLArenaPool *arena, CERTAVA *src);
+
+/* convert an OID to dotted-decimal representation */
+/* Returns a string that must be freed with PR_smprintf_free(). */
+extern char * CERT_GetOidString(const SECItem *oid);
+
+/*
+** 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(const CERTAVA *a, const CERTAVA *b);
+
+/*
+** Create an RDN (relative-distinguished-name). The argument list is a
+** NULL terminated list of AVA's.
+*/
+extern CERTRDN *CERT_CreateRDN(PLArenaPool *arena, CERTAVA *avas, ...);
+
+/*
+** Make a copy of "src" storing it in "dest".
+*/
+extern SECStatus CERT_CopyRDN(PLArenaPool *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(PLArenaPool *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(PLArenaPool *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);
+
+/*
+** Converts DER string (with explicit length) into zString, if destination 
+** buffer is big enough to receive it.  Does quoting and/or escaping as 
+** specified in RFC 1485.  Input string must be single or multi-byte DER
+** character set, (ASCII, UTF8, or ISO 8851-x) not a wide character set.
+** Returns SECSuccess or SECFailure with error code set. If output buffer
+** is too small, sets error code SEC_ERROR_OUTPUT_LEN.
+*/
+extern SECStatus
+CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen);
+
+/******************************************************************************
+ *
+ * Certificate handling operations
+ *
+ *****************************************************************************/
+
+/*
+** 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(PRTime notBefore, PRTime 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
+   (PLArenaPool *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);
+
+/*
+** Start adding extensions to a certificate request.
+*/
+void *
+CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req);
+
+/*
+** Reformat the certificate extension list into a CertificateRequest
+** attribute list.
+*/
+SECStatus
+CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req);
+
+/*
+** Extract the Extension Requests from a DER CertRequest attribute list.
+*/
+SECStatus
+CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
+                                     CERTCertExtension ***exts);
+
+/*
+** Extract a public key object from a certificate
+*/
+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, 
+					       PRTime 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
+   (PLArenaPool *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);
+
+extern SECItem *
+CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest,
+		       PLArenaPool *arena);
+
+extern CERTGeneralName *
+CERT_DecodeGeneralName(PLArenaPool *reqArena, SECItem *encodedName,
+		       CERTGeneralName  *genName);
+
+
+
+/*
+** 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(PLArenaPool *reqArena, SECItem *derCert,
+                                     SECItem *key);
+
+extern SECStatus CERT_KeyFromIssuerAndSN(PLArenaPool *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(PLArenaPool *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);
+
+/*
+** Extract the list of host names, host name patters, IP address strings
+** this cert is valid for.
+** This function does NOT return nicknames.
+** Type CERTCertNicknames is being used because it's a convenient 
+** data structure to carry a list of strings and its count.
+*/
+extern CERTCertNicknames *
+  CERT_GetValidDNSPatternsFromCert(CERTCertificate *cert);
+
+/*
+** 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 (PLArenaPool *arena, SECItem *derSignedCrl,int type);
+
+/*
+ * same as CERT_DecodeDERCrl, plus allow options to be passed in
+ */
+
+extern CERTSignedCrl *
+CERT_DecodeDERCrlWithFlags(PLArenaPool *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
+#define CRL_DECODE_ADOPT_HEAP_DER           0x00000008
+
+/* 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);
+
+/* add the specified DER CRL object to the CRL cache. Doing so will allow
+   certificate verification functions (such as CERT_VerifyCertificate)
+   to automatically find and make use of this CRL object.
+   Once a CRL is added to the CRL cache, the application must hold on to
+   the object's memory, because the cache will reference it directly. The
+   application can only free the object after it calls CERT_UncacheCRL to
+   remove it from the CRL cache.
+*/
+SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newcrl);
+
+/* remove a previously added CRL object from the CRL cache. It is OK
+   for the application to free the memory after a successful removal
+*/
+SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* oldcrl);
+
+/*
+** 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);
+
+/*
+** Encode Certificate SKID (Subject Key ID) extension.
+**
+*/
+extern SECStatus 
+CERT_EncodeSubjectKeyID(PLArenaPool *arena, const SECItem* srcString,
+                        SECItem *encodedValue);
+
+/*
+** Find a certificate in the database by a nickname
+**	"nickname" is the ascii string nickname to look for
+*/
+extern CERTCertificate *
+CERT_FindCertByNickname (CERTCertDBHandle *handle, const 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, const 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, PRTime 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 deprecated, 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(PLArenaPool *, 
+							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,
+				       PRTime 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,
+                PRTime 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, PRTime 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, PRTime 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, PRTime t,
+		     void *wincx, CERTVerifyLog *log);
+
+/*
+** 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);
+
+/* 
+** 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(const SECItem *derAVAValue);
+
+
+
+/*
+** extract various element strings from a distinguished name.
+**	"name" the distinguished 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);
+
+/* The return value must be freed with PORT_Free. */
+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(PLArenaPool *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);
+
+/*
+** Merge an external list of extensions into a cert's extension list, adding one
+** only when its OID matches none of the cert's existing extensions. Call this
+** immediately before calling CERT_FinishExtensions().
+*/
+SECStatus
+CERT_MergeExtensions(void *exthandle, CERTCertExtension **exts);
+
+/* 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
+   (PLArenaPool *arena, CERTBasicConstraints *value, SECItem *encodedValue);
+
+/*
+** Encode the value of the authorityKeyIdentifier extension.
+*/
+extern SECStatus CERT_EncodeAuthKeyID
+   (PLArenaPool *arena, CERTAuthKeyID *value, SECItem *encodedValue);
+
+/*
+** Encode the value of the crlDistributionPoints extension.
+*/
+extern SECStatus CERT_EncodeCRLDistributionPoints
+   (PLArenaPool *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 
+			(PLArenaPool *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
+   (PLArenaPool *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 (PLArenaPool *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, PRTime *value);
+
+/*
+** Set up a crl for adding X509v3 extensions.  Returns an opaque handle
+** used by routines that take an exthandle (void*) argument .
+**	"crl" is the CRL we are adding extensions to
+*/
+extern void *CERT_StartCRLExtensions(CERTCrl *crl);
+
+/*
+** Set up a crl entry for adding X509v3 extensions.  Returns an opaque handle
+** used by routines that take an exthandle (void*) argument .
+**	"crl" is the crl we are adding certs entries to
+**      "entry" is the crl entry we are adding extensions to
+*/
+extern void *CERT_StartCRLEntryExtensions(CERTCrl *crl, CERTCrlEntry *entry);
+
+extern CERTCertNicknames *CERT_GetCertNicknames (CERTCertDBHandle *handle,
+						 int what, void *wincx);
+
+/*
+** Finds the crlNumber extension and decodes its value into 'value'
+*/
+extern SECStatus CERT_FindCRLNumberExten (PLArenaPool *arena, CERTCrl *crl,
+                                          SECItem *value);
+
+extern SECStatus CERT_FindCRLEntryReasonExten (CERTCrlEntry *crlEntry,
+					       CERTCRLEntryReasonCode *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);
+
+/* Duplicate distinguished name array */
+extern CERTDistNames *CERT_DupDistNames(CERTDistNames *orig);
+
+/*
+** Generate an array of Distinguished names from an array of nicknames
+*/
+extern CERTDistNames *CERT_DistNamesFromNicknames
+   (CERTCertDBHandle *handle, char **nicknames, int nnames);
+
+/*
+** Generate an array of Distinguished names from a list of certs.
+*/
+extern CERTDistNames *CERT_DistNamesFromCertList(CERTCertList *list);
+
+/*
+** 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(const char *emailAddr);
+
+/* decode string representation of trust flags into trust struct */
+SECStatus
+CERT_DecodeTrustString(CERTCertTrust *trust, const 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);
+
+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);
+
+CERTCertificatePolicies *
+CERT_DecodeCertificatePoliciesExtension(SECItem *extnValue);
+
+void
+CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies);
+
+CERTCertificatePolicyMappings *
+CERT_DecodePolicyMappingsExtension(SECItem *encodedCertPolicyMaps);
+
+SECStatus
+CERT_DestroyPolicyMappingsExtension(CERTCertificatePolicyMappings *mappings);
+
+SECStatus
+CERT_DecodePolicyConstraintsExtension(
+    CERTCertificatePolicyConstraints *decodedValue, SECItem *encodedValue);
+
+SECStatus CERT_DecodeInhibitAnyExtension
+    (CERTCertificateInhibitAny *decodedValue, SECItem *extnValue);
+
+CERTUserNotice *
+CERT_DecodeUserNotice(SECItem *noticeItem);
+
+extern CERTGeneralName *
+CERT_DecodeAltNameExtension(PLArenaPool *reqArena, SECItem *EncodedAltName);
+
+extern CERTNameConstraints *
+CERT_DecodeNameConstraintsExtension(PLArenaPool *arena, 
+                                    SECItem *encodedConstraints);
+
+/* returns addr of a NULL termainated array of pointers to CERTAuthInfoAccess */
+extern CERTAuthInfoAccess **
+CERT_DecodeAuthInfoAccessExtension(PLArenaPool *reqArena,
+				   SECItem     *encodedExtension);
+
+extern CERTPrivKeyUsagePeriod *
+CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue);
+
+extern CERTGeneralName *
+CERT_GetNextGeneralName(CERTGeneralName *current);
+
+extern CERTGeneralName *
+CERT_GetPrevGeneralName(CERTGeneralName *current);
+
+CERTNameConstraint *
+CERT_GetNextNameConstraint(CERTNameConstraint *current);
+
+CERTNameConstraint *
+CERT_GetPrevNameConstraint(CERTNameConstraint *current);
+
+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);
+
+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, PLArenaPool *arena);
+
+char *
+CERT_GetNickName(CERTCertificate   *cert, CERTCertDBHandle *handle, PLArenaPool *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, PRTime 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,
+			 const 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(PLArenaPool *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, PRTime validTime, PRBool validOnly);
+
+/*
+ * 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_GetSPKIDigest(PLArenaPool *arena, const CERTCertificate *cert,
+                   SECOidTag digestAlg, SECItem *fill);
+
+
+SECStatus CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer,
+                        const SECItem* dp, PRTime t, void* wincx);
+
+
+/*
+ * Add a CERTNameConstraint to the CERTNameConstraint list
+ */
+extern CERTNameConstraint *
+CERT_AddNameConstraint(CERTNameConstraint *list, 
+		       CERTNameConstraint *constraint);
+
+/*
+ * Allocate space and copy CERTNameConstraint from src to dest.
+ * Arena is used to allocate result(if dest eq NULL) and its members
+ * SECItem data.
+ */
+extern CERTNameConstraint *
+CERT_CopyNameConstraint(PLArenaPool         *arena, 
+			CERTNameConstraint  *dest, 
+			CERTNameConstraint  *src);
+
+/*
+ * Verify name against all the constraints relevant to that type of
+ * the name.
+ */
+extern SECStatus
+CERT_CheckNameSpace(PLArenaPool          *arena,
+		    CERTNameConstraints  *constraints,
+		    CERTGeneralName      *currentName);
+
+/*
+ * Extract and allocate the name constraints extension from the CA cert.
+ */
+extern SECStatus
+CERT_FindNameConstraintsExten(PLArenaPool      *arena,
+			      CERTCertificate  *cert,
+			      CERTNameConstraints **constraints);
+
+/*
+ * Initialize a new GERTGeneralName fields (link)
+ */
+extern CERTGeneralName *
+CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type);
+
+/*
+ * PKIX extension encoding routines
+ */
+extern SECStatus
+CERT_EncodePolicyConstraintsExtension(PLArenaPool *arena,
+                                      CERTCertificatePolicyConstraints *constr,
+                                      SECItem *dest);
+extern SECStatus
+CERT_EncodeInhibitAnyExtension(PLArenaPool *arena,
+                               CERTCertificateInhibitAny *inhibitAny,
+                               SECItem *dest);
+extern SECStatus
+CERT_EncodePolicyMappingExtension(PLArenaPool *arena,
+                                  CERTCertificatePolicyMappings *maps,
+                                  SECItem *dest);
+
+extern SECStatus CERT_EncodeInfoAccessExtension(PLArenaPool *arena,
+                                                    CERTAuthInfoAccess **info,
+                                                    SECItem *dest);
+extern SECStatus
+CERT_EncodeUserNotice(PLArenaPool *arena,
+                      CERTUserNotice *notice,
+                      SECItem *dest);
+
+extern SECStatus
+CERT_EncodeDisplayText(PLArenaPool *arena,
+                       SECItem *text,
+                       SECItem *dest);
+
+extern SECStatus
+CERT_EncodeCertPoliciesExtension(PLArenaPool *arena,
+                                 CERTPolicyInfo **info,
+                                 SECItem *dest);
+extern SECStatus
+CERT_EncodeNoticeReference(PLArenaPool *arena,
+                           CERTNoticeReference *reference,
+                           SECItem *dest);
+
+/*
+ * Returns a pointer to a static structure.
+ */
+extern const CERTRevocationFlags*
+CERT_GetPKIXVerifyNistRevocationPolicy(void);
+
+/*
+ * Returns a pointer to a static structure.
+ */
+extern const CERTRevocationFlags*
+CERT_GetClassicOCSPEnabledSoftFailurePolicy(void);
+
+/*
+ * Returns a pointer to a static structure.
+ */
+extern const CERTRevocationFlags*
+CERT_GetClassicOCSPEnabledHardFailurePolicy(void);
+
+/*
+ * Returns a pointer to a static structure.
+ */
+extern const CERTRevocationFlags*
+CERT_GetClassicOCSPDisabledPolicy(void);
+
+/*
+ * Verify a Cert with libpkix
+ *  paramsIn control the verification options. If a value isn't specified
+ *   in paramsIn, it reverts to the application default.
+ *  paramsOut specifies the parameters the caller would like to get back.
+ *   the caller may pass NULL, in which case no parameters are returned.
+ */
+extern SECStatus CERT_PKIXVerifyCert(
+	CERTCertificate *cert,
+	SECCertificateUsage usages,
+	CERTValInParam *paramsIn,
+	CERTValOutParam *paramsOut,
+	void *wincx);
+/*
+ * This function changes the application defaults for the Verify function.
+ * It should be called once at app initialization time, and only changes
+ * if the default configuration changes.
+ *
+ * This changes the default values for the parameters specified. These
+ * defaults can be overridden in CERT_PKIXVerifyCert() by explicitly 
+ * setting the value in paramsIn.
+ */
+extern SECStatus CERT_PKIXSetDefaults(CERTValInParam *paramsIn);
+
+/* Makes old cert validation APIs(CERT_VerifyCert, CERT_VerifyCertificate)
+ * to use libpkix validation engine. The function should be called ones at
+ * application initialization time.
+ * Function is not thread safe.*/
+SECStatus CERT_SetUsePKIXForValidation(PRBool enable);
+
+/* The function return PR_TRUE if cert validation should use
+ * libpkix cert validation engine. */
+PRBool CERT_GetUsePKIXForValidation(void);
+
+SEC_END_PROTOS
+
+#endif /* _CERT_H_ */
diff --git a/mozilla/security/nss/lib/certdb/certdb.c b/mozilla/security/nss/lib/certdb/certdb.c
new file mode 100644
index 0000000..481b64b
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/certdb.c
@@ -0,0 +1,3244 @@
+/* ***** 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):
+ *    Aaron Spangler <aaron@spangler.ods.org>
+ *    Kaspar Brand <mozbugzilla@velox.ch>
+ *
+ * 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 ***** */
+
+/*
+ * Certificate handling code
+ *
+ * $Id: certdb.c,v 1.101 2009/05/18 21:33:25 nelson%bolyard.com Exp $
+ */
+
+#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 "certdb.h"
+#include "prprf.h"
+#include "sechash.h"
+#include "prlong.h"
+#include "certxutl.h"
+#include "portreg.h"
+#include "secerr.h"
+#include "sslerr.h"
+#include "pk11func.h"
+#include "xconst.h"   /* for  CERT_DecodeAltNameExtension */
+
+#include "pki.h"
+#include "pki3hack.h"
+
+SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(SEC_BitStringTemplate)
+SEC_ASN1_MKSUB(SEC_IntegerTemplate)
+SEC_ASN1_MKSUB(SEC_SkipTemplate)
+
+/*
+ * 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_TimeChoiceTemplate[] = {
+  { SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
+  { SEC_ASN1_UTC_TIME, 0, 0, siUTCTime },
+  { SEC_ASN1_GENERALIZED_TIME, 0, 0, siGeneralizedTime },
+  { 0 }
+};
+
+const SEC_ASN1Template CERT_ValidityTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTValidity) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+          offsetof(CERTValidity,notBefore),
+          SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+          offsetof(CERTValidity,notAfter),
+          SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
+    { 0 }
+};
+
+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 | SEC_ASN1_XTRN | 0, /* XXX DER_DEFAULT */ 
+	  offsetof(CERTCertificate,version),
+	  SEC_ASN1_SUB(SEC_IntegerTemplate) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(CERTCertificate,serialNumber) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(CERTCertificate,signature),
+	  SEC_ASN1_SUB(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_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
+	  offsetof(CERTCertificate,issuerID),
+	  SEC_ASN1_SUB(SEC_BitStringTemplate) },
+    { SEC_ASN1_OPTIONAL |  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
+	  offsetof(CERTCertificate,subjectID),
+	  SEC_ASN1_SUB(SEC_BitStringTemplate) },
+    { 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 | SEC_ASN1_XTRN,
+	  offsetof(CERTCertificate,signatureWrap.signatureAlgorithm),
+	  SEC_ASN1_SUB(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 | SEC_ASN1_XTRN | 0,
+	  0, SEC_ASN1_SUB(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 | SEC_ASN1_XTRN | 0,
+	  0, SEC_ASN1_SUB(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 | SEC_ASN1_XTRN | 0,
+	  0, SEC_ASN1_SUB(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 | SEC_ASN1_XTRN | 0,
+	  0, SEC_ASN1_SUB(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_TimeChoiceTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SequenceOfCertExtensionTemplate)
+
+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 *reqArena, SECItem *derCert, SECItem *key)
+{
+    int rv;
+    CERTSignedData sd;
+    CERTCertKey certkey;
+
+    if (!reqArena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
+    rv = SEC_QuickDERDecodeItem(reqArena, &sd, CERT_SignedDataTemplate,
+                                derCert);
+    
+    if ( rv ) {
+	goto loser;
+    }
+    
+    PORT_Memset(&certkey, 0, sizeof(CERTCertKey));
+    rv = SEC_QuickDERDecodeItem(reqArena, &certkey, CERT_CertKeyTemplate,
+                                &sd.data);
+
+    if ( rv ) {
+	goto loser;
+    }
+
+    return(CERT_KeyFromIssuerAndSN(reqArena, &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)
+{
+    PRUint32 nsCertType;
+
+    if (cert->nsCertType) {
+        /* once set, no need to recalculate */
+        return SECSuccess;
+    }
+    nsCertType = cert_ComputeCertType(cert);
+
+    /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */
+    PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32));
+    PR_AtomicSet((PRInt32 *)&cert->nsCertType, nsCertType);
+    return SECSuccess;
+}
+
+PRUint32
+cert_ComputeCertType(CERTCertificate *cert)
+{
+    SECStatus rv;
+    SECItem tmpitem;
+    SECItem encodedExtKeyUsage;
+    CERTOidSequence *extKeyUsage = NULL;
+    PRBool basicConstraintPresent = PR_FALSE;
+    CERTBasicConstraints basicConstraint;
+    PRUint32 nsCertType = 0;
+
+    tmpitem.data = NULL;
+    CERT_FindNSCertTypeExtension(cert, &tmpitem);
+    encodedExtKeyUsage.data = NULL;
+    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 && cert->emailAddr[0]) {
+	    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;
+	    }
+	}
+	/* Treat certs with step-up OID as also having SSL server type. */
+	if (findOIDinOIDSeqByTagNum(extKeyUsage, 
+				    SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) ==
+	    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 NS Cert Type extension and no EKU extension, then */
+	nsCertType = 0;
+	if (CERT_IsCACert(cert, &nsCertType))
+	    nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
+	/* if the basic constraint extension says the cert is a CA, then
+	   allow SSL CA and EMAIL CA and Status Responder */
+	if (basicConstraintPresent && basicConstraint.isCA ) {
+	    nsCertType |= (NS_CERT_TYPE_SSL_CA   |
+		           NS_CERT_TYPE_EMAIL_CA |
+		           EXT_KEY_USAGE_STATUS_RESPONDER);
+	}
+	/* 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 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 (encodedExtKeyUsage.data != NULL) {
+	PORT_Free(encodedExtKeyUsage.data);
+    }
+    if (extKeyUsage != NULL) {
+	CERT_DestroyOidSequence(extKeyUsage);
+    }
+    return nsCertType;
+}
+
+/*
+ * 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) {
+        cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE;
+    }
+
+    /* 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;
+    }
+
+    /* determine if this is a root cert */
+    cert->isRoot = cert_IsRootCert(cert);
+
+    /* initialize the certType */
+    rv = cert_GetCertType(cert);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+
+    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);
+}
+
+
+CERTValidity *
+CERT_CreateValidity(int64 notBefore, int64 notAfter)
+{
+    CERTValidity *v;
+    int rv;
+    PRArenaPool *arena;
+
+    if (notBefore > notAfter) {
+       PORT_SetError(SEC_ERROR_INVALID_ARGS);
+       return NULL;
+    }
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    
+    if ( !arena ) {
+	return(0);
+    }
+    
+    v = (CERTValidity*) PORT_ArenaZAlloc(arena, sizeof(CERTValidity));
+    if (v) {
+	v->arena = arena;
+	rv = DER_EncodeTimeChoice(arena, &v->notBefore, notBefore);
+	if (rv) goto loser;
+	rv = DER_EncodeTimeChoice(arena, &v->notAfter, notAfter);
+	if (rv) goto loser;
+    }
+    return v;
+
+  loser:
+    CERT_DestroyValidity(v);
+    return 0;
+}
+
+SECStatus
+CERT_CopyValidity(PRArenaPool *arena, CERTValidity *to, CERTValidity *from)
+{
+    SECStatus rv;
+
+    CERT_DestroyValidity(to);
+    to->arena = arena;
+    
+    rv = SECITEM_CopyItem(arena, &to->notBefore, &from->notBefore);
+    if (rv) return rv;
+    rv = SECITEM_CopyItem(arena, &to->notAfter, &from->notAfter);
+    return rv;
+}
+
+void
+CERT_DestroyValidity(CERTValidity *v)
+{
+    if (v && v->arena) {
+	PORT_FreeArena(v->arena, PR_FALSE);
+    }
+    return;
+}
+
+/*
+** 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)
+{
+    SECStatus rv;
+
+    if (!c || !notBefore || !notAfter) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    
+    /* convert DER not-before time */
+    rv = DER_DecodeTimeChoice(notBefore, &c->validity.notBefore);
+    if (rv) {
+	return(SECFailure);
+    }
+    
+    /* convert DER not-after time */
+    rv = DER_DecodeTimeChoice(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 (!c) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return(secCertTimeUndetermined);
+    }
+    /* 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_DecodeTimeChoice(notBefore, &date->lastUpdate);
+    if (rv) {
+	return(SECFailure);
+    }
+    
+    /* convert DER not-after time */
+    if (date->nextUpdate.data) {
+	rv = DER_DecodeTimeChoice(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 certUsageVerifyCA:
+	  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)
+{
+    unsigned int certKeyUsage;
+
+    if (!cert) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* choose between key agreement or key encipherment based on key
+     * type in cert
+     */
+    if ( requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT ) {
+	KeyType keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
+	/* turn off the special bit */
+	requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
+
+	switch (keyType) {
+	case rsaKey:
+	    requiredUsage |= KU_KEY_ENCIPHERMENT;
+	    break;
+	case dsaKey:
+	    requiredUsage |= KU_DIGITAL_SIGNATURE;
+	    break;
+	case fortezzaKey:
+	case keaKey:
+	case dhKey:
+	    requiredUsage |= KU_KEY_AGREEMENT;
+	    break;
+	case ecKey:
+	    /* Accept either signature or agreement. */
+	    if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)))
+		 goto loser;
+	    break;
+	default:
+	    goto loser;
+	}
+    }
+
+    certKeyUsage = cert->keyUsage;
+    if (certKeyUsage & KU_NON_REPUDIATION)
+        certKeyUsage |= KU_DIGITAL_SIGNATURE;
+    if ( (certKeyUsage & requiredUsage) == requiredUsage ) 
+    	return SECSuccess;
+
+loser:
+    PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
+    return SECFailure;
+}
+
+
+CERTCertificate *
+CERT_DupCertificate(CERTCertificate *c)
+{
+    if (c) {
+	NSSCertificate *tmp = STAN_GetNSSCertificate(c);
+	nssCertificate_AddRef(tmp);
+    }
+    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.
+**
+** This function may modify string cn, so caller must pass a modifiable copy.
+*/
+static SECStatus
+cert_TestHostName(char * cn, const char * hn)
+{
+    static int useShellExp = -1;
+
+    if (useShellExp < 0) {
+        useShellExp = (NULL != PR_GetEnv("NSS_USE_SHEXP_IN_CERT_NAME"));
+    }
+    if (useShellExp) {
+    	/* Backward compatible code, uses Shell Expressions (SHEXP). */
+	int 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;
+	}
+    } else {
+	/* New approach conforms to RFC 2818. */
+	char *wildcard    = PORT_Strchr(cn, '*');
+	char *firstcndot  = PORT_Strchr(cn, '.');
+	char *secondcndot = firstcndot ? PORT_Strchr(firstcndot+1, '.') : NULL;
+	char *firsthndot  = PORT_Strchr(hn, '.');
+
+	/* For a cn pattern to be considered valid, the wildcard character...
+	 * - may occur only in a DNS name with at least 3 components, and
+	 * - may occur only as last character in the first component, and
+	 * - may be preceded by additional characters
+	 */
+	if (wildcard && secondcndot && secondcndot[1] && firsthndot 
+	    && firstcndot  - wildcard  == 1
+	    && secondcndot - firstcndot > 1
+	    && PORT_Strrchr(cn, '*') == wildcard
+	    && !PORT_Strncasecmp(cn, hn, wildcard - cn)
+	    && !PORT_Strcasecmp(firstcndot, firsthndot)) {
+	    /* valid wildcard pattern match */
+	    return SECSuccess;
+	}
+    }
+    /* String cn has no wildcard or shell expression.  
+     * Compare entire string hn with cert name. 
+     */
+    if (PORT_Strcasecmp(hn, 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       = PR_FALSE;
+    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 fail;
+    }
+    isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
+    rv = SECFailure;
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!arena) 
+	goto fail;
+
+    nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
+    if (!current)
+    	goto fail;
+
+    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;
+		rv = CERT_RFC1485_EscapeAndQuote(cn, cnBufLen, 
+					    current->name.other.data, cnLen);
+		if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_OUTPUT_LEN) {
+		    cnBufLen = cnLen * 3 + 3; /* big enough for worst case */
+		    cn = (char *)PORT_ArenaAlloc(arena, cnBufLen);
+		    if (!cn)
+			goto fail;
+		    rv = CERT_RFC1485_EscapeAndQuote(cn, cnBufLen, 
+					    current->name.other.data, cnLen);
+		}
+		if (rv == SECSuccess)
+		    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_GetNextGeneralName(current);
+    } while (current != nameList);
+
+fail:
+
+    if (!(isIPaddr ? IPextCount : DNSextCount)) {
+	/* 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;
+}
+
+/*
+ * If found:
+ *   - subAltName contains the extension (caller must free)
+ *   - return value is the decoded namelist (allocated off arena)
+ * if not found, or if failure to decode:
+ *   - return value is NULL
+ */
+CERTGeneralName *
+cert_GetSubjectAltNameList(CERTCertificate *cert,
+                           PRArenaPool *arena)
+{
+    CERTGeneralName * nameList       = NULL;
+    SECStatus         rv             = SECFailure;
+    SECItem           subAltName;
+
+    if (!cert || !arena)
+      return NULL;
+
+    subAltName.data = NULL;
+
+    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
+                                &subAltName);
+    if (rv != SECSuccess)
+      return NULL;
+
+    nameList = CERT_DecodeAltNameExtension(arena, &subAltName);
+    SECITEM_FreeItem(&subAltName, PR_FALSE);
+    return nameList;
+}
+
+PRUint32
+cert_CountDNSPatterns(CERTGeneralName *firstName)
+{
+    CERTGeneralName * current;
+    PRUint32 count = 0;
+
+    if (!firstName)
+      return 0;
+
+    current = firstName;
+    do {
+        switch (current->type) {
+        case certDNSName:
+        case certIPAddress:
+            ++count;
+            break;
+        default:
+            break;
+        }
+        current = CERT_GetNextGeneralName(current);
+    } while (current != firstName);
+
+    return count;
+}
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+/* will fill nickNames, 
+ * will allocate all data from nickNames->arena,
+ * numberOfGeneralNames should have been obtained from cert_CountDNSPatterns,
+ * will ensure the numberOfGeneralNames matches the number of output entries.
+ */
+SECStatus
+cert_GetDNSPatternsFromGeneralNames(CERTGeneralName *firstName,
+                                    PRUint32 numberOfGeneralNames, 
+                                    CERTCertNicknames *nickNames)
+{
+    CERTGeneralName *currentInput;
+    char **currentOutput;
+
+    if (!firstName || !nickNames || !numberOfGeneralNames)
+      return SECFailure;
+
+    nickNames->numnicknames = numberOfGeneralNames;
+    nickNames->nicknames = PORT_ArenaAlloc(nickNames->arena,
+                                       sizeof(char *) * numberOfGeneralNames);
+    if (!nickNames->nicknames)
+      return SECFailure;
+
+    currentInput = firstName;
+    currentOutput = nickNames->nicknames;
+    do {
+        char *cn = NULL;
+        char ipbuf[INET6_ADDRSTRLEN];
+        PRNetAddr addr;
+
+        if (numberOfGeneralNames < 1) {
+          /* internal consistency error */
+          return SECFailure;
+        }
+
+        switch (currentInput->type) {
+        case certDNSName:
+            /* DNS name currentInput->name.other.data is not null terminated.
+            ** so must copy it.  
+            */
+            cn = (char *)PORT_ArenaAlloc(nickNames->arena, 
+                                         currentInput->name.other.len + 1);
+            if (!cn)
+              return SECFailure;
+            PORT_Memcpy(cn, currentInput->name.other.data, 
+                            currentInput->name.other.len);
+            cn[currentInput->name.other.len] = 0;
+            break;
+        case certIPAddress:
+            if (currentInput->name.other.len == 4) {
+              addr.inet.family = PR_AF_INET;
+              memcpy(&addr.inet.ip, currentInput->name.other.data, 
+                                    currentInput->name.other.len);
+            } else if (currentInput->name.other.len == 16) {
+              addr.ipv6.family = PR_AF_INET6;
+              memcpy(&addr.ipv6.ip, currentInput->name.other.data, 
+                                    currentInput->name.other.len);
+            }
+            if (PR_NetAddrToString(&addr, ipbuf, sizeof(ipbuf)) == PR_FAILURE)
+              return SECFailure;
+            cn = PORT_ArenaStrdup(nickNames->arena, ipbuf);
+            if (!cn)
+              return SECFailure;
+            break;
+        default:
+            break;
+        }
+        if (cn) {
+          *currentOutput = cn;
+          nickNames->totallen += PORT_Strlen(cn);
+          ++currentOutput;
+          --numberOfGeneralNames;
+        }
+        currentInput = CERT_GetNextGeneralName(currentInput);
+    } while (currentInput != firstName);
+
+    return (numberOfGeneralNames == 0) ? SECSuccess : SECFailure;
+}
+
+/*
+ * Collect all valid DNS names from the given cert.
+ * The output arena will reference some temporaray data,
+ * but this saves us from dealing with two arenas.
+ * The caller may free all data by freeing CERTCertNicknames->arena.
+ */
+CERTCertNicknames *
+CERT_GetValidDNSPatternsFromCert(CERTCertificate *cert)
+{
+    CERTGeneralName *generalNames;
+    CERTCertNicknames *nickNames;
+    PRArenaPool *arena;
+    char *singleName;
+    
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+        return NULL;
+    }
+    
+    nickNames = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
+    if (!nickNames) {
+      PORT_FreeArena(arena, PR_FALSE);
+      return NULL;
+    }
+
+    /* init the structure */
+    nickNames->arena = arena;
+    nickNames->head = NULL;
+    nickNames->numnicknames = 0;
+    nickNames->nicknames = NULL;
+    nickNames->totallen = 0;
+
+    generalNames = cert_GetSubjectAltNameList(cert, arena);
+    if (generalNames) {
+      SECStatus rv_getnames = SECFailure; 
+      PRUint32 numNames = cert_CountDNSPatterns(generalNames);
+
+      if (numNames) {
+        rv_getnames = cert_GetDNSPatternsFromGeneralNames(generalNames, 
+                                                          numNames, nickNames);
+      }
+
+      /* if there were names, we'll exit now, either with success or failure */
+      if (numNames) {
+        if (rv_getnames == SECSuccess) {
+          return nickNames;
+        }
+
+        /* failure to produce output */
+        PORT_FreeArena(arena, PR_FALSE);
+        return NULL;
+      }
+    }
+
+    /* no SAN extension or no names found in extension */
+    /* now try the NS cert name extension first, then the common name */
+    singleName = 
+      CERT_FindNSStringExtension(cert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
+    if (!singleName) {
+      singleName = CERT_GetCommonName(&cert->subject);
+    }
+
+    if (singleName) {
+      nickNames->numnicknames = 1;
+      nickNames->nicknames = PORT_ArenaAlloc(arena, sizeof(char *));
+      if (nickNames->nicknames) {
+        *nickNames->nicknames = PORT_ArenaStrdup(arena, singleName);
+      }
+      PORT_Free(singleName);
+
+      /* Did we allocate both the buffer of pointers and the string? */
+      if (nickNames->nicknames && *nickNames->nicknames) {
+        return nickNames;
+      }
+    }
+
+    PORT_FreeArena(arena, PR_FALSE);
+    return NULL;
+}
+
+/* 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);
+}
+
+static int
+cert_Version(CERTCertificate *cert)
+{
+    int version = 0;
+    if (cert && cert->version.data && cert->version.len) {
+	version = DER_GetInteger(&cert->version);
+	if (version < 0)
+	    version = 0;
+    }
+    return version;
+}
+
+static unsigned int
+cert_ComputeTrustOverrides(CERTCertificate *cert, unsigned int cType)
+{
+    CERTCertTrust *trust = cert->trust;
+
+    if (trust && (trust->sslFlags |
+		  trust->emailFlags |
+		  trust->objectSigningFlags)) {
+
+	if (trust->sslFlags & (CERTDB_VALID_PEER|CERTDB_TRUSTED)) 
+	    cType |= NS_CERT_TYPE_SSL_SERVER|NS_CERT_TYPE_SSL_CLIENT;
+	if (trust->sslFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED_CA)) 
+	    cType |= NS_CERT_TYPE_SSL_CA;
+#if defined(CERTDB_NOT_TRUSTED)
+	if (trust->sslFlags & CERTDB_NOT_TRUSTED) 
+	    cType &= ~(NS_CERT_TYPE_SSL_SERVER|NS_CERT_TYPE_SSL_CLIENT|
+	               NS_CERT_TYPE_SSL_CA);
+#endif
+	if (trust->emailFlags & (CERTDB_VALID_PEER|CERTDB_TRUSTED)) 
+	    cType |= NS_CERT_TYPE_EMAIL;
+	if (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED_CA)) 
+	    cType |= NS_CERT_TYPE_EMAIL_CA;
+#if defined(CERTDB_NOT_TRUSTED)
+	if (trust->emailFlags & CERTDB_NOT_TRUSTED) 
+	    cType &= ~(NS_CERT_TYPE_EMAIL|NS_CERT_TYPE_EMAIL_CA);
+#endif
+	if (trust->objectSigningFlags & (CERTDB_VALID_PEER|CERTDB_TRUSTED)) 
+	    cType |= NS_CERT_TYPE_OBJECT_SIGNING;
+	if (trust->objectSigningFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED_CA)) 
+	    cType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
+#if defined(CERTDB_NOT_TRUSTED)
+	if (trust->objectSigningFlags & CERTDB_NOT_TRUSTED) 
+	    cType &= ~(NS_CERT_TYPE_OBJECT_SIGNING|
+	               NS_CERT_TYPE_OBJECT_SIGNING_CA);
+#endif
+    }
+    return cType;
+}
+
+/*
+ * 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)
+{
+    unsigned int cType = cert->nsCertType;
+    PRBool ret = PR_FALSE;
+
+    if (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA | 
+                NS_CERT_TYPE_OBJECT_SIGNING_CA)) {
+        ret = PR_TRUE;
+    } else {
+	SECStatus rv;
+	CERTBasicConstraints constraints;
+
+	rv = CERT_FindBasicConstraintExten(cert, &constraints);
+	if (rv == SECSuccess && constraints.isCA) {
+	    ret = PR_TRUE;
+	    cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
+	} 
+    }
+
+    /* finally check if it's an X.509 v1 root or FORTEZZA V1 CA */
+    if (!ret && 
+        ((cert->isRoot && cert_Version(cert) < SEC_CERTIFICATE_VERSION_3) ||
+    	 fortezzaIsCA(cert) )) {
+	ret = PR_TRUE;
+	cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
+    }
+    /* Now apply trust overrides, if any */
+    cType = cert_ComputeTrustOverrides(cert, cType);
+    ret = (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
+                    NS_CERT_TYPE_OBJECT_SIGNING_CA)) ? PR_TRUE : PR_FALSE;
+
+    if (rettype != NULL) {
+	*rettype = cType;
+    }
+    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;
+}
+
+CERTCompareValidityStatus
+CERT_CompareValidityTimes(CERTValidity* val_a, CERTValidity* val_b)
+{
+    PRTime notBeforeA, notBeforeB, notAfterA, notAfterB;
+
+    if (!val_a || !val_b)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return certValidityUndetermined;
+    }
+
+    if ( SECSuccess != DER_DecodeTimeChoice(&notBeforeA, &val_a->notBefore) ||
+         SECSuccess != DER_DecodeTimeChoice(&notBeforeB, &val_b->notBefore) ||
+         SECSuccess != DER_DecodeTimeChoice(&notAfterA, &val_a->notAfter) ||
+         SECSuccess != DER_DecodeTimeChoice(&notAfterB, &val_b->notAfter) ) {
+        return certValidityUndetermined;
+    }
+
+    /* sanity check */
+    if (LL_CMP(notBeforeA,>,notAfterA) || LL_CMP(notBeforeB,>,notAfterB)) {
+        PORT_SetError(SEC_ERROR_INVALID_TIME);
+        return certValidityUndetermined;
+    }
+
+    if (LL_CMP(notAfterA,!=,notAfterB)) {
+        /* one cert validity goes farther into the future, select it */
+        return LL_CMP(notAfterA,<,notAfterB) ?
+            certValidityChooseB : certValidityChooseA;
+    }
+    /* the two certs have the same expiration date */
+    PORT_Assert(LL_CMP(notAfterA, == , notAfterB));
+    /* do they also have the same start date ? */
+    if (LL_CMP(notBeforeA,==,notBeforeB)) {
+	return certValidityEqual;
+    }
+    /* choose cert with the later start date */
+    return LL_CMP(notBeforeA,<,notBeforeB) ?
+        certValidityChooseB : certValidityChooseA;
+}
+
+/*
+ * 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 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(const 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, const char *trusts)
+{
+    unsigned int i;
+    unsigned int *pflags;
+    
+    if (!trust) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    trust->sslFlags = 0;
+    trust->emailFlags = 0;
+    trust->objectSigningFlags = 0;
+    if (!trusts) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    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;
+
+	  case 'i':
+	      *pflags = *pflags | CERTDB_INVISIBLE_CA;
+	      break;
+	  case 'g':
+	      *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;
+	      break;
+
+	  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);
+}
+
+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 = PORT_ZNewArray(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 (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 ((fcerts || !ncerts) ? SECSuccess : SECFailure);
+}
+
+/*
+ * 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;
+    SECStatus rv;
+    
+    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) ) {
+
+	PRBool bad = (PRBool)(!node->cert);
+
+	/* bad key usage ? */
+	if ( !bad && 
+	     CERT_CheckKeyUsage(node->cert, requiredKeyUsage) != SECSuccess ) {
+	    bad = PR_TRUE;
+	}
+	/* bad cert type ? */
+	if ( !bad ) {
+	    unsigned int certType = 0;
+	    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.
+		 */
+		(void)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 &&
+        ((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)
+{
+    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)
+{
+    PORT_Assert(certTrustLock != NULL);
+    PZ_Lock(certTrustLock);
+    return;
+}
+
+SECStatus
+cert_InitLocks(void)
+{
+    if ( certRefCountLock == NULL ) {
+        certRefCountLock = PZ_NewLock(nssILockRefLock);
+        PORT_Assert(certRefCountLock != NULL);
+        if (!certRefCountLock) {
+            return SECFailure;
+        }
+    }
+
+    if ( certTrustLock == NULL ) {
+        certTrustLock = PZ_NewLock(nssILockCertDB);
+        PORT_Assert(certTrustLock != NULL);
+        if (!certTrustLock) {
+            PZ_DestroyLock(certRefCountLock);
+            return SECFailure;
+        }
+    }    
+
+    return SECSuccess;
+}
+
+SECStatus
+cert_DestroyLocks(void)
+{
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert(certRefCountLock != NULL);
+    if (certRefCountLock) {
+        PZ_DestroyLock(certRefCountLock);
+        certRefCountLock = NULL;
+    } else {
+        rv = SECFailure;
+    }
+
+    PORT_Assert(certTrustLock != NULL);
+    if (certTrustLock) {
+        PZ_DestroyLock(certTrustLock);
+        certTrustLock = NULL;
+    } else {
+        rv = SECFailure;
+    }
+    return rv;
+}
+
+/*
+ * 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/mozilla/security/nss/lib/certdb/certdb.h b/mozilla/security/nss/lib/certdb/certdb.h
new file mode 100644
index 0000000..c489b0f
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/certdb.h
@@ -0,0 +1,97 @@
+/* ***** 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 ***** */
+
+#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(const 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);
+
+CERTSignedCrl* SEC_DupCrl(CERTSignedCrl* acrl);
+
+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);
+
+SEC_END_PROTOS
+
+#endif /* _CERTDB_H_ */
diff --git a/mozilla/security/nss/lib/certdb/certi.h b/mozilla/security/nss/lib/certdb/certi.h
new file mode 100644
index 0000000..db4441b
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/certi.h
@@ -0,0 +1,395 @@
+/* ***** 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 ***** */
+/*
+ * certi.h - private data structures for the certificate library
+ *
+ * $Id: certi.h,v 1.31 2009/07/31 18:35:30 christophe.ravel.bugs%sun.com Exp $
+ */
+#ifndef _CERTI_H_
+#define _CERTI_H_
+
+#include "certt.h"
+#include "nssrwlkt.h"
+
+/*
+#define GLOBAL_RWLOCK 1
+*/
+
+#define DPC_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;
+typedef struct CachedCrlStr CachedCrl;
+typedef struct NamedCRLCacheStr NamedCRLCache;
+typedef struct NamedCRLCacheEntryStr NamedCRLCacheEntry;
+
+struct OpaqueCRLFieldsStr {
+    PRBool partial;
+    PRBool decodingError;
+    PRBool badEntries;
+    PRBool badDER;
+    PRBool badExtensions;
+    PRBool heapDER;
+};
+
+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 */
+
+typedef enum {
+    CRL_OriginToken = 0,    /* CRL came from PKCS#11 token */
+    CRL_OriginExplicit = 1  /* CRL was explicitly added to the cache, from RAM */
+} CRLOrigin;
+
+typedef enum {
+    dpcacheNoEntry = 0,             /* no entry found for this SN */
+    dpcacheFoundEntry = 1,          /* entry found for this SN */
+    dpcacheCallerError = 2,         /* invalid args */
+    dpcacheInvalidCacheError = 3,   /* CRL in cache may be bad DER */
+                                    /* or unverified */
+    dpcacheEmpty = 4,               /* no CRL in cache */
+    dpcacheLookupError = 5          /* internal error */
+} dpcacheStatus;
+
+
+struct CachedCrlStr {
+    CERTSignedCrl* crl;
+    CRLOrigin origin;
+    /* 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 */
+    PRBool sigChecked; /* this CRL signature has already been checked */
+    PRBool sigValid; /* signature verification status .
+                        Only meaningful if checked is PR_TRUE . */
+    PRBool unbuildable; /* Avoid using assosiated CRL is it fails
+                         * a decoding step */
+};
+
+/*  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 DPC_RWLOCK
+    NSSRWLock* lock;
+#else
+    PRLock* lock;
+#endif
+    CERTCertificate* issuer;    /* cert issuer 
+                                   XXX there may be multiple issuer certs,
+                                       with different validity dates. Also
+                                       need to deal with SKID/AKID . See
+                                       bugzilla 217387, 233118 */
+    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).
+                                   Currently not used. */
+
+    /* array of full CRLs matching this distribution point */
+    PRUint32 ncrls;              /* total number of CRLs in crls */
+    CachedCrl** crls;            /* array of all matching CRLs */
+    /* 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 */
+    CachedCrl* selected;    /* full CRL selected for use in the cache */
+#if 0
+    /* for future use */
+    PRInt32 numdeltas;      /* number of delta CRLs used for the cache */
+    CachedCrl** deltas;     /* delta CRLs used for the cache */
+#endif
+    /* cache 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 */
+    PRBool refresh;        /* manual refresh from tokens has been forced */
+    PRBool mustchoose;     /* trigger reselection algorithm, for case when
+                              RAM CRL objects are dropped from the cache */
+    PRTime lastfetch;      /* time a CRL token fetch was last performed */
+    PRTime lastcheck;      /* time CRL token objects were last checked for
+                              existence */
+};
+
+/*  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* 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 {
+#ifdef GLOBAL_RWLOCK
+    NSSRWLock* lock;
+#else
+    PRLock* lock;
+#endif
+    /* 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);
+
+/* return maximum length of AVA value based on its type OID tag. */
+extern int cert_AVAOidTagToMaxLen(SECOidTag tag);
+
+/* Make an AVA, allocated from pool, from OID and DER encoded value */
+extern CERTAVA * CERT_CreateAVAFromRaw(PRArenaPool *pool, 
+                               const SECItem * OID, const SECItem * value);
+
+/* Make an AVA from binary input specified by SECItem */
+extern CERTAVA * CERT_CreateAVAFromSECItem(PRArenaPool *arena, SECOidTag kind, 
+                                           int valueType, SECItem *value);
+
+/*
+ * get a DPCache object for the given issuer subject and dp
+ * Automatically creates the cache object if it doesn't exist yet.
+ */
+SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
+                         const SECItem* dp, int64 t, void* wincx,
+                         CRLDPCache** dpcache, PRBool* writeLocked);
+
+/* check if a particular SN is in the CRL cache and return its entry */
+dpcacheStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn,
+                             CERTCrlEntry** returned);
+
+/* release a DPCache object that was previously acquired */
+void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked);
+
+/* this function assumes the caller holds a lock on the DPCache */
+SECStatus DPCache_GetAllCRLs(CRLDPCache* dpc, PRArenaPool* arena,
+                             CERTSignedCrl*** crls, PRUint16* status);
+
+/* this function assumes the caller holds a lock on the DPCache */
+SECStatus DPCache_GetCRLEntry(CRLDPCache* cache, PRBool readlocked,
+                              CERTSignedCrl* crl, SECItem* sn,
+                              CERTCrlEntry** returned);
+
+/*
+ * map Stan errors into NSS errors
+ * This function examines the stan error stack and automatically sets
+ * PORT_SetError(); to the appropriate SEC_ERROR value.
+ */
+void CERT_MapStanError();
+
+/* Interface function for libpkix cert validation engine:
+ * cert_verify wrapper. */
+SECStatus
+cert_VerifyCertChainPkix(CERTCertificate *cert,
+                         PRBool checkSig,
+                         SECCertUsage     requiredUsage,
+                         PRTime           time,
+                         void            *wincx,
+                         CERTVerifyLog   *log,
+                         PRBool          *sigError,
+                         PRBool          *revoked);
+
+SECStatus cert_InitLocks(void);
+
+SECStatus cert_DestroyLocks(void);
+
+/*
+ * fill in nsCertType field of the cert based on the cert extension
+ */
+extern SECStatus cert_GetCertType(CERTCertificate *cert);
+
+/*
+ * compute and return the value of nsCertType for cert, but do not 
+ * update the CERTCertificate.
+ */
+extern PRUint32 cert_ComputeCertType(CERTCertificate *cert);
+
+void cert_AddToVerifyLog(CERTVerifyLog *log,CERTCertificate *cert,
+                         unsigned long errorCode, unsigned int depth,
+                         void *arg);
+
+/* Insert a DER CRL into the CRL cache, and take ownership of it.
+ *
+ * cert_CacheCRLByGeneralName takes ownership of the memory in crl argument
+ * completely.  crl must be freeable by SECITEM_FreeItem. It will be freed
+ * immediately if it is rejected from the CRL cache, or later during cache
+ * updates when a new crl is available, or at shutdown time.
+ *
+ * canonicalizedName represents the source of the CRL, a GeneralName.
+ * The format of the encoding is not restricted, but all callers of
+ * cert_CacheCRLByGeneralName and cert_FindCRLByGeneralName must use
+ * the same encoding. To facilitate X.500 name matching, a canonicalized
+ * encoding of the GeneralName should be used, if available.
+ */
+ 
+SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
+                                     const SECItem* canonicalizedName);
+
+struct NamedCRLCacheStr {
+    PRLock* lock;
+    PLHashTable* entries;
+};
+
+/* NamedCRLCacheEntryStr is filled in by cert_CacheCRLByGeneralName,
+ * and read by cert_FindCRLByGeneralName */
+struct NamedCRLCacheEntryStr {
+    SECItem* canonicalizedName;
+    SECItem* crl;                   /* DER, kept only if CRL
+                                     * is successfully cached */
+    PRBool inCRLCache;
+    PRTime successfulInsertionTime; /* insertion time */
+    PRTime lastAttemptTime;         /* time of last call to
+                              cert_CacheCRLByGeneralName with this name */
+    PRBool badDER;      /* ASN.1 error */
+    PRBool dupe;        /* matching DER CRL already in CRL cache */
+    PRBool unsupported; /* IDP, delta, any other reason */
+};
+
+typedef enum {
+    certRevocationStatusRevoked = 0,
+    certRevocationStatusValid = 1,
+    certRevocationStatusUnknown = 2
+} CERTRevocationStatus;
+
+/* Returns detailed status of the cert(revStatus variable). Tells if
+ * issuer cache has OriginFetchedWithTimeout crl in it. */
+SECStatus
+cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
+                               const SECItem* dp, PRTime t, void *wincx,
+                               CERTRevocationStatus *revStatus,
+                               CERTCRLEntryReasonCode *revReason);
+
+
+SECStatus cert_AcquireNamedCRLCache(NamedCRLCache** returned);
+
+/* cert_FindCRLByGeneralName must be called only while the named cache is
+ * acquired, and the entry is only valid until cache is released.
+ */
+SECStatus cert_FindCRLByGeneralName(NamedCRLCache* ncc,
+                                    const SECItem* canonicalizedName,
+                                    NamedCRLCacheEntry** retEntry);
+
+SECStatus cert_ReleaseNamedCRLCache(NamedCRLCache* ncc);
+
+#endif /* _CERTI_H_ */
+
diff --git a/mozilla/security/nss/lib/certdb/certt.h b/mozilla/security/nss/lib/certdb/certt.h
new file mode 100644
index 0000000..64cbb87
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/certt.h
@@ -0,0 +1,1320 @@
+/* ***** 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 ***** */
+/*
+ * certt.h - public data structures for the certificate library
+ *
+ * $Id: certt.h,v 1.52 2009/05/29 18:10:38 alexei.volkov.bugs%sun.com Exp $
+ */
+#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;
+typedef struct NSSTrustDomainStr                 CERTCertDBHandle;
+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 CERTPrivKeyUsagePeriodStr         CERTPrivKeyUsagePeriod;
+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 {
+    PLArenaPool *arena;
+    CERTRDN **rdns;
+};
+
+/*
+** An X.509 validity object
+*/
+struct CERTValidityStr {
+    PLArenaPool *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 {
+    PLArenaPool *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 {
+    PLArenaPool *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
+     */
+    PLArenaPool *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 */
+    PRUint32 nsCertType;	/* value of the ns cert type extension */
+				/* must be 32-bit for PR_AtomicSet */
+
+    /* 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.
+     */
+    union {
+        void* apointer; /* was struct SECSocketNode* authsocketlist */
+        struct {
+            unsigned int hasUnsupportedCriticalExt :1;
+            /* add any new option bits needed here */
+        } bits;
+    } options;
+    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 {
+    PLArenaPool *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 {
+    PLArenaPool *arena;
+    SECItem version;
+    CERTName subject;
+    CERTSubjectPublicKeyInfo subjectPublicKeyInfo;
+    CERTAttribute **attributes;
+};
+#define SEC_CERTIFICATE_REQUEST_VERSION		0	/* what we *create* */
+
+
+/*
+** A certificate list object.
+*/
+struct CERTCertificateListStr {
+    SECItem *certs;
+    int len;					/* number of certs */
+    PLArenaPool *arena;
+};
+
+struct CERTCertListNodeStr {
+    PRCList links;
+    CERTCertificate *cert;
+    void *appData;
+};
+
+struct CERTCertListStr {
+    PRCList list;
+    PLArenaPool *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 {
+    PLArenaPool *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 {
+    PLArenaPool *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 {
+    PLArenaPool *arena;
+    CERTCertDBHandle *dbhandle;
+    CERTCrlNode *first;
+    CERTCrlNode *last;
+};
+
+
+struct CERTCrlNodeStr {
+    CERTCrlNode *next;
+    int 	type;
+    CERTSignedCrl *crl;
+};
+
+
+/*
+ * Array of X.500 Distinguished Names
+ */
+struct CERTDistNamesStr {
+    PLArenaPool *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 certificateUsageCheckAllUsages         (0x0000)
+#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,
+    secCertTimeUndetermined = 3 /* validity could not be decoded from the
+                                   cert, most likely because it was NULL */
+} SECCertTimeValidity;
+
+/*
+ * This is used as return status in functions that compare the validity
+ * periods of two certificates A and B, currently only
+ * CERT_CompareValidityTimes.
+ */
+
+typedef enum CERTCompareValidityStatusEnum
+{
+    certValidityUndetermined = 0, /* the function is unable to select one cert 
+                                     over another */
+    certValidityChooseB = 1,      /* cert B should be preferred */
+    certValidityEqual = 2,        /* both certs have the same validity period */
+    certValidityChooseA = 3       /* cert A should be preferred */
+} CERTCompareValidityStatus;
+
+/*
+ * 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 {
+    PLArenaPool *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_ENCIPHER_ONLY		(0x01)  /* bit 7 */
+#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 | \
+					 KU_ENCIPHER_ONLY)
+
+/* 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
+
+#define CERT_MAX_SERIAL_NUMBER_BYTES  20    /* from RFC 3280 */
+#define CERT_MAX_DN_BYTES             4096  /* arbitrary */
+
+/* x.509 v3 Reason Flags, 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 */
+
+/* enum for CRL Entry Reason Code */
+typedef enum CERTCRLEntryReasonCodeEnum {
+    crlEntryReasonUnspecified = 0,
+    crlEntryReasonKeyCompromise = 1,
+    crlEntryReasonCaCompromise = 2,
+    crlEntryReasonAffiliationChanged = 3,
+    crlEntryReasonSuperseded = 4,
+    crlEntryReasonCessationOfOperation = 5,
+    crlEntryReasoncertificatedHold = 6,
+    crlEntryReasonRemoveFromCRL = 8,
+    crlEntryReasonPrivilegeWithdrawn = 9,
+    crlEntryReasonAaCompromise = 10
+} CERTCRLEntryReasonCode;
+
+/* 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 {
+    PLArenaPool *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;
+};
+
+
+/* Private Key Usage Period extension struct. */
+struct CERTPrivKeyUsagePeriodStr {
+    SECItem notBefore;
+    SECItem notAfter;
+    PLArenaPool *arena;
+};
+
+/* 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 {
+    PLArenaPool *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,
+						    PRTime 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 {
+    PLArenaPool *arena;
+    CERTPolicyInfo **policyInfos;
+} CERTCertificatePolicies;
+
+typedef struct {
+    SECItem organization;
+    SECItem **noticeNumbers;
+} CERTNoticeReference;
+
+typedef struct {
+    PLArenaPool *arena;
+    CERTNoticeReference noticeReference;
+    SECItem derNoticeReference;
+    SECItem displayText;
+} CERTUserNotice;
+
+typedef struct {
+    PLArenaPool *arena;
+    SECItem **oids;
+} CERTOidSequence;
+
+/*
+ * these types are for the PKIX Policy Mappings extension
+ */
+typedef struct {
+    SECItem issuerDomainPolicy;
+    SECItem subjectDomainPolicy;
+} CERTPolicyMap;
+
+typedef struct {
+    PLArenaPool *arena;
+    CERTPolicyMap **policyMaps;
+} CERTCertificatePolicyMappings;
+
+/*
+ * these types are for the PKIX inhibitAnyPolicy extension
+ */
+typedef struct {
+    SECItem inhibitAnySkipCerts;
+} CERTCertificateInhibitAny;
+
+/*
+ * these types are for the PKIX Policy Constraints extension
+ */
+typedef struct {
+    SECItem explicitPolicySkipCerts;
+    SECItem inhibitMappingSkipCerts;
+} CERTCertificatePolicyConstraints;
+
+
+/*
+ * these types are for the CERT_PKIX* Verification functions
+ * These are all optional parameters.
+ */
+
+typedef enum {
+   cert_pi_end             = 0, /* SPECIAL: signifies end of array of  
+				 * CERTValParam* */
+   cert_pi_nbioContext     = 1, /* specify a non-blocking IO context used to
+			         * resume a session. If this argument is 
+				 * specified, no other arguments should be.
+				 * Specified in value.pointer.p. If the 
+				 * operation completes the context will be 
+				 * freed. */
+   cert_pi_nbioAbort       = 2, /* specify a non-blocking IO context for an 
+				 * existing operation which the caller wants
+			         * to abort. If this argument is 
+				 * specified, no other arguments should be.
+				 * Specified in value.pointer.p. If the 
+			         * operation succeeds the context will be 
+				 * freed. */
+   cert_pi_certList        = 3, /* specify the chain to validate against. If
+				 * this value is given, then the path 
+				 * construction step in the validation is 
+				 * skipped. Specified in value.pointer.chain */
+   cert_pi_policyOID       = 4, /* validate certificate for policy OID.
+				 * Specified in value.array.oids. Cert must
+				 * be good for at least one OID in order
+				 * to validate. Default is no policyOID */
+   cert_pi_policyFlags     = 5, /* flags for each policy specified in policyOID.
+				 * Specified in value.scalar.ul. Policy flags
+				 * apply to all specified oids. 
+				 * Use CERT_POLICY_FLAG_* macros below. If not
+				 * specified policy flags default to 0 */
+   cert_pi_keyusage        = 6, /* specify what the keyusages the certificate 
+				 * will be evaluated against, specified in
+				 * value.scalar.ui. The cert must validate for
+				 * at least one of the specified key usages.
+				 * Values match the KU_  bit flags defined
+				 * in this file. Default is derived from
+				 * the 'usages' function argument */
+   cert_pi_extendedKeyusage= 7, /* specify what the required extended key 
+				 * usage of the certificate. Specified as
+				 * an array of oidTags in value.array.oids.
+				 * The cert must validate for at least one
+				 * of the specified extended key usages.
+				 * If not specified, no extended key usages
+				 * will be checked. */
+   cert_pi_date            = 8, /* validate certificate is valid as of date 
+				 * specified in value.scalar.time. A special 
+				 * value '0' indicates 'now'. default is '0' */
+   cert_pi_revocationFlags = 9, /* Specify what revocation checking to do.
+				 * See CERT_REV_FLAG_* macros below
+				 * Set in value.pointer.revocation */
+   cert_pi_certStores      = 10,/* Bitmask of Cert Store flags (see below)
+				 * Set in value.scalar.ui */
+   cert_pi_trustAnchors    = 11,/* Specify the list of trusted roots to 
+				 * validate against. 
+				 * The default set of trusted roots, these are
+				 * root CA certs from libnssckbi.so or CA
+				 * certs trusted by user, are used in any of
+				 * the following cases:
+				 *      * when the parameter is not set.
+				 *      * when the list of trust anchors is empty.
+				 * Specified in value.pointer.chain */
+   cert_pi_useAIACertFetch = 12, /* Enables cert fetching using AIA extension.
+				 * In NSS 3.12.1 or later. Default is off.
+				 * Value is in value.scalar.b */
+   cert_pi_max                  /* SPECIAL: signifies maximum allowed value,
+				 *  can increase in future releases */
+} CERTValParamInType;
+
+/*
+ * for all out parameters:
+ *  out parameters are only returned if the caller asks for them in
+ *  the CERTValOutParam array. Caller is responsible for the CERTValOutParam
+ *  array itself. The pkix verify function will allocate and other arrays
+ *  pointers, or objects. The Caller is responsible for freeing those results.
+ * If SECWouldBlock is returned, only cert_pi_nbioContext is returned.
+ */
+typedef enum {
+   cert_po_end             = 0, /* SPECIAL: signifies end of array of  
+				 * CERTValParam* */
+   cert_po_nbioContext     = 1, /* Return a nonblocking context. If no
+				 * non-blocking context is specified, then
+				 * blocking IO will be used. 
+				 * Returned in value.pointer.p. The context is 
+				 * freed after an abort or a complete operation.
+				 * This value is only returned on SECWouldBlock.
+				 */
+   cert_po_trustAnchor     = 2, /* Return the trust anchor for the chain that
+				 * was validated. Returned in 
+				 * value.pointer.cert, this value is only 
+				 * returned on SECSuccess. */
+   cert_po_certList        = 3, /* Return the entire chain that was validated.
+				 * Returned in value.pointer.certList. If no 
+				 * chain could be constructed, this value 
+				 * would be NULL. */
+   cert_po_policyOID       = 4, /* Return the policies that were found to be
+				 * valid. Returned in value.array.oids as an 
+				 * array. This is only returned on 
+				 * SECSuccess. */
+   cert_po_errorLog        = 5, /* Return a log of problems with the chain.
+				 * Returned in value.pointer.log  */
+   cert_po_usages          = 6, /* Return what usages the certificate is valid
+				   for. Returned in value.scalar.usages */
+   cert_po_keyUsage        = 7, /* Return what key usages the certificate
+				 * is valid for.
+				 * Returned in value.scalar.usage */
+   cert_po_extendedKeyusage= 8, /* Return what extended key usages the
+				 * certificate is valid for.
+				 * Returned in value.array.oids */
+   cert_po_max                  /* SPECIAL: signifies maximum allowed value,
+				 *  can increase in future releases */
+
+} CERTValParamOutType;
+
+typedef enum {
+    cert_revocation_method_crl = 0,
+    cert_revocation_method_ocsp,
+    cert_revocation_method_count
+} CERTRevocationMethodIndex;
+
+
+/*
+ * The following flags are supposed to be used to control bits in
+ * each integer contained in the array pointed to be:
+ *     CERTRevocationTests.cert_rev_flags_per_method
+ * All Flags are prefixed by CERT_REV_M_, where _M_ indicates
+ * this is a method dependent flag.
+ */
+
+/*
+ * Whether or not to use a method for revocation testing.
+ * If set to "do not test", then all other flags are ignored.
+ */
+#define CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD     0L
+#define CERT_REV_M_TEST_USING_THIS_METHOD            1L
+
+/*
+ * Whether or not NSS is allowed to attempt to fetch fresh information
+ *         from the network.
+ * (Although fetching will never happen if fresh information for the
+ *           method is already locally available.)
+ */
+#define CERT_REV_M_ALLOW_NETWORK_FETCHING            0L
+#define CERT_REV_M_FORBID_NETWORK_FETCHING           2L
+
+/*
+ * Example for an implicit default source:
+ *         The globally configured default OCSP responder.
+ * IGNORE means:
+ *        ignore the implicit default source, whether it's configured or not.
+ * ALLOW means:
+ *       if an implicit default source is configured, 
+ *          then it overrides any available or missing source in the cert.
+ *       if no implicit default source is configured,
+ *          then we continue to use what's available (or not available) 
+ *          in the certs.
+ */ 
+#define CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE     0L
+#define CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE    4L
+
+/*
+ * Defines the behavior if no fresh information is available,
+ *   fetching from the network is allowed, but the source of revocation
+ *   information is unknown (even after considering implicit sources,
+ *   if allowed by other flags).
+ * SKIPT_TEST means:
+ *          We ignore that no fresh information is available and 
+ *          skip this test.
+ * REQUIRE_INFO means:
+ *          We still require that fresh information is available.
+ *          Other flags define what happens on missing fresh info.
+ */
+#define CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE       0L
+#define CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE    8L
+
+/*
+ * Defines the behavior if we are unable to obtain fresh information.
+ * INGORE means:
+ *      Return "cert status unknown"
+ * FAIL means:
+ *      Return "cert revoked".
+ */
+#define CERT_REV_M_IGNORE_MISSING_FRESH_INFO         0L
+#define CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO        16L
+
+/*
+ * What should happen if we were able to find fresh information using
+ * this method, and the data indicated the cert is good?
+ * STOP_TESTING means:
+ *              Our success is sufficient, do not continue testing
+ *              other methods.
+ * CONTINUE_TESTING means:
+ *                  We will continue and test the next allowed
+ *                  specified method.
+ */
+#define CERT_REV_M_STOP_TESTING_ON_FRESH_INFO        0L
+#define CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO    32L
+
+/*
+ * The following flags are supposed to be used to control bits in
+ *     CERTRevocationTests.cert_rev_method_independent_flags
+ * All Flags are prefixed by CERT_REV_M_, where _M_ indicates
+ * this is a method independent flag.
+ */
+
+/*
+ * This defines the order to checking.
+ * EACH_METHOD_SEPARATELY means:
+ *      Do all tests related to a particular allowed method
+ *      (both local information and network fetching) in a single step.
+ *      Only after testing for a particular method is done,
+ *      then switching to the next method will happen.
+ * ALL_LOCAL_INFORMATION_FIRST means:
+ *      Start by testing the information for all allowed methods
+ *      which are already locally available. Only after that is done
+ *      consider to fetch from the network (as allowed by other flags).
+ */
+#define CERT_REV_MI_TEST_EACH_METHOD_SEPARATELY       0L
+#define CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST  1L
+
+/*
+ * Use this flag to specify that it's necessary that fresh information
+ * is available for at least one of the allowed methods, but it's
+ * irrelevant which of the mechanisms succeeded.
+ * NO_OVERALL_INFO_REQUIREMENT means:
+ *     We strictly follow the requirements for each individual method.
+ * REQUIRE_SOME_FRESH_INFO_AVAILABLE means:
+ *     After the individual tests have been executed, we must have
+ *     been able to find fresh information using at least one method.
+ *     If we were unable to find fresh info, it's a failure.
+ *     This setting overrides the CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
+ *     flag on all methods.
+ */
+#define CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT       0L
+#define CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE 2L
+
+
+typedef struct {
+    /*
+     * The size of the array that cert_rev_flags_per_method points to,
+     * meaning, the number of methods that are known and defined
+     * by the caller.
+     */
+    PRUint32 number_of_defined_methods;
+
+    /*
+     * A pointer to an array of integers.
+     * Each integer defines revocation checking for a single method,
+     *      by having individual CERT_REV_M_* bits set or not set.
+     * The meaning of index numbers into this array are defined by 
+     *     enum CERTRevocationMethodIndex
+     * The size of the array must be specified by the caller in the separate
+     *     variable number_of_defined_methods.
+     * The size of the array may be smaller than 
+     *     cert_revocation_method_count, it can happen if a caller
+     *     is not yet aware of the latest revocation methods
+     *     (or does not want to use them).
+     */ 
+    PRUint64 *cert_rev_flags_per_method;
+
+    /*
+     * How many preferred methods are specified?
+     * This is equivalent to the size of the array that 
+     *      preferred_revocation_methods points to.
+     * It's allowed to set this value to zero,
+     *      then NSS will decide which methods to prefer.
+     */
+    PRUint32 number_of_preferred_methods;
+
+    /* Array that may specify an optional order of preferred methods.
+     * Each array entry shall contain a method identifier as defined
+     *   by CERTRevocationMethodIndex.
+     * The entry at index [0] specifies the method with highest preferrence.
+     * These methods will be tested first for locally available information.
+     * Methods allowed for downloading will be attempted in the same order.
+     */
+    CERTRevocationMethodIndex *preferred_methods;
+
+    /*
+     * An integer which defines certain aspects of revocation checking
+     * (independent of individual methods) by having individual
+     * CERT_REV_MI_* bits set or not set.
+     */
+    PRUint64 cert_rev_method_independent_flags;
+} CERTRevocationTests;
+
+typedef struct {
+    CERTRevocationTests leafTests;
+    CERTRevocationTests chainTests;
+} CERTRevocationFlags;
+
+typedef struct CERTValParamInValueStr {
+    union {
+        PRBool   b;
+        PRInt32  i;
+        PRUint32 ui;
+        PRInt64  l;
+        PRUint64 ul;
+        PRTime time;
+    } scalar;
+    union {
+        const void*    p;
+        const char*    s;
+        const CERTCertificate* cert;
+        const CERTCertList *chain;
+        const CERTRevocationFlags *revocation;
+    } pointer;
+    union {
+        const PRInt32  *pi;
+        const PRUint32 *pui;
+        const PRInt64  *pl;
+        const PRUint64 *pul;
+        const SECOidTag *oids;
+    } array;
+    int arraySize;
+} CERTValParamInValue;
+
+
+typedef struct CERTValParamOutValueStr {
+    union {
+        PRBool   b;
+        PRInt32  i;
+        PRUint32 ui;
+        PRInt64  l;
+        PRUint64 ul;
+        SECCertificateUsage usages;
+    } scalar;
+    union {
+        void*    p;
+        char*    s;
+        CERTVerifyLog *log;
+        CERTCertificate* cert;
+        CERTCertList *chain;
+    } pointer;
+    union {
+        void 	  *p;
+        SECOidTag *oids;
+    } array;
+    int arraySize;
+} CERTValParamOutValue;
+
+typedef struct {
+    CERTValParamInType type;
+    CERTValParamInValue value;
+} CERTValInParam;
+
+typedef struct {
+    CERTValParamOutType type;
+    CERTValParamOutValue value;
+} CERTValOutParam;
+
+/*
+ * Levels of standards conformance strictness for CERT_NameToAsciiInvertible
+ */
+typedef enum CertStrictnessLevels {
+    CERT_N2A_READABLE   =  0, /* maximum human readability */
+    CERT_N2A_STRICT     = 10, /* strict RFC compliance    */
+    CERT_N2A_INVERTIBLE = 20  /* maximum invertibility,
+                                 all DirectoryStrings encoded in hex */
+} CertStrictnessLevel;
+
+/*
+ * policy flag defines
+ */
+#define CERT_POLICY_FLAG_NO_MAPPING    1
+#define CERT_POLICY_FLAG_EXPLICIT      2
+#define CERT_POLICY_FLAG_NO_ANY        4
+
+/*
+ * CertStore flags
+ */
+#define CERT_ENABLE_LDAP_FETCH          1
+#define CERT_ENABLE_HTTP_FETCH          2
+
+/* This functin pointer type may be used for any function that takes
+ * a CERTCertificate * and returns an allocated string, which must be
+ * freed by a call to PORT_Free.
+ */
+typedef char * (*CERT_StringFromCertFcn)(CERTCertificate *cert);
+
+/* 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_TimeChoiceTemplate[];
+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[];
+extern const SEC_ASN1Template CERT_SignedCrlTemplate[];
+
+/*
+** 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_SequenceOfCertExtensionTemplate)
+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_ASN1_CHOOSER_DECLARE(CERT_SignedCrlTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_TimeChoiceTemplate)
+
+SEC_END_PROTOS
+
+#endif /* _CERTT_H_ */
diff --git a/mozilla/security/nss/lib/certdb/certv3.c b/mozilla/security/nss/lib/certdb/certv3.c
new file mode 100644
index 0000000..bb73a2e
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/certv3.c
@@ -0,0 +1,399 @@
+/* ***** 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 ***** */
+
+/*
+ * Code for dealing with X509.V3 extensions.
+ *
+ * $Id: certv3.c,v 1.10 2007/10/12 01:44:40 julien.pierre.boogz%sun.com Exp $
+ */
+
+#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 = {siBuffer,0};
+    SECItem baseitem = {siBuffer,0};
+    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;
+    
+    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_ASN1_GET(SEC_IA5StringTemplate), &urlitem);
+
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+    if ( hasbase ) {
+	rv = SEC_QuickDERDecodeItem(arena, &basestringitem,
+                                    SEC_ASN1_GET(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_ASN1_GET(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)
+{
+
+    SECStatus rv;
+    SECItem encodedValue = {siBuffer, NULL, 0 };
+    SECItem decodedValue = {siBuffer, NULL, 0 };
+
+    rv = cert_FindExtension
+	 (cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue);
+    if (rv == SECSuccess) {
+	PLArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+	if (tmpArena) {
+	    rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue, 
+	                                SEC_ASN1_GET(SEC_OctetStringTemplate), 
+					&encodedValue);
+	    if (rv == SECSuccess) {
+	        rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
+	    }
+	    PORT_FreeArena(tmpArena, PR_FALSE);
+	} else {
+	    rv = SECFailure;
+	}
+    }
+    SECITEM_FreeItem(&encodedValue, PR_FALSE);
+    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)
+{
+    SECItem keyUsage;
+    SECStatus rv;
+
+    /* There is no extension, v1 or v2 certificate */
+    if (cert->extensions == NULL) {
+	return (SECSuccess);
+    }
+    
+    keyUsage.data = NULL;
+
+    /* This code formerly ignored the Key Usage extension if it was
+    ** marked non-critical.  That was wrong.  Since we do understand it,
+    ** we are obligated to honor it, whether or not it is critical.
+    */
+    rv = CERT_FindKeyUsageExtension(cert, &keyUsage);
+    if (rv == SECFailure) {
+        rv = (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) ?
+	    SECSuccess : SECFailure;
+    } else if (!(keyUsage.data[0] & usage)) {
+	PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID);
+	rv = SECFailure;
+    }
+    PORT_Free (keyUsage.data);
+    return (rv);
+}
diff --git a/mozilla/security/nss/lib/certdb/certxutl.c b/mozilla/security/nss/lib/certdb/certxutl.c
new file mode 100644
index 0000000..c28ef21
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/certxutl.c
@@ -0,0 +1,531 @@
+/* ***** 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 ***** */
+
+/*
+ * 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_ASN1_GET(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;
+}
+
+SECStatus
+CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
+{
+    CERTCertExtension *ext;
+    SECStatus rv = SECSuccess;
+    SECOidTag tag;
+    extNode *node;
+    extRec *handle = exthandle;
+    
+    if (!exthandle || !extensions) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    while ((ext = *extensions++) != NULL) {
+        tag = SECOID_FindOIDTag(&ext->id);
+        for (node=handle->head; node != NULL; node=node->next) {
+            if (tag == 0) {
+                if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
+                    break;
+            }
+            else {
+                if (SECOID_FindOIDTag(&node->ext->id) == tag) {
+                    break;
+                }
+            }
+        }
+        if (node == NULL) {
+            PRBool critical = (ext->critical.len != 0 &&
+                            ext->critical.data[ext->critical.len - 1] != 0);
+            if (critical && tag == SEC_OID_UNKNOWN) {
+               PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+               rv = SECFailure;
+               break;
+            }
+            /* add to list */
+            rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value,
+                                         critical, PR_TRUE);
+            if (rv != SECSuccess)
+                break;
+        }
+    }
+    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_ASN1_GET(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/mozilla/security/nss/lib/certdb/certxutl.h b/mozilla/security/nss/lib/certdb/certxutl.h
new file mode 100644
index 0000000..9f8a159
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/certxutl.h
@@ -0,0 +1,82 @@
+/* ***** 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 ***** */
+
+/*
+ * 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/mozilla/security/nss/lib/certdb/crl.c b/mozilla/security/nss/lib/certdb/crl.c
new file mode 100644
index 0000000..78a8caf
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/crl.c
@@ -0,0 +1,3560 @@
+/* ***** 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 ***** */
+
+/*
+ * Moved from secpkcs7.c
+ *
+ * $Id: crl.c,v 1.68 2009/08/10 22:25:44 julien.pierre.boogz%sun.com Exp $
+ */
+ 
+#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"
+#if defined(DPC_RWLOCK) || defined(GLOBAL_RWLOCK)
+#include "nssrwlk.h"
+#endif
+#include "pk11priv.h"
+
+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 }
+};
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
+
+static const SEC_ASN1Template cert_KrlTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTCrl) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(CERTCrl,signatureAlg),
+	  SEC_ASN1_SUB(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 | SEC_ASN1_XTRN,
+	  offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
+	  SEC_ASN1_SUB(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_INLINE | SEC_ASN1_XTRN,
+	  offsetof(CERTCrlEntry,revocationDate),
+          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+    { 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 | SEC_ASN1_XTRN,
+	  offsetof(CERTCrl,signatureAlg),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)},
+    { SEC_ASN1_SAVE,
+	  offsetof(CERTCrl,derName) },
+    { SEC_ASN1_INLINE,
+	  offsetof(CERTCrl,name),
+	  CERT_NameTemplate },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(CERTCrl,lastUpdate),
+          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
+	  offsetof(CERTCrl,nextUpdate),
+          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+    { 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 | SEC_ASN1_XTRN,
+	  offsetof(CERTCrl,signatureAlg),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_SAVE,
+	  offsetof(CERTCrl,derName) },
+    { SEC_ASN1_INLINE,
+	  offsetof(CERTCrl,name),
+	  CERT_NameTemplate },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(CERTCrl,lastUpdate),
+          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
+	  offsetof(CERTCrl,nextUpdate),
+          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+    { 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_INLINE | SEC_ASN1_XTRN,
+        offsetof(CERTCrl,lastUpdate),
+        SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+    { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
+        offsetof(CERTCrl,nextUpdate),
+        SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
+	  offsetof(CERTCrl,entries),
+	  cert_CrlEntryTemplate }, /* decode entries */
+    { SEC_ASN1_SKIP_REST },
+    { 0 }
+};
+
+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 | SEC_ASN1_XTRN ,
+	  offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
+	  SEC_ASN1_SUB(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 | SEC_ASN1_XTRN,
+	  offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_BIT_STRING,
+	  offsetof(CERTSignedCrl,signatureWrap.signature) },
+    { 0 }
+};
+
+const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
+};
+
+/* get CRL version */
+int cert_get_crl_version(CERTCrl * crl)
+{
+    /* CRL version is defaulted to v1 */
+    int version = SEC_CRL_VERSION_1;
+    if (crl && crl->version.data != 0) {
+	version = (int)DER_GetUInteger (&crl->version);
+    }
+    return version;
+}
+
+
+/* check the entries in the CRL */
+SECStatus cert_check_crl_entries (CERTCrl *crl)
+{
+    CERTCrlEntry **entries;
+    CERTCrlEntry *entry;
+    PRBool hasCriticalExten = PR_FALSE;
+    SECStatus rv = SECSuccess;
+
+    if (!crl) {
+        return SECFailure;
+    }
+
+    if (crl->entries == NULL) {
+        /* CRLs with no entries are valid */
+        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) {
+                    if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) { 
+                        /* only CRL v2 critical extensions are supported */
+                        PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
+                        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_CRL_UNKNOWN_CRITICAL_EXTENSION);
+		rv = SECFailure;
+		break;
+	    }
+	}
+	++entries;
+    }
+    return(rv);
+}
+
+/* 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)
+{
+    PRBool hasCriticalExten = PR_FALSE;
+    int version = cert_get_crl_version(crl);
+	
+    if (version > SEC_CRL_VERSION_2) {
+	PORT_SetError (SEC_ERROR_CRL_INVALID_VERSION);
+	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) {
+                /* only CRL v2 critical extensions are supported */
+                PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
+                return (SECFailure);
+            }
+	    /* make sure that there is no unknown critical extension */
+	    if (cert_HasUnknownCriticalExten (crl->extensions) == PR_TRUE) {
+		PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
+		return (SECFailure);
+	    }
+	}
+    }
+
+    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;
+    PRArenaPool* myArena;
+
+    if (!arena) {
+        /* arena needed for QuickDER */
+        myArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    } else {
+        myArena = arena;
+    }
+    PORT_Memset (&sd, 0, sizeof (sd));
+    rv = SEC_QuickDERDecodeItem (myArena, &sd, CERT_SignedDataTemplate, derCrl);
+    if (SECSuccess == rv) {
+        PORT_Memset (&crlkey, 0, sizeof (crlkey));
+        rv = SEC_QuickDERDecodeItem(myArena, &crlkey, cert_CrlKeyTemplate, &sd.data);
+    }
+
+    /* make a copy so the data doesn't point to memory inside derCrl, which
+       may be temporary */
+    if (SECSuccess == rv) {
+        rv = SECITEM_CopyItem(arena, key, &crlkey.derName);
+    }
+
+    if (myArena != arena) {
+        PORT_FreeArena(myArena, PR_FALSE);
+    }
+
+    return rv;
+}
+
+#define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
+
+SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
+{
+    SECStatus rv = SECSuccess;
+    SECItem* crldata = NULL;
+    OpaqueCRLFields* extended = NULL;
+
+    if ( (!crl) ||
+         (!(extended = (OpaqueCRLFields*) crl->opaque)) ||
+         (PR_TRUE == extended->decodingError) ) {
+        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->decodingError = 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 */
+        }
+        rv = cert_check_crl_entries(&crl->crl);
+        if (rv != SECSuccess) {
+            extended->badExtensions = PR_TRUE;
+        }
+    }
+    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;
+    PRInt32 testOptions = options;
+
+    PORT_Assert(derSignedCrl);
+    if (!derSignedCrl) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    /* Adopting DER requires not copying it.  Code that sets ADOPT flag 
+     * but doesn't set DONT_COPY probably doesn't know What it is doing.  
+     * That condition is a programming error in the caller.
+     */
+    testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
+    PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER);
+    if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    /* make a new arena if needed */
+    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_ADOPT_HEAP_DER) {
+        extended->heapDER = PR_TRUE;
+    }
+    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 extensions */
+        rv =  cert_check_crl_version (&crl->crl);
+        if (rv != SECSuccess) {
+            extended->badExtensions = PR_TRUE;
+            break;
+        }
+
+        if (PR_TRUE == extended->partial) {
+            /* partial decoding, don't verify entries */
+            break;
+        }
+
+        rv = cert_check_crl_entries(&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) {
+        if (extended) {
+            extended->decodingError = PR_TRUE;
+        }
+        if (crl) {
+            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 decodable DER CRL, or no CRL at all.
+ * Caller may distinguish those cases by the value returned in "decoded".
+ * When DER CRL is not found, error code will be SEC_ERROR_CRL_NOT_FOUND.
+ *
+ * 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;
+
+    PORT_Assert(decoded);
+    if (!decoded) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    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 */
+	int nsserror = PORT_GetError();
+	if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
+	    rv = SECFailure;
+	}
+	goto loser;
+    }
+    PORT_Assert(crlHandle != CK_INVALID_HANDLE);
+    /* PK11_FindCrlByName obtained a slot reference. */
+    
+    /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
+       Force adoption of the DER CRL from the heap - this will cause it 
+       to be automatically freed when SEC_DestroyCrl is invoked */
+    decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
+
+    crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
+    if (crl) {
+        crl->slot = slot;
+        slot = NULL; /* adopt it */
+	derCrl = NULL; /* adopted by the crl struct */
+        crl->pkcs11ID = crlHandle;
+        if (url) {
+            crl->url = PORT_ArenaStrdup(crl->arena,url);
+        }
+    } else {
+        rv = SECFailure;
+    }
+    
+    if (url) {
+	PORT_Free(url);
+    }
+
+    if (slot) {
+	PK11_FreeSlot(slot);
+    }
+
+loser:
+    if (derCrl) {
+	SECITEM_FreeItem(derCrl, PR_TRUE);
+    }
+
+    *decoded = crl;
+
+    return rv;
+}
+
+
+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 = CK_INVALID_HANDLE;
+    SECStatus rv;
+
+    PORT_Assert(newCrl);
+    PORT_Assert(derCrl);
+
+    /* we can't use the cache here because we must look in the same
+       token */
+    rv = 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;
+	    if (oldCrl->url && !url)
+	        url = oldCrl->url;
+	    if (url)
+		crl->url = PORT_ArenaStrdup(crl->arena, url);
+	    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) {
+	    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 (GetOpaqueCRLFields(crl) &&
+                PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
+                SECITEM_FreeItem(crl->derCrl, PR_TRUE);
+            }
+            if (crl->arena) {
+                PORT_FreeArena(crl->arena, PR_FALSE);
+            }
+	}
+        return SECSuccess;
+    } else {
+        return SECFailure;
+    }
+}
+
+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_SignedCrlTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
+
+/* CRL cache code starts here */
+
+/* constructor */
+static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
+                           CRLOrigin origin);
+/* destructor */
+static SECStatus CachedCrl_Destroy(CachedCrl* crl);
+
+/* create hash table of CRL entries */
+static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
+
+/* empty the cache content */
+static SECStatus CachedCrl_Depopulate(CachedCrl* crl);
+
+/* are these CRLs the same, as far as the cache is concerned ?
+   Or are they the same token object, but with different DER ? */
+
+static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
+                                PRBool* isUpdated);
+
+/* create a DPCache object */
+static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
+                         const SECItem* subject, SECItem* dp);
+
+/* destructor for CRL DPCache object */
+static SECStatus DPCache_Destroy(CRLDPCache* cache);
+
+/* add a new CRL object to the dynamic array of CRLs of the DPCache, and
+   returns the cached CRL object . Needs write access to DPCache. */
+static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl,
+                                PRBool* added);
+
+/* fetch the CRL for this DP from the PKCS#11 tokens */
+static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
+                                         void* wincx);
+
+/* update the content of the CRL cache, including fetching of CRLs, and
+   reprocessing with specified issuer and date */
+static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
+                         PRBool readlocked, PRTime vfdate, void* wincx);
+
+/* returns true if there are CRLs from PKCS#11 slots */
+static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
+
+/* remove CRL at offset specified */
+static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
+
+/* Pick best CRL to use . needs write access */
+static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
+
+/* create an issuer cache object (per CA subject ) */
+static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
+                             CERTCertificate* issuer,
+                             const SECItem* subject, const SECItem* dp);
+
+/* destructor for CRL IssuerCache object */
+SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
+
+/* add a DPCache to the issuer cache */
+static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
+                                   CERTCertificate* issuer,
+                                   const SECItem* subject,
+                                   const SECItem* dp, CRLDPCache** newdpc);
+
+/* get a particular DPCache object from an IssuerCache */
+static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache,
+                                          const SECItem* dp);
+
+/*
+** Pre-allocator hash allocator ops.
+*/
+
+/* allocate memory for hash table */
+static void * PR_CALLBACK
+PreAllocTable(void *pool, PRSize size)
+{
+    PreAllocator* alloc = (PreAllocator*)pool;
+    PORT_Assert(alloc);
+    if (!alloc)
+    {
+        /* no allocator, or buffer full */
+        return NULL;
+    }
+    if (size > (alloc->len - alloc->used))
+    {
+        /* initial buffer full, let's use the arena */
+        alloc->extra += size;
+        return PORT_ArenaAlloc(alloc->arena, size);
+    }
+    /* use the initial buffer */
+    alloc->used += size;
+    return (char*) alloc->data + alloc->used - size;
+}
+
+/* free hash table memory.
+   Individual PreAllocator elements cannot be freed, so this is a no-op. */
+static void PR_CALLBACK
+PreFreeTable(void *pool, void *item)
+{
+}
+
+/* allocate memory for hash table */
+static PLHashEntry * PR_CALLBACK
+PreAllocEntry(void *pool, const void *key)
+{
+    return PreAllocTable(pool, sizeof(PLHashEntry));
+}
+
+/* free hash table entry.
+   Individual PreAllocator elements cannot be freed, so this is a no-op. */
+static void PR_CALLBACK
+PreFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+}
+
+/* methods required for PL hash table functions */
+static PLHashAllocOps preAllocOps =
+{
+    PreAllocTable, PreFreeTable,
+    PreAllocEntry, PreFreeEntry
+};
+
+/* destructor for PreAllocator object */
+void PreAllocator_Destroy(PreAllocator* PreAllocator)
+{
+    if (!PreAllocator)
+    {
+        return;
+    }
+    if (PreAllocator->arena)
+    {
+        PORT_FreeArena(PreAllocator->arena, PR_TRUE);
+    }
+}
+
+/* constructor for PreAllocator object */
+PreAllocator* PreAllocator_Create(PRSize size)
+{
+    PRArenaPool* arena = NULL;
+    PreAllocator* prebuffer = NULL;
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!arena)
+    {
+        return NULL;
+    }
+    prebuffer = (PreAllocator*)PORT_ArenaZAlloc(arena,
+                                                sizeof(PreAllocator));
+    if (!prebuffer)
+    {
+        PORT_FreeArena(arena, PR_TRUE);
+        return NULL;
+    }
+    prebuffer->arena = arena;
+
+    if (size)
+    {
+        prebuffer->len = size;
+        prebuffer->data = PORT_ArenaAlloc(arena, size);
+        if (!prebuffer->data)
+        {
+            PORT_FreeArena(arena, PR_TRUE);
+            return NULL;
+        }
+    }
+    return prebuffer;
+}
+
+/* global Named CRL cache object */
+static NamedCRLCache namedCRLCache = { NULL, NULL };
+
+/* global CRL cache object */
+static CRLCache crlcache = { NULL, NULL };
+
+/* initial state is off */
+static PRBool crlcache_initialized = PR_FALSE;
+
+PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000; /* how often
+    to query the tokens for CRL objects, in order to discover new objects, if
+    the cache does not contain any token CRLs . In microseconds */
+
+PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000 ; /* how often
+    to query the tokens for CRL objects, in order to discover new objects, if
+    the cache already contains token CRLs In microseconds */
+
+PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check
+    if a token CRL object still exists. In microseconds */
+
+/* this function is called at NSS initialization time */
+SECStatus InitCRLCache(void)
+{
+    if (PR_FALSE == crlcache_initialized)
+    {
+        PORT_Assert(NULL == crlcache.lock);
+        PORT_Assert(NULL == crlcache.issuers);
+        PORT_Assert(NULL == namedCRLCache.lock);
+        PORT_Assert(NULL == namedCRLCache.entries);
+        if (crlcache.lock || crlcache.issuers || namedCRLCache.lock ||
+            namedCRLCache.entries)
+        {
+            /* CRL cache already partially initialized */
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+        }
+#ifdef GLOBAL_RWLOCK
+        crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
+#else
+        crlcache.lock = PR_NewLock();
+#endif
+        namedCRLCache.lock = PR_NewLock();
+        crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+                                  PL_CompareValues, NULL, NULL);
+        namedCRLCache.entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+                                  PL_CompareValues, NULL, NULL);
+        if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers ||
+            !namedCRLCache.entries)
+        {
+            if (crlcache.lock)
+            {
+#ifdef GLOBAL_RWLOCK
+                NSSRWLock_Destroy(crlcache.lock);
+#else
+                PR_DestroyLock(crlcache.lock);
+#endif
+                crlcache.lock = NULL;
+            }
+            if (namedCRLCache.lock)
+            {
+                PR_DestroyLock(namedCRLCache.lock);
+                namedCRLCache.lock = NULL;
+            }
+            if (crlcache.issuers)
+            {
+                PL_HashTableDestroy(crlcache.issuers);
+                crlcache.issuers = NULL;
+            }
+            if (namedCRLCache.entries)
+            {
+                PL_HashTableDestroy(namedCRLCache.entries);
+                namedCRLCache.entries = NULL;
+            }
+
+            return SECFailure;
+        }
+        crlcache_initialized = PR_TRUE;
+        return SECSuccess;
+    }
+    else
+    {
+        PORT_Assert(crlcache.lock);
+        PORT_Assert(crlcache.issuers);
+        if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
+        {
+            /* CRL cache not fully initialized */
+            return SECFailure;
+        }
+        else
+        {
+            /* CRL cache already initialized */
+            return SECSuccess;
+        }
+    }
+}
+
+/* destructor for CRL DPCache object */
+static SECStatus DPCache_Destroy(CRLDPCache* cache)
+{
+    PRUint32 i = 0;
+    PORT_Assert(cache);
+    if (!cache)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (cache->lock)
+    {
+#ifdef DPC_RWLOCK
+        NSSRWLock_Destroy(cache->lock);
+#else
+        PR_DestroyLock(cache->lock);
+#endif
+    }
+    else
+    {
+        PORT_Assert(0);
+        return SECFailure;
+    }
+    /* destroy all our CRL objects */
+    for (i=0;i<cache->ncrls;i++)
+    {
+        if (!cache->crls || !cache->crls[i] ||
+            SECSuccess != CachedCrl_Destroy(cache->crls[i]))
+        {
+            return SECFailure;
+        }
+    }
+    /* free the array of CRLs */
+    if (cache->crls)
+    {
+	PORT_Free(cache->crls);
+    }
+    /* 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);
+    }
+    PORT_Free(cache);
+    return SECSuccess;
+}
+
+/* destructor for CRL IssuerCache object */
+SECStatus IssuerCache_Destroy(CRLIssuerCache* cache)
+{
+    PORT_Assert(cache);
+    if (!cache)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+#ifdef XCRL
+    if (cache->lock)
+    {
+        NSSRWLock_Destroy(cache->lock);
+    }
+    else
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (cache->issuer)
+    {
+        CERT_DestroyCertificate(cache->issuer);
+    }
+#endif
+    /* free the subject */
+    if (cache->subject)
+    {
+        SECITEM_FreeItem(cache->subject, PR_TRUE);
+    }
+    if (SECSuccess != DPCache_Destroy(cache->dpp))
+    {
+        PORT_Assert(0);
+        return SECFailure;
+    }
+    PORT_Free(cache);
+    return SECSuccess;
+}
+
+/* create a named CRL entry object */
+static SECStatus NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned)
+{
+    NamedCRLCacheEntry* entry = NULL;
+    if (!returned)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    *returned = NULL;
+    entry = (NamedCRLCacheEntry*) PORT_ZAlloc(sizeof(NamedCRLCacheEntry));
+    if (!entry)
+    {
+        return SECFailure;
+    }
+    *returned = entry;
+    return SECSuccess;
+}
+
+/* destroy a named CRL entry object */
+static SECStatus NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry)
+{
+    if (!entry)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (entry->crl)
+    {
+        /* named CRL cache owns DER memory */
+        SECITEM_ZfreeItem(entry->crl, PR_TRUE);
+    }
+    if (entry->canonicalizedName)
+    {
+        SECITEM_FreeItem(entry->canonicalizedName, PR_TRUE);
+    }
+    PORT_Free(entry);
+    return SECSuccess;
+}
+
+/* callback function used in hash table destructor */
+static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg)
+{
+    CRLIssuerCache* issuer = NULL;
+    SECStatus* rv = (SECStatus*) arg;
+
+    PORT_Assert(he);
+    if (!he)
+    {
+        return HT_ENUMERATE_NEXT;
+    }
+    issuer = (CRLIssuerCache*) he->value;
+    PORT_Assert(issuer);
+    if (issuer)
+    {
+        if (SECSuccess != IssuerCache_Destroy(issuer))
+        {
+            PORT_Assert(rv);
+            if (rv)
+            {
+                *rv = SECFailure;
+            }
+            return HT_ENUMERATE_NEXT;
+        }
+    }
+    return HT_ENUMERATE_NEXT;
+}
+
+/* callback function used in hash table destructor */
+static PRIntn PR_CALLBACK FreeNamedEntries(PLHashEntry *he, PRIntn i, void *arg)
+{
+    NamedCRLCacheEntry* entry = NULL;
+    SECStatus* rv = (SECStatus*) arg;
+
+    PORT_Assert(he);
+    if (!he)
+    {
+        return HT_ENUMERATE_NEXT;
+    }
+    entry = (NamedCRLCacheEntry*) he->value;
+    PORT_Assert(entry);
+    if (entry)
+    {
+        if (SECSuccess != NamedCRLCacheEntry_Destroy(entry))
+        {
+            PORT_Assert(rv);
+            if (rv)
+            {
+                *rv = SECFailure;
+            }
+            return HT_ENUMERATE_NEXT;
+        }
+    }
+    return HT_ENUMERATE_NEXT;
+}
+
+/* needs to be called at NSS shutdown time
+   This will destroy the global CRL cache, including 
+   - the hash table of issuer cache objects
+   - the issuer cache objects
+   - DPCache objects in issuer cache objects */
+SECStatus ShutdownCRLCache(void)
+{
+    SECStatus rv = SECSuccess;
+    if (PR_FALSE == crlcache_initialized &&
+        !crlcache.lock && !crlcache.issuers)
+    {
+        /* CRL cache has already been shut down */
+        return SECSuccess;
+    }
+    if (PR_TRUE == crlcache_initialized &&
+        (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock ||
+         !namedCRLCache.entries))
+    {
+        /* CRL cache has partially been shut down */
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    /* empty the CRL cache */
+    /* free the issuers */
+    PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
+    /* free the hash table of issuers */
+    PL_HashTableDestroy(crlcache.issuers);
+    crlcache.issuers = NULL;
+    /* free the global lock */
+#ifdef GLOBAL_RWLOCK
+    NSSRWLock_Destroy(crlcache.lock);
+#else
+    PR_DestroyLock(crlcache.lock);
+#endif
+    crlcache.lock = NULL;
+
+    /* empty the named CRL cache. This must be done after freeing the CRL
+     * cache, since some CRLs in this cache are in the memory for the other  */
+    /* free the entries */
+    PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv);
+    /* free the hash table of issuers */
+    PL_HashTableDestroy(namedCRLCache.entries);
+    namedCRLCache.entries = NULL;
+    /* free the global lock */
+    PR_DestroyLock(namedCRLCache.lock);
+    namedCRLCache.lock = NULL;
+
+    crlcache_initialized = PR_FALSE;
+    return rv;
+}
+
+/* add a new CRL object to the dynamic array of CRLs of the DPCache, and
+   returns the cached CRL object . Needs write access to DPCache. */
+static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl,
+                                PRBool* added)
+{
+    CachedCrl** newcrls = NULL;
+    PRUint32 i = 0;
+    PORT_Assert(cache);
+    PORT_Assert(newcrl);
+    PORT_Assert(added);
+    if (!cache || !newcrl || !added)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    *added = PR_FALSE;
+    /* before adding a new CRL, check if it is a duplicate */
+    for (i=0;i<cache->ncrls;i++)
+    {
+        CachedCrl* existing = NULL;
+        SECStatus rv = SECSuccess;
+        PRBool dupe = PR_FALSE, updated = PR_FALSE;
+        if (!cache->crls)
+        {
+            PORT_Assert(0);
+            return SECFailure;
+        }
+        existing = cache->crls[i];
+        if (!existing)
+        {
+            PORT_Assert(0);
+            return SECFailure;
+        }
+        rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
+        if (SECSuccess != rv)
+        {
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+        }
+        if (PR_TRUE == dupe)
+        {
+            /* dupe */
+            PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
+            return SECSuccess;
+        }
+        if (PR_TRUE == updated)
+        {
+            /* this token CRL is in the same slot and has the same object ID,
+               but different content. We need to remove the old object */
+            if (SECSuccess != DPCache_RemoveCRL(cache, i))
+            {
+                PORT_Assert(0);
+                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+                return PR_FALSE;
+            }
+        }
+    }
+
+    newcrls = (CachedCrl**)PORT_Realloc(cache->crls,
+        (cache->ncrls+1)*sizeof(CachedCrl*));
+    if (!newcrls)
+    {
+        return SECFailure;
+    }
+    cache->crls = newcrls;
+    cache->ncrls++;
+    cache->crls[cache->ncrls-1] = newcrl;
+    *added = PR_TRUE;
+    return SECSuccess;
+}
+
+/* remove CRL at offset specified */
+static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
+{
+    CachedCrl* acrl = NULL;
+    PORT_Assert(cache);
+    if (!cache || (!cache->crls) || (!(offset<cache->ncrls)) )
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    acrl = cache->crls[offset];
+    PORT_Assert(acrl);
+    if (!acrl)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    cache->crls[offset] = cache->crls[cache->ncrls-1];
+    cache->crls[cache->ncrls-1] = NULL;
+    cache->ncrls--;
+    if (cache->selected == acrl) {
+        cache->selected = NULL;
+    }
+    if (SECSuccess != CachedCrl_Destroy(acrl))
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/* check whether a CRL object stored in a PKCS#11 token still exists in
+   that token . This has to be efficient (the entire CRL value cannot be
+   transferred accross the token boundaries), so this is accomplished by
+   simply fetching the subject attribute and making sure it hasn't changed .
+   Note that technically, the CRL object could have been replaced with a new
+   PKCS#11 object of the same ID and subject (which actually happens in
+   softoken), but this function has no way of knowing that the object
+   value changed, since CKA_VALUE isn't checked. */
+static PRBool TokenCRLStillExists(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(crl->slot);
+    if (!slot)
+    {
+        return PR_FALSE;
+    }
+    oldSubject = &crl->crl.derName;
+    PORT_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;
+}
+
+/* verify the signature of a CRL against its issuer at a given date */
+static SECStatus CERT_VerifyCRL(
+    CERTSignedCrl* crlobject,
+    CERTCertificate* issuer,
+    PRTime vfdate,
+    void* wincx)
+{
+    return CERT_VerifySignedData(&crlobject->signatureWrap,
+                                 issuer, vfdate, wincx);
+}
+
+/* verify a CRL and update cache state */
+static SECStatus CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject,
+                          PRTime vfdate, void* wincx)
+{
+    /*  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 (!cache || !crlobject)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError)
+    {
+        crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
+            with bogus DER. Mark it checked so we won't try again */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        return SECSuccess;
+    }
+    else
+    {
+        SECStatus signstatus = SECFailure;
+        if (cache->issuer)
+        {
+            signstatus = CERT_VerifyCRL(crlobject->crl, cache->issuer, vfdate,
+                                        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 */
+            } else
+            {
+                crlobject->sigChecked = PR_TRUE;
+            }
+            PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
+            return SECSuccess;
+        } else
+        {
+            crlobject->sigChecked = PR_TRUE;
+            crlobject->sigValid = PR_TRUE;
+        }
+    }
+    
+    return SECSuccess;
+}
+
+/* fetch the CRLs for this DP from the PKCS#11 tokens */
+static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
+                                         void* wincx)
+{
+    SECStatus rv = SECSuccess;
+    CERTCrlHeadNode head;
+    if (!cache)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    /* first, initialize list */
+    memset(&head, 0, sizeof(head));
+    head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
+
+    /* 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)
+    {
+        /* fetch failed, add error bit */
+        cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
+    } else
+    {
+        /* fetch was successful, clear this error bit */
+        cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
+    }
+
+    /* add any CRLs found to our array */
+    if (SECSuccess == rv)
+    {
+        CERTCrlNode* crlNode = NULL;
+
+        for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
+        {
+            CachedCrl* returned = NULL;
+            CERTSignedCrl* crlobject = crlNode->crl;
+            if (!crlobject)
+            {
+                PORT_Assert(0);
+                continue;
+            }
+            rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
+            if (SECSuccess == rv)
+            {
+                PRBool added = PR_FALSE;
+                rv = DPCache_AddCRL(cache, returned, &added);
+                if (PR_TRUE != added)
+                {
+                    rv = CachedCrl_Destroy(returned);
+                    returned = NULL;
+                }
+                else if (vfdate)
+                {
+                    rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
+                }
+            }
+            else
+            {
+                /* not enough memory to add the CRL to the cache. mark it
+                   invalid so we will try again . */
+                cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
+            }
+            if (SECFailure == rv)
+            {
+                break;
+            }
+        }
+    }
+
+    if (head.arena)
+    {
+        CERTCrlNode* crlNode = NULL;
+        /* clean up the CRL list in case we got a partial one
+           during a failed fetch */
+        for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
+        {
+            if (crlNode->crl)
+            {
+                SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
+                   added to the cache and the refcount got bumped, or not, and
+                   thus we need to free its RAM */
+            }
+        }
+        PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
+    }
+
+    return rv;
+}
+
+static SECStatus CachedCrl_GetEntry(CachedCrl* crl, SECItem* sn,
+                                    CERTCrlEntry** returned)
+{
+    CERTCrlEntry* acrlEntry;
+     
+    PORT_Assert(crl);
+    PORT_Assert(crl->entries);
+    PORT_Assert(sn);
+    PORT_Assert(returned);
+    if (!crl || !sn || !returned || !crl->entries)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn);
+    if (acrlEntry)
+    {
+        *returned = acrlEntry;
+    }
+    else
+    {
+        *returned = NULL;
+    }
+    return SECSuccess;
+}
+
+/* check if a particular SN is in the CRL cache and return its entry */
+dpcacheStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn,
+                         CERTCrlEntry** returned)
+{
+    SECStatus rv;
+    if (!cache || !sn || !returned)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        /* no cache or SN to look up, or no way to return entry */
+        return dpcacheCallerError;
+    }
+    *returned = NULL;
+    if (0 != cache->invalid)
+    {
+        /* the cache contains a bad CRL, or there was a CRL fetching error.
+           consider all certs revoked as a security measure */
+        PORT_SetError(SEC_ERROR_CRL_INVALID);
+        return dpcacheInvalidCacheError;
+    }
+    if (!cache->selected)
+    {
+        /* no CRL means no entry to return. This is OK, except for
+         * NIST policy */
+        return dpcacheEmpty;
+    }
+    rv = CachedCrl_GetEntry(cache->selected, sn, returned);
+    if (SECSuccess != rv)
+    {
+        return dpcacheLookupError;
+    }
+    else
+    {
+        if (*returned)
+        {
+            return dpcacheFoundEntry;
+        }
+        else
+        {
+            return dpcacheNoEntry;
+        }
+    }
+}
+
+#if defined(DPC_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
+
+/* with a global lock, we are always locked for read before we need write
+   access, so do nothing */
+
+#define DPCache_LockWrite() \
+{ \
+}
+
+#define DPCache_UnlockWrite() \
+{ \
+}
+
+#endif
+
+/* update the content of the CRL cache, including fetching of CRLs, and
+   reprocessing with specified issuer and date . We are always holding
+   either the read or write lock on DPCache upon entry. */
+static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate*
+                                     issuer, PRBool readlocked, PRTime vfdate,
+                                     void* wincx)
+{
+    /* 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 forcedrefresh = PR_FALSE;
+    PRBool dirty = PR_FALSE; /* whether something was changed in the
+                                cache state during this update cycle */
+    PRBool hastokenCRLs = PR_FALSE;
+    PRTime now = 0;
+    PRTime lastfetch = 0;
+    PRBool mustunlock = PR_FALSE;
+
+    if (!cache)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    /* first, make sure we have obtained all the CRLs we need.
+       We do an expensive token fetch in the following cases :
+       1) cache is empty because no fetch was ever performed yet
+       2) cache is explicitly set to refresh state
+       3) cache is in invalid state because last fetch failed
+       4) cache contains no token CRLs, and it's been more than one minute
+          since the last fetch
+       5) cache contains token CRLs, and it's been more than 10 minutes since
+          the last fetch
+    */
+    forcedrefresh = cache->refresh;
+    lastfetch = cache->lastfetch;
+    if (PR_TRUE != forcedrefresh && 
+        (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED)))
+    {
+        now = PR_Now();
+        hastokenCRLs = DPCache_HasTokenCRLs(cache);
+    }
+    if ( (0 == lastfetch) ||
+
+         (PR_TRUE == forcedrefresh) ||
+
+         (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
+
+         ( (PR_FALSE == hastokenCRLs) &&
+           ( (now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
+             (now < cache->lastfetch)) ) ||
+
+         ( (PR_TRUE == hastokenCRLs) &&
+           ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
+            (now < cache->lastfetch)) ) )
+    {
+        /* the cache needs to be refreshed, and/or we had zero CRL for this
+           DP. Try to get one from PKCS#11 tokens */
+        DPCache_LockWrite();
+        /* check if another thread updated before us, and skip update if so */
+        if (lastfetch == cache->lastfetch)
+        {
+            /* we are the first */
+            rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
+            if (PR_TRUE == cache->refresh)
+            {
+                cache->refresh = PR_FALSE; /* clear refresh state */
+            }
+            dirty = PR_TRUE;
+            cache->lastfetch = PR_Now();
+        }
+        DPCache_UnlockWrite();
+    }
+
+    /* now, make sure we have no extraneous CRLs (deleted token objects)
+       we'll do this inexpensive existence check either
+       1) if there was a token object fetch
+       2) every minute */
+    if (( PR_TRUE != dirty) && (!now) )
+    {
+        now = PR_Now();
+    }
+    if ( (PR_TRUE == dirty) ||
+         ( (now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
+           (now < cache->lastcheck)) )
+    {
+        PRTime lastcheck = cache->lastcheck;
+        mustunlock = PR_FALSE;
+        /* check if all CRLs still exist */
+        for (i = 0; (i < cache->ncrls) ; i++)
+        {
+            CachedCrl* savcrl = cache->crls[i];
+            if ( (!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin))
+            {
+                /* we only want to check token CRLs */
+                continue;
+            }
+            if ((PR_TRUE != TokenCRLStillExists(savcrl->crl)))
+            {
+                
+                /* this CRL is gone */
+                if (PR_TRUE != mustunlock)
+                {
+                    DPCache_LockWrite();
+                    mustunlock = PR_TRUE;
+                }
+                /* first, we need to check if another thread did an update
+                   before we did */
+                if (lastcheck == cache->lastcheck)
+                {
+                    /* the CRL is gone. And we are the one to do the update */
+                    DPCache_RemoveCRL(cache, i);
+                    dirty = PR_TRUE;
+                }
+                /* stay locked here intentionally so we do all the other
+                   updates in this thread for the remaining CRLs */
+            }
+        }
+        if (PR_TRUE == mustunlock)
+        {
+            cache->lastcheck = PR_Now();
+            DPCache_UnlockWrite();
+            mustunlock = PR_FALSE;
+        }
+    }
+
+    /* add issuer certificate if it was previously unavailable */
+    if (issuer && (NULL == cache->issuer) &&
+        (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN)))
+    {
+        /* if we didn't have a valid issuer cert yet, but we do now. add it */
+        DPCache_LockWrite();
+        if (!cache->issuer)
+        {
+            dirty = PR_TRUE;
+            cache->issuer = CERT_DupCertificate(issuer);    
+        }
+        DPCache_UnlockWrite();
+    }
+
+    /* verify CRLs that couldn't be checked when inserted into the cache
+       because the issuer cert or a verification date was unavailable.
+       These are CRLs that were inserted into the cache through
+       SEC_FindCrlByName, or through manual insertion, rather than through a
+       certificate verification (CERT_CheckCRL) */
+
+    if (cache->issuer && vfdate )
+    {
+	mustunlock = PR_FALSE;
+        /* re-process all unverified CRLs */
+        for (i = 0; i < cache->ncrls ; i++)
+        {
+            CachedCrl* savcrl = cache->crls[i];
+            if (!savcrl)
+            {
+                continue;
+            }
+            if (PR_TRUE != savcrl->sigChecked)
+            {
+                if (!mustunlock)
+                {
+                    DPCache_LockWrite();
+                    mustunlock = PR_TRUE;
+                }
+                /* 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. Make sure first that the CRL is still
+                   in the array at the same position */
+                if ( (i<cache->ncrls) && (savcrl == cache->crls[i]) &&
+                     (PR_TRUE != savcrl->sigChecked) )
+                {
+                    /* the CRL is still there, unverified. Do it */
+                    CachedCrl_Verify(cache, savcrl, vfdate, wincx);
+                    dirty = PR_TRUE;
+                }
+                /* stay locked here intentionally so we do all the other
+                   updates in this thread for the remaining CRLs */
+            }
+            if (mustunlock && !dirty)
+            {
+                DPCache_UnlockWrite();
+                mustunlock = PR_FALSE;
+            }
+        }
+    }
+
+    if (dirty || cache->mustchoose)
+    {
+        /* changes to the content of the CRL cache necessitate examining all
+           CRLs for selection of the most appropriate one to cache */
+	if (!mustunlock)
+	{
+	    DPCache_LockWrite();
+	    mustunlock = PR_TRUE;
+	}
+        DPCache_SelectCRL(cache);
+        cache->mustchoose = PR_FALSE;
+    }
+    if (mustunlock)
+	DPCache_UnlockWrite();
+
+    return rv;
+}
+
+/* callback for qsort to sort by thisUpdate */
+static int SortCRLsByThisUpdate(const void* arg1, const void* arg2)
+{
+    PRTime timea, timeb;
+    SECStatus rv = SECSuccess;
+    CachedCrl* a, *b;
+
+    a = *(CachedCrl**) arg1;
+    b = *(CachedCrl**) arg2;
+
+    if (!a || !b)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        rv = SECFailure;
+    }
+
+    if (SECSuccess == rv)
+    {
+        rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
+    }                       
+    if (SECSuccess == rv)
+    {
+        rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
+    }
+    if (SECSuccess == rv)
+    {
+        if (timea > timeb)
+        {
+            return 1; /* a is better than b */
+        }
+        if (timea < timeb )
+        {
+            return -1; /* a is not as good as b */
+        }
+    }
+
+    /* if they are equal, or if all else fails, use pointer differences */
+    PORT_Assert(a != b); /* they should never be equal */
+    return a>b?1:-1;
+}
+
+/* callback for qsort to sort a set of disparate CRLs, some of which are
+   invalid DER or failed signature check.
+   
+   Validated CRLs are differentiated by thisUpdate .
+   Validated CRLs are preferred over non-validated CRLs .
+   Proper DER CRLs are preferred over non-DER data .
+*/
+static int SortImperfectCRLs(const void* arg1, const void* arg2)
+{
+    CachedCrl* a, *b;
+
+    a = *(CachedCrl**) arg1;
+    b = *(CachedCrl**) arg2;
+
+    if (!a || !b)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        PORT_Assert(0);
+    }
+    else
+    {
+        PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
+        if ( (PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid) )
+        {
+            /* both CRLs have been validated, choose the latest one */
+            return SortCRLsByThisUpdate(arg1, arg2);
+        }
+        if (PR_TRUE == a->sigValid)
+        {
+            return 1; /* a is greater than b */
+        }
+        if (PR_TRUE == b->sigValid)
+        {
+            return -1; /* a is not as good as b */
+        }
+        aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
+        bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
+        /* neither CRL had its signature check pass */
+        if ( (PR_FALSE == aDecoded) && (PR_FALSE == bDecoded) )
+        {
+            /* both CRLs are proper DER, choose the latest one */
+            return SortCRLsByThisUpdate(arg1, arg2);
+        }
+        if (PR_FALSE == aDecoded)
+        {
+            return 1; /* a is better than b */
+        }
+        if (PR_FALSE == bDecoded)
+        {
+            return -1; /* a is not as good as b */
+        }
+        /* both are invalid DER. sigh. */
+    }
+    /* if they are equal, or if all else fails, use pointer differences */
+    PORT_Assert(a != b); /* they should never be equal */
+    return a>b?1:-1;
+}
+
+
+/* Pick best CRL to use . needs write access */
+static SECStatus DPCache_SelectCRL(CRLDPCache* cache)
+{
+    PRUint32 i;
+    PRBool valid = PR_TRUE;
+    CachedCrl* selected = NULL;
+
+    PORT_Assert(cache);
+    if (!cache)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    /* if any invalid CRL is present, then the CRL cache is
+       considered invalid, for security reasons */
+    for (i = 0 ; i<cache->ncrls; i++)
+    {
+        if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
+            !cache->crls[i]->sigValid)
+        {
+            valid = PR_FALSE;
+            break;
+        }
+    }
+    if (PR_TRUE == valid)
+    {
+        /* all CRLs are valid, clear this error */
+        cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
+    } else
+    {
+        /* some CRLs are invalid, set this error */
+        cache->invalid |= CRL_CACHE_INVALID_CRLS;
+    }
+
+    if (cache->invalid)
+    {
+        /* cache is in an invalid state, so reset it */
+        if (cache->selected)
+        {
+            cache->selected = NULL;
+        }
+        /* also sort the CRLs imperfectly */
+        qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
+              SortImperfectCRLs);
+        return SECSuccess;
+    }
+    /* all CRLs are good, sort them by thisUpdate */
+    qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
+          SortCRLsByThisUpdate);
+
+    if (cache->ncrls)
+    {
+        /* pick the newest CRL */
+        selected = cache->crls[cache->ncrls-1];
+    
+        /* and populate the cache */
+        if (SECSuccess != CachedCrl_Populate(selected))
+        {
+            return SECFailure;
+        }
+    }
+
+    cache->selected = selected;
+
+    return SECSuccess;
+}
+
+/* initialize a DPCache object */
+static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
+                         const SECItem* subject, SECItem* dp)
+{
+    CRLDPCache* cache = NULL;
+    PORT_Assert(returned);
+    /* issuer and dp are allowed to be NULL */
+    if (!returned || !subject)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    *returned = NULL;
+    cache = PORT_ZAlloc(sizeof(CRLDPCache));
+    if (!cache)
+    {
+        return SECFailure;
+    }
+#ifdef DPC_RWLOCK
+    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
+#else
+    cache->lock = PR_NewLock();
+#endif
+    if (!cache->lock)
+    {
+	PORT_Free(cache);
+        return SECFailure;
+    }
+    if (issuer)
+    {
+        cache->issuer = CERT_DupCertificate(issuer);
+    }
+    cache->distributionPoint = SECITEM_DupItem(dp);
+    cache->subject = SECITEM_DupItem(subject);
+    cache->lastfetch = 0;
+    cache->lastcheck = 0;
+    *returned = cache;
+    return SECSuccess;
+}
+
+/* create an issuer cache object (per CA subject ) */
+static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
+                             CERTCertificate* issuer,
+                             const SECItem* subject, const SECItem* dp)
+{
+    SECStatus rv = SECSuccess;
+    CRLIssuerCache* cache = NULL;
+    PORT_Assert(returned);
+    PORT_Assert(subject);
+    /* issuer and dp are allowed to be NULL */
+    if (!returned || !subject)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    *returned = NULL;
+    cache = (CRLIssuerCache*) PORT_ZAlloc(sizeof(CRLIssuerCache));
+    if (!cache)
+    {
+        return SECFailure;
+    }
+    cache->subject = SECITEM_DupItem(subject);
+#ifdef 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)
+    {
+        PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
+        return SECFailure;
+    }
+    *returned = cache;
+    return SECSuccess;
+}
+
+/* add a DPCache to the issuer cache */
+static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
+                                   CERTCertificate* issuer,
+                                   const SECItem* subject,
+                                   const SECItem* dp,
+                                   CRLDPCache** newdpc)
+{
+    /* now create the required DP cache object */
+    if (!cache || !subject || !newdpc)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (!dp)
+    {
+        /* default distribution point */
+        SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
+        if (SECSuccess == rv)
+        {
+            *newdpc = cache->dpp;
+            return SECSuccess;
+        }
+    }
+    else
+    {
+        /* we should never hit this until we support multiple DPs */
+        PORT_Assert(dp);
+        /* XCRL allocate a new distribution point cache object, initialize it,
+           and add it to the hash table of DPs */
+    }
+    return SECFailure;
+}
+
+/* add an IssuerCache to the global hash table of issuers */
+static SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer)
+{    
+    PORT_Assert(issuer);
+    PORT_Assert(crlcache.issuers);
+    if (!issuer || !crlcache.issuers)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
+                                (void*) issuer))
+    {
+        return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/* retrieve the issuer cache object for a given issuer subject */
+static SECStatus CRLCache_GetIssuerCache(CRLCache* cache,
+                                         const 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)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        rv = SECFailure;
+    }
+
+    if (SECSuccess == rv)
+    {
+        *returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
+                                                         (void*) subject);
+    }
+
+    return rv;
+}
+
+/* retrieve the full CRL object that best matches the content of a DPCache */
+static CERTSignedCrl* GetBestCRL(CRLDPCache* cache, PRBool entries)
+{
+    CachedCrl* acrl = NULL;
+
+    PORT_Assert(cache);
+    if (!cache)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return NULL;
+    }
+
+    if (0 == cache->ncrls)
+    {
+        /* empty cache*/
+        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+        return NULL;
+    }    
+
+    /* if we have a valid full CRL selected, return it */
+    if (cache->selected)
+    {
+        return SEC_DupCrl(cache->selected->crl);
+    }
+
+    /* otherwise, use latest valid DER CRL */
+    acrl = cache->crls[cache->ncrls-1];
+
+    if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError) )
+    {
+        SECStatus rv = SECSuccess;
+        if (PR_TRUE == entries)
+        {
+            rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
+        }
+        if (SECSuccess == rv)
+        {
+            return SEC_DupCrl(acrl->crl);
+        }
+    }
+
+    PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+    return NULL;
+}
+
+/* get a particular DPCache object from an IssuerCache */
+static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, const 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)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return NULL;
+    }
+#ifdef XCRL
+    NSSRWLock_LockRead(cache->lock);
+#endif
+    dpp = cache->dpp;
+#ifdef XCRL
+    NSSRWLock_UnlockRead(cache->lock);
+#endif
+    return dpp;
+}
+
+/* get a DPCache object for the given issuer subject and dp
+   Automatically creates the cache object if it doesn't exist yet.
+   */
+SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
+                         const SECItem* dp, PRTime t, void* wincx,
+                         CRLDPCache** dpcache, PRBool* writeLocked)
+{
+    SECStatus rv = SECSuccess;
+    CRLIssuerCache* issuercache = NULL;
+#ifdef GLOBAL_RWLOCK
+    PRBool globalwrite = PR_FALSE;
+#endif
+    PORT_Assert(crlcache.lock);
+    if (!crlcache.lock)
+    {
+        /* CRL cache is not initialized */
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+#ifdef GLOBAL_RWLOCK
+    NSSRWLock_LockRead(crlcache.lock);
+#else
+    PR_Lock(crlcache.lock);
+#endif
+    rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
+    if (SECSuccess != rv)
+    {
+#ifdef GLOBAL_RWLOCK
+        NSSRWLock_UnlockRead(crlcache.lock);
+#else
+        PR_Unlock(crlcache.lock);
+#endif
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        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. */
+        
+        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 DPC_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 */
+#ifdef GLOBAL_RWLOCK
+            CRLIssuerCache* existing = NULL;
+            NSSRWLock_UnlockRead(crlcache.lock);
+            /* when using a r/w lock for the global cache, check if the issuer
+               already exists before adding to the hash table */
+            NSSRWLock_LockWrite(crlcache.lock);
+            globalwrite = PR_TRUE;
+            rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
+            if (!existing)
+            {
+#endif
+                rv = CRLCache_AddIssuer(issuercache);
+                if (SECSuccess != rv)
+                {
+                    /* failure */
+                    rv = SECFailure;
+                }
+#ifdef GLOBAL_RWLOCK
+            }
+            else
+            {
+                /* somebody else updated before we did */
+                IssuerCache_Destroy(issuercache); /* destroy the new object */
+                issuercache = existing; /* use the existing one */
+                *dpcache = IssuerCache_GetDPCache(issuercache, dp);
+            }
+#endif
+        }
+
+        /* now unlock the global cache. We only want to lock the issuer hash
+           table addition. Holding it longer would hurt scalability */
+#ifdef GLOBAL_RWLOCK
+        if (PR_TRUE == globalwrite)
+        {
+            NSSRWLock_UnlockWrite(crlcache.lock);
+            globalwrite = PR_FALSE;
+        }
+        else
+        {
+            NSSRWLock_UnlockRead(crlcache.lock);
+        }
+#else
+        PR_Unlock(crlcache.lock);
+#endif
+
+        /* if there was a failure adding an issuer cache object, destroy it */
+        if (SECSuccess != rv && issuercache)
+        {
+            if (PR_TRUE == *writeLocked)
+            {
+#ifdef DPC_RWLOCK
+                NSSRWLock_UnlockWrite((*dpcache)->lock);
+#else
+                PR_Unlock((*dpcache)->lock);
+#endif
+            }
+            IssuerCache_Destroy(issuercache);
+            issuercache = NULL;
+        }
+
+        if (SECSuccess != rv)
+        {
+            return SECFailure;
+        }
+    } else
+    {
+#ifdef GLOBAL_RWLOCK
+        NSSRWLock_UnlockRead(crlcache.lock);
+#else
+        PR_Unlock(crlcache.lock);
+#endif
+        *dpcache = IssuerCache_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 DPC_RWLOCK
+        NSSRWLock_LockRead((*dpcache)->lock);
+#else
+        PR_Lock((*dpcache)->lock);
+#endif
+    }
+    
+    if (SECSuccess == rv)
+    {
+        /* currently there is always one and only one DPCache per issuer */
+        PORT_Assert(*dpcache);
+        if (*dpcache)
+        {
+            /* make sure the DP cache is up to date before using it */
+            rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
+                                     t, wincx);
+        }
+        else
+        {
+            rv = SECFailure;
+        }
+    }
+    return rv;
+}
+
+/* unlock access to the DPCache */
+void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
+{
+    if (!dpcache)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return;
+    }
+#ifdef DPC_RWLOCK
+    if (PR_TRUE == writeLocked)
+    {
+        NSSRWLock_UnlockWrite(dpcache->lock);
+    }
+    else
+    {
+        NSSRWLock_UnlockRead(dpcache->lock);
+    }
+#else
+    PR_Unlock(dpcache->lock);
+#endif
+}
+
+SECStatus
+cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
+                               const SECItem* dp, PRTime t, void *wincx,
+                               CERTRevocationStatus *revStatus,
+                               CERTCRLEntryReasonCode *revReason)
+{
+    PRBool lockedwrite = PR_FALSE;
+    SECStatus rv = SECSuccess;
+    CRLDPCache* dpcache = NULL;
+    CERTRevocationStatus status = certRevocationStatusRevoked;
+    CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified;
+    CERTCrlEntry* entry = NULL;
+    dpcacheStatus ds;
+
+    if (!cert || !issuer)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    if (revStatus)
+    {
+        *revStatus = status;
+    }
+    if (revReason)
+    {
+        *revReason = reason;
+    }
+
+    if (t && SECSuccess != CERT_CheckCertValidTimes(issuer, t, PR_FALSE))
+    {
+        /* we won't be able to check the CRL's signature if the issuer cert
+           is expired as of the time we are verifying. This may cause a valid
+           CRL to be cached as bad. short-circuit to avoid this case. */
+        PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
+        return SECFailure;
+    }
+
+    rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
+                        &lockedwrite);
+    PORT_Assert(SECSuccess == rv);
+    if (SECSuccess != rv)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    /* now look up the certificate SN in the DP cache's CRL */
+    ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
+    switch (ds)
+    {
+        case dpcacheFoundEntry:
+            PORT_Assert(entry);
+            /* check the time if we have one */
+            if (entry->revocationDate.data && entry->revocationDate.len)
+            {
+                PRTime revocationDate = 0;
+                if (SECSuccess == DER_DecodeTimeChoice(&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
+                    {
+                        status = certRevocationStatusValid;
+                    }
+                }
+                else
+                {
+                    /* invalid revocation date, consider the certificate
+                       permanently revoked */
+                    rv = SECFailure;
+                }
+            }
+            else
+            {
+                /* no revocation date, certificate is permanently revoked */
+                rv = SECFailure;
+            }
+            if (SECFailure == rv)
+            {
+                SECStatus rv2 = CERT_FindCRLEntryReasonExten(entry, &reason);
+                PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
+            }
+            break;
+
+        case dpcacheEmpty:
+            /* useful for NIST policy */
+            status = certRevocationStatusUnknown;
+            break;
+
+        case dpcacheNoEntry:
+            status = certRevocationStatusValid;
+            break;
+
+        case dpcacheInvalidCacheError:
+            /* t of zero may have caused the CRL cache to fail to verify
+             * a CRL. treat it as unknown */
+            if (!t)
+            {
+                status = certRevocationStatusUnknown;
+            }
+            break;
+
+        default:
+            /* leave status as revoked */
+            break;
+    }
+
+    ReleaseDPCache(dpcache, lockedwrite);
+    if (revStatus)
+    {
+        *revStatus = status;
+    }
+    if (revReason)
+    {
+        *revReason = reason;
+    }
+    return rv;
+}
+
+/* check CRL revocation status of given certificate and issuer */
+SECStatus
+CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer,
+              const SECItem* dp, PRTime t, void* wincx)
+{
+    return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx,
+                                          NULL, NULL);
+}
+
+/* retrieve full CRL object that best matches the cache status */
+CERTSignedCrl *
+SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
+{
+    CERTSignedCrl* acrl = NULL;
+    CRLDPCache* dpcache = NULL;
+    SECStatus rv = SECSuccess;
+    PRBool writeLocked = PR_FALSE;
+
+    if (!crlKey)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
+    if (SECSuccess == rv)
+    {
+        acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
+        SEC_FindCrlByName always returned fully decoded CRLs in the past */
+        ReleaseDPCache(dpcache, writeLocked);
+    }
+    return acrl;
+}
+
+/* invalidate the CRL cache for a given issuer, which forces a refetch of
+   CRL objects from PKCS#11 tokens */
+void CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
+{
+    CRLDPCache* cache = NULL;
+    SECStatus rv = SECSuccess;
+    PRBool writeLocked = PR_FALSE;
+    PRBool readlocked;
+
+    (void) dbhandle; /* silence compiler warnings */
+
+    /* XCRL we will need to refresh all the DPs of the issuer in the future,
+            not just the default one */
+    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
+    if (SECSuccess != rv)
+    {
+        return;
+    }
+    /* we need to invalidate the DPCache here */
+    readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
+    DPCache_LockWrite();
+    cache->refresh = PR_TRUE;
+    DPCache_UnlockWrite();
+    ReleaseDPCache(cache, writeLocked);
+    return;
+}
+
+/* add the specified RAM CRL object to the cache */
+SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
+{
+    CRLDPCache* cache = NULL;
+    SECStatus rv = SECSuccess;
+    PRBool writeLocked = PR_FALSE;
+    PRBool readlocked;
+    CachedCrl* returned = NULL;
+    PRBool added = PR_FALSE;
+    CERTSignedCrl* newcrl = NULL;
+    int realerror = 0;
+    
+    if (!dbhandle || !newdercrl)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    /* first decode the DER CRL to make sure it's OK */
+    newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
+                                        CRL_DECODE_DONT_COPY_DER |
+                                        CRL_DECODE_SKIP_ENTRIES);
+
+    if (!newcrl)
+    {
+        return SECFailure;
+    }
+
+    /* XXX check if it has IDP extension. If so, do not proceed and set error */
+
+    rv = AcquireDPCache(NULL,
+                        &newcrl->crl.derName,
+                        NULL, 0, NULL, &cache, &writeLocked);
+    if (SECSuccess == rv)
+    {
+        readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
+    
+        rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
+        if (SECSuccess == rv && returned)
+        {
+            DPCache_LockWrite();
+            rv = DPCache_AddCRL(cache, returned, &added);
+            if (PR_TRUE != added)
+            {
+                realerror = PORT_GetError();
+                CachedCrl_Destroy(returned);
+                returned = NULL;
+            }
+            DPCache_UnlockWrite();
+        }
+    
+        ReleaseDPCache(cache, writeLocked);
+    
+        if (!added)
+        {
+            rv = SECFailure;
+        }
+    }
+    SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
+        and the refcount got bumped, or not, and thus we need to free its
+        RAM */
+    if (realerror)
+    {
+        PORT_SetError(realerror);
+    }
+    return rv;
+}
+
+/* remove the specified RAM CRL object from the cache */
+SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
+{
+    CRLDPCache* cache = NULL;
+    SECStatus rv = SECSuccess;
+    PRBool writeLocked = PR_FALSE;
+    PRBool readlocked;
+    PRBool removed = PR_FALSE;
+    PRUint32 i;
+    CERTSignedCrl* oldcrl = NULL;
+    
+    if (!dbhandle || !olddercrl)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    /* first decode the DER CRL to make sure it's OK */
+    oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
+                                        CRL_DECODE_DONT_COPY_DER |
+                                        CRL_DECODE_SKIP_ENTRIES);
+
+    if (!oldcrl)
+    {
+        /* if this DER CRL can't decode, it can't be in the cache */
+        return SECFailure;
+    }
+
+    rv = AcquireDPCache(NULL,
+                        &oldcrl->crl.derName,
+                        NULL, 0, NULL, &cache, &writeLocked);
+    if (SECSuccess == rv)
+    {
+        CachedCrl* returned = NULL;
+
+        readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
+    
+        rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
+        if (SECSuccess == rv && returned)
+        {
+            DPCache_LockWrite();
+            for (i=0;i<cache->ncrls;i++)
+            {
+                PRBool dupe = PR_FALSE, updated = PR_FALSE;
+                rv = CachedCrl_Compare(returned, cache->crls[i],
+                                                      &dupe, &updated);
+                if (SECSuccess != rv)
+                {
+                    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+                    break;
+                }
+                if (PR_TRUE == dupe)
+                {
+                    rv = DPCache_RemoveCRL(cache, i); /* got a match */
+                    if (SECSuccess == rv) {
+                        cache->mustchoose = PR_TRUE;
+                        removed = PR_TRUE;
+                    }
+                    break;
+                }
+            }
+            
+            DPCache_UnlockWrite();
+
+            if (SECSuccess != CachedCrl_Destroy(returned) ) {
+                rv = SECFailure;
+            }
+        }
+
+        ReleaseDPCache(cache, writeLocked);
+    }
+    if (SECSuccess != SEC_DestroyCrl(oldcrl) ) { 
+        /* need to do this because object is refcounted */
+        rv = SECFailure;
+    }
+    if (SECSuccess == rv && PR_TRUE != removed)
+    {
+        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+    }
+    return rv;
+}
+
+SECStatus cert_AcquireNamedCRLCache(NamedCRLCache** returned)
+{
+    PORT_Assert(returned);
+    if (!namedCRLCache.lock)
+    {
+        PORT_Assert(0);
+        return SECFailure;
+    }
+    PR_Lock(namedCRLCache.lock);
+    *returned = &namedCRLCache;
+    return SECSuccess;
+}
+
+/* This must be called only while cache is acquired, and the entry is only
+ * valid until cache is released.
+ */
+SECStatus cert_FindCRLByGeneralName(NamedCRLCache* ncc,
+                                    const SECItem* canonicalizedName,
+                                    NamedCRLCacheEntry** retEntry)
+{
+    if (!ncc || !canonicalizedName || !retEntry)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    *retEntry = (NamedCRLCacheEntry*) PL_HashTableLookup(namedCRLCache.entries,
+                                         (void*) canonicalizedName);
+    return SECSuccess;
+}
+
+SECStatus cert_ReleaseNamedCRLCache(NamedCRLCache* ncc)
+{
+    if (!ncc)
+    {
+        return SECFailure;
+    }
+    if (!ncc->lock)
+    {
+        PORT_Assert(0);
+        return SECFailure;
+    }
+    PR_Unlock(namedCRLCache.lock);
+    return SECSuccess;
+}
+
+/* creates new named cache entry from CRL, and tries to add it to CRL cache */
+static SECStatus addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl,
+                                    const SECItem* canonicalizedName,
+                                    NamedCRLCacheEntry** newEntry)
+{
+    SECStatus rv = SECSuccess;
+    NamedCRLCacheEntry* entry = NULL;
+
+    /* create new named entry */
+    if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry)
+    {
+        /* no need to keep unused CRL around */
+        SECITEM_ZfreeItem(crl, PR_TRUE);
+        return SECFailure;
+    }
+    entry = *newEntry;
+    entry->crl = crl; /* named CRL cache owns DER */
+    entry->lastAttemptTime = PR_Now();
+    entry->canonicalizedName = SECITEM_DupItem(canonicalizedName);
+    if (!entry->canonicalizedName)
+    {
+        rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */
+        PORT_Assert(SECSuccess == rv);
+        return SECFailure;
+    }
+    /* now, attempt to insert CRL into CRL cache */
+    if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl))
+    {
+        entry->inCRLCache = PR_TRUE;
+        entry->successfulInsertionTime = entry->lastAttemptTime;
+    }
+    else
+    {
+        switch (PR_GetError())
+        {
+            case SEC_ERROR_CRL_ALREADY_EXISTS:
+                entry->dupe = PR_TRUE;
+                break;
+
+            case SEC_ERROR_BAD_DER:
+                entry->badDER = PR_TRUE;
+                break;
+
+            /* all other reasons */
+            default:
+                entry->unsupported = PR_TRUE;
+                break;
+        }
+        rv = SECFailure;
+        /* no need to keep unused CRL around */
+        SECITEM_ZfreeItem(entry->crl, PR_TRUE);
+        entry->crl = NULL;
+    }
+    return rv;
+}
+
+/* take ownership of CRL, and insert it into the named CRL cache
+ * and indexed CRL cache
+ */
+SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
+                                     const SECItem* canonicalizedName)
+{
+    NamedCRLCacheEntry* oldEntry, * newEntry = NULL;
+    NamedCRLCache* ncc = NULL;
+    SECStatus rv = SECSuccess, rv2;
+
+    PORT_Assert(namedCRLCache.lock);
+    PORT_Assert(namedCRLCache.entries);
+
+    if (!crl || !canonicalizedName)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    rv = cert_AcquireNamedCRLCache(&ncc);
+    PORT_Assert(SECSuccess == rv);
+    if (SECSuccess != rv)
+    {
+        SECITEM_ZfreeItem(crl, PR_TRUE);
+        return SECFailure;
+    }
+    rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry);
+    PORT_Assert(SECSuccess == rv);
+    if (SECSuccess != rv)
+    {
+        rv = cert_ReleaseNamedCRLCache(ncc);
+        SECITEM_ZfreeItem(crl, PR_TRUE);
+        return SECFailure;
+    }
+    if (SECSuccess == addCRLToCache(dbhandle, crl, canonicalizedName,
+                                    &newEntry) )
+    {
+        if (!oldEntry)
+        {
+            /* add new good entry to the hash table */
+            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
+                                        (void*) newEntry->canonicalizedName,
+                                        (void*) newEntry))
+            {
+                PORT_Assert(0);
+                rv2 = NamedCRLCacheEntry_Destroy(newEntry);
+                PORT_Assert(SECSuccess == rv2);
+                rv = SECFailure;
+            }
+        }
+        else
+        {
+            PRBool removed;
+            /* remove the old CRL from the cache if needed */
+            if (oldEntry->inCRLCache)
+            {
+                rv = CERT_UncacheCRL(dbhandle, oldEntry->crl);
+                PORT_Assert(SECSuccess == rv);
+            }
+            removed = PL_HashTableRemove(namedCRLCache.entries,
+                                      (void*) oldEntry->canonicalizedName);
+            PORT_Assert(removed);
+            if (!removed)
+            {
+                rv = SECFailure;
+		/* leak old entry since we couldn't remove it from the hash table */
+            }
+            else
+            {
+                rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
+                PORT_Assert(SECSuccess == rv2);
+            }
+            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
+                                      (void*) newEntry->canonicalizedName,
+                                      (void*) newEntry))
+            {
+                PORT_Assert(0);
+                rv = SECFailure;
+            }
+        }
+    } else
+    {
+        /* error adding new CRL to cache */
+        if (!oldEntry)
+        {
+            /* no old cache entry, use the new one even though it's bad */
+            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
+                                        (void*) newEntry->canonicalizedName,
+                                        (void*) newEntry))
+            {
+                PORT_Assert(0);
+                rv = SECFailure;
+            }
+        }
+        else
+        {
+            if (oldEntry->inCRLCache)
+            {
+                /* previous cache entry was good, keep it and update time */
+                oldEntry-> lastAttemptTime = newEntry->lastAttemptTime;
+                /* throw away new bad entry */
+                rv = NamedCRLCacheEntry_Destroy(newEntry);
+                PORT_Assert(SECSuccess == rv);
+            }
+            else
+            {
+                /* previous cache entry was bad, just replace it */
+                PRBool removed = PL_HashTableRemove(namedCRLCache.entries,
+                                          (void*) oldEntry->canonicalizedName);
+                PORT_Assert(removed);
+                if (!removed)
+                {
+		    /* leak old entry since we couldn't remove it from the hash table */
+                    rv = SECFailure;
+                }
+                else
+                {
+                    rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
+                    PORT_Assert(SECSuccess == rv2);
+                }
+                if (NULL == PL_HashTableAdd(namedCRLCache.entries,
+                                          (void*) newEntry->canonicalizedName,
+                                          (void*) newEntry))
+                {
+                    PORT_Assert(0);
+                    rv = SECFailure;
+                }
+            }
+        }
+    }
+    rv2 = cert_ReleaseNamedCRLCache(ncc);
+    PORT_Assert(SECSuccess == rv2);
+
+    return rv;
+}
+
+static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
+                                  CRLOrigin origin)
+{
+    CachedCrl* newcrl = NULL;
+    if (!returned)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    newcrl = PORT_ZAlloc(sizeof(CachedCrl));
+    if (!newcrl)
+    {
+        return SECFailure;
+    }
+    newcrl->crl = SEC_DupCrl(crl);
+    newcrl->origin = origin;
+    *returned = newcrl;
+    return SECSuccess;
+}
+
+/* empty the cache content */
+static SECStatus CachedCrl_Depopulate(CachedCrl* crl)
+{
+    if (!crl)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+     /* destroy the hash table */
+    if (crl->entries)
+    {
+        PL_HashTableDestroy(crl->entries);
+        crl->entries = NULL;
+    }
+
+    /* free the pre buffer */
+    if (crl->prebuffer)
+    {
+        PreAllocator_Destroy(crl->prebuffer);
+        crl->prebuffer = NULL;
+    }
+    return SECSuccess;
+}
+
+static SECStatus CachedCrl_Destroy(CachedCrl* crl)
+{
+    if (!crl)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    CachedCrl_Depopulate(crl);
+    SEC_DestroyCrl(crl->crl);
+    PORT_Free(crl);
+    return SECSuccess;
+}
+
+/* create hash table of CRL entries */
+static SECStatus CachedCrl_Populate(CachedCrl* crlobject)
+{
+    SECStatus rv = SECFailure;
+    CERTCrlEntry** crlEntry = NULL;
+    PRUint32 numEntries = 0;
+
+    if (!crlobject)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    /* complete the entry decoding . XXX thread-safety of CRL object */
+    rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
+    if (SECSuccess != rv)
+    {
+        crlobject->unbuildable = PR_TRUE; /* don't try to build this again */
+        return SECFailure;
+    }
+
+    if (crlobject->entries && crlobject->prebuffer)
+    {
+        /* cache is already built */
+        return SECSuccess;
+    }
+
+    /* build the hash table from the full CRL */    
+    /* count CRL entries so we can pre-allocate space for hash table entries */
+    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
+         crlEntry++)
+    {
+        numEntries++;
+    }
+    crlobject->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
+    PORT_Assert(crlobject->prebuffer);
+    if (!crlobject->prebuffer)
+    {
+        return SECFailure;
+    }
+    /* create a new hash table */
+    crlobject->entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+                         PL_CompareValues, &preAllocOps, crlobject->prebuffer);
+    PORT_Assert(crlobject->entries);
+    if (!crlobject->entries)
+    {
+        return SECFailure;
+    }
+    /* add all serial numbers to the hash table */
+    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
+         crlEntry++)
+    {
+        PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
+                        *crlEntry);
+    }
+
+    return SECSuccess;
+}
+
+/* returns true if there are CRLs from PKCS#11 slots */
+static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache)
+{
+    PRBool answer = PR_FALSE;
+    PRUint32 i;
+    for (i=0;i<cache->ncrls;i++)
+    {
+        if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin) )
+        {
+            answer = PR_TRUE;
+            break;
+        }
+    }
+    return answer;
+}
+
+/* are these CRLs the same, as far as the cache is concerned ? */
+/* are these CRLs the same token object but with different DER ?
+   This can happen if the DER CRL got updated in the token, but the PKCS#11
+   object ID did not change. NSS softoken has the unfortunate property to
+   never change the object ID for CRL objects. */
+static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
+                                PRBool* isUpdated)
+{
+    PORT_Assert(a);
+    PORT_Assert(b);
+    PORT_Assert(isDupe);
+    PORT_Assert(isUpdated);
+    if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl)
+    {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    *isDupe = *isUpdated = PR_FALSE;
+
+    if (a == b)
+    {
+        /* dupe */
+        *isDupe = PR_TRUE;
+        *isUpdated = PR_FALSE;
+        return SECSuccess;
+    }
+    if (b->origin != a->origin)
+    {
+        /* CRLs of different origins are not considered dupes,
+           and can't be updated either */
+        return SECSuccess;
+    }
+    if (CRL_OriginToken == b->origin)
+    {
+        /* for token CRLs, slot and PKCS#11 object handle must match for CRL
+           to truly be a dupe */
+        if ( (b->crl->slot == a->crl->slot) &&
+             (b->crl->pkcs11ID == a->crl->pkcs11ID) )
+        {
+            /* ASN.1 DER needs to match for dupe check */
+            /* could optimize by just checking a few fields like thisUpdate */
+            if ( SECEqual == SECITEM_CompareItem(b->crl->derCrl,
+                                                 a->crl->derCrl) )
+            {
+                *isDupe = PR_TRUE;
+            }
+            else
+            {
+                *isUpdated = PR_TRUE;
+            }
+        }
+        return SECSuccess;
+    }
+    if (CRL_OriginExplicit == b->origin)
+    {
+        /* We need to make sure this is the same object that the user provided
+           to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
+           just do a pointer comparison here.
+        */
+        if (b->crl->derCrl == a->crl->derCrl)
+        {
+            *isDupe = PR_TRUE;
+        }
+    }
+    return SECSuccess;
+}
+
+/* this function assumes the caller holds a read lock on the DPCache */
+SECStatus DPCache_GetAllCRLs(CRLDPCache* dpc, PRArenaPool* arena,
+                             CERTSignedCrl*** crls, PRUint16* status)
+{
+    CERTSignedCrl** allcrls;
+    PRUint32 index;
+    if (!dpc || !crls || !status)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    *status = dpc->invalid;
+    *crls = NULL;
+    if (!dpc->ncrls)
+    {
+        /* no CRLs to return */
+        return SECSuccess;
+    }
+    allcrls = PORT_ArenaZNewArray(arena, CERTSignedCrl*, dpc->ncrls +1);
+    if (!allcrls)
+    {
+        return SECFailure;
+    }
+    for (index=0; index < dpc->ncrls ; index ++) {
+        CachedCrl* cachedcrl = dpc->crls[index];
+        if (!cachedcrl || !cachedcrl->crl)
+        {
+            PORT_Assert(0); /* this should never happen */
+            continue;
+        }
+        allcrls[index] = SEC_DupCrl(cachedcrl->crl);
+    }
+    *crls = allcrls;
+    return SECSuccess;
+}
+
+static CachedCrl* DPCache_FindCRL(CRLDPCache* cache, CERTSignedCrl* crl)
+{
+    PRUint32 index;
+    CachedCrl* cachedcrl = NULL;
+    for (index=0; index < cache->ncrls ; index ++) {
+        cachedcrl = cache->crls[index];
+        if (!cachedcrl || !cachedcrl->crl)
+        {
+            PORT_Assert(0); /* this should never happen */
+            continue;
+        }
+        if (cachedcrl->crl == crl) {
+            break;
+        }
+    }
+    return cachedcrl;
+}
+
+/* this function assumes the caller holds a lock on the DPCache */
+SECStatus DPCache_GetCRLEntry(CRLDPCache* cache, PRBool readlocked,
+                              CERTSignedCrl* crl, SECItem* sn,
+                              CERTCrlEntry** returned)
+{
+    CachedCrl* cachedcrl = NULL;
+    if (!cache || !crl || !sn || !returned)
+    {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    *returned = NULL;
+    /* first, we need to find the CachedCrl* that matches this CERTSignedCRL */
+    cachedcrl = DPCache_FindCRL(cache, crl);
+    if (!cachedcrl) {
+        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+        return SECFailure;
+    }
+
+    if (cachedcrl->unbuildable) {
+        /* this CRL could not be fully decoded */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        return SECFailure;
+    }
+    /* now, make sure it has a hash table. Otherwise, we'll need to build one */
+    if (!cachedcrl->entries || !cachedcrl->prebuffer) {
+        DPCache_LockWrite();
+        CachedCrl_Populate(cachedcrl);
+        DPCache_UnlockWrite();
+    }
+
+    /* finally, get the CRL entry */       
+    return CachedCrl_GetEntry(cachedcrl, sn, returned);
+}
+
diff --git a/mozilla/security/nss/lib/certdb/genname.c b/mozilla/security/nss/lib/certdb/genname.c
new file mode 100644
index 0000000..d465967
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/genname.c
@@ -0,0 +1,1974 @@
+/* ***** 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 "plarena.h"
+#include "seccomon.h"
+#include "secitem.h"
+#include "secoidt.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"
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_IntegerTemplate)
+SEC_ASN1_MKSUB(SEC_IA5StringTemplate)
+SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+
+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 | SEC_ASN1_XTRN | 0, 
+          offsetof(CERTNameConstraint, min),
+          SEC_ASN1_SUB(SEC_IntegerTemplate) }, 
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, 
+          offsetof(CERTNameConstraint, max),
+          SEC_ASN1_SUB(SEC_IntegerTemplate) },
+    { 0, }
+};
+
+const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
+};
+
+static const SEC_ASN1Template CERTNameConstraintsTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraints) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, 
+          offsetof(CERTNameConstraints, DERPermited), 
+	  CERT_NameConstraintSubtreeSubTemplate},
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 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 |
+          SEC_ASN1_XTRN | 0, offsetof(OtherName, name),
+          SEC_ASN1_SUB(SEC_AnyTemplate) },
+    { 0, } 
+};
+
+static const SEC_ASN1Template CERTOtherNameTemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 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 | SEC_ASN1_XTRN | 1 ,
+          offsetof(CERTGeneralName, name.other),
+          SEC_ASN1_SUB(SEC_IA5StringTemplate),
+          sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_DNSNameTemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2 ,
+          offsetof(CERTGeneralName, name.other),
+          SEC_ASN1_SUB(SEC_IA5StringTemplate),
+          sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_X400AddressTemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 3,
+          offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
+          sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_DirectoryNameTemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
+          SEC_ASN1_XTRN | 4, offsetof(CERTGeneralName, derDirectoryName),
+          SEC_ASN1_SUB(SEC_AnyTemplate), sizeof (CERTGeneralName)}
+};
+
+
+static const SEC_ASN1Template CERT_EDIPartyNameTemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 5,
+          offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
+          sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_URITemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 6 ,
+          offsetof(CERTGeneralName, name.other),
+          SEC_ASN1_SUB(SEC_IA5StringTemplate),
+          sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_IPAddressTemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 7 ,
+          offsetof(CERTGeneralName, name.other),
+          SEC_ASN1_SUB(SEC_OctetStringTemplate),
+          sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_RegisteredIDTemplate[] = {
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 8 ,
+          offsetof(CERTGeneralName, name.other),
+          SEC_ASN1_SUB(SEC_ObjectIDTemplate),
+          sizeof (CERTGeneralName)}
+};
+
+
+const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN , 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
+};
+
+
+
+CERTGeneralName *
+CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type)
+{
+    CERTGeneralName *name = arena 
+                            ? PORT_ArenaZNew(arena, CERTGeneralName)
+	                    : PORT_ZNew(CERTGeneralName);
+    if (name) {
+	name->type = type;
+	name->l.prev = name->l.next = &name->l;
+    }
+    return name;
+}
+
+/* Copy content of one General Name to another.
+** Caller has allocated destination general name.
+** This function does not change the destinate's GeneralName's list linkage.
+*/
+SECStatus
+cert_CopyOneGeneralName(PRArenaPool      *arena, 
+		        CERTGeneralName  *dest, 
+		        CERTGeneralName  *src)
+{
+    SECStatus rv;
+    void *mark = NULL;
+
+    PORT_Assert(dest != NULL);
+    dest->type = src->type;
+
+    mark = PORT_ArenaMark(arena);
+
+    switch (src->type) {
+    case certDirectoryName: 
+	rv = SECITEM_CopyItem(arena, &dest->derDirectoryName, 
+				      &src->derDirectoryName);
+	if (rv == SECSuccess) 
+	    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) 
+	    rv = SECITEM_CopyItem(arena, &dest->name.OthName.oid, 
+					  &src->name.OthName.oid);
+	break;
+
+    default: 
+	rv = SECITEM_CopyItem(arena, &dest->name.other, 
+				      &src->name.other);
+	break;
+
+    }
+    if (rv != SECSuccess) {
+        PORT_ArenaRelease(arena, mark);
+    } else {
+        PORT_ArenaUnmark(arena, mark);
+    }
+    return rv;
+}
+
+
+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 = PORT_ArenaZNew(arena, CERTGeneralNameList);
+    if (!list)
+    	goto loser;
+    if (name != NULL) {
+	SECStatus rv;
+	list->name = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
+	if (!list->name)
+	    goto loser;
+	rv = CERT_CopyGeneralName(arena, list->name, name);
+	if (rv != SECSuccess)
+	    goto loser;
+    }
+    list->lock = PZ_NewLock(nssILockList);
+    if (!list->lock)
+    	goto loser;
+    list->arena = arena;
+    list->refCount = 1;
+done:
+    return list;
+
+loser:
+    PORT_FreeArena(arena, PR_FALSE);
+    return NULL;
+}
+
+CERTGeneralName *
+CERT_GetNextGeneralName(CERTGeneralName *current)
+{
+    PRCList *next;
+    
+    next = current->l.next;
+    return (CERTGeneralName *) (((char *) next) - offsetof(CERTGeneralName, l));
+}
+
+CERTGeneralName *
+CERT_GetPrevGeneralName(CERTGeneralName *current)
+{
+    PRCList *prev;
+    prev = current->l.prev;
+    return (CERTGeneralName *) (((char *) prev) - offsetof(CERTGeneralName, l));
+}
+
+CERTNameConstraint *
+CERT_GetNextNameConstraint(CERTNameConstraint *current)
+{
+    PRCList *next;
+    
+    next = current->l.next;
+    return (CERTNameConstraint *) (((char *) next) - offsetof(CERTNameConstraint, l));
+}
+
+CERTNameConstraint *
+CERT_GetPrevNameConstraint(CERTNameConstraint *current)
+{
+    PRCList *prev;
+    prev = current->l.prev;
+    return (CERTNameConstraint *) (((char *) prev) - offsetof(CERTNameConstraint, l));
+}
+
+SECItem *
+CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest, PRArenaPool *arena)
+{
+
+    const SEC_ASN1Template * template;
+
+    PORT_Assert(arena);
+    if (arena == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    /* TODO: mark arena */
+    if (dest == NULL) {
+	dest = PORT_ArenaZNew(arena, SECItem);
+	if (!dest)
+	    goto loser;
+    }
+    if (genName->type == certDirectoryName) {
+	if (genName->derDirectoryName.data == NULL) {
+	    /* The field hasn't been encoded yet. */
+            SECItem * pre_dest =
+            SEC_ASN1EncodeItem (arena, &(genName->derDirectoryName),
+                                &(genName->name.directoryName),
+                                CERT_NameTemplate);
+            if (!pre_dest)
+                goto loser;
+	}
+	if (genName->derDirectoryName.data == NULL) {
+	    goto loser;
+	}
+    }
+    switch (genName->type) {
+    case certURI:           template = CERT_URITemplate;           break;
+    case certRFC822Name:    template = CERT_RFC822NameTemplate;    break;
+    case certDNSName:       template = CERT_DNSNameTemplate;       break;
+    case certIPAddress:     template = CERT_IPAddressTemplate;     break;
+    case certOtherName:     template = CERTOtherNameTemplate;      break;
+    case certRegisterID:    template = CERT_RegisteredIDTemplate;  break;
+         /* for this type, we expect the value is already encoded */
+    case certEDIPartyName:  template = CERT_EDIPartyNameTemplate;  break;
+	 /* for this type, we expect the value is already encoded */
+    case certX400Address:   template = CERT_X400AddressTemplate;   break;
+    case certDirectoryName: template = CERT_DirectoryNameTemplate; break;
+    default:
+	PORT_Assert(0); goto loser;
+    }
+    dest = SEC_ASN1EncodeItem(arena, dest, genName, template);
+    if (!dest) {
+	goto loser;
+    }
+    /* TODO: unmark arena */
+    return dest;
+loser:
+    /* TODO: release arena back to mark */
+    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);
+    /* TODO: mark arena */
+    current_name = names;
+    if (names != NULL) {
+	count = 1;
+    }
+    head = &(names->l);
+    while (current_name->l.next != head) {
+	current_name = CERT_GetNextGeneralName(current_name);
+	++count;
+    }
+    current_name = CERT_GetNextGeneralName(current_name);
+    items = PORT_ArenaNewArray(arena, 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_GetNextGeneralName(current_name);
+    }
+    items[i] = NULL;
+    /* TODO: unmark arena */
+    return items;
+loser:
+    /* TODO: release arena to mark */
+    return NULL;
+}
+
+CERTGeneralName *
+CERT_DecodeGeneralName(PRArenaPool      *reqArena,
+		       SECItem          *encodedName,
+		       CERTGeneralName  *genName)
+{
+    const SEC_ASN1Template *         template;
+    CERTGeneralNameType              genNameType;
+    SECStatus                        rv = SECSuccess;
+    SECItem* newEncodedName;
+
+    if (!reqArena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+    /* make a copy for decoding so the data decoded with QuickDER doesn't
+       point to temporary memory */
+    newEncodedName = SECITEM_ArenaDupItem(reqArena, encodedName);
+    if (!newEncodedName) {
+        return NULL;
+    }
+    /* TODO: mark arena */
+    genNameType = (CERTGeneralNameType)((*(newEncodedName->data) & 0x0f) + 1);
+    if (genName == NULL) {
+	genName = CERT_NewGeneralName(reqArena, genNameType);
+	if (!genName)
+	    goto loser;
+    } else {
+	genName->type = genNameType;
+	genName->l.prev = genName->l.next = &genName->l;
+    }
+
+    switch (genNameType) {
+    case certURI: 		template = CERT_URITemplate;           break;
+    case certRFC822Name: 	template = CERT_RFC822NameTemplate;    break;
+    case certDNSName: 		template = CERT_DNSNameTemplate;       break;
+    case certIPAddress: 	template = CERT_IPAddressTemplate;     break;
+    case certOtherName: 	template = CERTOtherNameTemplate;      break;
+    case certRegisterID: 	template = CERT_RegisteredIDTemplate;  break;
+    case certEDIPartyName: 	template = CERT_EDIPartyNameTemplate;  break;
+    case certX400Address: 	template = CERT_X400AddressTemplate;   break;
+    case certDirectoryName: 	template = CERT_DirectoryNameTemplate; break;
+    default: 
+        goto loser;
+    }
+    rv = SEC_QuickDERDecodeItem(reqArena, genName, template, newEncodedName);
+    if (rv != SECSuccess) 
+	goto loser;
+    if (genNameType == certDirectoryName) {
+	rv = SEC_QuickDERDecodeItem(reqArena, &(genName->name.directoryName), 
+				CERT_NameTemplate, 
+				&(genName->derDirectoryName));
+        if (rv != SECSuccess)
+	    goto loser;
+    }
+
+    /* TODO: unmark arena */
+    return genName;
+loser:
+    /* TODO: release arena to mark */
+    return NULL;
+}
+
+CERTGeneralName *
+cert_DecodeGeneralNames (PRArenaPool  *arena,
+			 SECItem      **encodedGenName)
+{
+    PRCList                           *head = NULL;
+    PRCList                           *tail = NULL;
+    CERTGeneralName                   *currentName = NULL;
+
+    PORT_Assert(arena);
+    if (!encodedGenName || !arena) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    /* TODO: mark arena */
+    while (*encodedGenName != NULL) {
+	currentName = CERT_DecodeGeneralName(arena, *encodedGenName, NULL);
+	if (currentName == NULL)
+	    break;
+	if (head == NULL) {
+	    head = &(currentName->l);
+	    tail = head;
+	}
+	currentName->l.next = head;
+	currentName->l.prev = tail;
+	tail = head->prev = tail->next = &(currentName->l);
+	encodedGenName++;
+    }
+    if (currentName) {
+	/* TODO: unmark arena */
+	return CERT_GetNextGeneralName(currentName);
+    }
+    /* TODO: release arena to mark */
+    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_GetNextGeneralName(name);
+	PORT_Free(name);
+	name = next;
+    } while (name != first);
+    return SECSuccess;
+}
+
+static SECItem *
+cert_EncodeNameConstraint(CERTNameConstraint  *constraint, 
+			 SECItem             *dest,
+			 PRArenaPool         *arena)
+{
+    PORT_Assert(arena);
+    if (dest == NULL) {
+	dest = PORT_ArenaZNew(arena, 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);
+    /* TODO: mark arena */
+    if (constraints != NULL) {
+	count = 1;
+    }
+    head = &constraints->l;
+    while (current_constraint->l.next != head) {
+	current_constraint = CERT_GetNextNameConstraint(current_constraint);
+	++count;
+    }
+    current_constraint = CERT_GetNextNameConstraint(current_constraint);
+    items = PORT_ArenaZNewArray(arena, 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_GetNextNameConstraint(current_constraint);
+    }
+    *dest = items;
+    if (*dest == NULL) {
+	goto loser;
+    }
+    /* TODO: unmark arena */
+    return SECSuccess;
+loser:
+    /* TODO: release arena to mark */
+    return SECFailure;
+}
+
+SECStatus 
+cert_EncodeNameConstraints(CERTNameConstraints  *constraints,
+			   PRArenaPool          *arena,
+			   SECItem              *dest)
+{
+    SECStatus    rv = SECSuccess;
+
+    PORT_Assert(arena);
+    /* TODO: mark 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;
+    }
+    /* TODO: unmark arena */
+    return SECSuccess;
+loser:
+    /* TODO: release arena to mark */
+    return SECFailure;
+}
+
+
+CERTNameConstraint *
+cert_DecodeNameConstraint(PRArenaPool       *reqArena,
+			  SECItem           *encodedConstraint)
+{
+    CERTNameConstraint     *constraint;
+    SECStatus              rv = SECSuccess;
+    CERTGeneralName        *temp;
+    SECItem*               newEncodedConstraint;
+
+    if (!reqArena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+    newEncodedConstraint = SECITEM_ArenaDupItem(reqArena, encodedConstraint);
+    if (!newEncodedConstraint) {
+        return NULL;
+    }
+    /* TODO: mark arena */
+    constraint = PORT_ArenaZNew(reqArena, CERTNameConstraint);
+    if (!constraint)
+    	goto loser;
+    rv = SEC_QuickDERDecodeItem(reqArena, constraint,
+                                CERTNameConstraintTemplate,
+                                newEncodedConstraint);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    temp = CERT_DecodeGeneralName(reqArena, &(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);
+    /* TODO: unmark arena */
+    return constraint;
+loser:
+    /* TODO: release arena back to mark */
+    return NULL;
+}
+
+CERTNameConstraint *
+cert_DecodeNameConstraintSubTree(PRArenaPool   *arena,
+				 SECItem       **subTree,
+				 PRBool        permited)
+{
+    CERTNameConstraint   *current = NULL;
+    CERTNameConstraint   *first = NULL;
+    CERTNameConstraint   *last = NULL;
+    int                  i = 0;
+
+    PORT_Assert(arena);
+    /* TODO: mark arena */
+    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);
+    /* TODO: unmark arena */
+    return first;
+loser:
+    /* TODO: release arena back to mark */
+    return NULL;
+}
+
+CERTNameConstraints *
+cert_DecodeNameConstraints(PRArenaPool   *reqArena,
+			   SECItem       *encodedConstraints)
+{
+    CERTNameConstraints   *constraints;
+    SECStatus             rv;
+    SECItem*              newEncodedConstraints;
+
+    if (!reqArena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+    PORT_Assert(encodedConstraints);
+    newEncodedConstraints = SECITEM_ArenaDupItem(reqArena, encodedConstraints);
+
+    /* TODO: mark arena */
+    constraints = PORT_ArenaZNew(reqArena, CERTNameConstraints);
+    if (constraints == NULL) {
+	goto loser;
+    }
+    rv = SEC_QuickDERDecodeItem(reqArena, constraints,
+                                CERTNameConstraintsTemplate,
+                                newEncodedConstraints);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    if (constraints->DERPermited != NULL && 
+        constraints->DERPermited[0] != NULL) {
+	constraints->permited = 
+	    cert_DecodeNameConstraintSubTree(reqArena,
+                                             constraints->DERPermited,
+                                             PR_TRUE);
+	if (constraints->permited == NULL) {
+	    goto loser;
+	}
+    }
+    if (constraints->DERExcluded != NULL && 
+        constraints->DERExcluded[0] != NULL) {
+	constraints->excluded = 
+	    cert_DecodeNameConstraintSubTree(reqArena,
+                                             constraints->DERExcluded,
+                                             PR_FALSE);
+	if (constraints->excluded == NULL) {
+	    goto loser;
+	}
+    }
+    /* TODO: unmark arena */
+    return constraints;
+loser:
+    /* TODO: release arena back to mark */
+    return NULL;
+}
+
+/* Copy a chain of one or more general names to a destination chain.
+** Caller has allocated at least the first destination GeneralName struct. 
+** Both source and destination chains are circular doubly-linked lists.
+** The first source struct is copied to the first destination struct.
+** If the source chain has more than one member, and the destination chain 
+** has only one member, then this function allocates new structs for all but 
+** the first copy from the arena and links them into the destination list.  
+** If the destination struct is part of a list with more than one member,
+** then this function traverses both the source and destination lists,
+** copying each source struct to the corresponding dest struct.
+** In that case, the destination list MUST contain at least as many 
+** structs as the source list or some dest entries will be overwritten.
+*/
+SECStatus
+CERT_CopyGeneralName(PRArenaPool      *arena, 
+		     CERTGeneralName  *dest, 
+		     CERTGeneralName  *src)
+{
+    SECStatus rv;
+    CERTGeneralName *destHead = dest;
+    CERTGeneralName *srcHead = src;
+
+    PORT_Assert(dest != NULL);
+    if (!dest) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    /* TODO: mark arena */
+    do {
+	rv = cert_CopyOneGeneralName(arena, dest, src);
+	if (rv != SECSuccess)
+	    goto loser;
+	src = CERT_GetNextGeneralName(src);
+	/* if there is only one general name, we shouldn't do this */
+	if (src != srcHead) {
+	    if (dest->l.next == &destHead->l) {
+		CERTGeneralName *temp;
+		temp = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
+		if (!temp) 
+		    goto loser;
+		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_GetNextGeneralName(dest);
+	    }
+	}
+    } while (src != srcHead && rv == SECSuccess);
+    /* TODO: unmark arena */
+    return rv;
+loser:
+    /* TODO: release back to mark */
+    return SECFailure;
+}
+
+
+CERTGeneralNameList *
+CERT_DupGeneralNameList(CERTGeneralNameList *list)
+{
+    if (list != NULL) {
+	PZ_Lock(list->lock);
+	list->refCount++;
+	PZ_Unlock(list->lock);
+    }
+    return list;
+}
+
+/* Allocate space and copy CERTNameConstraint from src to dest */
+CERTNameConstraint *
+CERT_CopyNameConstraint(PRArenaPool         *arena, 
+			CERTNameConstraint  *dest, 
+			CERTNameConstraint  *src)
+{
+    SECStatus  rv;
+    
+    /* TODO: mark arena */
+    if (dest == NULL) {
+	dest = PORT_ArenaZNew(arena, CERTNameConstraint);
+	if (!dest)
+	    goto loser;
+	/* 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;
+    /* TODO: unmark arena */
+    return dest;
+loser:
+    /* TODO: release arena to mark */
+    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;
+    }
+}
+
+
+/* Add a CERTNameConstraint to the CERTNameConstraint list */
+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_GetNameConstraintByType (CERTNameConstraint *constraints,
+			      CERTGeneralNameType type, 
+			      CERTNameConstraint **returnList,
+			      PRArenaPool *arena)
+{
+    CERTNameConstraint *current = NULL;
+    void               *mark = NULL;
+
+    *returnList = NULL;
+    if (!constraints)
+	return SECSuccess;
+
+    mark = PORT_ArenaMark(arena);
+
+    current = constraints;
+    do {
+	PORT_Assert(current->name.type);
+	if (current->name.type == type) {
+	    CERTNameConstraint *temp;
+	    temp = CERT_CopyNameConstraint(arena, NULL, current);
+	    if (temp == NULL) 
+		goto loser;
+	    *returnList = CERT_AddNameConstraint(*returnList, temp);
+	}
+	current = CERT_GetNextNameConstraint(current);
+    } while (current != constraints);
+    PORT_ArenaUnmark(arena, mark);
+    return SECSuccess;
+
+loser:
+    PORT_ArenaRelease(arena, mark);
+    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 (void *)&current->name.other;           /* SECItem * */
+
+	    case certOtherName: 
+		return (void *)&current->name.OthName;         /* OthName * */
+
+	    case certDirectoryName: 
+		return derFormat 
+		       ? (void *)&current->derDirectoryName    /* SECItem * */
+		       : (void *)&current->name.directoryName; /* CERTName * */
+	    }
+	    PORT_Assert(0); 
+	    return NULL;
+	}
+	current = CERT_GetNextGeneralName(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_GetNextGeneralName(names);
+	} while (names != first);
+    }
+    return length;
+}
+
+/* Creates new GeneralNames for any email addresses found in the 
+** input DN, and links them onto the list for the DN.
+*/
+SECStatus
+cert_ExtractDNEmailAddrs(CERTGeneralName *name, PLArenaPool *arena)
+{
+    CERTGeneralName *nameList = NULL;
+    const CERTRDN  **nRDNs = (const CERTRDN **)(name->name.directoryName.rdns);
+    SECStatus        rv        = SECSuccess;
+
+    PORT_Assert(name->type == certDirectoryName);
+    if (name->type != certDirectoryName) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* TODO: mark arena */
+    while (nRDNs && *nRDNs) { /* loop over RDNs */
+	const CERTRDN *nRDN = *nRDNs++;
+	CERTAVA **nAVAs = nRDN->avas;
+	while (nAVAs && *nAVAs) { /* loop over AVAs */
+	    int tag;
+	    CERTAVA *nAVA = *nAVAs++;
+	    tag = CERT_GetAVATag(nAVA);
+	    if ( tag == SEC_OID_PKCS9_EMAIL_ADDRESS ||
+		 tag == SEC_OID_RFC1274_MAIL) { /* email AVA */
+		CERTGeneralName *newName = NULL;
+		SECItem *avaValue = CERT_DecodeAVAValue(&nAVA->value);
+		if (!avaValue)
+		    goto loser;
+		rv = SECFailure;
+                newName = CERT_NewGeneralName(arena, certRFC822Name);
+		if (newName) {
+		   rv = SECITEM_CopyItem(arena, &newName->name.other, avaValue);
+		}
+		SECITEM_FreeItem(avaValue, PR_TRUE);
+		if (rv != SECSuccess)
+		    goto loser;
+		nameList = cert_CombineNamesLists(nameList, newName);
+	    } /* handle one email AVA */
+	} /* loop over AVAs */
+    } /* loop over RDNs */
+    /* combine new names with old one. */
+    name = cert_CombineNamesLists(name, nameList);
+    /* TODO: unmark arena */
+    return SECSuccess;
+
+loser:
+    /* TODO: release arena back to mark */
+    return SECFailure;
+}
+
+/* This function is called by CERT_VerifyCertChain to extract all
+** names from a cert in preparation for a name constraints test.
+*/
+CERTGeneralName *
+CERT_GetCertificateNames(CERTCertificate *cert, PRArenaPool *arena)
+{
+    CERTGeneralName  *DN;
+    CERTGeneralName  *altName         = NULL;
+    SECItem          altNameExtension = {siBuffer, NULL, 0 };
+    SECStatus        rv;
+
+    /* TODO: mark arena */
+    DN = CERT_NewGeneralName(arena, certDirectoryName);
+    if (DN == NULL) {
+	goto loser;
+    }
+    rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    /* Extract email addresses from DN, construct CERTGeneralName structs 
+    ** for them, add them to the name list 
+    */
+    rv = cert_ExtractDNEmailAddrs(DN, arena);
+    if (rv != SECSuccess)
+        goto loser;
+
+    /* Now extract any GeneralNames from the subject name names extension. */
+    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
+				&altNameExtension);
+    if (rv == SECSuccess) {
+	altName = CERT_DecodeAltNameExtension(arena, &altNameExtension);
+	rv = altName ? SECSuccess : SECFailure;
+    }
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND)
+	rv = SECSuccess;
+    if (altNameExtension.data)
+	SECITEM_FreeItem(&altNameExtension, PR_FALSE);
+    if (rv != SECSuccess)
+        goto loser;
+    DN = cert_CombineNamesLists(DN, altName);
+
+    /* TODO: unmark arena */
+    return DN;
+loser:
+    /* TODO: release arena to mark */
+    return NULL;
+}
+
+/* Returns SECSuccess if name matches constraint per RFC 3280 rules for 
+** URI name constraints.  SECFailure otherwise.
+** If the constraint begins with a dot, it is a domain name, otherwise
+** It is a host name.  Examples:
+**  Constraint            Name             Result
+** ------------      ---------------      --------
+**  foo.bar.com          foo.bar.com      matches
+**  foo.bar.com          FoO.bAr.CoM      matches
+**  foo.bar.com      www.foo.bar.com      no match
+**  foo.bar.com        nofoo.bar.com      no match
+** .foo.bar.com      www.foo.bar.com      matches
+** .foo.bar.com        nofoo.bar.com      no match
+** .foo.bar.com          foo.bar.com      no match
+** .foo.bar.com     www..foo.bar.com      no match
+*/
+static SECStatus
+compareURIN2C(const SECItem *name, const SECItem *constraint)
+{
+    int offset;
+    /* The spec is silent on intepreting zero-length constraints.
+    ** We interpret them as matching no URI names.
+    */
+    if (!constraint->len)
+        return SECFailure;
+    if (constraint->data[0] != '.') { 
+    	/* constraint is a host name. */
+    	if (name->len != constraint->len ||
+	    PL_strncasecmp((char *)name->data, 
+			   (char *)constraint->data, constraint->len))
+	    return SECFailure;
+    	return SECSuccess;
+    }
+    /* constraint is a domain name. */
+    if (name->len < constraint->len)
+        return SECFailure;
+    offset = name->len - constraint->len;
+    if (PL_strncasecmp((char *)(name->data + offset), 
+		       (char *)constraint->data, constraint->len))
+        return SECFailure;
+    if (!offset || 
+        (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
+	return SECSuccess;
+    return SECFailure;
+}
+
+/* for DNSname constraints, RFC 3280 says, (section 4.2.1.11, page 38)
+**
+** DNS name restrictions are expressed as foo.bar.com.  Any DNS name
+** that can be constructed by simply adding to the left hand side of the
+** name satisfies the name constraint.  For example, www.foo.bar.com
+** would satisfy the constraint but foo1.bar.com would not.
+**
+** But NIST's PKITS test suite requires that the constraint be treated
+** as a domain name, and requires that any name added to the left hand
+** side end in a dot ".".  Sensible, but not strictly following the RFC.
+**
+**  Constraint            Name            RFC 3280  NIST PKITS
+** ------------      ---------------      --------  ----------
+**  foo.bar.com          foo.bar.com      matches    matches
+**  foo.bar.com          FoO.bAr.CoM      matches    matches
+**  foo.bar.com      www.foo.bar.com      matches    matches
+**  foo.bar.com        nofoo.bar.com      MATCHES    NO MATCH
+** .foo.bar.com      www.foo.bar.com      matches    matches? disallowed?
+** .foo.bar.com          foo.bar.com      no match   no match
+** .foo.bar.com     www..foo.bar.com      matches    probably not 
+**
+** We will try to conform to NIST's PKITS tests, and the unstated 
+** rules they imply.
+*/
+static SECStatus
+compareDNSN2C(const SECItem *name, const SECItem *constraint)
+{
+    int offset;
+    /* The spec is silent on intepreting zero-length constraints.
+    ** We interpret them as matching all DNSnames.
+    */
+    if (!constraint->len)
+        return SECSuccess;
+    if (name->len < constraint->len)
+        return SECFailure;
+    offset = name->len - constraint->len;
+    if (PL_strncasecmp((char *)(name->data + offset), 
+		       (char *)constraint->data, constraint->len))
+        return SECFailure;
+    if (!offset || 
+        (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
+	return SECSuccess;
+    return SECFailure;
+}
+
+/* Returns SECSuccess if name matches constraint per RFC 3280 rules for
+** internet email addresses.  SECFailure otherwise.
+** If constraint contains a '@' then the two strings much match exactly.
+** Else if constraint starts with a '.'. then it must match the right-most
+** substring of the name, 
+** else constraint string must match entire name after the name's '@'.
+** Empty constraint string matches all names. All comparisons case insensitive.
+*/
+static SECStatus
+compareRFC822N2C(const SECItem *name, const SECItem *constraint)
+{
+    int offset;
+    if (!constraint->len)
+        return SECSuccess;
+    if (name->len < constraint->len)
+        return SECFailure;
+    if (constraint->len == 1 && constraint->data[0] == '.')
+        return SECSuccess;
+    for (offset = constraint->len - 1; offset >= 0; --offset) {
+    	if (constraint->data[offset] == '@') {
+	    return (name->len == constraint->len && 
+	        !PL_strncasecmp((char *)name->data, 
+				(char *)constraint->data, constraint->len))
+		? SECSuccess : SECFailure;
+	}
+    }
+    offset = name->len - constraint->len;
+    if (PL_strncasecmp((char *)(name->data + offset), 
+		       (char *)constraint->data, constraint->len))
+        return SECFailure;
+    if (constraint->data[0] == '.')
+        return SECSuccess;
+    if (offset > 0 && name->data[offset - 1] == '@')
+        return SECSuccess;
+    return SECFailure;
+}
+
+/* name contains either a 4 byte IPv4 address or a 16 byte IPv6 address.
+** constraint contains an address of the same length, and a subnet mask
+** of the same length.  Compare name's address to the constraint's 
+** address, subject to the mask.
+** Return SECSuccess if they match, SECFailure if they don't. 
+*/
+static SECStatus
+compareIPaddrN2C(const SECItem *name, const SECItem *constraint)
+{
+    int i;
+    if (name->len == 4 && constraint->len == 8) { /* ipv4 addr */
+        for (i = 0; i < 4; i++) {
+	    if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+4])
+	        goto loser;
+	}
+	return SECSuccess;
+    }
+    if (name->len == 16 && constraint->len == 32) { /* ipv6 addr */
+        for (i = 0; i < 16; i++) {
+	    if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+16])
+	        goto loser;
+	}
+	return SECSuccess;
+    }
+loser:
+    return SECFailure;
+}
+
+/* start with a SECItem that points to a URI.  Parse it lookingg for 
+** a hostname.  Modify item->data and item->len to define the hostname,
+** but do not modify and data at item->data.  
+** If anything goes wrong, the contents of *item are undefined.
+*/
+static SECStatus
+parseUriHostname(SECItem * item)
+{
+    int i;
+    PRBool found = PR_FALSE;
+    for (i = 0; (unsigned)(i+2) < item->len; ++i) {
+	if (item->data[i  ] == ':' &&
+	    item->data[i+1] == '/' &&
+	    item->data[i+2] == '/') {
+	    i += 3;
+	    item->data += i;
+	    item->len  -= i;
+	    found = PR_TRUE;
+	    break;
+	}
+    }
+    if (!found) 
+        return SECFailure;
+    /* now look for a '/', which is an upper bound in the end of the name */
+    for (i = 0; (unsigned)i < item->len; ++i) {
+	if (item->data[i] == '/') {
+	    item->len = i;
+	    break;
+	}
+    }
+    /* now look for a ':', which marks the end of the name */
+    for (i = item->len; --i >= 0; ) {
+        if (item->data[i] == ':') {
+	    item->len = i;
+	    break;
+	}
+    }
+    /* now look for an '@', which marks the beginning of the hostname */
+    for (i = 0; (unsigned)i < item->len; ++i) {
+	if (item->data[i] == '@') {
+	    ++i;
+	    item->data += i;
+	    item->len  -= i;
+	    break;
+	}
+    }
+    return item->len ? SECSuccess : SECFailure;
+}
+
+/* This function takes one name, and a list of constraints.
+** It searches the constraints looking for a match.
+** It returns SECSuccess if the name satisfies the constraints, i.e.,
+** if excluded, then the name does not match any constraint, 
+** if permitted, then the name matches at least one constraint.
+** It returns SECFailure if the name fails to satisfy the constraints,
+** or if some code fails (e.g. out of memory, or invalid constraint)
+*/
+SECStatus
+cert_CompareNameWithConstraints(CERTGeneralName     *name, 
+				CERTNameConstraint  *constraints,
+				PRBool              excluded)
+{
+    SECStatus           rv     = SECSuccess;
+    SECStatus           matched = SECFailure;
+    CERTNameConstraint  *current;
+
+    PORT_Assert(constraints);  /* caller should not call with NULL */
+    if (!constraints) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    current = constraints;
+    do {
+	rv = SECSuccess;
+	matched = SECFailure;
+	PORT_Assert(name->type == current->name.type);
+	switch (name->type) {
+
+	case certDNSName:
+	    matched = compareDNSN2C(&name->name.other, 
+	                            &current->name.name.other);
+	    break;
+
+	case certRFC822Name:
+	    matched = compareRFC822N2C(&name->name.other, 
+	                               &current->name.name.other);
+	    break;
+
+	case certURI:
+	    {
+		/* make a modifiable copy of the URI SECItem. */
+		SECItem uri = name->name.other;
+		/* find the hostname in the URI */
+		rv = parseUriHostname(&uri);
+		if (rv == SECSuccess) {
+		    /* does our hostname meet the constraint? */
+		    matched = compareURIN2C(&uri, &current->name.name.other);
+		}
+	    }
+	    break;
+
+	case certDirectoryName:
+	    /* Determine if the constraint directory name is a "prefix"
+	    ** for the directory name being tested. 
+	    */
+	  {
+	    /* status defaults to SECEqual, so that a constraint with 
+	    ** no AVAs will be a wildcard, matching all directory names.
+	    */
+	    SECComparison   status = SECEqual;
+	    const CERTRDN **cRDNs = 
+		    (const CERTRDN **)current->name.name.directoryName.rdns;  
+	    const CERTRDN **nRDNs = 
+		    (const CERTRDN **)name->name.directoryName.rdns;
+	    while (cRDNs && *cRDNs && nRDNs && *nRDNs) { 
+		/* loop over name RDNs and constraint RDNs in lock step */
+		const CERTRDN *cRDN = *cRDNs++;
+		const CERTRDN *nRDN = *nRDNs++;
+		CERTAVA **cAVAs = cRDN->avas;
+		while (cAVAs && *cAVAs) { /* loop over constraint AVAs */
+		    CERTAVA *cAVA = *cAVAs++;
+		    CERTAVA **nAVAs = nRDN->avas;
+		    while (nAVAs && *nAVAs) { /* loop over name AVAs */
+			CERTAVA *nAVA = *nAVAs++;
+			status = CERT_CompareAVA(cAVA, nAVA);
+			if (status == SECEqual) 
+			    break;
+		    } /* loop over name AVAs */
+		    if (status != SECEqual) 
+			break;
+		} /* loop over constraint AVAs */
+		if (status != SECEqual) 
+		    break;
+	    } /* loop over name RDNs and constraint RDNs */
+	    matched = (status == SECEqual) ? SECSuccess : SECFailure;
+	    break;
+	  }
+
+	case certIPAddress:	/* type 8 */
+	    matched = compareIPaddrN2C(&name->name.other, 
+	                               &current->name.name.other);
+	    break;
+
+	/* NSS does not know how to compare these "Other" type names with 
+	** their respective constraints.  But it does know how to tell
+	** if the constraint applies to the type of name (by comparing
+	** the constraint OID to the name OID).  NSS makes no use of "Other"
+	** type names at all, so NSS errs on the side of leniency for these 
+	** types, provided that their OIDs match.  So, when an "Other"
+	** name constraint appears in an excluded subtree, it never causes
+	** a name to fail.  When an "Other" name constraint appears in a
+	** permitted subtree, AND the constraint's OID matches the name's
+	** OID, then name is treated as if it matches the constraint.
+	*/
+	case certOtherName:	/* type 1 */
+	    matched = (!excluded &&
+		       name->type == current->name.type &&
+		       SECITEM_ItemsAreEqual(&name->name.OthName.oid,
+					     &current->name.name.OthName.oid))
+		 ? SECSuccess : SECFailure;
+	    break;
+
+	/* NSS does not know how to compare these types of names with their
+	** respective constraints.  But NSS makes no use of these types of 
+	** names at all, so it errs on the side of leniency for these types.
+	** Constraints for these types of names never cause the name to 
+	** fail the constraints test.  NSS behaves as if the name matched
+	** for permitted constraints, and did not match for excluded ones.
+	*/
+	case certX400Address:	/* type 4 */
+	case certEDIPartyName:  /* type 6 */
+	case certRegisterID:	/* type 9 */
+	    matched = excluded ? SECFailure : SECSuccess;
+	    break;
+
+	default: /* non-standard types are not supported */
+	    rv = SECFailure;
+	    break;
+	}
+	if (matched == SECSuccess || rv != SECSuccess)
+	    break;
+	current = CERT_GetNextNameConstraint(current);
+    } while (current != constraints);
+    if (rv == SECSuccess) {
+        if (matched == SECSuccess) 
+	    rv = excluded ? SECFailure : SECSuccess;
+	else
+	    rv = excluded ? SECSuccess : SECFailure;
+	return rv;
+    }
+
+    return SECFailure;
+}
+
+/* Add and link a CERTGeneralName to a CERTNameConstraint list. Most
+** likely the CERTNameConstraint passed in is either the permitted
+** list or the excluded list of a CERTNameConstraints.
+*/
+SECStatus
+CERT_AddNameConstraintByGeneralName(PLArenaPool *arena,
+                                    CERTNameConstraint **constraints,
+                                    CERTGeneralName *name)
+{
+    SECStatus rv;
+    CERTNameConstraint *current = NULL;
+    CERTNameConstraint *first = *constraints;
+    void *mark = NULL;
+
+    mark = PORT_ArenaMark(arena);
+
+    current = PORT_ArenaZNew(arena, CERTNameConstraint);
+    if (current == NULL) {
+        rv = SECFailure;
+        goto done;
+    }
+    
+    rv = cert_CopyOneGeneralName(arena, &current->name, name);
+    if (rv != SECSuccess) {
+        goto done;
+    }
+    
+    current->name.l.prev = current->name.l.next = &(current->name.l);
+    
+    if (first == NULL) {
+        *constraints = current;
+        PR_INIT_CLIST(&current->l);
+    } else {
+        PR_INSERT_BEFORE(&current->l, &first->l);
+    }
+
+done:
+    if (rv == SECFailure) {
+        PORT_ArenaRelease(arena, mark);
+    } else {
+        PORT_ArenaUnmark(arena, mark);
+    }
+    return rv;
+}
+
+/* Extract the name constraints extension from the CA cert. */
+SECStatus
+CERT_FindNameConstraintsExten(PRArenaPool      *arena,
+                              CERTCertificate  *cert,
+                              CERTNameConstraints **constraints)
+{
+    SECStatus            rv = SECSuccess;
+    SECItem              constraintsExtension;
+    void                *mark = NULL;
+    
+    *constraints = NULL;
+
+    rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, 
+                                &constraintsExtension);
+    if (rv != SECSuccess) {
+        if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
+            rv = SECSuccess;
+        }
+        return rv;
+    }
+
+    mark = PORT_ArenaMark(arena);
+
+    *constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
+    if (*constraints == NULL) { /* decode failed */
+        rv = SECFailure;
+    }
+    PORT_Free (constraintsExtension.data);
+
+    if (rv == SECFailure) {
+        PORT_ArenaRelease(arena, mark);
+    } else {
+        PORT_ArenaUnmark(arena, mark);
+    }
+
+    return rv;
+}
+
+/* Verify name against all the constraints relevant to that type of
+** the name.
+*/
+SECStatus
+CERT_CheckNameSpace(PRArenaPool          *arena,
+                    CERTNameConstraints  *constraints,
+                    CERTGeneralName      *currentName)
+{
+    CERTNameConstraint  *matchingConstraints;
+    SECStatus            rv = SECSuccess;
+    
+    if (constraints->excluded != NULL) {
+        rv = CERT_GetNameConstraintByType(constraints->excluded, 
+                                          currentName->type, 
+                                          &matchingConstraints, arena);
+        if (rv == SECSuccess && matchingConstraints != NULL) {
+            rv = cert_CompareNameWithConstraints(currentName, 
+                                                 matchingConstraints,
+                                                 PR_TRUE);
+        }
+        if (rv != SECSuccess) {
+            return(rv);
+        }
+    }
+    
+    if (constraints->permited != NULL) {
+        rv = CERT_GetNameConstraintByType(constraints->permited, 
+                                          currentName->type, 
+                                          &matchingConstraints, arena);
+        if (rv == SECSuccess && matchingConstraints != NULL) {
+            rv = cert_CompareNameWithConstraints(currentName, 
+                                                 matchingConstraints,
+                                                 PR_FALSE);
+        }
+        if (rv != SECSuccess) {
+            return(rv);
+        }
+    }
+
+    return(SECSuccess);
+}
+
+/* Extract the name constraints extension from the CA cert.
+** Test each and every name in namesList against all the constraints
+** relevant to that type of name.
+** Returns NULL in pBadCert for success, if all names are acceptable.
+** If some name is not acceptable, returns a pointer to the cert that
+** contained that name.
+*/
+SECStatus
+CERT_CompareNameSpace(CERTCertificate  *cert,
+		      CERTGeneralName  *namesList,
+ 		      CERTCertificate **certsList,
+ 		      PRArenaPool      *reqArena,
+ 		      CERTCertificate **pBadCert)
+{
+    SECStatus            rv = SECSuccess;
+    CERTNameConstraints  *constraints;
+    CERTGeneralName      *currentName;
+    int                  count = 0;
+    CERTCertificate      *badCert = NULL;
+
+    /* If no names to check, then no names can be bad. */
+    if (!namesList)
+    	goto done;
+    rv = CERT_FindNameConstraintsExten(reqArena, cert, &constraints);
+    if (rv != SECSuccess) {
+	count = -1;
+	goto done;
+    }
+
+    currentName = namesList;
+    do {
+	if (constraints){
+	    rv = CERT_CheckNameSpace(reqArena, constraints, currentName);
+	    if (rv != SECSuccess) {
+		break;
+	    }
+	}
+ 	currentName = CERT_GetNextGeneralName(currentName);
+ 	count ++;
+    } while (currentName != namesList);
+
+done:
+    if (rv != SECSuccess) {
+	badCert = (count >= 0) ? certsList[count] : cert;
+    }
+    if (pBadCert)
+	*pBadCert = badCert;
+
+    return rv;
+}
+
+/* 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_GetNextGeneralName(current);
+    } while (current != names);
+    if (!found)
+    	goto loser;
+
+    rv = SEC_QuickDERDecodeItem(arena, &nick,
+                            SEC_ASN1_GET(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;
+}
+
+#if 0
+/* not exported from shared libs, not used.  Turn on if we ever need it. */
+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_GetNextGeneralName(currentB);
+	    currentA = CERT_GetNextGeneralName(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_GetNextGeneralName(currentB);
+	} while (currentB != b && found != PR_TRUE);
+	if (found != PR_TRUE) {
+	    return SECFailure;
+	}
+	currentA = CERT_GetNextGeneralName(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;
+}
+#endif
+
+#if 0
+/* This function is not exported from NSS shared libraries, and is not
+** used inside of NSS.
+** XXX it doesn't check for failed allocations. :-(
+*/
+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 = PORT_ArenaNew(arena, SECItem);
+		if (item != NULL) {
+XXX		    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 = PORT_ArenaNew(arena, OtherName);
+	    } else {
+		tmpOther = PORT_New(OtherName);
+	    }
+	    if (tmpOther != NULL) {
+XXX		SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
+XXX		SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
+	    }
+	    PZ_Unlock(list->lock);
+	    return tmpOther;
+	  case certDirectoryName:
+	    if (arena) {
+		name = PORT_ArenaZNew(list->arena, CERTName);
+		if (name) {
+XXX		    CERT_CopyName(arena, name, (CERTName *) data);
+		}
+	    }
+	    PZ_Unlock(list->lock);
+	    return name;
+	}
+    }
+    PZ_Unlock(list->lock);
+    return NULL;
+}
+#endif
+
+#if 0
+/* This function is not exported from NSS shared libraries, and is not
+** used inside of NSS.
+** XXX it should NOT be a void function, since it does allocations
+** that can fail.
+*/
+void
+CERT_AddGeneralNameToList(CERTGeneralNameList *list, 
+			  CERTGeneralNameType type,
+			  void *data, SECItem *oid)
+{
+    CERTGeneralName *name;
+
+    if (list != NULL && data != NULL) {
+	PZ_Lock(list->lock);
+	name = CERT_NewGeneralName(list->arena, type);
+	if (!name)
+	    goto done;
+	switch (type) {
+	  case certDNSName:
+	  case certEDIPartyName:
+	  case certIPAddress:
+	  case certRegisterID:
+	  case certRFC822Name:
+	  case certX400Address:
+	  case certURI:
+XXX	    SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
+	    break;
+	  case certOtherName:
+XXX	    SECITEM_CopyItem(list->arena, &name->name.OthName.name,
+			     (SECItem *) data);
+XXX	    SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
+			     oid);
+	    break;
+	  case certDirectoryName:
+XXX	    CERT_CopyName(list->arena, &name->name.directoryName,
+			  (CERTName *) data);
+	    break;
+	}
+	list->name = cert_CombineNamesLists(list->name, name);
+	list->len++;
+done:
+	PZ_Unlock(list->lock);
+    }
+    return;
+}
+#endif
diff --git a/mozilla/security/nss/lib/certdb/genname.h b/mozilla/security/nss/lib/certdb/genname.h
new file mode 100644
index 0000000..d7ab0f1
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/genname.h
@@ -0,0 +1,138 @@
+/* ***** 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 ***** */
+
+#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 SECItem **
+cert_EncodeGeneralNames(PRArenaPool *arena, CERTGeneralName *names);
+
+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);
+
+/*********************************************************************/
+/* A thread safe implementation of General Names                     */
+/*********************************************************************/
+
+/* Destroy a Single CERTGeneralName */
+void
+CERT_DestroyGeneralName(CERTGeneralName *name);
+
+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 */
+
+/* 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 number of CERTGeneralName objects in the  doubly linked
+** list of which *names is a member.
+*/
+extern int
+CERT_GetNamesLength(CERTGeneralName *names);
+
+/************************************************************************/
+
+SECStatus
+CERT_CompareNameSpace(CERTCertificate  *cert,
+		      CERTGeneralName  *namesList,
+ 		      CERTCertificate **certsList,
+ 		      PRArenaPool      *reqArena,
+ 		      CERTCertificate **pBadCert);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/certdb/polcyxtn.c b/mozilla/security/nss/lib/certdb/polcyxtn.c
new file mode 100644
index 0000000..812f4ba
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/polcyxtn.c
@@ -0,0 +1,860 @@
+/* ***** 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 ***** */
+
+/*
+ * Support for various policy related extensions
+ *
+ * $Id: polcyxtn.c,v 1.11 2008/02/13 04:03:19 julien.pierre.boogz%sun.com Exp $
+ */
+
+#include "seccomon.h"
+#include "secport.h"
+#include "secder.h"
+#include "cert.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "secerr.h"
+#include "nspr.h"
+
+SEC_ASN1_MKSUB(SEC_IntegerTemplate)
+SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
+
+const SEC_ASN1Template CERT_DisplayTextTypeTemplate[] = {
+    { SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
+    { SEC_ASN1_IA5_STRING, 0, 0, siAsciiString},
+    { SEC_ASN1_VISIBLE_STRING , 0, 0, siVisibleString},
+    { SEC_ASN1_BMP_STRING  , 0, 0, siBMPString },
+    { SEC_ASN1_UTF8_STRING , 0, 0, siUTF8String },
+    { 0 }
+};
+
+const SEC_ASN1Template CERT_NoticeReferenceTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTNoticeReference) },
+    { SEC_ASN1_INLINE,
+	  offsetof(CERTNoticeReference, organization),
+           CERT_DisplayTextTypeTemplate, 0 },
+    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN,
+           offsetof(CERTNoticeReference, noticeNumbers),
+           SEC_ASN1_SUB(SEC_IntegerTemplate) }, 
+    { 0 }
+};
+
+const SEC_ASN1Template CERT_UserNoticeTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTUserNotice) },
+    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
+	  offsetof(CERTUserNotice, noticeReference),
+           CERT_NoticeReferenceTemplate, 0 },
+    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
+	  offsetof(CERTUserNotice, displayText),
+           CERT_DisplayTextTypeTemplate, 0 }, 
+    { 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 | SEC_ASN1_OPTIONAL,
+	  offsetof(CERTPolicyInfo, policyQualifiers),
+	  CERT_PolicyQualifierTemplate },
+    { 0 }
+};
+
+const SEC_ASN1Template CERT_CertificatePoliciesTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF,
+	  offsetof(CERTCertificatePolicies, policyInfos),
+	  CERT_PolicyInfoTemplate, sizeof(CERTCertificatePolicies)  }
+};
+
+const SEC_ASN1Template CERT_PolicyMapTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTPolicyMap) },
+    { SEC_ASN1_OBJECT_ID,
+	  offsetof(CERTPolicyMap, issuerDomainPolicy) },
+    { SEC_ASN1_OBJECT_ID,
+	  offsetof(CERTPolicyMap, subjectDomainPolicy) },
+    { 0 }
+};
+
+const SEC_ASN1Template CERT_PolicyMappingsTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF,
+	  offsetof(CERTCertificatePolicyMappings, policyMaps),
+	  CERT_PolicyMapTemplate, sizeof(CERTPolicyMap)  }
+};
+
+const SEC_ASN1Template CERT_PolicyConstraintsTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificatePolicyConstraints) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	  offsetof(CERTCertificatePolicyConstraints, explicitPolicySkipCerts),
+	  SEC_ASN1_SUB(SEC_IntegerTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
+	  offsetof(CERTCertificatePolicyConstraints, inhibitMappingSkipCerts),
+	  SEC_ASN1_SUB(SEC_IntegerTemplate) },
+    { 0 }
+};
+
+const SEC_ASN1Template CERT_InhibitAnyTemplate[] = {
+    { SEC_ASN1_INTEGER,
+	  offsetof(CERTCertificateInhibitAny, inhibitAnySkipCerts),
+	  NULL, sizeof(CERTCertificateInhibitAny)  }
+};
+
+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 certificate 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 && *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;
+}
+
+CERTCertificatePolicyMappings *
+CERT_DecodePolicyMappingsExtension(SECItem *extnValue)
+{
+    PRArenaPool *arena = NULL;
+    SECStatus rv;
+    CERTCertificatePolicyMappings *mappings;
+    SECItem newExtnValue;
+    
+    /* make a new arena */
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if ( !arena ) {
+        goto loser;
+    }
+
+    /* allocate the policy mappings structure */
+    mappings = (CERTCertificatePolicyMappings *)
+        PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicyMappings));
+    if ( mappings == NULL ) {
+        goto loser;
+    }
+    mappings->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 mappings */
+    rv = SEC_QuickDERDecodeItem
+        (arena, mappings, CERT_PolicyMappingsTemplate, &newExtnValue);
+    if ( rv != SECSuccess ) {
+        goto loser;
+    }
+
+    return(mappings);
+    
+loser:
+    if ( arena != NULL ) {
+        PORT_FreeArena(arena, PR_FALSE);
+    }
+    
+    return(NULL);
+}
+
+SECStatus
+CERT_DestroyPolicyMappingsExtension(CERTCertificatePolicyMappings *mappings)
+{
+    if ( mappings != NULL ) {
+        PORT_FreeArena(mappings->arena, PR_FALSE);
+    }
+    return SECSuccess;
+}
+
+SECStatus
+CERT_DecodePolicyConstraintsExtension
+                             (CERTCertificatePolicyConstraints *decodedValue,
+                              SECItem *encodedValue)
+{
+    CERTCertificatePolicyConstraints decodeContext;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+
+    /* initialize so we can tell when an optional component is omitted */
+    PORT_Memset(&decodeContext, 0, sizeof(decodeContext));
+
+    /* make a new arena */
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (!arena) {
+        return SECFailure;
+    }
+
+    do {
+        /* decode the policy constraints */
+        rv = SEC_QuickDERDecodeItem(arena,
+                &decodeContext, CERT_PolicyConstraintsTemplate, encodedValue);
+
+        if ( rv != SECSuccess ) {
+            break;
+        }
+
+        if (decodeContext.explicitPolicySkipCerts.len == 0) {
+            *(PRInt32 *)decodedValue->explicitPolicySkipCerts.data = -1;
+        } else {
+            *(PRInt32 *)decodedValue->explicitPolicySkipCerts.data =
+                    DER_GetInteger(&decodeContext.explicitPolicySkipCerts);
+        }
+
+        if (decodeContext.inhibitMappingSkipCerts.len == 0) {
+            *(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data = -1;
+        } else {
+            *(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data =
+                    DER_GetInteger(&decodeContext.inhibitMappingSkipCerts);
+        }
+
+        if ((*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
+                PR_INT32_MIN) ||
+            (*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
+                PR_INT32_MAX) ||
+            (*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
+                PR_INT32_MIN) ||
+            (*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
+                PR_INT32_MAX)) {
+            rv = SECFailure;
+        }
+    
+    } while (0);
+
+    PORT_FreeArena(arena, PR_FALSE);
+    return(rv);
+}
+
+SECStatus CERT_DecodeInhibitAnyExtension
+        (CERTCertificateInhibitAny *decodedValue, SECItem *encodedValue)
+{
+    CERTCertificateInhibitAny decodeContext;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+
+    /* make a new arena */
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if ( !arena ) {
+        return SECFailure;
+    }
+
+    do {
+
+        /* decode the policy mappings */
+        decodeContext.inhibitAnySkipCerts.type = siUnsignedInteger;
+        rv = SEC_QuickDERDecodeItem(arena,
+                &decodeContext, CERT_InhibitAnyTemplate, encodedValue);
+
+        if ( rv != SECSuccess ) {
+            break;
+        }
+
+        *(PRInt32 *)decodedValue->inhibitAnySkipCerts.data =
+                DER_GetInteger(&decodeContext.inhibitAnySkipCerts);
+
+    } while (0);
+
+    PORT_FreeArena(arena, PR_FALSE);
+    return(rv);
+}
+
+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) {
+
+        rv = SEC_QuickDERDecodeItem(arena, &userNotice->noticeReference,
+                                    CERT_NoticeReferenceTemplate,
+                                    &userNotice->derNoticeReference);
+        if (rv == SECFailure) {
+            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 && *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 | SEC_ASN1_XTRN,
+	  offsetof(CERTOidSequence, oids),
+	  SEC_ASN1_SUB(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);
+}
+
+
+SECStatus
+CERT_EncodePolicyConstraintsExtension(PRArenaPool *arena,
+                                      CERTCertificatePolicyConstraints *constr,
+                                      SECItem *dest)
+{
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert(constr != NULL && dest != NULL);
+    if (constr == NULL || dest == NULL) {
+	return SECFailure;
+    }
+
+    if (SEC_ASN1EncodeItem (arena, dest, constr,
+                            CERT_PolicyConstraintsTemplate) == NULL) {
+	rv = SECFailure;
+    }
+    return(rv);
+}
+
+SECStatus
+CERT_EncodePolicyMappingExtension(PRArenaPool *arena,
+                                  CERTCertificatePolicyMappings *mapping,
+                                  SECItem *dest)
+{
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert(mapping != NULL && dest != NULL);
+    if (mapping == NULL || dest == NULL) {
+	return SECFailure;
+    }
+
+    if (SEC_ASN1EncodeItem (arena, dest, mapping,
+                            CERT_PolicyMappingsTemplate) == NULL) {
+	rv = SECFailure;
+    }
+    return(rv);
+}
+
+
+
+SECStatus
+CERT_EncodeCertPoliciesExtension(PRArenaPool *arena,
+                                 CERTPolicyInfo **info,
+                                 SECItem *dest)
+{
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert(info != NULL && dest != NULL);
+    if (info == NULL || dest == NULL) {
+	return SECFailure;
+    }
+
+    if (SEC_ASN1EncodeItem (arena, dest, info,
+                            CERT_CertificatePoliciesTemplate) == NULL) {
+	rv = SECFailure;
+    }
+    return(rv);
+}
+
+SECStatus
+CERT_EncodeUserNotice(PRArenaPool *arena,
+                      CERTUserNotice *notice,
+                      SECItem *dest)
+{
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert(notice != NULL && dest != NULL);
+    if (notice == NULL || dest == NULL) {
+	return SECFailure;
+    }
+
+    if (SEC_ASN1EncodeItem(arena, dest,
+                           notice, CERT_UserNoticeTemplate) == NULL) {
+	rv = SECFailure;
+    }
+
+    return(rv);
+}
+
+SECStatus
+CERT_EncodeNoticeReference(PRArenaPool *arena,
+                           CERTNoticeReference *reference,
+                           SECItem *dest)
+{
+    SECStatus rv = SECSuccess;
+    
+    PORT_Assert(reference != NULL && dest != NULL);
+    if (reference == NULL || dest == NULL) {
+	return SECFailure;
+    }
+
+    if (SEC_ASN1EncodeItem (arena, dest, reference,
+                            CERT_NoticeReferenceTemplate) == NULL) {
+	rv = SECFailure;
+    }
+
+    return(rv);
+}
+
+SECStatus
+CERT_EncodeInhibitAnyExtension(PRArenaPool *arena,
+                               CERTCertificateInhibitAny *certInhibitAny,
+                               SECItem *dest)
+{
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert(certInhibitAny != NULL && dest != NULL);
+    if (certInhibitAny == NULL || dest == NULL) {
+	return SECFailure;
+    }
+
+    if (SEC_ASN1EncodeItem (arena, dest, certInhibitAny,
+                            CERT_InhibitAnyTemplate) == NULL) {
+	rv = SECFailure;
+    }
+    return(rv);
+}
diff --git a/mozilla/security/nss/lib/certdb/secname.c b/mozilla/security/nss/lib/certdb/secname.c
new file mode 100644
index 0000000..1010897
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/secname.c
@@ -0,0 +1,742 @@
+/* ***** 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):
+ *   John Gardiner Myers <jgmyers@speakeasy.net>
+ *
+ * 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 "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"
+#include "certi.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;
+}
+
+
+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;
+    int      maxLen;
+    SECOidData *oidrec;
+
+    oidrec = SECOID_FindOIDByTag(type);
+    if (oidrec == NULL)
+	return SECFailure;
+
+    oid = oidrec->oid.data;
+    oidLen = oidrec->oid.len;
+
+    maxLen = cert_AVAOidTagToMaxLen(type);
+    if (maxLen < 0) {
+	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 = (unsigned)maxLen;
+    return SECSuccess;
+}
+
+static SECStatus
+SetupAVAValue(PRArenaPool *arena, int valueType, const SECItem *in, 
+              SECItem *out, unsigned maxLen)
+{
+    PRUint8 *value, *cp, *ucs4Val;
+    unsigned valueLen, valueLenLen, total;
+    unsigned ucs4Len = 0, ucs4MaxLen;
+
+    value    = in->data;
+    valueLen = in->len;
+    switch (valueType) {
+      case SEC_ASN1_PRINTABLE_STRING:
+      case SEC_ASN1_IA5_STRING:
+      case SEC_ASN1_T61_STRING:
+      case SEC_ASN1_UTF8_STRING: /* no conversion required */
+	break;
+      case SEC_ASN1_UNIVERSAL_STRING:
+	ucs4MaxLen = valueLen * 6;
+	ucs4Val = (PRUint8 *)PORT_ArenaZAlloc(arena, ucs4MaxLen);
+	if(!ucs4Val || !PORT_UCS4_UTF8Conversion(PR_TRUE, value, valueLen,
+					ucs4Val, ucs4MaxLen, &ucs4Len)) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return SECFailure;
+	}
+	value = ucs4Val;
+	valueLen = ucs4Len;
+    	maxLen *= 4;
+	break;
+      default:
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    if (valueLen > maxLen) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    } 
+
+    valueLenLen = DER_LengthLength(valueLen);
+    total = 1 + valueLenLen + valueLen;
+    cp = (PRUint8*)PORT_ArenaAlloc(arena, total);
+    if (!cp) {
+	return SECFailure;
+    }
+    out->data = cp;
+    out->len  = total;
+    cp = (PRUint8 *)DER_StoreHeader(cp, valueType, valueLen);
+    PORT_Memcpy(cp, value, valueLen);
+    return SECSuccess;
+}
+
+CERTAVA *
+CERT_CreateAVAFromRaw(PRArenaPool *pool, const SECItem * OID, 
+                      const SECItem * value)
+{
+    CERTAVA *ava;
+    int rv;
+
+    ava = PORT_ArenaZNew(pool, CERTAVA);
+    if (ava) {
+	rv = SECITEM_CopyItem(pool, &ava->type, OID);
+	if (rv) 
+	    return NULL;
+
+	rv = SECITEM_CopyItem(pool, &ava->value, value);
+	if (rv) 
+	    return NULL;
+    }
+    return ava;
+}
+
+CERTAVA *
+CERT_CreateAVAFromSECItem(PRArenaPool *arena, SECOidTag kind, int valueType, 
+                          SECItem *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 NULL;
+	}
+	rv = SetupAVAValue(arena, valueType, value, &ava->value, maxLen);
+	if (rv) {
+	    /* Illegal value type */
+	    return NULL;
+	}
+    }
+    return ava;
+}
+
+CERTAVA *
+CERT_CreateAVA(PRArenaPool *arena, SECOidTag kind, int valueType, char *value)
+{
+    SECItem item = { siBuffer, NULL, 0 };
+
+    item.data = (PRUint8 *)value;
+    item.len  = PORT_Strlen(value);
+
+    return CERT_CreateAVAFromSECItem(arena, kind, valueType, &item);
+}
+
+CERTAVA *
+CERT_CopyAVA(PRArenaPool *arena, CERTAVA *from)
+{
+    CERTAVA *ava;
+    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 = SECSuccess;
+
+    /* Copy each ava from from */
+    avas = from->avas;
+    if (avas) {
+	if (avas[0] == NULL) {
+	    rv = CERT_AddAVA(arena, to, NULL);
+	    return rv;
+	}
+	while ((fava = *avas++) != 0) {
+	    tava = CERT_CopyAVA(arena, fava);
+	    if (!tava) {
+	    	rv = SECFailure;
+		break;
+	    }
+	    rv = CERT_AddAVA(arena, to, tava);
+	    if (rv != SECSuccess) 
+	    	break;
+	}
+    }
+    return rv;
+}
+
+/************************************************************************/
+
+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 = SECSuccess;
+
+    if (!to || !from) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    CERT_DestroyName(to);
+    to->arena = arena;
+
+    /* Copy each rdn from from */
+    rdns = from->rdns;
+    if (rdns) {
+    	if (rdns[0] == NULL) {
+	    rv = CERT_AddRDN(to, NULL);
+	    return rv;
+	}
+	while ((frdn = *rdns++) != NULL) {
+	    trdn = CERT_CreateRDN(arena, NULL);
+	    if (!trdn) {
+		rv = SECFailure;
+		break;
+	    }
+	    rv = CERT_CopyRDN(arena, trdn, frdn);
+	    if (rv != SECSuccess) 
+	        break;
+	    rv = CERT_AddRDN(to, trdn);
+	    if (rv != SECSuccess) 
+	        break;
+	}
+    }
+    return rv;
+}
+
+/************************************************************************/
+
+static void
+canonicalize(SECItem * foo)
+{
+    int ch, lastch, len, src, dest;
+
+    /* strip trailing whitespace. */
+    len = foo->len;
+    while (len > 0 && ((ch = foo->data[len - 1]) == ' ' || 
+           ch == '\t' || ch == '\r' || ch == '\n')) {
+	len--;
+    }
+
+    src = 0;
+    /* strip leading whitespace. */
+    while (src < len && ((ch = foo->data[src]) == ' ' || 
+           ch == '\t' || ch == '\r' || ch == '\n')) {
+	src++;
+    }
+    dest = 0; lastch = ' ';
+    while (src < len) {
+        ch = foo->data[src++];
+	if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
+	    ch = ' ';
+	    if (ch == lastch)
+	        continue;
+	} else if (ch >= 'A' && ch <= 'Z') {
+	    ch |= 0x20;  /* downshift */
+	}
+	foo->data[dest++] = lastch = ch;
+    }
+    foo->len = dest;
+}
+
+/* SECItems a and b contain DER-encoded printable strings. */
+SECComparison
+CERT_CompareDERPrintableStrings(const SECItem *a, const SECItem *b)
+{
+    SECComparison rv = SECLessThan;
+    SECItem * aVal = CERT_DecodeAVAValue(a);
+    SECItem * bVal = CERT_DecodeAVAValue(b);
+
+    if (aVal && aVal->len && aVal->data &&
+	bVal && bVal->len && bVal->data) {
+	canonicalize(aVal);
+	canonicalize(bVal);
+	rv = SECITEM_CompareItem(aVal, bVal);
+    }
+    SECITEM_FreeItem(aVal, PR_TRUE);
+    SECITEM_FreeItem(bVal, PR_TRUE);
+    return rv;
+}
+
+SECComparison
+CERT_CompareAVA(const CERTAVA *a, const CERTAVA *b)
+{
+    SECComparison rv;
+
+    rv = SECITEM_CompareItem(&a->type, &b->type);
+    if (SECEqual != rv)
+	return rv;  /* Attribute types don't match. */
+    /* Let's be optimistic.  Maybe the values will just compare equal. */
+    rv = SECITEM_CompareItem(&a->value, &b->value);
+    if (SECEqual == rv)
+        return rv;  /* values compared exactly. */
+    if (a->value.len && a->value.data && b->value.len && b->value.data) {
+	/* Here, the values did not match.  
+	** If the values had different encodings, convert them to the same
+	** encoding and compare that way.
+	*/
+	if (a->value.data[0] != b->value.data[0]) {
+	    /* encodings differ.  Convert both to UTF-8 and compare. */
+	    SECItem * aVal = CERT_DecodeAVAValue(&a->value);
+	    SECItem * bVal = CERT_DecodeAVAValue(&b->value);
+	    if (aVal && aVal->len && aVal->data &&
+	        bVal && bVal->len && bVal->data) {
+		rv = SECITEM_CompareItem(aVal, bVal);
+	    }
+	    SECITEM_FreeItem(aVal, PR_TRUE);
+	    SECITEM_FreeItem(bVal, PR_TRUE);
+	} else if (a->value.data[0] == 0x13) { /* both are printable strings. */
+	    /* printable strings */
+	    rv = CERT_CompareDERPrintableStrings(&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;
+
+    while (NULL != (aava = *aavas++)) {
+	for (bavas = b->avas; bava = *bavas++; ) {
+	    rv = SECITEM_CompareItem(&aava->type, &bava->type);
+	    if (SECEqual == rv) {
+		rv = CERT_CompareAVA(aava, bava);
+		if (SECEqual != rv) 
+		    return rv;
+		break;
+	    }
+    	}
+	if (!bava)  /* didn't find a match */
+	    return SECGreaterThan;
+    }
+    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(const SECItem *derAVAValue)
+{
+          SECItem          *retItem; 
+    const SEC_ASN1Template *theTemplate       = NULL;
+          enum { conv_none, conv_ucs4, conv_ucs2, conv_iso88591 } convert = conv_none;
+          SECItem           avaValue          = {siBuffer, 0}; 
+          PLArenaPool      *newarena          = NULL;
+
+    if (!derAVAValue || !derAVAValue->len || !derAVAValue->data) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    switch(derAVAValue->data[0]) {
+	case SEC_ASN1_UNIVERSAL_STRING:
+	    convert = conv_ucs4;
+	    theTemplate = SEC_ASN1_GET(SEC_UniversalStringTemplate);
+	    break;
+	case SEC_ASN1_IA5_STRING:
+	    theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
+	    break;
+	case SEC_ASN1_PRINTABLE_STRING:
+	    theTemplate = SEC_ASN1_GET(SEC_PrintableStringTemplate);
+	    break;
+	case SEC_ASN1_T61_STRING:
+	    /*
+	     * Per common practice, we're not decoding actual T.61, but instead
+	     * treating T61-labeled strings as containing ISO-8859-1.
+	     */
+	    convert = conv_iso88591;
+	    theTemplate = SEC_ASN1_GET(SEC_T61StringTemplate);
+	    break;
+	case SEC_ASN1_BMP_STRING:
+	    convert = conv_ucs2;
+	    theTemplate = SEC_ASN1_GET(SEC_BMPStringTemplate);
+	    break;
+	case SEC_ASN1_UTF8_STRING:
+	    /* No conversion needed ! */
+	    theTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
+	    break;
+	default:
+	    PORT_SetError(SEC_ERROR_INVALID_AVA);
+	    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 (convert != conv_none) {
+	unsigned int   utf8ValLen = avaValue.len * 3;
+	unsigned char *utf8Val    = (unsigned char*)
+				    PORT_ArenaZAlloc(newarena, utf8ValLen);
+
+        switch (convert) {
+        case conv_ucs4:
+           if(avaValue.len % 4 != 0 ||
+              !PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data, avaValue.len,
+					utf8Val, utf8ValLen, &utf8ValLen)) {
+                PORT_FreeArena(newarena, PR_FALSE);
+                PORT_SetError(SEC_ERROR_INVALID_AVA);
+		return NULL;
+	   }
+	   break;
+	case conv_ucs2:
+           if(avaValue.len % 2 != 0 ||
+              !PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data, avaValue.len,
+					utf8Val, utf8ValLen, &utf8ValLen)) {
+                PORT_FreeArena(newarena, PR_FALSE);
+                PORT_SetError(SEC_ERROR_INVALID_AVA);
+		return NULL;
+	   }
+	   break;
+	case conv_iso88591:
+           if(!PORT_ISO88591_UTF8Conversion(avaValue.data, avaValue.len,
+					utf8Val, utf8ValLen, &utf8ValLen)) {
+                PORT_FreeArena(newarena, PR_FALSE);
+                PORT_SetError(SEC_ERROR_INVALID_AVA);
+		return NULL;
+	   }
+	   break;
+	case conv_none:
+	   PORT_Assert(0); /* not reached */
+	   break;
+	}
+	  
+	avaValue.data = utf8Val;
+	avaValue.len = utf8ValLen;
+    }
+
+    retItem = SECITEM_DupItem(&avaValue);
+    PORT_FreeArena(newarena, PR_FALSE);
+    return retItem;
+}
diff --git a/mozilla/security/nss/lib/certdb/stanpcertdb.c b/mozilla/security/nss/lib/certdb/stanpcertdb.c
new file mode 100644
index 0000000..da0d7bc
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/stanpcertdb.c
@@ -0,0 +1,1031 @@
+/* ***** 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 "prtime.h"
+
+#include "cert.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 "base64.h"
+#include "sechash.h"
+#include "plhash.h"
+#include "pk11func.h" /* sigh */
+
+#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(const 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);
+
+    if (c == NULL) {
+        /* error code is set */
+        return SECFailure;
+    }
+
+    /* 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);
+}
+
+extern const NSSError NSS_ERROR_NO_ERROR;
+extern const NSSError NSS_ERROR_INTERNAL_ERROR;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_INVALID_ARENA_MARK;
+extern const NSSError NSS_ERROR_DUPLICATE_POINTER;
+extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED;
+extern const NSSError NSS_ERROR_TRACKER_NOT_EMPTY;
+extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED;
+extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD;
+extern const NSSError NSS_ERROR_VALUE_TOO_LARGE;
+extern const NSSError NSS_ERROR_UNSUPPORTED_TYPE;
+extern const NSSError NSS_ERROR_BUFFER_TOO_SHORT;
+extern const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT;
+extern const NSSError NSS_ERROR_INVALID_BASE64;
+extern const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT;
+extern const NSSError NSS_ERROR_INVALID_ITEM;
+extern const NSSError NSS_ERROR_INVALID_STRING;
+extern const NSSError NSS_ERROR_INVALID_ASN1ENCODER;
+extern const NSSError NSS_ERROR_INVALID_ASN1DECODER;
+extern const NSSError NSS_ERROR_INVALID_BER;
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
+extern const NSSError NSS_ERROR_INVALID_UTF8;
+extern const NSSError NSS_ERROR_INVALID_NSSOID;
+extern const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE;
+extern const NSSError NSS_ERROR_NOT_FOUND;
+extern const NSSError NSS_ERROR_INVALID_PASSWORD;
+extern const NSSError NSS_ERROR_USER_CANCELED;
+extern const NSSError NSS_ERROR_MAXIMUM_FOUND;
+extern const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND;
+extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
+extern const NSSError NSS_ERROR_HASH_COLLISION;
+extern const NSSError NSS_ERROR_DEVICE_ERROR;
+extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
+extern const NSSError NSS_ERROR_BUSY;
+extern const NSSError NSS_ERROR_ALREADY_INITIALIZED;
+extern const NSSError NSS_ERROR_PKCS11;
+
+
+/* Look at the stan error stack and map it to NSS 3 errors */
+#define STAN_MAP_ERROR(x,y)   \
+ else if (error == (x)) {     \
+  secError = y;               \
+ }                            \
+
+/* 
+ * map Stan errors into NSS errors
+ * This function examines the stan error stack and automatically sets
+ * PORT_SetError(); to the appropriate SEC_ERROR value.
+ */
+void
+CERT_MapStanError()
+{
+    PRInt32 *errorStack;
+    NSSError error, prevError;
+    int secError;
+    int i;
+
+    error = 0;
+
+    errorStack = NSS_GetErrorStack();
+    if (errorStack == 0) {
+	PORT_SetError(0);
+	return;
+    } 
+    error = prevError = CKR_GENERAL_ERROR;
+    /* get the 'top 2' error codes from the stack */
+    for (i=0; errorStack[i]; i++) {
+	prevError = error;
+	error = errorStack[i];
+    }
+    if (error == NSS_ERROR_PKCS11) {
+	/* map it */
+	secError = PK11_MapError(prevError);
+    }
+	STAN_MAP_ERROR(NSS_ERROR_NO_ERROR, 0)
+	STAN_MAP_ERROR(NSS_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_BASE64, SEC_ERROR_BAD_DATA)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_BER, SEC_ERROR_BAD_DER)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ATAV, SEC_ERROR_INVALID_AVA)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_PASSWORD,SEC_ERROR_BAD_PASSWORD)
+	STAN_MAP_ERROR(NSS_ERROR_BUSY, SEC_ERROR_BUSY)
+	STAN_MAP_ERROR(NSS_ERROR_DEVICE_ERROR, SEC_ERROR_IO)
+	STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND, 
+			SEC_ERROR_UNKNOWN_ISSUER)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_CERTIFICATE, SEC_ERROR_CERT_NOT_VALID)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_UTF8, SEC_ERROR_BAD_DATA)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_NSSOID, SEC_ERROR_BAD_DATA)
+
+	/* these are library failure for lack of a better error code */
+	STAN_MAP_ERROR(NSS_ERROR_NOT_FOUND, SEC_ERROR_LIBRARY_FAILURE)
+	STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_IN_CACHE,
+						 SEC_ERROR_LIBRARY_FAILURE)
+	STAN_MAP_ERROR(NSS_ERROR_MAXIMUM_FOUND, SEC_ERROR_LIBRARY_FAILURE)
+	STAN_MAP_ERROR(NSS_ERROR_USER_CANCELED, SEC_ERROR_LIBRARY_FAILURE)
+	STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_INITIALIZED,
+						 SEC_ERROR_LIBRARY_FAILURE)
+	STAN_MAP_ERROR(NSS_ERROR_ALREADY_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE)
+	STAN_MAP_ERROR(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD,
+						 SEC_ERROR_LIBRARY_FAILURE)
+	STAN_MAP_ERROR(NSS_ERROR_HASH_COLLISION, SEC_ERROR_LIBRARY_FAILURE)
+
+	STAN_MAP_ERROR(NSS_ERROR_INTERNAL_ERROR, SEC_ERROR_LIBRARY_FAILURE)
+
+	/* these are all invalid arguments */
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ARGUMENT, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_POINTER, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA_MARK, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_DUPLICATE_POINTER, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_POINTER_NOT_REGISTERED, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_EMPTY, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_VALUE_TOO_LARGE, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_UNSUPPORTED_TYPE, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_BUFFER_TOO_SHORT, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ATOB_CONTEXT, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_BTOA_CONTEXT, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ITEM, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_STRING, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1ENCODER, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1DECODER, SEC_ERROR_INVALID_ARGS)
+	STAN_MAP_ERROR(NSS_ERROR_UNKNOWN_ATTRIBUTE, SEC_ERROR_INVALID_ARGS)
+    else {
+	secError = SEC_ERROR_LIBRARY_FAILURE;
+    }
+    PORT_SetError(secError);
+}
+
+    
+
+SECStatus
+CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert,
+		    CERTCertTrust *trust)
+{
+    SECStatus rv = SECSuccess;
+    PRStatus ret;
+
+    CERT_LockCertTrust(cert);
+    ret = STAN_ChangeCertTrust(cert, trust);
+    CERT_UnlockCertTrust(cert);
+    if (ret != PR_SUCCESS) {
+	rv = SECFailure;
+	CERT_MapStanError();
+    }
+    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);
+    nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
+    nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
+    SECStatus rv;
+    PRStatus ret;
+
+    if (c == NULL) {
+	CERT_MapStanError();
+        return SECFailure;
+    }
+
+    context = c->object.cryptoContext;
+    if (!context) {
+	PORT_SetError(SEC_ERROR_ADDING_CERT); 
+	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, &lockTrace);
+    nssCertificateStore_RemoveCertLOCKED(context->certStore, c);
+    nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace);
+    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_GetCERTCertificateOrRelease(c); /* should return same pointer */
+    if (!cert) {
+	CERT_MapStanError();
+        return SECFailure;
+    }
+    cert->istemp = PR_FALSE;
+    cert->isperm = PR_TRUE;
+    if (!trust) {
+	return SECSuccess;
+    }
+    ret = STAN_ChangeCertTrust(cert, trust);
+    rv = SECSuccess;
+    if (ret != PR_SUCCESS) {
+	rv = SECFailure;
+	CERT_MapStanError();
+    }
+    return rv;
+}
+
+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)
+{
+    NSSCertificate *c;
+    CERTCertificate *cc;
+    NSSCertificate *tempCert = NULL;
+    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);
+	}
+	if (c) {
+	    /* 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 (!nssItem_Equal(&c->encoding, &encoding, NULL)) {
+		nssCertificate_Destroy(c);
+		PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
+		cc = NULL;
+	    } else {
+    		cc = STAN_GetCERTCertificateOrRelease(c);
+		if (cc == NULL) {
+		    CERT_MapStanError();
+		}
+	    }
+	    return cc;
+	}
+    }
+    pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor);
+    if (!pkio) {
+	CERT_MapStanError();
+	return NULL;
+    }
+    c = nss_ZNEW(pkio->arena, NSSCertificate);
+    if (!c) {
+	CERT_MapStanError();
+	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
+     */
+    /* 'c' is not adopted here, if we fail loser frees what has been
+     * allocated so far for 'c' */
+    cc = STAN_GetCERTCertificate(c);
+    if (!cc) {
+	CERT_MapStanError();
+        goto loser;
+    }
+    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 && cc->emailAddr[0]) {
+	c->email = nssUTF8_Create(c->object.arena, 
+	                          nssStringType_PrintableString, 
+	                          (NSSUTF8 *)cc->emailAddr, 
+	                          PORT_Strlen(cc->emailAddr));
+    }
+
+    tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c);
+    if (!tempCert) {
+	CERT_MapStanError();
+	goto loser;
+    }
+    /* destroy our copy */
+    NSSCertificate_Destroy(c);
+    /* and use the stored entry */
+    c = tempCert;
+    cc = STAN_GetCERTCertificateOrRelease(c);
+    if (!cc) {
+	/* STAN_GetCERTCertificateOrRelease destroys c on failure. */
+	CERT_MapStanError();
+	return NULL;
+    }
+
+    cc->istemp = PR_TRUE;
+    cc->isperm = PR_FALSE;
+    return cc;
+loser:
+    /* Perhaps this should be nssCertificate_Destroy(c) */
+    nssPKIObject_Destroy(&c->object);
+    return NULL;
+}
+
+/* This symbol is exported for backward compatibility. */
+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) {
+	CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
+    }
+    if (cp) {
+	CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(cp));
+    }
+    return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
+}
+
+CERTCertificate *
+CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID)
+{
+    CERTCertList *list;
+    CERTCertificate *cert = NULL;
+    CERTCertListNode *node, *head;
+
+    list = CERT_CreateSubjectCertList(NULL,handle,name,0,PR_FALSE);
+    if (list == NULL) return NULL;
+
+    node = head = CERT_LIST_HEAD(list);
+    if (head) {
+	do {
+	    if (node->cert && 
+		SECITEM_ItemsAreEqual(&node->cert->subjectKeyID, keyID) ) {
+		cert = CERT_DupCertificate(node->cert);
+		goto done;
+	    }
+	    node = CERT_LIST_NEXT(node);
+	} while (node && head != node);
+    }
+    PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
+done:
+    if (list) {
+        CERT_DestroyCertList(list);
+    }
+    return cert;
+}
+
+CERTCertificate *
+CERT_FindCertByNickname(CERTCertDBHandle *handle, const 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) {
+	    CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
+	}
+    } else {
+	c = ct;
+    }
+    return c ? STAN_GetCERTCertificateOrRelease(c) : 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_GetCERTCertificateOrRelease(c);
+}
+
+CERTCertificate *
+CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, const char *name)
+{
+    NSSCryptoContext *cc;
+    NSSCertificate *c, *ct;
+    CERTCertificate *cert;
+    NSSUsage usage;
+
+    if (NULL == name) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    usage.anyUsage = PR_TRUE;
+    cc = STAN_GetDefaultCryptoContext();
+    ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, 
+                                                       NULL, &usage, NULL);
+    if (!ct && PORT_Strchr(name, '@') != NULL) {
+        char* lowercaseName = CERT_FixupEmailAddr(name);
+        if (lowercaseName) {
+	    ct = NSSCryptoContext_FindBestCertificateByEmail(cc, lowercaseName, 
+							    NULL, &usage, NULL);
+            PORT_Free(lowercaseName);
+        }
+    }
+    cert = PK11_FindCertFromNickname(name, NULL);
+    if (cert) {
+	c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert));
+	CERT_DestroyCertificate(cert);
+	if (ct) {
+	    CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
+	}
+    } else {
+	c = ct;
+    }
+    return c ? STAN_GetCERTCertificateOrRelease(c) : 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_GetCERTCertificateOrRelease(*ci);
+	/* *ci may be invalid at this point, don't reference it again */
+        if (cert) {
+	    /* NOTE: add_to_subject_list adopts the incoming 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_GetCERTCertificateOrRelease(*ci);
+	/* *ci may be invalid at this point, don't reference it again */
+        if (cert) {
+	    /* NOTE: add_to_subject_list adopts the incoming cert. */
+	    add_to_subject_list(certList, cert, validOnly, sorttime);
+        }
+	ci++;
+    }
+    /* all the references have been adopted or freed at this point, just
+     * free the arrays now */
+    nss_ZFreeIf(tSubjectCerts);
+    nss_ZFreeIf(pSubjectCerts);
+    return certList;
+loser:
+    /* need to free the references in tSubjectCerts and pSubjectCerts! */
+    nssCertificateArray_Destroy(tSubjectCerts);
+    nssCertificateArray_Destroy(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 if (cert->arena) {
+	    PORT_FreeArena(cert->arena, PR_FALSE);
+	}
+    }
+    return;
+}
+
+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;
+		NSSItem profTime, profData;
+		NSSITEM_FROM_SECITEM(&profTime, profileTime);
+		NSSITEM_FROM_SECITEM(&profData, emailProfile);
+		stanProfile = nssSMIMEProfile_Create(c, &profTime, &profData);
+		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;
+        }
+    }
+
+    if (cert->slot && cert->isperm && CERT_IsUserCert(cert) &&
+	(!emailProfile || !emailProfile->len)) {
+	/* Don't clobber emailProfile for user certs. */
+    	return SECSuccess;
+    }
+
+    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;
+
+    if (!cert || !cert->emailAddr || !cert->emailAddr[0]) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return 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;
+}
+
+/*
+ * deprecated functions that are now just stubs.
+ */
+/*
+ * Close the database
+ */
+void
+__CERT_ClosePermCertDB(CERTCertDBHandle *handle)
+{
+    PORT_Assert("CERT_ClosePermCertDB is Deprecated" == NULL);
+    return;
+}
+
+SECStatus
+CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname,
+                        PRBool readOnly)
+{
+    PORT_Assert("CERT_OpenCertDBFilename is Deprecated" == NULL);
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+SECItem *
+SECKEY_HashPassword(char *pw, SECItem *salt)
+{
+    PORT_Assert("SECKEY_HashPassword is Deprecated" == NULL);
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return NULL;
+}
+
+SECStatus
+__CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle,
+                                 SECItem *derSubject,
+                                 void *cb, void *cbarg)
+{
+    PORT_Assert("CERT_TraversePermCertsForSubject is Deprecated" == NULL);
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+
+SECStatus
+__CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname,
+                                  void *cb, void *cbarg)
+{
+    PORT_Assert("CERT_TraversePermCertsForNickname is Deprecated" == NULL);
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+
+
diff --git a/mozilla/security/nss/lib/certdb/xauthkid.c b/mozilla/security/nss/lib/certdb/xauthkid.c
new file mode 100644
index 0000000..7d50798
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/xauthkid.c
@@ -0,0 +1,160 @@
+/* ***** 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 ***** */
+
+/*
+ * X.509 v3 Subject Key Usage Extension 
+ *
+ */
+
+#include "prtypes.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"
+
+SEC_ASN1_MKSUB(SEC_IntegerTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+
+const SEC_ASN1Template CERTAuthKeyIDTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAuthKeyID) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	  offsetof(CERTAuthKeyID,keyID), SEC_ASN1_SUB(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 | SEC_ASN1_XTRN | 2,
+	  offsetof(CERTAuthKeyID,authCertSerialNumber),
+          SEC_ASN1_SUB(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));
+	if (value == NULL)
+	    break;
+	value->DERAuthCertIssuer = NULL;
+        /* 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/mozilla/security/nss/lib/certdb/xbsconst.c b/mozilla/security/nss/lib/certdb/xbsconst.c
new file mode 100644
index 0000000..221a568
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/xbsconst.c
@@ -0,0 +1,177 @@
+/* ***** 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 ***** */
+
+/*
+ * X.509 v3 Basic Constraints Extension 
+ */
+
+#include "prtypes.h"
+#include <limits.h>     /* for LONG_MAX */
+#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 = decodeContext.isCA.data 
+	              ? (PRBool)(decodeContext.isCA.data[0] != 0)
+		      : PR_FALSE;
+	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) {
+	    long len = DER_GetInteger (&decodeContext.pathLenConstraint);
+	    if (len < 0 || len == LONG_MAX) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		GEN_BREAK (SECFailure);
+	    }
+	    value->pathLenConstraint = len;
+	} 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/mozilla/security/nss/lib/certdb/xconst.c b/mozilla/security/nss/lib/certdb/xconst.c
new file mode 100644
index 0000000..7d23b40
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/xconst.c
@@ -0,0 +1,318 @@
+/* ***** 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 ***** */
+
+/*
+ * X.509 Extension Encoding  
+ */
+
+#include "prtypes.h"
+#include "seccomon.h"
+#include "secdert.h"
+#include "secoidt.h"
+#include "secasn1t.h"
+#include "secasn1.h"
+#include "cert.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 }
+};
+
+SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate)
+
+static const SEC_ASN1Template CERTPrivateKeyUsagePeriodTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+      0, NULL, sizeof(CERTPrivKeyUsagePeriod) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC  | SEC_ASN1_XTRN | 0,
+	  offsetof(CERTPrivKeyUsagePeriod, notBefore), 
+	  SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC  | SEC_ASN1_XTRN | 1,
+	  offsetof(CERTPrivKeyUsagePeriod, notAfter), 
+	  SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate)},
+    { 0, } 
+};
+
+
+const SEC_ASN1Template CERTAltNameTemplate[] = {
+    { SEC_ASN1_CONSTRUCTED, offsetof(CERTAltNameEncodedContext, 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, const SECItem* srcString,
+                        SECItem *encodedValue)
+{
+    SECStatus rv = SECSuccess;
+
+    if (!srcString) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    if (SEC_ASN1EncodeItem (arena, encodedValue, srcString,
+			    CERTSubjectKeyIDTemplate) == NULL) {
+	rv = SECFailure;
+    }
+    
+    return(rv);
+}
+
+
+SECStatus
+CERT_EncodePrivateKeyUsagePeriod(PRArenaPool *arena, 
+                                CERTPrivKeyUsagePeriod *pkup, 
+				SECItem *encodedValue)
+{
+    SECStatus rv = SECSuccess;
+
+    if (SEC_ASN1EncodeItem (arena, encodedValue, pkup,
+			    CERTPrivateKeyUsagePeriodTemplate) == NULL) {
+	rv = SECFailure;
+    }
+    return(rv);
+}
+
+CERTPrivKeyUsagePeriod *
+CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue)
+{
+    SECStatus rv;
+    CERTPrivKeyUsagePeriod *pPeriod;
+    SECItem newExtnValue;
+
+    /* allocate the certificate policies structure */
+    pPeriod = PORT_ArenaZNew(arena, CERTPrivKeyUsagePeriod);
+    if ( pPeriod == NULL ) {
+	goto loser;
+    }
+    
+    pPeriod->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;
+    }
+
+    rv = SEC_QuickDERDecodeItem(arena, pPeriod, 
+                                CERTPrivateKeyUsagePeriodTemplate,
+			        &newExtnValue);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+    return pPeriod;
+    
+loser:
+    return NULL;
+}
+
+
+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 *reqArena, SECItem *EncodedAltName)
+{
+    SECStatus                  rv = SECSuccess;
+    CERTAltNameEncodedContext  encodedContext;
+    SECItem*                   newEncodedAltName;
+
+    if (!reqArena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    newEncodedAltName = SECITEM_ArenaDupItem(reqArena, EncodedAltName);
+    if (!newEncodedAltName) {
+        return NULL;
+    }
+
+    encodedContext.encodedGenName = NULL;
+    PORT_Memset(&encodedContext, 0, sizeof(CERTAltNameEncodedContext));
+    rv = SEC_QuickDERDecodeItem (reqArena, &encodedContext,
+                                 CERT_GeneralNamesTemplate, newEncodedAltName);
+    if (rv == SECFailure) {
+	goto loser;
+    }
+    if (encodedContext.encodedGenName && encodedContext.encodedGenName[0])
+	return cert_DecodeGeneralNames(reqArena,
+                                       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 *reqArena,
+				   SECItem     *encodedExtension)
+{
+    CERTAuthInfoAccess **info = NULL;
+    SECStatus rv;
+    int i;
+    SECItem* newEncodedExtension;
+
+    if (!reqArena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    newEncodedExtension = SECITEM_ArenaDupItem(reqArena, encodedExtension);
+    if (!newEncodedExtension) {
+        return NULL;
+    }
+
+    rv = SEC_QuickDERDecodeItem(reqArena, &info, CERTAuthInfoAccessTemplate, 
+			    newEncodedExtension);
+    if (rv != SECSuccess || info == NULL) {
+	return NULL;
+    }
+
+    for (i = 0; info[i] != NULL; i++) {
+	info[i]->location = CERT_DecodeGeneralName(reqArena,
+						   &(info[i]->derLocation),
+						   NULL);
+    }
+    return info;
+}
+
+SECStatus
+CERT_EncodeInfoAccessExtension(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/mozilla/security/nss/lib/certdb/xconst.h b/mozilla/security/nss/lib/certdb/xconst.h
new file mode 100644
index 0000000..59cc0d7
--- /dev/null
+++ b/mozilla/security/nss/lib/certdb/xconst.h
@@ -0,0 +1,68 @@
+/* ***** 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 ***** */
+#ifndef _XCONST_H_
+#define _XCONST_H_
+
+#include "certt.h"
+
+typedef struct CERTAltNameEncodedContextStr {
+    SECItem **encodedGenName;
+} CERTAltNameEncodedContext;
+
+
+
+SEC_BEGIN_PROTOS
+
+extern SECStatus
+CERT_EncodePrivateKeyUsagePeriod(PRArenaPool *arena, 
+                                CERTPrivKeyUsagePeriod *pkup,
+				SECItem *encodedValue);
+
+extern SECStatus
+CERT_EncodeNameConstraintsExtension(PRArenaPool *arena, 
+                                    CERTNameConstraints  *value,
+			            SECItem *encodedValue);
+
+extern SECStatus 
+CERT_EncodeIA5TypeExtension(PRArenaPool *arena, char *value, 
+                            SECItem *encodedValue);
+
+SECStatus
+cert_EncodeAuthInfoAccessExtension(PRArenaPool *arena,
+				   CERTAuthInfoAccess **info,
+				   SECItem *dest);
+SEC_END_PROTOS
+#endif
diff --git a/mozilla/security/nss/lib/certhigh/certhigh.c b/mozilla/security/nss/lib/certhigh/certhigh.c
new file mode 100644
index 0000000..83a4b01
--- /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(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);
+}
+
diff --git a/mozilla/security/nss/lib/certhigh/certhtml.c b/mozilla/security/nss/lib/certhigh/certhtml.c
new file mode 100644
index 0000000..e87d33b
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/certhtml.c
@@ -0,0 +1,312 @@
+/* ***** 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 ***** */
+
+/*
+ * certhtml.c --- convert a cert to html
+ *
+ * $Id: certhtml.c,v 1.8 2007/05/15 23:14:25 julien.pierre.bugs%sun.com Exp $
+ */
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "sechash.h"
+#include "cert.h"
+#include "keyhi.h"
+#include "secder.h"
+#include "prprf.h"
+#include "secport.h"
+#include "secasn1.h"
+#include "pk11func.h"
+
+static char *hex = "0123456789ABCDEF";
+
+/*
+** Convert a der-encoded integer to a hex printable string form
+*/
+char *CERT_Hexify (SECItem *i, int do_colon)
+{
+    unsigned char *cp, *end;
+    char *rv, *o;
+
+    if (!i->len) {
+	return PORT_Strdup("00");
+    }
+
+    rv = o = (char*) PORT_Alloc(i->len * 3);
+    if (!rv) return rv;
+
+    cp = i->data;
+    end = cp + i->len;
+    while (cp < end) {
+	unsigned char ch = *cp++;
+	*o++ = hex[(ch >> 4) & 0xf];
+	*o++ = hex[ch & 0xf];
+	if (cp != end) {
+	    if (do_colon) {
+		*o++ = ':';
+	    }
+	} 
+    }
+    *o = 0;           /* Null terminate the string */
+    return rv;
+}
+
+#define BREAK "<br>"
+#define BREAKLEN 4
+#define COMMA ", "
+#define COMMALEN 2
+
+#define MAX_OUS 20
+#define MAX_DC MAX_OUS
+
+
+char *CERT_FormatName (CERTName *name)
+{
+    CERTRDN** rdns;
+    CERTRDN * rdn;
+    CERTAVA** avas;
+    CERTAVA*  ava;
+    char *    buf	= 0;
+    char *    tmpbuf	= 0;
+    SECItem * cn	= 0;
+    SECItem * email	= 0;
+    SECItem * org	= 0;
+    SECItem * loc	= 0;
+    SECItem * state	= 0;
+    SECItem * country	= 0;
+    SECItem * dq     	= 0;
+
+    unsigned  len 	= 0;
+    int       tag;
+    int       i;
+    int       ou_count = 0;
+    int       dc_count = 0;
+    PRBool    first;
+    SECItem * orgunit[MAX_OUS];
+    SECItem * dc[MAX_DC];
+
+    /* Loop over name components and gather the interesting ones */
+    rdns = name->rdns;
+    while ((rdn = *rdns++) != 0) {
+	avas = rdn->avas;
+	while ((ava = *avas++) != 0) {
+	    tag = CERT_GetAVATag(ava);
+	    switch(tag) {
+	      case SEC_OID_AVA_COMMON_NAME:
+		cn = CERT_DecodeAVAValue(&ava->value);
+		if (!cn) {
+ 			goto loser;
+		}
+		len += cn->len;
+		break;
+	      case SEC_OID_AVA_COUNTRY_NAME:
+		country = CERT_DecodeAVAValue(&ava->value);
+		if (!country) {
+ 			goto loser;
+		}
+		len += country->len;
+		break;
+	      case SEC_OID_AVA_LOCALITY:
+		loc = CERT_DecodeAVAValue(&ava->value);
+		if (!loc) {
+ 			goto loser;
+		}
+		len += loc->len;
+		break;
+	      case SEC_OID_AVA_STATE_OR_PROVINCE:
+		state = CERT_DecodeAVAValue(&ava->value);
+		if (!state) {
+ 			goto loser;
+		}
+		len += state->len;
+		break;
+	      case SEC_OID_AVA_ORGANIZATION_NAME:
+		org = CERT_DecodeAVAValue(&ava->value);
+		if (!org) {
+ 			goto loser;
+		}
+		len += org->len;
+		break;
+	      case SEC_OID_AVA_DN_QUALIFIER:
+		dq = CERT_DecodeAVAValue(&ava->value);
+		if (!dq) {
+ 			goto loser;
+		}
+		len += dq->len;
+		break;
+	      case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
+		if (ou_count < MAX_OUS) {
+			orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value);
+			if (!orgunit[ou_count]) {
+				goto loser;
+                        }
+			len += orgunit[ou_count++]->len;
+		}
+		break;
+	      case SEC_OID_AVA_DC:
+		if (dc_count < MAX_DC) {
+			dc[dc_count] = CERT_DecodeAVAValue(&ava->value);
+			if (!dc[dc_count]) {
+				goto loser;
+			}
+			len += dc[dc_count++]->len;
+		}
+		break;
+	      case SEC_OID_PKCS9_EMAIL_ADDRESS:
+	      case SEC_OID_RFC1274_MAIL:
+		email = CERT_DecodeAVAValue(&ava->value);
+		if (!email) {
+			goto loser;
+		}
+		len += email->len;
+		break;
+	      default:
+		break;
+	    }
+	}
+    }
+
+    /* XXX - add some for formatting */
+    len += 128;
+
+    /* allocate buffer */
+    buf = (char *)PORT_Alloc(len);
+    if ( !buf ) {
+	return(0);
+    }
+
+    tmpbuf = buf;
+    
+    if ( cn ) {
+	PORT_Memcpy(tmpbuf, cn->data, cn->len);
+	tmpbuf += cn->len;
+	PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
+	tmpbuf += BREAKLEN;
+    }
+    if ( email ) {
+	PORT_Memcpy(tmpbuf, email->data, email->len);
+	tmpbuf += ( email->len );
+	PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
+	tmpbuf += BREAKLEN;
+    }
+    for (i=ou_count-1; i >= 0; i--) {
+	PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len);
+	tmpbuf += ( orgunit[i]->len );
+	PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
+	tmpbuf += BREAKLEN;
+    }
+    if ( dq ) {
+	PORT_Memcpy(tmpbuf, dq->data, dq->len);
+	tmpbuf += ( dq->len );
+	PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
+	tmpbuf += BREAKLEN;
+    }
+    if ( org ) {
+	PORT_Memcpy(tmpbuf, org->data, org->len);
+	tmpbuf += ( org->len );
+	PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
+	tmpbuf += BREAKLEN;
+    }
+    for (i=dc_count-1; i >= 0; i--) {
+	PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len);
+	tmpbuf += ( dc[i]->len );
+	PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
+	tmpbuf += BREAKLEN;
+    }
+    first = PR_TRUE;
+    if ( loc ) {
+	PORT_Memcpy(tmpbuf, loc->data,  loc->len);
+	tmpbuf += ( loc->len );
+	first = PR_FALSE;
+    }
+    if ( state ) {
+	if ( !first ) {
+	    PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
+	    tmpbuf += COMMALEN;
+	}
+	PORT_Memcpy(tmpbuf, state->data, state->len);
+	tmpbuf += ( state->len );
+	first = PR_FALSE;
+    }
+    if ( country ) {
+	if ( !first ) {
+	    PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
+	    tmpbuf += COMMALEN;
+	}
+	PORT_Memcpy(tmpbuf, country->data, country->len);
+	tmpbuf += ( country->len );
+	first = PR_FALSE;
+    }
+    if ( !first ) {
+	PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
+	tmpbuf += BREAKLEN;
+    }
+
+    *tmpbuf = 0;
+
+    /* fall through and clean */
+loser:
+    if ( cn ) {
+	SECITEM_FreeItem(cn, PR_TRUE);
+    }
+    if ( email ) {
+	SECITEM_FreeItem(email, PR_TRUE);
+    }
+    for (i=ou_count-1; i >= 0; i--) {
+	SECITEM_FreeItem(orgunit[i], PR_TRUE);
+    }
+    if ( dq ) {
+	SECITEM_FreeItem(dq, PR_TRUE);
+    }
+    if ( org ) {
+	SECITEM_FreeItem(org, PR_TRUE);
+    }
+    for (i=dc_count-1; i >= 0; i--) {
+	SECITEM_FreeItem(dc[i], PR_TRUE);
+    }
+    if ( loc ) {
+	SECITEM_FreeItem(loc, PR_TRUE);
+    }
+    if ( state ) {
+	SECITEM_FreeItem(state, PR_TRUE);
+    }
+    if ( country ) {
+	SECITEM_FreeItem(country, PR_TRUE);
+    }
+
+    return(buf);
+}
+
diff --git a/mozilla/security/nss/lib/certhigh/certreq.c b/mozilla/security/nss/lib/certhigh/certreq.c
new file mode 100644
index 0000000..fc7a7dd
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/certreq.c
@@ -0,0 +1,352 @@
+/* ***** 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 "cert.h"
+#include "certt.h"
+#include "secder.h"
+#include "key.h"
+#include "secitem.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+
+const SEC_ASN1Template CERT_AttributeTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(CERTAttribute) },
+    { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
+    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(CERTAttribute, attrValue),
+	SEC_ASN1_SUB(SEC_AnyTemplate) },
+    { 0 }
+};
+
+const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
+};
+
+const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTCertificateRequest) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(CERTCertificateRequest,version) },
+    { SEC_ASN1_INLINE,
+	  offsetof(CERTCertificateRequest,subject),
+	  CERT_NameTemplate },
+    { SEC_ASN1_INLINE,
+	  offsetof(CERTCertificateRequest,subjectPublicKeyInfo),
+	  CERT_SubjectPublicKeyInfoTemplate },
+    { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+	  offsetof(CERTCertificateRequest,attributes), 
+	  CERT_SetOfAttributeTemplate },
+    { 0 }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
+
+CERTCertificate *
+CERT_CreateCertificate(unsigned long serialNumber,
+		      CERTName *issuer,
+		      CERTValidity *validity,
+		      CERTCertificateRequest *req)
+{
+    CERTCertificate *c;
+    int rv;
+    PRArenaPool *arena;
+    
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    
+    if ( !arena ) {
+	return(0);
+    }
+
+    c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
+    
+    if (c) {
+	c->referenceCount = 1;
+	c->arena = arena;
+
+	/*
+	 * Default is a plain version 1.
+	 * If extensions are added, it will get changed as appropriate.
+	 */
+	rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
+	if (rv) goto loser;
+
+	rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
+	if (rv) goto loser;
+
+	rv = CERT_CopyName(arena, &c->issuer, issuer);
+	if (rv) goto loser;
+
+	rv = CERT_CopyValidity(arena, &c->validity, validity);
+	if (rv) goto loser;
+
+	rv = CERT_CopyName(arena, &c->subject, &req->subject);
+	if (rv) goto loser;
+	rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
+					  &req->subjectPublicKeyInfo);
+	if (rv) goto loser;
+    }
+    return c;
+
+  loser:
+    CERT_DestroyCertificate(c);
+    return 0;
+}
+
+/************************************************************************/
+/* It's clear from the comments that the original author of this 
+ * function expected the template for certificate requests to treat
+ * the attributes as a SET OF ANY.  This function expected to be 
+ * passed an array of SECItems each of which contained an already encoded
+ * Attribute.  But the cert request template does not treat the 
+ * Attributes as a SET OF ANY, and AFAIK never has.  Instead the template
+ * encodes attributes as a SET OF xxxxxxx.  That is, it expects to encode
+ * each of the Attributes, not have them pre-encoded.  Consequently an 
+ * array of SECItems containing encoded Attributes is of no value to this 
+ * function.  But we cannot change the signature of this public function.
+ * It must continue to take SECItems.
+ *
+ * I have recoded this function so that each SECItem contains an 
+ * encoded cert extension.  The encoded cert extensions form the list for the
+ * single attribute of the cert request. In this implementation there is at most
+ * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
+ */
+
+CERTCertificateRequest *
+CERT_CreateCertificateRequest(CERTName *subject,
+			     CERTSubjectPublicKeyInfo *spki,
+			     SECItem **attributes)
+{
+    CERTCertificateRequest *certreq;
+    PRArenaPool *arena;
+    CERTAttribute * attribute;
+    SECOidData * oidData;
+    SECStatus rv;
+    int i = 0;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if ( arena == NULL ) {
+	return NULL;
+    }
+    
+    certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
+    if (!certreq) {
+	PORT_FreeArena(arena, PR_FALSE);
+	return NULL;
+    }
+    /* below here it is safe to goto loser */
+
+    certreq->arena = arena;
+    
+    rv = DER_SetUInteger(arena, &certreq->version,
+			 SEC_CERTIFICATE_REQUEST_VERSION);
+    if (rv != SECSuccess)
+	goto loser;
+
+    rv = CERT_CopyName(arena, &certreq->subject, subject);
+    if (rv != SECSuccess)
+	goto loser;
+
+    rv = SECKEY_CopySubjectPublicKeyInfo(arena,
+				      &certreq->subjectPublicKeyInfo,
+				      spki);
+    if (rv != SECSuccess)
+	goto loser;
+
+    certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute*, 2);
+    if(!certreq->attributes) 
+	goto loser;
+
+    /* Copy over attribute information */
+    if (!attributes || !attributes[0]) {
+	/*
+	 ** Invent empty attribute information. According to the
+	 ** pkcs#10 spec, attributes has this ASN.1 type:
+	 **
+	 ** attributes [0] IMPLICIT Attributes
+	 ** 
+	 ** Which means, we should create a NULL terminated list
+	 ** with the first entry being NULL;
+	 */
+	certreq->attributes[0] = NULL;
+	return certreq;
+    }	
+
+    /* allocate space for attributes */
+    attribute = PORT_ArenaZNew(arena, CERTAttribute);
+    if (!attribute) 
+	goto loser;
+
+    oidData = SECOID_FindOIDByTag( SEC_OID_PKCS9_EXTENSION_REQUEST );
+    PORT_Assert(oidData);
+    if (!oidData)
+	goto loser;
+    rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
+    if (rv != SECSuccess)
+	goto loser;
+
+    for (i = 0; attributes[i] != NULL ; i++) 
+	;
+    attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i+1);
+    if (!attribute->attrValue) 
+	goto loser;
+
+    /* copy attributes */
+    for (i = 0; attributes[i]; i++) {
+	/*
+	** Attributes are a SetOf Attribute which implies
+	** lexigraphical ordering.  It is assumes that the
+	** attributes are passed in sorted.  If we need to
+	** add functionality to sort them, there is an
+	** example in the PKCS 7 code.
+	*/
+	attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
+	if(!attribute->attrValue[i]) 
+	    goto loser;
+    }
+
+    certreq->attributes[0] = attribute;
+
+    return certreq;
+
+loser:
+    CERT_DestroyCertificateRequest(certreq);
+    return NULL;
+}
+
+void
+CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
+{
+    if (req && req->arena) {
+	PORT_FreeArena(req->arena, PR_FALSE);
+    }
+    return;
+}
+
+static void
+setCRExt(void *o, CERTCertExtension **exts)
+{
+    ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
+}
+
+/*
+** Set up to start gathering cert extensions for a cert request.
+** The list is created as CertExtensions and converted to an
+** attribute list by CERT_FinishCRAttributes().
+ */
+extern void *cert_StartExtensions(void *owner, PRArenaPool *ownerArena,
+                       void (*setExts)(void *object, CERTCertExtension **exts));
+void *
+CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
+{
+    return (cert_StartExtensions ((void *)req, req->arena, setCRExt));
+}
+
+/*
+** At entry req->attributes actually contains an list of cert extensions--
+** req-attributes is overloaded until the list is DER encoded (the first
+** ...EncodeItem() below).
+** We turn this into an attribute list by encapsulating it
+** in a PKCS 10 Attribute structure
+ */
+SECStatus
+CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
+{   SECItem *extlist;
+    SECOidData *oidrec;
+    CERTAttribute *attribute;
+   
+    if (!req || !req->arena) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    if (req->attributes == NULL || req->attributes[0] == NULL)
+        return SECSuccess;
+
+    extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
+                            SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
+    if (extlist == NULL)
+        return(SECFailure);
+
+    oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
+    if (oidrec == NULL)
+	return SECFailure;
+
+    /* now change the list of cert extensions into a list of attributes
+     */
+    req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2);
+
+    attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
+    
+    if (req->attributes == NULL || attribute == NULL ||
+        SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem*, 2);
+
+    if (attribute->attrValue == NULL)
+        return SECFailure;
+
+    attribute->attrValue[0] = extlist;
+    attribute->attrValue[1] = NULL;
+    req->attributes[0] = attribute;
+    req->attributes[1] = NULL;
+
+    return SECSuccess;
+}
+
+SECStatus
+CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
+                                        CERTCertExtension ***exts)
+{
+    if (req == NULL || exts == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    
+    if (req->attributes == NULL || *req->attributes == NULL)
+        return SECSuccess;
+    
+    if ((*req->attributes)->attrValue == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    return(SEC_ASN1DecodeItem(req->arena, exts, 
+            SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
+            (*req->attributes)->attrValue[0]));
+}
diff --git a/mozilla/security/nss/lib/certhigh/certvfy.c b/mozilla/security/nss/lib/certhigh/certvfy.c
new file mode 100644
index 0000000..c04c1fc
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/certvfy.c
@@ -0,0 +1,2040 @@
+/* ***** 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 "secport.h"
+#include "seccomon.h"
+#include "secoid.h"
+#include "sslerr.h"
+#include "genname.h"
+#include "keyhi.h"
+#include "cert.h"
+#include "certdb.h"
+#include "certi.h"
+#include "cryptohi.h"
+#define NO_LIBPKIX
+#ifndef NO_LIBPKIX
+#include "pkix.h"
+/*#include "pkix_sample_modules.h" */
+#include "pkix_pl_cert.h"
+#endif  /* NO_LIBPKIX */
+
+
+#include "nsspki.h"
+#include "pkitm.h"
+#include "pkim.h"
+#include "pki3hack.h"
+#include "base.h"
+
+#ifdef NO_LIBPKIX
+SECStatus
+cert_VerifyCertChainPkix(
+    CERTCertificate *cert,
+    PRBool           checkSig,
+    SECCertUsage     requiredUsage,
+    PRTime           time,
+    void            *wincx,
+    CERTVerifyLog   *log,
+    PRBool          *pSigerror,
+    PRBool          *pRevoked)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+SECStatus
+CERT_SetUsePKIXForValidation(PRBool enable)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+PRBool
+CERT_GetUsePKIXForValidation()
+{
+    return PR_FALSE;
+}
+
+SECStatus CERT_PKIXVerifyCert(
+    CERTCertificate *cert,
+    SECCertificateUsage usages,
+    CERTValInParam *paramsIn,
+    CERTValOutParam *paramsOut,
+    void *wincx)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+#endif  /* NO_LIBPKIX */
+
+/*
+ * Check the validity times of a certificate
+ */
+SECStatus
+CERT_CertTimesValid(CERTCertificate *c)
+{
+    SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE);
+    return (valid == secCertTimeValid) ? SECSuccess : SECFailure;
+}
+
+/*
+ * verify the signature of a signed data object with the given DER publickey
+ */
+SECStatus
+CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd, 
+                                   SECKEYPublicKey *pubKey,
+		                   void *wincx)
+{
+    SECStatus        rv;
+    SECItem          sig;
+    SECOidTag        hashAlg = SEC_OID_UNKNOWN;
+
+    if ( !pubKey || !sd ) {
+	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+	return SECFailure;
+    }
+
+    /* check the signature */
+    sig = sd->signature;
+    /* convert sig->len from bit counts to byte count. */
+    DER_ConvertBitString(&sig);
+
+    rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey, 
+			&sig, &sd->signatureAlgorithm, &hashAlg, wincx);
+    if (rv == SECSuccess) {
+        /* Are we honoring signatures for this algorithm?  */
+	PRUint32 policyFlags = 0;
+	rv = NSS_GetAlgorithmPolicy(hashAlg, &policyFlags);
+	if (rv == SECSuccess && 
+	    !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    rv = SECFailure;
+	}
+    }
+    return rv;
+}
+
+/*
+ * verify the signature of a signed data object with the given DER publickey
+ */
+SECStatus
+CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd, 
+                                       CERTSubjectPublicKeyInfo *pubKeyInfo,
+		                       void *wincx)
+{
+    SECKEYPublicKey *pubKey;
+    SECStatus        rv		= SECFailure;
+
+    /* get cert's public key */
+    pubKey = SECKEY_ExtractPublicKey(pubKeyInfo);
+    if (pubKey) {
+	rv =  CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
+	SECKEY_DestroyPublicKey(pubKey);
+    }
+    return rv;
+}
+
+/*
+ * verify the signature of a signed data object with the given certificate
+ */
+SECStatus
+CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert,
+		      int64 t, void *wincx)
+{
+    SECKEYPublicKey *pubKey = 0;
+    SECStatus        rv     = SECFailure;
+    SECCertTimeValidity validity;
+
+    /* check the certificate's validity */
+    validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE);
+    if ( validity != secCertTimeValid ) {
+	return rv;
+    }
+
+    /* get cert's public key */
+    pubKey = CERT_ExtractPublicKey(cert);
+    if (pubKey) {
+	rv =  CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
+	SECKEY_DestroyPublicKey(pubKey);
+    }
+    return rv;
+}
+
+
+/* Software FORTEZZA installation hack. The software fortezza installer does
+ * not have access to the krl and cert.db file. Accept FORTEZZA Certs without
+ * KRL's in this case. 
+ */
+static int dont_use_krl = 0;
+/* not a public exposed function... */
+void sec_SetCheckKRLState(int value) { dont_use_krl = value; }
+
+SECStatus
+SEC_CheckKRL(CERTCertDBHandle *handle,SECKEYPublicKey *key,
+	     CERTCertificate *rootCert, int64 t, void * wincx)
+{
+    CERTSignedCrl *crl = NULL;
+    SECStatus rv = SECFailure;
+    SECStatus rv2;
+    CERTCrlEntry **crlEntry;
+    SECCertTimeValidity validity;
+    CERTCertificate *issuerCert = NULL;
+
+    if (dont_use_krl) return SECSuccess;
+
+    /* first look up the KRL */
+    crl = SEC_FindCrlByName(handle,&rootCert->derSubject, SEC_KRL_TYPE);
+    if (crl == NULL) {
+	PORT_SetError(SEC_ERROR_NO_KRL);
+	goto done;
+    }
+
+    /* get the issuing certificate */
+    issuerCert = CERT_FindCertByName(handle, &crl->crl.derName);
+    if (issuerCert == NULL) {
+        PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
+        goto done;
+    }
+
+
+    /* now verify the KRL signature */
+    rv2 = CERT_VerifySignedData(&crl->signatureWrap, issuerCert, t, wincx);
+    if (rv2 != SECSuccess) {
+	PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
+    	goto done;
+    }
+
+    /* Verify the date validity of the KRL */
+    validity = SEC_CheckCrlTimes(&crl->crl, t);
+    if (validity == secCertTimeExpired) {
+	PORT_SetError(SEC_ERROR_KRL_EXPIRED);
+	goto done;
+    }
+
+    /* now make sure the key in this cert is still valid */
+    if (key->keyType != fortezzaKey) {
+	PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
+	goto done; /* This should be an assert? */
+    }
+
+    /* now make sure the key is not on the revocation list */
+    for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) {
+	if (PORT_Memcmp((*crlEntry)->serialNumber.data,
+				key->u.fortezza.KMID,
+				    (*crlEntry)->serialNumber.len) == 0) {
+	    PORT_SetError(SEC_ERROR_REVOKED_KEY);
+	    goto done;
+	}
+    }
+    rv = SECSuccess;
+
+done:
+    if (issuerCert) CERT_DestroyCertificate(issuerCert);
+    if (crl) SEC_DestroyCrl(crl);
+    return rv;
+}
+
+SECStatus
+SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert,
+	     CERTCertificate *caCert, int64 t, void * wincx)
+{
+    return CERT_CheckCRL(cert, caCert, NULL, t, wincx);
+}
+
+/*
+ * Find the issuer of a cert.  Use the authorityKeyID if it exists.
+ */
+CERTCertificate *
+CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage)
+{
+    NSSCertificate *me;
+    NSSTime *nssTime;
+    NSSTrustDomain *td;
+    NSSCryptoContext *cc;
+    NSSCertificate *chain[3];
+    NSSUsage nssUsage;
+    PRStatus status;
+
+    me = STAN_GetNSSCertificate(cert);
+    if (!me) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+    nssTime = NSSTime_SetPRTime(NULL, validTime);
+    nssUsage.anyUsage = PR_FALSE;
+    nssUsage.nss3usage = usage;
+    nssUsage.nss3lookingForCA = PR_TRUE;
+    memset(chain, 0, 3*sizeof(NSSCertificate *));
+    td   = STAN_GetDefaultTrustDomain();
+    cc = STAN_GetDefaultCryptoContext();
+    (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL, 
+                                    chain, 2, NULL, &status, td, cc);
+    nss_ZFreeIf(nssTime);
+    if (status == PR_SUCCESS) {
+	PORT_Assert(me == chain[0]);
+	/* if it's a root, the chain will only have one cert */
+	if (!chain[1]) {
+	    /* already has a reference from the call to BuildChain */
+	    return cert;
+	} 
+	NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
+	return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */
+    } 
+    if (chain[0]) {
+	PORT_Assert(me == chain[0]);
+	NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
+    }
+    PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
+    return NULL;
+}
+
+/*
+ * return required trust flags for various cert usages for CAs
+ */
+SECStatus
+CERT_TrustFlagsForCACertUsage(SECCertUsage usage,
+			      unsigned int *retFlags,
+			      SECTrustType *retTrustType)
+{
+    unsigned int requiredFlags;
+    SECTrustType trustType;
+
+    switch ( usage ) {
+      case certUsageSSLClient:
+	requiredFlags = CERTDB_TRUSTED_CLIENT_CA;
+	trustType = trustSSL;
+        break;
+      case certUsageSSLServer:
+      case certUsageSSLCA:
+	requiredFlags = CERTDB_TRUSTED_CA;
+	trustType = trustSSL;
+        break;
+      case certUsageSSLServerWithStepUp:
+	requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA;
+	trustType = trustSSL;
+        break;
+      case certUsageEmailSigner:
+      case certUsageEmailRecipient:
+	requiredFlags = CERTDB_TRUSTED_CA;
+	trustType = trustEmail;
+	break;
+      case certUsageObjectSigner:
+	requiredFlags = CERTDB_TRUSTED_CA;
+	trustType = trustObjectSigning;
+	break;
+      case certUsageVerifyCA:
+      case certUsageAnyCA:
+      case certUsageStatusResponder:
+	requiredFlags = CERTDB_TRUSTED_CA;
+	trustType = trustTypeNone;
+	break;
+      default:
+	PORT_Assert(0);
+	goto loser;
+    }
+    if ( retFlags != NULL ) {
+	*retFlags = requiredFlags;
+    }
+    if ( retTrustType != NULL ) {
+	*retTrustType = trustType;
+    }
+    
+    return(SECSuccess);
+loser:
+    return(SECFailure);
+}
+
+void
+cert_AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, unsigned long error,
+	       unsigned int depth, void *arg)
+{
+    CERTVerifyLogNode *node, *tnode;
+
+    PORT_Assert(log != NULL);
+    
+    node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena,
+						sizeof(CERTVerifyLogNode));
+    if ( node != NULL ) {
+	node->cert = CERT_DupCertificate(cert);
+	node->error = error;
+	node->depth = depth;
+	node->arg = arg;
+	
+	if ( log->tail == NULL ) {
+	    /* empty list */
+	    log->head = log->tail = node;
+	    node->prev = NULL;
+	    node->next = NULL;
+	} else if ( depth >= log->tail->depth ) {
+	    /* add to tail */
+	    node->prev = log->tail;
+	    log->tail->next = node;
+	    log->tail = node;
+	    node->next = NULL;
+	} else if ( depth < log->head->depth ) {
+	    /* add at head */
+	    node->prev = NULL;
+	    node->next = log->head;
+	    log->head->prev = node;
+	    log->head = node;
+	} else {
+	    /* add in middle */
+	    tnode = log->tail;
+	    while ( tnode != NULL ) {
+		if ( depth >= tnode->depth ) {
+		    /* insert after tnode */
+		    node->prev = tnode;
+		    node->next = tnode->next;
+		    tnode->next->prev = node;
+		    tnode->next = node;
+		    break;
+		}
+
+		tnode = tnode->prev;
+	    }
+	}
+
+	log->count++;
+    }
+    return;
+}
+
+#define EXIT_IF_NOT_LOGGING(log) \
+    if ( log == NULL ) { \
+	goto loser; \
+    }
+
+#define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \
+    if ( log != NULL ) { \
+	cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \
+    } else { \
+	goto loser; \
+    }
+
+#define LOG_ERROR(log,cert,depth,arg) \
+    if ( log != NULL ) { \
+	cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \
+    }
+
+
+typedef enum { cbd_None, cbd_User, cbd_CA } cbd_FortezzaType;
+
+static SECStatus
+cert_VerifyFortezzaV1Cert(CERTCertDBHandle *handle, CERTCertificate *cert,
+	cbd_FortezzaType *next_type, cbd_FortezzaType last_type,
+	int64 t, void *wincx)
+{
+    unsigned char priv = 0;
+    SECKEYPublicKey *key;
+    SECStatus rv;
+
+    *next_type = cbd_CA;
+
+    /* read the key */
+    key = CERT_ExtractPublicKey(cert);
+
+    /* Cant' get Key? fail. */
+    if (key == NULL) {
+    	PORT_SetError(SEC_ERROR_BAD_KEY);
+	return SECFailure;
+    }
+
+
+    /* if the issuer is not an old fortezza cert, we bail */
+    if (key->keyType != fortezzaKey) {
+    	SECKEY_DestroyPublicKey(key);
+	/* CA Cert not fortezza */
+    	PORT_SetError(SEC_ERROR_NOT_FORTEZZA_ISSUER);
+	return SECFailure;
+    }
+
+    /* get the privilege mask */
+    if (key->u.fortezza.DSSpriviledge.len > 0) {
+	priv = key->u.fortezza.DSSpriviledge.data[0];
+    }
+
+    /*
+     * make sure the CA's keys are OK
+     */
+            
+    rv = SEC_CheckKRL(handle, key, NULL, t, wincx);
+    SECKEY_DestroyPublicKey(key);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+
+    switch (last_type) {
+      case cbd_User:
+	/* first check for subordination */
+	/*rv = FortezzaSubordinateCheck(cert,issuerCert);*/
+	rv = SECSuccess;
+
+	/* now check for issuer privilege */
+	if ((rv != SECSuccess) || ((priv & 0x10) == 0)) {
+	    /* bail */
+	    PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
+	    return SECFailure;
+	}
+	break;
+      case cbd_CA:
+	if ((priv & 0x20) == 0) {
+	    /* bail */
+	    PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
+	    return SECFailure;
+	}
+	break;
+      case cbd_None:
+	*next_type = (priv & 0x30) ? cbd_CA : cbd_User;
+	break;
+      default:
+	/* bail */ /* shouldn't ever happen */
+    	PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+static SECStatus
+cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert,
+		     PRBool checkSig, PRBool* sigerror,
+                     SECCertUsage certUsage, int64 t, void *wincx,
+                     CERTVerifyLog *log, PRBool* revoked)
+{
+    SECTrustType trustType;
+    CERTBasicConstraints basicConstraint;
+    CERTCertificate *issuerCert = NULL;
+    CERTCertificate *subjectCert = NULL;
+    CERTCertificate *badCert = NULL;
+    PRBool isca;
+    PRBool isFortezzaV1 = PR_FALSE;
+    SECStatus rv;
+    SECStatus rvFinal = SECSuccess;
+    int count;
+    int currentPathLen = 0;
+    int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
+    unsigned int caCertType;
+    unsigned int requiredCAKeyUsage;
+    unsigned int requiredFlags;
+    PRArenaPool *arena = NULL;
+    CERTGeneralName *namesList = NULL;
+    CERTCertificate **certsList      = NULL;
+    int certsListLen = 16;
+    int namesCount = 0;
+    PRBool subjectCertIsSelfIssued;
+
+    cbd_FortezzaType last_type = cbd_None;
+
+    if (revoked) {
+        *revoked = PR_FALSE;
+    }
+
+    if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
+					 &requiredCAKeyUsage,
+					 &caCertType)
+	!= SECSuccess ) {
+	PORT_Assert(0);
+	EXIT_IF_NOT_LOGGING(log);
+	requiredCAKeyUsage = 0;
+	caCertType = 0;
+    }
+
+    switch ( certUsage ) {
+      case certUsageSSLClient:
+      case certUsageSSLServer:
+      case certUsageSSLCA:
+      case certUsageSSLServerWithStepUp:
+      case certUsageEmailSigner:
+      case certUsageEmailRecipient:
+      case certUsageObjectSigner:
+      case certUsageVerifyCA:
+      case certUsageAnyCA:
+      case certUsageStatusResponder:
+	if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
+					   &trustType) != SECSuccess ) {
+	    PORT_Assert(0);
+	    EXIT_IF_NOT_LOGGING(log);
+	    requiredFlags = 0;
+	    trustType = trustSSL;
+	}
+	break;
+      default:
+	PORT_Assert(0);
+	EXIT_IF_NOT_LOGGING(log);
+	requiredFlags = 0;
+	trustType = trustSSL;/* This used to be 0, but we need something
+			      * that matches the enumeration type.
+			      */
+	caCertType = 0;
+    }
+    
+    subjectCert = CERT_DupCertificate(cert);
+    if ( subjectCert == NULL ) {
+	goto loser;
+    }
+
+    /* determine if the cert is fortezza.
+     */
+    isFortezzaV1 = (PRBool)
+	(CERT_GetCertKeyType(&subjectCert->subjectPublicKeyInfo) 
+							== fortezzaKey);
+
+    if (isFortezzaV1) {
+	rv = cert_VerifyFortezzaV1Cert(handle, subjectCert, &last_type, 
+						cbd_None, t, wincx);
+	if (rv == SECFailure) {
+	    /**** PORT_SetError is already set by cert_VerifyFortezzaV1Cert **/
+	    LOG_ERROR_OR_EXIT(log,subjectCert,0,0);
+	}
+    }
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+
+    certsList = PORT_ZNewArray(CERTCertificate *, certsListLen);
+    if (certsList == NULL)
+	goto loser;
+
+    /* RFC 3280 says that the name constraints will apply to the names
+    ** in the leaf (EE) cert, whether it is self issued or not, so
+    ** we pretend that it is not.
+    */
+    subjectCertIsSelfIssued = PR_FALSE;
+    for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {
+	PRBool validCAOverride = PR_FALSE;
+
+	/* Construct a list of names for the current and all previous 
+	 * certifcates (except leaf (EE) certs, root CAs, and self-issued
+	 * intermediate CAs) to be verified against the name constraints 
+	 * extension of the issuer certificate. 
+	 */
+	if (subjectCertIsSelfIssued == PR_FALSE) {
+	    CERTGeneralName *subjectNameList;
+	    int subjectNameListLen;
+	    int i;
+	    subjectNameList    = CERT_GetCertificateNames(subjectCert, arena);
+	    if (!subjectNameList)
+		goto loser;
+	    subjectNameListLen = CERT_GetNamesLength(subjectNameList);
+	    if (!subjectNameListLen)
+		goto loser;
+	    if (certsListLen <= namesCount + subjectNameListLen) {
+		CERTCertificate **tmpCertsList;
+		certsListLen = (namesCount + subjectNameListLen) * 2;
+		tmpCertsList = 
+		    (CERTCertificate **)PORT_Realloc(certsList, 
+	                            certsListLen * sizeof(CERTCertificate *));
+		if (tmpCertsList == NULL) {
+		    goto loser;
+		}
+		certsList = tmpCertsList;
+	    }
+	    for (i = 0; i < subjectNameListLen; i++) {
+		certsList[namesCount + i] = subjectCert;
+	    }
+	    namesCount += subjectNameListLen;
+	    namesList = cert_CombineNamesLists(namesList, subjectNameList);
+	}
+
+        /* check if the cert has an unsupported critical extension */
+	if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) {
+	    PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+	    LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
+	}
+
+	/* find the certificate of the issuer */
+	issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage);
+	if ( ! issuerCert ) {
+	    PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
+	    LOG_ERROR(log,subjectCert,count,0);
+	    goto loser;
+	}
+
+	/* verify the signature on the cert */
+	if ( checkSig ) {
+	    rv = CERT_VerifySignedData(&subjectCert->signatureWrap,
+				       issuerCert, t, wincx);
+    
+	    if ( rv != SECSuccess ) {
+                if (sigerror) {
+                    *sigerror = PR_TRUE;
+                }
+		if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) {
+		    PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
+		    LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
+		} else {
+		    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+		    LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
+		}
+	    }
+	}
+
+	/*
+	 * XXX - fortezza may need error logging stuff added
+	 */
+	if (isFortezzaV1) {
+	    rv = cert_VerifyFortezzaV1Cert(handle, issuerCert, &last_type, 
+					last_type, t, wincx);
+	    if (rv == SECFailure) {
+		/**** PORT_SetError is already set by *
+		 * cert_VerifyFortezzaV1Cert **/
+		LOG_ERROR_OR_EXIT(log,subjectCert,0,0);
+	    }
+	}
+
+	/* If the basicConstraint extension is included in an immediate CA
+	 * certificate, make sure that the isCA flag is on.  If the
+	 * pathLenConstraint component exists, it must be greater than the
+	 * number of CA certificates we have seen so far.  If the extension
+	 * is omitted, we will assume that this is a CA certificate with
+	 * an unlimited pathLenConstraint (since it already passes the
+	 * netscape-cert-type extension checking).
+	 *
+	 * In the fortezza (V1) case, we've already checked the CA bits
+	 * in the key, so we're presumed to be a CA; however we really don't
+	 * want to bypass Basic constraint or netscape extension parsing.
+         * 
+         * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA
+	 */
+
+	rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint);
+	if ( rv != SECSuccess ) {
+	    if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
+		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
+	    } 
+	    pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
+	    /* no basic constraints found, if we're fortezza, CA bit is already
+	     * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca
+	     * isca = PR_FALSE */
+	    isca = isFortezzaV1;
+	} else  {
+	    if ( basicConstraint.isCA == PR_FALSE ) {
+		PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
+		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
+	    }
+	    pathLengthLimit = basicConstraint.pathLenConstraint;
+	    isca = PR_TRUE;
+	}    
+	/* make sure that the path len constraint is properly set.*/
+	if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) {
+	    PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
+	    LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit);
+	}
+	
+	/* XXX - the error logging may need to go down into CRL stuff at some
+	 * point
+	 */
+	/* check revoked list (issuer) */
+        rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
+        if (rv == SECFailure) {
+            if (revoked) {
+                *revoked = PR_TRUE;
+            }
+            LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
+        } else if (rv == SECWouldBlock) {
+            /* We found something fishy, so we intend to issue an
+             * error to the user, but the user may wish to continue
+             * processing, in which case we better make sure nothing
+             * worse has happened... so keep cranking the loop */
+            rvFinal = SECFailure;
+            if (revoked) {
+                *revoked = PR_TRUE;
+            }
+            LOG_ERROR(log,subjectCert,count,0);
+        }
+
+	if ( issuerCert->trust ) {
+	    /* we have some trust info, but this does NOT imply that this
+	     * cert is actually trusted for any purpose.  The cert may be
+	     * explicitly UNtrusted.  We won't know until we examine the
+	     * trust bits.
+	     */
+	    unsigned int flags;
+
+	    if (certUsage != certUsageAnyCA &&
+	        certUsage != certUsageStatusResponder) {
+
+	        /*
+	         * XXX This choice of trustType seems arbitrary.
+	         */
+	        if ( certUsage == certUsageVerifyCA ) {
+	            if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) {
+	                trustType = trustEmail;
+	            } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) {
+	                trustType = trustSSL;
+	            } else {
+	                trustType = trustObjectSigning;
+	            }
+	        }
+
+	        flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType);
+	        if (( flags & requiredFlags ) == requiredFlags) {
+	            /* we found a trusted one, so return */
+	            rv = rvFinal; 
+	            goto done;
+	        }
+	        if (flags & CERTDB_VALID_CA) {
+	            validCAOverride = PR_TRUE;
+	        }
+	    } else {
+                /* Check if we have any valid trust when cheching for
+                 * certUsageAnyCA or certUsageStatusResponder. */
+                for (trustType = trustSSL; trustType < trustTypeNone;
+                     trustType++) {
+                    flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType);
+                    if ((flags & requiredFlags) == requiredFlags) {
+	                rv = rvFinal; 
+	                goto done;
+                    }
+                    if (flags & CERTDB_VALID_CA)
+                        validCAOverride = PR_TRUE;
+                }
+            }
+        }
+
+	if (!validCAOverride) {
+	    /*
+	     * Make sure that if this is an intermediate CA in the chain that
+	     * it was given permission by its signer to be a CA.
+	     */
+	    /*
+	     * if basicConstraints says it is a ca, then we check the
+	     * nsCertType.  If the nsCertType has any CA bits set, then
+	     * it must have the right one.
+	     */
+	    if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) {
+		isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
+	    }
+	
+	    if (  !isca  ) {
+		PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
+		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
+	    }
+
+	    /* make sure key usage allows cert signing */
+	    if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) {
+		PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
+		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage);
+	    }
+	}
+
+	/* make sure that the entire chain is within the name space of the 
+	** current issuer certificate.
+	*/
+	rv = CERT_CompareNameSpace(issuerCert, namesList, certsList, 
+	                           arena, &badCert);
+	if (rv != SECSuccess || badCert != NULL) {
+	    PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE);
+            LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0);
+	    goto loser;
+	}
+	/* make sure that the issuer is not self signed.  If it is, then
+	 * stop here to prevent looping.
+	 */
+	if (issuerCert->isRoot) {
+	    PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
+	    LOG_ERROR(log, issuerCert, count+1, 0);
+	    goto loser;
+	} 
+	/* The issuer cert will be the subject cert in the next loop.
+	 * A cert is self-issued if its subject and issuer are equal and
+	 * both are of non-zero length. 
+	 */
+	subjectCertIsSelfIssued = (PRBool)
+	    SECITEM_ItemsAreEqual(&issuerCert->derIssuer, 
+				  &issuerCert->derSubject) &&
+	    issuerCert->derSubject.len > 0;
+	if (subjectCertIsSelfIssued == PR_FALSE) {
+	    /* RFC 3280 says only non-self-issued intermediate CA certs 
+	     * count in path length.
+	     */
+	    ++currentPathLen;
+	}
+
+	CERT_DestroyCertificate(subjectCert);
+	subjectCert = issuerCert;
+	issuerCert = NULL;
+    }
+
+    PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
+    LOG_ERROR(log,subjectCert,count,0);
+loser:
+    rv = SECFailure;
+done:
+    if (certsList != NULL) {
+	PORT_Free(certsList);
+    }
+    if ( issuerCert ) {
+	CERT_DestroyCertificate(issuerCert);
+    }
+    
+    if ( subjectCert ) {
+	CERT_DestroyCertificate(subjectCert);
+    }
+
+    if ( arena != NULL ) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return rv;
+}
+
+SECStatus
+cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
+                     PRBool checkSig, PRBool* sigerror,
+                     SECCertUsage certUsage, int64 t, void *wincx,
+                     CERTVerifyLog *log, PRBool* revoked)
+{
+    if (CERT_GetUsePKIXForValidation()) {
+        return cert_VerifyCertChainPkix(cert, checkSig, certUsage, t,
+                                        wincx, log, sigerror, revoked);
+    }
+    return cert_VerifyCertChainOld(handle, cert, checkSig, sigerror,
+                                   certUsage, t, wincx, log, revoked);
+}
+
+SECStatus
+CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
+		     PRBool checkSig, SECCertUsage certUsage, int64 t,
+		     void *wincx, CERTVerifyLog *log)
+{
+    return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t,
+			 wincx, log, NULL);
+}
+
+/*
+ * verify that a CA can sign a certificate with the requested usage.
+ */
+SECStatus
+CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
+		PRBool checkSig, SECCertUsage certUsage, int64 t,
+		void *wincx, CERTVerifyLog *log)
+{
+    SECTrustType trustType;
+    CERTBasicConstraints basicConstraint;
+    PRBool isca;
+    PRBool validCAOverride = PR_FALSE;
+    SECStatus rv;
+    SECStatus rvFinal = SECSuccess;
+    int flags;
+    unsigned int caCertType;
+    unsigned int requiredCAKeyUsage;
+    unsigned int requiredFlags;
+    CERTCertificate *issuerCert;
+
+
+    if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
+					 &requiredCAKeyUsage,
+					 &caCertType) != SECSuccess ) {
+	PORT_Assert(0);
+	EXIT_IF_NOT_LOGGING(log);
+	requiredCAKeyUsage = 0;
+	caCertType = 0;
+    }
+
+    switch ( certUsage ) {
+      case certUsageSSLClient:
+      case certUsageSSLServer:
+      case certUsageSSLCA:
+      case certUsageSSLServerWithStepUp:
+      case certUsageEmailSigner:
+      case certUsageEmailRecipient:
+      case certUsageObjectSigner:
+      case certUsageVerifyCA:
+      case certUsageStatusResponder:
+	if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
+					   &trustType) != SECSuccess ) {
+	    PORT_Assert(0);
+	    EXIT_IF_NOT_LOGGING(log);
+	    requiredFlags = 0;
+	    trustType = trustSSL;
+	}
+	break;
+      default:
+	PORT_Assert(0);
+	EXIT_IF_NOT_LOGGING(log);
+	requiredFlags = 0;
+	trustType = trustSSL;/* This used to be 0, but we need something
+			      * that matches the enumeration type.
+			      */
+	caCertType = 0;
+    }
+    
+    /* If the basicConstraint extension is included in an intermmediate CA
+     * certificate, make sure that the isCA flag is on.  If the
+     * pathLenConstraint component exists, it must be greater than the
+     * number of CA certificates we have seen so far.  If the extension
+     * is omitted, we will assume that this is a CA certificate with
+     * an unlimited pathLenConstraint (since it already passes the
+     * netscape-cert-type extension checking).
+     *
+     * In the fortezza (V1) case, we've already checked the CA bits
+     * in the key, so we're presumed to be a CA; however we really don't
+     * want to bypass Basic constraint or netscape extension parsing.
+     * 
+     * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA
+     */
+
+    rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
+    if ( rv != SECSuccess ) {
+	if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
+	    LOG_ERROR_OR_EXIT(log,cert,0,0);
+	} 
+	/* no basic constraints found, if we're fortezza, CA bit is already
+	 * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca
+	 * isca = PR_FALSE */
+	isca = PR_FALSE;
+    } else  {
+	if ( basicConstraint.isCA == PR_FALSE ) {
+	    PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
+	    LOG_ERROR_OR_EXIT(log,cert,0,0);
+	}
+
+	/* can't check path length if we don't know the previous path */
+	isca = PR_TRUE;
+    }
+	
+    if ( cert->trust ) {
+	/* we have some trust info, but this does NOT imply that this
+	 * cert is actually trusted for any purpose.  The cert may be
+	 * explicitly UNtrusted.  We won't know until we examine the
+	 * trust bits.
+	 */
+        if (certUsage == certUsageStatusResponder) {
+	    /* Check the special case of certUsageStatusResponder */
+            issuerCert = CERT_FindCertIssuer(cert, t, certUsage);
+            if (issuerCert) {
+                if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx) 
+		    != SECSuccess) {
+                    PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
+                    CERT_DestroyCertificate(issuerCert);
+                    goto loser;
+                }
+                CERT_DestroyCertificate(issuerCert);
+            }
+	    /* XXX We have NOT determined that this cert is trusted.
+	     * For years, NSS has treated this as trusted, 
+	     * but it seems incorrect.
+	     */
+	    rv = rvFinal; 
+	    goto done;
+        }
+
+	/*
+	 * check the trust parms of the issuer
+	 */
+	flags = SEC_GET_TRUST_FLAGS(cert->trust, trustType);
+	if ( ( flags & requiredFlags ) == requiredFlags) {
+	    /* we found a trusted one, so return */
+	    rv = rvFinal; 
+	    goto done;
+	}
+	if (flags & CERTDB_VALID_CA) {
+	    validCAOverride = PR_TRUE;
+	}
+    }
+    if (!validCAOverride) {
+	/*
+	 * Make sure that if this is an intermediate CA in the chain that
+	 * it was given permission by its signer to be a CA.
+	 */
+	/*
+	 * if basicConstraints says it is a ca, then we check the
+	 * nsCertType.  If the nsCertType has any CA bits set, then
+	 * it must have the right one.
+	 */
+	if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) {
+	    isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
+	}
+	
+	if (!isca) {
+	    PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
+	    LOG_ERROR_OR_EXIT(log,cert,0,0);
+	}
+	    
+	/* make sure key usage allows cert signing */
+	if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) {
+	    PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
+	    LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage);
+	}
+    }
+    /* make sure that the issuer is not self signed.  If it is, then
+     * stop here to prevent looping.
+     */
+    if (cert->isRoot) {
+	    PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
+	    LOG_ERROR(log, cert, 0, 0);
+	    goto loser;
+    }
+
+    return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t, 
+		     					wincx, log);
+loser:
+    rv = SECFailure;
+done:
+    return rv;
+}
+
+#define NEXT_USAGE() { \
+    i*=2; \
+    certUsage++; \
+    continue; \
+}
+
+#define VALID_USAGE() { \
+    NEXT_USAGE(); \
+}
+
+#define INVALID_USAGE() { \
+    if (returnedUsages) { \
+        *returnedUsages &= (~i); \
+    } \
+    if (PR_TRUE == requiredUsage) { \
+        valid = SECFailure; \
+    } \
+    NEXT_USAGE(); \
+}
+
+/*
+ * verify a certificate by checking if it's valid and that we
+ * trust the issuer.
+ *
+ * certificateUsage contains a bitfield of all cert usages that are
+ * required for verification to succeed
+ *
+ * a bitfield of cert usages is returned in *returnedUsages
+ * if requiredUsages is non-zero, the returned bitmap is only
+ * for those required usages, otherwise it is for all usages
+ *
+ */
+SECStatus
+CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
+		PRBool checkSig, SECCertificateUsage requiredUsages, int64 t,
+		void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages)
+{
+    SECStatus rv;
+    SECStatus valid;
+    unsigned int requiredKeyUsage;
+    unsigned int requiredCertType;
+    unsigned int flags;
+    unsigned int certType;
+    PRBool       allowOverride;
+    SECCertTimeValidity validity;
+    CERTStatusConfig *statusConfig;
+    PRInt32 i;
+    SECCertUsage certUsage = 0;
+    PRBool checkedOCSP = PR_FALSE;
+    PRBool checkAllUsages = PR_FALSE;
+    PRBool revoked = PR_FALSE;
+    PRBool sigerror = PR_FALSE;
+
+    if (!requiredUsages) {
+        /* there are no required usages, so the user probably wants to
+           get status for all usages */
+        checkAllUsages = PR_TRUE;
+    }
+
+    if (returnedUsages) {
+        *returnedUsages = 0;
+    } else {
+        /* we don't have a place to return status for all usages,
+           so we can skip checks for usages that aren't required */
+        checkAllUsages = PR_FALSE;
+    }
+    valid = SECSuccess ; /* start off assuming cert is valid */
+   
+    /* make sure that the cert is valid at time t */
+    allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) ||
+                             (requiredUsages & certificateUsageSSLServerWithStepUp));
+    validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
+    if ( validity != secCertTimeValid ) {
+        valid = SECFailure;
+        LOG_ERROR_OR_EXIT(log,cert,0,validity);
+    }
+
+    /* check key usage and netscape cert type */
+    cert_GetCertType(cert);
+    certType = cert->nsCertType;
+
+    for (i=1; i<=certificateUsageHighest && 
+              (SECSuccess == valid || returnedUsages || log) ; ) {
+        PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
+        if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
+            NEXT_USAGE();
+        }
+        if (returnedUsages) {
+            *returnedUsages |= i; /* start off assuming this usage is valid */
+        }
+        switch ( certUsage ) {
+          case certUsageSSLClient:
+          case certUsageSSLServer:
+          case certUsageSSLServerWithStepUp:
+          case certUsageSSLCA:
+          case certUsageEmailSigner:
+          case certUsageEmailRecipient:
+          case certUsageObjectSigner:
+          case certUsageStatusResponder:
+            rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
+                                                  &requiredKeyUsage,
+                                                  &requiredCertType);
+            if ( rv != SECSuccess ) {
+                PORT_Assert(0);
+                /* EXIT_IF_NOT_LOGGING(log); XXX ??? */
+                requiredKeyUsage = 0;
+                requiredCertType = 0;
+                INVALID_USAGE();
+            }
+            break;
+
+          case certUsageAnyCA:
+          case certUsageProtectedObjectSigner:
+          case certUsageUserCertImport:
+          case certUsageVerifyCA:
+              /* these usages cannot be verified */
+              NEXT_USAGE();
+
+          default:
+            PORT_Assert(0);
+            requiredKeyUsage = 0;
+            requiredCertType = 0;
+            INVALID_USAGE();
+        }
+        if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
+            if (PR_TRUE == requiredUsage) {
+                PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
+            }
+            LOG_ERROR(log,cert,0,requiredKeyUsage);
+            INVALID_USAGE();
+        }
+        if ( !( certType & requiredCertType ) ) {
+            if (PR_TRUE == requiredUsage) {
+                PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
+            }
+            LOG_ERROR(log,cert,0,requiredCertType);
+            INVALID_USAGE();
+        }
+
+        /* check trust flags to see if this cert is directly trusted */
+        if ( cert->trust ) { /* the cert is in the DB */
+            switch ( certUsage ) {
+              case certUsageSSLClient:
+              case certUsageSSLServer:
+                flags = cert->trust->sslFlags;
+
+                /* is the cert directly trusted or not trusted ? */
+                if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
+                    if ( flags & CERTDB_TRUSTED ) {	/* trust this cert */
+                        VALID_USAGE();
+                    } else { /* don't trust this cert */
+                        if (PR_TRUE == requiredUsage) {
+                            PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
+                        }
+                        LOG_ERROR(log,cert,0,flags);
+                        INVALID_USAGE();
+                    }
+                }
+                break;
+              case certUsageSSLServerWithStepUp:
+                /* XXX - step up certs can't be directly trusted */
+                break;
+              case certUsageSSLCA:
+                break;
+              case certUsageEmailSigner:
+              case certUsageEmailRecipient:
+                flags = cert->trust->emailFlags;
+
+                /* is the cert directly trusted or not trusted ? */
+                if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
+                    ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
+                    VALID_USAGE();
+                }
+                break;
+              case certUsageObjectSigner:
+                flags = cert->trust->objectSigningFlags;
+
+                /* is the cert directly trusted or not trusted ? */
+                if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
+                    if ( flags & CERTDB_TRUSTED ) {	/* trust this cert */
+                        VALID_USAGE();
+                    } else { /* don't trust this cert */
+                        if (PR_TRUE == requiredUsage) {
+                            PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
+                        }
+                        LOG_ERROR(log,cert,0,flags);
+                        INVALID_USAGE();
+                    }
+                }
+                break;
+              case certUsageVerifyCA:
+              case certUsageStatusResponder:
+                flags = cert->trust->sslFlags;
+                /* is the cert directly trusted or not trusted ? */
+                if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+                    ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+                    VALID_USAGE();
+                }
+                flags = cert->trust->emailFlags;
+                /* is the cert directly trusted or not trusted ? */
+                if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+                    ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+                    VALID_USAGE();
+                }
+                flags = cert->trust->objectSigningFlags;
+                /* is the cert directly trusted or not trusted ? */
+                if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+                    ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+                    VALID_USAGE();
+                }
+                break;
+              case certUsageAnyCA:
+              case certUsageProtectedObjectSigner:
+              case certUsageUserCertImport:
+                /* XXX to make the compiler happy.  Should these be
+                 * explicitly handled?
+                 */
+                break;
+            }
+        }
+
+        if (PR_TRUE == revoked || PR_TRUE == sigerror) {
+            INVALID_USAGE();
+        }
+
+        rv = cert_VerifyCertChain(handle, cert,
+            checkSig, &sigerror,
+            certUsage, t, wincx, log,
+            &revoked);
+
+        if (rv != SECSuccess) {
+            /* EXIT_IF_NOT_LOGGING(log); XXX ???? */
+            INVALID_USAGE();
+        }
+
+        /*
+         * Check OCSP revocation status, but only if the cert we are checking
+         * is not a status reponder itself.  We only do this in the case
+         * where we checked the cert chain (above); explicit trust "wins"
+         * (avoids status checking, just as it avoids CRL checking) by
+         * bypassing this code.
+         */
+
+        if (PR_FALSE == checkedOCSP) {
+            checkedOCSP = PR_TRUE; /* only check OCSP once */
+            statusConfig = CERT_GetStatusConfig(handle);
+            if (requiredUsages != certificateUsageStatusResponder &&
+                statusConfig != NULL) {
+                if (statusConfig->statusChecker != NULL) {
+                    rv = (* statusConfig->statusChecker)(handle, cert,
+                                                                 t, wincx);
+                    if (rv != SECSuccess) {
+                        LOG_ERROR(log,cert,0,0);
+                        revoked = PR_TRUE;
+                        INVALID_USAGE();
+                    }
+                }
+            }
+        }
+
+        NEXT_USAGE();
+    }
+    
+loser:
+    return(valid);
+}
+
+SECStatus
+CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
+		PRBool checkSig, SECCertUsage certUsage, int64 t,
+		void *wincx, CERTVerifyLog *log)
+{
+    SECStatus rv;
+    unsigned int requiredKeyUsage;
+    unsigned int requiredCertType;
+    unsigned int flags;
+    unsigned int certType;
+    PRBool       allowOverride;
+    SECCertTimeValidity validity;
+    CERTStatusConfig *statusConfig;
+   
+#ifdef notdef 
+    /* check if this cert is in the Evil list */
+    rv = CERT_CheckForEvilCert(cert);
+    if ( rv != SECSuccess ) {
+	PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
+	LOG_ERROR_OR_EXIT(log,cert,0,0);
+    }
+#endif
+    
+    /* make sure that the cert is valid at time t */
+    allowOverride = (PRBool)((certUsage == certUsageSSLServer) ||
+                             (certUsage == certUsageSSLServerWithStepUp));
+    validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
+    if ( validity != secCertTimeValid ) {
+	LOG_ERROR_OR_EXIT(log,cert,0,validity);
+    }
+
+    /* check key usage and netscape cert type */
+    cert_GetCertType(cert);
+    certType = cert->nsCertType;
+    switch ( certUsage ) {
+      case certUsageSSLClient:
+      case certUsageSSLServer:
+      case certUsageSSLServerWithStepUp:
+      case certUsageSSLCA:
+      case certUsageEmailSigner:
+      case certUsageEmailRecipient:
+      case certUsageObjectSigner:
+      case certUsageStatusResponder:
+	rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
+					      &requiredKeyUsage,
+					      &requiredCertType);
+	if ( rv != SECSuccess ) {
+	    PORT_Assert(0);
+	    EXIT_IF_NOT_LOGGING(log);
+	    requiredKeyUsage = 0;
+	    requiredCertType = 0;
+	}
+	break;
+      case certUsageVerifyCA:
+      case certUsageAnyCA:
+	requiredKeyUsage = KU_KEY_CERT_SIGN;
+	requiredCertType = NS_CERT_TYPE_CA;
+	if ( ! ( certType & NS_CERT_TYPE_CA ) ) {
+	    certType |= NS_CERT_TYPE_CA;
+	}
+	break;
+      default:
+	PORT_Assert(0);
+	EXIT_IF_NOT_LOGGING(log);
+	requiredKeyUsage = 0;
+	requiredCertType = 0;
+    }
+    if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
+	PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
+	LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage);
+    }
+    if ( !( certType & requiredCertType ) ) {
+	PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
+	LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType);
+    }
+
+    /* check trust flags to see if this cert is directly trusted */
+    if ( cert->trust ) { /* the cert is in the DB */
+	switch ( certUsage ) {
+	  case certUsageSSLClient:
+	  case certUsageSSLServer:
+	    flags = cert->trust->sslFlags;
+	    
+	    /* is the cert directly trusted or not trusted ? */
+	    if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
+		if ( flags & CERTDB_TRUSTED ) {	/* trust this cert */
+		    goto winner;
+		} else { /* don't trust this cert */
+		    PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
+		    LOG_ERROR_OR_EXIT(log,cert,0,flags);
+		}
+	    }
+	    break;
+	  case certUsageSSLServerWithStepUp:
+	    /* XXX - step up certs can't be directly trusted */
+	    break;
+	  case certUsageSSLCA:
+	    break;
+	  case certUsageEmailSigner:
+	  case certUsageEmailRecipient:
+	    flags = cert->trust->emailFlags;
+	    
+	    /* is the cert directly trusted or not trusted ? */
+	    if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
+		( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
+		goto winner;
+	    }
+	    break;
+	  case certUsageObjectSigner:
+	    flags = cert->trust->objectSigningFlags;
+
+	    /* is the cert directly trusted or not trusted ? */
+	    if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
+		if ( flags & CERTDB_TRUSTED ) {	/* trust this cert */
+		    goto winner;
+		} else { /* don't trust this cert */
+		    PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
+		    LOG_ERROR_OR_EXIT(log,cert,0,flags);
+		}
+	    }
+	    break;
+	  case certUsageVerifyCA:
+	  case certUsageStatusResponder:
+	    flags = cert->trust->sslFlags;
+	    /* is the cert directly trusted or not trusted ? */
+	    if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+		( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+		goto winner;
+	    }
+	    flags = cert->trust->emailFlags;
+	    /* is the cert directly trusted or not trusted ? */
+	    if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+		( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+		goto winner;
+	    }
+	    flags = cert->trust->objectSigningFlags;
+	    /* is the cert directly trusted or not trusted ? */
+	    if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+		( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+		goto winner;
+	    }
+	    break;
+	  case certUsageAnyCA:
+	  case certUsageProtectedObjectSigner:
+	  case certUsageUserCertImport:
+	    /* XXX to make the compiler happy.  Should these be
+	     * explicitly handled?
+	     */
+	    break;
+	}
+    }
+
+    rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage,
+			      t, wincx, log);
+    if (rv != SECSuccess) {
+	EXIT_IF_NOT_LOGGING(log);
+    }
+
+    /*
+     * Check revocation status, but only if the cert we are checking
+     * is not a status reponder itself.  We only do this in the case
+     * where we checked the cert chain (above); explicit trust "wins"
+     * (avoids status checking, just as it avoids CRL checking, which
+     * is all done inside VerifyCertChain) by bypassing this code.
+     */
+    statusConfig = CERT_GetStatusConfig(handle);
+    if (certUsage != certUsageStatusResponder && statusConfig != NULL) {
+	if (statusConfig->statusChecker != NULL) {
+	    rv = (* statusConfig->statusChecker)(handle, cert,
+							 t, wincx);
+	    if (rv != SECSuccess) {
+		LOG_ERROR_OR_EXIT(log,cert,0,0);
+	    }
+	}
+    }
+
+winner:
+    return(SECSuccess);
+
+loser:
+    rv = SECFailure;
+    
+    return(rv);
+}
+
+/*
+ * verify a certificate by checking if its valid and that we
+ * trust the issuer.  Verify time against now.
+ */
+SECStatus
+CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
+		   PRBool checkSig, SECCertificateUsage requiredUsages,
+                   void *wincx, SECCertificateUsage* returnedUsages)
+{
+    return(CERT_VerifyCertificate(handle, cert, checkSig, 
+		   requiredUsages, PR_Now(), wincx, NULL, returnedUsages));
+}
+
+/* obsolete, do not use for new code */
+SECStatus
+CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
+		   PRBool checkSig, SECCertUsage certUsage, void *wincx)
+{
+    return(CERT_VerifyCert(handle, cert, checkSig, 
+		   certUsage, PR_Now(), wincx, NULL));
+}
+
+
+/* [ FROM pcertdb.c ] */
+/*
+ * 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)
+{
+    CERTCertList *certList = NULL;
+    CERTCertificate *cert = NULL;
+    unsigned int requiredTrustFlags;
+    SECTrustType requiredTrustType;
+    unsigned int flags;
+    
+    PRBool lookingForCA = PR_FALSE;
+    SECStatus rv;
+    CERTCertListNode *node;
+    CERTCertificate *saveUntrustedCA = NULL;
+    
+    /* if preferTrusted is set, must be a CA cert */
+    PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) );
+    
+    if ( owner == certOwnerCA ) {
+	lookingForCA = PR_TRUE;
+	if ( preferTrusted ) {
+	    rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags,
+					       &requiredTrustType);
+	    if ( rv != SECSuccess ) {
+		goto loser;
+	    }
+	    requiredTrustFlags |= CERTDB_VALID_CA;
+	}
+    }
+
+    certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime,
+					  validOnly);
+    if ( certList != NULL ) {
+	rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA);
+	if ( rv != SECSuccess ) {
+	    goto loser;
+	}
+	
+	node = CERT_LIST_HEAD(certList);
+	
+	while ( !CERT_LIST_END(node, certList) ) {
+	    cert = node->cert;
+
+	    /* looking for a trusted CA cert */
+	    if ( ( owner == certOwnerCA ) && preferTrusted &&
+		( requiredTrustType != trustTypeNone ) ) {
+
+		if ( cert->trust == NULL ) {
+		    flags = 0;
+		} else {
+		    flags = SEC_GET_TRUST_FLAGS(cert->trust, requiredTrustType);
+		}
+
+		if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) {
+		    /* cert is not trusted */
+		    /* if this is the first cert to get this far, then save
+		     * it, so we can use it if we can't find a trusted one
+		     */
+		    if ( saveUntrustedCA == NULL ) {
+			saveUntrustedCA = cert;
+		    }
+		    goto endloop;
+		}
+	    }
+	    /* if we got this far, then this cert meets all criteria */
+	    break;
+	    
+endloop:
+	    node = CERT_LIST_NEXT(node);
+	    cert = NULL;
+	}
+
+	/* use the saved one if we have it */
+	if ( cert == NULL ) {
+	    cert = saveUntrustedCA;
+	}
+
+	/* if we found one then bump the ref count before freeing the list */
+	if ( cert != NULL ) {
+	    /* bump the ref count */
+	    cert = CERT_DupCertificate(cert);
+	}
+	
+	CERT_DestroyCertList(certList);
+    }
+
+    return(cert);
+
+loser:
+    if ( certList != NULL ) {
+	CERT_DestroyCertList(certList);
+    }
+
+    return(NULL);
+}
+
+
+/* [ From certdb.c ] */
+/*
+ * 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)
+{
+    CERTCertificate *issuerCert = NULL;
+    CERTCertificate *subjectCert;
+    CERTCertListNode *node, *freenode;
+    CERTCertificate *cert;
+    int n;
+    char **names;
+    PRBool found;
+    int64 time;
+    
+    if ( nCANames <= 0 ) {
+	return(SECSuccess);
+    }
+
+    time = PR_Now();
+    
+    node = CERT_LIST_HEAD(certList);
+    
+    while ( ! CERT_LIST_END(node, certList) ) {
+	cert = node->cert;
+	
+	subjectCert = CERT_DupCertificate(cert);
+
+	/* traverse the CA certs for this cert */
+	found = PR_FALSE;
+	while ( subjectCert != NULL ) {
+	    n = nCANames;
+	    names = caNames;
+	   
+            if (subjectCert->issuerName != NULL) { 
+	        while ( n > 0 ) {
+		    if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) {
+		        found = PR_TRUE;
+		        break;
+		    }
+
+		    n--;
+		    names++;
+                }
+	    }
+
+	    if ( found ) {
+		break;
+	    }
+	    
+	    issuerCert = CERT_FindCertIssuer(subjectCert, time, usage);
+	    if ( issuerCert == subjectCert ) {
+		CERT_DestroyCertificate(issuerCert);
+		issuerCert = NULL;
+		break;
+	    }
+	    CERT_DestroyCertificate(subjectCert);
+	    subjectCert = issuerCert;
+
+	}
+	CERT_DestroyCertificate(subjectCert);
+	if ( !found ) {
+	    /* CA was not found, so remove this cert from the list */
+	    freenode = node;
+	    node = CERT_LIST_NEXT(node);
+	    CERT_RemoveCertListNode(freenode);
+	} else {
+	    /* CA was found, so leave it in the list */
+	    node = CERT_LIST_NEXT(node);
+	}
+    }
+    
+    return(SECSuccess);
+}
+
+/*
+ * 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)
+{
+    SECCertTimeValidity validity;
+    char *nickname = NULL, *tmpstr = NULL;
+    
+    validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE);
+
+    /* if the cert is good, then just use the nickname directly */
+    if ( validity == secCertTimeValid ) {
+	if ( arena == NULL ) {
+	    nickname = PORT_Strdup(cert->nickname);
+	} else {
+	    nickname = PORT_ArenaStrdup(arena, cert->nickname);
+	}
+	
+	if ( nickname == NULL ) {
+	    goto loser;
+	}
+    } else {
+	    
+	/* if the cert is not valid, then tack one of the strings on the
+	 * end
+	 */
+	if ( validity == secCertTimeExpired ) {
+	    tmpstr = PR_smprintf("%s%s", cert->nickname,
+				 expiredString);
+	} else if ( validity == secCertTimeNotValidYet ) {
+	    /* not yet valid */
+	    tmpstr = PR_smprintf("%s%s", cert->nickname,
+				 notYetGoodString);
+        } else {
+            /* undetermined */
+	    tmpstr = PR_smprintf("%s",
+                        "(NULL) (Validity Unknown)");
+        }
+
+	if ( tmpstr == NULL ) {
+	    goto loser;
+	}
+
+	if ( arena ) {
+	    /* copy the string into the arena and free the malloc'd one */
+	    nickname = PORT_ArenaStrdup(arena, tmpstr);
+	    PORT_Free(tmpstr);
+	} else {
+	    nickname = tmpstr;
+	}
+	if ( nickname == NULL ) {
+	    goto loser;
+	}
+    }    
+    return(nickname);
+
+loser:
+    return(NULL);
+}
+
+/*
+ * 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)
+{
+    CERTCertNicknames *names;
+    PRArenaPool *arena;
+    CERTCertListNode *node;
+    char **nn;
+    
+    /* allocate an arena */
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if ( arena == NULL ) {
+	return(NULL);
+    }
+    
+    /* allocate the structure */
+    names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
+    if ( names == NULL ) {
+	goto loser;
+    }
+
+    /* init the structure */
+    names->arena = arena;
+    names->head = NULL;
+    names->numnicknames = 0;
+    names->nicknames = NULL;
+    names->totallen = 0;
+
+    /* count the certs in the list */
+    node = CERT_LIST_HEAD(certList);
+    while ( ! CERT_LIST_END(node, certList) ) {
+	names->numnicknames++;
+	node = CERT_LIST_NEXT(node);
+    }
+    
+    /* allocate nicknames array */
+    names->nicknames = PORT_ArenaAlloc(arena,
+				       sizeof(char *) * names->numnicknames);
+    if ( names->nicknames == NULL ) {
+	goto loser;
+    }
+
+    /* just in case printf can't deal with null strings */
+    if (expiredString == NULL ) {
+	expiredString = "";
+    }
+
+    if ( notYetGoodString == NULL ) {
+	notYetGoodString = "";
+    }
+    
+    /* traverse the list of certs and collect the nicknames */
+    nn = names->nicknames;
+    node = CERT_LIST_HEAD(certList);
+    while ( ! CERT_LIST_END(node, certList) ) {
+	*nn = CERT_GetCertNicknameWithValidity(arena, node->cert,
+					       expiredString,
+					       notYetGoodString);
+	if ( *nn == NULL ) {
+	    goto loser;
+	}
+
+	names->totallen += PORT_Strlen(*nn);
+	
+	nn++;
+	node = CERT_LIST_NEXT(node);
+    }
+
+    return(names);
+
+loser:
+    PORT_FreeArena(arena, PR_FALSE);
+    return(NULL);
+}
+
+/*
+ * 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)
+{
+    int explen, nyglen, namelen;
+    int retlen;
+    char *retstr;
+    
+    namelen = PORT_Strlen(namestring);
+    explen = PORT_Strlen(expiredString);
+    nyglen = PORT_Strlen(notYetGoodString);
+    
+    if ( namelen > explen ) {
+	if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) {
+	    retlen = namelen - explen;
+	    retstr = (char *)PORT_Alloc(retlen+1);
+	    if ( retstr == NULL ) {
+		goto loser;
+	    }
+	    
+	    PORT_Memcpy(retstr, namestring, retlen);
+	    retstr[retlen] = '\0';
+	    goto done;
+	}
+    }
+
+    if ( namelen > nyglen ) {
+	if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) {
+	    retlen = namelen - nyglen;
+	    retstr = (char *)PORT_Alloc(retlen+1);
+	    if ( retstr == NULL ) {
+		goto loser;
+	    }
+	    
+	    PORT_Memcpy(retstr, namestring, retlen);
+	    retstr[retlen] = '\0';
+	    goto done;
+	}
+    }
+
+    /* if name string is shorter than either invalid string, then it must
+     * be a raw nickname
+     */
+    retstr = PORT_Strdup(namestring);
+    
+done:
+    return(retstr);
+
+loser:
+    return(NULL);
+}
+
+CERTCertList *
+CERT_GetCertChainFromCert(CERTCertificate *cert, int64 time, SECCertUsage usage)
+{
+    CERTCertList *chain = NULL;
+    int count = 0;
+
+    if (NULL == cert) {
+        return NULL;
+    }
+    
+    cert = CERT_DupCertificate(cert);
+    if (NULL == cert) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return NULL;
+    }
+
+    chain = CERT_NewCertList();
+    if (NULL == chain) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return NULL;
+    }
+
+    while (cert != NULL && ++count <= CERT_MAX_CERT_CHAIN) {
+	if (SECSuccess != CERT_AddCertToListTail(chain, cert)) {
+            /* return partial chain */
+            PORT_SetError(SEC_ERROR_NO_MEMORY);
+            return chain;
+        }
+
+	if (cert->isRoot) {
+            /* return complete chain */
+	    return chain;
+	}
+
+	cert = CERT_FindCertIssuer(cert, time, usage);
+    }
+
+    /* return partial chain */
+    PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
+    return chain;
+}
diff --git a/mozilla/security/nss/lib/certhigh/crlv2.c b/mozilla/security/nss/lib/certhigh/crlv2.c
new file mode 100644
index 0000000..308215d
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/crlv2.c
@@ -0,0 +1,194 @@
+/* ***** 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 ***** */
+
+/*
+ * Code for dealing with x.509 v3 crl and crl entries extensions.
+ *
+ * $Id: crlv2.c,v 1.6 2007/10/12 01:44:41 julien.pierre.boogz%sun.com Exp $
+ */
+
+#include "cert.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "secoidt.h"
+#include "secder.h"
+#include "secasn1.h"
+#include "certxutl.h"
+
+SECStatus
+CERT_FindCRLExtensionByOID(CERTCrl *crl, SECItem *oid, SECItem *value)
+{
+    return (cert_FindExtensionByOID (crl->extensions, oid, value));
+}
+    
+
+SECStatus
+CERT_FindCRLExtension(CERTCrl *crl, int tag, SECItem *value)
+{
+    return (cert_FindExtension (crl->extensions, tag, value));
+}
+
+
+/* Callback to set extensions and adjust verison */
+static void
+SetCrlExts(void *object, CERTCertExtension **exts)
+{
+    CERTCrl *crl = (CERTCrl *)object;
+
+    crl->extensions = exts;
+    DER_SetUInteger (crl->arena, &crl->version, SEC_CRL_VERSION_2);
+}
+
+void *
+CERT_StartCRLExtensions(CERTCrl *crl)
+{
+    return (cert_StartExtensions ((void *)crl, crl->arena, SetCrlExts));
+}
+
+static void
+SetCrlEntryExts(void *object, CERTCertExtension **exts)
+{
+    CERTCrlEntry *crlEntry = (CERTCrlEntry *)object;
+
+    crlEntry->extensions = exts;
+}
+
+void *
+CERT_StartCRLEntryExtensions(CERTCrl *crl, CERTCrlEntry *entry)
+{
+    return (cert_StartExtensions (entry, crl->arena, SetCrlEntryExts));
+}
+
+SECStatus CERT_FindCRLNumberExten (PRArenaPool *arena, CERTCrl *crl,
+                                   SECItem *value)
+{
+    SECItem encodedExtenValue;
+    SECItem *tmpItem = NULL;
+    SECStatus rv;
+    void *mark = NULL;
+
+    encodedExtenValue.data = NULL;
+    encodedExtenValue.len = 0;
+
+    rv = cert_FindExtension(crl->extensions, SEC_OID_X509_CRL_NUMBER,
+			  &encodedExtenValue);
+    if ( rv != SECSuccess )
+	return (rv);
+
+    mark = PORT_ArenaMark(arena);
+
+    tmpItem = SECITEM_ArenaDupItem(arena, &encodedExtenValue);
+    if (tmpItem) {
+        rv = SEC_QuickDERDecodeItem (arena, value,
+                                     SEC_ASN1_GET(SEC_IntegerTemplate),
+                                     tmpItem);
+    } else {
+        rv = SECFailure;
+    }
+
+    PORT_Free (encodedExtenValue.data);
+    if (rv == SECFailure) {
+        PORT_ArenaRelease(arena, mark);
+    } else {
+        PORT_ArenaUnmark(arena, mark);
+    }
+    return (rv);
+}
+
+SECStatus CERT_FindCRLEntryReasonExten (CERTCrlEntry *crlEntry,
+                                        CERTCRLEntryReasonCode *value)
+{
+    SECItem wrapperItem = {siBuffer,0};
+    SECItem tmpItem = {siBuffer,0};
+    SECStatus rv;
+    PRArenaPool *arena = NULL;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);   
+    if ( ! arena ) {
+	return(SECFailure);
+    }
+    
+    rv = cert_FindExtension(crlEntry->extensions, SEC_OID_X509_REASON_CODE, 
+                            &wrapperItem);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+
+    rv = SEC_QuickDERDecodeItem(arena, &tmpItem,
+                                SEC_ASN1_GET(SEC_EnumeratedTemplate),
+                                &wrapperItem);
+
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+
+    *value = (CERTCRLEntryReasonCode) DER_GetInteger(&tmpItem);
+
+loser:
+    if ( arena ) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    
+    if ( wrapperItem.data ) {
+	PORT_Free(wrapperItem.data);
+    }
+
+    return (rv);
+}
+
+SECStatus CERT_FindInvalidDateExten (CERTCrl *crl, int64 *value)
+{
+    SECItem encodedExtenValue;
+    SECItem decodedExtenValue = {siBuffer,0};
+    SECStatus rv;
+
+    encodedExtenValue.data = decodedExtenValue.data = NULL;
+    encodedExtenValue.len = decodedExtenValue.len = 0;
+
+    rv = cert_FindExtension
+	 (crl->extensions, SEC_OID_X509_INVALID_DATE, &encodedExtenValue);
+    if ( rv != SECSuccess )
+	return (rv);
+
+    rv = SEC_ASN1DecodeItem (NULL, &decodedExtenValue,
+			     SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
+                             &encodedExtenValue);
+    if (rv == SECSuccess)
+	rv = DER_GeneralizedTimeToTime(value, &encodedExtenValue);
+    PORT_Free (decodedExtenValue.data);
+    PORT_Free (encodedExtenValue.data);
+    return (rv);
+}
diff --git a/mozilla/security/nss/lib/certhigh/ocsp.c b/mozilla/security/nss/lib/certhigh/ocsp.c
new file mode 100644
index 0000000..0ffdb34
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/ocsp.c
@@ -0,0 +1,5578 @@
+/* ***** 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):
+ *   Kai Engert (kengert@redhat.com)
+ *
+ * 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 ***** */
+
+/*
+ * Implementation of OCSP services, for both client and server.
+ * (XXX, really, mostly just for client right now, but intended to do both.)
+ *
+ * $Id: ocsp.c,v 1.61 2010/01/08 01:06:47 wtc%google.com Exp $
+ */
+
+#include "prerror.h"
+#include "prprf.h"
+#include "plarena.h"
+#include "prnetdb.h"
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "secoidt.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "cert.h"
+#include "xconst.h"
+#include "secerr.h"
+#include "secoid.h"
+#include "hasht.h"
+#include "sechash.h"
+#include "secasn1.h"
+#include "keyhi.h"
+#include "cryptohi.h"
+#include "ocsp.h"
+#include "ocspti.h"
+#include "ocspi.h"
+#include "genname.h"
+#include "certxutl.h"
+#include "pk11func.h"	/* for PK11_HashBuf */
+#include <stdarg.h>
+#include <plhash.h>
+
+#define DEFAULT_OCSP_CACHE_SIZE 1000
+#define DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 1*60*60L
+#define DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 24*60*60L
+#define DEFAULT_OSCP_TIMEOUT_SECONDS 60
+#define MICROSECONDS_PER_SECOND 1000000L
+
+typedef struct OCSPCacheItemStr OCSPCacheItem;
+typedef struct OCSPCacheDataStr OCSPCacheData;
+
+struct OCSPCacheItemStr {
+    /* LRU linking */
+    OCSPCacheItem *moreRecent;
+    OCSPCacheItem *lessRecent;
+
+    /* key */
+    CERTOCSPCertID *certID;
+    /* CertID's arena also used to allocate "this" cache item */
+
+    /* cache control information */
+    PRTime nextFetchAttemptTime;
+
+    /* Cached contents. Use a separate arena, because lifetime is different */
+    PRArenaPool *certStatusArena; /* NULL means: no cert status cached */
+    ocspCertStatus certStatus;
+
+    /* This may contain an error code when no OCSP response is available. */
+    SECErrorCodes missingResponseError;
+
+    PRPackedBool haveThisUpdate;
+    PRPackedBool haveNextUpdate;
+    PRTime thisUpdate;
+    PRTime nextUpdate;
+};
+
+struct OCSPCacheDataStr {
+    PLHashTable *entries;
+    PRUint32 numberOfEntries;
+    OCSPCacheItem *MRUitem; /* most recently used cache item */
+    OCSPCacheItem *LRUitem; /* least recently used cache item */
+};
+
+static struct OCSPGlobalStruct {
+    PRMonitor *monitor;
+    const SEC_HttpClientFcn *defaultHttpClientFcn;
+    PRInt32 maxCacheEntries;
+    PRUint32 minimumSecondsToNextFetchAttempt;
+    PRUint32 maximumSecondsToNextFetchAttempt;
+    PRUint32 timeoutSeconds;
+    OCSPCacheData cache;
+    SEC_OcspFailureMode ocspFailureMode;
+    CERT_StringFromCertFcn alternateOCSPAIAFcn;
+} OCSP_Global = { NULL, 
+                  NULL, 
+                  DEFAULT_OCSP_CACHE_SIZE, 
+                  DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
+                  DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
+                  DEFAULT_OSCP_TIMEOUT_SECONDS,
+                  {NULL, 0, NULL, NULL},
+                  ocspMode_FailureIsVerificationFailure,
+                  NULL
+                };
+
+
+
+/* Forward declarations */
+static SECItem *
+ocsp_GetEncodedOCSPResponseFromRequest(PRArenaPool *arena, 
+                                       CERTOCSPRequest *request,
+                                       char *location, int64 time,
+                                       PRBool addServiceLocator,
+                                       void *pwArg,
+                                       CERTOCSPRequest **pRequest);
+static SECStatus
+ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, 
+                              CERTOCSPCertID *certID, 
+                              CERTCertificate *cert, 
+                              int64 time, 
+                              void *pwArg,
+                              PRBool *certIDWasConsumed,
+                              SECStatus *rv_ocsp);
+static SECStatus
+ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, 
+                                        CERTOCSPResponse *response, 
+                                        CERTOCSPCertID   *certID,
+                                        CERTCertificate  *signerCert,
+                                        int64             time,
+                                        CERTOCSPSingleResponse **pSingleResponse);
+
+static SECStatus
+ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, int64 time);
+
+#ifndef DEBUG
+#define OCSP_TRACE(msg)
+#define OCSP_TRACE_TIME(msg, time)
+#define OCSP_TRACE_CERT(cert)
+#define OCSP_TRACE_CERTID(certid)
+#else
+#define OCSP_TRACE(msg) ocsp_Trace msg
+#define OCSP_TRACE_TIME(msg, time) ocsp_dumpStringWithTime(msg, time)
+#define OCSP_TRACE_CERT(cert) dumpCertificate(cert)
+#define OCSP_TRACE_CERTID(certid) dumpCertID(certid)
+
+#if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS) \
+     || defined(XP_MACOSX)) && !defined(_WIN32_WCE)
+#define NSS_HAVE_GETENV 1
+#endif
+
+static PRBool wantOcspTrace()
+{
+    static PRBool firstTime = PR_TRUE;
+    static PRBool wantTrace = PR_FALSE;
+
+#ifdef NSS_HAVE_GETENV
+    if (firstTime) {
+        char *ev = getenv("NSS_TRACE_OCSP");
+        if (ev && ev[0]) {
+            wantTrace = PR_TRUE;
+        }
+        firstTime = PR_FALSE;
+    }
+#endif
+    return wantTrace;
+}
+
+static void
+ocsp_Trace(const char *format, ...)
+{
+    char buf[2000];
+    va_list args;
+  
+    if (!wantOcspTrace())
+        return;
+    va_start(args, format);
+    PR_vsnprintf(buf, sizeof(buf), format, args);
+    va_end(args);
+    PR_LogPrint("%s", buf);
+}
+
+static void
+ocsp_dumpStringWithTime(const char *str, int64 time)
+{
+    PRExplodedTime timePrintable;
+    char timestr[256];
+
+    if (!wantOcspTrace())
+        return;
+    PR_ExplodeTime(time, PR_GMTParameters, &timePrintable);
+    if (PR_FormatTime(timestr, 256, "%a %b %d %H:%M:%S %Y", &timePrintable)) {
+        ocsp_Trace("OCSP %s %s\n", str, timestr);
+    }
+}
+
+static void
+printHexString(const char *prefix, SECItem *hexval)
+{
+    unsigned int i;
+    char *hexbuf = NULL;
+
+    for (i = 0; i < hexval->len; i++) {
+        if (i != hexval->len - 1) {
+            hexbuf = PR_sprintf_append(hexbuf, "%02x:", hexval->data[i]);
+        } else {
+            hexbuf = PR_sprintf_append(hexbuf, "%02x", hexval->data[i]);
+        }
+    }
+    if (hexbuf) {
+        ocsp_Trace("%s %s\n", prefix, hexbuf);
+        PR_smprintf_free(hexbuf);
+    }
+}
+
+static void
+dumpCertificate(CERTCertificate *cert)
+{
+    if (!wantOcspTrace())
+        return;
+
+    ocsp_Trace("OCSP ----------------\n");
+    ocsp_Trace("OCSP ## SUBJECT:  %s\n", cert->subjectName);
+    {
+        int64 timeBefore, timeAfter;
+        PRExplodedTime beforePrintable, afterPrintable;
+        char beforestr[256], afterstr[256];
+        PRStatus rv1, rv2;
+        DER_DecodeTimeChoice(&timeBefore, &cert->validity.notBefore);
+        DER_DecodeTimeChoice(&timeAfter, &cert->validity.notAfter);
+        PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable);
+        PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable);
+        rv1 = PR_FormatTime(beforestr, 256, "%a %b %d %H:%M:%S %Y", 
+                      &beforePrintable);
+        rv2 = PR_FormatTime(afterstr, 256, "%a %b %d %H:%M:%S %Y", 
+                      &afterPrintable);
+        ocsp_Trace("OCSP ## VALIDITY:  %s to %s\n", rv1 ? beforestr : "",
+                   rv2 ? afterstr : "");
+    }
+    ocsp_Trace("OCSP ## ISSUER:  %s\n", cert->issuerName);
+    printHexString("OCSP ## SERIAL NUMBER:", &cert->serialNumber);
+}
+
+static void
+dumpCertID(CERTOCSPCertID *certID)
+{
+    if (!wantOcspTrace())
+        return;
+
+    printHexString("OCSP certID issuer", &certID->issuerNameHash);
+    printHexString("OCSP certID serial", &certID->serialNumber);
+}
+#endif
+
+SECStatus
+SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable)
+{
+    if (!OCSP_Global.monitor) {
+      PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+      return SECFailure;
+    }
+    
+    PR_EnterMonitor(OCSP_Global.monitor);
+    OCSP_Global.defaultHttpClientFcn = fcnTable;
+    PR_ExitMonitor(OCSP_Global.monitor);
+    
+    return SECSuccess;
+}
+
+SECStatus
+CERT_RegisterAlternateOCSPAIAInfoCallBack(
+			CERT_StringFromCertFcn   newCallback,
+			CERT_StringFromCertFcn * oldCallback)
+{
+    CERT_StringFromCertFcn old;
+
+    if (!OCSP_Global.monitor) {
+      PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+      return SECFailure;
+    }
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    old = OCSP_Global.alternateOCSPAIAFcn;
+    OCSP_Global.alternateOCSPAIAFcn = newCallback;
+    PR_ExitMonitor(OCSP_Global.monitor);
+    if (oldCallback)
+    	*oldCallback = old;
+    return SECSuccess;
+}
+
+static PLHashNumber PR_CALLBACK
+ocsp_CacheKeyHashFunction(const void *key)
+{
+    CERTOCSPCertID *cid = (CERTOCSPCertID *)key;
+    PLHashNumber hash = 0;
+    unsigned int i;
+    unsigned char *walk;
+  
+    /* a very simple hash calculation for the initial coding phase */
+    walk = (unsigned char*)cid->issuerNameHash.data;
+    for (i=0; i < cid->issuerNameHash.len; ++i, ++walk) {
+        hash += *walk;
+    }
+    walk = (unsigned char*)cid->issuerKeyHash.data;
+    for (i=0; i < cid->issuerKeyHash.len; ++i, ++walk) {
+        hash += *walk;
+    }
+    walk = (unsigned char*)cid->serialNumber.data;
+    for (i=0; i < cid->serialNumber.len; ++i, ++walk) {
+        hash += *walk;
+    }
+    return hash;
+}
+
+static PRIntn PR_CALLBACK
+ocsp_CacheKeyCompareFunction(const void *v1, const void *v2)
+{
+    CERTOCSPCertID *cid1 = (CERTOCSPCertID *)v1;
+    CERTOCSPCertID *cid2 = (CERTOCSPCertID *)v2;
+  
+    return (SECEqual == SECITEM_CompareItem(&cid1->issuerNameHash, 
+                                            &cid2->issuerNameHash)
+            && SECEqual == SECITEM_CompareItem(&cid1->issuerKeyHash, 
+                                               &cid2->issuerKeyHash)
+            && SECEqual == SECITEM_CompareItem(&cid1->serialNumber, 
+                                               &cid2->serialNumber));
+}
+
+static SECStatus
+ocsp_CopyRevokedInfo(PRArenaPool *arena, ocspCertStatus *dest, 
+                     ocspRevokedInfo *src)
+{
+    SECStatus rv = SECFailure;
+    void *mark;
+  
+    mark = PORT_ArenaMark(arena);
+  
+    dest->certStatusInfo.revokedInfo = 
+        (ocspRevokedInfo *) PORT_ArenaZAlloc(arena, sizeof(ocspRevokedInfo));
+    if (!dest->certStatusInfo.revokedInfo) {
+        goto loser;
+    }
+  
+    rv = SECITEM_CopyItem(arena, 
+                          &dest->certStatusInfo.revokedInfo->revocationTime, 
+                          &src->revocationTime);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+  
+    if (src->revocationReason) {
+        dest->certStatusInfo.revokedInfo->revocationReason = 
+            SECITEM_ArenaDupItem(arena, src->revocationReason);
+        if (!dest->certStatusInfo.revokedInfo->revocationReason) {
+            goto loser;
+        }
+    }  else {
+        dest->certStatusInfo.revokedInfo->revocationReason = NULL;
+    }
+  
+    PORT_ArenaUnmark(arena, mark);
+    return SECSuccess;
+
+loser:
+    PORT_ArenaRelease(arena, mark);
+    return SECFailure;
+}
+
+static SECStatus
+ocsp_CopyCertStatus(PRArenaPool *arena, ocspCertStatus *dest, 
+                    ocspCertStatus*src)
+{
+    SECStatus rv = SECFailure;
+    dest->certStatusType = src->certStatusType;
+  
+    switch (src->certStatusType) {
+    case ocspCertStatus_good:
+        dest->certStatusInfo.goodInfo = 
+            SECITEM_ArenaDupItem(arena, src->certStatusInfo.goodInfo);
+        if (dest->certStatusInfo.goodInfo != NULL) {
+            rv = SECSuccess;
+        }
+        break;
+    case ocspCertStatus_revoked:
+        rv = ocsp_CopyRevokedInfo(arena, dest, 
+                                  src->certStatusInfo.revokedInfo);
+        break;
+    case ocspCertStatus_unknown:
+        dest->certStatusInfo.unknownInfo = 
+            SECITEM_ArenaDupItem(arena, src->certStatusInfo.unknownInfo);
+        if (dest->certStatusInfo.unknownInfo != NULL) {
+            rv = SECSuccess;
+        }
+        break;
+    case ocspCertStatus_other:
+    default:
+        PORT_Assert(src->certStatusType == ocspCertStatus_other);
+        dest->certStatusInfo.otherInfo = 
+            SECITEM_ArenaDupItem(arena, src->certStatusInfo.otherInfo);
+        if (dest->certStatusInfo.otherInfo != NULL) {
+            rv = SECSuccess;
+        }
+        break;
+    }
+    return rv;
+}
+
+static void
+ocsp_AddCacheItemToLinkedList(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
+{
+    PR_EnterMonitor(OCSP_Global.monitor);
+
+    if (!cache->LRUitem) {
+        cache->LRUitem = new_most_recent;
+    }
+    new_most_recent->lessRecent = cache->MRUitem;
+    new_most_recent->moreRecent = NULL;
+
+    if (cache->MRUitem) {
+        cache->MRUitem->moreRecent = new_most_recent;
+    }
+    cache->MRUitem = new_most_recent;
+
+    PR_ExitMonitor(OCSP_Global.monitor);
+}
+
+static void
+ocsp_RemoveCacheItemFromLinkedList(OCSPCacheData *cache, OCSPCacheItem *item)
+{
+    PR_EnterMonitor(OCSP_Global.monitor);
+
+    if (!item->lessRecent && !item->moreRecent) {
+        /*
+         * Fail gracefully on attempts to remove an item from the list,
+         * which is currently not part of the list.
+         * But check for the edge case it is the single entry in the list.
+         */
+        if (item == cache->LRUitem &&
+            item == cache->MRUitem) {
+            /* remove the single entry */
+            PORT_Assert(cache->numberOfEntries == 1);
+            PORT_Assert(item->moreRecent == NULL);
+            cache->MRUitem = NULL;
+            cache->LRUitem = NULL;
+        }
+        PR_ExitMonitor(OCSP_Global.monitor);
+        return;
+    }
+
+    PORT_Assert(cache->numberOfEntries > 1);
+  
+    if (item == cache->LRUitem) {
+        PORT_Assert(item != cache->MRUitem);
+        PORT_Assert(item->lessRecent == NULL);
+        PORT_Assert(item->moreRecent != NULL);
+        PORT_Assert(item->moreRecent->lessRecent == item);
+        cache->LRUitem = item->moreRecent;
+        cache->LRUitem->lessRecent = NULL;
+    }
+    else if (item == cache->MRUitem) {
+        PORT_Assert(item->moreRecent == NULL);
+        PORT_Assert(item->lessRecent != NULL);
+        PORT_Assert(item->lessRecent->moreRecent == item);
+        cache->MRUitem = item->lessRecent;
+        cache->MRUitem->moreRecent = NULL;
+    } else {
+        /* remove an entry in the middle of the list */
+        PORT_Assert(item->moreRecent != NULL);
+        PORT_Assert(item->lessRecent != NULL);
+        PORT_Assert(item->lessRecent->moreRecent == item);
+        PORT_Assert(item->moreRecent->lessRecent == item);
+        item->moreRecent->lessRecent = item->lessRecent;
+        item->lessRecent->moreRecent = item->moreRecent;
+    }
+
+    item->lessRecent = NULL;
+    item->moreRecent = NULL;
+
+    PR_ExitMonitor(OCSP_Global.monitor);
+}
+
+static void
+ocsp_MakeCacheEntryMostRecent(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
+{
+    OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent THREADID %p\n", 
+                PR_GetCurrentThread()));
+    PR_EnterMonitor(OCSP_Global.monitor);
+    if (cache->MRUitem == new_most_recent) {
+        OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent ALREADY MOST\n"));
+        PR_ExitMonitor(OCSP_Global.monitor);
+        return;
+    }
+    OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent NEW entry\n"));
+    ocsp_RemoveCacheItemFromLinkedList(cache, new_most_recent);
+    ocsp_AddCacheItemToLinkedList(cache, new_most_recent);
+    PR_ExitMonitor(OCSP_Global.monitor);
+}
+
+static PRBool
+ocsp_IsCacheDisabled()
+{
+    /* 
+     * maxCacheEntries == 0 means unlimited cache entries
+     * maxCacheEntries  < 0 means cache is disabled
+     */
+    PRBool retval;
+    PR_EnterMonitor(OCSP_Global.monitor);
+    retval = (OCSP_Global.maxCacheEntries < 0);
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return retval;
+}
+
+static OCSPCacheItem *
+ocsp_FindCacheEntry(OCSPCacheData *cache, CERTOCSPCertID *certID)
+{
+    OCSPCacheItem *found_ocsp_item = NULL;
+    OCSP_TRACE(("OCSP ocsp_FindCacheEntry\n"));
+    OCSP_TRACE_CERTID(certID);
+    PR_EnterMonitor(OCSP_Global.monitor);
+    if (ocsp_IsCacheDisabled())
+        goto loser;
+  
+    found_ocsp_item = (OCSPCacheItem *)PL_HashTableLookup(
+                          cache->entries, certID);
+    if (!found_ocsp_item)
+        goto loser;
+  
+    OCSP_TRACE(("OCSP ocsp_FindCacheEntry FOUND!\n"));
+    ocsp_MakeCacheEntryMostRecent(cache, found_ocsp_item);
+
+loser:
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return found_ocsp_item;
+}
+
+static void
+ocsp_FreeCacheItem(OCSPCacheItem *item)
+{
+    OCSP_TRACE(("OCSP ocsp_FreeCacheItem\n"));
+    if (item->certStatusArena) {
+        PORT_FreeArena(item->certStatusArena, PR_FALSE);
+    }
+    if (item->certID->poolp) {
+        /* freeing this poolp arena will also free item */
+        PORT_FreeArena(item->certID->poolp, PR_FALSE);
+    }
+}
+
+static void
+ocsp_RemoveCacheItem(OCSPCacheData *cache, OCSPCacheItem *item)
+{
+    /* The item we're removing could be either the least recently used item,
+     * or it could be an item that couldn't get updated with newer status info
+     * because of an allocation failure, or it could get removed because we're 
+     * cleaning up.
+     */
+    PRBool couldRemoveFromHashTable;
+    OCSP_TRACE(("OCSP ocsp_RemoveCacheItem, THREADID %p\n", PR_GetCurrentThread()));
+    PR_EnterMonitor(OCSP_Global.monitor);
+
+    ocsp_RemoveCacheItemFromLinkedList(cache, item);
+    couldRemoveFromHashTable = PL_HashTableRemove(cache->entries, 
+                                                  item->certID);
+    PORT_Assert(couldRemoveFromHashTable);
+    --cache->numberOfEntries;
+    ocsp_FreeCacheItem(item);
+    PR_ExitMonitor(OCSP_Global.monitor);
+}
+
+static void
+ocsp_CheckCacheSize(OCSPCacheData *cache)
+{
+    OCSP_TRACE(("OCSP ocsp_CheckCacheSize\n"));
+    PR_EnterMonitor(OCSP_Global.monitor);
+    if (OCSP_Global.maxCacheEntries <= 0) /* disabled or unlimited */
+        return;
+    while (cache->numberOfEntries > OCSP_Global.maxCacheEntries) {
+        ocsp_RemoveCacheItem(cache, cache->LRUitem);
+    }
+    PR_ExitMonitor(OCSP_Global.monitor);
+}
+
+SECStatus
+CERT_ClearOCSPCache()
+{
+    OCSP_TRACE(("OCSP CERT_ClearOCSPCache\n"));
+    PR_EnterMonitor(OCSP_Global.monitor);
+    while (OCSP_Global.cache.numberOfEntries > 0) {
+        ocsp_RemoveCacheItem(&OCSP_Global.cache, 
+                             OCSP_Global.cache.LRUitem);
+    }
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return SECSuccess;
+}
+
+static SECStatus
+ocsp_CreateCacheItemAndConsumeCertID(OCSPCacheData *cache,
+                                     CERTOCSPCertID *certID, 
+                                     OCSPCacheItem **pCacheItem)
+{
+    PRArenaPool *arena;
+    void *mark;
+    PLHashEntry *new_hash_entry;
+    OCSPCacheItem *item;
+  
+    PORT_Assert(pCacheItem != NULL);
+    *pCacheItem = NULL;
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    arena = certID->poolp;
+    mark = PORT_ArenaMark(arena);
+  
+    /* ZAlloc will init all Bools to False and all Pointers to NULL
+       and all error codes to zero/good. */
+    item = (OCSPCacheItem *)PORT_ArenaZAlloc(certID->poolp, 
+                                             sizeof(OCSPCacheItem));
+    if (!item) {
+        goto loser; 
+    }
+    item->certID = certID;
+    new_hash_entry = PL_HashTableAdd(cache->entries, item->certID, 
+                                     item);
+    if (!new_hash_entry) {
+        goto loser;
+    }
+    ++cache->numberOfEntries;
+    PORT_ArenaUnmark(arena, mark);
+    ocsp_AddCacheItemToLinkedList(cache, item);
+    *pCacheItem = item;
+
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return SECSuccess;
+  
+loser:
+    PORT_ArenaRelease(arena, mark);
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return SECFailure;
+}
+
+static SECStatus
+ocsp_SetCacheItemResponse(OCSPCacheItem *item,
+                          const CERTOCSPSingleResponse *response)
+{
+    if (item->certStatusArena) {
+        PORT_FreeArena(item->certStatusArena, PR_FALSE);
+        item->certStatusArena = NULL;
+    }
+    item->haveThisUpdate = item->haveNextUpdate = PR_FALSE;
+    if (response) {
+        SECStatus rv;
+        item->certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+        if (item->certStatusArena == NULL) {
+            return SECFailure;
+        }
+        rv = ocsp_CopyCertStatus(item->certStatusArena, &item->certStatus, 
+                                 response->certStatus);
+        if (rv != SECSuccess) {
+            PORT_FreeArena(item->certStatusArena, PR_FALSE);
+            item->certStatusArena = NULL;
+            return rv;
+        }
+        item->missingResponseError = 0;
+        rv = DER_GeneralizedTimeToTime(&item->thisUpdate, 
+                                       &response->thisUpdate);
+        item->haveThisUpdate = (rv == SECSuccess);
+        if (response->nextUpdate) {
+            rv = DER_GeneralizedTimeToTime(&item->nextUpdate, 
+                                           response->nextUpdate);
+            item->haveNextUpdate = (rv == SECSuccess);
+        } else {
+            item->haveNextUpdate = PR_FALSE;
+        }
+    }
+    return SECSuccess;
+}
+
+static void
+ocsp_FreshenCacheItemNextFetchAttemptTime(OCSPCacheItem *cacheItem)
+{
+    PRTime now;
+    PRTime earliestAllowedNextFetchAttemptTime;
+    PRTime latestTimeWhenResponseIsConsideredFresh;
+  
+    OCSP_TRACE(("OCSP ocsp_FreshenCacheItemNextFetchAttemptTime\n"));
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+  
+    now = PR_Now();
+    OCSP_TRACE_TIME("now:", now);
+  
+    if (cacheItem->haveThisUpdate) {
+        OCSP_TRACE_TIME("thisUpdate:", cacheItem->thisUpdate);
+        latestTimeWhenResponseIsConsideredFresh = cacheItem->thisUpdate +
+            OCSP_Global.maximumSecondsToNextFetchAttempt * 
+                MICROSECONDS_PER_SECOND;
+        OCSP_TRACE_TIME("latestTimeWhenResponseIsConsideredFresh:", 
+                        latestTimeWhenResponseIsConsideredFresh);
+    } else {
+        latestTimeWhenResponseIsConsideredFresh = now +
+            OCSP_Global.minimumSecondsToNextFetchAttempt *
+                MICROSECONDS_PER_SECOND;
+        OCSP_TRACE_TIME("no thisUpdate, "
+                        "latestTimeWhenResponseIsConsideredFresh:", 
+                        latestTimeWhenResponseIsConsideredFresh);
+    }
+  
+    if (cacheItem->haveNextUpdate) {
+        OCSP_TRACE_TIME("have nextUpdate:", cacheItem->nextUpdate);
+    }
+  
+    if (cacheItem->haveNextUpdate &&
+        cacheItem->nextUpdate < latestTimeWhenResponseIsConsideredFresh) {
+        latestTimeWhenResponseIsConsideredFresh = cacheItem->nextUpdate;
+        OCSP_TRACE_TIME("nextUpdate is smaller than latestFresh, setting "
+                        "latestTimeWhenResponseIsConsideredFresh:", 
+                        latestTimeWhenResponseIsConsideredFresh);
+    }
+  
+    earliestAllowedNextFetchAttemptTime = now +
+        OCSP_Global.minimumSecondsToNextFetchAttempt * 
+            MICROSECONDS_PER_SECOND;
+    OCSP_TRACE_TIME("earliestAllowedNextFetchAttemptTime:", 
+                    earliestAllowedNextFetchAttemptTime);
+  
+    if (latestTimeWhenResponseIsConsideredFresh < 
+        earliestAllowedNextFetchAttemptTime) {
+        latestTimeWhenResponseIsConsideredFresh = 
+            earliestAllowedNextFetchAttemptTime;
+        OCSP_TRACE_TIME("latest < earliest, setting latest to:", 
+                        latestTimeWhenResponseIsConsideredFresh);
+    }
+  
+    cacheItem->nextFetchAttemptTime = 
+        latestTimeWhenResponseIsConsideredFresh;
+    OCSP_TRACE_TIME("nextFetchAttemptTime", 
+        latestTimeWhenResponseIsConsideredFresh);
+
+    PR_ExitMonitor(OCSP_Global.monitor);
+}
+
+static PRBool
+ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem)
+{
+    PRTime now;
+    PRBool retval;
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    now = PR_Now();
+    retval = (cacheItem->nextFetchAttemptTime > now);
+    OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", retval));
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return retval;
+}
+
+/*
+ * Status in *certIDWasConsumed will always be correct, regardless of 
+ * return value.
+ */
+static SECStatus
+ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache, 
+                              CERTOCSPCertID *certID,
+                              CERTOCSPSingleResponse *single,
+                              PRBool *certIDWasConsumed)
+{
+    SECStatus rv;
+    OCSPCacheItem *cacheItem;
+    OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n"));
+  
+    if (!certIDWasConsumed) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    *certIDWasConsumed = PR_FALSE;
+  
+    PR_EnterMonitor(OCSP_Global.monitor);
+    PORT_Assert(OCSP_Global.maxCacheEntries >= 0);
+  
+    cacheItem = ocsp_FindCacheEntry(cache, certID);
+    if (!cacheItem) {
+        rv = ocsp_CreateCacheItemAndConsumeCertID(cache, certID, 
+                                                  &cacheItem);
+        if (rv != SECSuccess) {
+            PR_ExitMonitor(OCSP_Global.monitor);
+            return rv;
+        }
+        *certIDWasConsumed = PR_TRUE;
+    }
+    if (single) {
+        rv = ocsp_SetCacheItemResponse(cacheItem, single);
+        if (rv != SECSuccess) {
+            ocsp_RemoveCacheItem(cache, cacheItem);
+            PR_ExitMonitor(OCSP_Global.monitor);
+            return rv;
+        }
+    } else {
+        cacheItem->missingResponseError = PORT_GetError();
+    }
+    ocsp_FreshenCacheItemNextFetchAttemptTime(cacheItem);
+    ocsp_CheckCacheSize(cache);
+
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return SECSuccess;
+}
+
+extern SECStatus
+CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode)
+{
+    switch (ocspFailureMode) {
+    case ocspMode_FailureIsVerificationFailure:
+    case ocspMode_FailureIsNotAVerificationFailure:
+        break;
+    default:
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    OCSP_Global.ocspFailureMode = ocspFailureMode;
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return SECSuccess;
+}
+
+SECStatus
+CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,
+                       PRUint32 minimumSecondsToNextFetchAttempt,
+                       PRUint32 maximumSecondsToNextFetchAttempt)
+{
+    if (minimumSecondsToNextFetchAttempt > maximumSecondsToNextFetchAttempt
+        || maxCacheEntries < -1) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+  
+    PR_EnterMonitor(OCSP_Global.monitor);
+  
+    if (maxCacheEntries < 0) {
+        OCSP_Global.maxCacheEntries = -1; /* disable cache */
+    } else if (maxCacheEntries == 0) {
+        OCSP_Global.maxCacheEntries = 0; /* unlimited cache entries */
+    } else {
+        OCSP_Global.maxCacheEntries = maxCacheEntries;
+    }
+  
+    if (minimumSecondsToNextFetchAttempt < 
+            OCSP_Global.minimumSecondsToNextFetchAttempt
+        || maximumSecondsToNextFetchAttempt < 
+            OCSP_Global.maximumSecondsToNextFetchAttempt) {
+        /*
+         * Ensure our existing cache entries are not used longer than the 
+         * new settings allow, we're lazy and just clear the cache
+         */
+        CERT_ClearOCSPCache();
+    }
+  
+    OCSP_Global.minimumSecondsToNextFetchAttempt = 
+        minimumSecondsToNextFetchAttempt;
+    OCSP_Global.maximumSecondsToNextFetchAttempt = 
+        maximumSecondsToNextFetchAttempt;
+    ocsp_CheckCacheSize(&OCSP_Global.cache);
+  
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return SECSuccess;
+}
+
+SECStatus
+CERT_SetOCSPTimeout(PRUint32 seconds)
+{
+    /* no locking, see bug 406120 */
+    OCSP_Global.timeoutSeconds = seconds;
+    return SECSuccess;
+}
+
+/* this function is called at NSS initialization time */
+SECStatus OCSP_InitGlobal(void)
+{
+    SECStatus rv = SECFailure;
+
+    if (OCSP_Global.monitor == NULL) {
+        OCSP_Global.monitor = PR_NewMonitor();
+    }
+    if (!OCSP_Global.monitor)
+        return SECFailure;
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    if (!OCSP_Global.cache.entries) {
+        OCSP_Global.cache.entries = 
+            PL_NewHashTable(0, 
+                            ocsp_CacheKeyHashFunction, 
+                            ocsp_CacheKeyCompareFunction, 
+                            PL_CompareValues, 
+                            NULL, 
+                            NULL);
+        OCSP_Global.ocspFailureMode = ocspMode_FailureIsVerificationFailure;
+        OCSP_Global.cache.numberOfEntries = 0;
+        OCSP_Global.cache.MRUitem = NULL;
+        OCSP_Global.cache.LRUitem = NULL;
+    } else {
+        /*
+         * NSS might call this function twice while attempting to init.
+         * But it's not allowed to call this again after any activity.
+         */
+        PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+    }
+    if (OCSP_Global.cache.entries)
+        rv = SECSuccess;
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return rv;
+}
+
+SECStatus OCSP_ShutdownGlobal(void)
+{
+    if (!OCSP_Global.monitor)
+        return SECSuccess;
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    if (OCSP_Global.cache.entries) {
+        CERT_ClearOCSPCache();
+        PL_HashTableDestroy(OCSP_Global.cache.entries);
+        OCSP_Global.cache.entries = NULL;
+    }
+    PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
+    OCSP_Global.cache.MRUitem = NULL;
+    OCSP_Global.cache.LRUitem = NULL;
+
+    OCSP_Global.defaultHttpClientFcn = NULL;
+    OCSP_Global.maxCacheEntries = DEFAULT_OCSP_CACHE_SIZE;
+    OCSP_Global.minimumSecondsToNextFetchAttempt = 
+      DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
+    OCSP_Global.maximumSecondsToNextFetchAttempt =
+      DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
+    OCSP_Global.ocspFailureMode =
+      ocspMode_FailureIsVerificationFailure;
+    PR_ExitMonitor(OCSP_Global.monitor);
+
+    PR_DestroyMonitor(OCSP_Global.monitor);
+    OCSP_Global.monitor = NULL;
+    return SECSuccess;
+}
+
+/*
+ * A return value of NULL means: 
+ *   The application did not register it's own HTTP client.
+ */
+const SEC_HttpClientFcn *SEC_GetRegisteredHttpClient()
+{
+    const SEC_HttpClientFcn *retval;
+
+    if (!OCSP_Global.monitor) {
+      PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+      return NULL;
+    }
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    retval = OCSP_Global.defaultHttpClientFcn;
+    PR_ExitMonitor(OCSP_Global.monitor);
+    
+    return retval;
+}
+
+/*
+ * The following structure is only used internally.  It is allocated when
+ * someone turns on OCSP checking, and hangs off of the status-configuration
+ * structure in the certdb structure.  We use it to keep configuration
+ * information specific to OCSP checking.
+ */
+typedef struct ocspCheckingContextStr {
+    PRBool useDefaultResponder;
+    char *defaultResponderURI;
+    char *defaultResponderNickname;
+    CERTCertificate *defaultResponderCert;
+} ocspCheckingContext;
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_IntegerTemplate)
+SEC_ASN1_MKSUB(SEC_NullTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+SEC_ASN1_MKSUB(SEC_PointerToAnyTemplate)
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(SEC_SequenceOfAnyTemplate)
+SEC_ASN1_MKSUB(SEC_PointerToGeneralizedTimeTemplate)
+SEC_ASN1_MKSUB(SEC_PointerToEnumeratedTemplate)
+
+/*
+ * Forward declarations of sub-types, so I can lay out the types in the
+ * same order as the ASN.1 is laid out in the OCSP spec itself.
+ *
+ * These are in alphabetical order (case-insensitive); please keep it that way!
+ */
+extern const SEC_ASN1Template ocsp_CertIDTemplate[];
+extern const SEC_ASN1Template ocsp_PointerToSignatureTemplate[];
+extern const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[];
+extern const SEC_ASN1Template ocsp_ResponseDataTemplate[];
+extern const SEC_ASN1Template ocsp_RevokedInfoTemplate[];
+extern const SEC_ASN1Template ocsp_SingleRequestTemplate[];
+extern const SEC_ASN1Template ocsp_SingleResponseTemplate[];
+extern const SEC_ASN1Template ocsp_TBSRequestTemplate[];
+
+
+/*
+ * Request-related templates...
+ */
+
+/*
+ * OCSPRequest	::=	SEQUENCE {
+ *	tbsRequest		TBSRequest,
+ *	optionalSignature	[0] EXPLICIT Signature OPTIONAL }
+ */
+static const SEC_ASN1Template ocsp_OCSPRequestTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(CERTOCSPRequest) },
+    { SEC_ASN1_POINTER,
+	offsetof(CERTOCSPRequest, tbsRequest),
+	ocsp_TBSRequestTemplate },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+	offsetof(CERTOCSPRequest, optionalSignature),
+	ocsp_PointerToSignatureTemplate },
+    { 0 }
+};
+
+/*
+ * TBSRequest	::=	SEQUENCE {
+ *	version			[0] EXPLICIT Version DEFAULT v1,
+ *	requestorName		[1] EXPLICIT GeneralName OPTIONAL,
+ *	requestList		SEQUENCE OF Request,
+ *	requestExtensions	[2] EXPLICIT Extensions OPTIONAL }
+ *
+ * Version	::=	INTEGER { v1(0) }
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_TBSRequestTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(ocspTBSRequest) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |		/* XXX DER_DEFAULT */
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	offsetof(ocspTBSRequest, version),
+	SEC_ASN1_SUB(SEC_IntegerTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
+	offsetof(ocspTBSRequest, derRequestorName),
+	SEC_ASN1_SUB(SEC_PointerToAnyTemplate) },
+    { SEC_ASN1_SEQUENCE_OF,
+	offsetof(ocspTBSRequest, requestList),
+	ocsp_SingleRequestTemplate },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
+	offsetof(ocspTBSRequest, requestExtensions),
+	CERT_SequenceOfCertExtensionTemplate },
+    { 0 }
+};
+
+/*
+ * Signature	::=	SEQUENCE {
+ *	signatureAlgorithm	AlgorithmIdentifier,
+ *	signature		BIT STRING,
+ *	certs			[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+static const SEC_ASN1Template ocsp_SignatureTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(ocspSignature) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	offsetof(ocspSignature, signatureAlgorithm),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_BIT_STRING,
+	offsetof(ocspSignature, signature) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	offsetof(ocspSignature, derCerts), 
+	SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
+    { 0 }
+};
+
+/*
+ * This template is just an extra level to use in an explicitly-tagged
+ * reference to a Signature.
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_PointerToSignatureTemplate[] = {
+    { SEC_ASN1_POINTER, 0, ocsp_SignatureTemplate }
+};
+
+/*
+ * Request	::=	SEQUENCE {
+ *	reqCert			CertID,
+ *	singleRequestExtensions	[0] EXPLICIT Extensions OPTIONAL }
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_SingleRequestTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 
+	0, NULL, sizeof(ocspSingleRequest) },
+    { SEC_ASN1_POINTER,
+	offsetof(ocspSingleRequest, reqCert),
+	ocsp_CertIDTemplate },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+	offsetof(ocspSingleRequest, singleRequestExtensions),
+	CERT_SequenceOfCertExtensionTemplate },
+    { 0 }
+};
+
+
+/*
+ * This data structure and template (CertID) is used by both OCSP
+ * requests and responses.  It is the only one that is shared.
+ *
+ * CertID	::=	SEQUENCE {
+ *	hashAlgorithm		AlgorithmIdentifier,
+ *	issuerNameHash		OCTET STRING,	-- Hash of Issuer DN
+ *	issuerKeyHash		OCTET STRING,	-- Hash of Issuer public key
+ *	serialNumber		CertificateSerialNumber }
+ *
+ * CertificateSerialNumber ::=	INTEGER
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_CertIDTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 
+	0, NULL, sizeof(CERTOCSPCertID) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	offsetof(CERTOCSPCertID, hashAlgorithm),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OCTET_STRING,
+	offsetof(CERTOCSPCertID, issuerNameHash) },
+    { SEC_ASN1_OCTET_STRING,
+	offsetof(CERTOCSPCertID, issuerKeyHash) },
+    { SEC_ASN1_INTEGER, 
+	offsetof(CERTOCSPCertID, serialNumber) },
+    { 0 }
+};
+
+
+/*
+ * Response-related templates...
+ */
+
+/*
+ * OCSPResponse	::=	SEQUENCE {
+ *	responseStatus		OCSPResponseStatus,
+ *	responseBytes		[0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+static const SEC_ASN1Template ocsp_OCSPResponseTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 
+	0, NULL, sizeof(CERTOCSPResponse) },
+    { SEC_ASN1_ENUMERATED, 
+	offsetof(CERTOCSPResponse, responseStatus) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+	offsetof(CERTOCSPResponse, responseBytes),
+	ocsp_PointerToResponseBytesTemplate },
+    { 0 }
+};
+
+/*
+ * ResponseBytes	::=	SEQUENCE {
+ *	responseType		OBJECT IDENTIFIER,
+ *	response		OCTET STRING }
+ */
+static const SEC_ASN1Template ocsp_ResponseBytesTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(ocspResponseBytes) },
+    { SEC_ASN1_OBJECT_ID,
+	offsetof(ocspResponseBytes, responseType) },
+    { SEC_ASN1_OCTET_STRING,
+	offsetof(ocspResponseBytes, response) },
+    { 0 }
+};
+
+/*
+ * This template is just an extra level to use in an explicitly-tagged
+ * reference to a ResponseBytes.
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[] = {
+    { SEC_ASN1_POINTER, 0, ocsp_ResponseBytesTemplate }
+};
+
+/*
+ * BasicOCSPResponse	::=	SEQUENCE {
+ *	tbsResponseData		ResponseData,
+ *	signatureAlgorithm	AlgorithmIdentifier,
+ *	signature		BIT STRING,
+ *	certs			[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+static const SEC_ASN1Template ocsp_BasicOCSPResponseTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(ocspBasicOCSPResponse) },
+    { SEC_ASN1_ANY | SEC_ASN1_SAVE,
+	offsetof(ocspBasicOCSPResponse, tbsResponseDataDER) },
+    { SEC_ASN1_POINTER,
+	offsetof(ocspBasicOCSPResponse, tbsResponseData),
+	ocsp_ResponseDataTemplate },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_BIT_STRING,
+	offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	offsetof(ocspBasicOCSPResponse, responseSignature.derCerts),
+	SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
+    { 0 }
+};
+
+/*
+ * ResponseData	::=	SEQUENCE {
+ *	version			[0] EXPLICIT Version DEFAULT v1,
+ *	responderID		ResponderID,
+ *	producedAt		GeneralizedTime,
+ *	responses		SEQUENCE OF SingleResponse,
+ *	responseExtensions	[1] EXPLICIT Extensions OPTIONAL }
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_ResponseDataTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(ocspResponseData) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |		/* XXX DER_DEFAULT */
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	offsetof(ocspResponseData, version),
+	SEC_ASN1_SUB(SEC_IntegerTemplate) },
+    { SEC_ASN1_ANY,
+	offsetof(ocspResponseData, derResponderID) },
+    { SEC_ASN1_GENERALIZED_TIME,
+	offsetof(ocspResponseData, producedAt) },
+    { SEC_ASN1_SEQUENCE_OF,
+	offsetof(ocspResponseData, responses),
+	ocsp_SingleResponseTemplate },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+	offsetof(ocspResponseData, responseExtensions),
+	CERT_SequenceOfCertExtensionTemplate },
+    { 0 }
+};
+
+/*
+ * ResponderID	::=	CHOICE {
+ *	byName			[1] EXPLICIT Name,
+ *	byKey			[2] EXPLICIT KeyHash }
+ *
+ * KeyHash ::=	OCTET STRING -- SHA-1 hash of responder's public key
+ * (excluding the tag and length fields)
+ *
+ * XXX Because the ASN.1 encoder and decoder currently do not provide
+ * a way to automatically handle a CHOICE, we need to do it in two
+ * steps, looking at the type tag and feeding the exact choice back
+ * to the ASN.1 code.  Hopefully that will change someday and this
+ * can all be simplified down into a single template.  Anyway, for
+ * now we list each choice as its own template:
+ */
+static const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[] = {
+    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+	offsetof(ocspResponderID, responderIDValue.name),
+	CERT_NameTemplate }
+};
+static const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[] = {
+    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+        SEC_ASN1_XTRN | 2,
+	offsetof(ocspResponderID, responderIDValue.keyHash),
+	SEC_ASN1_SUB(SEC_OctetStringTemplate) }
+};
+static const SEC_ASN1Template ocsp_ResponderIDOtherTemplate[] = {
+    { SEC_ASN1_ANY,
+	offsetof(ocspResponderID, responderIDValue.other) }
+};
+
+/* Decode choice container, but leave x509 name object encoded */
+static const SEC_ASN1Template ocsp_ResponderIDDerNameTemplate[] = {
+    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+        SEC_ASN1_XTRN | 1, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
+};
+
+/*
+ * SingleResponse	::=	SEQUENCE {
+ *	certID			CertID,
+ *	certStatus		CertStatus,
+ *	thisUpdate		GeneralizedTime,
+ *	nextUpdate		[0] EXPLICIT GeneralizedTime OPTIONAL,
+ *	singleExtensions	[1] EXPLICIT Extensions OPTIONAL }
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_SingleResponseTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(CERTOCSPSingleResponse) },
+    { SEC_ASN1_POINTER,
+	offsetof(CERTOCSPSingleResponse, certID),
+	ocsp_CertIDTemplate },
+    { SEC_ASN1_ANY,
+	offsetof(CERTOCSPSingleResponse, derCertStatus) },
+    { SEC_ASN1_GENERALIZED_TIME,
+	offsetof(CERTOCSPSingleResponse, thisUpdate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	offsetof(CERTOCSPSingleResponse, nextUpdate),
+	SEC_ASN1_SUB(SEC_PointerToGeneralizedTimeTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+	offsetof(CERTOCSPSingleResponse, singleExtensions),
+	CERT_SequenceOfCertExtensionTemplate },
+    { 0 }
+};
+
+/*
+ * CertStatus	::=	CHOICE {
+ *	good			[0] IMPLICIT NULL,
+ *	revoked			[1] IMPLICIT RevokedInfo,
+ *	unknown			[2] IMPLICIT UnknownInfo }
+ *
+ * Because the ASN.1 encoder and decoder currently do not provide
+ * a way to automatically handle a CHOICE, we need to do it in two
+ * steps, looking at the type tag and feeding the exact choice back
+ * to the ASN.1 code.  Hopefully that will change someday and this
+ * can all be simplified down into a single template.  Anyway, for
+ * now we list each choice as its own template:
+ */
+static const SEC_ASN1Template ocsp_CertStatusGoodTemplate[] = {
+    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+	offsetof(ocspCertStatus, certStatusInfo.goodInfo),
+	SEC_ASN1_SUB(SEC_NullTemplate) }
+};
+static const SEC_ASN1Template ocsp_CertStatusRevokedTemplate[] = {
+    { SEC_ASN1_POINTER | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, 
+	offsetof(ocspCertStatus, certStatusInfo.revokedInfo),
+	ocsp_RevokedInfoTemplate }
+};
+static const SEC_ASN1Template ocsp_CertStatusUnknownTemplate[] = {
+    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
+	offsetof(ocspCertStatus, certStatusInfo.unknownInfo),
+	SEC_ASN1_SUB(SEC_NullTemplate) }
+};
+static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = {
+    { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+	offsetof(ocspCertStatus, certStatusInfo.otherInfo),
+	SEC_ASN1_SUB(SEC_AnyTemplate) }
+};
+
+/*
+ * RevokedInfo	::=	SEQUENCE {
+ *	revocationTime		GeneralizedTime,
+ *	revocationReason	[0] EXPLICIT CRLReason OPTIONAL }
+ *
+ * Note: this should be static but the AIX compiler doesn't like it (because it
+ * was forward-declared above); it is not meant to be exported, but this
+ * is the only way it will compile.
+ */
+const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(ocspRevokedInfo) },
+    { SEC_ASN1_GENERALIZED_TIME,
+	offsetof(ocspRevokedInfo, revocationTime) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
+      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+        SEC_ASN1_XTRN | 0,
+	offsetof(ocspRevokedInfo, revocationReason), 
+	SEC_ASN1_SUB(SEC_PointerToEnumeratedTemplate) },
+    { 0 }
+};
+
+
+/*
+ * OCSP-specific extension templates:
+ */
+
+/*
+ * ServiceLocator	::=	SEQUENCE {
+ *	issuer			Name,
+ *	locator			AuthorityInfoAccessSyntax OPTIONAL }
+ */
+static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(ocspServiceLocator) },
+    { SEC_ASN1_POINTER,
+	offsetof(ocspServiceLocator, issuer),
+	CERT_NameTemplate },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+	offsetof(ocspServiceLocator, locator) },
+    { 0 }
+};
+
+
+/*
+ * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy):
+ */
+
+/* 
+ * FUNCTION: CERT_EncodeOCSPRequest
+ *   DER encodes an OCSP Request, possibly adding a signature as well.
+ *   XXX Signing is not yet supported, however; see comments in code.
+ * INPUTS: 
+ *   PRArenaPool *arena
+ *     The return value is allocated from here.
+ *     If a NULL is passed in, allocation is done from the heap instead.
+ *   CERTOCSPRequest *request
+ *     The request to be encoded.
+ *   void *pwArg
+ *     Pointer to argument for password prompting, if needed.  (Definitely
+ *     not needed if not signing.)
+ * RETURN:
+ *   Returns a NULL on error and a pointer to the SECItem with the
+ *   encoded value otherwise.  Any error is likely to be low-level
+ *   (e.g. no memory).
+ */
+SECItem *
+CERT_EncodeOCSPRequest(PRArenaPool *arena, CERTOCSPRequest *request, 
+		       void *pwArg)
+{
+    ocspTBSRequest *tbsRequest;
+    SECStatus rv;
+
+    /* XXX All of these should generate errors if they fail. */
+    PORT_Assert(request);
+    PORT_Assert(request->tbsRequest);
+
+    tbsRequest = request->tbsRequest;
+
+    if (request->tbsRequest->extensionHandle != NULL) {
+	rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle);
+	request->tbsRequest->extensionHandle = NULL;
+	if (rv != SECSuccess)
+	    return NULL;
+    }
+
+    /*
+     * XXX When signed requests are supported and request->optionalSignature
+     * is not NULL:
+     *  - need to encode tbsRequest->requestorName
+     *  - need to encode tbsRequest
+     *  - need to sign that encoded result (using cert in sig), filling in the
+     *    request->optionalSignature structure with the result, the signing
+     *    algorithm and (perhaps?) the cert (and its chain?) in derCerts
+     */
+
+    return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate);
+}
+
+
+/*
+ * FUNCTION: CERT_DecodeOCSPRequest
+ *   Decode a DER encoded OCSP Request.
+ * INPUTS:
+ *   SECItem *src
+ *     Pointer to a SECItem holding DER encoded OCSP Request.
+ * RETURN:
+ *   Returns a pointer to a CERTOCSPRequest containing the decoded request.
+ *   On error, returns NULL.  Most likely error is trouble decoding
+ *   (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory).
+ */
+CERTOCSPRequest *
+CERT_DecodeOCSPRequest(SECItem *src)
+{
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECFailure;
+    CERTOCSPRequest *dest = NULL;
+    int i;
+    SECItem newSrc;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+    dest = (CERTOCSPRequest *) PORT_ArenaZAlloc(arena, 
+						sizeof(CERTOCSPRequest));
+    if (dest == NULL) {
+	goto loser;
+    }
+    dest->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, &newSrc, src);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+
+    rv = SEC_QuickDERDecodeItem(arena, dest, ocsp_OCSPRequestTemplate, &newSrc);
+    if (rv != SECSuccess) {
+	if (PORT_GetError() == SEC_ERROR_BAD_DER)
+	    PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
+	goto loser;
+    }
+
+    /*
+     * XXX I would like to find a way to get rid of the necessity
+     * of doing this copying of the arena pointer.
+     */
+    for (i = 0; dest->tbsRequest->requestList[i] != NULL; i++) {
+	dest->tbsRequest->requestList[i]->arena = arena;
+    }
+
+    return dest;
+
+loser:
+    if (arena != NULL) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return NULL;
+}
+
+SECStatus
+CERT_DestroyOCSPCertID(CERTOCSPCertID* certID)
+{
+    if (certID && certID->poolp) {
+	PORT_FreeArena(certID->poolp, PR_FALSE);
+	return SECSuccess;
+    }
+    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    return SECFailure;
+}
+
+/*
+ * Digest data 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).
+ */
+
+static SECItem *
+ocsp_DigestValue(PRArenaPool *arena, SECOidTag digestAlg, 
+                 SECItem *fill, const SECItem *src)
+{
+    const SECHashObject *digestObject;
+    SECItem *result = NULL;
+    void *mark = NULL;
+    void *digestBuff = NULL;
+
+    if ( arena != NULL ) {
+        mark = PORT_ArenaMark(arena);
+    }
+
+    digestObject = HASH_GetHashObjectByOidTag(digestAlg);
+    if ( digestObject == NULL ) {
+        goto loser;
+    }
+
+    if (fill == NULL || fill->data == NULL) {
+	result = SECITEM_AllocItem(arena, fill, digestObject->length);
+	if ( result == NULL ) {
+	   goto loser;
+	}
+	digestBuff = result->data;
+    } else {
+	if (fill->len < digestObject->length) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    goto loser;
+	}
+	digestBuff = fill->data;
+    }
+
+    if (PK11_HashBuf(digestAlg, digestBuff,
+                     src->data, src->len) != SECSuccess) {
+        goto loser;
+    }
+
+    if ( arena != NULL ) {
+        PORT_ArenaUnmark(arena, mark);
+    }
+
+    if (result == NULL) {
+        result = fill;
+    }
+    return result;
+
+loser:
+    if (arena != NULL) {
+        PORT_ArenaRelease(arena, mark);
+    } else {
+        if (result != NULL) {
+            SECITEM_FreeItem(result, (fill == NULL) ? PR_TRUE : PR_FALSE);
+        }
+    }
+    return(NULL);
+}
+
+/*
+ * 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).
+ */
+SECItem *
+CERT_GetSPKIDigest(PRArenaPool *arena, const CERTCertificate *cert,
+                           SECOidTag digestAlg, SECItem *fill)
+{
+    SECItem spk;
+
+    /*
+     * Copy just the length and data pointer (nothing needs to be freed)
+     * of the subject public key so we can convert the length from bits
+     * to bytes, which is what the digest function expects.
+     */
+    spk = cert->subjectPublicKeyInfo.subjectPublicKey;
+    DER_ConvertBitString(&spk);
+
+    return ocsp_DigestValue(arena, digestAlg, fill, &spk);
+}
+
+/*
+ * Digest the cert's subject name using the specified algorithm.
+ */
+static SECItem *
+cert_GetSubjectNameDigest(PRArenaPool *arena, const CERTCertificate *cert,
+                           SECOidTag digestAlg, SECItem *fill)
+{
+    SECItem name;
+
+    /*
+     * Copy just the length and data pointer (nothing needs to be freed)
+     * of the subject name
+     */
+    name = cert->derSubject;
+
+    return ocsp_DigestValue(arena, digestAlg, fill, &name);
+}
+
+/*
+ * Create and fill-in a CertID.  This function fills in the hash values
+ * (issuerNameHash and issuerKeyHash), and is hardwired to use SHA1.
+ * Someday it might need to be more flexible about hash algorithm, but
+ * for now we have no intention/need to create anything else.
+ *
+ * Error causes a null to be returned; most likely cause is trouble
+ * finding the certificate issuer (SEC_ERROR_UNKNOWN_ISSUER).
+ * Other errors are low-level problems (no memory, bad database, etc.).
+ */
+static CERTOCSPCertID *
+ocsp_CreateCertID(PRArenaPool *arena, CERTCertificate *cert, int64 time)
+{
+    CERTOCSPCertID *certID;
+    CERTCertificate *issuerCert = NULL;
+    void *mark = PORT_ArenaMark(arena);
+    SECStatus rv;
+
+    PORT_Assert(arena != NULL);
+
+    certID = PORT_ArenaZNew(arena, CERTOCSPCertID);
+    if (certID == NULL) {
+	goto loser;
+    }
+
+    rv = SECOID_SetAlgorithmID(arena, &certID->hashAlgorithm, SEC_OID_SHA1,
+			       NULL);
+    if (rv != SECSuccess) {
+	goto loser; 
+    }
+
+    issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA);
+    if (issuerCert == NULL) {
+	goto loser;
+    }
+
+    if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_SHA1,
+                                  &(certID->issuerNameHash)) == NULL) {
+        goto loser;
+    }
+    certID->issuerSHA1NameHash.data = certID->issuerNameHash.data;
+    certID->issuerSHA1NameHash.len = certID->issuerNameHash.len;
+
+    if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD5,
+                                  &(certID->issuerMD5NameHash)) == NULL) {
+        goto loser;
+    }
+
+    if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD2,
+                                  &(certID->issuerMD2NameHash)) == NULL) {
+        goto loser;
+    }
+
+    if (CERT_GetSPKIDigest(arena, issuerCert, SEC_OID_SHA1,
+				   &(certID->issuerKeyHash)) == NULL) {
+	goto loser;
+    }
+    certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data;
+    certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len;
+    /* cache the other two hash algorithms as well */
+    if (CERT_GetSPKIDigest(arena, issuerCert, SEC_OID_MD5,
+				   &(certID->issuerMD5KeyHash)) == NULL) {
+	goto loser;
+    }
+    if (CERT_GetSPKIDigest(arena, issuerCert, SEC_OID_MD2,
+				   &(certID->issuerMD2KeyHash)) == NULL) {
+	goto loser;
+    }
+
+
+    /* now we are done with issuerCert */
+    CERT_DestroyCertificate(issuerCert);
+    issuerCert = NULL;
+
+    rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber);
+    if (rv != SECSuccess) {
+	goto loser; 
+    }
+
+    PORT_ArenaUnmark(arena, mark);
+    return certID;
+
+loser:
+    if (issuerCert != NULL) {
+	CERT_DestroyCertificate(issuerCert);
+    }
+    PORT_ArenaRelease(arena, mark);
+    return NULL;
+}
+
+CERTOCSPCertID*
+CERT_CreateOCSPCertID(CERTCertificate *cert, int64 time)
+{
+    PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    CERTOCSPCertID *certID;
+    PORT_Assert(arena != NULL);
+    if (!arena)
+	return NULL;
+    
+    certID = ocsp_CreateCertID(arena, cert, time);
+    if (!certID) {
+	PORT_FreeArena(arena, PR_FALSE);
+	return NULL;
+    }
+    certID->poolp = arena;
+    return certID;
+}
+
+/*
+ * Callback to set Extensions in request object
+ */
+void SetSingleReqExts(void *object, CERTCertExtension **exts)
+{
+  ocspSingleRequest *singleRequest =
+    (ocspSingleRequest *)object;
+
+  singleRequest->singleRequestExtensions = exts;
+}
+
+/*
+ * Add the Service Locator extension to the singleRequestExtensions
+ * for the given singleRequest.
+ *
+ * All errors are internal or low-level problems (e.g. no memory).
+ */
+static SECStatus
+ocsp_AddServiceLocatorExtension(ocspSingleRequest *singleRequest,
+				CERTCertificate *cert)
+{
+    ocspServiceLocator *serviceLocator = NULL;
+    void *extensionHandle = NULL;
+    SECStatus rv = SECFailure;
+
+    serviceLocator = PORT_ZNew(ocspServiceLocator);
+    if (serviceLocator == NULL)
+	goto loser;
+
+    /*
+     * Normally it would be a bad idea to do a direct reference like
+     * this rather than allocate and copy the name *or* at least dup
+     * a reference of the cert.  But all we need is to be able to read
+     * the issuer name during the encoding we are about to do, so a
+     * copy is just a waste of time.
+     */
+    serviceLocator->issuer = &cert->issuer;
+
+    rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS,
+				&serviceLocator->locator);
+    if (rv != SECSuccess) {
+	if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
+	    goto loser;
+    }
+
+    /* prepare for following loser gotos */
+    rv = SECFailure;
+    PORT_SetError(0);
+
+    extensionHandle = cert_StartExtensions(singleRequest,
+                       singleRequest->arena, SetSingleReqExts);
+    if (extensionHandle == NULL)
+	goto loser;
+
+    rv = CERT_EncodeAndAddExtension(extensionHandle,
+				    SEC_OID_PKIX_OCSP_SERVICE_LOCATOR,
+				    serviceLocator, PR_FALSE,
+				    ocsp_ServiceLocatorTemplate);
+
+loser:
+    if (extensionHandle != NULL) {
+	/*
+	 * Either way we have to finish out the extension context (so it gets
+	 * freed).  But careful not to override any already-set bad status.
+	 */
+	SECStatus tmprv = CERT_FinishExtensions(extensionHandle);
+	if (rv == SECSuccess)
+	    rv = tmprv;
+    }
+
+    /*
+     * Finally, free the serviceLocator structure itself and we are done.
+     */
+    if (serviceLocator != NULL) {
+	if (serviceLocator->locator.data != NULL)
+	    SECITEM_FreeItem(&serviceLocator->locator, PR_FALSE);
+	PORT_Free(serviceLocator);
+    }
+
+    return rv;
+}
+
+/*
+ * Creates an array of ocspSingleRequest based on a list of certs.
+ * Note that the code which later compares the request list with the
+ * response expects this array to be in the exact same order as the
+ * certs are found in the list.  It would be harder to change that
+ * order than preserve it, but since the requirement is not obvious,
+ * it deserves to be mentioned.
+ *
+ * Any problem causes a null return and error set:
+ *      SEC_ERROR_UNKNOWN_ISSUER
+ * Other errors are low-level problems (no memory, bad database, etc.).
+ */
+static ocspSingleRequest **
+ocsp_CreateSingleRequestList(PRArenaPool *arena, CERTCertList *certList,
+                             int64 time, PRBool includeLocator)
+{
+    ocspSingleRequest **requestList = NULL;
+    CERTCertListNode *node = NULL;
+    int i, count;
+    void *mark = PORT_ArenaMark(arena);
+ 
+    node = CERT_LIST_HEAD(certList);
+    for (count = 0; !CERT_LIST_END(node, certList); count++) {
+        node = CERT_LIST_NEXT(node);
+    }
+
+    if (count == 0)
+	goto loser;
+
+    requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, count + 1);
+    if (requestList == NULL)
+	goto loser;
+
+    node = CERT_LIST_HEAD(certList);
+    for (i = 0; !CERT_LIST_END(node, certList); i++) {
+        requestList[i] = PORT_ArenaZNew(arena, ocspSingleRequest);
+        if (requestList[i] == NULL)
+            goto loser;
+
+        OCSP_TRACE(("OCSP CERT_CreateOCSPRequest %s\n", node->cert->subjectName));
+        requestList[i]->arena = arena;
+        requestList[i]->reqCert = ocsp_CreateCertID(arena, node->cert, time);
+        if (requestList[i]->reqCert == NULL)
+            goto loser;
+
+        if (includeLocator == PR_TRUE) {
+            SECStatus rv;
+
+            rv = ocsp_AddServiceLocatorExtension(requestList[i], node->cert);
+            if (rv != SECSuccess)
+                goto loser;
+        }
+
+        node = CERT_LIST_NEXT(node);
+    }
+
+    PORT_Assert(i == count);
+
+    PORT_ArenaUnmark(arena, mark);
+    requestList[i] = NULL;
+    return requestList;
+
+loser:
+    PORT_ArenaRelease(arena, mark);
+    return NULL;
+}
+
+static ocspSingleRequest **
+ocsp_CreateRequestFromCert(PRArenaPool *arena, 
+                           CERTOCSPCertID *certID, 
+                           CERTCertificate *singleCert,
+                           int64 time, 
+                           PRBool includeLocator)
+{
+    ocspSingleRequest **requestList = NULL;
+    void *mark = PORT_ArenaMark(arena);
+    PORT_Assert(certID != NULL && singleCert != NULL);
+
+    /* meaning of value 2: one entry + one end marker */
+    requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, 2);
+    if (requestList == NULL)
+        goto loser;
+    requestList[0] = PORT_ArenaZNew(arena, ocspSingleRequest);
+    if (requestList[0] == NULL)
+        goto loser;
+    requestList[0]->arena = arena;
+    /* certID will live longer than the request */
+    requestList[0]->reqCert = certID; 
+
+    if (includeLocator == PR_TRUE) {
+        SECStatus rv;
+        rv = ocsp_AddServiceLocatorExtension(requestList[0], singleCert);
+        if (rv != SECSuccess)
+            goto loser;
+    }
+
+    PORT_ArenaUnmark(arena, mark);
+    requestList[1] = NULL;
+    return requestList;
+
+loser:
+    PORT_ArenaRelease(arena, mark);
+    return NULL;
+}
+
+static CERTOCSPRequest *
+ocsp_prepareEmptyOCSPRequest()
+{
+    PRArenaPool *arena = NULL;
+    CERTOCSPRequest *request = NULL;
+    ocspTBSRequest *tbsRequest = NULL;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+        goto loser;
+    }
+    request = PORT_ArenaZNew(arena, CERTOCSPRequest);
+    if (request == NULL) {
+        goto loser;
+    }
+    request->arena = arena;
+
+    tbsRequest = PORT_ArenaZNew(arena, ocspTBSRequest);
+    if (tbsRequest == NULL) {
+        goto loser;
+    }
+    request->tbsRequest = tbsRequest;
+    /* version 1 is the default, so we need not fill in a version number */
+    return request;
+
+loser:
+    if (arena != NULL) {
+        PORT_FreeArena(arena, PR_FALSE);
+    }
+    return NULL;
+}
+
+CERTOCSPRequest *
+cert_CreateSingleCertOCSPRequest(CERTOCSPCertID *certID, 
+                                 CERTCertificate *singleCert, 
+                                 int64 time, 
+                                 PRBool addServiceLocator,
+                                 CERTCertificate *signerCert)
+{
+    CERTOCSPRequest *request;
+    OCSP_TRACE(("OCSP cert_CreateSingleCertOCSPRequest %s\n", singleCert->subjectName));
+
+    /* XXX Support for signerCert may be implemented later,
+     * see also the comment in CERT_CreateOCSPRequest.
+     */
+    if (signerCert != NULL) {
+        PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+        return NULL;
+    }
+
+    request = ocsp_prepareEmptyOCSPRequest();
+    if (!request)
+        return NULL;
+    /*
+     * Version 1 is the default, so we need not fill in a version number.
+     * Now create the list of single requests, one for each cert.
+     */
+    request->tbsRequest->requestList = 
+        ocsp_CreateRequestFromCert(request->arena, 
+                                   certID,
+                                   singleCert,
+                                   time,
+                                   addServiceLocator);
+    if (request->tbsRequest->requestList == NULL) {
+        PORT_FreeArena(request->arena, PR_FALSE);
+        return NULL;
+    }
+    return request;
+}
+
+/*
+ * FUNCTION: CERT_CreateOCSPRequest
+ *   Creates a CERTOCSPRequest, requesting the status of the certs in 
+ *   the given list.
+ * INPUTS:
+ *   CERTCertList *certList
+ *     A list of certs for which status will be requested.
+ *     Note that all of these certificates should have the same issuer,
+ *     or it's expected the response will be signed by a trusted responder.
+ *     If the certs need to be broken up into multiple requests, that
+ *     must be handled by the caller (and thus by having multiple calls
+ *     to this routine), who knows about where the request(s) are being
+ *     sent and whether there are any trusted responders in place.
+ *   int64 time
+ *     Indicates the time for which the certificate status is to be 
+ *     determined -- this may be used in the search for the cert's issuer
+ *     but has no effect on the request itself.
+ *   PRBool addServiceLocator
+ *     If true, the Service Locator extension should be added to the
+ *     single request(s) for each cert.
+ *   CERTCertificate *signerCert
+ *     If non-NULL, means sign the request using this cert.  Otherwise,
+ *     do not sign.
+ *     XXX note that request signing is not yet supported; see comment in code
+ * RETURN:
+ *   A pointer to a CERTOCSPRequest structure containing an OCSP request
+ *   for the cert list.  On error, null is returned, with an error set
+ *   indicating the reason.  This is likely SEC_ERROR_UNKNOWN_ISSUER.
+ *   (The issuer is needed to create a request for the certificate.)
+ *   Other errors are low-level problems (no memory, bad database, etc.).
+ */
+CERTOCSPRequest *
+CERT_CreateOCSPRequest(CERTCertList *certList, int64 time, 
+		       PRBool addServiceLocator,
+		       CERTCertificate *signerCert)
+{
+    CERTOCSPRequest *request = NULL;
+
+    if (!certList) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+    /*
+     * XXX When we are prepared to put signing of requests back in, 
+     * we will need to allocate a signature
+     * structure for the request, fill in the "derCerts" field in it,
+     * save the signerCert there, as well as fill in the "requestorName"
+     * field of the tbsRequest.
+     */
+    if (signerCert != NULL) {
+        PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+        return NULL;
+    }
+    request = ocsp_prepareEmptyOCSPRequest();
+    if (!request)
+        return NULL;
+    /*
+     * Now create the list of single requests, one for each cert.
+     */
+    request->tbsRequest->requestList = 
+        ocsp_CreateSingleRequestList(request->arena, 
+                                     certList,
+                                     time,
+                                     addServiceLocator);
+    if (request->tbsRequest->requestList == NULL) {
+        PORT_FreeArena(request->arena, PR_FALSE);
+        return NULL;
+    }
+    return request;
+}
+
+/*
+ * FUNCTION: CERT_AddOCSPAcceptableResponses
+ *   Add the AcceptableResponses extension to an OCSP Request.
+ * INPUTS:
+ *   CERTOCSPRequest *request
+ *     The request to which the extension should be added.
+ *   ...
+ *     A list (of one or more) of SECOidTag -- each of the response types
+ *     to be added.  The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE.
+ *     (This marks the end of the list, and it must be specified because a
+ *     client conforming to the OCSP standard is required to handle the basic
+ *     response type.)  The OIDs are not checked in any way.
+ * RETURN:
+ *   SECSuccess if the extension is added; SECFailure if anything goes wrong.
+ *   All errors are internal or low-level problems (e.g. no memory).
+ */
+
+void SetRequestExts(void *object, CERTCertExtension **exts)
+{
+  CERTOCSPRequest *request = (CERTOCSPRequest *)object;
+
+  request->tbsRequest->requestExtensions = exts;
+}
+
+SECStatus
+CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request,
+				SECOidTag responseType0, ...)
+{
+    void *extHandle;
+    va_list ap;
+    int i, count;
+    SECOidTag responseType;
+    SECOidData *responseOid;
+    SECItem **acceptableResponses = NULL;
+    SECStatus rv = SECFailure;
+
+    extHandle = request->tbsRequest->extensionHandle;
+    if (extHandle == NULL) {
+	extHandle = cert_StartExtensions(request, request->arena, SetRequestExts);
+	if (extHandle == NULL)
+	    goto loser;
+    }
+
+    /* Count number of OIDS going into the extension value. */
+    count = 1;
+    if (responseType0 != SEC_OID_PKIX_OCSP_BASIC_RESPONSE) {
+	va_start(ap, responseType0);
+	do {
+	    count++;
+	    responseType = va_arg(ap, SECOidTag);
+	} while (responseType != SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
+	va_end(ap);
+    }
+
+    acceptableResponses = PORT_NewArray(SECItem *, count + 1);
+    if (acceptableResponses == NULL)
+	goto loser;
+
+    i = 0;
+    responseOid = SECOID_FindOIDByTag(responseType0);
+    acceptableResponses[i++] = &(responseOid->oid);
+    if (count > 1) {
+	va_start(ap, responseType0);
+	for ( ; i < count; i++) {
+	    responseType = va_arg(ap, SECOidTag);
+	    responseOid = SECOID_FindOIDByTag(responseType);
+	    acceptableResponses[i] = &(responseOid->oid);
+	}
+	va_end(ap);
+    }
+    acceptableResponses[i] = NULL;
+
+    rv = CERT_EncodeAndAddExtension(extHandle, SEC_OID_PKIX_OCSP_RESPONSE,
+                                &acceptableResponses, PR_FALSE,
+                                SEC_ASN1_GET(SEC_SequenceOfObjectIDTemplate));
+    if (rv != SECSuccess)
+	goto loser;
+
+    PORT_Free(acceptableResponses);
+    if (request->tbsRequest->extensionHandle == NULL)
+	request->tbsRequest->extensionHandle = extHandle;
+    return SECSuccess;
+
+loser:
+    if (acceptableResponses != NULL)
+	PORT_Free(acceptableResponses);
+    if (extHandle != NULL)
+	(void) CERT_FinishExtensions(extHandle);
+    return rv;
+}
+
+
+/*
+ * FUNCTION: CERT_DestroyOCSPRequest
+ *   Frees an OCSP Request structure.
+ * INPUTS:
+ *   CERTOCSPRequest *request
+ *     Pointer to CERTOCSPRequest to be freed.
+ * RETURN:
+ *   No return value; no errors.
+ */
+void
+CERT_DestroyOCSPRequest(CERTOCSPRequest *request)
+{
+    if (request == NULL)
+	return;
+
+    if (request->tbsRequest != NULL) {
+	if (request->tbsRequest->requestorName != NULL)
+	    CERT_DestroyGeneralNameList(request->tbsRequest->requestorName);
+	if (request->tbsRequest->extensionHandle != NULL)
+	    (void) CERT_FinishExtensions(request->tbsRequest->extensionHandle);
+    }
+
+    if (request->optionalSignature != NULL) {
+	if (request->optionalSignature->cert != NULL)
+	    CERT_DestroyCertificate(request->optionalSignature->cert);
+
+	/*
+	 * XXX Need to free derCerts?  Or do they come out of arena?
+	 * (Currently we never fill in derCerts, which is why the
+	 * answer is not obvious.  Once we do, add any necessary code
+	 * here and remove this comment.)
+	 */
+    }
+
+    /*
+     * We should actually never have a request without an arena,
+     * but check just in case.  (If there isn't one, there is not
+     * much we can do about it...)
+     */
+    PORT_Assert(request->arena != NULL);
+    if (request->arena != NULL)
+	PORT_FreeArena(request->arena, PR_FALSE);
+}
+
+
+/*
+ * RESPONSE SUPPORT FUNCTIONS (encode/create/decode/destroy):
+ */
+
+/*
+ * Helper function for encoding or decoding a ResponderID -- based on the
+ * given type, return the associated template for that choice.
+ */
+static const SEC_ASN1Template *
+ocsp_ResponderIDTemplateByType(ocspResponderIDType responderIDType)
+{
+    const SEC_ASN1Template *responderIDTemplate;
+
+    switch (responderIDType) {
+	case ocspResponderID_byName:
+	    responderIDTemplate = ocsp_ResponderIDByNameTemplate;
+	    break;
+	case ocspResponderID_byKey:
+	    responderIDTemplate = ocsp_ResponderIDByKeyTemplate;
+	    break;
+	case ocspResponderID_other:
+	default:
+	    PORT_Assert(responderIDType == ocspResponderID_other);
+	    responderIDTemplate = ocsp_ResponderIDOtherTemplate;
+	    break;
+    }
+
+    return responderIDTemplate;
+}
+
+/*
+ * Helper function for encoding or decoding a CertStatus -- based on the
+ * given type, return the associated template for that choice.
+ */
+static const SEC_ASN1Template *
+ocsp_CertStatusTemplateByType(ocspCertStatusType certStatusType)
+{
+    const SEC_ASN1Template *certStatusTemplate;
+
+    switch (certStatusType) {
+	case ocspCertStatus_good:
+	    certStatusTemplate = ocsp_CertStatusGoodTemplate;
+	    break;
+	case ocspCertStatus_revoked:
+	    certStatusTemplate = ocsp_CertStatusRevokedTemplate;
+	    break;
+	case ocspCertStatus_unknown:
+	    certStatusTemplate = ocsp_CertStatusUnknownTemplate;
+	    break;
+	case ocspCertStatus_other:
+	default:
+	    PORT_Assert(certStatusType == ocspCertStatus_other);
+	    certStatusTemplate = ocsp_CertStatusOtherTemplate;
+	    break;
+    }
+
+    return certStatusTemplate;
+}
+
+/*
+ * Helper function for decoding a certStatus -- turn the actual DER tag
+ * into our local translation.
+ */
+static ocspCertStatusType
+ocsp_CertStatusTypeByTag(int derTag)
+{
+    ocspCertStatusType certStatusType;
+
+    switch (derTag) {
+	case 0:
+	    certStatusType = ocspCertStatus_good;
+	    break;
+	case 1:
+	    certStatusType = ocspCertStatus_revoked;
+	    break;
+	case 2:
+	    certStatusType = ocspCertStatus_unknown;
+	    break;
+	default:
+	    certStatusType = ocspCertStatus_other;
+	    break;
+    }
+
+    return certStatusType;
+}
+
+/*
+ * Helper function for decoding SingleResponses -- they each contain
+ * a status which is encoded as CHOICE, which needs to be decoded "by hand".
+ *
+ * Note -- on error, this routine does not release the memory it may
+ * have allocated; it expects its caller to do that.
+ */
+static SECStatus
+ocsp_FinishDecodingSingleResponses(PRArenaPool *reqArena,
+				   CERTOCSPSingleResponse **responses)
+{
+    ocspCertStatus *certStatus;
+    ocspCertStatusType certStatusType;
+    const SEC_ASN1Template *certStatusTemplate;
+    int derTag;
+    int i;
+    SECStatus rv = SECFailure;
+
+    if (!reqArena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (responses == NULL)			/* nothing to do */
+	return SECSuccess;
+
+    for (i = 0; responses[i] != NULL; i++) {
+        SECItem* newStatus;
+	/*
+	 * The following assert points out internal errors (problems in
+	 * the template definitions or in the ASN.1 decoder itself, etc.).
+	 */
+	PORT_Assert(responses[i]->derCertStatus.data != NULL);
+
+	derTag = responses[i]->derCertStatus.data[0] & SEC_ASN1_TAGNUM_MASK;
+	certStatusType = ocsp_CertStatusTypeByTag(derTag);
+	certStatusTemplate = ocsp_CertStatusTemplateByType(certStatusType);
+
+	certStatus = PORT_ArenaZAlloc(reqArena, sizeof(ocspCertStatus));
+	if (certStatus == NULL) {
+	    goto loser;
+	}
+        newStatus = SECITEM_ArenaDupItem(reqArena, &responses[i]->derCertStatus);
+        if (!newStatus) {
+            goto loser;
+        }
+	rv = SEC_QuickDERDecodeItem(reqArena, certStatus, certStatusTemplate,
+				newStatus);
+	if (rv != SECSuccess) {
+	    if (PORT_GetError() == SEC_ERROR_BAD_DER)
+		PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+	    goto loser;
+	}
+
+	certStatus->certStatusType = certStatusType;
+	responses[i]->certStatus = certStatus;
+    }
+
+    return SECSuccess;
+
+loser:
+    return rv;
+}
+
+/*
+ * Helper function for decoding a responderID -- turn the actual DER tag
+ * into our local translation.
+ */
+static ocspResponderIDType
+ocsp_ResponderIDTypeByTag(int derTag)
+{
+    ocspResponderIDType responderIDType;
+
+    switch (derTag) {
+	case 1:
+	    responderIDType = ocspResponderID_byName;
+	    break;
+	case 2:
+	    responderIDType = ocspResponderID_byKey;
+	    break;
+	default:
+	    responderIDType = ocspResponderID_other;
+	    break;
+    }
+
+    return responderIDType;
+}
+
+/*
+ * Decode "src" as a BasicOCSPResponse, returning the result.
+ */
+static ocspBasicOCSPResponse *
+ocsp_DecodeBasicOCSPResponse(PRArenaPool *arena, SECItem *src)
+{
+    void *mark;
+    ocspBasicOCSPResponse *basicResponse;
+    ocspResponseData *responseData;
+    ocspResponderID *responderID;
+    ocspResponderIDType responderIDType;
+    const SEC_ASN1Template *responderIDTemplate;
+    int derTag;
+    SECStatus rv;
+    SECItem newsrc;
+
+    mark = PORT_ArenaMark(arena);
+
+    basicResponse = PORT_ArenaZAlloc(arena, sizeof(ocspBasicOCSPResponse));
+    if (basicResponse == NULL) {
+	goto loser;
+    }
+
+    /* 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, &newsrc, src);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+
+    rv = SEC_QuickDERDecodeItem(arena, basicResponse,
+			    ocsp_BasicOCSPResponseTemplate, &newsrc);
+    if (rv != SECSuccess) {
+	if (PORT_GetError() == SEC_ERROR_BAD_DER)
+	    PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+	goto loser;
+    }
+
+    responseData = basicResponse->tbsResponseData;
+
+    /*
+     * The following asserts point out internal errors (problems in
+     * the template definitions or in the ASN.1 decoder itself, etc.).
+     */
+    PORT_Assert(responseData != NULL);
+    PORT_Assert(responseData->derResponderID.data != NULL);
+
+    /*
+     * XXX Because responderID is a CHOICE, which is not currently handled
+     * by our ASN.1 decoder, we have to decode it "by hand".
+     */
+    derTag = responseData->derResponderID.data[0] & SEC_ASN1_TAGNUM_MASK;
+    responderIDType = ocsp_ResponderIDTypeByTag(derTag);
+    responderIDTemplate = ocsp_ResponderIDTemplateByType(responderIDType);
+
+    responderID = PORT_ArenaZAlloc(arena, sizeof(ocspResponderID));
+    if (responderID == NULL) {
+	goto loser;
+    }
+
+    rv = SEC_QuickDERDecodeItem(arena, responderID, responderIDTemplate,
+			    &responseData->derResponderID);
+    if (rv != SECSuccess) {
+	if (PORT_GetError() == SEC_ERROR_BAD_DER)
+	    PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+	goto loser;
+    }
+
+    responderID->responderIDType = responderIDType;
+    responseData->responderID = responderID;
+
+    /*
+     * XXX Each SingleResponse also contains a CHOICE, which has to be
+     * fixed up by hand.
+     */
+    rv = ocsp_FinishDecodingSingleResponses(arena, responseData->responses);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    PORT_ArenaUnmark(arena, mark);
+    return basicResponse;
+
+loser:
+    PORT_ArenaRelease(arena, mark);
+    return NULL;
+}
+
+
+/*
+ * Decode the responseBytes based on the responseType found in "rbytes",
+ * leaving the resulting translated/decoded information in there as well.
+ */
+static SECStatus
+ocsp_DecodeResponseBytes(PRArenaPool *arena, ocspResponseBytes *rbytes)
+{
+    PORT_Assert(rbytes != NULL);		/* internal error, really */
+    if (rbytes == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);	/* XXX set better error? */
+	return SECFailure;
+    }
+
+    rbytes->responseTypeTag = SECOID_FindOIDTag(&rbytes->responseType);
+    switch (rbytes->responseTypeTag) {
+	case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
+	    {
+		ocspBasicOCSPResponse *basicResponse;
+
+		basicResponse = ocsp_DecodeBasicOCSPResponse(arena,
+							     &rbytes->response);
+		if (basicResponse == NULL)
+		    return SECFailure;
+
+		rbytes->decodedResponse.basic = basicResponse;
+	    }
+	    break;
+
+	/*
+	 * Add new/future response types here.
+	 */
+
+	default:
+	    PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE);
+	    return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+
+/*
+ * FUNCTION: CERT_DecodeOCSPResponse
+ *   Decode a DER encoded OCSP Response.
+ * INPUTS:
+ *   SECItem *src
+ *     Pointer to a SECItem holding DER encoded OCSP Response.
+ * RETURN:
+ *   Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response);
+ *   the caller is responsible for destroying it.  Or NULL if error (either
+ *   response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE),
+ *   it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE),
+ *   or a low-level or internal error occurred).
+ */
+CERTOCSPResponse *
+CERT_DecodeOCSPResponse(SECItem *src)
+{
+    PRArenaPool *arena = NULL;
+    CERTOCSPResponse *response = NULL;
+    SECStatus rv = SECFailure;
+    ocspResponseStatus sv;
+    SECItem newSrc;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+    response = (CERTOCSPResponse *) PORT_ArenaZAlloc(arena,
+						     sizeof(CERTOCSPResponse));
+    if (response == NULL) {
+	goto loser;
+    }
+    response->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, &newSrc, src);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+
+    rv = SEC_QuickDERDecodeItem(arena, response, ocsp_OCSPResponseTemplate, &newSrc);
+    if (rv != SECSuccess) {
+	if (PORT_GetError() == SEC_ERROR_BAD_DER)
+	    PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+	goto loser;
+    }
+
+    sv = (ocspResponseStatus) DER_GetInteger(&response->responseStatus);
+    response->statusValue = sv;
+    if (sv != ocspResponse_successful) {
+	/*
+	 * If the response status is anything but successful, then we
+	 * are all done with decoding; the status is all there is.
+	 */
+	return response;
+    }
+
+    /*
+     * A successful response contains much more information, still encoded.
+     * Now we need to decode that.
+     */
+    rv = ocsp_DecodeResponseBytes(arena, response->responseBytes);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    return response;
+
+loser:
+    if (arena != NULL) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return NULL;
+}
+
+/*
+ * The way an OCSPResponse is defined, there are many levels to descend
+ * before getting to the actual response information.  And along the way
+ * we need to check that the response *type* is recognizable, which for
+ * now means that it is a BasicOCSPResponse, because that is the only
+ * type currently defined.  Rather than force all routines to perform
+ * a bunch of sanity checking every time they want to work on a response,
+ * this function isolates that and gives back the interesting part.
+ * Note that no copying is done, this just returns a pointer into the
+ * substructure of the response which is passed in.
+ *
+ * XXX This routine only works when a valid response structure is passed
+ * into it; this is checked with many assertions.  Assuming the response
+ * was creating by decoding, it wouldn't make it this far without being
+ * okay.  That is a sufficient assumption since the entire OCSP interface
+ * is only used internally.  When this interface is officially exported,
+ * each assertion below will need to be followed-up with setting an error
+ * and returning (null).
+ *
+ * FUNCTION: ocsp_GetResponseData
+ *   Returns ocspResponseData structure and a pointer to tbs response
+ *   data DER from a valid ocsp response. 
+ * INPUTS:
+ *   CERTOCSPResponse *response
+ *     structure of a valid ocsp response
+ * RETURN:
+ *   Returns a pointer to ocspResponseData structure: decoded OCSP response
+ *   data, and a pointer(tbsResponseDataDER) to its undecoded data DER.
+ */
+ocspResponseData *
+ocsp_GetResponseData(CERTOCSPResponse *response, SECItem **tbsResponseDataDER)
+{
+    ocspBasicOCSPResponse *basic;
+    ocspResponseData *responseData;
+
+    PORT_Assert(response != NULL);
+
+    PORT_Assert(response->responseBytes != NULL);
+
+    PORT_Assert(response->responseBytes->responseTypeTag
+		== SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
+
+    basic = response->responseBytes->decodedResponse.basic;
+    PORT_Assert(basic != NULL);
+
+    responseData = basic->tbsResponseData;
+    PORT_Assert(responseData != NULL);
+
+    if (tbsResponseDataDER) {
+        *tbsResponseDataDER = &basic->tbsResponseDataDER;
+
+        PORT_Assert((*tbsResponseDataDER)->data != NULL);
+        PORT_Assert((*tbsResponseDataDER)->len != 0);
+    }
+
+    return responseData;
+}
+
+/*
+ * Much like the routine above, except it returns the response signature.
+ * Again, no copy is done.
+ */
+ocspSignature *
+ocsp_GetResponseSignature(CERTOCSPResponse *response)
+{
+    ocspBasicOCSPResponse *basic;
+
+    PORT_Assert(response != NULL);
+    if (NULL == response->responseBytes) {
+        return NULL;
+    }
+    PORT_Assert(response->responseBytes != NULL);
+    PORT_Assert(response->responseBytes->responseTypeTag
+		== SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
+
+    basic = response->responseBytes->decodedResponse.basic;
+    PORT_Assert(basic != NULL);
+
+    return &(basic->responseSignature);
+}
+
+
+/*
+ * FUNCTION: CERT_DestroyOCSPResponse
+ *   Frees an OCSP Response structure.
+ * INPUTS:
+ *   CERTOCSPResponse *request
+ *     Pointer to CERTOCSPResponse to be freed.
+ * RETURN:
+ *   No return value; no errors.
+ */
+void
+CERT_DestroyOCSPResponse(CERTOCSPResponse *response)
+{
+    if (response != NULL) {
+	ocspSignature *signature = ocsp_GetResponseSignature(response);
+	if (signature && signature->cert != NULL)
+	    CERT_DestroyCertificate(signature->cert);
+
+	/*
+	 * We should actually never have a response without an arena,
+	 * but check just in case.  (If there isn't one, there is not
+	 * much we can do about it...)
+	 */
+	PORT_Assert(response->arena != NULL);
+	if (response->arena != NULL) {
+	    PORT_FreeArena(response->arena, PR_FALSE);
+	}
+    }
+}
+
+
+/*
+ * OVERALL OCSP CLIENT SUPPORT (make and send a request, verify a response):
+ */
+
+
+/*
+ * Pick apart a URL, saving the important things in the passed-in pointers.
+ *
+ * We expect to find "http://<hostname>[:<port>]/[path]", though we will
+ * tolerate that final slash character missing, as well as beginning and
+ * trailing whitespace, and any-case-characters for "http".  All of that
+ * tolerance is what complicates this routine.  What we want is just to
+ * pick out the hostname, the port, and the path.
+ *
+ * On a successful return, the caller will need to free the output pieces
+ * of hostname and path, which are copies of the values found in the url.
+ */
+static SECStatus
+ocsp_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath)
+{
+    unsigned short port = 80;		/* default, in case not in url */
+    char *hostname = NULL;
+    char *path = NULL;
+    const char *save;
+    char c;
+    int len;
+
+    if (url == NULL)
+	goto loser;
+
+    /*
+     * Skip beginning whitespace.
+     */
+    c = *url;
+    while ((c == ' ' || c == '\t') && c != '\0') {
+	url++;
+	c = *url;
+    }
+    if (c == '\0')
+	goto loser;
+
+    /*
+     * Confirm, then skip, protocol.  (Since we only know how to do http,
+     * that is all we will accept).
+     */
+    if (PORT_Strncasecmp(url, "http://", 7) != 0)
+	goto loser;
+    url += 7;
+
+    /*
+     * Whatever comes next is the hostname (or host IP address).  We just
+     * save it aside and then search for its end so we can determine its
+     * length and copy it.
+     *
+     * XXX Note that because we treat a ':' as a terminator character
+     * (and below, we expect that to mean there is a port specification
+     * immediately following), we will not handle IPv6 addresses.  That is
+     * apparently an acceptable limitation, for the time being.  Some day,
+     * when there is a clear way to specify a URL with an IPv6 address that
+     * can be parsed unambiguously, this code should be made to do that.
+     */
+    save = url;
+    c = *url;
+    while (c != '/' && c != ':' && c != '\0' && c != ' ' && c != '\t') {
+	url++;
+	c = *url;
+    }
+    len = url - save;
+    hostname = PORT_Alloc(len + 1);
+    if (hostname == NULL)
+	goto loser;
+    PORT_Memcpy(hostname, save, len);
+    hostname[len] = '\0';
+
+    /*
+     * Now we figure out if there was a port specified or not.
+     * If so, we need to parse it (as a number) and skip it.
+     */
+    if (c == ':') {
+	url++;
+	port = (unsigned short) PORT_Atoi(url);
+	c = *url;
+	while (c != '/' && c != '\0' && c != ' ' && c != '\t') {
+	    if (c < '0' || c > '9')
+		goto loser;
+	    url++;
+	    c = *url;
+	}
+    }
+
+    /*
+     * Last thing to find is a path.  There *should* be a slash,
+     * if nothing else -- but if there is not we provide one.
+     */
+    if (c == '/') {
+	save = url;
+	while (c != '\0' && c != ' ' && c != '\t') {
+	    url++;
+	    c = *url;
+	}
+	len = url - save;
+	path = PORT_Alloc(len + 1);
+	if (path == NULL)
+	    goto loser;
+	PORT_Memcpy(path, save, len);
+	path[len] = '\0';
+    } else {
+	path = PORT_Strdup("/");
+	if (path == NULL)
+	    goto loser;
+    }
+
+    *pHostname = hostname;
+    *pPort = port;
+    *pPath = path;
+    return SECSuccess;
+
+loser:
+    if (hostname != NULL)
+	PORT_Free(hostname);
+    PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+    return SECFailure;
+}
+
+/*
+ * Open a socket to the specified host on the specified port, and return it.
+ * The host is either a hostname or an IP address.
+ */
+static PRFileDesc *
+ocsp_ConnectToHost(const char *host, PRUint16 port)
+{
+    PRFileDesc *sock = NULL;
+    PRIntervalTime timeout;
+    PRNetAddr addr;
+    char *netdbbuf = NULL;
+
+    sock = PR_NewTCPSocket();
+    if (sock == NULL)
+	goto loser;
+
+    /* XXX Some day need a way to set (and get?) the following value */
+    timeout = PR_SecondsToInterval(30);
+
+    /*
+     * If the following converts an IP address string in "dot notation"
+     * into a PRNetAddr.  If it fails, we assume that is because we do not
+     * have such an address, but instead a host *name*.  In that case we
+     * then lookup the host by name.  Using the NSPR function this way
+     * means we do not have to have our own logic for distinguishing a
+     * valid numerical IP address from a hostname.
+     */
+    if (PR_StringToNetAddr(host, &addr) != PR_SUCCESS) {
+	PRIntn hostIndex;
+	PRHostEnt hostEntry;
+
+	netdbbuf = PORT_Alloc(PR_NETDB_BUF_SIZE);
+	if (netdbbuf == NULL)
+	    goto loser;
+
+	if (PR_GetHostByName(host, netdbbuf, PR_NETDB_BUF_SIZE,
+			     &hostEntry) != PR_SUCCESS)
+	    goto loser;
+
+	hostIndex = 0;
+	do {
+	    hostIndex = PR_EnumerateHostEnt(hostIndex, &hostEntry, port, &addr);
+	    if (hostIndex <= 0)
+		goto loser;
+	} while (PR_Connect(sock, &addr, timeout) != PR_SUCCESS);
+
+	PORT_Free(netdbbuf);
+    } else {
+	/*
+	 * First put the port into the address, then connect.
+	 */
+	if (PR_InitializeNetAddr(PR_IpAddrNull, port, &addr) != PR_SUCCESS)
+	    goto loser;
+	if (PR_Connect(sock, &addr, timeout) != PR_SUCCESS)
+	    goto loser;
+    }
+
+    return sock;
+
+loser:
+    if (sock != NULL)
+	PR_Close(sock);
+    if (netdbbuf != NULL)
+	PORT_Free(netdbbuf);
+    return NULL;
+}
+
+/*
+ * Sends an encoded OCSP request to the server identified by "location",
+ * and returns the socket on which it was sent (so can listen for the reply).
+ * "location" is expected to be a valid URL -- an error parsing it produces
+ * SEC_ERROR_CERT_BAD_ACCESS_LOCATION.  Other errors are likely problems
+ * connecting to it, or writing to it, or allocating memory, and the low-level
+ * errors appropriate to the problem will be set.
+ */
+static PRFileDesc *
+ocsp_SendEncodedRequest(char *location, SECItem *encodedRequest)
+{
+    char *hostname = NULL;
+    char *path = NULL;
+    PRUint16 port;
+    SECStatus rv;
+    PRFileDesc *sock = NULL;
+    PRFileDesc *returnSock = NULL;
+    char *header = NULL;
+
+    /*
+     * Take apart the location, getting the hostname, port, and path.
+     */
+    rv = ocsp_ParseURL(location, &hostname, &port, &path);
+    if (rv != SECSuccess)
+	goto loser;
+
+    PORT_Assert(hostname != NULL);
+    PORT_Assert(path != NULL);
+
+    sock = ocsp_ConnectToHost(hostname, port);
+    if (sock == NULL)
+	goto loser;
+
+    header = PR_smprintf("POST %s HTTP/1.0\r\n"
+			 "Host: %s:%d\r\n"
+			 "Content-Type: application/ocsp-request\r\n"
+			 "Content-Length: %u\r\n\r\n",
+			 path, hostname, port, encodedRequest->len);
+    if (header == NULL)
+	goto loser;
+
+    /*
+     * The NSPR documentation promises that if it can, it will write the full
+     * amount; this will not return a partial value expecting us to loop.
+     */
+    if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0)
+	goto loser;
+
+    if (PR_Write(sock, encodedRequest->data,
+		 (PRInt32) encodedRequest->len) < 0)
+	goto loser;
+
+    returnSock = sock;
+    sock = NULL;
+
+loser:
+    if (header != NULL)
+	PORT_Free(header);
+    if (sock != NULL)
+	PR_Close(sock);
+    if (path != NULL)
+	PORT_Free(path);
+    if (hostname != NULL)
+	PORT_Free(hostname);
+
+    return returnSock;
+}
+
+/*
+ * Read from "fd" into "buf" -- expect/attempt to read a given number of bytes
+ * Obviously, stop if hit end-of-stream. Timeout is passed in.
+ */
+
+static int
+ocsp_read(PRFileDesc *fd, char *buf, int toread, PRIntervalTime timeout)
+{
+    int total = 0;
+
+    while (total < toread)
+    {
+        PRInt32 got;
+
+        got = PR_Recv(fd, buf + total, (PRInt32) (toread - total), 0, timeout);
+        if (got < 0)
+        {
+            if (0 == total)
+            {
+                total = -1; /* report the error if we didn't read anything yet */
+            }
+            break;
+        }
+        else
+        if (got == 0)
+        {			/* EOS */
+            break;
+        }
+
+        total += got;
+    }
+
+    return total;
+}
+
+#define OCSP_BUFSIZE 1024
+
+#define AbortHttpDecode(error) \
+{ \
+        if (inBuffer) \
+            PORT_Free(inBuffer); \
+        PORT_SetError(error); \
+        return NULL; \
+}
+
+
+/*
+ * Reads on the given socket and returns an encoded response when received.
+ * Properly formatted HTTP/1.0 response headers are expected to be read
+ * from the socket, preceding a binary-encoded OCSP response.  Problems
+ * with parsing cause the error SEC_ERROR_OCSP_BAD_HTTP_RESPONSE to be
+ * set; any other problems are likely low-level i/o or memory allocation
+ * errors.
+ */
+static SECItem *
+ocsp_GetEncodedResponse(PRArenaPool *arena, PRFileDesc *sock)
+{
+    /* first read HTTP status line and headers */
+
+    char* inBuffer = NULL;
+    PRInt32 offset = 0;
+    PRInt32 inBufsize = 0;
+    const PRInt32 bufSizeIncrement = OCSP_BUFSIZE; /* 1 KB at a time */
+    const PRInt32 maxBufSize = 8 * bufSizeIncrement ; /* 8 KB max */
+    const char* CRLF = "\r\n";
+    const PRInt32 CRLFlen = strlen(CRLF);
+    const char* headerEndMark = "\r\n\r\n";
+    const PRInt32 markLen = strlen(headerEndMark);
+    const PRIntervalTime ocsptimeout =
+        PR_SecondsToInterval(30); /* hardcoded to 30s for now */
+    char* headerEnd = NULL;
+    PRBool EOS = PR_FALSE;
+    const char* httpprotocol = "HTTP/";
+    const PRInt32 httplen = strlen(httpprotocol);
+    const char* httpcode = NULL;
+    const char* contenttype = NULL;
+    PRInt32 contentlength = 0;
+    PRInt32 bytesRead = 0;
+    char* statusLineEnd = NULL;
+    char* space = NULL;
+    char* nextHeader = NULL;
+    SECItem* result = NULL;
+
+    /* read up to at least the end of the HTTP headers */
+    do
+    {
+        inBufsize += bufSizeIncrement;
+        inBuffer = PORT_Realloc(inBuffer, inBufsize+1);
+        if (NULL == inBuffer)
+        {
+            AbortHttpDecode(SEC_ERROR_NO_MEMORY);
+        }
+        bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement,
+            ocsptimeout);
+        if (bytesRead > 0)
+        {
+            PRInt32 searchOffset = (offset - markLen) >0 ? offset-markLen : 0;
+            offset += bytesRead;
+            *(inBuffer + offset) = '\0'; /* NULL termination */
+            headerEnd = strstr((const char*)inBuffer + searchOffset, headerEndMark);
+            if (bytesRead < bufSizeIncrement)
+            {
+                /* we read less data than requested, therefore we are at
+                   EOS or there was a read error */
+                EOS = PR_TRUE;
+            }
+        }
+        else
+        {
+            /* recv error or EOS */
+            EOS = PR_TRUE;
+        }
+    } while ( (!headerEnd) && (PR_FALSE == EOS) &&
+              (inBufsize < maxBufSize) );
+
+    if (!headerEnd)
+    {
+        AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+    }
+
+    /* parse the HTTP status line  */
+    statusLineEnd = strstr((const char*)inBuffer, CRLF);
+    if (!statusLineEnd)
+    {
+        AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+    }
+    *statusLineEnd = '\0';
+
+    /* check for HTTP/ response */
+    space = strchr((const char*)inBuffer, ' ');
+    if (!space || PORT_Strncasecmp((const char*)inBuffer, httpprotocol, httplen) != 0 )
+    {
+        AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+    }
+
+    /* check the HTTP status code of 200 */
+    httpcode = space +1;
+    space = strchr(httpcode, ' ');
+    if (!space)
+    {
+        AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+    }
+    *space = 0;
+    if (0 != strcmp(httpcode, "200"))
+    {
+        AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+    }
+
+    /* parse the HTTP headers in the buffer . We only care about
+       content-type and content-length
+    */
+
+    nextHeader = statusLineEnd + CRLFlen;
+    *headerEnd = '\0'; /* terminate */
+    do
+    {
+        char* thisHeaderEnd = NULL;
+        char* value = NULL;
+        char* colon = strchr(nextHeader, ':');
+        
+        if (!colon)
+        {
+            AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+        }
+
+        *colon = '\0';
+        value = colon + 1;
+
+        /* jpierre - note : the following code will only handle the basic form
+           of HTTP/1.0 response headers, of the form "name: value" . Headers
+           split among multiple lines are not supported. This is not common
+           and should not be an issue, but it could become one in the
+           future */
+
+        if (*value != ' ')
+        {
+            AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+        }
+
+        value++;
+        thisHeaderEnd  = strstr(value, CRLF);
+        if (thisHeaderEnd )
+        {
+            *thisHeaderEnd  = '\0';
+        }
+
+        if (0 == PORT_Strcasecmp(nextHeader, "content-type"))
+        {
+            contenttype = value;
+        }
+        else
+        if (0 == PORT_Strcasecmp(nextHeader, "content-length"))
+        {
+            contentlength = atoi(value);
+        }
+
+        if (thisHeaderEnd )
+        {
+            nextHeader = thisHeaderEnd + CRLFlen;
+        }
+        else
+        {
+            nextHeader = NULL;
+        }
+
+    } while (nextHeader && (nextHeader < (headerEnd + CRLFlen) ) );
+
+    /* check content-type */
+    if (!contenttype ||
+        (0 != PORT_Strcasecmp(contenttype, "application/ocsp-response")) )
+    {
+        AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+    }
+
+    /* read the body of the OCSP response */
+    offset = offset - (PRInt32) (headerEnd - (const char*)inBuffer) - markLen;
+    if (offset)
+    {
+        /* move all data to the beginning of the buffer */
+        PORT_Memmove(inBuffer, headerEnd + markLen, offset);
+    }
+
+    /* resize buffer to only what's needed to hold the current response */
+    inBufsize = (1 + (offset-1) / bufSizeIncrement ) * bufSizeIncrement ;
+
+    while ( (PR_FALSE == EOS) &&
+            ( (contentlength == 0) || (offset < contentlength) ) &&
+            (inBufsize < maxBufSize)
+            )
+    {
+        /* we still need to receive more body data */
+        inBufsize += bufSizeIncrement;
+        inBuffer = PORT_Realloc(inBuffer, inBufsize+1);
+        if (NULL == inBuffer)
+        {
+            AbortHttpDecode(SEC_ERROR_NO_MEMORY);
+        }
+        bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement,
+                              ocsptimeout);
+        if (bytesRead > 0)
+        {
+            offset += bytesRead;
+            if (bytesRead < bufSizeIncrement)
+            {
+                /* we read less data than requested, therefore we are at
+                   EOS or there was a read error */
+                EOS = PR_TRUE;
+            }
+        }
+        else
+        {
+            /* recv error or EOS */
+            EOS = PR_TRUE;
+        }
+    }
+
+    if (0 == offset)
+    {
+        AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+    }
+
+    /*
+     * Now allocate the item to hold the data.
+     */
+    result = SECITEM_AllocItem(arena, NULL, offset);
+    if (NULL == result)
+    {
+        AbortHttpDecode(SEC_ERROR_NO_MEMORY);
+    }
+
+    /*
+     * And copy the data left in the buffer.
+    */
+    PORT_Memcpy(result->data, inBuffer, offset);
+
+    /* and free the temporary buffer */
+    PORT_Free(inBuffer);
+    return result;
+}
+
+SECStatus
+CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath)
+{
+    return ocsp_ParseURL(url, pHostname, pPort, pPath);
+}
+
+/*
+ * Limit the size of http responses we are willing to accept.
+ */
+#define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024
+
+static SECItem *
+fetchOcspHttpClientV1(PRArenaPool *arena, 
+                      const SEC_HttpClientFcnV1 *hcv1, 
+                      char *location, 
+                      SECItem *encodedRequest)
+{
+    char *hostname = NULL;
+    char *path = NULL;
+    PRUint16 port;
+    SECItem *encodedResponse = NULL;
+    SEC_HTTP_SERVER_SESSION pServerSession = NULL;
+    SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
+    PRUint16 myHttpResponseCode;
+    const char *myHttpResponseData;
+    PRUint32 myHttpResponseDataLen;
+
+    if (ocsp_ParseURL(location, &hostname, &port, &path) == SECFailure) {
+        PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
+        goto loser;
+    }
+    
+    PORT_Assert(hostname != NULL);
+    PORT_Assert(path != NULL);
+
+    if ((*hcv1->createSessionFcn)(
+            hostname, 
+            port, 
+            &pServerSession) != SECSuccess) {
+        PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+        goto loser;
+    }
+
+    /* We use a non-zero timeout, which means:
+       - the client will use blocking I/O
+       - TryFcn will not return WOULD_BLOCK nor a poll descriptor
+       - it's sufficient to call TryFcn once
+       No lock for accessing OCSP_Global.timeoutSeconds, bug 406120
+    */
+
+    if ((*hcv1->createFcn)(
+            pServerSession,
+            "http",
+            path,
+            "POST",
+            PR_TicksPerSecond() * OCSP_Global.timeoutSeconds,
+            &pRequestSession) != SECSuccess) {
+        PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+        goto loser;
+    }
+
+    if ((*hcv1->setPostDataFcn)(
+            pRequestSession, 
+            (char*)encodedRequest->data,
+            encodedRequest->len,
+            "application/ocsp-request") != SECSuccess) {
+        PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+        goto loser;
+    }
+
+    /* we don't want result objects larger than this: */
+    myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN;
+
+    OCSP_TRACE(("OCSP trySendAndReceive %s\n", location));
+
+    if ((*hcv1->trySendAndReceiveFcn)(
+            pRequestSession, 
+            NULL,
+            &myHttpResponseCode,
+            NULL,
+            NULL,
+            &myHttpResponseData,
+            &myHttpResponseDataLen) != SECSuccess) {
+        PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+        goto loser;
+    }
+
+    OCSP_TRACE(("OCSP trySendAndReceive result http %d\n", myHttpResponseCode));
+
+    if (myHttpResponseCode != 200) {
+        PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+        goto loser;
+    }
+
+    encodedResponse = SECITEM_AllocItem(arena, NULL, myHttpResponseDataLen);
+
+    if (!encodedResponse) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        goto loser;
+    }
+
+    PORT_Memcpy(encodedResponse->data, myHttpResponseData, myHttpResponseDataLen);
+
+loser:
+    if (pRequestSession != NULL) 
+        (*hcv1->freeFcn)(pRequestSession);
+    if (pServerSession != NULL)
+        (*hcv1->freeSessionFcn)(pServerSession);
+    if (path != NULL)
+	PORT_Free(path);
+    if (hostname != NULL)
+	PORT_Free(hostname);
+    
+    return encodedResponse;
+}
+
+/*
+ * FUNCTION: CERT_GetEncodedOCSPResponse
+ *   Creates and sends a request to an OCSP responder, then reads and
+ *   returns the (encoded) response.
+ * INPUTS:
+ *   PRArenaPool *arena
+ *     Pointer to arena from which return value will be allocated.
+ *     If NULL, result will be allocated from the heap (and thus should
+ *     be freed via SECITEM_FreeItem).
+ *   CERTCertList *certList
+ *     A list of certs for which status will be requested.
+ *     Note that all of these certificates should have the same issuer,
+ *     or it's expected the response will be signed by a trusted responder.
+ *     If the certs need to be broken up into multiple requests, that
+ *     must be handled by the caller (and thus by having multiple calls
+ *     to this routine), who knows about where the request(s) are being
+ *     sent and whether there are any trusted responders in place.
+ *   char *location
+ *     The location of the OCSP responder (a URL).
+ *   int64 time
+ *     Indicates the time for which the certificate status is to be 
+ *     determined -- this may be used in the search for the cert's issuer
+ *     but has no other bearing on the operation.
+ *   PRBool addServiceLocator
+ *     If true, the Service Locator extension should be added to the
+ *     single request(s) for each cert.
+ *   CERTCertificate *signerCert
+ *     If non-NULL, means sign the request using this cert.  Otherwise,
+ *     do not sign.
+ *   void *pwArg
+ *     Pointer to argument for password prompting, if needed.  (Definitely
+ *     not needed if not signing.)
+ * OUTPUTS:
+ *   CERTOCSPRequest **pRequest
+ *     Pointer in which to store the OCSP request created for the given
+ *     list of certificates.  It is only filled in if the entire operation
+ *     is successful and the pointer is not null -- and in that case the
+ *     caller is then reponsible for destroying it.
+ * RETURN:
+ *   Returns a pointer to the SECItem holding the response.
+ *   On error, returns null with error set describing the reason:
+ *	SEC_ERROR_UNKNOWN_ISSUER
+ *	SEC_ERROR_CERT_BAD_ACCESS_LOCATION
+ *	SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
+ *   Other errors are low-level problems (no memory, bad database, etc.).
+ */
+SECItem *
+CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList,
+			    char *location, int64 time,
+			    PRBool addServiceLocator,
+			    CERTCertificate *signerCert, void *pwArg,
+			    CERTOCSPRequest **pRequest)
+{
+    CERTOCSPRequest *request;
+    request = CERT_CreateOCSPRequest(certList, time, addServiceLocator,
+                                     signerCert);
+    if (!request)
+        return NULL;
+    return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, 
+                                                  time, addServiceLocator, 
+                                                  pwArg, pRequest);
+}
+
+static SECItem *
+ocsp_GetEncodedOCSPResponseFromRequest(PRArenaPool *arena, 
+                                       CERTOCSPRequest *request,
+                                       char *location, int64 time,
+                                       PRBool addServiceLocator,
+                                       void *pwArg,
+                                       CERTOCSPRequest **pRequest)
+{
+    SECItem *encodedRequest = NULL;
+    SECItem *encodedResponse = NULL;
+    PRFileDesc *sock = NULL;
+    SECStatus rv;
+    const SEC_HttpClientFcn *registeredHttpClient = NULL;
+
+    rv = CERT_AddOCSPAcceptableResponses(request,
+					 SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
+    if (rv != SECSuccess)
+	goto loser;
+
+    encodedRequest = CERT_EncodeOCSPRequest(NULL, request, pwArg);
+    if (encodedRequest == NULL)
+	goto loser;
+
+    registeredHttpClient = SEC_GetRegisteredHttpClient();
+
+    if (registeredHttpClient
+            &&
+            registeredHttpClient->version == 1) {
+        encodedResponse = fetchOcspHttpClientV1(
+                              arena,
+                              &registeredHttpClient->fcnTable.ftable1,
+                              location,
+                              encodedRequest);
+    }
+    else {
+      /* use internal http client */
+    
+      sock = ocsp_SendEncodedRequest(location, encodedRequest);
+      if (sock == NULL)
+	  goto loser;
+
+      encodedResponse = ocsp_GetEncodedResponse(arena, sock);
+    }
+
+    if (encodedResponse != NULL && pRequest != NULL) {
+	*pRequest = request;
+	request = NULL;			/* avoid destroying below */
+    }
+
+loser:
+    if (request != NULL)
+	CERT_DestroyOCSPRequest(request);
+    if (encodedRequest != NULL)
+	SECITEM_FreeItem(encodedRequest, PR_TRUE);
+    if (sock != NULL)
+	PR_Close(sock);
+
+    return encodedResponse;
+}
+
+static SECItem *
+ocsp_GetEncodedOCSPResponseForSingleCert(PRArenaPool *arena, 
+                                         CERTOCSPCertID *certID, 
+                                         CERTCertificate *singleCert, 
+                                         char *location, int64 time,
+                                         PRBool addServiceLocator,
+                                         void *pwArg,
+                                         CERTOCSPRequest **pRequest)
+{
+    CERTOCSPRequest *request;
+    request = cert_CreateSingleCertOCSPRequest(certID, singleCert, time, 
+                                               addServiceLocator, NULL);
+    if (!request)
+        return NULL;
+    return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, 
+                                                  time, addServiceLocator, 
+                                                  pwArg, pRequest);
+}
+
+/* Checks a certificate for the key usage extension of OCSP signer. */
+static PRBool
+ocsp_CertIsOCSPDesignatedResponder(CERTCertificate *cert)
+{
+    SECStatus rv;
+    SECItem extItem;
+    SECItem **oids;
+    SECItem *oid;
+    SECOidTag oidTag;
+    PRBool retval;
+    CERTOidSequence *oidSeq = NULL;
+
+
+    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 ) {
+	oid = *oids;
+	
+	oidTag = SECOID_FindOIDTag(oid);
+	
+	if ( oidTag == SEC_OID_OCSP_RESPONDER ) {
+	    goto success;
+	}
+	
+	oids++;
+    }
+
+loser:
+    retval = PR_FALSE;
+    PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+    goto done;
+success:
+    retval = PR_TRUE;
+done:
+    if ( extItem.data != NULL ) {
+	PORT_Free(extItem.data);
+    }
+    if ( oidSeq != NULL ) {
+	CERT_DestroyOidSequence(oidSeq);
+    }
+    
+    return(retval);
+}
+
+
+#ifdef LATER	/*
+		 * XXX This function is not currently used, but will
+		 * be needed later when we do revocation checking of
+		 * the responder certificate.  Of course, it may need
+		 * revising then, if the cert extension interface has
+		 * changed.  (Hopefully it will!)
+		 */
+
+/* Checks a certificate to see if it has the OCSP no check extension. */
+static PRBool
+ocsp_CertHasNoCheckExtension(CERTCertificate *cert)
+{
+    SECStatus rv;
+    
+    rv = CERT_FindCertExtension(cert, SEC_OID_PKIX_OCSP_NO_CHECK, 
+				NULL);
+    if (rv == SECSuccess) {
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+#endif	/* LATER */
+
+static PRBool
+ocsp_matchcert(SECItem *certIndex,CERTCertificate *testCert)
+{
+    SECItem item;
+    unsigned char buf[HASH_LENGTH_MAX];
+
+    item.data = buf;
+    item.len = SHA1_LENGTH;
+
+    if (CERT_GetSPKIDigest(NULL,testCert,SEC_OID_SHA1, &item) == NULL) {
+	return PR_FALSE;
+    }
+    if  (SECITEM_ItemsAreEqual(certIndex,&item)) {
+	return PR_TRUE;
+    }
+    if (CERT_GetSPKIDigest(NULL,testCert,SEC_OID_MD5, &item) == NULL) {
+	return PR_FALSE;
+    }
+    if  (SECITEM_ItemsAreEqual(certIndex,&item)) {
+	return PR_TRUE;
+    }
+    if (CERT_GetSPKIDigest(NULL,testCert,SEC_OID_MD2, &item) == NULL) {
+	return PR_FALSE;
+    }
+    if  (SECITEM_ItemsAreEqual(certIndex,&item)) {
+	return PR_TRUE;
+    }
+
+    return PR_FALSE;
+}
+
+static CERTCertificate *
+ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle,CERTOCSPCertID *certID);
+
+CERTCertificate *
+ocsp_GetSignerCertificate(CERTCertDBHandle *handle, ocspResponseData *tbsData,
+                          ocspSignature *signature, CERTCertificate *issuer)
+{
+    CERTCertificate **certs = NULL;
+    CERTCertificate *signerCert = NULL;
+    SECStatus rv = SECFailure;
+    PRBool lookupByName = PR_TRUE;
+    void *certIndex = NULL;
+    int certCount = 0;
+
+    PORT_Assert(tbsData->responderID != NULL);
+    switch (tbsData->responderID->responderIDType) {
+    case ocspResponderID_byName:
+	lookupByName = PR_TRUE;
+	certIndex = &tbsData->derResponderID;
+	break;
+    case ocspResponderID_byKey:
+	lookupByName = PR_FALSE;
+	certIndex = &tbsData->responderID->responderIDValue.keyHash;
+	break;
+    case ocspResponderID_other:
+    default:
+	PORT_Assert(0);
+	PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+	return NULL;
+    }
+
+    /*
+     * If the signature contains some certificates as well, temporarily
+     * import them in case they are needed for verification.
+     *
+     * Note that the result of this is that each cert in "certs" needs
+     * to be destroyed.
+     */
+    if (signature->derCerts != NULL) {
+	for (; signature->derCerts[certCount] != NULL; certCount++) {
+	    /* just counting */
+	}
+	rv = CERT_ImportCerts(handle, certUsageStatusResponder, certCount,
+	                      signature->derCerts, &certs,
+	                      PR_FALSE, PR_FALSE, NULL);
+	if (rv != SECSuccess)
+	     goto finish;
+    }
+
+    /*
+     * Now look up the certificate that did the signing.
+     * The signer can be specified either by name or by key hash.
+     */
+    if (lookupByName) {
+	SECItem *crIndex = (SECItem*)certIndex;
+	SECItem encodedName;
+	PLArenaPool *arena;
+
+	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+	if (arena != NULL) {
+
+	    rv = SEC_QuickDERDecodeItem(arena, &encodedName,
+	                                ocsp_ResponderIDDerNameTemplate,
+	                                crIndex);
+	    if (rv != SECSuccess) {
+	        if (PORT_GetError() == SEC_ERROR_BAD_DER)
+	            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+	    } else {
+	            signerCert = CERT_FindCertByName(handle, &encodedName);
+	    }
+	    PORT_FreeArena(arena, PR_FALSE);
+	}
+    } else {
+	/*
+	 * The signer is either 1) a known issuer CA we passed in,
+	 * 2) the default OCSP responder, or 3) an intermediate CA
+	 * passed in the cert list to use. Figure out which it is.
+	 */
+	int i;
+	CERTCertificate *responder = 
+            ocsp_CertGetDefaultResponder(handle, NULL);
+	if (responder && ocsp_matchcert(certIndex,responder)) {
+	    signerCert = CERT_DupCertificate(responder);
+	} else if (issuer && ocsp_matchcert(certIndex,issuer)) {
+	    signerCert = CERT_DupCertificate(issuer);
+	} 
+	for (i=0; (signerCert == NULL) && (i < certCount); i++) {
+	    if (ocsp_matchcert(certIndex,certs[i])) {
+		signerCert = CERT_DupCertificate(certs[i]);
+	    }
+	}
+    }
+
+finish:
+    if (certs != NULL) {
+	CERT_DestroyCertArray(certs, certCount);
+    }
+
+    return signerCert;
+}
+
+SECStatus
+ocsp_VerifyResponseSignature(CERTCertificate *signerCert,
+                             ocspSignature *signature,
+                             SECItem *tbsResponseDataDER,
+                             void *pwArg)
+{
+    SECItem rawSignature;
+    SECKEYPublicKey *signerKey = NULL;
+    SECStatus rv = SECFailure;
+
+    /*
+     * Now get the public key from the signer's certificate; we need
+     * it to perform the verification.
+     */
+    signerKey = CERT_ExtractPublicKey(signerCert);
+    if (signerKey == NULL)
+	return SECFailure;
+    /*
+     * We copy the signature data *pointer* and length, so that we can
+     * modify the length without damaging the original copy.  This is a
+     * simple copy, not a dup, so no destroy/free is necessary.
+     */
+    rawSignature = signature->signature;
+    /*
+     * The raw signature is a bit string, but we need to represent its
+     * length in bytes, because that is what the verify function expects.
+     */
+    DER_ConvertBitString(&rawSignature);
+
+    rv = VFY_VerifyDataWithAlgorithmID(tbsResponseDataDER->data,
+                                       tbsResponseDataDER->len,
+                                       signerKey, &rawSignature,
+                                       &signature->signatureAlgorithm,
+                                       NULL, pwArg);
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) {
+        PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE);
+    }
+    
+    if (signerKey != NULL) {
+        SECKEY_DestroyPublicKey(signerKey);
+    }
+
+    return rv;
+}
+
+
+/*
+ * FUNCTION: CERT_VerifyOCSPResponseSignature
+ *   Check the signature on an OCSP Response.  Will also perform a
+ *   verification of the signer's certificate.  Note, however, that a
+ *   successful verification does not make any statement about the
+ *   signer's *authority* to provide status for the certificate(s),
+ *   that must be checked individually for each certificate.
+ * INPUTS:
+ *   CERTOCSPResponse *response
+ *     Pointer to response structure with signature to be checked.
+ *   CERTCertDBHandle *handle
+ *     Pointer to CERTCertDBHandle for certificate DB to use for verification.
+ *   void *pwArg
+ *     Pointer to argument for password prompting, if needed.
+ * OUTPUTS:
+ *   CERTCertificate **pSignerCert
+ *     Pointer in which to store signer's certificate; only filled-in if
+ *     non-null.
+ * RETURN:
+ *   Returns SECSuccess when signature is valid, anything else means invalid.
+ *   Possible errors set:
+ *	SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID
+ *	SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time
+ *	SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found
+ *	SEC_ERROR_BAD_SIGNATURE - the signature did not verify
+ *   Other errors are any of the many possible failures in cert verification
+ *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
+ *   verifying the signer's cert, or low-level problems (no memory, etc.)
+ */
+SECStatus
+CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response,	
+				 CERTCertDBHandle *handle, void *pwArg,
+				 CERTCertificate **pSignerCert,
+				 CERTCertificate *issuer)
+{
+    SECItem *tbsResponseDataDER;
+    CERTCertificate *signerCert = NULL;
+    SECStatus rv = SECFailure;
+    int64 producedAt;
+
+    /* ocsp_DecodeBasicOCSPResponse will fail if asn1 decoder is unable
+     * to properly decode tbsData (see the function and
+     * ocsp_BasicOCSPResponseTemplate). Thus, tbsData can not be
+     * equal to null */
+    ocspResponseData *tbsData = ocsp_GetResponseData(response,
+                                                     &tbsResponseDataDER);
+    ocspSignature *signature = ocsp_GetResponseSignature(response);
+
+    if (!signature) {
+        PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE);
+        return SECFailure;
+    }
+
+    /*
+     * If this signature has already gone through verification, just
+     * return the cached result.
+     */
+    if (signature->wasChecked) {
+	if (signature->status == SECSuccess) {
+	    if (pSignerCert != NULL)
+		*pSignerCert = CERT_DupCertificate(signature->cert);
+	} else {
+	    PORT_SetError(signature->failureReason);
+	}
+	return signature->status;
+    }
+
+    signerCert = ocsp_GetSignerCertificate(handle, tbsData,
+                                           signature, issuer);
+    if (signerCert == NULL) {
+	rv = SECFailure;
+	if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) {
+	    /* Make the error a little more specific. */
+	    PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+	}
+	goto finish;
+    }
+
+    /*
+     * We could mark this true at the top of this function, or always
+     * below at "finish", but if the problem was just that we could not
+     * find the signer's cert, leave that as if the signature hasn't
+     * been checked in case a subsequent call might have better luck.
+     */
+    signature->wasChecked = PR_TRUE;
+
+    /*
+     * The function will also verify the signer certificate; we
+     * need to tell it *when* that certificate must be valid -- for our
+     * purposes we expect it to be valid when the response was signed.
+     * The value of "producedAt" is the signing time.
+     */
+    rv = DER_GeneralizedTimeToTime(&producedAt, &tbsData->producedAt);
+    if (rv != SECSuccess)
+        goto finish;
+
+    /*
+     * Just because we have a cert does not mean it is any good; check
+     * it for validity, trust and usage.
+     */
+    if (ocsp_CertIsOCSPDefaultResponder(handle, signerCert)) {
+        rv = SECSuccess;
+    } else {
+        SECCertUsage certUsage;
+        if (CERT_IsCACert(signerCert, NULL)) {
+            certUsage = certUsageAnyCA;
+        } else {
+            certUsage = certUsageStatusResponder;
+        }
+        rv = CERT_VerifyCert(handle, signerCert, PR_TRUE,
+                             certUsage, producedAt, pwArg, NULL);
+        if (rv != SECSuccess) {
+            PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+            goto finish;
+        }
+    }
+
+    rv = ocsp_VerifyResponseSignature(signerCert, signature,
+                                      tbsResponseDataDER,
+                                      pwArg);
+
+finish:
+    if (signature->wasChecked)
+	signature->status = rv;
+
+    if (rv != SECSuccess) {
+	signature->failureReason = PORT_GetError();
+	if (signerCert != NULL)
+	    CERT_DestroyCertificate(signerCert);
+    } else {
+	/*
+	 * Save signer's certificate in signature.
+	 */
+	signature->cert = signerCert;
+	if (pSignerCert != NULL) {
+	    /*
+	     * Pass pointer to signer's certificate back to our caller,
+	     * who is also now responsible for destroying it.
+	     */
+	    *pSignerCert = CERT_DupCertificate(signerCert);
+	}
+    }
+
+    return rv;
+}
+
+/*
+ * See if the request's certID and the single response's certID match.
+ * This can be easy or difficult, depending on whether the same hash
+ * algorithm was used.
+ */
+static PRBool
+ocsp_CertIDsMatch(CERTCertDBHandle *handle,
+		  CERTOCSPCertID *requestCertID,
+		  CERTOCSPCertID *responseCertID)
+{
+    PRBool match = PR_FALSE;
+    SECOidTag hashAlg;
+    SECItem *keyHash = NULL;
+    SECItem *nameHash = NULL;
+
+    /*
+     * In order to match, they must have the same issuer and the same
+     * serial number.
+     *
+     * We just compare the easier things first.
+     */
+    if (SECITEM_CompareItem(&requestCertID->serialNumber,
+			    &responseCertID->serialNumber) != SECEqual) {
+	goto done;
+    }
+
+    /*
+     * Make sure the "parameters" are not too bogus.  Since we encoded
+     * requestCertID->hashAlgorithm, we don't need to check it.
+     */
+    if (responseCertID->hashAlgorithm.parameters.len > 2) {
+	goto done;
+    }
+    if (SECITEM_CompareItem(&requestCertID->hashAlgorithm.algorithm,
+		&responseCertID->hashAlgorithm.algorithm) == SECEqual) {
+	/*
+	 * If the hash algorithms match then we can do a simple compare
+	 * of the hash values themselves.
+	 */
+	if ((SECITEM_CompareItem(&requestCertID->issuerNameHash,
+				&responseCertID->issuerNameHash) == SECEqual)
+	    && (SECITEM_CompareItem(&requestCertID->issuerKeyHash,
+				&responseCertID->issuerKeyHash) == SECEqual)) {
+	    match = PR_TRUE;
+	}
+	goto done;
+    }
+
+    hashAlg = SECOID_FindOIDTag(&responseCertID->hashAlgorithm.algorithm);
+    switch (hashAlg) {
+    case SEC_OID_SHA1:
+	keyHash = &requestCertID->issuerSHA1KeyHash;
+	nameHash = &requestCertID->issuerSHA1NameHash;
+	break;
+    case SEC_OID_MD5:
+	keyHash = &requestCertID->issuerMD5KeyHash;
+	nameHash = &requestCertID->issuerMD5NameHash;
+	break;
+    case SEC_OID_MD2:
+	keyHash = &requestCertID->issuerMD2KeyHash;
+	nameHash = &requestCertID->issuerMD2NameHash;
+	break;
+    default:
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ 	return SECFailure;
+    }
+
+    if ((keyHash != NULL)
+	&& (SECITEM_CompareItem(nameHash,
+				&responseCertID->issuerNameHash) == SECEqual)
+	&& (SECITEM_CompareItem(keyHash,
+				&responseCertID->issuerKeyHash) == SECEqual)) {
+	match = PR_TRUE;
+    }
+
+done:
+    return match;
+}
+
+/*
+ * Find the single response for the cert specified by certID.
+ * No copying is done; this just returns a pointer to the appropriate
+ * response within responses, if it is found (and null otherwise).
+ * This is fine, of course, since this function is internal-use only.
+ */
+static CERTOCSPSingleResponse *
+ocsp_GetSingleResponseForCertID(CERTOCSPSingleResponse **responses,
+				CERTCertDBHandle *handle,
+				CERTOCSPCertID *certID)
+{
+    CERTOCSPSingleResponse *single;
+    int i;
+
+    if (responses == NULL)
+	return NULL;
+
+    for (i = 0; responses[i] != NULL; i++) {
+	single = responses[i];
+	if (ocsp_CertIDsMatch(handle, certID, single->certID)) {
+	    return single;
+	}
+    }
+
+    /*
+     * The OCSP server should have included a response even if it knew
+     * nothing about the certificate in question.  Since it did not,
+     * this will make it look as if it had.
+     * 
+     * XXX Should we make this a separate error to notice the server's
+     * bad behavior?
+     */
+    PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT);
+    return NULL;
+}
+
+static ocspCheckingContext *
+ocsp_GetCheckingContext(CERTCertDBHandle *handle)
+{
+    CERTStatusConfig *statusConfig;
+    ocspCheckingContext *ocspcx = NULL;
+
+    statusConfig = CERT_GetStatusConfig(handle);
+    if (statusConfig != NULL) {
+	ocspcx = statusConfig->statusContext;
+
+	/*
+	 * This is actually an internal error, because we should never
+	 * have a good statusConfig without a good statusContext, too.
+	 * For lack of anything better, though, we just assert and use
+	 * the same error as if there were no statusConfig (set below).
+	 */
+	PORT_Assert(ocspcx != NULL);
+    }
+
+    if (ocspcx == NULL)
+	PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED);
+
+    return ocspcx;
+}
+
+/*
+ * Return cert reference if the given signerCert is the default responder for
+ * the given certID.  If not, or if any error, return NULL.
+ */
+static CERTCertificate *
+ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle, CERTOCSPCertID *certID)
+{
+    ocspCheckingContext *ocspcx;
+
+    ocspcx = ocsp_GetCheckingContext(handle);
+    if (ocspcx == NULL)
+	goto loser;
+
+   /*
+    * Right now we have only one default responder.  It applies to
+    * all certs when it is used, so the check is simple and certID
+    * has no bearing on the answer.  Someday in the future we may
+    * allow configuration of different responders for different
+    * issuers, and then we would have to use the issuer specified
+    * in certID to determine if signerCert is the right one.
+    */
+    if (ocspcx->useDefaultResponder) {
+	PORT_Assert(ocspcx->defaultResponderCert != NULL);
+	return ocspcx->defaultResponderCert;
+    }
+
+loser:
+    return NULL;
+}
+
+/*
+ * Return true if the cert is one of the default responders configured for
+ * ocsp context. If not, or if any error, return false.
+ */
+PRBool
+ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle *handle, CERTCertificate *cert)
+{
+    ocspCheckingContext *ocspcx;
+
+    ocspcx = ocsp_GetCheckingContext(handle);
+    if (ocspcx == NULL)
+	return PR_FALSE;
+
+   /*
+    * Right now we have only one default responder.  It applies to
+    * all certs when it is used, so the check is simple and certID
+    * has no bearing on the answer.  Someday in the future we may
+    * allow configuration of different responders for different
+    * issuers, and then we would have to use the issuer specified
+    * in certID to determine if signerCert is the right one.
+    */
+    if (ocspcx->useDefaultResponder &&
+        CERT_CompareCerts(ocspcx->defaultResponderCert, cert)) {
+	return PR_TRUE;
+    }
+
+    return PR_FALSE;
+}
+
+/*
+ * Check that the given signer certificate is authorized to sign status
+ * information for the given certID.  Return true if it is, false if not
+ * (or if there is any error along the way).  If false is returned because
+ * the signer is not authorized, the following error will be set:
+ *	SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
+ * Other errors are low-level problems (no memory, bad database, etc.).
+ *
+ * There are three ways to be authorized.  In the order in which we check,
+ * using the terms used in the OCSP spec, the signer must be one of:
+ *  1.  A "trusted responder" -- it matches a local configuration
+ *      of OCSP signing authority for the certificate in question.
+ *  2.  The CA who issued the certificate in question.
+ *  3.  A "CA designated responder", aka an "authorized responder" -- it
+ *      must be represented by a special cert issued by the CA who issued
+ *      the certificate in question.
+ */
+static PRBool
+ocsp_AuthorizedResponderForCertID(CERTCertDBHandle *handle,
+				  CERTCertificate *signerCert,
+				  CERTOCSPCertID *certID,
+				  int64 thisUpdate)
+{
+    CERTCertificate *issuerCert = NULL, *defRespCert;
+    SECItem *keyHash = NULL;
+    SECItem *nameHash = NULL;
+    SECOidTag hashAlg;
+    PRBool keyHashEQ = PR_FALSE, nameHashEQ = PR_FALSE;
+
+    /*
+     * Check first for a trusted responder, which overrides everything else.
+     */
+    if ((defRespCert = ocsp_CertGetDefaultResponder(handle, certID)) &&
+        CERT_CompareCerts(defRespCert, signerCert)) {
+        return PR_TRUE;
+    }
+
+    /*
+     * In the other two cases, we need to do an issuer comparison.
+     * How we do it depends on whether the signer certificate has the
+     * special extension (for a designated responder) or not.
+     *
+     * First, lets check if signer of the response is the actual issuer
+     * of the cert. For that we will use signer cert key hash and cert subj
+     * name hash and will compare them with already calculated issuer key
+     * hash and issuer name hash. The hash algorithm is picked from response
+     * certID hash to avoid second hash calculation.
+     */
+
+    hashAlg = SECOID_FindOIDTag(&certID->hashAlgorithm.algorithm);
+
+    keyHash = CERT_GetSPKIDigest(NULL, signerCert, hashAlg, NULL);
+    if (keyHash != NULL) {
+
+        keyHashEQ =
+            (SECITEM_CompareItem(keyHash,
+                                 &certID->issuerKeyHash) == SECEqual);
+        SECITEM_FreeItem(keyHash, PR_TRUE);
+    }
+    if (keyHashEQ &&
+        (nameHash = cert_GetSubjectNameDigest(NULL, signerCert,
+                                              hashAlg, NULL))) {
+        nameHashEQ =
+            (SECITEM_CompareItem(nameHash,
+                                 &certID->issuerNameHash) == SECEqual);
+            
+        SECITEM_FreeItem(nameHash, PR_TRUE);
+        if (nameHashEQ) {
+            /* The issuer of the cert is the the signer of the response */
+            return PR_TRUE;
+        }
+    }
+
+
+    keyHashEQ = PR_FALSE;
+    nameHashEQ = PR_FALSE;
+
+    if (!ocsp_CertIsOCSPDesignatedResponder(signerCert)) {
+        PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
+        return PR_FALSE;
+    }
+
+    /*
+     * The signer is a designated responder.  Its issuer must match
+     * the issuer of the cert being checked.
+     */
+    issuerCert = CERT_FindCertIssuer(signerCert, thisUpdate,
+                                     certUsageAnyCA);
+    if (issuerCert == NULL) {
+        /*
+         * We could leave the SEC_ERROR_UNKNOWN_ISSUER error alone,
+         * but the following will give slightly more information.
+         * Once we have an error stack, things will be much better.
+         */
+        PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
+        return PR_FALSE;
+    }
+
+    keyHash = CERT_GetSPKIDigest(NULL, issuerCert, hashAlg, NULL);
+    nameHash = cert_GetSubjectNameDigest(NULL, issuerCert, hashAlg, NULL);
+
+    CERT_DestroyCertificate(issuerCert);
+
+    if (keyHash != NULL && nameHash != NULL) {
+        keyHashEQ = 
+            (SECITEM_CompareItem(keyHash,
+                                 &certID->issuerKeyHash) == SECEqual);
+
+        nameHashEQ =
+            (SECITEM_CompareItem(nameHash,
+                                 &certID->issuerNameHash) == SECEqual);
+    }
+
+    if (keyHash) {
+        SECITEM_FreeItem(keyHash, PR_TRUE);
+    }
+    if (nameHash) {
+        SECITEM_FreeItem(nameHash, PR_TRUE);
+    }
+
+    if (keyHashEQ && nameHashEQ) {
+        return PR_TRUE;
+    }
+
+    PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
+    return PR_FALSE;
+}
+
+/*
+ * We need to check that a responder gives us "recent" information.
+ * Since a responder can pre-package responses, we need to pick an amount
+ * of time that is acceptable to us, and reject any response that is
+ * older than that.
+ *
+ * XXX This *should* be based on some configuration parameter, so that
+ * different usages could specify exactly what constitutes "sufficiently
+ * recent".  But that is not going to happen right away.  For now, we
+ * want something from within the last 24 hours.  This macro defines that
+ * number in seconds.
+ */
+#define OCSP_ALLOWABLE_LAPSE_SECONDS	(24L * 60L * 60L)
+
+static PRBool
+ocsp_TimeIsRecent(int64 checkTime)
+{
+    int64 now = PR_Now();
+    int64 lapse, tmp;
+
+    LL_I2L(lapse, OCSP_ALLOWABLE_LAPSE_SECONDS);
+    LL_I2L(tmp, PR_USEC_PER_SEC);
+    LL_MUL(lapse, lapse, tmp);		/* allowable lapse in microseconds */
+
+    LL_ADD(checkTime, checkTime, lapse);
+    if (LL_CMP(now, >, checkTime))
+	return PR_FALSE;
+
+    return PR_TRUE;
+}
+
+#define OCSP_SLOP (5L*60L) /* OCSP responses are allowed to be 5 minutes
+                              in the future by default */
+
+static PRUint32 ocspsloptime = OCSP_SLOP;	/* seconds */
+
+/*
+ * If an old response contains the revoked certificate status, we want
+ * to return SECSuccess so the response will be used.
+ */
+static SECStatus
+ocsp_HandleOldSingleResponse(CERTOCSPSingleResponse *single, PRTime time)
+{
+    SECStatus rv;
+    ocspCertStatus *status = single->certStatus;
+    if (status->certStatusType == ocspCertStatus_revoked) {
+        rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time);
+        if (rv != SECSuccess &&
+            PORT_GetError() == SEC_ERROR_REVOKED_CERTIFICATE) {
+            /*
+             * Return SECSuccess now.  The subsequent ocsp_CertRevokedAfter
+             * call in ocsp_CertHasGoodStatus will cause
+             * ocsp_CertHasGoodStatus to fail with
+             * SEC_ERROR_REVOKED_CERTIFICATE.
+             */
+            return SECSuccess;
+        }
+
+    }
+    PORT_SetError(SEC_ERROR_OCSP_OLD_RESPONSE);
+    return SECFailure;
+}
+
+/*
+ * Check that this single response is okay.  A return of SECSuccess means:
+ *   1. The signer (represented by "signerCert") is authorized to give status
+ *	for the cert represented by the individual response in "single".
+ *   2. The value of thisUpdate is earlier than now.
+ *   3. The value of producedAt is later than or the same as thisUpdate.
+ *   4. If nextUpdate is given:
+ *	- The value of nextUpdate is later than now.
+ *	- The value of producedAt is earlier than nextUpdate.
+ *	Else if no nextUpdate:
+ *	- The value of thisUpdate is fairly recent.
+ *	- The value of producedAt is fairly recent.
+ *	However we do not need to perform an explicit check for this last
+ *	constraint because it is already guaranteed by checking that
+ *	producedAt is later than thisUpdate and thisUpdate is recent.
+ * Oh, and any responder is "authorized" to say that a cert is unknown to it.
+ *
+ * If any of those checks fail, SECFailure is returned and an error is set:
+ *	SEC_ERROR_OCSP_FUTURE_RESPONSE
+ *	SEC_ERROR_OCSP_OLD_RESPONSE
+ *	SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
+ * Other errors are low-level problems (no memory, bad database, etc.).
+ */ 
+static SECStatus
+ocsp_VerifySingleResponse(CERTOCSPSingleResponse *single,
+			  CERTCertDBHandle *handle,
+			  CERTCertificate *signerCert,
+			  int64 producedAt)
+{
+    CERTOCSPCertID *certID = single->certID;
+    int64 now, thisUpdate, nextUpdate, tmstamp, tmp;
+    SECStatus rv;
+
+    OCSP_TRACE(("OCSP ocsp_VerifySingleResponse, nextUpdate: %d\n", 
+               ((single->nextUpdate) != 0)));
+    /*
+     * If all the responder said was that the given cert was unknown to it,
+     * that is a valid response.  Not very interesting to us, of course,
+     * but all this function is concerned with is validity of the response,
+     * not the status of the cert.
+     */
+    PORT_Assert(single->certStatus != NULL);
+    if (single->certStatus->certStatusType == ocspCertStatus_unknown)
+	return SECSuccess;
+
+    /*
+     * We need to extract "thisUpdate" for use below and to pass along
+     * to AuthorizedResponderForCertID in case it needs it for doing an
+     * issuer look-up.
+     */
+    rv = DER_GeneralizedTimeToTime(&thisUpdate, &single->thisUpdate);
+    if (rv != SECSuccess)
+	return rv;
+
+    /*
+     * First confirm that signerCert is authorized to give this status.
+     */
+    if (ocsp_AuthorizedResponderForCertID(handle, signerCert, certID,
+					  thisUpdate) != PR_TRUE)
+	return SECFailure;
+
+    /*
+     * Now check the time stuff, as described above.
+     */
+    now = PR_Now();
+    /* allow slop time for future response */
+    LL_UI2L(tmstamp, ocspsloptime); /* get slop time in seconds */
+    LL_UI2L(tmp, PR_USEC_PER_SEC);
+    LL_MUL(tmp, tmstamp, tmp); /* convert the slop time to PRTime */
+    LL_ADD(tmstamp, tmp, now); /* add current time to it */
+
+    if (LL_CMP(thisUpdate, >, tmstamp) || LL_CMP(producedAt, <, thisUpdate)) {
+	PORT_SetError(SEC_ERROR_OCSP_FUTURE_RESPONSE);
+	return SECFailure;
+    }
+    if (single->nextUpdate != NULL) {
+	rv = DER_GeneralizedTimeToTime(&nextUpdate, single->nextUpdate);
+	if (rv != SECSuccess)
+	    return rv;
+
+	LL_ADD(tmp, tmp, nextUpdate);
+	if (LL_CMP(tmp, <, now) || LL_CMP(producedAt, >, nextUpdate))
+	    return ocsp_HandleOldSingleResponse(single, now);
+    } else if (ocsp_TimeIsRecent(thisUpdate) != PR_TRUE) {
+	return ocsp_HandleOldSingleResponse(single, now);
+    }
+
+    return SECSuccess;
+}
+
+
+/*
+ * FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation
+ *   Get the value of the URI of the OCSP responder for the given cert.
+ *   This is found in the (optional) Authority Information Access extension
+ *   in the cert.
+ * INPUTS:
+ *   CERTCertificate *cert
+ *     The certificate being examined.
+ * RETURN:
+ *   char *
+ *     A copy of the URI for the OCSP method, if found.  If either the
+ *     extension is not present or it does not contain an entry for OCSP,
+ *     SEC_ERROR_CERT_BAD_ACCESS_LOCATION will be set and a NULL returned.
+ *     Any other error will also result in a NULL being returned.
+ *     
+ *     This result should be freed (via PORT_Free) when no longer in use.
+ */
+char *
+CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert)
+{
+    CERTGeneralName *locname = NULL;
+    SECItem *location = NULL;
+    SECItem *encodedAuthInfoAccess = NULL;
+    CERTAuthInfoAccess **authInfoAccess = NULL;
+    char *locURI = NULL;
+    PRArenaPool *arena = NULL;
+    SECStatus rv;
+    int i;
+
+    /*
+     * Allocate this one from the heap because it will get filled in
+     * by CERT_FindCertExtension which will also allocate from the heap,
+     * and we can free the entire thing on our way out.
+     */
+    encodedAuthInfoAccess = SECITEM_AllocItem(NULL, NULL, 0);
+    if (encodedAuthInfoAccess == NULL)
+	goto loser;
+
+    rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS,
+				encodedAuthInfoAccess);
+    if (rv == SECFailure) {
+	PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+	goto loser;
+    }
+
+    /*
+     * The rest of the things allocated in the routine will come out of
+     * this arena, which is temporary just for us to decode and get at the
+     * AIA extension.  The whole thing will be destroyed on our way out,
+     * after we have copied the location string (url) itself (if found).
+     */
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL)
+	goto loser;
+
+    authInfoAccess = CERT_DecodeAuthInfoAccessExtension(arena,
+							encodedAuthInfoAccess);
+    if (authInfoAccess == NULL)
+	goto loser;
+
+    for (i = 0; authInfoAccess[i] != NULL; i++) {
+	if (SECOID_FindOIDTag(&authInfoAccess[i]->method) == SEC_OID_PKIX_OCSP)
+	    locname = authInfoAccess[i]->location;
+    }
+
+    /*
+     * If we found an AIA extension, but it did not include an OCSP method,
+     * that should look to our caller as if we did not find the extension
+     * at all, because it is only an OCSP method that we care about.
+     * So set the same error that would be set if the AIA extension was
+     * not there at all.
+     */
+    if (locname == NULL) {
+	PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+	goto loser;
+    }
+
+    /*
+     * The following is just a pointer back into locname (i.e. not a copy);
+     * thus it should not be freed.
+     */
+    location = CERT_GetGeneralNameByType(locname, certURI, PR_FALSE);
+    if (location == NULL) {
+	/*
+	 * XXX Appears that CERT_GetGeneralNameByType does not set an
+	 * error if there is no name by that type.  For lack of anything
+	 * better, act as if the extension was not found.  In the future
+	 * this should probably be something more like the extension was
+	 * badly formed.
+	 */
+	PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+	goto loser;
+    }
+
+    /*
+     * That location is really a string, but it has a specified length
+     * without a null-terminator.  We need a real string that does have
+     * a null-terminator, and we need a copy of it anyway to return to
+     * our caller -- so allocate and copy.
+     */
+    locURI = PORT_Alloc(location->len + 1);
+    if (locURI == NULL) {
+	goto loser;
+    }
+    PORT_Memcpy(locURI, location->data, location->len);
+    locURI[location->len] = '\0';
+
+loser:
+    if (arena != NULL)
+	PORT_FreeArena(arena, PR_FALSE);
+
+    if (encodedAuthInfoAccess != NULL)
+	SECITEM_FreeItem(encodedAuthInfoAccess, PR_TRUE);
+
+    return locURI;
+}
+
+
+/*
+ * Figure out where we should go to find out the status of the given cert
+ * via OCSP.  If allowed to use a default responder uri and a default
+ * responder is set up, then that is our answer.
+ * If not, see if the certificate has an Authority Information Access (AIA)
+ * extension for OCSP, and return the value of that.  Otherwise return NULL.
+ * We also let our caller know whether or not the responder chosen was
+ * a default responder or not through the output variable isDefault;
+ * its value has no meaning unless a good (non-null) value is returned
+ * for the location.
+ *
+ * The result needs to be freed (PORT_Free) when no longer in use.
+ */
+char *
+ocsp_GetResponderLocation(CERTCertDBHandle *handle, CERTCertificate *cert,
+			  PRBool canUseDefault, PRBool *isDefault)
+{
+    ocspCheckingContext *ocspcx = NULL;
+    char *ocspUrl = NULL;
+
+    if (canUseDefault) {
+        ocspcx = ocsp_GetCheckingContext(handle);
+    }
+    if (ocspcx != NULL && ocspcx->useDefaultResponder) {
+	/*
+	 * A default responder wins out, if specified.
+	 * XXX Someday this may be a more complicated determination based
+	 * on the cert's issuer.  (That is, we could have different default
+	 * responders configured for different issuers.)
+	 */
+	PORT_Assert(ocspcx->defaultResponderURI != NULL);
+	*isDefault = PR_TRUE;
+	return (PORT_Strdup(ocspcx->defaultResponderURI));
+    }
+
+    /*
+     * No default responder set up, so go see if we can find an AIA
+     * extension that has a value for OCSP, and get the url from that.
+     */
+    *isDefault = PR_FALSE;
+    ocspUrl = CERT_GetOCSPAuthorityInfoAccessLocation(cert);
+    if (!ocspUrl) {
+	CERT_StringFromCertFcn altFcn;
+
+	PR_EnterMonitor(OCSP_Global.monitor);
+	altFcn = OCSP_Global.alternateOCSPAIAFcn;
+	PR_ExitMonitor(OCSP_Global.monitor);
+	if (altFcn) {
+	    ocspUrl = (*altFcn)(cert);
+	    if (ocspUrl)
+		*isDefault = PR_TRUE;
+    	}
+    }
+    return ocspUrl;
+}
+
+/*
+ * Return SECSuccess if the cert was revoked *after* "time",
+ * SECFailure otherwise.
+ */
+static SECStatus
+ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, int64 time)
+{
+    int64 revokedTime;
+    SECStatus rv;
+
+    rv = DER_GeneralizedTimeToTime(&revokedTime, &revokedInfo->revocationTime);
+    if (rv != SECSuccess)
+	return rv;
+
+    /*
+     * Set the error even if we will return success; someone might care.
+     */
+    PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
+
+    if (LL_CMP(revokedTime, >, time))
+	return SECSuccess;
+
+    return SECFailure;
+}
+
+/*
+ * See if the cert represented in the single response had a good status
+ * at the specified time.
+ */
+static SECStatus
+ocsp_CertHasGoodStatus(ocspCertStatus *status, int64 time)
+{
+    SECStatus rv;
+    switch (status->certStatusType) {
+    case ocspCertStatus_good:
+        rv = SECSuccess;
+        break;
+    case ocspCertStatus_revoked:
+        rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time);
+        break;
+    case ocspCertStatus_unknown:
+        PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT);
+        rv = SECFailure;
+        break;
+    case ocspCertStatus_other:
+    default:
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+        rv = SECFailure;
+        break;
+    }
+    return rv;
+}
+
+static SECStatus
+ocsp_SingleResponseCertHasGoodStatus(CERTOCSPSingleResponse *single, 
+                                     int64 time)
+{
+    return ocsp_CertHasGoodStatus(single->certStatus, time);
+}
+
+/* Return value SECFailure means: not found or not fresh.
+ * On SECSuccess, the out parameters contain the OCSP status.
+ * rvOcsp contains the overall result of the OCSP operation.
+ * Depending on input parameter ignoreGlobalOcspFailureSetting,
+ * a soft failure might be converted into *rvOcsp=SECSuccess.
+ * If the cached attempt to obtain OCSP information had resulted
+ * in a failure, missingResponseError shows the error code of
+ * that failure.
+ */
+SECStatus
+ocsp_GetCachedOCSPResponseStatusIfFresh(CERTOCSPCertID *certID, 
+                                        int64 time, 
+                                        PRBool ignoreGlobalOcspFailureSetting,
+                                        SECStatus *rvOcsp,
+                                        SECErrorCodes *missingResponseError)
+{
+    OCSPCacheItem *cacheItem = NULL;
+    SECStatus rv = SECFailure;
+  
+    if (!certID || !missingResponseError || !rvOcsp) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    *rvOcsp = SECFailure;
+    *missingResponseError = 0;
+  
+    PR_EnterMonitor(OCSP_Global.monitor);
+    cacheItem = ocsp_FindCacheEntry(&OCSP_Global.cache, certID);
+    if (cacheItem && ocsp_IsCacheItemFresh(cacheItem)) {
+        /* having an arena means, we have a cached certStatus */
+        if (cacheItem->certStatusArena) {
+            *rvOcsp = ocsp_CertHasGoodStatus(&cacheItem->certStatus, time);
+            if (*rvOcsp != SECSuccess) {
+                *missingResponseError = PORT_GetError();
+            }
+            rv = SECSuccess;
+        } else {
+            /*
+             * No status cached, the previous attempt failed.
+             * If OCSP is required, we never decide based on a failed attempt 
+             * However, if OCSP is optional, a recent OCSP failure is
+             * an allowed good state.
+             */
+            if (!ignoreGlobalOcspFailureSetting &&
+                OCSP_Global.ocspFailureMode == 
+                    ocspMode_FailureIsNotAVerificationFailure) {
+                rv = SECSuccess;
+                *rvOcsp = SECSuccess;
+            }
+            *missingResponseError = cacheItem->missingResponseError;
+        }
+    }
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return rv;
+}
+
+PRBool
+ocsp_FetchingFailureIsVerificationFailure()
+{
+    PRBool isFailure;
+
+    PR_EnterMonitor(OCSP_Global.monitor);
+    isFailure =
+        OCSP_Global.ocspFailureMode == ocspMode_FailureIsVerificationFailure;
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return isFailure;
+}
+
+/*
+ * FUNCTION: CERT_CheckOCSPStatus
+ *   Checks the status of a certificate via OCSP.  Will only check status for
+ *   a certificate that has an AIA (Authority Information Access) extension
+ *   for OCSP *or* when a "default responder" is specified and enabled.
+ *   (If no AIA extension for OCSP and no default responder in place, the
+ *   cert is considered to have a good status and SECSuccess is returned.)
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     certificate DB of the cert that is being checked
+ *   CERTCertificate *cert
+ *     the certificate being checked
+ *   XXX in the long term also need a boolean parameter that specifies
+ *	whether to check the cert chain, as well; for now we check only
+ *	the leaf (the specified certificate)
+ *   int64 time
+ *     time for which status is to be determined
+ *   void *pwArg
+ *     argument for password prompting, if needed
+ * RETURN:
+ *   Returns SECSuccess if an approved OCSP responder "knows" the cert
+ *   *and* returns a non-revoked status for it; SECFailure otherwise,
+ *   with an error set describing the reason:
+ *
+ *	SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
+ *	SEC_ERROR_OCSP_FUTURE_RESPONSE
+ *	SEC_ERROR_OCSP_MALFORMED_REQUEST
+ *	SEC_ERROR_OCSP_MALFORMED_RESPONSE
+ *	SEC_ERROR_OCSP_OLD_RESPONSE
+ *	SEC_ERROR_OCSP_REQUEST_NEEDS_SIG
+ *	SEC_ERROR_OCSP_SERVER_ERROR
+ *	SEC_ERROR_OCSP_TRY_SERVER_LATER
+ *	SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST
+ *	SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
+ *	SEC_ERROR_OCSP_UNKNOWN_CERT
+ *	SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
+ *	SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE
+ *
+ *	SEC_ERROR_BAD_SIGNATURE
+ *	SEC_ERROR_CERT_BAD_ACCESS_LOCATION
+ *	SEC_ERROR_INVALID_TIME
+ *	SEC_ERROR_REVOKED_CERTIFICATE
+ *	SEC_ERROR_UNKNOWN_ISSUER
+ *	SEC_ERROR_UNKNOWN_SIGNER
+ *
+ *   Other errors are any of the many possible failures in cert verification
+ *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
+ *   verifying the signer's cert, or low-level problems (error allocating
+ *   memory, error performing ASN.1 decoding, etc.).
+ */    
+SECStatus 
+CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
+		     int64 time, void *pwArg)
+{
+    CERTOCSPCertID *certID;
+    PRBool certIDWasConsumed = PR_FALSE;
+    SECStatus rv = SECFailure;
+    SECStatus rvOcsp;
+    SECErrorCodes dummy_error_code; /* we ignore this */
+  
+    OCSP_TRACE_CERT(cert);
+    OCSP_TRACE_TIME("## requested validity time:", time);
+  
+    certID = CERT_CreateOCSPCertID(cert, time);
+    if (!certID)
+        return SECFailure;
+    rv = ocsp_GetCachedOCSPResponseStatusIfFresh(
+        certID, time, PR_FALSE, /* ignoreGlobalOcspFailureSetting */
+        &rvOcsp, &dummy_error_code);
+    if (rv == SECSuccess) {
+        CERT_DestroyOCSPCertID(certID);
+        return rvOcsp;
+    }
+    rv = ocsp_GetOCSPStatusFromNetwork(handle, certID, cert, time, pwArg, 
+                                       &certIDWasConsumed, 
+                                       &rvOcsp);
+    if (rv != SECSuccess) {
+        /* we were unable to obtain ocsp status. Check if we should
+         * return cert status revoked. */
+        rvOcsp = ocsp_FetchingFailureIsVerificationFailure() ?
+            SECFailure : SECSuccess;
+    }
+    if (!certIDWasConsumed) {
+        CERT_DestroyOCSPCertID(certID);
+    }
+    return rvOcsp;
+}
+
+/*
+ * Status in *certIDWasConsumed will always be correct, regardless of 
+ * return value.
+ */
+static SECStatus
+ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, 
+                              CERTOCSPCertID *certID, 
+                              CERTCertificate *cert, 
+                              int64 time, 
+                              void *pwArg,
+                              PRBool *certIDWasConsumed,
+                              SECStatus *rv_ocsp)
+{
+    char *location = NULL;
+    PRBool locationIsDefault;
+    SECItem *encodedResponse = NULL;
+    CERTOCSPRequest *request = NULL;
+    CERTOCSPResponse *response = NULL;
+    CERTCertificate *signerCert = NULL;
+    CERTCertificate *issuerCert = NULL;
+    SECStatus rv = SECFailure;
+    CERTOCSPSingleResponse *single = NULL;
+
+    if (!certIDWasConsumed || !rv_ocsp) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    *certIDWasConsumed = PR_FALSE;
+    *rv_ocsp = SECFailure;
+
+    /*
+     * The first thing we need to do is find the location of the responder.
+     * This will be the value of the default responder (if enabled), else
+     * it will come out of the AIA extension in the cert (if present).
+     * If we have no such location, then this cert does not "deserve" to
+     * be checked -- that is, we consider it a success and just return.
+     * The way we tell that is by looking at the error number to see if
+     * the problem was no AIA extension was found; any other error was
+     * a true failure that we unfortunately have to treat as an overall
+     * failure here.
+     */
+    location = ocsp_GetResponderLocation(handle, cert, PR_TRUE,
+                                         &locationIsDefault);
+    if (location == NULL) {
+       int err = PORT_GetError();
+       if (err == SEC_ERROR_EXTENSION_NOT_FOUND ||
+           err == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) {
+           PORT_SetError(0);
+           *rv_ocsp = SECSuccess;
+           return SECSuccess;
+       }
+       return SECFailure;
+    }
+
+    /*
+     * XXX In the fullness of time, we will want/need to handle a
+     * certificate chain.  This will be done either when a new parameter
+     * tells us to, or some configuration variable tells us to.  In any
+     * case, handling it is complicated because we may need to send as
+     * many requests (and receive as many responses) as we have certs
+     * in the chain.  If we are going to talk to a default responder,
+     * and we only support one default responder, we can put all of the
+     * certs together into one request.  Otherwise, we must break them up
+     * into multiple requests.  (Even if all of the requests will go to
+     * the same location, the signature on each response will be different,
+     * because each issuer is different.  Carefully read the OCSP spec
+     * if you do not understand this.)
+     */
+
+    /*
+     * XXX If/when signing of requests is supported, that second NULL
+     * should be changed to be the signer certificate.  Not sure if that
+     * should be passed into this function or retrieved via some operation
+     * on the handle/context.
+     */
+    encodedResponse = 
+        ocsp_GetEncodedOCSPResponseForSingleCert(NULL, certID, cert, location,
+                                                 time, locationIsDefault,
+                                                 pwArg, &request);
+    if (encodedResponse == NULL) {
+        goto loser;
+    }
+
+    response = CERT_DecodeOCSPResponse(encodedResponse);
+    if (response == NULL) {
+	goto loser;
+    }
+
+    /*
+     * Okay, we at least have a response that *looks* like a response!
+     * Now see if the overall response status value is good or not.
+     * If not, we set an error and give up.  (It means that either the
+     * server had a problem, or it didn't like something about our
+     * request.  Either way there is nothing to do but give up.)
+     * Otherwise, we continue to find the actual per-cert status
+     * in the response.
+     */
+    if (CERT_GetOCSPResponseStatus(response) != SECSuccess) {
+	goto loser;
+    }
+
+    /*
+     * If we've made it this far, we expect a response with a good signature.
+     * So, check for that.
+     */
+    issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA);
+    rv = CERT_VerifyOCSPResponseSignature(response, handle, pwArg, &signerCert,
+			issuerCert);
+    if (rv != SECSuccess)
+	goto loser;
+
+    PORT_Assert(signerCert != NULL);	/* internal consistency check */
+    /* XXX probably should set error, return failure if signerCert is null */
+
+
+    /*
+     * Again, we are only doing one request for one cert.
+     * XXX When we handle cert chains, the following code will obviously
+     * have to be modified, in coordation with the code above that will
+     * have to determine how to make multiple requests, etc. 
+     */
+
+    rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID, 
+                                                 signerCert, time, &single);
+    if (rv != SECSuccess)
+        goto loser;
+
+    *rv_ocsp = ocsp_SingleResponseCertHasGoodStatus(single, time);
+
+loser:
+    PR_EnterMonitor(OCSP_Global.monitor);
+    if (OCSP_Global.maxCacheEntries >= 0) {
+        /* single == NULL means: remember response failure */
+        ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, single, 
+                                      certIDWasConsumed);
+        /* ignore cache update failures */
+    }
+    PR_ExitMonitor(OCSP_Global.monitor);
+
+    if (issuerCert != NULL)
+	CERT_DestroyCertificate(issuerCert);
+    if (signerCert != NULL)
+	CERT_DestroyCertificate(signerCert);
+    if (response != NULL)
+	CERT_DestroyOCSPResponse(response);
+    if (request != NULL)
+	CERT_DestroyOCSPRequest(request);
+    if (encodedResponse != NULL)
+	SECITEM_FreeItem(encodedResponse, PR_TRUE);
+    if (location != NULL)
+	PORT_Free(location);
+    return rv;
+}
+
+static SECStatus
+ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, 
+                                        CERTOCSPResponse *response, 
+                                        CERTOCSPCertID   *certID,
+                                        CERTCertificate  *signerCert,
+                                        int64             time,
+                                        CERTOCSPSingleResponse 
+                                            **pSingleResponse)
+{
+    SECStatus rv;
+    ocspResponseData *responseData;
+    int64 producedAt;
+    CERTOCSPSingleResponse *single;
+
+    /*
+     * The ResponseData part is the real guts of the response.
+     */
+    responseData = ocsp_GetResponseData(response, NULL);
+    if (responseData == NULL) {
+        rv = SECFailure;
+        goto loser;
+    }
+
+    /*
+     * There is one producedAt time for the entire response (and a separate
+     * thisUpdate time for each individual single response).  We need to
+     * compare them, so get the overall time to pass into the check of each
+     * single response.
+     */
+    rv = DER_GeneralizedTimeToTime(&producedAt, &responseData->producedAt);
+    if (rv != SECSuccess)
+        goto loser;
+
+    single = ocsp_GetSingleResponseForCertID(responseData->responses,
+                                             handle, certID);
+    if (single == NULL) {
+        rv = SECFailure;
+        goto loser;
+    }
+
+    rv = ocsp_VerifySingleResponse(single, handle, signerCert, producedAt);
+    if (rv != SECSuccess)
+        goto loser;
+    *pSingleResponse = single;
+
+loser:
+    return rv;
+}
+
+SECStatus
+CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle, 
+                            CERTOCSPResponse *response, 
+                            CERTOCSPCertID   *certID,
+                            CERTCertificate  *signerCert,
+                            int64             time)
+{
+    /*
+     * We do not update the cache, because:
+     *
+     * CERT_GetOCSPStatusForCertID is an old exported API that was introduced
+     * before the OCSP cache got implemented.
+     *
+     * The implementation of helper function cert_ProcessOCSPResponse
+     * requires the ability to transfer ownership of the the given certID to
+     * the cache. The external API doesn't allow us to prevent the caller from
+     * destroying the certID. We don't have the original certificate available,
+     * therefore we are unable to produce another certID object (that could 
+     * be stored in the cache).
+     *
+     * Should we ever implement code to produce a deep copy of certID,
+     * then this could be changed to allow updating the cache.
+     * The duplication would have to be done in 
+     * cert_ProcessOCSPResponse, if the out parameter to indicate
+     * a transfer of ownership is NULL.
+     */
+    return cert_ProcessOCSPResponse(handle, response, certID, 
+                                    signerCert, time, 
+                                    NULL, NULL);
+}
+
+/*
+ * The first 5 parameters match the definition of CERT_GetOCSPStatusForCertID.
+ */
+SECStatus
+cert_ProcessOCSPResponse(CERTCertDBHandle *handle, 
+                         CERTOCSPResponse *response, 
+                         CERTOCSPCertID   *certID,
+                         CERTCertificate  *signerCert,
+                         int64             time,
+                         PRBool           *certIDWasConsumed,
+                         SECStatus        *cacheUpdateStatus)
+{
+    SECStatus rv;
+    SECStatus rv_cache;
+    CERTOCSPSingleResponse *single = NULL;
+
+    rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID, 
+                                                 signerCert, time, &single);
+    if (rv == SECSuccess) {
+        /*
+         * Check whether the status says revoked, and if so 
+         * how that compares to the time value passed into this routine.
+         */
+        rv = ocsp_SingleResponseCertHasGoodStatus(single, time);
+    }
+
+    if (certIDWasConsumed) {
+        /*
+         * We don't have copy-of-certid implemented. In order to update 
+         * the cache, the caller must supply an out variable 
+         * certIDWasConsumed, allowing us to return ownership status.
+         */
+  
+        PR_EnterMonitor(OCSP_Global.monitor);
+        if (OCSP_Global.maxCacheEntries >= 0) {
+            /* single == NULL means: remember response failure */
+            rv_cache = 
+                ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID,
+                                              single, certIDWasConsumed);
+        }
+        PR_ExitMonitor(OCSP_Global.monitor);
+        if (cacheUpdateStatus) {
+            *cacheUpdateStatus = rv_cache;
+        }
+    }
+
+    return rv;
+}
+
+SECStatus
+cert_RememberOCSPProcessingFailure(CERTOCSPCertID *certID,
+                                   PRBool         *certIDWasConsumed)
+{
+    SECStatus rv = SECSuccess;
+    PR_EnterMonitor(OCSP_Global.monitor);
+    if (OCSP_Global.maxCacheEntries >= 0) {
+        rv = ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, NULL, 
+                                           certIDWasConsumed);
+    }
+    PR_ExitMonitor(OCSP_Global.monitor);
+    return rv;
+}
+
+/*
+ * Disable status checking and destroy related structures/data.
+ */
+static SECStatus
+ocsp_DestroyStatusChecking(CERTStatusConfig *statusConfig)
+{
+    ocspCheckingContext *statusContext;
+
+    /*
+     * Disable OCSP checking
+     */
+    statusConfig->statusChecker = NULL;
+
+    statusContext = statusConfig->statusContext;
+    PORT_Assert(statusContext != NULL);
+    if (statusContext == NULL)
+	return SECFailure;
+
+    if (statusContext->defaultResponderURI != NULL)
+	PORT_Free(statusContext->defaultResponderURI);
+    if (statusContext->defaultResponderNickname != NULL)
+	PORT_Free(statusContext->defaultResponderNickname);
+
+    PORT_Free(statusContext);
+    statusConfig->statusContext = NULL;
+
+    PORT_Free(statusConfig);
+
+    return SECSuccess;
+}
+
+
+/*
+ * FUNCTION: CERT_DisableOCSPChecking
+ *   Turns off OCSP checking for the given certificate database.
+ *   This routine disables OCSP checking.  Though it will return
+ *   SECFailure if OCSP checking is not enabled, it is "safe" to
+ *   call it that way and just ignore the return value, if it is
+ *   easier to just call it than to "remember" whether it is enabled.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Certificate database for which OCSP checking will be disabled.
+ * RETURN:
+ *   Returns SECFailure if an error occurred (usually means that OCSP
+ *   checking was not enabled or status contexts were not initialized --
+ *   error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise.
+ */
+SECStatus
+CERT_DisableOCSPChecking(CERTCertDBHandle *handle)
+{
+    CERTStatusConfig *statusConfig;
+    ocspCheckingContext *statusContext;
+
+    if (handle == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    statusConfig = CERT_GetStatusConfig(handle);
+    statusContext = ocsp_GetCheckingContext(handle);
+    if (statusContext == NULL)
+	return SECFailure;
+
+    if (statusConfig->statusChecker != CERT_CheckOCSPStatus) {
+	/*
+	 * Status configuration is present, but either not currently
+	 * enabled or not for OCSP.
+	 */
+	PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED);
+	return SECFailure;
+    }
+
+    /* cache no longer necessary */
+    CERT_ClearOCSPCache();
+
+    /*
+     * This is how we disable status checking.  Everything else remains
+     * in place in case we are enabled again.
+     */
+    statusConfig->statusChecker = NULL;
+
+    return SECSuccess;
+}
+
+/*
+ * Allocate and initialize the informational structures for status checking.
+ * This is done when some configuration of OCSP is being done or when OCSP
+ * checking is being turned on, whichever comes first.
+ */
+static SECStatus
+ocsp_InitStatusChecking(CERTCertDBHandle *handle)
+{
+    CERTStatusConfig *statusConfig = NULL;
+    ocspCheckingContext *statusContext = NULL;
+
+    PORT_Assert(CERT_GetStatusConfig(handle) == NULL);
+    if (CERT_GetStatusConfig(handle) != NULL) {
+	/* XXX or call statusConfig->statusDestroy and continue? */
+	return SECFailure;
+    }
+
+    statusConfig = PORT_ZNew(CERTStatusConfig);
+    if (statusConfig == NULL)
+	goto loser;
+
+    statusContext = PORT_ZNew(ocspCheckingContext);
+    if (statusContext == NULL)
+	goto loser;
+
+    statusConfig->statusDestroy = ocsp_DestroyStatusChecking;
+    statusConfig->statusContext = statusContext;
+
+    CERT_SetStatusConfig(handle, statusConfig);
+
+    return SECSuccess;
+
+loser:
+    if (statusConfig != NULL)
+	PORT_Free(statusConfig);
+    return SECFailure;
+}
+
+
+/*
+ * FUNCTION: CERT_EnableOCSPChecking
+ *   Turns on OCSP checking for the given certificate database.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Certificate database for which OCSP checking will be enabled.
+ * RETURN:
+ *   Returns SECFailure if an error occurred (likely only problem
+ *   allocating memory); SECSuccess otherwise.
+ */
+SECStatus
+CERT_EnableOCSPChecking(CERTCertDBHandle *handle)
+{
+    CERTStatusConfig *statusConfig;
+    
+    SECStatus rv;
+
+    if (handle == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    statusConfig = CERT_GetStatusConfig(handle);
+    if (statusConfig == NULL) {
+	rv = ocsp_InitStatusChecking(handle);
+	if (rv != SECSuccess)
+	    return rv;
+
+	/* Get newly established value */
+	statusConfig = CERT_GetStatusConfig(handle);
+	PORT_Assert(statusConfig != NULL);
+    }
+
+    /*
+     * Setting the checker function is what really enables the checking
+     * when each cert verification is done.
+     */
+    statusConfig->statusChecker = CERT_CheckOCSPStatus;
+
+    return SECSuccess;
+}
+
+
+/*
+ * FUNCTION: CERT_SetOCSPDefaultResponder
+ *   Specify the location and cert of the default responder.
+ *   If OCSP checking is already enabled *and* use of a default responder
+ *   is also already enabled, all OCSP checking from now on will go directly
+ *   to the specified responder.  If OCSP checking is not enabled, or if
+ *   it is but use of a default responder is not enabled, the information
+ *   will be recorded and take effect whenever both are enabled.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Cert database on which OCSP checking should use the default responder.
+ *   char *url
+ *     The location of the default responder (e.g. "http://foo.com:80/ocsp")
+ *     Note that the location will not be tested until the first attempt
+ *     to send a request there.
+ *   char *name
+ *     The nickname of the cert to trust (expected) to sign the OCSP responses.
+ *     If the corresponding cert cannot be found, SECFailure is returned.
+ * RETURN:
+ *   Returns SECFailure if an error occurred; SECSuccess otherwise.
+ *   The most likely error is that the cert for "name" could not be found
+ *   (probably SEC_ERROR_UNKNOWN_CERT).  Other errors are low-level (no memory,
+ *   bad database, etc.).
+ */
+SECStatus
+CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle,
+			     const char *url, const char *name)
+{
+    CERTCertificate *cert;
+    ocspCheckingContext *statusContext;
+    char *url_copy = NULL;
+    char *name_copy = NULL;
+    SECStatus rv;
+
+    if (handle == NULL || url == NULL || name == NULL) {
+	/*
+	 * XXX When interface is exported, probably want better errors;
+	 * perhaps different one for each parameter.
+	 */
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    /*
+     * Find the certificate for the specified nickname.  Do this first
+     * because it seems the most likely to fail.
+     *
+     * XXX Shouldn't need that cast if the FindCertByNickname interface
+     * used const to convey that it does not modify the name.  Maybe someday.
+     */
+    cert = CERT_FindCertByNickname(handle, (char *) name);
+    if (cert == NULL) {
+      /*
+       * look for the cert on an external token.
+       */
+      cert = PK11_FindCertFromNickname((char *)name, NULL);
+    }
+    if (cert == NULL)
+	return SECFailure;
+
+    /*
+     * Make a copy of the url and nickname.
+     */
+    url_copy = PORT_Strdup(url);
+    name_copy = PORT_Strdup(name);
+    if (url_copy == NULL || name_copy == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    statusContext = ocsp_GetCheckingContext(handle);
+
+    /*
+     * Allocate and init the context if it doesn't already exist.
+     */
+    if (statusContext == NULL) {
+	rv = ocsp_InitStatusChecking(handle);
+	if (rv != SECSuccess)
+	    goto loser;
+
+	statusContext = ocsp_GetCheckingContext(handle);
+	PORT_Assert(statusContext != NULL);	/* extreme paranoia */
+    }
+
+    /*
+     * Note -- we do not touch the status context until after all of
+     * the steps which could cause errors.  If something goes wrong,
+     * we want to leave things as they were.
+     */
+
+    /*
+     * Get rid of old url and name if there.
+     */
+    if (statusContext->defaultResponderNickname != NULL)
+	PORT_Free(statusContext->defaultResponderNickname);
+    if (statusContext->defaultResponderURI != NULL)
+	PORT_Free(statusContext->defaultResponderURI);
+
+    /*
+     * And replace them with the new ones.
+     */
+    statusContext->defaultResponderURI = url_copy;
+    statusContext->defaultResponderNickname = name_copy;
+
+    /*
+     * If there was already a cert in place, get rid of it and replace it.
+     * Otherwise, we are not currently enabled, so we don't want to save it;
+     * it will get re-found and set whenever use of a default responder is
+     * enabled.
+     */
+    if (statusContext->defaultResponderCert != NULL) {
+	CERT_DestroyCertificate(statusContext->defaultResponderCert);
+	statusContext->defaultResponderCert = cert;
+        /*OCSP enabled, switching responder: clear cache*/
+        CERT_ClearOCSPCache();
+    } else {
+	PORT_Assert(statusContext->useDefaultResponder == PR_FALSE);
+	CERT_DestroyCertificate(cert);
+        /*OCSP currently not enabled, no need to clear cache*/
+    }
+
+    return SECSuccess;
+
+loser:
+    CERT_DestroyCertificate(cert);
+    if (url_copy != NULL)
+	PORT_Free(url_copy);
+    if (name_copy != NULL)
+	PORT_Free(name_copy);
+    return rv;
+}
+
+
+/*
+ * FUNCTION: CERT_EnableOCSPDefaultResponder
+ *   Turns on use of a default responder when OCSP checking.
+ *   If OCSP checking is already enabled, this will make subsequent checks
+ *   go directly to the default responder.  (The location of the responder
+ *   and the nickname of the responder cert must already be specified.)
+ *   If OCSP checking is not enabled, this will be recorded and take effect
+ *   whenever it is enabled.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Cert database on which OCSP checking should use the default responder.
+ * RETURN:
+ *   Returns SECFailure if an error occurred; SECSuccess otherwise.
+ *   No errors are especially likely unless the caller did not previously
+ *   perform a successful call to SetOCSPDefaultResponder (in which case
+ *   the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER).
+ */
+SECStatus
+CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle)
+{
+    ocspCheckingContext *statusContext;
+    CERTCertificate *cert;
+    SECStatus rv;
+    SECCertificateUsage usage;
+
+    if (handle == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    statusContext = ocsp_GetCheckingContext(handle);
+
+    if (statusContext == NULL) {
+	/*
+	 * Strictly speaking, the error already set is "correct",
+	 * but cover over it with one more helpful in this context.
+	 */
+	PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
+	return SECFailure;
+    }
+
+    if (statusContext->defaultResponderURI == NULL) {
+	PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
+	return SECFailure;
+    }
+
+    if (statusContext->defaultResponderNickname == NULL) {
+	PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
+	return SECFailure;
+    }
+
+    /*
+     * Find the cert for the nickname.
+     */
+    cert = CERT_FindCertByNickname(handle,
+				   statusContext->defaultResponderNickname);
+    if (cert == NULL) {
+        cert = PK11_FindCertFromNickname(statusContext->defaultResponderNickname,
+                                         NULL);
+    }
+    /*
+     * We should never have trouble finding the cert, because its
+     * existence should have been proven by SetOCSPDefaultResponder.
+     */
+    PORT_Assert(cert != NULL);
+    if (cert == NULL)
+	return SECFailure;
+
+   /*
+    * Supplied cert should at least have  a signing capability in order for us
+    * to use it as a trusted responder cert. Ability to sign is guaranteed  if
+    * cert is validated to have any set of the usages below.
+    */
+    rv = CERT_VerifyCertificateNow(handle, cert, PR_TRUE,
+                                   certificateUsageCheckAllUsages,
+                                   NULL, &usage);
+    if (rv != SECSuccess || (usage & (certificateUsageSSLClient |
+                                      certificateUsageSSLServer |
+                                      certificateUsageSSLServerWithStepUp |
+                                      certificateUsageEmailSigner |
+                                      certificateUsageObjectSigner |
+                                      certificateUsageStatusResponder |
+                                      certificateUsageSSLCA)) == 0) {
+	PORT_SetError(SEC_ERROR_OCSP_RESPONDER_CERT_INVALID);
+	return SECFailure;
+    }
+
+    /*
+     * And hang onto it.
+     */
+    statusContext->defaultResponderCert = cert;
+
+    /* we don't allow a mix of cache entries from different responders */
+    CERT_ClearOCSPCache();
+
+    /*
+     * Finally, record the fact that we now have a default responder enabled.
+     */
+    statusContext->useDefaultResponder = PR_TRUE;
+    return SECSuccess;
+}
+
+
+/*
+ * FUNCTION: CERT_DisableOCSPDefaultResponder
+ *   Turns off use of a default responder when OCSP checking.
+ *   (Does nothing if use of a default responder is not enabled.)
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Cert database on which OCSP checking should stop using a default
+ *     responder.
+ * RETURN:
+ *   Returns SECFailure if an error occurred; SECSuccess otherwise.
+ *   Errors very unlikely (like random memory corruption...).
+ */
+SECStatus
+CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle)
+{
+    CERTStatusConfig *statusConfig;
+    ocspCheckingContext *statusContext;
+    CERTCertificate *tmpCert;
+
+    if (handle == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    statusConfig = CERT_GetStatusConfig(handle);
+    if (statusConfig == NULL)
+	return SECSuccess;
+
+    statusContext = ocsp_GetCheckingContext(handle);
+    PORT_Assert(statusContext != NULL);
+    if (statusContext == NULL)
+	return SECFailure;
+
+    tmpCert = statusContext->defaultResponderCert;
+    if (tmpCert) {
+	statusContext->defaultResponderCert = NULL;
+	CERT_DestroyCertificate(tmpCert);
+        /* we don't allow a mix of cache entries from different responders */
+        CERT_ClearOCSPCache();
+    }
+
+    /*
+     * Finally, record the fact.
+     */
+    statusContext->useDefaultResponder = PR_FALSE;
+    return SECSuccess;
+}
+
+
+SECStatus
+CERT_GetOCSPResponseStatus(CERTOCSPResponse *response)
+{
+    PORT_Assert(response);
+    if (response->statusValue == ocspResponse_successful)
+	return SECSuccess;
+
+    switch (response->statusValue) {
+      case ocspResponse_malformedRequest:
+	PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
+	break;
+      case ocspResponse_internalError:
+	PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+	break;
+      case ocspResponse_tryLater:
+	PORT_SetError(SEC_ERROR_OCSP_TRY_SERVER_LATER);
+	break;
+      case ocspResponse_sigRequired:
+	/* XXX We *should* retry with a signature, if possible. */
+	PORT_SetError(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG);
+	break;
+      case ocspResponse_unauthorized:
+	PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST);
+	break;
+      case ocspResponse_other:
+      case ocspResponse_unused:
+      default:
+	PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS);
+	break;
+    }
+    return SECFailure;
+}
diff --git a/mozilla/security/nss/lib/certhigh/ocsp.h b/mozilla/security/nss/lib/certhigh/ocsp.h
new file mode 100644
index 0000000..04a406a
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/ocsp.h
@@ -0,0 +1,634 @@
+/* ***** 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 ***** */
+
+/*
+ * Interface to the OCSP implementation.
+ *
+ * $Id: ocsp.h,v 1.14 2009/03/21 01:40:35 nelson%bolyard.com Exp $
+ */
+
+#ifndef _OCSP_H_
+#define _OCSP_H_
+
+
+#include "plarena.h"
+#include "seccomon.h"
+#include "secoidt.h"
+#include "keyt.h"
+#include "certt.h"
+#include "ocspt.h"
+
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/*
+ * This function registers the HttpClient with whose functions the
+ * HttpClientFcn structure has been populated as the default Http
+ * client.
+ *
+ * The function table must be a global object.
+ * The caller must ensure that NSS will be able to call
+ * the registered functions for the lifetime of the process.
+ */
+extern SECStatus
+SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable);
+
+/*
+ * This function obtains the HttpClient which has been registered
+ * by an earlier call to SEC_RegisterDefaultHttpClient.
+ */
+extern const SEC_HttpClientFcn *
+SEC_GetRegisteredHttpClient(void);
+
+/*
+ * Sets parameters that control NSS' internal OCSP cache.
+ * maxCacheEntries, special varlues are:
+ *   -1 disable cache
+ *   0 unlimited cache entries
+ * minimumSecondsToNextFetchAttempt:
+ *   whenever an OCSP request was attempted or completed over the network,
+ *   wait at least this number of seconds before trying to fetch again.
+ * maximumSecondsToNextFetchAttempt:
+ *   this is the maximum age of a cached response we allow, until we try
+ *   to fetch an updated response, even if the OCSP responder expects
+ *   that newer information update will not be available yet.
+ */
+extern SECStatus
+CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,
+                       PRUint32 minimumSecondsToNextFetchAttempt,
+                       PRUint32 maximumSecondsToNextFetchAttempt);
+
+/*
+ * Set the desired behaviour on OCSP failures.
+ * See definition of ocspFailureMode for allowed choices.
+ */
+extern SECStatus
+CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode);
+
+/*
+ * Configure the maximum time NSS will wait for an OCSP response.
+ */
+extern SECStatus
+CERT_SetOCSPTimeout(PRUint32 seconds);
+
+/*
+ * Removes all items currently stored in the OCSP cache.
+ */
+extern SECStatus
+CERT_ClearOCSPCache(void);
+
+/*
+ * FUNCTION: CERT_EnableOCSPChecking
+ *   Turns on OCSP checking for the given certificate database.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Certificate database for which OCSP checking will be enabled.
+ * RETURN:
+ *   Returns SECFailure if an error occurred (likely only problem
+ *   allocating memory); SECSuccess otherwise.
+ */
+extern SECStatus
+CERT_EnableOCSPChecking(CERTCertDBHandle *handle);
+
+/*
+ * FUNCTION: CERT_DisableOCSPChecking
+ *   Turns off OCSP checking for the given certificate database.
+ *   This routine disables OCSP checking.  Though it will return
+ *   SECFailure if OCSP checking is not enabled, it is "safe" to
+ *   call it that way and just ignore the return value, if it is
+ *   easier to just call it than to "remember" whether it is enabled.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Certificate database for which OCSP checking will be disabled.
+ * RETURN:
+ *   Returns SECFailure if an error occurred (usually means that OCSP
+ *   checking was not enabled or status contexts were not initialized --
+ *   error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise.
+ */
+extern SECStatus
+CERT_DisableOCSPChecking(CERTCertDBHandle *handle);
+
+/*
+ * FUNCTION: CERT_SetOCSPDefaultResponder
+ *   Specify the location and cert of the default responder.
+ *   If OCSP checking is already enabled *and* use of a default responder
+ *   is also already enabled, all OCSP checking from now on will go directly
+ *   to the specified responder.  If OCSP checking is not enabled, or if
+ *   it is but use of a default responder is not enabled, the information
+ *   will be recorded and take effect whenever both are enabled.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Cert database on which OCSP checking should use the default responder.
+ *   char *url
+ *     The location of the default responder (e.g. "http://foo.com:80/ocsp")
+ *     Note that the location will not be tested until the first attempt
+ *     to send a request there.
+ *   char *name
+ *     The nickname of the cert to trust (expected) to sign the OCSP responses.
+ *     If the corresponding cert cannot be found, SECFailure is returned.
+ * RETURN:
+ *   Returns SECFailure if an error occurred; SECSuccess otherwise.
+ *   The most likely error is that the cert for "name" could not be found
+ *   (probably SEC_ERROR_UNKNOWN_CERT).  Other errors are low-level (no memory,
+ *   bad database, etc.).
+ */
+extern SECStatus
+CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle,
+			     const char *url, const char *name);
+
+/*
+ * FUNCTION: CERT_EnableOCSPDefaultResponder
+ *   Turns on use of a default responder when OCSP checking.
+ *   If OCSP checking is already enabled, this will make subsequent checks
+ *   go directly to the default responder.  (The location of the responder
+ *   and the nickname of the responder cert must already be specified.)
+ *   If OCSP checking is not enabled, this will be recorded and take effect
+ *   whenever it is enabled.
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Cert database on which OCSP checking should use the default responder.
+ * RETURN:
+ *   Returns SECFailure if an error occurred; SECSuccess otherwise.
+ *   No errors are especially likely unless the caller did not previously
+ *   perform a successful call to SetOCSPDefaultResponder (in which case
+ *   the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER).
+ */
+extern SECStatus
+CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle);
+
+/*
+ * FUNCTION: CERT_DisableOCSPDefaultResponder
+ *   Turns off use of a default responder when OCSP checking.
+ *   (Does nothing if use of a default responder is not enabled.)
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     Cert database on which OCSP checking should stop using a default
+ *     responder.
+ * RETURN:
+ *   Returns SECFailure if an error occurred; SECSuccess otherwise.
+ *   Errors very unlikely (like random memory corruption...).
+ */
+extern SECStatus
+CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle);
+
+/*
+ * -------------------------------------------------------
+ * The Functions above are those expected to be used by a client
+ * providing OCSP status checking along with every cert verification.
+ * The functions below are for OCSP testing, debugging, or clients
+ * or servers performing more specialized OCSP tasks.
+ * -------------------------------------------------------
+ */
+
+/*
+ * FUNCTION: CERT_CreateOCSPRequest
+ *   Creates a CERTOCSPRequest, requesting the status of the certs in 
+ *   the given list.
+ * INPUTS:
+ *   CERTCertList *certList
+ *     A list of certs for which status will be requested.
+ *     Note that all of these certificates should have the same issuer,
+ *     or it's expected the response will be signed by a trusted responder.
+ *     If the certs need to be broken up into multiple requests, that
+ *     must be handled by the caller (and thus by having multiple calls
+ *     to this routine), who knows about where the request(s) are being
+ *     sent and whether there are any trusted responders in place.
+ *   PRTime time
+ *     Indicates the time for which the certificate status is to be 
+ *     determined -- this may be used in the search for the cert's issuer
+ *     but has no effect on the request itself.
+ *   PRBool addServiceLocator
+ *     If true, the Service Locator extension should be added to the
+ *     single request(s) for each cert.
+ *   CERTCertificate *signerCert
+ *     If non-NULL, means sign the request using this cert.  Otherwise,
+ *     do not sign.
+ *     XXX note that request signing is not yet supported; see comment in code
+ * RETURN:
+ *   A pointer to a CERTOCSPRequest structure containing an OCSP request
+ *   for the cert list.  On error, null is returned, with an error set
+ *   indicating the reason.  This is likely SEC_ERROR_UNKNOWN_ISSUER.
+ *   (The issuer is needed to create a request for the certificate.)
+ *   Other errors are low-level problems (no memory, bad database, etc.).
+ */
+extern CERTOCSPRequest *
+CERT_CreateOCSPRequest(CERTCertList *certList, PRTime time, 
+		       PRBool addServiceLocator,
+		       CERTCertificate *signerCert);
+
+/*
+ * FUNCTION: CERT_AddOCSPAcceptableResponses
+ *   Add the AcceptableResponses extension to an OCSP Request.
+ * INPUTS:
+ *   CERTOCSPRequest *request
+ *     The request to which the extension should be added.
+ *   SECOidTag responseType0, ...
+ *     A list (of one or more) of SECOidTag -- each of the response types
+ *     to be added.  The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE.
+ *     (This marks the end of the list, and it must be specified because a
+ *     client conforming to the OCSP standard is required to handle the basic
+ *     response type.)  The OIDs are not checked in any way.
+ * RETURN:
+ *   SECSuccess if the extension is added; SECFailure if anything goes wrong.
+ *   All errors are internal or low-level problems (e.g. no memory).
+ */
+extern SECStatus
+CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request,
+				SECOidTag responseType0, ...);
+
+/* 
+ * FUNCTION: CERT_EncodeOCSPRequest
+ *   DER encodes an OCSP Request, possibly adding a signature as well.
+ *   XXX Signing is not yet supported, however; see comments in code.
+ * INPUTS: 
+ *   PLArenaPool *arena
+ *     The return value is allocated from here.
+ *     If a NULL is passed in, allocation is done from the heap instead.
+ *   CERTOCSPRequest *request
+ *     The request to be encoded.
+ *   void *pwArg
+ *     Pointer to argument for password prompting, if needed.  (Definitely
+ *     not needed if not signing.)
+ * RETURN:
+ *   Returns a NULL on error and a pointer to the SECItem with the
+ *   encoded value otherwise.  Any error is likely to be low-level
+ *   (e.g. no memory).
+ */
+extern SECItem *
+CERT_EncodeOCSPRequest(PLArenaPool *arena, CERTOCSPRequest *request, 
+		       void *pwArg);
+
+/*
+ * FUNCTION: CERT_DecodeOCSPRequest
+ *   Decode a DER encoded OCSP Request.
+ * INPUTS:
+ *   SECItem *src
+ *     Pointer to a SECItem holding DER encoded OCSP Request.
+ * RETURN:
+ *   Returns a pointer to a CERTOCSPRequest containing the decoded request.
+ *   On error, returns NULL.  Most likely error is trouble decoding
+ *   (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory).
+ */
+extern CERTOCSPRequest *
+CERT_DecodeOCSPRequest(SECItem *src);
+
+/*
+ * FUNCTION: CERT_DestroyOCSPRequest
+ *   Frees an OCSP Request structure.
+ * INPUTS:
+ *   CERTOCSPRequest *request
+ *     Pointer to CERTOCSPRequest to be freed.
+ * RETURN:
+ *   No return value; no errors.
+ */
+extern void
+CERT_DestroyOCSPRequest(CERTOCSPRequest *request);
+
+/*
+ * FUNCTION: CERT_DecodeOCSPResponse
+ *   Decode a DER encoded OCSP Response.
+ * INPUTS:
+ *   SECItem *src
+ *     Pointer to a SECItem holding DER encoded OCSP Response.
+ * RETURN:
+ *   Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response);
+ *   the caller is responsible for destroying it.  Or NULL if error (either
+ *   response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE),
+ *   it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE),
+ *   or a low-level or internal error occurred).
+ */
+extern CERTOCSPResponse *
+CERT_DecodeOCSPResponse(SECItem *src);
+
+/*
+ * FUNCTION: CERT_DestroyOCSPResponse
+ *   Frees an OCSP Response structure.
+ * INPUTS:
+ *   CERTOCSPResponse *request
+ *     Pointer to CERTOCSPResponse to be freed.
+ * RETURN:
+ *   No return value; no errors.
+ */
+extern void
+CERT_DestroyOCSPResponse(CERTOCSPResponse *response);
+
+/*
+ * FUNCTION: CERT_GetEncodedOCSPResponse
+ *   Creates and sends a request to an OCSP responder, then reads and
+ *   returns the (encoded) response.
+ * INPUTS:
+ *   PLArenaPool *arena
+ *     Pointer to arena from which return value will be allocated.
+ *     If NULL, result will be allocated from the heap (and thus should
+ *     be freed via SECITEM_FreeItem).
+ *   CERTCertList *certList
+ *     A list of certs for which status will be requested.
+ *     Note that all of these certificates should have the same issuer,
+ *     or it's expected the response will be signed by a trusted responder.
+ *     If the certs need to be broken up into multiple requests, that
+ *     must be handled by the caller (and thus by having multiple calls
+ *     to this routine), who knows about where the request(s) are being
+ *     sent and whether there are any trusted responders in place.
+ *   char *location
+ *     The location of the OCSP responder (a URL).
+ *   PRTime time
+ *     Indicates the time for which the certificate status is to be 
+ *     determined -- this may be used in the search for the cert's issuer
+ *     but has no other bearing on the operation.
+ *   PRBool addServiceLocator
+ *     If true, the Service Locator extension should be added to the
+ *     single request(s) for each cert.
+ *   CERTCertificate *signerCert
+ *     If non-NULL, means sign the request using this cert.  Otherwise,
+ *     do not sign.
+ *   void *pwArg
+ *     Pointer to argument for password prompting, if needed.  (Definitely
+ *     not needed if not signing.)
+ * OUTPUTS:
+ *   CERTOCSPRequest **pRequest
+ *     Pointer in which to store the OCSP request created for the given
+ *     list of certificates.  It is only filled in if the entire operation
+ *     is successful and the pointer is not null -- and in that case the
+ *     caller is then reponsible for destroying it.
+ * RETURN:
+ *   Returns a pointer to the SECItem holding the response.
+ *   On error, returns null with error set describing the reason:
+ *	SEC_ERROR_UNKNOWN_ISSUER
+ *	SEC_ERROR_CERT_BAD_ACCESS_LOCATION
+ *	SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
+ *   Other errors are low-level problems (no memory, bad database, etc.).
+ */
+extern SECItem *
+CERT_GetEncodedOCSPResponse(PLArenaPool *arena, CERTCertList *certList,
+			    char *location, PRTime time,
+			    PRBool addServiceLocator,
+			    CERTCertificate *signerCert, void *pwArg,
+			    CERTOCSPRequest **pRequest);
+
+/*
+ * FUNCTION: CERT_VerifyOCSPResponseSignature
+ *   Check the signature on an OCSP Response.  Will also perform a
+ *   verification of the signer's certificate.  Note, however, that a
+ *   successful verification does not make any statement about the
+ *   signer's *authority* to provide status for the certificate(s),
+ *   that must be checked individually for each certificate.
+ * INPUTS:
+ *   CERTOCSPResponse *response
+ *     Pointer to response structure with signature to be checked.
+ *   CERTCertDBHandle *handle
+ *     Pointer to CERTCertDBHandle for certificate DB to use for verification.
+ *   void *pwArg
+ *     Pointer to argument for password prompting, if needed.
+ *   CERTCertificate *issuerCert
+ *     Issuer of the certificate that generated the OCSP request.
+ * OUTPUTS:
+ *   CERTCertificate **pSignerCert
+ *     Pointer in which to store signer's certificate; only filled-in if
+ *     non-null.
+ * RETURN:
+ *   Returns SECSuccess when signature is valid, anything else means invalid.
+ *   Possible errors set:
+ *	SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID
+ *	SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time
+ *	SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found
+ *	SEC_ERROR_BAD_SIGNATURE - the signature did not verify
+ *   Other errors are any of the many possible failures in cert verification
+ *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
+ *   verifying the signer's cert, or low-level problems (no memory, etc.)
+ */
+extern SECStatus
+CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response,	
+				 CERTCertDBHandle *handle, void *pwArg,
+				 CERTCertificate **pSignerCert,
+				 CERTCertificate *issuerCert);
+
+/*
+ * FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation
+ *   Get the value of the URI of the OCSP responder for the given cert.
+ *   This is found in the (optional) Authority Information Access extension
+ *   in the cert.
+ * INPUTS:
+ *   CERTCertificate *cert
+ *     The certificate being examined.
+ * RETURN:
+ *   char *
+ *     A copy of the URI for the OCSP method, if found.  If either the
+ *     extension is not present or it does not contain an entry for OCSP,
+ *     SEC_ERROR_EXTENSION_NOT_FOUND will be set and a NULL returned.
+ *     Any other error will also result in a NULL being returned.
+ *     
+ *     This result should be freed (via PORT_Free) when no longer in use.
+ */
+extern char *
+CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert);
+
+/*
+ * FUNCTION: CERT_RegisterAlternateOCSPAIAInfoCallBack
+ *   This function serves two purposes.  
+ *   1) It registers the address of a callback function that will be 
+ *   called for certs that have no OCSP AIA extension, to see if the 
+ *   callback wishes to supply an alternative URL for such an OCSP inquiry.
+ *   2) It outputs the previously registered function's address to the 
+ *   address supplied by the caller, unless that is NULL.
+ *   The registered callback function returns NULL, or an allocated string 
+ *   that may be subsequently freed by calling PORT_Free().
+ * RETURN:
+ *   SECSuccess or SECFailure (if the library is not yet intialized)
+ */
+extern SECStatus
+CERT_RegisterAlternateOCSPAIAInfoCallBack(
+			CERT_StringFromCertFcn   newCallback,
+			CERT_StringFromCertFcn * oldCallback);
+
+/*
+ * FUNCTION: CERT_ParseURL
+ *   Parse the URI of a OCSP responder into hostname, port, and path.
+ * INPUTS:
+ *   const char *location
+ *     The URI to be parsed
+ * OUTPUTS:
+ *   char *pHostname
+ *     Pointer to store the hostname obtained from the URI.
+ *     This result should be freed (via PORT_Free) when no longer in use.
+ *   PRUint16 *pPort
+ *     Pointer to store the port number obtained from the URI.
+ *   char *pPath
+ *     Pointer to store the path obtained from the URI.
+ *     This result should be freed (via PORT_Free) when no longer in use.
+ * RETURN:
+ *   Returns SECSuccess when parsing was successful. Anything else means
+ *   problems were encountered.
+ *     
+ */
+extern SECStatus
+CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath);
+
+/*
+ * FUNCTION: CERT_CheckOCSPStatus
+ *   Checks the status of a certificate via OCSP.  Will only check status for
+ *   a certificate that has an AIA (Authority Information Access) extension
+ *   for OCSP *or* when a "default responder" is specified and enabled.
+ *   (If no AIA extension for OCSP and no default responder in place, the
+ *   cert is considered to have a good status and SECSuccess is returned.)
+ * INPUTS:
+ *   CERTCertDBHandle *handle
+ *     certificate DB of the cert that is being checked
+ *   CERTCertificate *cert
+ *     the certificate being checked
+ *   XXX in the long term also need a boolean parameter that specifies
+ *	whether to check the cert chain, as well; for now we check only
+ *	the leaf (the specified certificate)
+ *   PRTime time
+ *     time for which status is to be determined
+ *   void *pwArg
+ *     argument for password prompting, if needed
+ * RETURN:
+ *   Returns SECSuccess if an approved OCSP responder "knows" the cert
+ *   *and* returns a non-revoked status for it; SECFailure otherwise,
+ *   with an error set describing the reason:
+ *
+ *	SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
+ *	SEC_ERROR_OCSP_FUTURE_RESPONSE
+ *	SEC_ERROR_OCSP_MALFORMED_REQUEST
+ *	SEC_ERROR_OCSP_MALFORMED_RESPONSE
+ *	SEC_ERROR_OCSP_OLD_RESPONSE
+ *	SEC_ERROR_OCSP_REQUEST_NEEDS_SIG
+ *	SEC_ERROR_OCSP_SERVER_ERROR
+ *	SEC_ERROR_OCSP_TRY_SERVER_LATER
+ *	SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST
+ *	SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
+ *	SEC_ERROR_OCSP_UNKNOWN_CERT
+ *	SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
+ *	SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE
+ *
+ *	SEC_ERROR_BAD_SIGNATURE
+ *	SEC_ERROR_CERT_BAD_ACCESS_LOCATION
+ *	SEC_ERROR_INVALID_TIME
+ *	SEC_ERROR_REVOKED_CERTIFICATE
+ *	SEC_ERROR_UNKNOWN_ISSUER
+ *	SEC_ERROR_UNKNOWN_SIGNER
+ *
+ *   Other errors are any of the many possible failures in cert verification
+ *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
+ *   verifying the signer's cert, or low-level problems (error allocating
+ *   memory, error performing ASN.1 decoding, etc.).
+ */    
+extern SECStatus 
+CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
+		     PRTime time, void *pwArg);
+/*
+ * FUNCTION: CERT_GetOCSPStatusForCertID
+ *  Returns the OCSP status contained in the passed in paramter response
+ *  that corresponds to the certID passed in.
+ * INPUTS:
+ *  CERTCertDBHandle *handle
+ *    certificate DB of the cert that is being checked
+ *  CERTOCSPResponse *response
+ *    the OCSP response we want to retrieve status from.
+ *  CERTOCSPCertID *certID
+ *    the ID we want to look for from the response.
+ *  CERTCertificate *signerCert
+ *    the certificate that was used to sign the OCSP response.
+ *    must be obtained via a call to CERT_VerifyOCSPResponseSignature.
+ *  PRTime time
+ *    The time at which we're checking the status for.
+ *  RETURN:
+ *    Return values are the same as those for CERT_CheckOCSPStatus
+ */
+extern SECStatus
+CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle, 
+			    CERTOCSPResponse *response,
+			    CERTOCSPCertID   *certID,
+			    CERTCertificate  *signerCert,
+                            PRTime            time);
+
+/*
+ * FUNCTION CERT_GetOCSPResponseStatus
+ *   Returns the response status for the response passed.
+ * INPUTS:
+ *   CERTOCSPResponse *response
+ *     The response to query for status
+ *  RETURN:
+ *    Returns SECSuccess if the response has a successful status value.
+ *    Otherwise it returns SECFailure and sets one of the following error
+ *    codes via PORT_SetError
+ *        SEC_ERROR_OCSP_MALFORMED_REQUEST
+ *        SEC_ERROR_OCSP_SERVER_ERROR
+ *        SEC_ERROR_OCSP_TRY_SERVER_LATER
+ *        SEC_ERROR_OCSP_REQUEST_NEEDS_SIG
+ *        SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST
+ *        SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
+ */
+extern SECStatus
+CERT_GetOCSPResponseStatus(CERTOCSPResponse *response);
+
+/*
+ * FUNCTION CERT_CreateOCSPCertID
+ *  Returns the OCSP certID for the certificate passed in.
+ * INPUTS:
+ *  CERTCertificate *cert
+ *    The certificate for which to create the certID for.
+ *  PRTime time
+ *    The time at which the id is requested for.  This is used
+ *    to determine the appropriate issuer for the cert since
+ *    the issuing CA may be an older expired certificate.
+ *  RETURN:
+ *    A new copy of a CERTOCSPCertID*.  The memory for this certID
+ *    should be freed by calling CERT_DestroyOCSPCertID when the 
+ *    certID is no longer necessary.
+ */
+extern CERTOCSPCertID*
+CERT_CreateOCSPCertID(CERTCertificate *cert, PRTime time);
+
+/*
+ * FUNCTION: CERT_DestroyOCSPCertID
+ *  Frees the memory associated with the certID passed in.
+ * INPUTS:
+ *  CERTOCSPCertID* certID
+ *    The certID that the caller no longer needs and wants to 
+ *    free the associated memory.
+ * RETURN:
+ *  SECSuccess if freeing the memory was successful.  Returns
+ *  SECFailure if the memory passed in was not allocated with
+ *  a call to CERT_CreateOCSPCertID.
+ */
+extern SECStatus
+CERT_DestroyOCSPCertID(CERTOCSPCertID* certID);
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif /* _OCSP_H_ */
diff --git a/mozilla/security/nss/lib/certhigh/ocspi.h b/mozilla/security/nss/lib/certhigh/ocspi.h
new file mode 100644
index 0000000..8a76cab
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/ocspi.h
@@ -0,0 +1,172 @@
+/* ***** 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 ***** */
+/*
+ * ocspi.h - NSS internal interfaces to OCSP code
+ *
+ * $Id: ocspi.h,v 1.11 2008/10/31 23:02:37 alexei.volkov.bugs%sun.com Exp $
+ */
+
+#ifndef _OCSPI_H_
+#define _OCSPI_H_
+
+SECStatus OCSP_InitGlobal(void);
+SECStatus OCSP_ShutdownGlobal(void);
+
+ocspResponseData *
+ocsp_GetResponseData(CERTOCSPResponse *response, SECItem **tbsResponseDataDER);
+
+ocspSignature *
+ocsp_GetResponseSignature(CERTOCSPResponse *response);
+
+PRBool
+ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle *handle, CERTCertificate *cert);
+
+CERTCertificate *
+ocsp_GetSignerCertificate(CERTCertDBHandle *handle, ocspResponseData *tbsData,
+                          ocspSignature *signature, CERTCertificate *issuer);
+
+SECStatus
+ocsp_VerifyResponseSignature(CERTCertificate *signerCert,
+                             ocspSignature *signature,
+                             SECItem *tbsResponseDataDER,
+                             void *pwArg);
+
+CERTOCSPRequest *
+cert_CreateSingleCertOCSPRequest(CERTOCSPCertID *certID, 
+                                 CERTCertificate *singleCert, 
+                                 int64 time, 
+                                 PRBool addServiceLocator,
+                                 CERTCertificate *signerCert);
+
+SECStatus
+ocsp_GetCachedOCSPResponseStatusIfFresh(CERTOCSPCertID *certID, 
+                                        int64 time, 
+                                        PRBool ignoreOcspFailureMode,
+                                        SECStatus *rvOcsp,
+                                        SECErrorCodes *missingResponseError);
+
+/*
+ * FUNCTION: cert_ProcessOCSPResponse
+ *  Same behavior and basic parameters as CERT_GetOCSPStatusForCertID.
+ *  In addition it can update the OCSP cache (using information
+ *  available internally to this function).
+ * INPUTS:
+ *  CERTCertDBHandle *handle
+ *    certificate DB of the cert that is being checked
+ *  CERTOCSPResponse *response
+ *    the OCSP response we want to retrieve status from.
+ *  CERTOCSPCertID *certID
+ *    the ID we want to look for from the response.
+ *  CERTCertificate *signerCert
+ *    the certificate that was used to sign the OCSP response.
+ *    must be obtained via a call to CERT_VerifyOCSPResponseSignature.
+ *  int64 time
+ *    The time at which we're checking the status for.
+ *  PRBool *certIDWasConsumed
+ *    In and Out parameter.
+ *    If certIDWasConsumed is NULL on input,
+ *    this function might produce a deep copy of cert ID
+ *    for storing it in the cache.
+ *    If out value is true, ownership of parameter certID was
+ *    transferred to the OCSP cache.
+ *  SECStatus *cacheUpdateStatus
+ *    This optional out parameter will contain the result
+ *    of the cache update operation (if requested).
+ *  RETURN:
+ *    The return value is not influenced by the cache operation,
+ *    it matches the documentation for CERT_CheckOCSPStatus
+ */
+
+SECStatus
+cert_ProcessOCSPResponse(CERTCertDBHandle *handle, 
+                         CERTOCSPResponse *response, 
+                         CERTOCSPCertID   *certID,
+                         CERTCertificate  *signerCert,
+                         int64             time,
+                         PRBool           *certIDWasConsumed,
+                         SECStatus        *cacheUpdateStatus);
+
+/*
+ * FUNCTION: cert_RememberOCSPProcessingFailure
+ *  If an application notices a failure during OCSP processing,
+ *  it should finally call this function. The failure will be recorded
+ *  in the OCSP cache in order to avoid repetitive failures.
+ * INPUTS:
+ *  CERTOCSPCertID *certID
+ *    the ID that was used for the failed OCSP processing
+ *  PRBool *certIDWasConsumed
+ *    Out parameter, if set to true, ownership of parameter certID was
+ *    transferred to the OCSP cache.
+ *  RETURN:
+ *    Status of the cache update operation.
+ */
+
+SECStatus
+cert_RememberOCSPProcessingFailure(CERTOCSPCertID *certID,
+                                   PRBool         *certIDWasConsumed);
+
+/*
+ * FUNCTION: ocsp_GetResponderLocation
+ *  Check ocspx context for user-designated responder URI first. If not
+ *  found, checks cert AIA extension.
+ * INPUTS:
+ *  CERTCertDBHandle *handle
+ *    certificate DB of the cert that is being checked
+ *  CERTCertificate *cert
+ *     The certificate being examined.
+ *  PRBool *certIDWasConsumed
+ *    Out parameter, if set to true, URI of default responder is
+ *    returned.
+ *  RETURN:
+ *    Responder URI.
+ */
+char *
+ocsp_GetResponderLocation(CERTCertDBHandle *handle,
+                          CERTCertificate *cert,
+                          PRBool canUseDefaultLocation,
+                          PRBool *isDefault);
+
+/* FUNCTION: ocsp_FetchingFailureIsVerificationFailure
+ * The function checks the global ocsp settings and
+ * tells how to treat an ocsp response fetching failure.
+ * RETURNS:
+ *   if PR_TRUE is returned, then treat fetching as a
+ *   revoked cert status.
+ */
+PRBool
+ocsp_FetchingFailureIsVerificationFailure();
+
+#endif /* _OCSPI_H_ */
diff --git a/mozilla/security/nss/lib/certhigh/ocspt.h b/mozilla/security/nss/lib/certhigh/ocspt.h
new file mode 100644
index 0000000..d5186f9
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/ocspt.h
@@ -0,0 +1,316 @@
+/* ***** 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 ***** */
+
+/*
+ * Public header for exported OCSP types.
+ *
+ * $Id: ocspt.h,v 1.9 2007/03/23 06:57:57 kaie%kuix.de Exp $
+ */
+
+#ifndef _OCSPT_H_
+#define _OCSPT_H_
+
+/*
+ * The following are all opaque types.  If someone needs to get at
+ * a field within, then we need to fix the API.  Try very hard not
+ * make the type available to them.
+ */
+typedef struct CERTOCSPRequestStr CERTOCSPRequest;
+typedef struct CERTOCSPResponseStr CERTOCSPResponse;
+
+/*
+ * XXX I think only those first two above should need to be exported,
+ * but until I know for certain I am leaving the rest of these here, too.
+ */
+typedef struct CERTOCSPCertIDStr CERTOCSPCertID;
+typedef struct CERTOCSPCertStatusStr CERTOCSPCertStatus;
+typedef struct CERTOCSPSingleResponseStr CERTOCSPSingleResponse;
+
+/*
+ * This interface is described in terms of an HttpClient which
+ * supports at least a specified set of functions. (An implementer may
+ * provide HttpClients with additional functionality accessible only to
+ * users with a particular implementation in mind.) The basic behavior
+ * is provided by defining a set of functions, listed in an
+ * SEC_HttpServerFcnStruct. If the implementor of a SpecificHttpClient
+ * registers his SpecificHttpClient as the default HttpClient, then his
+ * functions will be called by the user of an HttpClient, such as an
+ * OCSPChecker.
+ *
+ * The implementer of a specific HttpClient (e.g., the NSS-provided
+ * DefaultHttpClient), populates an SEC_HttpClientFcnStruct, uses it to
+ * register his client, and waits for his functions to be called.
+ *
+ * For future expandability, the SEC_HttpClientFcnStruct is defined as a
+ * union, with the version field acting as a selector. The proposed
+ * initial version of the structure is given following the definition
+ * of the union. The HttpClientState structure is implementation-
+ * dependent, and should be opaque to the user.
+ */
+
+typedef void * SEC_HTTP_SERVER_SESSION;
+typedef void * SEC_HTTP_REQUEST_SESSION;
+
+/*
+ * This function creates a SEC_HTTP_SERVER_SESSION object. The implementer of a
+ * specific HttpClient will allocate the necessary space, when this
+ * function is called, and will free it when the corresponding FreeFcn
+ * is called. The SEC_HTTP_SERVER_SESSION object is passed, as an opaque object,
+ * to subsequent calls.
+ *
+ * If the function returns SECSuccess, the returned SEC_HTTP_SERVER_SESSION
+ * must be cleaned up with a call to SEC_HttpServer_FreeSession,
+ * after processing is finished.
+ */
+typedef SECStatus (*SEC_HttpServer_CreateSessionFcn)(
+   const char *host,
+   PRUint16 portnum,
+   SEC_HTTP_SERVER_SESSION *pSession);
+
+/*
+ * This function is called to allow the implementation to attempt to keep
+ * the connection alive. Depending on the underlying platform, it might
+ * immediately return SECSuccess without having performed any operations.
+ * (If a connection has not been kept alive, a subsequent call to
+ * SEC_HttpRequest_TrySendAndReceiveFcn should reopen the connection
+ * automatically.)
+ *
+ * If the connection uses nonblocking I/O, this function may return
+ * SECWouldBlock and store a nonzero value at "pPollDesc". In that case
+ * the caller may wait on the poll descriptor, and should call this function
+ * again until SECSuccess (and a zero value at "pPollDesc") is obtained.
+ */ 
+typedef SECStatus (*SEC_HttpServer_KeepAliveSessionFcn)(
+   SEC_HTTP_SERVER_SESSION session,
+   PRPollDesc **pPollDesc);
+
+/*
+ * This function frees the client SEC_HTTP_SERVER_SESSION object, closes all
+ * SEC_HTTP_REQUEST_SESSIONs created for that server, discards all partial results,
+ * frees any memory that was allocated by the client, and invalidates any
+ * response pointers that might have been returned by prior server or request
+ * functions.
+ */ 
+typedef SECStatus (*SEC_HttpServer_FreeSessionFcn)(
+   SEC_HTTP_SERVER_SESSION session);
+
+/*
+ * This function creates a SEC_HTTP_REQUEST_SESSION object. The implementer of a
+ * specific HttpClient will allocate the necessary space, when this
+ * function is called, and will free it when the corresponding FreeFcn
+ * is called. The SEC_HTTP_REQUEST_SESSION object is passed, as an opaque object,
+ * to subsequent calls.
+ *
+ * An implementation that does not support the requested protocol variant
+ * (usually "http", but could eventually allow "https") or request method
+ * should return SECFailure.
+ *
+ * Timeout values may include the constants PR_INTERVAL_NO_TIMEOUT (wait
+ * forever) or PR_INTERVAL_NO_WAIT (nonblocking I/O).
+ *
+ * If the function returns SECSuccess, the returned SEC_HTTP_REQUEST_SESSION
+ * must be cleaned up with a call to SEC_HttpRequest_FreeSession,
+ * after processing is finished.
+ */
+typedef SECStatus (*SEC_HttpRequest_CreateFcn)(
+   SEC_HTTP_SERVER_SESSION session,
+   const char *http_protocol_variant, /* usually "http" */
+   const char *path_and_query_string,
+   const char *http_request_method, 
+   const PRIntervalTime timeout, 
+   SEC_HTTP_REQUEST_SESSION *pRequest);
+
+/*
+ * This function sets data to be sent to the server for an HTTP request
+ * of http_request_method == POST. If a particular implementation 
+ * supports it, the details for the POST request can be set by calling 
+ * this function, prior to activating the request with TrySendAndReceiveFcn.
+ *
+ * An implementation that does not support the POST method should 
+ * implement a SetPostDataFcn function that returns immediately.
+ *
+ * Setting http_content_type is optional, the parameter may
+ * by NULL or the empty string.
+ */ 
+typedef SECStatus (*SEC_HttpRequest_SetPostDataFcn)(
+   SEC_HTTP_REQUEST_SESSION request,
+   const char *http_data, 
+   const PRUint32 http_data_len,
+   const char *http_content_type);
+
+/*
+ * This function sets an additional HTTP protocol request header.
+ * If a particular implementation supports it, one or multiple headers
+ * can be added to the request by calling this function once or multiple
+ * times, prior to activating the request with TryFcn.
+ *
+ * An implementation that does not support setting additional headers
+ * should implement an AddRequestHeaderFcn function that returns immediately.
+ */ 
+typedef SECStatus (*SEC_HttpRequest_AddHeaderFcn)(
+   SEC_HTTP_REQUEST_SESSION request,
+   const char *http_header_name, 
+   const char *http_header_value);
+
+/*
+ * This function initiates or continues an HTTP request. After
+ * parameters have been set with the Create function and, optionally,
+ * modified or enhanced with the AddParams function, this call creates
+ * the socket connection and initiates the communication.
+ *
+ * If a timeout value of zero is specified, indicating non-blocking
+ * I/O, the client creates a non-blocking socket, and returns a status
+ * of SECWouldBlock and a non-NULL PRPollDesc if the operation is not
+ * complete. In that case all other return parameters are undefined.
+ * The caller is expected to repeat the call, possibly after using
+ * PRPoll to determine that a completion has occurred, until a return
+ * value of SECSuccess (and a NULL value for pPollDesc) or a return
+ * value of SECFailure (indicating failure on the network level)
+ * is obtained.
+ *
+ * http_response_data_len is both input and output parameter.
+ * If a pointer to a PRUint32 is supplied, the http client is
+ * expected to check the given integer value and always set an out
+ * value, even on failure.
+ * An input value of zero means, the caller will accept any response len.
+ * A different input value indicates the maximum response value acceptable
+ * to the caller.
+ * If data is successfully read and the size is acceptable to the caller,
+ * the function will return SECSuccess and set http_response_data_len to
+ * the size of the block returned in http_response_data.
+ * If the data read from the http server is larger than the acceptable
+ * size, the function will return SECFailure.
+ * http_response_data_len will be set to a value different from zero to
+ * indicate the reason of the failure.
+ * An out value of "0" means, the failure was unrelated to the 
+ * acceptable size.
+ * An out value of "1" means, the result data is larger than the
+ * accpeptable size, but the real size is not yet known to the http client 
+ * implementation and it stopped retrieving it,
+ * Any other out value combined with a return value of SECFailure
+ * will indicate the actual size of the server data.
+ *
+ * The caller is permitted to provide NULL values for any of the
+ * http_response arguments, indicating the caller is not interested in
+ * those values. If the caller does provide an address, the HttpClient
+ * stores at that address a pointer to the corresponding argument, at
+ * the completion of the operation.
+ *
+ * All returned pointers will be owned by the the HttpClient
+ * implementation and will remain valid until the call to 
+ * SEC_HttpRequest_FreeFcn.
+ */ 
+typedef SECStatus (*SEC_HttpRequest_TrySendAndReceiveFcn)(
+   SEC_HTTP_REQUEST_SESSION request,
+   PRPollDesc **pPollDesc,
+   PRUint16 *http_response_code, 
+   const char **http_response_content_type, 
+   const char **http_response_headers, 
+   const char **http_response_data, 
+   PRUint32 *http_response_data_len); 
+
+/*
+ * Calling CancelFcn asks for premature termination of the request.
+ *
+ * Future calls to SEC_HttpRequest_TrySendAndReceive should
+ * by avoided, but in this case the HttpClient implementation 
+ * is expected to return immediately with SECFailure.
+ *
+ * After calling CancelFcn, a separate call to SEC_HttpRequest_FreeFcn 
+ * is still necessary to free resources.
+ */ 
+typedef SECStatus (*SEC_HttpRequest_CancelFcn)(
+   SEC_HTTP_REQUEST_SESSION request);
+
+/*
+ * Before calling this function, it must be assured the request
+ * has been completed, i.e. either SEC_HttpRequest_TrySendAndReceiveFcn has
+ * returned SECSuccess, or the request has been canceled with
+ * a call to SEC_HttpRequest_CancelFcn.
+ * 
+ * This function frees the client state object, closes all sockets, 
+ * discards all partial results, frees any memory that was allocated 
+ * by the client, and invalidates all response pointers that might
+ * have been returned by SEC_HttpRequest_TrySendAndReceiveFcn
+ */ 
+typedef SECStatus (*SEC_HttpRequest_FreeFcn)(
+   SEC_HTTP_REQUEST_SESSION request);
+
+typedef struct SEC_HttpClientFcnV1Struct {
+   SEC_HttpServer_CreateSessionFcn createSessionFcn;
+   SEC_HttpServer_KeepAliveSessionFcn keepAliveSessionFcn;
+   SEC_HttpServer_FreeSessionFcn freeSessionFcn;
+   SEC_HttpRequest_CreateFcn createFcn;
+   SEC_HttpRequest_SetPostDataFcn setPostDataFcn;
+   SEC_HttpRequest_AddHeaderFcn addHeaderFcn;
+   SEC_HttpRequest_TrySendAndReceiveFcn trySendAndReceiveFcn;
+   SEC_HttpRequest_CancelFcn cancelFcn;
+   SEC_HttpRequest_FreeFcn freeFcn;
+} SEC_HttpClientFcnV1;
+
+typedef struct SEC_HttpClientFcnStruct {
+   PRInt16 version;
+   union {
+      SEC_HttpClientFcnV1 ftable1;
+      /* SEC_HttpClientFcnV2 ftable2; */
+      /* ...                      */
+   } fcnTable;
+} SEC_HttpClientFcn;
+
+/*
+ * ocspMode_FailureIsVerificationFailure:
+ * This is the classic behaviour of NSS.
+ * Any OCSP failure is a verification failure (classic mode, default).
+ * Without a good response, OCSP networking will be retried each time
+ * it is required for verifying a cert.
+ *
+ * ocspMode_FailureIsNotAVerificationFailure:
+ * If we fail to obtain a valid OCSP response, consider the
+ * cert as good.
+ * Failed OCSP attempts might get cached and not retried until
+ * minimumSecondsToNextFetchAttempt.
+ * If we are able to obtain a valid response, the cert
+ * will be considered good, if either status is "good"
+ * or the cert was not yet revoked at verification time.
+ *
+ * Additional failure modes might be added in the future.
+ */
+typedef enum {
+    ocspMode_FailureIsVerificationFailure = 0,
+    ocspMode_FailureIsNotAVerificationFailure = 1
+} SEC_OcspFailureMode;
+
+#endif /* _OCSPT_H_ */
diff --git a/mozilla/security/nss/lib/certhigh/ocspti.h b/mozilla/security/nss/lib/certhigh/ocspti.h
new file mode 100644
index 0000000..c457b2c
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/ocspti.h
@@ -0,0 +1,409 @@
+/* ***** 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 ***** */
+
+/*
+ * Private header defining OCSP types.
+ *
+ * $Id: ocspti.h,v 1.7 2007/01/09 23:39:08 alexei.volkov.bugs%sun.com Exp $
+ */
+
+#ifndef _OCSPTI_H_
+#define _OCSPTI_H_
+
+#include "ocspt.h"
+
+#include "certt.h"
+#include "plarena.h"
+#include "seccomon.h"
+#include "secoidt.h"
+
+
+/*
+ * Some notes about naming conventions...
+ *
+ * The public data types all start with "CERTOCSP" (e.g. CERTOCSPRequest).
+ * (Even the public types are opaque, however.  Only their names are
+ * "exported".)
+ *
+ * Internal-only data types drop the "CERT" prefix and use only the
+ * lower-case "ocsp" (e.g. ocspTBSRequest), for brevity sake.
+ *
+ * In either case, the base/suffix of the type name usually matches the
+ * name as defined in the OCSP specification.  The exceptions to this are:
+ *  - When there is overlap between the "OCSP" or "ocsp" prefix and
+ *    the name used in the standard.  That is, you cannot strip off the
+ *    "CERTOCSP" or "ocsp" prefix and necessarily get the name of the
+ *    type as it is defined in the standard; the "real" name will be
+ *    *either* "OCSPSuffix" or just "Suffix".
+ *  - When the name in the standard was a little too generic.  (e.g. The
+ *    standard defines "Request" but we call it a "SingleRequest".)
+ *    In this case a comment above the type definition calls attention
+ *    to the difference.
+ *
+ * The definitions laid out in this header file are intended to follow
+ * the same order as the definitions in the OCSP specification itself.
+ * With the OCSP standard in hand, you should be able to move through
+ * this file and follow along.  To future modifiers of this file: please
+ * try to keep it that way.  The only exceptions are the few cases where
+ * we need to define a type before it is referenced (e.g. enumerations),
+ * whereas in the OCSP specification these are usually defined the other
+ * way around (reference before definition).
+ */
+
+
+/*
+ * Forward-declarations of internal-only data structures.
+ *
+ * These are in alphabetical order (case-insensitive); please keep it that way!
+ */
+typedef struct ocspBasicOCSPResponseStr ocspBasicOCSPResponse;
+typedef struct ocspCertStatusStr ocspCertStatus;
+typedef struct ocspResponderIDStr ocspResponderID;
+typedef struct ocspResponseBytesStr ocspResponseBytes;
+typedef struct ocspResponseDataStr ocspResponseData;
+typedef struct ocspRevokedInfoStr ocspRevokedInfo;
+typedef struct ocspServiceLocatorStr ocspServiceLocator;
+typedef struct ocspSignatureStr ocspSignature;
+typedef struct ocspSingleRequestStr ocspSingleRequest;
+typedef struct ocspSingleResponseStr ocspSingleResponse;
+typedef struct ocspTBSRequestStr ocspTBSRequest;
+
+
+/*
+ * An OCSPRequest; this is what is sent (encoded) to an OCSP responder.
+ */
+struct CERTOCSPRequestStr {
+    PRArenaPool *arena;			/* local; not part of encoding */
+    ocspTBSRequest *tbsRequest;
+    ocspSignature *optionalSignature;
+};
+
+/*
+ * A TBSRequest; when an OCSPRequest is signed, the encoding of this
+ * is what the signature is actually applied to.  ("TBS" == To Be Signed)
+ * Whether signed or not, however, this structure will be present, and
+ * is the "meat" of the OCSPRequest.
+ *
+ * Note that the "requestorName" field cannot be encoded/decoded in the
+ * same pass as the entire request -- it needs to be handled with a special
+ * call to convert to/from our internal form of a GeneralName.  Thus the
+ * "derRequestorName" field, which is the actual DER-encoded bytes.
+ *
+ * The "extensionHandle" field is used on creation only; it holds
+ * in-progress extensions as they are optionally added to the request.
+ */
+struct ocspTBSRequestStr {
+    SECItem version;			/* an INTEGER */
+    SECItem *derRequestorName;		/* encoded GeneralName; see above */
+    CERTGeneralNameList *requestorName;	/* local; not part of encoding */
+    ocspSingleRequest **requestList;
+    CERTCertExtension **requestExtensions;
+    void *extensionHandle;		/* local; not part of encoding */
+};
+
+/*
+ * This is the actual signature information for an OCSPRequest (applied to
+ * the TBSRequest structure) or for a BasicOCSPResponse (applied to a
+ * ResponseData structure).
+ *
+ * Note that the "signature" field itself is a BIT STRING; operations on
+ * it need to keep that in mind, converting the length to bytes as needed
+ * and back again afterward (so that the length is usually expressing bits).
+ *
+ * The "cert" field is the signer's certificate.  In the case of a received
+ * signature, it will be filled in when the signature is verified.  In the
+ * case of a created signature, it is filled in on creation and will be the
+ * cert used to create the signature when the signing-and-encoding occurs,
+ * as well as the cert (and its chain) to fill in derCerts if requested.
+ *
+ * The extra fields cache information about the signature after we have
+ * attempted a verification.  "wasChecked", if true, means the signature
+ * has been checked against the appropriate data and thus that "status"
+ * contains the result of that verification.  If "status" is not SECSuccess,
+ * "failureReason" is a copy of the error code that was set at the time;
+ * presumably it tells why the signature verification failed.
+ */
+struct ocspSignatureStr {
+    SECAlgorithmID signatureAlgorithm;
+    SECItem signature;			/* a BIT STRING */
+    SECItem **derCerts;			/* a SEQUENCE OF Certificate */
+    CERTCertificate *cert;		/* local; not part of encoding */
+    PRBool wasChecked;			/* local; not part of encoding */
+    SECStatus status;			/* local; not part of encoding */
+    int failureReason;			/* local; not part of encoding */
+};
+
+/*
+ * An OCSPRequest contains a SEQUENCE OF these, one for each certificate
+ * whose status is being checked.
+ *
+ * Note that in the OCSP specification this is just called "Request",
+ * but since that seemed confusing (vs. an OCSPRequest) and to be more
+ * consistent with the parallel type "SingleResponse", I called it a
+ * "SingleRequest".
+ * 
+ * XXX figure out how to get rid of that arena -- there must be a way
+ */
+struct ocspSingleRequestStr {
+    PRArenaPool *arena;			/* just a copy of the response arena,
+					 * needed here for extension handling
+					 * routines, on creation only */
+    CERTOCSPCertID *reqCert;
+    CERTCertExtension **singleRequestExtensions;
+};
+
+/*
+ * A CertID is the means of identifying a certificate, used both in requests
+ * and in responses.
+ *
+ * When in a SingleRequest it specifies the certificate to be checked.
+ * When in a SingleResponse it is the cert whose status is being given.
+ */
+struct CERTOCSPCertIDStr {
+    SECAlgorithmID hashAlgorithm;
+    SECItem issuerNameHash;		/* an OCTET STRING */
+    SECItem issuerKeyHash;		/* an OCTET STRING */
+    SECItem serialNumber;		/* an INTEGER */
+    SECItem issuerSHA1NameHash;		/* keep other hashes around when */
+    SECItem issuerMD5NameHash;              /* we have them */
+    SECItem issuerMD2NameHash;
+    SECItem issuerSHA1KeyHash;		/* keep other hashes around when */
+    SECItem issuerMD5KeyHash;              /* we have them */
+    SECItem issuerMD2KeyHash;
+    PRArenaPool *poolp;
+};
+
+/*
+ * This describes the value of the responseStatus field in an OCSPResponse.
+ * The corresponding ASN.1 definition is:
+ *
+ * OCSPResponseStatus	::=	ENUMERATED {
+ *	successful		(0),	--Response has valid confirmations
+ *	malformedRequest	(1),	--Illegal confirmation request
+ *	internalError		(2),	--Internal error in issuer
+ *	tryLater		(3),	--Try again later
+ *					--(4) is not used
+ *	sigRequired		(5),	--Must sign the request
+ *	unauthorized		(6),	--Request unauthorized
+ * }
+ */
+typedef enum {
+    ocspResponse_successful = 0,
+    ocspResponse_malformedRequest = 1,
+    ocspResponse_internalError = 2,
+    ocspResponse_tryLater = 3,
+    ocspResponse_unused = 4,
+    ocspResponse_sigRequired = 5,
+    ocspResponse_unauthorized = 6,
+    ocspResponse_other			/* unknown/unrecognized value */
+} ocspResponseStatus;
+
+/*
+ * An OCSPResponse is what is sent (encoded) by an OCSP responder.
+ *
+ * The field "responseStatus" is the ASN.1 encoded value; the field
+ * "statusValue" is simply that same value translated into our local
+ * type ocspResponseStatus.
+ */
+struct CERTOCSPResponseStr {
+    PRArenaPool *arena;			/* local; not part of encoding */
+    SECItem responseStatus;		/* an ENUMERATED, see above */
+    ocspResponseStatus statusValue;	/* local; not part of encoding */
+    ocspResponseBytes *responseBytes;	/* only when status is successful */
+};
+
+/*
+ * A ResponseBytes (despite appearances) is what contains the meat
+ * of a successful response -- but still in encoded form.  The type
+ * given as "responseType" tells you how to decode the string.
+ *
+ * We look at the OID and translate it into our local OID representation
+ * "responseTypeTag", and use that value to tell us how to decode the
+ * actual response itself.  For now the only kind of OCSP response we
+ * know about is a BasicOCSPResponse.  However, the intention in the
+ * OCSP specification is to allow for other response types, so we are
+ * building in that flexibility from the start and thus put a pointer
+ * to that data structure inside of a union.  Whenever OCSP adds more
+ * response types, just add them to the union.
+ */
+struct ocspResponseBytesStr {
+    SECItem responseType;		/* an OBJECT IDENTIFIER */
+    SECOidTag responseTypeTag;		/* local; not part of encoding */
+    SECItem response;			/* an OCTET STRING */
+    union {
+	ocspBasicOCSPResponse *basic;	/* when type is id-pkix-ocsp-basic */
+    } decodedResponse;			/* local; not part of encoding */
+};
+
+/*
+ * A BasicOCSPResponse -- when the responseType in a ResponseBytes is
+ * id-pkix-ocsp-basic, the "response" OCTET STRING above is the DER
+ * encoding of one of these.
+ *
+ * Note that in the OCSP specification, the signature fields are not
+ * part of a separate sub-structure.  But since they are the same fields
+ * as we define for the signature in a request, it made sense to share
+ * the C data structure here and in some shared code to operate on them.
+ */
+struct ocspBasicOCSPResponseStr {
+    SECItem tbsResponseDataDER;
+    ocspResponseData *tbsResponseData;	/* "tbs" == To Be Signed */
+    ocspSignature responseSignature;
+};
+
+/*
+ * A ResponseData is the part of a BasicOCSPResponse that is signed
+ * (after it is DER encoded).  It contains the real details of the response
+ * (a per-certificate status).
+ */
+struct ocspResponseDataStr {
+    SECItem version;			/* an INTEGER */
+    SECItem derResponderID;
+    ocspResponderID *responderID;	/* local; not part of encoding */
+    SECItem producedAt;			/* a GeneralizedTime */
+    CERTOCSPSingleResponse **responses;
+    CERTCertExtension **responseExtensions;
+};
+
+/*
+ * A ResponderID identifies the responder -- or more correctly, the
+ * signer of the response.  The ASN.1 definition of a ResponderID is:
+ *
+ * ResponderID	::=	CHOICE {
+ *	byName			[1] EXPLICIT Name,
+ *	byKey			[2] EXPLICIT KeyHash }
+ *
+ * Because it is CHOICE, the type of identification used and the
+ * identification itself are actually encoded together.  To represent
+ * this same information internally, we explicitly define a type and
+ * save it, along with the value, into a data structure.
+ */
+
+typedef enum {
+    ocspResponderID_byName,
+    ocspResponderID_byKey,
+    ocspResponderID_other		/* unknown kind of responderID */
+} ocspResponderIDType;
+
+struct ocspResponderIDStr {
+    ocspResponderIDType responderIDType;/* local; not part of encoding */
+    union {
+	CERTName name;			/* when ocspResponderID_byName */
+	SECItem keyHash;		/* when ocspResponderID_byKey */
+	SECItem other;			/* when ocspResponderID_other */
+    } responderIDValue;
+};
+
+/*
+ * The ResponseData in a BasicOCSPResponse contains a SEQUENCE OF
+ * SingleResponse -- one for each certificate whose status is being supplied.
+ * 
+ * XXX figure out how to get rid of that arena -- there must be a way
+ */
+struct CERTOCSPSingleResponseStr {
+    PRArenaPool *arena;			/* just a copy of the response arena,
+					 * needed here for extension handling
+					 * routines, on creation only */
+    CERTOCSPCertID *certID;
+    SECItem derCertStatus;
+    ocspCertStatus *certStatus;		/* local; not part of encoding */
+    SECItem thisUpdate;			/* a GeneralizedTime */
+    SECItem *nextUpdate;		/* a GeneralizedTime */
+    CERTCertExtension **singleExtensions;
+};
+
+/*
+ * A CertStatus is the actual per-certificate status.  Its ASN.1 definition:
+ *
+ * CertStatus	::=	CHOICE {
+ *	good			[0] IMPLICIT NULL,
+ *	revoked			[1] IMPLICIT RevokedInfo,
+ *	unknown			[2] IMPLICIT UnknownInfo }
+ *
+ * (where for now UnknownInfo is defined to be NULL but in the
+ * future may be replaced with an enumeration).
+ *
+ * Because it is CHOICE, the status value and its associated information
+ * (if any) are actually encoded together.  To represent this same
+ * information internally, we explicitly define a type and save it,
+ * along with the value, into a data structure.
+ */
+
+typedef enum {
+    ocspCertStatus_good,		/* cert is not revoked */
+    ocspCertStatus_revoked,		/* cert is revoked */
+    ocspCertStatus_unknown,		/* cert was unknown to the responder */
+    ocspCertStatus_other		/* status was not an expected value */
+} ocspCertStatusType;
+
+/*
+ * This is the actual per-certificate status.
+ *
+ * The "goodInfo" and "unknownInfo" items are only place-holders for a NULL.
+ * (Though someday OCSP may replace UnknownInfo with an enumeration that
+ * gives more detailed information.)
+ */
+struct ocspCertStatusStr {
+    ocspCertStatusType certStatusType;	/* local; not part of encoding */
+    union {
+	SECItem *goodInfo;		/* when ocspCertStatus_good */
+	ocspRevokedInfo *revokedInfo;	/* when ocspCertStatus_revoked */
+	SECItem *unknownInfo;		/* when ocspCertStatus_unknown */
+	SECItem *otherInfo;		/* when ocspCertStatus_other */
+    } certStatusInfo; 
+};
+
+/*
+ * A RevokedInfo gives information about a revoked certificate -- when it
+ * was revoked and why.
+ */
+struct ocspRevokedInfoStr {
+    SECItem revocationTime;		/* a GeneralizedTime */
+    SECItem *revocationReason;		/* a CRLReason; ignored for now */
+};
+
+/*
+ * ServiceLocator can be included as one of the singleRequestExtensions.
+ * When added, it specifies the (name of the) issuer of the cert being
+ * checked, and optionally the value of the AuthorityInfoAccess extension
+ * if the cert has one.
+ */
+struct ocspServiceLocatorStr {
+    CERTName *issuer;
+    SECItem locator;	/* DER encoded authInfoAccess extension from cert */
+};
+
+#endif /* _OCSPTI_H_ */
diff --git a/mozilla/security/nss/lib/certhigh/xcrldist.c b/mozilla/security/nss/lib/certhigh/xcrldist.c
new file mode 100644
index 0000000..d4d098a
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/xcrldist.c
@@ -0,0 +1,249 @@
+/* ***** 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 ***** */
+
+/*
+ * Code for dealing with x.509 v3 CRL Distribution Point extension.
+ */
+#include "genname.h"
+#include "certt.h"
+#include "secerr.h"
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_BitStringTemplate)
+
+extern void PrepareBitStringForEncoding (SECItem *bitMap, SECItem *value);
+
+static const SEC_ASN1Template FullNameTemplate[] = {
+    {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0,
+	offsetof (CRLDistributionPoint,derFullName), 
+	CERT_GeneralNamesTemplate}
+};
+
+static const SEC_ASN1Template RelativeNameTemplate[] = {
+    {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, 
+	offsetof (CRLDistributionPoint,distPoint.relativeName), 
+	CERT_RDNTemplate}
+};
+
+static const SEC_ASN1Template DistributionPointNameTemplate[] = {
+    { SEC_ASN1_CHOICE,
+	offsetof(CRLDistributionPoint, distPointType), NULL,
+	sizeof(CRLDistributionPoint) },
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0,
+	offsetof (CRLDistributionPoint, derFullName), 
+	CERT_GeneralNamesTemplate, generalName },
+    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, 
+	offsetof (CRLDistributionPoint, distPoint.relativeName), 
+	CERT_RDNTemplate, relativeDistinguishedName },
+    { 0 }
+};
+
+static const SEC_ASN1Template CRLDistributionPointTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRLDistributionPoint) },
+	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+	    SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0,
+	    offsetof(CRLDistributionPoint,derDistPoint),
+            SEC_ASN1_SUB(SEC_AnyTemplate)},
+	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
+	    offsetof(CRLDistributionPoint,bitsmap),
+            SEC_ASN1_SUB(SEC_BitStringTemplate) },
+	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+	    SEC_ASN1_CONSTRUCTED | 2,
+	    offsetof(CRLDistributionPoint, derCrlIssuer), 
+	    CERT_GeneralNamesTemplate},
+    { 0 }
+};
+
+const SEC_ASN1Template CERTCRLDistributionPointsTemplate[] = {
+    {SEC_ASN1_SEQUENCE_OF, 0, CRLDistributionPointTemplate}
+};
+
+SECStatus
+CERT_EncodeCRLDistributionPoints (PLArenaPool *arena, 
+				  CERTCrlDistributionPoints *value,
+				  SECItem *derValue)
+{
+    CRLDistributionPoint **pointList, *point;
+    PLArenaPool *ourPool = NULL;
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert (derValue);
+    PORT_Assert (value && value->distPoints);
+
+    do {
+	ourPool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+	if (ourPool == NULL) {
+	    rv = SECFailure;
+	    break;
+	}    
+	
+	pointList = value->distPoints;
+	while (*pointList) {
+	    point = *pointList;
+	    point->derFullName = NULL;
+	    point->derDistPoint.data = NULL;
+
+	    switch (point->distPointType) {
+	    case generalName:
+		point->derFullName = cert_EncodeGeneralNames
+		    (ourPool, point->distPoint.fullName);
+		
+		if (!point->derFullName ||
+		    !SEC_ASN1EncodeItem (ourPool, &point->derDistPoint,
+			  point, FullNameTemplate))
+		    rv = SECFailure;
+		break;
+
+	    case relativeDistinguishedName:
+		if (!SEC_ASN1EncodeItem(ourPool, &point->derDistPoint, 
+		      point, RelativeNameTemplate)) 
+		    rv = SECFailure;
+		break;
+
+	    /* distributionPointName is omitted */
+	    case 0: break;
+
+	    default:
+		PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID);
+		rv = SECFailure;
+		break;
+	    }
+
+	    if (rv != SECSuccess)
+		break;
+
+	    if (point->reasons.data)
+		PrepareBitStringForEncoding (&point->bitsmap, &point->reasons);
+
+	    if (point->crlIssuer) {
+		point->derCrlIssuer = cert_EncodeGeneralNames
+		    (ourPool, point->crlIssuer);
+		if (!point->derCrlIssuer) {
+		    rv = SECFailure;
+		    break;
+	    	}
+	    }
+	    ++pointList;
+	}
+	if (rv != SECSuccess)
+	    break;
+	if (!SEC_ASN1EncodeItem(arena, derValue, value, 
+		CERTCRLDistributionPointsTemplate)) {
+	    rv = SECFailure;
+	    break;
+	}
+    } while (0);
+    PORT_FreeArena (ourPool, PR_FALSE);
+    return rv;
+}
+
+CERTCrlDistributionPoints *
+CERT_DecodeCRLDistributionPoints (PLArenaPool *arena, SECItem *encodedValue)
+{
+   CERTCrlDistributionPoints *value = NULL;    
+   CRLDistributionPoint **pointList, *point;    
+   SECStatus rv = SECSuccess;
+   SECItem newEncodedValue;
+
+   PORT_Assert (arena);
+   do {
+	value = PORT_ArenaZNew(arena, CERTCrlDistributionPoints);
+	if (value == NULL) {
+	    rv = SECFailure;
+	    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->distPoints, 
+		CERTCRLDistributionPointsTemplate, &newEncodedValue);
+	if (rv != SECSuccess)
+	    break;
+
+	pointList = value->distPoints;
+	while (NULL != (point = *pointList)) {
+
+	    /* get the data if the distributionPointName is not omitted */
+	    if (point->derDistPoint.data != NULL) {
+		rv = SEC_QuickDERDecodeItem(arena, point, 
+			DistributionPointNameTemplate, &(point->derDistPoint));
+		if (rv != SECSuccess)
+		    break;
+
+		switch (point->distPointType) {
+		case generalName:
+		    point->distPoint.fullName = 
+			cert_DecodeGeneralNames(arena, point->derFullName);
+		    rv = point->distPoint.fullName ? SECSuccess : SECFailure;
+		    break;
+
+		case relativeDistinguishedName:
+		    break;
+
+		default:
+		    PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID);
+		    rv = SECFailure;
+		    break;
+		} /* end switch */
+		if (rv != SECSuccess)
+		    break;
+	    } /* end if */
+
+	    /* Get the reason code if it's not omitted in the encoding */
+	    if (point->bitsmap.data != NULL) {
+	    	SECItem bitsmap = point->bitsmap;
+		DER_ConvertBitString(&bitsmap);
+		rv = SECITEM_CopyItem(arena, &point->reasons, &bitsmap);
+		if (rv != SECSuccess)
+		    break;
+	    }
+
+	    /* Get the crl issuer name if it's not omitted in the encoding */
+	    if (point->derCrlIssuer != NULL) {
+		point->crlIssuer = cert_DecodeGeneralNames(arena, 
+			           point->derCrlIssuer);
+		if (!point->crlIssuer)
+		    break;
+	    }
+	    ++pointList;
+	} /* end while points remain */
+   } while (0);
+   return (rv == SECSuccess ? value : NULL);
+}
diff --git a/mozilla/security/nss/lib/cryptohi/cryptohi.h b/mozilla/security/nss/lib/cryptohi/cryptohi.h
new file mode 100644
index 0000000..4a1d87b
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/cryptohi.h
@@ -0,0 +1,401 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: cryptohi.h,v 1.13 2009/09/23 22:51:56 wtc%google.com Exp $ */
+
+#ifndef _CRYPTOHI_H_
+#define _CRYPTOHI_H_
+
+#include "blapit.h"
+
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secdert.h"
+#include "cryptoht.h"
+#include "keyt.h"
+#include "certt.h"
+
+
+SEC_BEGIN_PROTOS
+
+
+/****************************************/
+/*
+** DER encode/decode (EC)DSA signatures
+*/
+
+/* ANSI X9.57 defines DSA signatures as DER encoded data.  Our DSA code (and
+ * most of the rest of the world) just generates 40 bytes of raw data.  These
+ * functions convert between formats.
+ */
+extern SECStatus DSAU_EncodeDerSig(SECItem *dest, SECItem *src);
+extern SECItem *DSAU_DecodeDerSig(const SECItem *item);
+
+/*
+ * Unlike DSA, raw ECDSA signatures do not have a fixed length.
+ * Rather they contain two integers r and s whose length depends
+ * on the size of the EC key used for signing.
+ *
+ * We can reuse the DSAU_EncodeDerSig interface to DER encode
+ * raw ECDSA signature keeping in mind that the length of r 
+ * is the same as that of s and exactly half of src->len.
+ *
+ * For decoding, we need to pass the length of the desired
+ * raw signature (twice the key size) explicitly.
+ */
+extern SECStatus DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, 
+					  unsigned int len);
+extern SECItem *DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len);
+
+/****************************************/
+/*
+** Signature creation operations
+*/
+
+/*
+** Create a new signature context used for signing a data stream.
+**	"alg" the signature algorithm to use (e.g. SEC_OID_RSA_WITH_MD5)
+**	"privKey" the private key to use
+*/
+extern SGNContext *SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *privKey);
+
+/*
+** Destroy a signature-context object
+**	"key" the object
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void SGN_DestroyContext(SGNContext *cx, PRBool freeit);
+
+/*
+** Reset the signing context "cx" to its initial state, preparing it for
+** another stream of data.
+*/
+extern SECStatus SGN_Begin(SGNContext *cx);
+
+/*
+** Update the signing context with more data to sign.
+**	"cx" the context
+**	"input" the input data to sign
+**	"inputLen" the length of the input data
+*/
+extern SECStatus SGN_Update(SGNContext *cx, const unsigned char *input,
+			   unsigned int inputLen);
+
+/*
+** Finish the signature process. Use either k0 or k1 to sign the data
+** stream that was input using SGN_Update. The resulting signature is
+** formatted using PKCS#1 and then encrypted using RSA private or public
+** encryption.
+**	"cx" the context
+**	"result" the final signature data (memory is allocated)
+*/
+extern SECStatus SGN_End(SGNContext *cx, SECItem *result);
+
+/*
+** Sign a single block of data using private key encryption and given
+** signature/hash algorithm.
+**	"result" the final signature data (memory is allocated)
+**	"buf" the input data to sign
+**	"len" the amount of data to sign
+**	"pk" the private key to encrypt with
+**	"algid" the signature/hash algorithm to sign with 
+**		(must be compatible with the key type).
+*/
+extern SECStatus SEC_SignData(SECItem *result, unsigned char *buf, int len,
+			     SECKEYPrivateKey *pk, SECOidTag algid);
+
+/*
+** Sign a pre-digested block of data using private key encryption, encoding
+**  The given signature/hash algorithm.
+**	"result" the final signature data (memory is allocated)
+**	"digest" the digest to sign
+**	"pk" the private key to encrypt with
+**	"algtag" The algorithm tag to encode (need for RSA only)
+*/
+extern SECStatus SGN_Digest(SECKEYPrivateKey *privKey,
+                SECOidTag algtag, SECItem *result, SECItem *digest);
+
+/*
+** DER sign a single block of data using private key encryption and the
+** MD5 hashing algorithm. This routine first computes a digital signature
+** using SEC_SignData, then wraps it with an CERTSignedData and then der
+** encodes the result.
+**	"arena" is the memory arena to use to allocate data from
+** 	"result" the final der encoded data (memory is allocated)
+** 	"buf" the input data to sign
+** 	"len" the amount of data to sign
+** 	"pk" the private key to encrypt with
+*/
+extern SECStatus SEC_DerSignData(PLArenaPool *arena, SECItem *result,
+				unsigned char *buf, int len,
+				SECKEYPrivateKey *pk, SECOidTag algid);
+
+/*
+** Destroy a signed-data object.
+**	"sd" the object
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void SEC_DestroySignedData(CERTSignedData *sd, PRBool freeit);
+
+/*
+** Get the signature algorithm tag number for the given key type and hash
+** algorithm tag. Returns SEC_OID_UNKNOWN if key type and hash algorithm
+** do not match or are not supported.
+*/
+extern SECOidTag SEC_GetSignatureAlgorithmOidTag(KeyType keyType,
+                                                 SECOidTag hashAlgTag);
+
+/****************************************/
+/*
+** Signature verification operations
+*/
+
+/*
+** Create a signature verification context. This version is deprecated,
+**  This function is deprecated. Use VFY_CreateContextDirect or 
+**  VFY_CreateContextWithAlgorithmID instead.
+**	"key" the public key to verify with
+**	"sig" the encrypted signature data if sig is NULL then
+**	   VFY_EndWithSignature must be called with the correct signature at
+**	   the end of the processing.
+**	"sigAlg" specifies the signing algorithm to use (including the 
+**         hash algorthim).  This must match the key type.
+**	"wincx" void pointer to the window context
+*/
+extern VFYContext *VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig,
+				     SECOidTag sigAlg, void *wincx);
+/*
+** Create a signature verification context.
+**	"key" the public key to verify with
+**	"sig" the encrypted signature data if sig is NULL then
+**	   VFY_EndWithSignature must be called with the correct signature at
+**	   the end of the processing.
+**	"pubkAlg" specifies the cryptographic signing algorithm to use (the
+**         raw algorithm without any hash specified.  This must match the key 
+**         type.
+**	"hashAlg" specifies the hashing algorithm used. If the key is an 
+**	   RSA key, and sig is not NULL, then hashAlg can be SEC_OID_UNKNOWN.
+**	   the hash is selected from data in the sig.
+**	"hash" optional pointer to return the actual hash algorithm used.
+**	   in practice this should always match the passed in hashAlg (the
+**	   exception is the case where hashAlg is SEC_OID_UNKNOWN above).
+**         If this value is NULL no, hash oid is returned.
+**	"wincx" void pointer to the window context
+*/
+extern VFYContext *VFY_CreateContextDirect(const SECKEYPublicKey *key,
+					   const SECItem *sig,
+	     				   SECOidTag pubkAlg, 
+					   SECOidTag hashAlg, 
+					   SECOidTag *hash, void *wincx);
+/*
+** Create a signature verification context from a algorithm ID.
+**	"key" the public key to verify with
+**	"sig" the encrypted signature data if sig is NULL then
+**	   VFY_EndWithSignature must be called with the correct signature at
+**	   the end of the processing.
+**	"algid" specifies the signing algorithm and parameters to use.
+**         This must match the key type.
+**      "hash" optional pointer to return the oid of the actual hash used in 
+**         the signature. If this value is NULL no, hash oid is returned.
+**	"wincx" void pointer to the window context
+*/
+extern VFYContext *VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, 
+				     const SECItem *sig,
+				     const SECAlgorithmID *algid, 
+				     SECOidTag *hash,
+				     void *wincx);
+
+/*
+** Destroy a verification-context object.
+**	"cx" the context to destroy
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void VFY_DestroyContext(VFYContext *cx, PRBool freeit);
+
+extern SECStatus VFY_Begin(VFYContext *cx);
+
+/*
+** Update a verification context with more input data. The input data
+** is fed to a secure hash function (depending on what was in the
+** encrypted signature data).
+**	"cx" the context
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus VFY_Update(VFYContext *cx, const unsigned char *input,
+			    unsigned int inputLen);
+
+/*
+** Finish the verification process. The return value is a status which
+** indicates success or failure. On success, the SECSuccess value is
+** returned. Otherwise, SECFailure is returned and the error code found
+** using PORT_GetError() indicates what failure occurred.
+** 	"cx" the context
+*/
+extern SECStatus VFY_End(VFYContext *cx);
+
+/*
+** Finish the verification process. The return value is a status which
+** indicates success or failure. On success, the SECSuccess value is
+** returned. Otherwise, SECFailure is returned and the error code found
+** using PORT_GetError() indicates what failure occurred. If signature is
+** supplied the verification uses this signature to verify, otherwise the
+** signature passed in VFY_CreateContext() is used. 
+** VFY_EndWithSignature(cx,NULL); is identical to VFY_End(cx);.
+** 	"cx" the context
+** 	"sig" the encrypted signature data
+*/
+extern SECStatus VFY_EndWithSignature(VFYContext *cx, SECItem *sig);
+
+
+/*
+** Verify the signature on a block of data for which we already have
+** the digest. The signature data is an RSA private key encrypted
+** block of data formatted according to PKCS#1.
+**  This function is deprecated. Use VFY_VerifyDigestDirect or 
+**  VFY_VerifyDigestWithAlgorithmID instead.
+** 	"dig" the digest
+** 	"key" the public key to check the signature with
+** 	"sig" the encrypted signature data
+**	"sigAlg" specifies the signing algorithm to use.  This must match
+**	    the key type.
+**	"wincx" void pointer to the window context
+**/
+extern SECStatus VFY_VerifyDigest(SECItem *dig, SECKEYPublicKey *key,
+				  SECItem *sig, SECOidTag sigAlg, void *wincx);
+/*
+** Verify the signature on a block of data for which we already have
+** the digest. The signature data is an RSA private key encrypted
+** block of data formatted according to PKCS#1.
+** 	"dig" the digest
+** 	"key" the public key to check the signature with
+** 	"sig" the encrypted signature data
+**	"pubkAlg" specifies the cryptographic signing algorithm to use (the
+**         raw algorithm without any hash specified.  This must match the key 
+**         type.
+**	"hashAlg" specifies the hashing algorithm used.
+**	"wincx" void pointer to the window context
+**/
+extern SECStatus VFY_VerifyDigestDirect(const SECItem *dig, 
+					const SECKEYPublicKey *key,
+					const SECItem *sig, SECOidTag pubkAlg, 
+					SECOidTag hashAlg, void *wincx);
+/*
+** Verify the signature on a block of data for which we already have
+** the digest. The signature data is an RSA private key encrypted
+** block of data formatted according to PKCS#1.
+**	"key" the public key to verify with
+**	"sig" the encrypted signature data if sig is NULL then
+**	   VFY_EndWithSignature must be called with the correct signature at
+**	   the end of the processing.
+**	"algid" specifies the signing algorithm and parameters to use.
+**         This must match the key type.
+**      "hash" oid of the actual hash used to create digest. If this  value is
+**         not set to SEC_OID_UNKNOWN, it must match the hash of the signature.
+**	"wincx" void pointer to the window context
+*/
+extern SECStatus VFY_VerifyDigestWithAlgorithmID(const SECItem *dig, 
+				const SECKEYPublicKey *key, const SECItem *sig,
+				const SECAlgorithmID *algid, SECOidTag hash,
+				void *wincx);
+
+/*
+** Verify the signature on a block of data. The signature data is an RSA
+** private key encrypted block of data formatted according to PKCS#1.
+**   This function is deprecated. Use VFY_VerifyDataDirect or 
+**   VFY_VerifyDataWithAlgorithmID instead.
+** 	"buf" the input data
+** 	"len" the length of the input data
+** 	"key" the public key to check the signature with
+** 	"sig" the encrypted signature data
+**	"sigAlg" specifies the signing algorithm to use.  This must match
+**	    the key type.
+**	"wincx" void pointer to the window context
+*/
+extern SECStatus VFY_VerifyData(unsigned char *buf, int len,
+				SECKEYPublicKey *key, SECItem *sig,
+				SECOidTag sigAlg, void *wincx);
+/*
+** Verify the signature on a block of data. The signature data is an RSA
+** private key encrypted block of data formatted according to PKCS#1.
+** 	"buf" the input data
+** 	"len" the length of the input data
+** 	"key" the public key to check the signature with
+** 	"sig" the encrypted signature data
+**	"pubkAlg" specifies the cryptographic signing algorithm to use (the
+**         raw algorithm without any hash specified.  This must match the key 
+**         type.
+**	"hashAlg" specifies the hashing algorithm used. If the key is an 
+**	   RSA key, and sig is not NULL, then hashAlg can be SEC_OID_UNKNOWN.
+**	   the hash is selected from data in the sig.
+**	"hash" optional pointer to return the actual hash algorithm used.
+**	   in practice this should always match the passed in hashAlg (the
+**	   exception is the case where hashAlg is SEC_OID_UNKNOWN above).
+**         If this value is NULL no, hash oid is returned.
+**	"wincx" void pointer to the window context
+*/
+extern SECStatus VFY_VerifyDataDirect(const unsigned char *buf, int len,
+				      const SECKEYPublicKey *key, 
+				      const SECItem *sig,
+				      SECOidTag pubkAlg, SECOidTag hashAlg, 
+				      SECOidTag *hash, void *wincx);
+
+/*
+** Verify the signature on a block of data. The signature data is an RSA
+** private key encrypted block of data formatted according to PKCS#1.
+** 	"buf" the input data
+** 	"len" the length of the input data
+** 	"key" the public key to check the signature with
+** 	"sig" the encrypted signature data
+**	"algid" specifies the signing algorithm and parameters to use.
+**         This must match the key type.
+**      "hash" optional pointer to return the oid of the actual hash used in 
+**         the signature. If this value is NULL no, hash oid is returned.
+**	"wincx" void pointer to the window context
+*/
+extern SECStatus VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, 
+				int len, const SECKEYPublicKey *key,
+				 const SECItem *sig,
+				const SECAlgorithmID *algid, SECOidTag *hash,
+				void *wincx);
+
+
+SEC_END_PROTOS
+
+#endif /* _CRYPTOHI_H_ */
diff --git a/mozilla/security/nss/lib/cryptohi/cryptoht.h b/mozilla/security/nss/lib/cryptohi/cryptoht.h
new file mode 100644
index 0000000..fe43dff
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/cryptoht.h
@@ -0,0 +1,48 @@
+/*
+ * cryptoht.h - public data structures for the crypto library
+ *
+ * ***** 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 ***** */
+/* $Id: cryptoht.h,v 1.3 2004/04/27 23:04:35 gerv%gerv.net Exp $ */
+
+#ifndef _CRYPTOHT_H_
+#define _CRYPTOHT_H_
+
+typedef struct SGNContextStr SGNContext;
+typedef struct VFYContextStr VFYContext;
+
+
+#endif /* _CRYPTOHT_H_ */
diff --git a/mozilla/security/nss/lib/cryptohi/dsautil.c b/mozilla/security/nss/lib/cryptohi/dsautil.c
new file mode 100644
index 0000000..231a793
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/dsautil.c
@@ -0,0 +1,300 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 "cryptohi.h"
+#include "secasn1.h"
+#include "secitem.h"
+#include "prerr.h"
+
+#ifndef DSA_SUBPRIME_LEN
+#define DSA_SUBPRIME_LEN 20	/* bytes */
+#endif
+
+typedef struct {
+    SECItem r;
+    SECItem s;
+} DSA_ASN1Signature;
+
+const SEC_ASN1Template DSA_SignatureTemplate[] =
+{
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DSA_ASN1Signature) },
+    { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,r) },
+    { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,s) },
+    { 0, }
+};
+
+/* Input is variable length multi-byte integer, MSB first (big endian).
+** Most signficant bit of first byte is NOT treated as a sign bit. 
+** May be one or more leading bytes of zeros. 
+** Output is variable length multi-byte integer, MSB first (big endian).
+** Most significant bit of first byte will be zero (positive sign bit)
+** No more than one leading zero byte.
+** Caller supplies dest buffer, and assures that it is long enough,
+** e.g. at least one byte longer that src's buffer.
+*/
+void
+DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src)
+{
+    unsigned char *pSrc = src->data;
+    unsigned char *pDst = dest->data;
+    unsigned int   cntSrc = src->len;
+
+    /* skip any leading zeros. */
+    while (cntSrc && !(*pSrc)) { 
+    	pSrc++; 
+	cntSrc--;
+    }
+    if (!cntSrc) {
+    	*pDst = 0; 
+	dest->len = 1; 
+	return; 
+    }
+
+    if (*pSrc & 0x80)
+    	*pDst++ = 0;
+
+    PORT_Memcpy(pDst, pSrc, cntSrc);
+    dest->len = (pDst - dest->data) + cntSrc;
+}
+
+/*
+** src is a buffer holding a signed variable length integer.
+** dest is a buffer which will be filled with an unsigned integer,
+** MSB first (big endian) with leading zeros, so that the last byte
+** of src will be the LSB of the integer.  The result will be exactly
+** the length specified by the caller in dest->len.
+** src can be shorter than dest.  src can be longer than dst, but only
+** if the extra leading bytes are zeros.
+*/
+SECStatus
+DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src)
+{
+    unsigned char *pSrc = src->data;
+    unsigned char *pDst = dest->data;
+    unsigned int   cntSrc = src->len;
+    unsigned int   cntDst = dest->len;
+    int            zCount = cntDst - cntSrc;
+
+    if (zCount > 0) {
+    	PORT_Memset(pDst, 0, zCount);
+	PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
+	return SECSuccess;
+    }
+    if (zCount <= 0) {
+	/* Source is longer than destination.  Check for leading zeros. */
+	while (zCount++ < 0) {
+	    if (*pSrc++ != 0)
+		goto loser;
+	}
+    }
+    PORT_Memcpy(pDst, pSrc, cntDst);
+    return SECSuccess;
+
+loser:
+    PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
+    return SECFailure;
+}
+
+/* src is a "raw" ECDSA or DSA signature, the first half contains r
+ * and the second half contains s. dest is the DER encoded signature.
+*/
+static SECStatus
+common_EncodeDerSig(SECItem *dest, SECItem *src)
+{
+    SECItem *         item;
+    SECItem           srcItem;
+    DSA_ASN1Signature sig;
+    unsigned char     *signedR;
+    unsigned char     *signedS;
+    unsigned int len;
+
+    /* Allocate memory with room for an extra byte that
+     * may be required if the top bit in the first byte
+     * is already set.
+     */
+    len = src->len/2;
+    signedR = (unsigned char *) PORT_Alloc(len + 1);
+    if (!signedR) return SECFailure;
+    signedS = (unsigned char *) PORT_ZAlloc(len + 1);
+    if (!signedS) {
+        if (signedR) PORT_Free(signedR);
+	return SECFailure;
+    }
+
+    PORT_Memset(&sig, 0, sizeof(sig));
+
+    /* Must convert r and s from "unsigned" integers to "signed" integers.
+    ** If the high order bit of the first byte (MSB) is 1, then must
+    ** prepend with leading zero.  
+    ** Must remove all but one leading zero byte from numbers.
+    */
+    sig.r.type = siUnsignedInteger;
+    sig.r.data = signedR;
+    sig.r.len  = sizeof signedR;
+    sig.s.type = siUnsignedInteger;
+    sig.s.data = signedS;
+    sig.s.len  = sizeof signedR;
+
+    srcItem.data = src->data;
+    srcItem.len  = len;
+
+    DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
+    srcItem.data += len;
+    DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
+
+    item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
+    if (signedR) PORT_Free(signedR);
+    if (signedS) PORT_Free(signedS);
+    if (item == NULL)
+	return SECFailure;
+
+    /* XXX leak item? */
+    return SECSuccess;
+}
+
+/* src is a DER-encoded ECDSA or DSA signature.
+** Returns a newly-allocated SECItem structure, pointing at a newly allocated
+** buffer containing the "raw" signature, which is len bytes of r,
+** followed by len bytes of s. For DSA, len is always DSA_SUBPRIME_LEN.
+** For ECDSA, len depends on the key size used to create the signature.
+*/
+static SECItem *
+common_DecodeDerSig(const SECItem *item, unsigned int len)
+{
+    SECItem *         result = NULL;
+    SECStatus         status;
+    DSA_ASN1Signature sig;
+    SECItem           dst;
+
+    PORT_Memset(&sig, 0, sizeof(sig));
+
+    result = PORT_ZNew(SECItem);
+    if (result == NULL)
+	goto loser;
+
+    result->len  = 2 * len;
+    result->data = (unsigned char*)PORT_Alloc(2 * len);
+    if (result->data == NULL)
+	goto loser;
+
+    sig.r.type = siUnsignedInteger;
+    sig.s.type = siUnsignedInteger;
+    status = SEC_ASN1DecodeItem(NULL, &sig, DSA_SignatureTemplate, item);
+    if (status != SECSuccess)
+	goto loser;
+
+    /* Convert sig.r and sig.s from variable  length signed integers to 
+    ** fixed length unsigned integers.
+    */
+    dst.data = result->data;
+    dst.len  = len;
+    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
+    if (status != SECSuccess)
+    	goto loser;
+
+    dst.data += len;
+    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
+    if (status != SECSuccess)
+    	goto loser;
+
+done:
+    if (sig.r.data != NULL)
+	PORT_Free(sig.r.data);
+    if (sig.s.data != NULL)
+	PORT_Free(sig.s.data);
+
+    return result;
+
+loser:
+    if (result != NULL) {
+	SECITEM_FreeItem(result, PR_TRUE);
+	result = NULL;
+    }
+    goto done;
+}
+
+/* src is a "raw" DSA signature, 20 bytes of r followed by 20 bytes of s.
+** dest is the signature DER encoded. ?
+*/
+SECStatus
+DSAU_EncodeDerSig(SECItem *dest, SECItem *src)
+{
+    PORT_Assert(src->len == 2 * DSA_SUBPRIME_LEN);
+    if (src->len != 2 * DSA_SUBPRIME_LEN) {
+    	PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
+	return SECFailure;
+    }
+
+    return common_EncodeDerSig(dest, src);
+}
+
+/* src is a "raw" DSA signature of length len (len/2 bytes of r followed
+** by len/2 bytes of s). dest is the signature DER encoded.
+*/
+SECStatus
+DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len)
+{
+
+    PORT_Assert((src->len == len) && (len % 2 == 0));
+    if ((src->len != len) || (src->len % 2 != 0)) {
+    	PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
+	return SECFailure;
+    }
+
+    return common_EncodeDerSig(dest, src);
+}
+
+/* src is a DER-encoded DSA signature.
+** Returns a newly-allocated SECItem structure, pointing at a newly allocated
+** buffer containing the "raw" DSA signature, which is 20 bytes of r,
+** followed by 20 bytes of s.
+*/
+SECItem *
+DSAU_DecodeDerSig(const SECItem *item)
+{
+    return common_DecodeDerSig(item, DSA_SUBPRIME_LEN);
+}
+
+/* src is a DER-encoded ECDSA signature.
+** Returns a newly-allocated SECItem structure, pointing at a newly allocated
+** buffer containing the "raw" ECDSA signature of length len containing
+** r followed by s (both padded to take up exactly len/2 bytes).
+*/
+SECItem *
+DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len)
+{
+    return common_DecodeDerSig(item, len/2);
+}
diff --git a/mozilla/security/nss/lib/cryptohi/key.h b/mozilla/security/nss/lib/cryptohi/key.h
new file mode 100644
index 0000000..24f8153
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/key.h
@@ -0,0 +1,45 @@
+/* ***** 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 ***** */
+/* $Id: key.h,v 1.5 2009/10/15 23:58:13 wtc%google.com Exp $ */
+
+/* This header is deprecated.  Please include keyhi.h instead. */
+
+#ifndef _KEY_H_
+#define _KEY_H_
+
+#include "keyhi.h"
+
+#endif /* _KEY_H_ */
diff --git a/mozilla/security/nss/lib/cryptohi/keyhi.h b/mozilla/security/nss/lib/cryptohi/keyhi.h
new file mode 100644
index 0000000..b358e07
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/keyhi.h
@@ -0,0 +1,311 @@
+/* ***** 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):
+ *   Dr Stephen Henson <stephen.henson@gemplus.com>
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: keyhi.h,v 1.17 2008/06/14 14:20:00 wtc%google.com Exp $ */
+
+#ifndef _KEYHI_H_
+#define _KEYHI_H_
+
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secdert.h"
+#include "keythi.h"
+#include "certt.h"
+/*#include "secpkcs5.h" */
+
+SEC_BEGIN_PROTOS
+
+
+/*
+** Destroy a subject-public-key-info object.
+*/
+extern void SECKEY_DestroySubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki);
+
+/*
+** Copy subject-public-key-info "src" to "dst". "dst" is filled in
+** appropriately (memory is allocated for each of the sub objects).
+*/
+extern SECStatus SECKEY_CopySubjectPublicKeyInfo(PLArenaPool *arena,
+					     CERTSubjectPublicKeyInfo *dst,
+					     CERTSubjectPublicKeyInfo *src);
+
+/*
+** Update the PQG parameters for a cert's public key.
+** Only done for DSA and Fortezza certs
+*/
+extern SECStatus
+SECKEY_UpdateCertPQG(CERTCertificate * subjectCert);
+
+
+/* Compare the KEA parameters of two public keys.  
+ * Only used by fortezza.      */
+
+extern SECStatus
+SECKEY_KEAParamCompare(CERTCertificate *cert1,CERTCertificate *cert2);
+
+/*
+** Return the strength of the public key in bytes
+*/
+extern unsigned SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk);
+
+/*
+** Return the strength of the public key in bits
+*/
+extern unsigned SECKEY_PublicKeyStrengthInBits(const SECKEYPublicKey *pubk);
+
+/*
+** Return the length of the signature in bytes
+*/
+extern unsigned SECKEY_SignatureLen(const SECKEYPublicKey *pubk);
+
+/*
+** Make a copy of the private key "privKey"
+*/
+extern SECKEYPrivateKey *SECKEY_CopyPrivateKey(const SECKEYPrivateKey *privKey);
+
+/*
+** Make a copy of the public key "pubKey"
+*/
+extern SECKEYPublicKey *SECKEY_CopyPublicKey(const SECKEYPublicKey *pubKey);
+
+/*
+** Convert a private key "privateKey" into a public key
+*/
+extern SECKEYPublicKey *SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privateKey);
+
+/*
+ * create a new RSA key pair. The private Key is returned...
+ */
+SECKEYPrivateKey *SECKEY_CreateRSAPrivateKey(int keySizeInBits,
+					   SECKEYPublicKey **pubk, void *cx);
+	
+/*
+ * create a new DH key pair. The private Key is returned...
+ */
+SECKEYPrivateKey *SECKEY_CreateDHPrivateKey(SECKEYDHParams *param,
+					   SECKEYPublicKey **pubk, void *cx);
+
+/*
+ * create a new EC key pair. The private Key is returned...
+ */
+SECKEYPrivateKey *SECKEY_CreateECPrivateKey(SECKEYECParams *param,
+                                           SECKEYPublicKey **pubk, void *cx);
+
+/*
+** Create a subject-public-key-info based on a public key.
+*/
+extern CERTSubjectPublicKeyInfo *
+SECKEY_CreateSubjectPublicKeyInfo(SECKEYPublicKey *k);
+
+/*
+** Decode a DER encoded public key into an SECKEYPublicKey structure.
+*/
+extern SECKEYPublicKey *SECKEY_DecodeDERPublicKey(SECItem *pubkder);
+
+/*
+** Convert a base64 ascii encoded DER public key to our internal format.
+*/
+extern SECKEYPublicKey *SECKEY_ConvertAndDecodePublicKey(char *pubkstr);
+
+/*
+** Convert a base64 ascii encoded DER public key and challenge to spki,
+** and verify the signature and challenge data are correct
+*/
+extern CERTSubjectPublicKeyInfo *
+SECKEY_ConvertAndDecodePublicKeyAndChallenge(char *pkacstr, char *challenge,
+								void *cx);
+
+/*
+** Encode a  CERTSubjectPublicKeyInfo structure. into a
+** DER encoded subject public key info. 
+*/
+SECItem *
+SECKEY_EncodeDERSubjectPublicKeyInfo(SECKEYPublicKey *pubk);
+
+/*
+** Decode a DER encoded subject public key info into a
+** CERTSubjectPublicKeyInfo structure.
+*/
+extern CERTSubjectPublicKeyInfo *
+SECKEY_DecodeDERSubjectPublicKeyInfo(SECItem *spkider);
+
+/*
+** Convert a base64 ascii encoded DER subject public key info to our
+** internal format.
+*/
+extern CERTSubjectPublicKeyInfo *
+SECKEY_ConvertAndDecodeSubjectPublicKeyInfo(char *spkistr);
+
+/*
+ * extract the public key from a subject Public Key info structure.
+ * (used by JSS).
+ */
+extern SECKEYPublicKey *
+SECKEY_ExtractPublicKey(CERTSubjectPublicKeyInfo *);
+
+/*
+** Destroy a private key object.
+**	"key" the object
+*/
+extern void SECKEY_DestroyPrivateKey(SECKEYPrivateKey *key);
+
+
+/*
+** Destroy a public key object.
+**	"key" the object
+*/
+extern void SECKEY_DestroyPublicKey(SECKEYPublicKey *key);
+
+/* Destroy and zero out a private key info structure.  for now this
+ * function zero's out memory allocated in an arena for the key 
+ * since PORT_FreeArena does not currently do this.  
+ *
+ * NOTE -- If a private key info is allocated in an arena, one should 
+ * not call this function with freeit = PR_FALSE.  The function should 
+ * destroy the arena.  
+ */
+extern void
+SECKEY_DestroyPrivateKeyInfo(SECKEYPrivateKeyInfo *pvk, PRBool freeit);
+
+/* Destroy and zero out an encrypted private key info.
+ *
+ * NOTE -- If a encrypted private key info is allocated in an arena, one should 
+ * not call this function with freeit = PR_FALSE.  The function should 
+ * destroy the arena.  
+ */
+extern void
+SECKEY_DestroyEncryptedPrivateKeyInfo(SECKEYEncryptedPrivateKeyInfo *epki,
+				      PRBool freeit);
+
+/* Copy private key info structure.  
+ *  poolp is the arena into which the contents of from is to be copied.
+ *	NULL is a valid entry.
+ *  to is the destination private key info
+ *  from is the source private key info
+ * if either from or to is NULL or an error occurs, SECFailure is 
+ * returned.  otherwise, SECSuccess is returned.
+ */
+extern SECStatus
+SECKEY_CopyPrivateKeyInfo(PLArenaPool *poolp,
+			  SECKEYPrivateKeyInfo *to,
+			  SECKEYPrivateKeyInfo *from);
+
+extern SECStatus
+SECKEY_CacheStaticFlags(SECKEYPrivateKey* key);
+
+/* Copy encrypted private key info structure.  
+ *  poolp is the arena into which the contents of from is to be copied.
+ *	NULL is a valid entry.
+ *  to is the destination encrypted private key info
+ *  from is the source encrypted private key info
+ * if either from or to is NULL or an error occurs, SECFailure is 
+ * returned.  otherwise, SECSuccess is returned.
+ */
+extern SECStatus
+SECKEY_CopyEncryptedPrivateKeyInfo(PLArenaPool *poolp,
+				   SECKEYEncryptedPrivateKeyInfo *to,
+				   SECKEYEncryptedPrivateKeyInfo *from);
+/*
+ * Accessor functions for key type of public and private keys.
+ */
+KeyType SECKEY_GetPrivateKeyType(SECKEYPrivateKey *privKey);
+KeyType SECKEY_GetPublicKeyType(SECKEYPublicKey *pubKey);
+
+/*
+ * Creates a PublicKey from its DER encoding.
+ * Currently only supports RSA and DSA keys.
+ */
+SECKEYPublicKey*
+SECKEY_ImportDERPublicKey(SECItem *derKey, CK_KEY_TYPE type);
+
+SECKEYPrivateKeyList*
+SECKEY_NewPrivateKeyList(void);
+
+void
+SECKEY_DestroyPrivateKeyList(SECKEYPrivateKeyList *keys);
+
+void
+SECKEY_RemovePrivateKeyListNode(SECKEYPrivateKeyListNode *node);
+
+SECStatus
+SECKEY_AddPrivateKeyToListTail( SECKEYPrivateKeyList *list,
+                                SECKEYPrivateKey *key);
+
+#define PRIVKEY_LIST_HEAD(l) ((SECKEYPrivateKeyListNode*)PR_LIST_HEAD(&l->list))
+#define PRIVKEY_LIST_NEXT(n) ((SECKEYPrivateKeyListNode *)n->links.next)
+#define PRIVKEY_LIST_END(n,l) (((void *)n) == ((void *)&l->list))
+
+SECKEYPublicKeyList*
+SECKEY_NewPublicKeyList(void);
+
+void
+SECKEY_DestroyPublicKeyList(SECKEYPublicKeyList *keys);
+
+void
+SECKEY_RemovePublicKeyListNode(SECKEYPublicKeyListNode *node);
+
+SECStatus
+SECKEY_AddPublicKeyToListTail( SECKEYPublicKeyList *list,
+                                SECKEYPublicKey *key);
+
+#define PUBKEY_LIST_HEAD(l) ((SECKEYPublicKeyListNode*)PR_LIST_HEAD(&l->list))
+#define PUBKEY_LIST_NEXT(n) ((SECKEYPublicKeyListNode *)n->links.next)
+#define PUBKEY_LIST_END(n,l) (((void *)n) == ((void *)&l->list))
+
+/*
+ * Length in bits of the EC's field size.  This is also the length of
+ * the x and y coordinates of EC points, such as EC public keys and
+ * base points.
+ *
+ * Return 0 on failure (unknown EC domain parameters).
+ */
+extern int SECKEY_ECParamsToKeySize(const SECItem *params);
+
+/*
+ * Length in bits of the EC base point order, usually denoted n.  This
+ * is also the length of EC private keys and ECDSA signature components
+ * r and s.
+ *
+ * Return 0 on failure (unknown EC domain parameters).
+ */
+extern int SECKEY_ECParamsToBasePointOrderLen(const SECItem *params);
+
+SEC_END_PROTOS
+
+#endif /* _KEYHI_H_ */
diff --git a/mozilla/security/nss/lib/cryptohi/keyi.h b/mozilla/security/nss/lib/cryptohi/keyi.h
new file mode 100644
index 0000000..2057e13
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/keyi.h
@@ -0,0 +1,57 @@
+/* ***** 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
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bob Relyea, Red Hat
+ *
+ * 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 ***** */
+/* $Id: keyi.h,v 1.1 2006/02/08 06:14:07 rrelyea%redhat.com Exp $ */
+
+#ifndef _KEYI_H_
+#define _KEYI_H_
+
+
+SEC_BEGIN_PROTOS
+/* NSS private functions */
+/* map an oid to a keytype... actually this function and it's converse
+ *  are good candidates for public functions..  */
+KeyType seckey_GetKeyType(SECOidTag pubKeyOid);
+
+/* extract the 'encryption' (could be signing) and hash oids from and
+ * algorithm, key and parameters (parameters is the parameters field
+ * of a algorithm ID structure (SECAlgorithmID)*/
+SECStatus sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg,
+             const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg);
+
+SEC_END_PROTOS
+
+#endif /* _KEYHI_H_ */
diff --git a/mozilla/security/nss/lib/cryptohi/keyt.h b/mozilla/security/nss/lib/cryptohi/keyt.h
new file mode 100644
index 0000000..3f77f67
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/keyt.h
@@ -0,0 +1,43 @@
+/* ***** 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 ***** */
+/* $Id: keyt.h,v 1.4 2004/04/27 23:04:35 gerv%gerv.net Exp $ */
+
+#ifndef _KEYT_H_
+#define _KEYT_H_
+
+#include "keythi.h"
+
+#endif /* _KEYT_H_ */
diff --git a/mozilla/security/nss/lib/cryptohi/keythi.h b/mozilla/security/nss/lib/cryptohi/keythi.h
new file mode 100644
index 0000000..cd55b05
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/keythi.h
@@ -0,0 +1,255 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+#ifndef _KEYTHI_H_
+#define _KEYTHI_H_ 1
+
+#include "plarena.h"
+#include "pkcs11t.h"
+#include "secmodt.h"
+#include "prclist.h"
+
+typedef enum { 
+    nullKey = 0, 
+    rsaKey = 1, 
+    dsaKey = 2, 
+    fortezzaKey = 3,
+    dhKey = 4, 
+    keaKey = 5,
+    ecKey = 6
+} KeyType;
+
+/*
+** Template Definitions
+**/
+
+SEC_BEGIN_PROTOS
+extern const SEC_ASN1Template SECKEY_RSAPublicKeyTemplate[];
+extern const SEC_ASN1Template SECKEY_DSAPublicKeyTemplate[];
+extern const SEC_ASN1Template SECKEY_DHPublicKeyTemplate[];
+extern const SEC_ASN1Template SECKEY_DHParamKeyTemplate[];
+extern const SEC_ASN1Template SECKEY_PQGParamsTemplate[];
+extern const SEC_ASN1Template SECKEY_DSAPrivateKeyExportTemplate[];
+
+/* Windows DLL accessor functions */
+extern SEC_ASN1TemplateChooser NSS_Get_SECKEY_DSAPublicKeyTemplate;
+extern SEC_ASN1TemplateChooser NSS_Get_SECKEY_RSAPublicKeyTemplate;
+SEC_END_PROTOS
+
+
+/*
+** RSA Public Key structures
+** member names from PKCS#1, section 7.1 
+*/
+
+struct SECKEYRSAPublicKeyStr {
+    PLArenaPool * arena;
+    SECItem modulus;
+    SECItem publicExponent;
+};
+typedef struct SECKEYRSAPublicKeyStr SECKEYRSAPublicKey;
+
+
+/*
+** DSA Public Key and related structures
+*/
+
+struct SECKEYPQGParamsStr {
+    PLArenaPool *arena;
+    SECItem prime;    /* p */
+    SECItem subPrime; /* q */
+    SECItem base;     /* g */
+    /* XXX chrisk: this needs to be expanded to hold j and validationParms (RFC2459 7.3.2) */
+};
+typedef struct SECKEYPQGParamsStr SECKEYPQGParams;
+
+struct SECKEYDSAPublicKeyStr {
+    SECKEYPQGParams params;
+    SECItem publicValue;
+};
+typedef struct SECKEYDSAPublicKeyStr SECKEYDSAPublicKey;
+
+
+/*
+** Diffie-Hellman Public Key structure
+** Structure member names suggested by PKCS#3.
+*/
+struct SECKEYDHParamsStr {
+    PLArenaPool * arena;
+    SECItem prime; /* p */
+    SECItem base; /* g */
+};
+typedef struct SECKEYDHParamsStr SECKEYDHParams;
+
+struct SECKEYDHPublicKeyStr {
+    PLArenaPool * arena;
+    SECItem prime;
+    SECItem base;
+    SECItem publicValue;
+};
+typedef struct SECKEYDHPublicKeyStr SECKEYDHPublicKey;
+
+/*
+** Elliptic curve Public Key structure
+** The PKCS#11 layer needs DER encoding of ANSI X9.62
+** parameters value
+*/
+typedef SECItem SECKEYECParams;
+
+struct SECKEYECPublicKeyStr {
+    SECKEYECParams DEREncodedParams;
+    int     size;             /* size in bits */
+    SECItem publicValue;      /* encoded point */
+    /* XXX Even though the PKCS#11 interface takes encoded parameters,
+     * we may still wish to decode them above PKCS#11 for things like
+     * printing key information. For named curves, which is what
+     * we initially support, we ought to have the curve name at the
+     * very least.
+     */
+};
+typedef struct SECKEYECPublicKeyStr SECKEYECPublicKey;
+
+/*
+** FORTEZZA Public Key structures
+*/
+struct SECKEYFortezzaPublicKeyStr {
+    int      KEAversion;
+    int      DSSversion;
+    unsigned char    KMID[8];
+    SECItem clearance;
+    SECItem KEApriviledge;
+    SECItem DSSpriviledge;
+    SECItem KEAKey;
+    SECItem DSSKey;
+    SECKEYPQGParams params;
+    SECKEYPQGParams keaParams;
+};
+typedef struct SECKEYFortezzaPublicKeyStr SECKEYFortezzaPublicKey;
+
+struct SECKEYDiffPQGParamsStr {
+    SECKEYPQGParams DiffKEAParams;
+    SECKEYPQGParams DiffDSAParams;
+};
+typedef struct SECKEYDiffPQGParamsStr SECKEYDiffPQGParams;
+
+struct SECKEYPQGDualParamsStr {
+    SECKEYPQGParams CommParams;
+    SECKEYDiffPQGParams DiffParams;
+};
+typedef struct SECKEYPQGDualParamsStr SECKEYPQGDualParams;
+
+struct SECKEYKEAParamsStr {
+    PLArenaPool *arena;
+    SECItem hash;
+};
+typedef struct SECKEYKEAParamsStr SECKEYKEAParams;
+ 
+struct SECKEYKEAPublicKeyStr {
+    SECKEYKEAParams params;
+    SECItem publicValue;
+};
+typedef struct SECKEYKEAPublicKeyStr SECKEYKEAPublicKey;
+
+/*
+** A Generic  public key object.
+*/
+struct SECKEYPublicKeyStr {
+    PLArenaPool *arena;
+    KeyType keyType;
+    PK11SlotInfo *pkcs11Slot;
+    CK_OBJECT_HANDLE pkcs11ID;
+    union {
+        SECKEYRSAPublicKey rsa;
+	SECKEYDSAPublicKey dsa;
+	SECKEYDHPublicKey  dh;
+        SECKEYKEAPublicKey kea;
+        SECKEYFortezzaPublicKey fortezza;
+	SECKEYECPublicKey  ec;
+    } u;
+};
+typedef struct SECKEYPublicKeyStr SECKEYPublicKey;
+
+/* bit flag definitions for staticflags */
+#define SECKEY_Attributes_Cached 0x1    /* bit 0 states
+                                           whether attributes are cached */
+#define SECKEY_CKA_PRIVATE (1U << 1)    /* bit 1 is the value of CKA_PRIVATE */
+
+#define SECKEY_ATTRIBUTES_CACHED(key) \
+     (0 != (key->staticflags & SECKEY_Attributes_Cached))
+
+#define SECKEY_ATTRIBUTE_VALUE(key,attribute) \
+     (0 != (key->staticflags & SECKEY_##attribute))
+
+#define SECKEY_HAS_ATTRIBUTE_SET(key,attribute) \
+    (0 != (key->staticflags & SECKEY_Attributes_Cached)) ? \
+    (0 != (key->staticflags & SECKEY_##attribute)) : \
+    PK11_HasAttributeSet(key->pkcs11Slot,key->pkcs11ID,attribute)
+
+/*
+** A generic key structure
+*/ 
+struct SECKEYPrivateKeyStr {
+    PLArenaPool *arena;
+    KeyType keyType;
+    PK11SlotInfo *pkcs11Slot;	/* pkcs11 slot this key lives in */
+    CK_OBJECT_HANDLE pkcs11ID;  /* ID of pkcs11 object */
+    PRBool pkcs11IsTemp;	/* temp pkcs11 object, delete it when done */
+    void *wincx;		/* context for errors and pw prompts */
+    PRUint32 staticflags;       /* bit flag of cached PKCS#11 attributes */
+};
+typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey;
+
+typedef struct {
+    PRCList links;
+    SECKEYPrivateKey *key;
+} SECKEYPrivateKeyListNode;
+
+typedef struct {
+    PRCList list;
+    PLArenaPool *arena;
+} SECKEYPrivateKeyList;
+
+typedef struct {
+    PRCList links;
+    SECKEYPublicKey *key;
+} SECKEYPublicKeyListNode;
+
+typedef struct {
+    PRCList list;
+    PLArenaPool *arena;
+} SECKEYPublicKeyList;
+#endif /* _KEYTHI_H_ */
+
diff --git a/mozilla/security/nss/lib/cryptohi/sechash.c b/mozilla/security/nss/lib/cryptohi/sechash.c
new file mode 100644
index 0000000..dc069ed
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/sechash.c
@@ -0,0 +1,422 @@
+/* ***** 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 "sechash.h"
+#include "secoidt.h"
+#include "secerr.h"
+#include "blapi.h"
+#include "pk11func.h"	/* for the PK11_ calls below. */
+
+static void *
+null_hash_new_context(void)
+{
+    return NULL;
+}
+
+static void *
+null_hash_clone_context(void *v)
+{
+    PORT_Assert(v == NULL);
+    return NULL;
+}
+
+static void
+null_hash_begin(void *v)
+{
+}
+
+static void
+null_hash_update(void *v, const unsigned char *input, unsigned int length)
+{
+}
+
+static void
+null_hash_end(void *v, unsigned char *output, unsigned int *outLen,
+	      unsigned int maxOut)
+{
+    *outLen = 0;
+}
+
+static void
+null_hash_destroy_context(void *v, PRBool b)
+{
+    PORT_Assert(v == NULL);
+}
+
+
+static void *
+md2_NewContext(void) {
+	return (void *) PK11_CreateDigestContext(SEC_OID_MD2);
+}
+
+static void *
+md5_NewContext(void) {
+	return (void *) PK11_CreateDigestContext(SEC_OID_MD5);
+}
+
+static void *
+sha1_NewContext(void) {
+	return (void *) PK11_CreateDigestContext(SEC_OID_SHA1);
+}
+
+static void *
+sha256_NewContext(void) {
+	return (void *) PK11_CreateDigestContext(SEC_OID_SHA256);
+}
+
+static void *
+sha384_NewContext(void) {
+	return (void *) PK11_CreateDigestContext(SEC_OID_SHA384);
+}
+
+static void *
+sha512_NewContext(void) {
+	return (void *) PK11_CreateDigestContext(SEC_OID_SHA512);
+}
+
+const SECHashObject SECHashObjects[] = {
+  { 0,
+    (void * (*)(void)) null_hash_new_context,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) null_hash_destroy_context,
+    (void (*)(void *)) null_hash_begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) null_hash_update,
+    (void (*)(void *, unsigned char *, unsigned int *,
+	      unsigned int)) null_hash_end,
+    0,
+    HASH_AlgNULL
+  },
+  { MD2_LENGTH,
+    (void * (*)(void)) md2_NewContext,
+    (void * (*)(void *)) PK11_CloneContext,
+    (void (*)(void *, PRBool)) PK11_DestroyContext,
+    (void (*)(void *)) PK11_DigestBegin,
+    (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) 
+							PK11_DigestFinal,
+    MD2_BLOCK_LENGTH,
+    HASH_AlgMD2
+  },
+  { MD5_LENGTH,
+    (void * (*)(void)) md5_NewContext,
+    (void * (*)(void *)) PK11_CloneContext,
+    (void (*)(void *, PRBool)) PK11_DestroyContext,
+    (void (*)(void *)) PK11_DigestBegin,
+    (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) 
+							PK11_DigestFinal,
+    MD5_BLOCK_LENGTH,
+    HASH_AlgMD5
+  },
+  { SHA1_LENGTH,
+    (void * (*)(void)) sha1_NewContext,
+    (void * (*)(void *)) PK11_CloneContext,
+    (void (*)(void *, PRBool)) PK11_DestroyContext,
+    (void (*)(void *)) PK11_DigestBegin,
+    (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) 
+							PK11_DigestFinal,
+    SHA1_BLOCK_LENGTH,
+    HASH_AlgSHA1
+  },
+  { SHA256_LENGTH,
+    (void * (*)(void)) sha256_NewContext,
+    (void * (*)(void *)) PK11_CloneContext,
+    (void (*)(void *, PRBool)) PK11_DestroyContext,
+    (void (*)(void *)) PK11_DigestBegin,
+    (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) 
+							PK11_DigestFinal,
+    SHA256_BLOCK_LENGTH,
+    HASH_AlgSHA256
+  },
+  { SHA384_LENGTH,
+    (void * (*)(void)) sha384_NewContext,
+    (void * (*)(void *)) PK11_CloneContext,
+    (void (*)(void *, PRBool)) PK11_DestroyContext,
+    (void (*)(void *)) PK11_DigestBegin,
+    (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) 
+							PK11_DigestFinal,
+    SHA384_BLOCK_LENGTH,
+    HASH_AlgSHA384
+  },
+  { SHA512_LENGTH,
+    (void * (*)(void)) sha512_NewContext,
+    (void * (*)(void *)) PK11_CloneContext,
+    (void (*)(void *, PRBool)) PK11_DestroyContext,
+    (void (*)(void *)) PK11_DigestBegin,
+    (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) 
+							PK11_DigestFinal,
+    SHA512_BLOCK_LENGTH,
+    HASH_AlgSHA512
+  },
+};
+
+const SECHashObject * 
+HASH_GetHashObject(HASH_HashType type)
+{
+    return &SECHashObjects[type];
+}
+
+HASH_HashType
+HASH_GetHashTypeByOidTag(SECOidTag hashOid)
+{
+    HASH_HashType ht	= HASH_AlgNULL;
+
+    switch(hashOid) {
+    case SEC_OID_MD2:	 ht = HASH_AlgMD2;    break;
+    case SEC_OID_MD5:	 ht = HASH_AlgMD5;    break;
+    case SEC_OID_SHA1:	 ht = HASH_AlgSHA1;   break;
+    case SEC_OID_SHA256: ht = HASH_AlgSHA256; break;
+    case SEC_OID_SHA384: ht = HASH_AlgSHA384; break;
+    case SEC_OID_SHA512: ht = HASH_AlgSHA512; break;
+    default:             ht = HASH_AlgNULL;   
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	break;
+    }
+    return ht;
+}
+
+SECOidTag
+HASH_GetHashOidTagByHMACOidTag(SECOidTag hmacOid)
+{
+    SECOidTag hashOid = SEC_OID_UNKNOWN;
+
+    switch(hmacOid) {
+    /* no oid exists for HMAC_MD2 */
+    /* NSS does not define a oid for HMAC_MD4 */
+    case SEC_OID_HMAC_SHA1:   hashOid = SEC_OID_SHA1;   break;
+    case SEC_OID_HMAC_SHA256: hashOid = SEC_OID_SHA256; break;
+    case SEC_OID_HMAC_SHA384: hashOid = SEC_OID_SHA384; break;
+    case SEC_OID_HMAC_SHA512: hashOid = SEC_OID_SHA512; break;
+    default:                  hashOid = SEC_OID_UNKNOWN;   
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	break;
+    }
+    return hashOid;
+}
+
+SECOidTag
+HASH_GetHMACOidTagByHashOidTag(SECOidTag hashOid)
+{
+    SECOidTag hmacOid = SEC_OID_UNKNOWN;
+
+    switch(hmacOid) {
+    /* no oid exists for HMAC_MD2 */
+    /* NSS does not define a oid for HMAC_MD4 */
+    case SEC_OID_SHA1:   hmacOid = SEC_OID_HMAC_SHA1;   break;
+    case SEC_OID_SHA256: hmacOid = SEC_OID_HMAC_SHA256; break;
+    case SEC_OID_SHA384: hmacOid = SEC_OID_HMAC_SHA384; break;
+    case SEC_OID_SHA512: hmacOid = SEC_OID_HMAC_SHA512; break;
+    default:             hmacOid = SEC_OID_UNKNOWN;   
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	break;
+    }
+    return hmacOid;
+}
+
+const SECHashObject * 
+HASH_GetHashObjectByOidTag(SECOidTag hashOid)
+{
+    HASH_HashType ht	= HASH_GetHashTypeByOidTag(hashOid);
+
+    return (ht == HASH_AlgNULL) ? NULL : &SECHashObjects[ht];
+}
+
+/* returns zero for unknown hash OID */
+unsigned int
+HASH_ResultLenByOidTag(SECOidTag hashOid)
+{
+    const SECHashObject * hashObject = HASH_GetHashObjectByOidTag(hashOid);
+    unsigned int          resultLen = 0;
+
+    if (hashObject)
+    	resultLen = hashObject->length;
+    return resultLen;
+}
+
+/* returns zero if hash type invalid. */
+unsigned int
+HASH_ResultLen(HASH_HashType type)
+{
+    if ( ( type < HASH_AlgNULL ) || ( type >= HASH_AlgTOTAL ) ) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return(0);
+    }
+    
+    return(SECHashObjects[type].length);
+}
+
+unsigned int
+HASH_ResultLenContext(HASHContext *context)
+{
+    return(context->hashobj->length);
+}
+
+
+
+SECStatus
+HASH_HashBuf(HASH_HashType type,
+	     unsigned char *dest,
+	     unsigned char *src,
+	     PRUint32 src_len)
+{
+    HASHContext *cx;
+    unsigned int part;
+    
+    if ( ( type < HASH_AlgNULL ) || ( type >= HASH_AlgTOTAL ) ) {
+	return(SECFailure);
+    }
+    
+    cx = HASH_Create(type);
+    if ( cx == NULL ) {
+	return(SECFailure);
+    }
+    HASH_Begin(cx);
+    HASH_Update(cx, src, src_len);
+    HASH_End(cx, dest, &part, HASH_ResultLenContext(cx));
+    HASH_Destroy(cx);
+
+    return(SECSuccess);
+}
+
+HASHContext *
+HASH_Create(HASH_HashType type)
+{
+    void *hash_context = NULL;
+    HASHContext *ret = NULL;
+    
+    if ( ( type < HASH_AlgNULL ) || ( type >= HASH_AlgTOTAL ) ) {
+	return(NULL);
+    }
+    
+    hash_context = (* SECHashObjects[type].create)();
+    if ( hash_context == NULL ) {
+	goto loser;
+    }
+
+    ret = (HASHContext *)PORT_Alloc(sizeof(HASHContext));
+    if ( ret == NULL ) {
+	goto loser;
+    }
+
+    ret->hash_context = hash_context;
+    ret->hashobj = &SECHashObjects[type];
+    
+    return(ret);
+    
+loser:
+    if ( hash_context != NULL ) {
+	(* SECHashObjects[type].destroy)(hash_context, PR_TRUE);
+    }
+    
+    return(NULL);
+}
+
+
+HASHContext *
+HASH_Clone(HASHContext *context)
+{
+    void *hash_context = NULL;
+    HASHContext *ret = NULL;
+    
+    hash_context = (* context->hashobj->clone)(context->hash_context);
+    if ( hash_context == NULL ) {
+	goto loser;
+    }
+
+    ret = (HASHContext *)PORT_Alloc(sizeof(HASHContext));
+    if ( ret == NULL ) {
+	goto loser;
+    }
+
+    ret->hash_context = hash_context;
+    ret->hashobj = context->hashobj;
+    
+    return(ret);
+    
+loser:
+    if ( hash_context != NULL ) {
+	(* context->hashobj->destroy)(hash_context, PR_TRUE);
+    }
+    
+    return(NULL);
+
+}
+
+void
+HASH_Destroy(HASHContext *context)
+{
+    (* context->hashobj->destroy)(context->hash_context, PR_TRUE);
+    PORT_Free(context);
+    return;
+}
+
+
+void
+HASH_Begin(HASHContext *context)
+{
+    (* context->hashobj->begin)(context->hash_context);
+    return;
+}
+
+
+void
+HASH_Update(HASHContext *context,
+	    const unsigned char *src,
+	    unsigned int len)
+{
+    (* context->hashobj->update)(context->hash_context, src, len);
+    return;
+}
+
+void
+HASH_End(HASHContext *context,
+	 unsigned char *result,
+	 unsigned int *result_len,
+	 unsigned int max_result_len)
+{
+    (* context->hashobj->end)(context->hash_context, result, result_len,
+			      max_result_len);
+    return;
+}
+
+HASH_HashType
+HASH_GetType(HASHContext *context)
+{
+    return(context->hashobj->type);
+}
diff --git a/mozilla/security/nss/lib/cryptohi/seckey.c b/mozilla/security/nss/lib/cryptohi/seckey.c
new file mode 100644
index 0000000..7a58b21
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/seckey.c
@@ -0,0 +1,2530 @@
+/* ***** 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):
+ *   Dr Stephen Henson <stephen.henson@gemplus.com>
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 "cryptohi.h"
+#include "keyhi.h"
+#include "secoid.h"
+#include "secitem.h"
+#include "secder.h"
+#include "base64.h"
+#include "secasn1.h"
+#include "cert.h"
+#include "pk11func.h"
+#include "secerr.h"
+#include "secdig.h"
+#include "prtime.h"
+#include "ec.h"
+#include "keyi.h"
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+const SEC_ASN1Template CERT_SubjectPublicKeyInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTSubjectPublicKeyInfo) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(CERTSubjectPublicKeyInfo,algorithm),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_BIT_STRING,
+	  offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
+    { 0, }
+};
+
+const SEC_ASN1Template CERT_PublicKeyAndChallengeTemplate[] =
+{
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPublicKeyAndChallenge) },
+    { SEC_ASN1_ANY, offsetof(CERTPublicKeyAndChallenge,spki) },
+    { SEC_ASN1_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge) },
+    { 0 }
+};
+
+const SEC_ASN1Template SECKEY_RSAPublicKeyTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.modulus), },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.publicExponent), },
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_DSAPublicKeyTemplate[] = {
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dsa.publicValue), },
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,prime) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,subPrime) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,base) },
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_DHPublicKeyTemplate[] = {
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.publicValue), },
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_DHParamKeyTemplate[] = {
+    { SEC_ASN1_SEQUENCE,  0, NULL, sizeof(SECKEYPublicKey) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.prime), },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.base), },
+    /* XXX chrisk: this needs to be expanded for decoding of j and validationParms (RFC2459 7.3.2) */
+    { SEC_ASN1_SKIP_REST },
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_FortezzaParameterTemplate[] = {
+    { SEC_ASN1_SEQUENCE,  0, NULL, sizeof(SECKEYPQGParams) },
+    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPQGParams,prime), },
+    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPQGParams,subPrime), },
+    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPQGParams,base), },
+    { 0 },
+};
+ 
+const SEC_ASN1Template SECKEY_FortezzaDiffParameterTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYDiffPQGParams) },
+    { SEC_ASN1_INLINE, offsetof(SECKEYDiffPQGParams,DiffKEAParams), 
+                       SECKEY_FortezzaParameterTemplate},
+    { SEC_ASN1_INLINE, offsetof(SECKEYDiffPQGParams,DiffDSAParams), 
+                       SECKEY_FortezzaParameterTemplate},
+    { 0 },
+};
+
+const SEC_ASN1Template SECKEY_FortezzaPreParamTemplate[] = {
+    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
+      SEC_ASN1_CONTEXT_SPECIFIC | 1, offsetof(SECKEYPQGDualParams,CommParams),
+                SECKEY_FortezzaParameterTemplate},
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_FortezzaAltPreParamTemplate[] = {
+    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
+      SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(SECKEYPQGDualParams,DiffParams),
+                SECKEY_FortezzaDiffParameterTemplate},
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_KEAPublicKeyTemplate[] = {
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.kea.publicValue), },
+    { 0, }
+};
+
+const SEC_ASN1Template SECKEY_KEAParamsTemplate[] = {
+    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPublicKey,u.kea.params.hash), }, 
+    { 0, }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_DSAPublicKeyTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_RSAPublicKeyTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SubjectPublicKeyInfoTemplate)
+
+/*
+ * See bugzilla bug 125359
+ * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
+ * all of the templates above that en/decode into integers must be converted
+ * from ASN.1's signed integer type.  This is done by marking either the
+ * source or destination (encoding or decoding, respectively) type as
+ * siUnsignedInteger.
+ */
+static void
+prepare_rsa_pub_key_for_asn1(SECKEYPublicKey *pubk)
+{
+    pubk->u.rsa.modulus.type = siUnsignedInteger;
+    pubk->u.rsa.publicExponent.type = siUnsignedInteger;
+}
+
+static void
+prepare_dsa_pub_key_for_asn1(SECKEYPublicKey *pubk)
+{
+    pubk->u.dsa.publicValue.type = siUnsignedInteger;
+}
+
+static void
+prepare_pqg_params_for_asn1(SECKEYPQGParams *params)
+{
+    params->prime.type = siUnsignedInteger;
+    params->subPrime.type = siUnsignedInteger;
+    params->base.type = siUnsignedInteger;
+}
+
+static void
+prepare_dh_pub_key_for_asn1(SECKEYPublicKey *pubk)
+{
+    pubk->u.dh.prime.type = siUnsignedInteger;
+    pubk->u.dh.base.type = siUnsignedInteger;
+    pubk->u.dh.publicValue.type = siUnsignedInteger;
+}
+
+static void
+prepare_kea_pub_key_for_asn1(SECKEYPublicKey *pubk)
+{
+    pubk->u.kea.publicValue.type = siUnsignedInteger;
+}
+
+/* Create an RSA key pair is any slot able to do so.
+** The created keys are "session" (temporary), not "token" (permanent), 
+** and they are "sensitive", which makes them costly to move to another token.
+*/
+SECKEYPrivateKey *
+SECKEY_CreateRSAPrivateKey(int keySizeInBits,SECKEYPublicKey **pubk, void *cx)
+{
+    SECKEYPrivateKey *privk;
+    PK11RSAGenParams param;
+    PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN,cx);
+    if (!slot) {
+	return NULL;
+    }
+
+    param.keySizeInBits = keySizeInBits;
+    param.pe = 65537L;
+    
+    privk = PK11_GenerateKeyPair(slot,CKM_RSA_PKCS_KEY_PAIR_GEN,&param,pubk,
+					PR_FALSE, PR_TRUE, cx);
+    PK11_FreeSlot(slot);
+    return(privk);
+}
+
+/* Create a DH key pair in any slot able to do so, 
+** This is a "session" (temporary), not "token" (permanent) key. 
+** Because of the high probability that this key will need to be moved to
+** another token, and the high cost of moving "sensitive" keys, we attempt
+** to create this key pair without the "sensitive" attribute, but revert to 
+** creating a "sensitive" key if necessary.
+*/
+SECKEYPrivateKey *
+SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *cx)
+{
+    SECKEYPrivateKey *privk;
+    PK11SlotInfo *slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx);
+    if (!slot) {
+	return NULL;
+    }
+
+    privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, param, 
+                                 pubk, PR_FALSE, PR_FALSE, cx);
+    if (!privk) 
+	privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, param, 
+	                             pubk, PR_FALSE, PR_TRUE, cx);
+
+    PK11_FreeSlot(slot);
+    return(privk);
+}
+
+/* Create an EC key pair in any slot able to do so, 
+** This is a "session" (temporary), not "token" (permanent) key. 
+** Because of the high probability that this key will need to be moved to
+** another token, and the high cost of moving "sensitive" keys, we attempt
+** to create this key pair without the "sensitive" attribute, but revert to 
+** creating a "sensitive" key if necessary.
+*/
+SECKEYPrivateKey *
+SECKEY_CreateECPrivateKey(SECKEYECParams *param, SECKEYPublicKey **pubk, void *cx)
+{
+    SECKEYPrivateKey *privk;
+    PK11SlotInfo *slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN,cx);
+    if (!slot) {
+	return NULL;
+    }
+
+    privk = PK11_GenerateKeyPairWithOpFlags(slot, CKM_EC_KEY_PAIR_GEN, 
+                        param, pubk,
+                        PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE | 
+                        PK11_ATTR_PUBLIC,
+                        CKF_DERIVE, CKF_DERIVE|CKF_SIGN,cx);
+    if (!privk) 
+        privk = PK11_GenerateKeyPairWithOpFlags(slot, CKM_EC_KEY_PAIR_GEN, 
+                        param, pubk,
+                        PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE | 
+                        PK11_ATTR_PRIVATE,
+                        CKF_DERIVE, CKF_DERIVE|CKF_SIGN,cx);
+
+    PK11_FreeSlot(slot);
+    return(privk);
+}
+
+void
+SECKEY_DestroyPrivateKey(SECKEYPrivateKey *privk)
+{
+    if (privk) {
+	if (privk->pkcs11Slot) {
+	    if (privk->pkcs11IsTemp) {
+	    	PK11_DestroyObject(privk->pkcs11Slot,privk->pkcs11ID);
+	    }
+	    PK11_FreeSlot(privk->pkcs11Slot);
+
+	}
+    	if (privk->arena) {
+	    PORT_FreeArena(privk->arena, PR_TRUE);
+	}
+    }
+}
+
+void
+SECKEY_DestroyPublicKey(SECKEYPublicKey *pubk)
+{
+    if (pubk) {
+	if (pubk->pkcs11Slot) {
+	    if (!PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) {
+		PK11_DestroyObject(pubk->pkcs11Slot,pubk->pkcs11ID);
+	    }
+	    PK11_FreeSlot(pubk->pkcs11Slot);
+	}
+    	if (pubk->arena) {
+	    PORT_FreeArena(pubk->arena, PR_FALSE);
+	}
+    }
+}
+
+SECStatus
+SECKEY_CopySubjectPublicKeyInfo(PRArenaPool *arena,
+			     CERTSubjectPublicKeyInfo *to,
+			     CERTSubjectPublicKeyInfo *from)
+{
+    SECStatus rv;
+    SECItem spk;
+
+    rv = SECOID_CopyAlgorithmID(arena, &to->algorithm, &from->algorithm);
+    if (rv == SECSuccess) {
+	/*
+	 * subjectPublicKey is a bit string, whose length is in bits.
+	 * Convert the length from bits to bytes for SECITEM_CopyItem.
+	 */
+	spk = from->subjectPublicKey;
+	DER_ConvertBitString(&spk);
+	rv = SECITEM_CopyItem(arena, &to->subjectPublicKey, &spk);
+	/* Set the length back to bits. */
+	if (rv == SECSuccess) {
+	    to->subjectPublicKey.len = from->subjectPublicKey.len;
+	}
+    }
+
+    return rv;
+}
+
+SECStatus
+SECKEY_KEASetParams(SECKEYKEAParams * params, SECKEYPublicKey * pubKey) {
+
+    if (pubKey->keyType == fortezzaKey) {
+        /* the key is a fortezza V1 public key  */
+
+	/* obtain hash of pubkey->u.fortezza.params.prime.data +
+		          pubkey->u.fortezza.params.subPrime.data +
+			  pubkey->u.fortezza.params.base.data  */
+
+	/* store hash in params->hash */
+
+    } else if (pubKey->keyType == keaKey) {
+
+        /* the key is a new fortezza KEA public key. */
+        SECITEM_CopyItem(pubKey->arena, &params->hash, 
+	                 &pubKey->u.kea.params.hash );
+
+    } else {
+
+	/* the key has no KEA parameters */
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+SECStatus
+SECKEY_KEAParamCompare(CERTCertificate *cert1,CERTCertificate *cert2) 
+{
+
+    SECStatus rv;
+
+    SECKEYPublicKey *pubKey1 = 0;
+    SECKEYPublicKey *pubKey2 = 0;
+
+    SECKEYKEAParams params1;
+    SECKEYKEAParams params2;
+
+
+    rv = SECFailure;
+
+    /* get cert1's public key */
+    pubKey1 = CERT_ExtractPublicKey(cert1);
+    if ( !pubKey1 ) {
+	return(SECFailure);
+    }
+    
+
+    /* get cert2's public key */
+    pubKey2 = CERT_ExtractPublicKey(cert2);
+    if ( !pubKey2 ) {
+	return(SECFailure);
+    }
+
+    /* handle the case when both public keys are new
+     * fortezza KEA public keys.    */
+
+    if ((pubKey1->keyType == keaKey) &&
+        (pubKey2->keyType == keaKey) ) {
+
+        rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.kea.params.hash,
+	                         &pubKey2->u.kea.params.hash);
+	goto done;
+    }
+
+    /* handle the case when both public keys are old fortezza
+     * public keys.              */
+
+    if ((pubKey1->keyType == fortezzaKey) &&
+        (pubKey2->keyType == fortezzaKey) ) {
+
+        rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.fortezza.keaParams.prime,
+	                         &pubKey2->u.fortezza.keaParams.prime);
+
+	if (rv == SECEqual) {
+	    rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.fortezza.keaParams.subPrime,
+	                             &pubKey2->u.fortezza.keaParams.subPrime);
+	}
+
+	if (rv == SECEqual) {
+	    rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.fortezza.keaParams.base,
+	                             &pubKey2->u.fortezza.keaParams.base);
+	}
+	
+	goto done;
+    }
+
+
+    /* handle the case when the public keys are a mixture of 
+     * old and new.                          */
+
+    rv = SECKEY_KEASetParams(&params1, pubKey1);
+    if (rv != SECSuccess) return rv;
+
+    rv = SECKEY_KEASetParams(&params2, pubKey2);
+    if (rv != SECSuccess) return rv;
+
+    rv = (SECStatus)SECITEM_CompareItem(&params1.hash, &params2.hash);
+
+done:
+    SECKEY_DestroyPublicKey(pubKey1);
+    SECKEY_DestroyPublicKey(pubKey2);
+
+    return rv;   /* returns SECEqual if parameters are equal */
+
+}
+
+
+/* Procedure to update the pqg parameters for a cert's public key.
+ * pqg parameters only need to be updated for DSA and fortezza certificates.
+ * The procedure uses calls to itself recursively to update a certificate
+ * issuer's pqg parameters.  Some important rules are:
+ *    - Do nothing if the cert already has PQG parameters.
+ *    - If the cert does not have PQG parameters, obtain them from the issuer.
+ *    - A valid cert chain cannot have a DSA or Fortezza cert without
+ *      pqg parameters that has a parent that is not a DSA or Fortezza cert.
+ *    - pqg paramters are stored in two different formats: the standard
+ *      DER encoded format and the fortezza-only wrapped format.  The params
+ *      should be copied from issuer to subject cert without modifying the
+ *      formats.  The public key extraction code will deal with the different
+ *      formats at the time of extraction.  */
+
+static SECStatus
+seckey_UpdateCertPQGChain(CERTCertificate * subjectCert, int count)
+{
+    SECStatus rv;
+    SECOidData *oid=NULL;
+    int tag;
+    CERTSubjectPublicKeyInfo * subjectSpki=NULL;
+    CERTSubjectPublicKeyInfo * issuerSpki=NULL;
+    CERTCertificate *issuerCert = NULL;
+
+    rv = SECSuccess;
+
+    /* increment cert chain length counter*/
+    count++;
+
+    /* check if cert chain length exceeds the maximum length*/
+    if (count > CERT_MAX_CERT_CHAIN) {
+	return SECFailure;
+    }
+
+    oid = SECOID_FindOID(&subjectCert->subjectPublicKeyInfo.algorithm.algorithm);            
+    if (oid != NULL) {  
+        tag = oid->offset;
+             
+        /* Check if cert has a DSA or Fortezza public key. If not, return
+         * success since no PQG params need to be updated.  */
+
+	if ( (tag != SEC_OID_MISSI_KEA_DSS_OLD) &&
+	     (tag != SEC_OID_MISSI_DSS_OLD) &&
+             (tag != SEC_OID_MISSI_KEA_DSS) &&
+             (tag != SEC_OID_MISSI_DSS) &&               
+             (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
+             (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
+             (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
+             (tag != SEC_OID_SDN702_DSA_SIGNATURE) &&
+             (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) {
+            
+            return SECSuccess;
+        }
+    } else {
+        return SECFailure;  /* return failure if oid is NULL */  
+    }
+
+    /* if cert has PQG parameters, return success */
+
+    subjectSpki=&subjectCert->subjectPublicKeyInfo;
+
+    if (subjectSpki->algorithm.parameters.len != 0) {
+        return SECSuccess;
+    }
+
+    /* check if the cert is self-signed */
+    if (subjectCert->isRoot) {
+      /* fail since cert is self-signed and has no pqg params. */
+	return SECFailure;     
+    }
+     
+    /* get issuer cert */
+    issuerCert = CERT_FindCertIssuer(subjectCert, PR_Now(), certUsageAnyCA);
+    if ( ! issuerCert ) {
+	return SECFailure;
+    }
+
+    /* if parent is not DSA or fortezza, return failure since
+       we don't allow this case. */
+
+    oid = SECOID_FindOID(&issuerCert->subjectPublicKeyInfo.algorithm.algorithm);
+    if (oid != NULL) {  
+        tag = oid->offset;
+             
+        /* Check if issuer cert has a DSA or Fortezza public key. If not,
+         * return failure.   */
+
+	if ( (tag != SEC_OID_MISSI_KEA_DSS_OLD) &&
+	     (tag != SEC_OID_MISSI_DSS_OLD) &&
+             (tag != SEC_OID_MISSI_KEA_DSS) &&
+             (tag != SEC_OID_MISSI_DSS) &&               
+             (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
+             (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
+             (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
+             (tag != SEC_OID_SDN702_DSA_SIGNATURE) &&
+             (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) {            
+            rv = SECFailure;
+            goto loser;
+        }
+    } else {
+        rv = SECFailure;  /* return failure if oid is NULL */  
+        goto loser;
+    }
+
+
+    /* at this point the subject cert has no pqg parameters and the
+     * issuer cert has a DSA or fortezza public key.  Update the issuer's
+     * pqg parameters with a recursive call to this same function. */
+
+    rv = seckey_UpdateCertPQGChain(issuerCert, count);
+    if (rv != SECSuccess) {
+        rv = SECFailure;
+        goto loser;
+    }
+
+    /* ensure issuer has pqg parameters */
+
+    issuerSpki=&issuerCert->subjectPublicKeyInfo;
+    if (issuerSpki->algorithm.parameters.len == 0) {
+        rv = SECFailure; 
+    }
+
+    /* if update was successful and pqg params present, then copy the
+     * parameters to the subject cert's key. */
+
+    if (rv == SECSuccess) {
+        rv = SECITEM_CopyItem(subjectCert->arena,
+                              &subjectSpki->algorithm.parameters, 
+	   		      &issuerSpki->algorithm.parameters);
+    }
+
+loser:
+    if (issuerCert) {
+        CERT_DestroyCertificate(issuerCert);
+    }
+    return rv;
+
+}
+ 
+
+SECStatus
+SECKEY_UpdateCertPQG(CERTCertificate * subjectCert)
+{
+    if (!subjectCert) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    return seckey_UpdateCertPQGChain(subjectCert,0);
+}
+   
+
+/* Decode the PQG parameters.  The params could be stored in two
+ * possible formats, the old fortezza-only wrapped format or
+ * the standard DER encoded format.   Store the decoded parameters in an
+ * old fortezza cert data structure */
+ 
+SECStatus
+SECKEY_FortezzaDecodePQGtoOld(PRArenaPool *arena, SECKEYPublicKey *pubk,
+                              SECItem *params) {
+    SECStatus rv;
+    SECKEYPQGDualParams dual_params;
+    SECItem newparams;
+
+    PORT_Assert(arena);
+
+    if (params == NULL) return SECFailure; 
+    
+    if (params->data == NULL) return SECFailure;
+
+    /* make a copy of the data into the arena so QuickDER output is valid */
+    rv = SECITEM_CopyItem(arena, &newparams, params);
+
+    /* Check if params use the standard format.
+     * The value 0xa1 will appear in the first byte of the parameter data
+     * if the PQG parameters are not using the standard format. This
+     * code should be changed to use a better method to detect non-standard
+     * parameters.    */
+
+    if ((newparams.data[0] != 0xa1) &&
+        (newparams.data[0] != 0xa0)) {
+
+        if (SECSuccess == rv) {
+            /* PQG params are in the standard format */
+
+	    /* Store DSA PQG parameters */
+	    prepare_pqg_params_for_asn1(&pubk->u.fortezza.params);
+            rv = SEC_QuickDERDecodeItem(arena, &pubk->u.fortezza.params,
+                              SECKEY_PQGParamsTemplate,
+                              &newparams);
+        }
+
+	if (SECSuccess == rv) {
+
+	    /* Copy the DSA PQG parameters to the KEA PQG parameters. */
+	    rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.prime,
+                                  &pubk->u.fortezza.params.prime);
+        }
+        if (SECSuccess == rv) {
+            rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.subPrime,
+                                  &pubk->u.fortezza.params.subPrime);
+        }
+        if (SECSuccess == rv) {
+            rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.base,
+                                  &pubk->u.fortezza.params.base);
+        }
+    } else {
+
+	dual_params.CommParams.prime.len = 0;
+        dual_params.CommParams.subPrime.len = 0;
+	dual_params.CommParams.base.len = 0;
+	dual_params.DiffParams.DiffDSAParams.prime.len = 0;
+        dual_params.DiffParams.DiffDSAParams.subPrime.len = 0;
+	dual_params.DiffParams.DiffDSAParams.base.len = 0;
+
+        /* else the old fortezza-only wrapped format is used. */
+
+        if (SECSuccess == rv) {
+	    if (newparams.data[0] == 0xa1) {
+                rv = SEC_QuickDERDecodeItem(arena, &dual_params, 
+				    SECKEY_FortezzaPreParamTemplate, &newparams);
+	    } else {
+                rv = SEC_QuickDERDecodeItem(arena, &dual_params, 
+	   			        SECKEY_FortezzaAltPreParamTemplate, &newparams);
+            }
+        }
+	
+        if ( (dual_params.CommParams.prime.len > 0) &&
+             (dual_params.CommParams.subPrime.len > 0) && 
+             (dual_params.CommParams.base.len > 0) ) {
+            /* copy in common params */
+	    if (SECSuccess == rv) {
+	        rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.prime,
+                                      &dual_params.CommParams.prime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.subPrime,
+                                      &dual_params.CommParams.subPrime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.base,
+                                      &dual_params.CommParams.base);
+            }
+
+	    /* Copy the DSA PQG parameters to the KEA PQG parameters. */
+            if (SECSuccess == rv) {
+	        rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.prime,
+                                      &pubk->u.fortezza.params.prime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.subPrime,
+                                      &pubk->u.fortezza.params.subPrime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.base,
+                                      &pubk->u.fortezza.params.base);
+            }
+        } else {
+
+	    /* else copy in different params */
+
+	    /* copy DSA PQG parameters */
+            if (SECSuccess == rv) {
+	        rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.prime,
+                                  &dual_params.DiffParams.DiffDSAParams.prime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.subPrime,
+                                  &dual_params.DiffParams.DiffDSAParams.subPrime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.base,
+                                  &dual_params.DiffParams.DiffDSAParams.base);
+            }
+
+	    /* copy KEA PQG parameters */
+
+            if (SECSuccess == rv) {
+	        rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.prime,
+                                  &dual_params.DiffParams.DiffKEAParams.prime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.subPrime,
+                                  &dual_params.DiffParams.DiffKEAParams.subPrime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.base,
+                                  &dual_params.DiffParams.DiffKEAParams.base);
+            }
+        }
+    }
+    return rv;
+}
+
+
+/* Decode the DSA PQG parameters.  The params could be stored in two
+ * possible formats, the old fortezza-only wrapped format or
+ * the normal standard format.  Store the decoded parameters in
+ * a V3 certificate data structure.  */ 
+
+SECStatus
+SECKEY_DSADecodePQG(PRArenaPool *arena, SECKEYPublicKey *pubk, SECItem *params) {
+    SECStatus rv;
+    SECKEYPQGDualParams dual_params;
+    SECItem newparams;
+
+    if (params == NULL) return SECFailure; 
+    
+    if (params->data == NULL) return SECFailure;
+
+    PORT_Assert(arena);
+
+    /* make a copy of the data into the arena so QuickDER output is valid */
+    rv = SECITEM_CopyItem(arena, &newparams, params);
+
+    /* Check if params use the standard format.
+     * The value 0xa1 will appear in the first byte of the parameter data
+     * if the PQG parameters are not using the standard format.  This
+     * code should be changed to use a better method to detect non-standard
+     * parameters.    */
+
+    if ((newparams.data[0] != 0xa1) &&
+        (newparams.data[0] != 0xa0)) {
+    
+        if (SECSuccess == rv) {
+             /* PQG params are in the standard format */
+             prepare_pqg_params_for_asn1(&pubk->u.dsa.params);
+             rv = SEC_QuickDERDecodeItem(arena, &pubk->u.dsa.params,
+                                 SECKEY_PQGParamsTemplate,
+                                 &newparams);
+        }
+    } else {
+
+	dual_params.CommParams.prime.len = 0;
+        dual_params.CommParams.subPrime.len = 0;
+	dual_params.CommParams.base.len = 0;
+	dual_params.DiffParams.DiffDSAParams.prime.len = 0;
+        dual_params.DiffParams.DiffDSAParams.subPrime.len = 0;
+	dual_params.DiffParams.DiffDSAParams.base.len = 0;
+
+        if (SECSuccess == rv) {
+            /* else the old fortezza-only wrapped format is used. */
+            if (newparams.data[0] == 0xa1) {
+                rv = SEC_QuickDERDecodeItem(arena, &dual_params, 
+				    SECKEY_FortezzaPreParamTemplate, &newparams);
+	    } else {
+                rv = SEC_QuickDERDecodeItem(arena, &dual_params, 
+	   			        SECKEY_FortezzaAltPreParamTemplate, &newparams);
+            }
+        }
+
+        if ( (dual_params.CommParams.prime.len > 0) &&
+             (dual_params.CommParams.subPrime.len > 0) && 
+             (dual_params.CommParams.base.len > 0) ) {
+            /* copy in common params */
+
+            if (SECSuccess == rv) {	    
+	        rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime,
+                                      &dual_params.CommParams.prime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime,
+                                      &dual_params.CommParams.subPrime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base,
+                                    &dual_params.CommParams.base);
+            }
+        } else {
+
+	    /* else copy in different params */
+
+	    /* copy DSA PQG parameters */
+            if (SECSuccess == rv) {
+	        rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime,
+                                      &dual_params.DiffParams.DiffDSAParams.prime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime,
+                                      &dual_params.DiffParams.DiffDSAParams.subPrime);
+            }
+            if (SECSuccess == rv) {
+                rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base,
+                                      &dual_params.DiffParams.DiffDSAParams.base);
+            }
+        }
+    }
+    return rv;
+}
+
+
+/* Decodes the DER encoded fortezza public key and stores the results in a
+ * structure of type SECKEYPublicKey. */
+
+SECStatus
+SECKEY_FortezzaDecodeCertKey(PRArenaPool *arena, SECKEYPublicKey *pubk,
+                             SECItem *rawkey, SECItem *params) {
+
+	unsigned char *rawptr = rawkey->data;
+	unsigned char *end = rawkey->data + rawkey->len;
+	unsigned char *clearptr;
+
+	/* first march down and decode the raw key data */
+
+	/* version */	
+	pubk->u.fortezza.KEAversion = *rawptr++;
+	if (*rawptr++ != 0x01) {
+		return SECFailure;
+	}
+
+	/* KMID */
+	PORT_Memcpy(pubk->u.fortezza.KMID,rawptr,
+				sizeof(pubk->u.fortezza.KMID));
+	rawptr += sizeof(pubk->u.fortezza.KMID);
+
+	/* clearance (the string up to the first byte with the hi-bit on */
+	clearptr = rawptr;
+	while ((rawptr < end) && (*rawptr++ & 0x80));
+
+	if (rawptr >= end) { return SECFailure; }
+	pubk->u.fortezza.clearance.len = rawptr - clearptr;
+	pubk->u.fortezza.clearance.data = 
+		(unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.clearance.len);
+	if (pubk->u.fortezza.clearance.data == NULL) {
+		return SECFailure;
+	}
+	PORT_Memcpy(pubk->u.fortezza.clearance.data,clearptr,
+					pubk->u.fortezza.clearance.len);
+
+	/* KEAPrivilege (the string up to the first byte with the hi-bit on */
+	clearptr = rawptr;
+	while ((rawptr < end) && (*rawptr++ & 0x80));
+	if (rawptr >= end) { return SECFailure; }
+	pubk->u.fortezza.KEApriviledge.len = rawptr - clearptr;
+	pubk->u.fortezza.KEApriviledge.data = 
+		(unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.KEApriviledge.len);
+	if (pubk->u.fortezza.KEApriviledge.data == NULL) {
+		return SECFailure;
+	}
+	PORT_Memcpy(pubk->u.fortezza.KEApriviledge.data,clearptr,
+				pubk->u.fortezza.KEApriviledge.len);
+
+
+	/* now copy the key. The next to bytes are the key length, and the
+	 * key follows */
+	pubk->u.fortezza.KEAKey.len = (*rawptr << 8) | rawptr[1];
+
+	rawptr += 2;
+	if (rawptr+pubk->u.fortezza.KEAKey.len > end) { return SECFailure; }
+	pubk->u.fortezza.KEAKey.data = 
+			(unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.KEAKey.len);
+	if (pubk->u.fortezza.KEAKey.data == NULL) {
+		return SECFailure;
+	}
+	PORT_Memcpy(pubk->u.fortezza.KEAKey.data,rawptr,
+					pubk->u.fortezza.KEAKey.len);
+	rawptr += pubk->u.fortezza.KEAKey.len;
+
+	/* shared key */
+	if (rawptr >= end) {
+	    pubk->u.fortezza.DSSKey.len = pubk->u.fortezza.KEAKey.len;
+	    /* this depends on the fact that we are going to get freed with an
+	     * ArenaFree call. We cannot free DSSKey and KEAKey separately */
+	    pubk->u.fortezza.DSSKey.data=
+					pubk->u.fortezza.KEAKey.data;
+	    pubk->u.fortezza.DSSpriviledge.len = 
+				pubk->u.fortezza.KEApriviledge.len;
+	    pubk->u.fortezza.DSSpriviledge.data =
+			pubk->u.fortezza.DSSpriviledge.data;
+	    goto done;
+	}
+		
+
+	/* DSS Version is next */
+	pubk->u.fortezza.DSSversion = *rawptr++;
+
+	if (*rawptr++ != 2) {
+		return SECFailure;
+	}
+
+	/* DSSPrivilege (the string up to the first byte with the hi-bit on */
+	clearptr = rawptr;
+	while ((rawptr < end) && (*rawptr++ & 0x80));
+	if (rawptr >= end) { return SECFailure; }
+	pubk->u.fortezza.DSSpriviledge.len = rawptr - clearptr;
+	pubk->u.fortezza.DSSpriviledge.data = 
+		(unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.DSSpriviledge.len);
+	if (pubk->u.fortezza.DSSpriviledge.data == NULL) {
+		return SECFailure;
+	}
+	PORT_Memcpy(pubk->u.fortezza.DSSpriviledge.data,clearptr,
+				pubk->u.fortezza.DSSpriviledge.len);
+
+	/* finally copy the DSS key. The next to bytes are the key length,
+	 *  and the key follows */
+	pubk->u.fortezza.DSSKey.len = (*rawptr << 8) | rawptr[1];
+
+	rawptr += 2;
+	if (rawptr+pubk->u.fortezza.DSSKey.len > end){ return SECFailure; }
+	pubk->u.fortezza.DSSKey.data = 
+			(unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.DSSKey.len);
+	if (pubk->u.fortezza.DSSKey.data == NULL) {
+		return SECFailure;
+	}
+	PORT_Memcpy(pubk->u.fortezza.DSSKey.data,rawptr,
+					pubk->u.fortezza.DSSKey.len);
+
+	/* ok, now we decode the parameters */
+done:
+
+        return SECKEY_FortezzaDecodePQGtoOld(arena, pubk, params);
+}
+
+
+/* Function used to make an oid tag to a key type */
+KeyType 
+seckey_GetKeyType (SECOidTag tag) {
+    KeyType keyType;
+
+    switch (tag) {
+      case SEC_OID_X500_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_RSA_ENCRYPTION:
+	keyType = rsaKey;
+	break;
+      case SEC_OID_ANSIX9_DSA_SIGNATURE:
+	keyType = dsaKey;
+	break;
+      case SEC_OID_MISSI_KEA_DSS_OLD:
+      case SEC_OID_MISSI_KEA_DSS:
+      case SEC_OID_MISSI_DSS_OLD:
+      case SEC_OID_MISSI_DSS:  
+	keyType = fortezzaKey;
+	break;
+      case SEC_OID_MISSI_KEA:
+      case SEC_OID_MISSI_ALT_KEA:
+	keyType = keaKey;
+	break;
+      case SEC_OID_X942_DIFFIE_HELMAN_KEY:
+	keyType = dhKey;
+	break;
+      case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+	keyType = ecKey;
+	break;
+      default:
+	keyType = nullKey;
+    }
+    return keyType;
+}
+
+/* Function used to determine what kind of cert we are dealing with. */
+KeyType 
+CERT_GetCertKeyType (CERTSubjectPublicKeyInfo *spki) 
+{
+    return seckey_GetKeyType(SECOID_GetAlgorithmTag(&spki->algorithm));
+}
+
+static SECKEYPublicKey *
+seckey_ExtractPublicKey(CERTSubjectPublicKeyInfo *spki)
+{
+    SECKEYPublicKey *pubk;
+    SECItem os, newOs, newParms;
+    SECStatus rv;
+    PRArenaPool *arena;
+    SECOidTag tag;
+
+    arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL)
+	return NULL;
+
+    pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
+    if (pubk == NULL) {
+	PORT_FreeArena (arena, PR_FALSE);
+	return NULL;
+    }
+
+    pubk->arena = arena;
+    pubk->pkcs11Slot = 0;
+    pubk->pkcs11ID = CK_INVALID_HANDLE;
+
+
+    /* Convert bit string length from bits to bytes */
+    os = spki->subjectPublicKey;
+    DER_ConvertBitString (&os);
+
+    tag = SECOID_GetAlgorithmTag(&spki->algorithm);
+
+    /* 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, &newOs, &os);
+    if ( rv == SECSuccess )
+    switch ( tag ) {
+      case SEC_OID_X500_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_RSA_ENCRYPTION:
+	pubk->keyType = rsaKey;
+	prepare_rsa_pub_key_for_asn1(pubk);        
+        rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_RSAPublicKeyTemplate, &newOs);
+	if (rv == SECSuccess)
+	    return pubk;
+	break;
+      case SEC_OID_ANSIX9_DSA_SIGNATURE:
+      case SEC_OID_SDN702_DSA_SIGNATURE:
+	pubk->keyType = dsaKey;
+	prepare_dsa_pub_key_for_asn1(pubk);
+	rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DSAPublicKeyTemplate, &newOs);
+	if (rv != SECSuccess) break;
+
+        rv = SECKEY_DSADecodePQG(arena, pubk,
+                                 &spki->algorithm.parameters); 
+
+	if (rv == SECSuccess) return pubk;
+	break;
+      case SEC_OID_X942_DIFFIE_HELMAN_KEY:
+	pubk->keyType = dhKey;
+	prepare_dh_pub_key_for_asn1(pubk);
+	rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DHPublicKeyTemplate, &newOs);
+	if (rv != SECSuccess) 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, &newParms, &spki->algorithm.parameters);
+        if ( rv != SECSuccess )
+            break;
+
+        rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DHParamKeyTemplate,
+                                 &newParms); 
+
+	if (rv == SECSuccess) return pubk;
+	break;
+      case SEC_OID_MISSI_KEA_DSS_OLD:
+      case SEC_OID_MISSI_KEA_DSS:
+      case SEC_OID_MISSI_DSS_OLD:
+      case SEC_OID_MISSI_DSS:
+	pubk->keyType = fortezzaKey;
+	rv = SECKEY_FortezzaDecodeCertKey(arena, pubk, &newOs,
+				          &spki->algorithm.parameters);
+	if (rv == SECSuccess)
+	    return pubk;
+	break;
+
+      case SEC_OID_MISSI_KEA:
+	pubk->keyType = keaKey;
+
+	prepare_kea_pub_key_for_asn1(pubk);
+        rv = SEC_QuickDERDecodeItem(arena, pubk,
+                                SECKEY_KEAPublicKeyTemplate, &newOs);
+        if (rv != SECSuccess) 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, &newParms, &spki->algorithm.parameters);
+        if ( rv != SECSuccess )
+            break;
+
+        rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_KEAParamsTemplate,
+                        &newParms);
+
+	if (rv == SECSuccess)
+	    return pubk;
+
+        break;
+
+      case SEC_OID_MISSI_ALT_KEA:
+	pubk->keyType = keaKey;
+
+        rv = SECITEM_CopyItem(arena,&pubk->u.kea.publicValue,&newOs);
+        if (rv != SECSuccess) 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, &newParms, &spki->algorithm.parameters);
+        if ( rv != SECSuccess )
+            break;
+
+        rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_KEAParamsTemplate,
+                        &newParms);
+
+	if (rv == SECSuccess)
+	    return pubk;
+
+        break;
+
+      case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+	pubk->keyType = ecKey;
+	pubk->u.ec.size = 0;
+
+	/* Since PKCS#11 directly takes the DER encoding of EC params
+	 * and public value, we don't need any decoding here.
+	 */
+        rv = SECITEM_CopyItem(arena, &pubk->u.ec.DEREncodedParams, 
+	    &spki->algorithm.parameters);
+        if ( rv != SECSuccess )
+            break;
+        rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &newOs);
+	if (rv == SECSuccess) return pubk;
+	break;
+
+      default:
+	rv = SECFailure;
+	break;
+    }
+
+    SECKEY_DestroyPublicKey (pubk);
+    return NULL;
+}
+
+
+/* required for JSS */
+SECKEYPublicKey *
+SECKEY_ExtractPublicKey(CERTSubjectPublicKeyInfo *spki)
+{
+    return seckey_ExtractPublicKey(spki);
+}
+
+SECKEYPublicKey *
+CERT_ExtractPublicKey(CERTCertificate *cert)
+{
+    SECStatus rv;
+
+    if (!cert) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    rv = SECKEY_UpdateCertPQG(cert);
+    if (rv != SECSuccess) return NULL;
+
+    return seckey_ExtractPublicKey(&cert->subjectPublicKeyInfo);
+}
+
+/*
+ * Get the public key for the fortezza KMID. NOTE this requires the
+ * PQG paramters to be set. We probably should have a fortezza call that 
+ * just extracts the kmid for us directly so this function can work
+ * without having the whole cert chain
+ */
+SECKEYPublicKey *
+CERT_KMIDPublicKey(CERTCertificate *cert)
+{
+    return seckey_ExtractPublicKey(&cert->subjectPublicKeyInfo);
+}
+
+int
+SECKEY_ECParamsToKeySize(const SECItem *encodedParams)
+{
+    SECOidTag tag;
+    SECItem oid = { siBuffer, NULL, 0};
+	
+    /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID),
+     * followed by the length of the curve oid and the curve oid.
+     */
+    oid.len = encodedParams->data[1];
+    oid.data = encodedParams->data + 2;
+    if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)
+	return 0;
+
+    switch (tag) {
+    case SEC_OID_SECG_EC_SECP112R1:
+    case SEC_OID_SECG_EC_SECP112R2:
+        return 112;
+
+    case SEC_OID_SECG_EC_SECT113R1:
+    case SEC_OID_SECG_EC_SECT113R2:
+	return 113;
+
+    case SEC_OID_SECG_EC_SECP128R1:
+    case SEC_OID_SECG_EC_SECP128R2:
+	return 128;
+
+    case SEC_OID_SECG_EC_SECT131R1:
+    case SEC_OID_SECG_EC_SECT131R2:
+	return 131;
+
+    case SEC_OID_SECG_EC_SECP160K1:
+    case SEC_OID_SECG_EC_SECP160R1:
+    case SEC_OID_SECG_EC_SECP160R2:
+	return 160;
+
+    case SEC_OID_SECG_EC_SECT163K1:
+    case SEC_OID_SECG_EC_SECT163R1:
+    case SEC_OID_SECG_EC_SECT163R2:
+    case SEC_OID_ANSIX962_EC_C2PNB163V1:
+    case SEC_OID_ANSIX962_EC_C2PNB163V2:
+    case SEC_OID_ANSIX962_EC_C2PNB163V3:
+	return 163;
+
+    case SEC_OID_ANSIX962_EC_C2PNB176V1:
+	return 176;
+
+    case SEC_OID_ANSIX962_EC_C2TNB191V1:
+    case SEC_OID_ANSIX962_EC_C2TNB191V2:
+    case SEC_OID_ANSIX962_EC_C2TNB191V3:
+    case SEC_OID_ANSIX962_EC_C2ONB191V4:
+    case SEC_OID_ANSIX962_EC_C2ONB191V5:
+	return 191;
+
+    case SEC_OID_SECG_EC_SECP192K1:
+    case SEC_OID_ANSIX962_EC_PRIME192V1:
+    case SEC_OID_ANSIX962_EC_PRIME192V2:
+    case SEC_OID_ANSIX962_EC_PRIME192V3:
+	return 192;
+
+    case SEC_OID_SECG_EC_SECT193R1:
+    case SEC_OID_SECG_EC_SECT193R2:
+	return 193;
+
+    case SEC_OID_ANSIX962_EC_C2PNB208W1:
+	return 208;
+
+    case SEC_OID_SECG_EC_SECP224K1:
+    case SEC_OID_SECG_EC_SECP224R1:
+	return 224;
+
+    case SEC_OID_SECG_EC_SECT233K1:
+    case SEC_OID_SECG_EC_SECT233R1:
+	return 233;
+
+    case SEC_OID_SECG_EC_SECT239K1:
+    case SEC_OID_ANSIX962_EC_C2TNB239V1:
+    case SEC_OID_ANSIX962_EC_C2TNB239V2:
+    case SEC_OID_ANSIX962_EC_C2TNB239V3:
+    case SEC_OID_ANSIX962_EC_C2ONB239V4:
+    case SEC_OID_ANSIX962_EC_C2ONB239V5:
+    case SEC_OID_ANSIX962_EC_PRIME239V1:
+    case SEC_OID_ANSIX962_EC_PRIME239V2:
+    case SEC_OID_ANSIX962_EC_PRIME239V3:
+	return 239;
+
+    case SEC_OID_SECG_EC_SECP256K1:
+    case SEC_OID_ANSIX962_EC_PRIME256V1:
+	return 256;
+
+    case SEC_OID_ANSIX962_EC_C2PNB272W1:
+	return 272;
+
+    case SEC_OID_SECG_EC_SECT283K1:
+    case SEC_OID_SECG_EC_SECT283R1:
+	return 283;
+
+    case SEC_OID_ANSIX962_EC_C2PNB304W1:
+	return 304;
+
+    case SEC_OID_ANSIX962_EC_C2TNB359V1:
+	return 359;
+
+    case SEC_OID_ANSIX962_EC_C2PNB368W1:
+	return 368;
+
+    case SEC_OID_SECG_EC_SECP384R1:
+	return 384;
+
+    case SEC_OID_SECG_EC_SECT409K1:
+    case SEC_OID_SECG_EC_SECT409R1:
+	return 409;
+
+    case SEC_OID_ANSIX962_EC_C2TNB431R1:
+	return 431;
+
+    case SEC_OID_SECG_EC_SECP521R1:
+	return 521;
+
+    case SEC_OID_SECG_EC_SECT571K1:
+    case SEC_OID_SECG_EC_SECT571R1:
+	return 571;
+
+    default:
+	PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+	return 0;
+    }
+}
+
+int
+SECKEY_ECParamsToBasePointOrderLen(const SECItem *encodedParams)
+{
+    SECOidTag tag;
+    SECItem oid = { siBuffer, NULL, 0};
+	
+    /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID),
+     * followed by the length of the curve oid and the curve oid.
+     */
+    oid.len = encodedParams->data[1];
+    oid.data = encodedParams->data + 2;
+    if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)
+	return 0;
+
+    switch (tag) {
+    case SEC_OID_SECG_EC_SECP112R1:
+        return 112;
+    case SEC_OID_SECG_EC_SECP112R2:
+        return 110;
+
+    case SEC_OID_SECG_EC_SECT113R1:
+    case SEC_OID_SECG_EC_SECT113R2:
+	return 113;
+
+    case SEC_OID_SECG_EC_SECP128R1:
+	return 128;
+    case SEC_OID_SECG_EC_SECP128R2:
+	return 126;
+
+    case SEC_OID_SECG_EC_SECT131R1:
+    case SEC_OID_SECG_EC_SECT131R2:
+	return 131;
+
+    case SEC_OID_SECG_EC_SECP160K1:
+    case SEC_OID_SECG_EC_SECP160R1:
+    case SEC_OID_SECG_EC_SECP160R2:
+	return 161;
+
+    case SEC_OID_SECG_EC_SECT163K1:
+	return 163;
+    case SEC_OID_SECG_EC_SECT163R1:
+	return 162;
+    case SEC_OID_SECG_EC_SECT163R2:
+    case SEC_OID_ANSIX962_EC_C2PNB163V1:
+	return 163;
+    case SEC_OID_ANSIX962_EC_C2PNB163V2:
+    case SEC_OID_ANSIX962_EC_C2PNB163V3:
+	return 162;
+
+    case SEC_OID_ANSIX962_EC_C2PNB176V1:
+	return 161;
+
+    case SEC_OID_ANSIX962_EC_C2TNB191V1:
+	return 191;
+    case SEC_OID_ANSIX962_EC_C2TNB191V2:
+	return 190;
+    case SEC_OID_ANSIX962_EC_C2TNB191V3:
+	return 189;
+    case SEC_OID_ANSIX962_EC_C2ONB191V4:
+	return 191;
+    case SEC_OID_ANSIX962_EC_C2ONB191V5:
+	return 188;
+
+    case SEC_OID_SECG_EC_SECP192K1:
+    case SEC_OID_ANSIX962_EC_PRIME192V1:
+    case SEC_OID_ANSIX962_EC_PRIME192V2:
+    case SEC_OID_ANSIX962_EC_PRIME192V3:
+	return 192;
+
+    case SEC_OID_SECG_EC_SECT193R1:
+    case SEC_OID_SECG_EC_SECT193R2:
+	return 193;
+
+    case SEC_OID_ANSIX962_EC_C2PNB208W1:
+	return 193;
+
+    case SEC_OID_SECG_EC_SECP224K1:
+	return 225;
+    case SEC_OID_SECG_EC_SECP224R1:
+	return 224;
+
+    case SEC_OID_SECG_EC_SECT233K1:
+	return 232;
+    case SEC_OID_SECG_EC_SECT233R1:
+	return 233;
+
+    case SEC_OID_SECG_EC_SECT239K1:
+    case SEC_OID_ANSIX962_EC_C2TNB239V1:
+	return 238;
+    case SEC_OID_ANSIX962_EC_C2TNB239V2:
+	return 237;
+    case SEC_OID_ANSIX962_EC_C2TNB239V3:
+	return 236;
+    case SEC_OID_ANSIX962_EC_C2ONB239V4:
+	return 238;
+    case SEC_OID_ANSIX962_EC_C2ONB239V5:
+	return 237;
+    case SEC_OID_ANSIX962_EC_PRIME239V1:
+    case SEC_OID_ANSIX962_EC_PRIME239V2:
+    case SEC_OID_ANSIX962_EC_PRIME239V3:
+	return 239;
+
+    case SEC_OID_SECG_EC_SECP256K1:
+    case SEC_OID_ANSIX962_EC_PRIME256V1:
+	return 256;
+
+    case SEC_OID_ANSIX962_EC_C2PNB272W1:
+	return 257;
+
+    case SEC_OID_SECG_EC_SECT283K1:
+	return 281;
+    case SEC_OID_SECG_EC_SECT283R1:
+	return 282;
+
+    case SEC_OID_ANSIX962_EC_C2PNB304W1:
+	return 289;
+
+    case SEC_OID_ANSIX962_EC_C2TNB359V1:
+	return 353;
+
+    case SEC_OID_ANSIX962_EC_C2PNB368W1:
+	return 353;
+
+    case SEC_OID_SECG_EC_SECP384R1:
+	return 384;
+
+    case SEC_OID_SECG_EC_SECT409K1:
+	return 407;
+    case SEC_OID_SECG_EC_SECT409R1:
+	return 409;
+
+    case SEC_OID_ANSIX962_EC_C2TNB431R1:
+	return 418;
+
+    case SEC_OID_SECG_EC_SECP521R1:
+	return 521;
+
+    case SEC_OID_SECG_EC_SECT571K1:
+    case SEC_OID_SECG_EC_SECT571R1:
+	return 570;
+
+    default:
+	PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+	return 0;
+    }
+}
+
+/* returns key strength in bytes (not bits) */
+unsigned
+SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk)
+{
+    unsigned char b0;
+    unsigned size;
+
+    /* interpret modulus length as key strength... in
+     * fortezza that's the public key length */
+
+    switch (pubk->keyType) {
+    case rsaKey:
+    	b0 = pubk->u.rsa.modulus.data[0];
+    	return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
+    case dsaKey:
+    	b0 = pubk->u.dsa.publicValue.data[0];
+    	return b0 ? pubk->u.dsa.publicValue.len :
+	    pubk->u.dsa.publicValue.len - 1;
+    case dhKey:
+    	b0 = pubk->u.dh.publicValue.data[0];
+    	return b0 ? pubk->u.dh.publicValue.len :
+	    pubk->u.dh.publicValue.len - 1;
+    case fortezzaKey:
+	return PR_MAX(pubk->u.fortezza.KEAKey.len, pubk->u.fortezza.DSSKey.len);
+    case ecKey:
+	/* Get the key size in bits and adjust */
+	size =	SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
+	return (size + 7)/8;
+    default:
+	break;
+    }
+    PORT_SetError(SEC_ERROR_INVALID_KEY);
+    return 0;
+}
+
+/* returns key strength in bits */
+unsigned
+SECKEY_PublicKeyStrengthInBits(const SECKEYPublicKey *pubk)
+{
+    unsigned size;
+    switch (pubk->keyType) {
+    case rsaKey:
+    case dsaKey:
+    case dhKey:
+    case fortezzaKey:
+	return SECKEY_PublicKeyStrength(pubk) * 8; /* 1 byte = 8 bits */
+    case ecKey:
+	size = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
+	return size;
+    default:
+	break;
+    }
+    PORT_SetError(SEC_ERROR_INVALID_KEY);
+    return 0;
+}
+
+/* returns signature length in bytes (not bits) */
+unsigned
+SECKEY_SignatureLen(const SECKEYPublicKey *pubk)
+{
+    unsigned char b0;
+    unsigned size;
+
+    switch (pubk->keyType) {
+    case rsaKey:
+    	b0 = pubk->u.rsa.modulus.data[0];
+    	return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
+    case fortezzaKey:
+    case dsaKey:
+    	return DSA_SIGNATURE_LEN;
+    case ecKey:
+	/* Get the base point order length in bits and adjust */
+	size =	SECKEY_ECParamsToBasePointOrderLen(
+		&pubk->u.ec.DEREncodedParams);
+	return ((size + 7)/8) * 2;
+    default:
+	break;
+    }
+    PORT_SetError(SEC_ERROR_INVALID_KEY);
+    return 0;
+}
+
+SECKEYPrivateKey *
+SECKEY_CopyPrivateKey(const SECKEYPrivateKey *privk)
+{
+    SECKEYPrivateKey *copyk;
+    PRArenaPool *arena;
+    
+    if (!privk || !privk->pkcs11Slot) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	return NULL;
+    }
+
+    copyk = (SECKEYPrivateKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPrivateKey));
+    if (copyk) {
+	copyk->arena = arena;
+	copyk->keyType = privk->keyType;
+
+	/* copy the PKCS #11 parameters */
+	copyk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot);
+	/* if the key we're referencing was a temparary key we have just
+	 * created, that we want to go away when we're through, we need
+	 * to make a copy of it */
+	if (privk->pkcs11IsTemp) {
+	    copyk->pkcs11ID = 
+			PK11_CopyKey(privk->pkcs11Slot,privk->pkcs11ID);
+	    if (copyk->pkcs11ID == CK_INVALID_HANDLE) goto fail;
+	} else {
+	    copyk->pkcs11ID = privk->pkcs11ID;
+	}
+	copyk->pkcs11IsTemp = privk->pkcs11IsTemp;
+	copyk->wincx = privk->wincx;
+	copyk->staticflags = privk->staticflags;
+	return copyk;
+    } else {
+	PORT_SetError (SEC_ERROR_NO_MEMORY);
+    }
+
+fail:
+    PORT_FreeArena (arena, PR_FALSE);
+    return NULL;
+}
+
+SECKEYPublicKey *
+SECKEY_CopyPublicKey(const SECKEYPublicKey *pubk)
+{
+    SECKEYPublicKey *copyk;
+    PRArenaPool *arena;
+    SECStatus rv = SECSuccess;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	PORT_SetError (SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+
+    copyk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey));
+    if (!copyk) {
+        PORT_FreeArena (arena, PR_FALSE);
+        PORT_SetError (SEC_ERROR_NO_MEMORY);
+        return NULL;
+    }
+
+    copyk->arena = arena;
+    copyk->keyType = pubk->keyType;
+    if (pubk->pkcs11Slot && 
+        PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) {
+        copyk->pkcs11Slot = PK11_ReferenceSlot(pubk->pkcs11Slot);
+        copyk->pkcs11ID = pubk->pkcs11ID;
+    } else {
+        copyk->pkcs11Slot = NULL;	/* go get own reference */
+        copyk->pkcs11ID = CK_INVALID_HANDLE;
+    }
+    switch (pubk->keyType) {
+      case rsaKey:
+          rv = SECITEM_CopyItem(arena, &copyk->u.rsa.modulus,
+                                &pubk->u.rsa.modulus);
+          if (rv == SECSuccess) {
+              rv = SECITEM_CopyItem (arena, &copyk->u.rsa.publicExponent,
+                                     &pubk->u.rsa.publicExponent);
+              if (rv == SECSuccess)
+                  return copyk;
+          }
+          break;
+      case dsaKey:
+          rv = SECITEM_CopyItem(arena, &copyk->u.dsa.publicValue,
+                                &pubk->u.dsa.publicValue);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.dsa.params.prime,
+                                &pubk->u.dsa.params.prime);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.dsa.params.subPrime,
+                                &pubk->u.dsa.params.subPrime);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.dsa.params.base,
+                                &pubk->u.dsa.params.base);
+          break;
+      case keaKey:
+          rv = SECITEM_CopyItem(arena, &copyk->u.kea.publicValue,
+                                &pubk->u.kea.publicValue);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.kea.params.hash,
+                                &pubk->u.kea.params.hash);
+          break;
+      case fortezzaKey:
+          copyk->u.fortezza.KEAversion = pubk->u.fortezza.KEAversion;
+          copyk->u.fortezza.DSSversion = pubk->u.fortezza.DSSversion;
+          PORT_Memcpy(copyk->u.fortezza.KMID, pubk->u.fortezza.KMID,
+                      sizeof(pubk->u.fortezza.KMID));
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.clearance, 
+                                &pubk->u.fortezza.clearance);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.KEApriviledge, 
+                                &pubk->u.fortezza.KEApriviledge);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.DSSpriviledge, 
+                                &pubk->u.fortezza.DSSpriviledge);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.KEAKey, 
+                                &pubk->u.fortezza.KEAKey);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.DSSKey, 
+                                &pubk->u.fortezza.DSSKey);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.params.prime, 
+                                &pubk->u.fortezza.params.prime);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.params.subPrime, 
+                                &pubk->u.fortezza.params.subPrime);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.params.base, 
+                                &pubk->u.fortezza.params.base);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.keaParams.prime, 
+                                &pubk->u.fortezza.keaParams.prime);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.keaParams.subPrime, 
+                                &pubk->u.fortezza.keaParams.subPrime);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.fortezza.keaParams.base, 
+                                &pubk->u.fortezza.keaParams.base);
+          break;
+      case dhKey:
+          rv = SECITEM_CopyItem(arena,&copyk->u.dh.prime,&pubk->u.dh.prime);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena,&copyk->u.dh.base,&pubk->u.dh.base);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena, &copyk->u.dh.publicValue, 
+                                &pubk->u.dh.publicValue);
+          break;
+      case ecKey:
+          copyk->u.ec.size = pubk->u.ec.size;
+          rv = SECITEM_CopyItem(arena,&copyk->u.ec.DEREncodedParams,
+                                &pubk->u.ec.DEREncodedParams);
+          if (rv != SECSuccess) break;
+          rv = SECITEM_CopyItem(arena,&copyk->u.ec.publicValue,
+                                &pubk->u.ec.publicValue);
+          break;
+      case nullKey:
+          return copyk;
+      default:
+          rv = SECFailure;
+          break;
+    }
+    if (rv == SECSuccess)
+        return copyk;
+
+    SECKEY_DestroyPublicKey (copyk);
+    return NULL;
+}
+
+
+SECKEYPublicKey *
+SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk)
+{
+    SECKEYPublicKey *pubk;
+    PRArenaPool *arena;
+    CERTCertificate *cert;
+    SECStatus rv;
+
+    /*
+     * First try to look up the cert.
+     */
+    cert = PK11_GetCertFromPrivateKey(privk);
+    if (cert) {
+	pubk = CERT_ExtractPublicKey(cert);
+	CERT_DestroyCertificate(cert);
+	return pubk;
+    }
+
+    /* couldn't find the cert, build pub key by hand */
+    arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	PORT_SetError (SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+    pubk = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena,
+						   sizeof (SECKEYPublicKey));
+    if (pubk == NULL) {
+	PORT_FreeArena(arena,PR_FALSE);
+	return NULL;
+    }
+    pubk->keyType = privk->keyType;
+    pubk->pkcs11Slot = NULL;
+    pubk->pkcs11ID = CK_INVALID_HANDLE;
+    pubk->arena = arena;
+
+    /*
+     * fortezza is at the head of this switch, since we don't want to
+     * allocate an arena... CERT_ExtractPublicKey will to that for us.
+     */
+    switch(privk->keyType) {
+      case fortezzaKey:
+      case nullKey:
+      case dhKey:
+      case dsaKey:
+	/* Nothing to query, if the cert isn't there, we're done -- no way
+	 * to get the public key */
+	break;
+      case rsaKey:
+	rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID,
+				CKA_MODULUS,arena,&pubk->u.rsa.modulus);
+	if (rv != SECSuccess)  break;
+	rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID,
+			CKA_PUBLIC_EXPONENT,arena,&pubk->u.rsa.publicExponent);
+	if (rv != SECSuccess)  break;
+	return pubk;
+	break;
+    default:
+	break;
+    }
+
+    PORT_FreeArena (arena, PR_FALSE);
+    return NULL;
+}
+
+CERTSubjectPublicKeyInfo *
+SECKEY_CreateSubjectPublicKeyInfo(SECKEYPublicKey *pubk)
+{
+    CERTSubjectPublicKeyInfo *spki;
+    PRArenaPool *arena;
+    SECItem params = { siBuffer, NULL, 0 };
+
+    if (!pubk) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+
+    spki = (CERTSubjectPublicKeyInfo *) PORT_ArenaZAlloc(arena, sizeof (*spki));
+    if (spki != NULL) {
+	SECStatus rv;
+	SECItem *rv_item;
+	
+	spki->arena = arena;
+	switch(pubk->keyType) {
+	  case rsaKey:
+	    rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
+				     SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
+	    if (rv == SECSuccess) {
+		/*
+		 * DER encode the public key into the subjectPublicKeyInfo.
+		 */
+		prepare_rsa_pub_key_for_asn1(pubk);
+		rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey,
+					     pubk, SECKEY_RSAPublicKeyTemplate);
+		if (rv_item != NULL) {
+		    /*
+		     * The stored value is supposed to be a BIT_STRING,
+		     * so convert the length.
+		     */
+		    spki->subjectPublicKey.len <<= 3;
+		    /*
+		     * We got a good one; return it.
+		     */
+		    return spki;
+		}
+	    }
+	    break;
+	  case dsaKey:
+	    /* DER encode the params. */
+	    prepare_pqg_params_for_asn1(&pubk->u.dsa.params);
+	    rv_item = SEC_ASN1EncodeItem(arena, &params, &pubk->u.dsa.params,
+					 SECKEY_PQGParamsTemplate);
+	    if (rv_item != NULL) {
+		rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
+					   SEC_OID_ANSIX9_DSA_SIGNATURE,
+					   &params);
+		if (rv == SECSuccess) {
+		    /*
+		     * DER encode the public key into the subjectPublicKeyInfo.
+		     */
+		    prepare_dsa_pub_key_for_asn1(pubk);
+		    rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey,
+						 pubk,
+						 SECKEY_DSAPublicKeyTemplate);
+		    if (rv_item != NULL) {
+			/*
+			 * The stored value is supposed to be a BIT_STRING,
+			 * so convert the length.
+			 */
+			spki->subjectPublicKey.len <<= 3;
+			/*
+			 * We got a good one; return it.
+			 */
+			return spki;
+		    }
+		}
+	    }
+	    SECITEM_FreeItem(&params, PR_FALSE);
+	    break;
+	  case ecKey:
+	    rv = SECITEM_CopyItem(arena, &params, 
+				  &pubk->u.ec.DEREncodedParams);
+	    if (rv != SECSuccess) break;
+
+	    rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
+				       SEC_OID_ANSIX962_EC_PUBLIC_KEY,
+				       &params);
+	    if (rv != SECSuccess) break;
+
+	    rv = SECITEM_CopyItem(arena, &spki->subjectPublicKey,
+				  &pubk->u.ec.publicValue);
+
+	    if (rv == SECSuccess) {
+	        /*
+		 * The stored value is supposed to be a BIT_STRING,
+		 * so convert the length.
+		 */
+	        spki->subjectPublicKey.len <<= 3;
+		/*
+		 * We got a good one; return it.
+		 */
+		return spki;
+	    }
+	    break;
+	  case keaKey:
+	  case dhKey: /* later... */
+
+	  break;  
+	  case fortezzaKey:
+#ifdef notdef
+	    /* encode the DSS parameters (PQG) */
+	    rv = FortezzaBuildParams(&params,pubk);
+	    if (rv != SECSuccess) break;
+
+	    /* set the algorithm */
+	    rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
+				       SEC_OID_MISSI_KEA_DSS, &params);
+	    PORT_Free(params.data);
+	    if (rv == SECSuccess) {
+		/*
+		 * Encode the public key into the subjectPublicKeyInfo.
+		 * Fortezza key material is not standard DER
+		 */
+		rv = FortezzaEncodeCertKey(arena,&spki->subjectPublicKey,pubk);
+		if (rv == SECSuccess) {
+		    /*
+		     * The stored value is supposed to be a BIT_STRING,
+		     * so convert the length.
+		     */
+		    spki->subjectPublicKey.len <<= 3;
+
+		    /*
+		     * We got a good one; return it.
+		     */
+		    return spki;
+		}
+	    }
+#endif
+	    break;
+	  default:
+	    break;
+	}
+    } else {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+
+    PORT_FreeArena(arena, PR_FALSE);
+    return NULL;
+}
+
+void
+SECKEY_DestroySubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki)
+{
+    if (spki && spki->arena) {
+	PORT_FreeArena(spki->arena, PR_FALSE);
+    }
+}
+
+/*
+ * this only works for RSA keys... need to do something
+ * similiar to CERT_ExtractPublicKey for other key times.
+ */
+SECKEYPublicKey *
+SECKEY_DecodeDERPublicKey(SECItem *pubkder)
+{
+    PRArenaPool *arena;
+    SECKEYPublicKey *pubk;
+    SECStatus rv;
+    SECItem newPubkder;
+
+    arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	PORT_SetError (SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+
+    pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey));
+    if (pubk != NULL) {
+	pubk->arena = arena;
+	pubk->pkcs11Slot = NULL;
+	pubk->pkcs11ID = 0;
+	prepare_rsa_pub_key_for_asn1(pubk);
+        /* 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, &newPubkder, pubkder);
+        if ( rv == SECSuccess ) {
+	    rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_RSAPublicKeyTemplate,
+				&newPubkder);
+        }
+	if (rv == SECSuccess)
+	    return pubk;
+	SECKEY_DestroyPublicKey (pubk);
+    } else {
+	PORT_SetError (SEC_ERROR_NO_MEMORY);
+    }
+
+    PORT_FreeArena (arena, PR_FALSE);
+    return NULL;
+}
+
+/*
+ * Decode a base64 ascii encoded DER encoded public key.
+ */
+SECKEYPublicKey *
+SECKEY_ConvertAndDecodePublicKey(char *pubkstr)
+{
+    SECKEYPublicKey *pubk;
+    SECStatus rv;
+    SECItem der;
+
+    rv = ATOB_ConvertAsciiToItem (&der, pubkstr);
+    if (rv != SECSuccess)
+	return NULL;
+
+    pubk = SECKEY_DecodeDERPublicKey (&der);
+
+    PORT_Free (der.data);
+    return pubk;
+}
+
+SECItem *
+SECKEY_EncodeDERSubjectPublicKeyInfo(SECKEYPublicKey *pubk)
+{
+    CERTSubjectPublicKeyInfo *spki=NULL;
+    SECItem *spkiDER=NULL;
+
+    /* get the subjectpublickeyinfo */
+    spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
+    if( spki == NULL ) {
+	goto finish;
+    }
+
+    /* DER-encode the subjectpublickeyinfo */
+    spkiDER = SEC_ASN1EncodeItem(NULL /*arena*/, NULL/*dest*/, spki,
+					CERT_SubjectPublicKeyInfoTemplate);
+
+    SECKEY_DestroySubjectPublicKeyInfo(spki);
+
+finish:
+    return spkiDER;
+}
+
+
+CERTSubjectPublicKeyInfo *
+SECKEY_DecodeDERSubjectPublicKeyInfo(SECItem *spkider)
+{
+    PRArenaPool *arena;
+    CERTSubjectPublicKeyInfo *spki;
+    SECStatus rv;
+    SECItem newSpkider;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+
+    spki = (CERTSubjectPublicKeyInfo *)
+		PORT_ArenaZAlloc(arena, sizeof (CERTSubjectPublicKeyInfo));
+    if (spki != NULL) {
+	spki->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, &newSpkider, spkider);
+        if ( rv == SECSuccess ) {
+            rv = SEC_QuickDERDecodeItem(arena,spki,
+				    CERT_SubjectPublicKeyInfoTemplate, &newSpkider);
+        }
+	if (rv == SECSuccess)
+	    return spki;
+    } else {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+
+    PORT_FreeArena(arena, PR_FALSE);
+    return NULL;
+}
+
+/*
+ * Decode a base64 ascii encoded DER encoded subject public key info.
+ */
+CERTSubjectPublicKeyInfo *
+SECKEY_ConvertAndDecodeSubjectPublicKeyInfo(char *spkistr)
+{
+    CERTSubjectPublicKeyInfo *spki;
+    SECStatus rv;
+    SECItem der;
+
+    rv = ATOB_ConvertAsciiToItem(&der, spkistr);
+    if (rv != SECSuccess)
+	return NULL;
+
+    spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
+
+    PORT_Free(der.data);
+    return spki;
+}
+
+/*
+ * Decode a base64 ascii encoded DER encoded public key and challenge
+ * Verify digital signature and make sure challenge matches
+ */
+CERTSubjectPublicKeyInfo *
+SECKEY_ConvertAndDecodePublicKeyAndChallenge(char *pkacstr, char *challenge,
+								void *wincx)
+{
+    CERTSubjectPublicKeyInfo *spki = NULL;
+    CERTPublicKeyAndChallenge pkac;
+    SECStatus rv;
+    SECItem signedItem;
+    PRArenaPool *arena = NULL;
+    CERTSignedData sd;
+    SECItem sig;
+    SECKEYPublicKey *pubKey = NULL;
+    unsigned int len;
+    
+    signedItem.data = NULL;
+    
+    /* convert the base64 encoded data to binary */
+    rv = ATOB_ConvertAsciiToItem(&signedItem, pkacstr);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    /* create an arena */
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+
+    /* decode the outer wrapping of signed data */
+    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
+    rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, &signedItem );
+    if ( rv ) {
+	goto loser;
+    }
+
+    /* decode the public key and challenge wrapper */
+    PORT_Memset(&pkac, 0, sizeof(CERTPublicKeyAndChallenge));
+    rv = SEC_QuickDERDecodeItem(arena, &pkac, CERT_PublicKeyAndChallengeTemplate, 
+			    &sd.data);
+    if ( rv ) {
+	goto loser;
+    }
+
+    /* decode the subject public key info */
+    spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&pkac.spki);
+    if ( spki == NULL ) {
+	goto loser;
+    }
+    
+    /* get the public key */
+    pubKey = seckey_ExtractPublicKey(spki);
+    if ( pubKey == NULL ) {
+	goto loser;
+    }
+
+    /* check the signature */
+    sig = sd.signature;
+    DER_ConvertBitString(&sig);
+    rv = VFY_VerifyDataWithAlgorithmID(sd.data.data, sd.data.len, pubKey, &sig,
+			&(sd.signatureAlgorithm), NULL, wincx);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+    
+    /* check the challenge */
+    if ( challenge ) {
+	len = PORT_Strlen(challenge);
+	/* length is right */
+	if ( len != pkac.challenge.len ) {
+	    goto loser;
+	}
+	/* actual data is right */
+	if ( PORT_Memcmp(challenge, pkac.challenge.data, len) != 0 ) {
+	    goto loser;
+	}
+    }
+    goto done;
+
+loser:
+    /* make sure that we return null if we got an error */
+    if ( spki ) {
+	SECKEY_DestroySubjectPublicKeyInfo(spki);
+    }
+    spki = NULL;
+    
+done:
+    if ( signedItem.data ) {
+	PORT_Free(signedItem.data);
+    }
+    if ( arena ) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    if ( pubKey ) {
+	SECKEY_DestroyPublicKey(pubKey);
+    }
+    
+    return spki;
+}
+
+void
+SECKEY_DestroyPrivateKeyInfo(SECKEYPrivateKeyInfo *pvk,
+			     PRBool freeit)
+{
+    PRArenaPool *poolp;
+
+    if(pvk != NULL) {
+	if(pvk->arena) {
+	    poolp = pvk->arena;
+	    /* zero structure since PORT_FreeArena does not support
+	     * this yet.
+	     */
+	    PORT_Memset(pvk->privateKey.data, 0, pvk->privateKey.len);
+	    PORT_Memset((char *)pvk, 0, sizeof(*pvk));
+	    if(freeit == PR_TRUE) {
+		PORT_FreeArena(poolp, PR_TRUE);
+	    } else {
+		pvk->arena = poolp;
+	    }
+	} else {
+	    SECITEM_ZfreeItem(&pvk->version, PR_FALSE);
+	    SECITEM_ZfreeItem(&pvk->privateKey, PR_FALSE);
+	    SECOID_DestroyAlgorithmID(&pvk->algorithm, PR_FALSE);
+	    PORT_Memset((char *)pvk, 0, sizeof(pvk));
+	    if(freeit == PR_TRUE) {
+		PORT_Free(pvk);
+	    }
+	}
+    }
+}
+
+void
+SECKEY_DestroyEncryptedPrivateKeyInfo(SECKEYEncryptedPrivateKeyInfo *epki,
+				      PRBool freeit)
+{
+    PRArenaPool *poolp;
+
+    if(epki != NULL) {
+	if(epki->arena) {
+	    poolp = epki->arena;
+	    /* zero structure since PORT_FreeArena does not support
+	     * this yet.
+	     */
+	    PORT_Memset(epki->encryptedData.data, 0, epki->encryptedData.len);
+	    PORT_Memset((char *)epki, 0, sizeof(*epki));
+	    if(freeit == PR_TRUE) {
+		PORT_FreeArena(poolp, PR_TRUE);
+	    } else {
+		epki->arena = poolp;
+	    }
+	} else {
+	    SECITEM_ZfreeItem(&epki->encryptedData, PR_FALSE);
+	    SECOID_DestroyAlgorithmID(&epki->algorithm, PR_FALSE);
+	    PORT_Memset((char *)epki, 0, sizeof(epki));
+	    if(freeit == PR_TRUE) {
+		PORT_Free(epki);
+	    }
+	}
+    }
+}
+
+SECStatus
+SECKEY_CopyPrivateKeyInfo(PRArenaPool *poolp,
+			  SECKEYPrivateKeyInfo *to,
+			  SECKEYPrivateKeyInfo *from)
+{
+    SECStatus rv = SECFailure;
+
+    if((to == NULL) || (from == NULL)) {
+	return SECFailure;
+    }
+
+    rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm);
+    if(rv != SECSuccess) {
+	return SECFailure;
+    }
+    rv = SECITEM_CopyItem(poolp, &to->privateKey, &from->privateKey);
+    if(rv != SECSuccess) {
+	return SECFailure;
+    }
+    rv = SECITEM_CopyItem(poolp, &to->version, &from->version);
+
+    return rv;
+}
+
+SECStatus
+SECKEY_CopyEncryptedPrivateKeyInfo(PRArenaPool *poolp, 
+				   SECKEYEncryptedPrivateKeyInfo *to,
+				   SECKEYEncryptedPrivateKeyInfo *from)
+{
+    SECStatus rv = SECFailure;
+
+    if((to == NULL) || (from == NULL)) {
+	return SECFailure;
+    }
+
+    rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm);
+    if(rv != SECSuccess) {
+	return SECFailure;
+    }
+    rv = SECITEM_CopyItem(poolp, &to->encryptedData, &from->encryptedData);
+
+    return rv;
+}
+
+KeyType
+SECKEY_GetPrivateKeyType(SECKEYPrivateKey *privKey)
+{
+   return privKey->keyType;
+}
+
+KeyType
+SECKEY_GetPublicKeyType(SECKEYPublicKey *pubKey)
+{
+   return pubKey->keyType;
+}
+
+SECKEYPublicKey*
+SECKEY_ImportDERPublicKey(SECItem *derKey, CK_KEY_TYPE type)
+{
+    SECKEYPublicKey *pubk = NULL;
+    SECStatus rv = SECFailure;
+    SECItem newDerKey;
+
+    if (!derKey) {
+        return NULL;
+    } 
+
+    pubk = PORT_ZNew(SECKEYPublicKey);
+    if(pubk == NULL) {
+        goto finish;
+    }
+    pubk->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (NULL == pubk->arena) {
+        goto finish;
+    }
+    rv = SECITEM_CopyItem(pubk->arena, &newDerKey, derKey);
+    if (SECSuccess != rv) {
+        goto finish;
+    }
+
+    pubk->pkcs11Slot = NULL;
+    pubk->pkcs11ID = CK_INVALID_HANDLE;
+
+    switch( type ) {
+      case CKK_RSA:
+	prepare_rsa_pub_key_for_asn1(pubk);
+        rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_RSAPublicKeyTemplate, &newDerKey);
+        pubk->keyType = rsaKey;
+        break;
+      case CKK_DSA:
+	prepare_dsa_pub_key_for_asn1(pubk);
+        rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DSAPublicKeyTemplate, &newDerKey);
+        pubk->keyType = dsaKey;
+        break;
+      case CKK_DH:
+	prepare_dh_pub_key_for_asn1(pubk);
+        rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DHPublicKeyTemplate, &newDerKey);
+        pubk->keyType = dhKey;
+        break;
+      default:
+        rv = SECFailure;
+        break;
+    }
+
+finish:
+    if( rv != SECSuccess && pubk != NULL) {
+        if (pubk->arena) {
+            PORT_FreeArena(pubk->arena, PR_TRUE);
+        }
+        PORT_Free(pubk);
+        pubk = NULL;
+    }
+    return pubk;
+}
+
+SECKEYPrivateKeyList*
+SECKEY_NewPrivateKeyList(void)
+{
+    PRArenaPool *arena = NULL;
+    SECKEYPrivateKeyList *ret = NULL;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if ( arena == NULL ) {
+        goto loser;
+    }
+
+    ret = (SECKEYPrivateKeyList *)PORT_ArenaZAlloc(arena,
+                sizeof(SECKEYPrivateKeyList));
+    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
+SECKEY_DestroyPrivateKeyList(SECKEYPrivateKeyList *keys)
+{
+    while( !PR_CLIST_IS_EMPTY(&keys->list) ) {
+        SECKEY_RemovePrivateKeyListNode(
+            (SECKEYPrivateKeyListNode*)(PR_LIST_HEAD(&keys->list)) );
+    }
+
+    PORT_FreeArena(keys->arena, PR_FALSE);
+
+    return;
+}
+
+
+void
+SECKEY_RemovePrivateKeyListNode(SECKEYPrivateKeyListNode *node)
+{
+    PR_ASSERT(node->key);
+    SECKEY_DestroyPrivateKey(node->key);
+    node->key = NULL;
+    PR_REMOVE_LINK(&node->links);
+    return;
+
+}
+
+SECStatus
+SECKEY_AddPrivateKeyToListTail( SECKEYPrivateKeyList *list,
+                                SECKEYPrivateKey *key)
+{
+    SECKEYPrivateKeyListNode *node;
+
+    node = (SECKEYPrivateKeyListNode *)PORT_ArenaZAlloc(list->arena,
+                sizeof(SECKEYPrivateKeyListNode));
+    if ( node == NULL ) {
+        goto loser;
+    }
+
+    PR_INSERT_BEFORE(&node->links, &list->list);
+    node->key = key;
+    return(SECSuccess);
+
+loser:
+    return(SECFailure);
+}
+
+
+SECKEYPublicKeyList*
+SECKEY_NewPublicKeyList(void)
+{
+    PRArenaPool *arena = NULL;
+    SECKEYPublicKeyList *ret = NULL;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if ( arena == NULL ) {
+        goto loser;
+    }
+
+    ret = (SECKEYPublicKeyList *)PORT_ArenaZAlloc(arena,
+                sizeof(SECKEYPublicKeyList));
+    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
+SECKEY_DestroyPublicKeyList(SECKEYPublicKeyList *keys)
+{
+    while( !PR_CLIST_IS_EMPTY(&keys->list) ) {
+        SECKEY_RemovePublicKeyListNode(
+            (SECKEYPublicKeyListNode*)(PR_LIST_HEAD(&keys->list)) );
+    }
+
+    PORT_FreeArena(keys->arena, PR_FALSE);
+
+    return;
+}
+
+
+void
+SECKEY_RemovePublicKeyListNode(SECKEYPublicKeyListNode *node)
+{
+    PR_ASSERT(node->key);
+    SECKEY_DestroyPublicKey(node->key);
+    node->key = NULL;
+    PR_REMOVE_LINK(&node->links);
+    return;
+
+}
+
+SECStatus
+SECKEY_AddPublicKeyToListTail( SECKEYPublicKeyList *list,
+                                SECKEYPublicKey *key)
+{
+    SECKEYPublicKeyListNode *node;
+
+    node = (SECKEYPublicKeyListNode *)PORT_ArenaZAlloc(list->arena,
+                sizeof(SECKEYPublicKeyListNode));
+    if ( node == NULL ) {
+        goto loser;
+    }
+
+    PR_INSERT_BEFORE(&node->links, &list->list);
+    node->key = key;
+    return(SECSuccess);
+
+loser:
+    return(SECFailure);
+}
+
+#define SECKEY_CacheAttribute(key, attribute) \
+    if (CK_TRUE == PK11_HasAttributeSet(key->pkcs11Slot, key->pkcs11ID, attribute)) { \
+        key->staticflags |= SECKEY_##attribute; \
+    } else { \
+        key->staticflags &= (~SECKEY_##attribute); \
+    }
+
+SECStatus
+SECKEY_CacheStaticFlags(SECKEYPrivateKey* key)
+{
+    SECStatus rv = SECFailure;
+    if (key && key->pkcs11Slot && key->pkcs11ID) {
+        key->staticflags |= SECKEY_Attributes_Cached;
+        SECKEY_CacheAttribute(key, CKA_PRIVATE);
+        rv = SECSuccess;
+    }
+    return rv;
+}
diff --git a/mozilla/security/nss/lib/cryptohi/secsign.c b/mozilla/security/nss/lib/cryptohi/secsign.c
new file mode 100644
index 0000000..48d68c1
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/secsign.c
@@ -0,0 +1,518 @@
+/*
+ * Signature stuff.
+ *
+ * ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: secsign.c,v 1.21 2009/09/23 22:51:56 wtc%google.com Exp $ */
+
+#include <stdio.h>
+#include "cryptohi.h"
+#include "sechash.h"
+#include "secder.h"
+#include "keyhi.h"
+#include "secoid.h"
+#include "secdig.h"
+#include "pk11func.h"
+#include "secerr.h"
+#include "keyi.h"
+
+struct SGNContextStr {
+    SECOidTag signalg;
+    SECOidTag hashalg;
+    void *hashcx;
+    const SECHashObject *hashobj;
+    SECKEYPrivateKey *key;
+};
+
+SGNContext *
+SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key)
+{
+    SGNContext *cx;
+    SECOidTag hashalg, signalg;
+    KeyType keyType;
+    SECStatus rv;
+
+    /* OK, map a PKCS #7 hash and encrypt algorithm into
+     * a standard hashing algorithm. Why did we pass in the whole
+     * PKCS #7 algTag if we were just going to change here you might
+     * ask. Well the answer is for some cards we may have to do the
+     * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
+     * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5.
+     */
+    /* we have a private key, not a public key, so don't pass it in */
+    rv =  sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg);
+    if (rv != SECSuccess) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return 0;
+    }
+    keyType = seckey_GetKeyType(signalg);
+
+    /* verify our key type */
+    if (key->keyType != keyType &&
+	!((key->keyType == dsaKey) && (keyType == fortezzaKey)) &&
+	!((key->keyType == fortezzaKey) && (keyType == dsaKey)) ) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return 0;
+    }
+
+#ifndef NSS_ECC_MORE_THAN_SUITE_B
+    if (key->keyType == ecKey) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return 0;
+    }
+#endif
+
+    cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext));
+    if (cx) {
+	cx->hashalg = hashalg;
+	cx->signalg = signalg;
+	cx->key = key;
+    }
+    return cx;
+}
+
+void
+SGN_DestroyContext(SGNContext *cx, PRBool freeit)
+{
+    if (cx) {
+	if (cx->hashcx != NULL) {
+	    (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
+	    cx->hashcx = NULL;
+	}
+	if (freeit) {
+	    PORT_ZFree(cx, sizeof(SGNContext));
+	}
+    }
+}
+
+SECStatus
+SGN_Begin(SGNContext *cx)
+{
+    if (cx->hashcx != NULL) {
+	(*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
+	cx->hashcx = NULL;
+    }
+
+    cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg);
+    if (!cx->hashobj)
+	return SECFailure;	/* error code is already set */
+
+    cx->hashcx = (*cx->hashobj->create)();
+    if (cx->hashcx == NULL)
+	return SECFailure;
+
+    (*cx->hashobj->begin)(cx->hashcx);
+    return SECSuccess;
+}
+
+SECStatus
+SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen)
+{
+    if (cx->hashcx == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    (*cx->hashobj->update)(cx->hashcx, input, inputLen);
+    return SECSuccess;
+}
+
+/* XXX Old template; want to expunge it eventually. */
+static DERTemplate SECAlgorithmIDTemplate[] = {
+    { DER_SEQUENCE,
+	  0, NULL, sizeof(SECAlgorithmID) },
+    { DER_OBJECT_ID,
+	  offsetof(SECAlgorithmID,algorithm), },
+    { DER_OPTIONAL | DER_ANY,
+	  offsetof(SECAlgorithmID,parameters), },
+    { 0, }
+};
+
+/*
+ * XXX OLD Template.  Once all uses have been switched over to new one,
+ * remove this.
+ */
+static DERTemplate SGNDigestInfoTemplate[] = {
+    { DER_SEQUENCE,
+	  0, NULL, sizeof(SGNDigestInfo) },
+    { DER_INLINE,
+	  offsetof(SGNDigestInfo,digestAlgorithm),
+	  SECAlgorithmIDTemplate, },
+    { DER_OCTET_STRING,
+	  offsetof(SGNDigestInfo,digest), },
+    { 0, }
+};
+
+SECStatus
+SGN_End(SGNContext *cx, SECItem *result)
+{
+    unsigned char digest[HASH_LENGTH_MAX];
+    unsigned part1;
+    int signatureLen;
+    SECStatus rv;
+    SECItem digder, sigitem;
+    PRArenaPool *arena = 0;
+    SECKEYPrivateKey *privKey = cx->key;
+    SGNDigestInfo *di = 0;
+
+    result->data = 0;
+    digder.data = 0;
+
+    /* Finish up digest function */
+    if (cx->hashcx == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest));
+
+
+    if (privKey->keyType == rsaKey) {
+
+	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+	if ( !arena ) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+    
+	/* Construct digest info */
+	di = SGN_CreateDigestInfo(cx->hashalg, digest, part1);
+	if (!di) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+
+	/* Der encode the digest as a DigestInfo */
+        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
+                        di);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+    } else {
+	digder.data = digest;
+	digder.len = part1;
+    }
+
+    /*
+    ** Encrypt signature after constructing appropriate PKCS#1 signature
+    ** block
+    */
+    signatureLen = PK11_SignatureLen(privKey);
+    if (signatureLen <= 0) {
+	PORT_SetError(SEC_ERROR_INVALID_KEY);
+	rv = SECFailure;
+	goto loser;
+    }
+    sigitem.len = signatureLen;
+    sigitem.data = (unsigned char*) PORT_Alloc(signatureLen);
+
+    if (sigitem.data == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = PK11_Sign(privKey, &sigitem, &digder);
+    if (rv != SECSuccess) {
+	PORT_Free(sigitem.data);
+	sigitem.data = NULL;
+	goto loser;
+    }
+
+    if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) ||
+        (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) {
+        /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */
+	rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); 
+	PORT_Free(sigitem.data);
+	if (rv != SECSuccess)
+	    goto loser;
+    } else {
+	result->len = sigitem.len;
+	result->data = sigitem.data;
+    }
+
+  loser:
+    SGN_DestroyDigestInfo(di);
+    if (arena != NULL) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return rv;
+}
+
+/************************************************************************/
+
+/*
+** Sign a block of data returning in result a bunch of bytes that are the
+** signature. Returns zero on success, an error code on failure.
+*/
+SECStatus
+SEC_SignData(SECItem *res, unsigned char *buf, int len,
+	     SECKEYPrivateKey *pk, SECOidTag algid)
+{
+    SECStatus rv;
+    SGNContext *sgn;
+
+
+    sgn = SGN_NewContext(algid, pk);
+
+    if (sgn == NULL)
+	return SECFailure;
+
+    rv = SGN_Begin(sgn);
+    if (rv != SECSuccess)
+	goto loser;
+
+    rv = SGN_Update(sgn, buf, len);
+    if (rv != SECSuccess)
+	goto loser;
+
+    rv = SGN_End(sgn, res);
+
+  loser:
+    SGN_DestroyContext(sgn, PR_TRUE);
+    return rv;
+}
+
+/************************************************************************/
+    
+DERTemplate CERTSignedDataTemplate[] =
+{
+    { DER_SEQUENCE,
+	  0, NULL, sizeof(CERTSignedData) },
+    { DER_ANY,
+	  offsetof(CERTSignedData,data), },
+    { DER_INLINE,
+	  offsetof(CERTSignedData,signatureAlgorithm),
+	  SECAlgorithmIDTemplate, },
+    { DER_BIT_STRING,
+	  offsetof(CERTSignedData,signature), },
+    { 0, }
+};
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+const SEC_ASN1Template CERT_SignedDataTemplate[] =
+{
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(CERTSignedData) },
+    { SEC_ASN1_ANY,
+	  offsetof(CERTSignedData,data), },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(CERTSignedData,signatureAlgorithm),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), },
+    { SEC_ASN1_BIT_STRING,
+	  offsetof(CERTSignedData,signature), },
+    { 0, }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate)
+
+
+SECStatus
+SEC_DerSignData(PRArenaPool *arena, SECItem *result, 
+	unsigned char *buf, int len, SECKEYPrivateKey *pk, SECOidTag algID)
+{
+    SECItem it;
+    CERTSignedData sd;
+    SECStatus rv;
+
+    it.data = 0;
+
+    /* XXX We should probably have some asserts here to make sure the key type
+     * and algID match
+     */
+
+    if (algID == SEC_OID_UNKNOWN) {
+	switch(pk->keyType) {
+	  case rsaKey:
+	    algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+	    break;
+	  case dsaKey:
+	    algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
+	    break;
+	  case ecKey:
+	    algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
+	    break;
+	  default:
+	    PORT_SetError(SEC_ERROR_INVALID_KEY);
+	    return SECFailure;
+	}
+    }
+
+    /* Sign input buffer */
+    rv = SEC_SignData(&it, buf, len, pk, algID);
+    if (rv) goto loser;
+
+    /* Fill out SignedData object */
+    PORT_Memset(&sd, 0, sizeof(sd));
+    sd.data.data = buf;
+    sd.data.len = len;
+    sd.signature.data = it.data;
+    sd.signature.len = it.len << 3;		/* convert to bit string */
+    rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
+    if (rv) goto loser;
+
+    /* DER encode the signed data object */
+    rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
+    /* FALL THROUGH */
+
+  loser:
+    PORT_Free(it.data);
+    return rv;
+}
+
+SECStatus
+SGN_Digest(SECKEYPrivateKey *privKey,
+		SECOidTag algtag, SECItem *result, SECItem *digest)
+{
+    int modulusLen;
+    SECStatus rv;
+    SECItem digder;
+    PRArenaPool *arena = 0;
+    SGNDigestInfo *di = 0;
+
+
+    result->data = 0;
+
+    if (privKey->keyType == rsaKey) {
+
+	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+	if ( !arena ) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+    
+	/* Construct digest info */
+	di = SGN_CreateDigestInfo(algtag, digest->data, digest->len);
+	if (!di) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+
+	/* Der encode the digest as a DigestInfo */
+        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
+                        di);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+    } else {
+	digder.data = digest->data;
+	digder.len = digest->len;
+    }
+
+    /*
+    ** Encrypt signature after constructing appropriate PKCS#1 signature
+    ** block
+    */
+    modulusLen = PK11_SignatureLen(privKey);
+    if (modulusLen <= 0) {
+	PORT_SetError(SEC_ERROR_INVALID_KEY);
+	rv = SECFailure;
+	goto loser;
+    }
+    result->len = modulusLen;
+    result->data = (unsigned char*) PORT_Alloc(modulusLen);
+
+    if (result->data == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = PK11_Sign(privKey, result, &digder);
+    if (rv != SECSuccess) {
+	PORT_Free(result->data);
+	result->data = NULL;
+    }
+
+  loser:
+    SGN_DestroyDigestInfo(di);
+    if (arena != NULL) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return rv;
+}
+
+SECOidTag
+SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag)
+{
+    SECOidTag sigTag = SEC_OID_UNKNOWN;
+
+    switch (keyType) {
+    case rsaKey:
+	switch (hashAlgTag) {
+	case SEC_OID_MD2:
+	    sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;	break;
+	case SEC_OID_MD5:
+	    sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;	break;
+	case SEC_OID_UNKNOWN:	/* default for RSA if not specified */
+	case SEC_OID_SHA1:
+	    sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;	break;
+	case SEC_OID_SHA256:
+	    sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;	break;
+	case SEC_OID_SHA384:
+	    sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;	break;
+	case SEC_OID_SHA512:
+	    sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;	break;
+	default:
+	    break;
+	}
+	break;
+    case dsaKey:
+	switch (hashAlgTag) {
+	case SEC_OID_UNKNOWN:	/* default for DSA if not specified */
+	case SEC_OID_SHA1:
+	    sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break;
+	default:
+	    break;
+	}
+	break;
+    case ecKey:
+	switch (hashAlgTag) {
+	case SEC_OID_UNKNOWN:	/* default for ECDSA if not specified */
+	case SEC_OID_SHA1:
+            sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break;
+	case SEC_OID_SHA256:
+            sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break;
+	case SEC_OID_SHA384:
+            sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break;
+	case SEC_OID_SHA512:
+            sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break;
+	default:
+	break;
+	}
+    default:
+    	break;
+    }
+    return sigTag;
+}
diff --git a/mozilla/security/nss/lib/cryptohi/secvfy.c b/mozilla/security/nss/lib/cryptohi/secvfy.c
new file mode 100644
index 0000000..fd1ffb7
--- /dev/null
+++ b/mozilla/security/nss/lib/cryptohi/secvfy.c
@@ -0,0 +1,750 @@
+/*
+ * Verification stuff.
+ *
+ * ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: secvfy.c,v 1.22 2008/02/28 04:27:36 nelson%bolyard.com Exp $ */
+
+#include <stdio.h>
+#include "cryptohi.h"
+#include "sechash.h"
+#include "keyhi.h"
+#include "secasn1.h"
+#include "secoid.h"
+#include "pk11func.h"
+#include "secdig.h"
+#include "secerr.h"
+#include "keyi.h"
+
+/*
+** Decrypt signature block using public key
+** Store the hash algorithm oid tag in *tagp
+** Store the digest in the digest buffer
+** Store the digest length in *digestlen
+** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION
+*/
+static SECStatus
+DecryptSigBlock(SECOidTag *tagp, unsigned char *digest,
+		unsigned int *digestlen, unsigned int maxdigestlen,
+		SECKEYPublicKey *key, const SECItem *sig, char *wincx)
+{
+    SGNDigestInfo *di   = NULL;
+    unsigned char *buf  = NULL;
+    SECStatus      rv;
+    SECOidTag      tag;
+    SECItem        it;
+
+    if (key == NULL) goto loser;
+
+    it.len  = SECKEY_PublicKeyStrength(key);
+    if (!it.len) goto loser;
+    it.data = buf = (unsigned char *)PORT_Alloc(it.len);
+    if (!buf) goto loser;
+
+    /* decrypt the block */
+    rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx);
+    if (rv != SECSuccess) goto loser;
+
+    di = SGN_DecodeDigestInfo(&it);
+    if (di == NULL) goto sigloser;
+
+    /*
+    ** Finally we have the digest info; now we can extract the algorithm
+    ** ID and the signature block
+    */
+    tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
+    /* Check that tag is an appropriate algorithm */
+    if (tag == SEC_OID_UNKNOWN) {
+	goto sigloser;
+    }
+    /* make sure the "parameters" are not too bogus. */
+    if (di->digestAlgorithm.parameters.len > 2) {
+	goto sigloser;
+    }
+    if (di->digest.len > maxdigestlen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	goto loser;
+    }
+    PORT_Memcpy(digest, di->digest.data, di->digest.len);
+    *tagp = tag;
+    *digestlen = di->digest.len;
+    goto done;
+
+  sigloser:
+    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+
+  loser:
+    rv = SECFailure;
+
+  done:
+    if (di   != NULL) SGN_DestroyDigestInfo(di);
+    if (buf  != NULL) PORT_Free(buf);
+    
+    return rv;
+}
+
+
+struct VFYContextStr {
+    SECOidTag hashAlg;  /* the hash algorithm */
+    SECKEYPublicKey *key;
+    /*
+     * This buffer holds either the digest or the full signature
+     * depending on the type of the signature (key->keyType).  It is
+     * defined as a union to make sure it always has enough space.
+     *
+     * Use the "buffer" union member to reference the buffer.
+     * Note: do not take the size of the "buffer" union member.  Take
+     * the size of the union or some other union member instead.
+     */
+    union {
+	unsigned char buffer[1];
+
+	/* the digest in the decrypted RSA signature */
+	unsigned char rsadigest[HASH_LENGTH_MAX];
+	/* the full DSA signature... 40 bytes */
+	unsigned char dsasig[DSA_SIGNATURE_LEN];
+	/* the full ECDSA signature */
+	unsigned char ecdsasig[2 * MAX_ECKEY_LEN];
+    } u;
+    unsigned int rsadigestlen;
+    void * wincx;
+    void *hashcx;
+    const SECHashObject *hashobj;
+    SECOidTag encAlg;  /* enc alg */
+    PRBool hasSignature;  /* true if the signature was provided in the
+                           * VFY_CreateContext call.  If false, the
+                           * signature must be provided with a
+                           * VFY_EndWithSignature call. */
+};
+
+/*
+ * decode the ECDSA or DSA signature from it's DER wrapping.
+ * The unwrapped/raw signature is placed in the buffer pointed
+ * to by dsig and has enough room for len bytes.
+ */
+static SECStatus
+decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig,
+		       unsigned int len) {
+    SECItem *dsasig = NULL; /* also used for ECDSA */
+    SECStatus rv=SECSuccess;
+
+    if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
+	(algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) {
+        if (sig->len != len) {
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return SECFailure;
+	} 
+
+	PORT_Memcpy(dsig, sig->data, sig->len);
+	return SECSuccess;
+    }
+
+    if (algid ==  SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
+	if (len > MAX_ECKEY_LEN * 2) {
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return SECFailure;
+	}
+    }
+    dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len);
+
+    if ((dsasig == NULL) || (dsasig->len != len)) {
+	rv = SECFailure;
+    } else {
+	PORT_Memcpy(dsig, dsasig->data, dsasig->len);
+    }
+
+    if (dsasig != NULL) SECITEM_FreeItem(dsasig, PR_TRUE);
+    if (rv == SECFailure) PORT_SetError(SEC_ERROR_BAD_DER);
+    return rv;
+}
+
+const SEC_ASN1Template hashParameterTemplate[] =
+{
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
+    { SEC_ASN1_OBJECT_ID, 0 },
+    { SEC_ASN1_SKIP_REST },
+    { 0, }
+};
+
+/*
+ * Pulls the hash algorithm, signing algorithm, and key type out of a
+ * composite algorithm.
+ *
+ * sigAlg: the composite algorithm to dissect.
+ * hashalg: address of a SECOidTag which will be set with the hash algorithm.
+ * encalg: address of a SECOidTag which will be set with the signing alg.
+ *
+ * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the
+ *	algorithm was not found or was not a signing algorithm.
+ */
+SECStatus
+sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, 
+             const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg)
+{
+    int len;
+    PRArenaPool *arena;
+    SECStatus rv;
+    SECItem oid;
+
+    PR_ASSERT(hashalg!=NULL);
+    PR_ASSERT(encalg!=NULL);
+
+    switch (sigAlg) {
+      /* We probably shouldn't be generating MD2 signatures either */
+      case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
+        *hashalg = SEC_OID_MD2;
+	break;
+      case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
+        *hashalg = SEC_OID_MD5;
+	break;
+      case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
+      case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
+      case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
+        *hashalg = SEC_OID_SHA1;
+	break;
+      case SEC_OID_PKCS1_RSA_ENCRYPTION:
+        *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */
+	break;
+
+      case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
+      case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
+	*hashalg = SEC_OID_SHA256;
+	break;
+      case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
+      case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
+	*hashalg = SEC_OID_SHA384;
+	break;
+      case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
+      case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
+	*hashalg = SEC_OID_SHA512;
+	break;
+
+      /* what about normal DSA? */
+      case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
+      case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
+      case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
+        *hashalg = SEC_OID_SHA1;
+	break;
+      case SEC_OID_MISSI_DSS:
+      case SEC_OID_MISSI_KEA_DSS:
+      case SEC_OID_MISSI_KEA_DSS_OLD:
+      case SEC_OID_MISSI_DSS_OLD:
+        *hashalg = SEC_OID_SHA1;
+	break;
+      case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
+	/* This is an EC algorithm. Recommended means the largest
+	 * hash algorithm that is not reduced by the keysize of 
+	 * the EC algorithm. Note that key strength is in bytes and
+	 * algorithms are specified in bits. Never use an algorithm
+	 * weaker than sha1. */
+	len = SECKEY_PublicKeyStrength(key);
+	if (len < 28) { /* 28 bytes == 224 bits */
+	    *hashalg = SEC_OID_SHA1;
+	} else if (len < 32) { /* 32 bytes == 256 bits */
+	    /* SHA 224 not supported in NSS */
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    return SECFailure;
+	} else if (len < 48) { /* 48 bytes == 384 bits */
+	    *hashalg = SEC_OID_SHA256;
+	} else if (len < 64) { /* 48 bytes == 512 bits */
+	    *hashalg = SEC_OID_SHA384;
+	} else {
+	    /* use the largest in this case */
+	    *hashalg = SEC_OID_SHA512;
+	}
+	break;
+      case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
+	if (param == NULL) {
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    return SECFailure;
+	}
+	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+	if (arena == NULL) {
+	    return SECFailure;
+	}
+	rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param);
+	if (rv != SECSuccess) {
+	    PORT_FreeArena(arena, PR_FALSE);
+	    return rv;
+	}
+	*hashalg = SECOID_FindOIDTag(&oid);
+	/* only accept hash algorithms */
+	if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
+	    /* error set by HASH_GetHashTypeByOidTag */
+	    return SECFailure;
+	}
+	break;
+      /* we don't implement MD4 hashes */
+      case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
+      default:
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return SECFailure;
+    }
+    /* get the "encryption" algorithm */ 
+    switch (sigAlg) {
+      case SEC_OID_PKCS1_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
+      case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
+      case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
+      case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
+	*encalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
+	break;
+
+      /* what about normal DSA? */
+      case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
+      case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
+	*encalg = SEC_OID_ANSIX9_DSA_SIGNATURE;
+	break;
+      case SEC_OID_MISSI_DSS:
+      case SEC_OID_MISSI_KEA_DSS:
+      case SEC_OID_MISSI_KEA_DSS_OLD:
+      case SEC_OID_MISSI_DSS_OLD:
+	*encalg = SEC_OID_MISSI_DSS;
+	break;
+      case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
+      case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
+      case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
+      case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
+      case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
+      case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
+	*encalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+	break;
+      /* we don't implement MD4 hashes */
+      case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
+      default:
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * we can verify signatures that come from 2 different sources:
+ *  one in with the signature contains a signature oid, and the other
+ *  in which the signature is managed by a Public key (encAlg) oid
+ *  and a hash oid. The latter is the more basic, so that's what
+ *  our base vfyCreate function takes.
+ *
+ * There is one noteworthy corner case, if we are using an RSA key, and the
+ * signature block is provided, then the hashAlg can be specified as 
+ * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied
+ * in the RSA signature block.
+ */
+static VFYContext *
+vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, 
+	SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx)
+{
+    VFYContext *cx;
+    SECStatus rv;
+    unsigned int sigLen;
+    KeyType type;
+
+    /* make sure the encryption algorithm matches the key type */
+    type = seckey_GetKeyType(encAlg);
+    if (key->keyType != type) {
+	PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH);
+	return NULL;
+    }
+
+    cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext));
+    if (cx == NULL) {
+	goto loser;
+    }
+
+    cx->wincx = wincx;
+    cx->hasSignature = (sig != NULL);
+    cx->encAlg = encAlg;
+    cx->hashAlg = hashAlg;
+    cx->key = SECKEY_CopyPublicKey(key);
+    rv = SECSuccess;
+    if (sig) {
+	switch (key->keyType) {
+	case rsaKey:
+	    rv = DecryptSigBlock(&cx->hashAlg, cx->u.buffer, &cx->rsadigestlen,
+			HASH_LENGTH_MAX, cx->key, sig, (char*)wincx);
+	    if (cx->hashAlg != hashAlg && hashAlg != SEC_OID_UNKNOWN) {
+		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+		rv = SECFailure;	
+	    }
+	    break;
+	case dsaKey:
+	case ecKey:
+	    sigLen = SECKEY_SignatureLen(key);
+	    if (sigLen == 0) {
+		/* error set by SECKEY_SignatureLen */
+		rv = SECFailure;	
+		break;
+	    }
+	    rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen);
+ 	    break;
+	default:
+	    rv = SECFailure;
+	    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+	    break;
+	}
+    }
+
+    if (rv) goto loser;
+
+    /* check hash alg again, RSA may have changed it.*/
+    if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) {
+	/* error set by HASH_GetHashTypeByOidTag */
+	goto loser;
+    }
+
+    if (hash) {
+	*hash = cx->hashAlg;
+    }
+    return cx;
+
+  loser:
+    if (cx) {
+	VFY_DestroyContext(cx, PR_TRUE);
+    }
+    return 0;
+}
+
+VFYContext *
+VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg,
+		  void *wincx)
+{
+    SECOidTag encAlg, hashAlg;
+    SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg);
+    if (rv != SECSuccess) {
+	return NULL;
+    }
+    return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
+}
+
+VFYContext *
+VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig, 
+			SECOidTag encAlg, SECOidTag hashAlg, 
+			SECOidTag *hash, void *wincx)
+{
+  return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
+}
+
+VFYContext *
+VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig,
+	      const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx)
+{
+    SECOidTag encAlg, hashAlg;
+    SECStatus rv = sec_DecodeSigAlg(key, 
+		    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), 
+		    &sigAlgorithm->parameters, &encAlg, &hashAlg);
+    if (rv != SECSuccess) {
+	return NULL;
+    }
+    return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
+}
+
+void
+VFY_DestroyContext(VFYContext *cx, PRBool freeit)
+{
+    if (cx) {
+	if (cx->hashcx != NULL) {
+	    (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
+	    cx->hashcx = NULL;
+	}
+	if (cx->key) {
+	    SECKEY_DestroyPublicKey(cx->key);
+	}
+	if (freeit) {
+	    PORT_ZFree(cx, sizeof(VFYContext));
+	}
+    }
+}
+
+SECStatus
+VFY_Begin(VFYContext *cx)
+{
+    if (cx->hashcx != NULL) {
+	(*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
+	cx->hashcx = NULL;
+    }
+
+    cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg);
+    if (!cx->hashobj) 
+	return SECFailure;	/* error code is set */
+
+    cx->hashcx = (*cx->hashobj->create)();
+    if (cx->hashcx == NULL)
+	return SECFailure;
+
+    (*cx->hashobj->begin)(cx->hashcx);
+    return SECSuccess;
+}
+
+SECStatus
+VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen)
+{
+    if (cx->hashcx == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    (*cx->hashobj->update)(cx->hashcx, input, inputLen);
+    return SECSuccess;
+}
+
+SECStatus
+VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
+{
+    unsigned char final[HASH_LENGTH_MAX];
+    unsigned part;
+    SECItem hash,dsasig; /* dsasig is also used for ECDSA */
+    SECStatus rv;
+
+    if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    if (cx->hashcx == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final));
+    switch (cx->key->keyType) {
+      case ecKey:
+      case dsaKey:
+	dsasig.data = cx->u.buffer;
+	dsasig.len = SECKEY_SignatureLen(cx->key);
+	if (dsasig.len == 0) {
+	    return SECFailure;
+	} 
+	if (sig) {
+	    rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data,
+					dsasig.len);
+	    if (rv != SECSuccess) {
+		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+		return SECFailure;
+	    }
+	} 
+	hash.data = final;
+	hash.len = part;
+	if (PK11_Verify(cx->key,&dsasig,&hash,cx->wincx) != SECSuccess) {
+		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+		return SECFailure;
+	}
+	break;
+      case rsaKey:
+	if (sig) {
+	    SECOidTag hashid = SEC_OID_UNKNOWN;
+	    rv = DecryptSigBlock(&hashid, cx->u.buffer, &cx->rsadigestlen,
+		    HASH_LENGTH_MAX, cx->key, sig, (char*)cx->wincx);
+	    if ((rv != SECSuccess) || (hashid != cx->hashAlg)) {
+		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+		return SECFailure;
+	    }
+	}
+	if ((part != cx->rsadigestlen) ||
+	    PORT_Memcmp(final, cx->u.buffer, part)) {
+	    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	    return SECFailure;
+	}
+	break;
+      default:
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	return SECFailure; /* shouldn't happen */
+    }
+    return SECSuccess;
+}
+
+SECStatus
+VFY_End(VFYContext *cx)
+{
+    return VFY_EndWithSignature(cx,NULL);
+}
+
+/************************************************************************/
+/*
+ * Verify that a previously-computed digest matches a signature.
+ */
+static SECStatus
+vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, 
+		 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
+		 void *wincx)
+{
+    SECStatus rv;
+    VFYContext *cx;
+    SECItem dsasig; /* also used for ECDSA */
+
+    rv = SECFailure;
+
+    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
+    if (cx != NULL) {
+	switch (key->keyType) {
+	case rsaKey:
+	    if ((digest->len != cx->rsadigestlen) ||
+		PORT_Memcmp(digest->data, cx->u.buffer, digest->len)) {
+		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	    } else {
+		rv = SECSuccess;
+	    }
+	    break;
+	case dsaKey:
+	case ecKey:
+	    dsasig.data = cx->u.buffer;
+	    dsasig.len = SECKEY_SignatureLen(cx->key);
+	    if (dsasig.len == 0) {
+		break;
+	    }
+	    if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx)
+		!= SECSuccess) {
+		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	    } else {
+		rv = SECSuccess;
+	    }
+	    break;
+	default:
+	    break;
+	}
+	VFY_DestroyContext(cx, PR_TRUE);
+    }
+    return rv;
+}
+
+SECStatus
+VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key, 
+		       const SECItem *sig, SECOidTag encAlg, 
+		       SECOidTag hashAlg, void *wincx)
+{
+    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
+}
+
+SECStatus
+VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig,
+		 SECOidTag algid, void *wincx)
+{
+    SECOidTag encAlg, hashAlg;
+    SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
+    if (rv != SECSuccess) {
+	return SECFailure;
+    }
+    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
+}
+
+/*
+ * this function takes an optional hash oid, which the digest function
+ * will be compared with our target hash value.
+ */
+SECStatus
+VFY_VerifyDigestWithAlgorithmID(const SECItem *digest, 
+		const SECKEYPublicKey *key, const SECItem *sig, 
+		const SECAlgorithmID *sigAlgorithm, 
+		SECOidTag hashCmp, void *wincx)
+{
+    SECOidTag encAlg, hashAlg;
+    SECStatus rv = sec_DecodeSigAlg(key, 
+		    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), 
+		    &sigAlgorithm->parameters, &encAlg, &hashAlg);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    if ( hashCmp != SEC_OID_UNKNOWN && 
+	 hashAlg != SEC_OID_UNKNOWN &&
+	 hashCmp != hashAlg) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	return SECFailure;
+    }
+    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
+}
+
+static SECStatus
+vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
+	       const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
+	       SECOidTag *hash, void *wincx)
+{
+    SECStatus rv;
+    VFYContext *cx;
+
+    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
+    if (cx == NULL)
+	return SECFailure;
+
+    rv = VFY_Begin(cx);
+    if (rv == SECSuccess) {
+	rv = VFY_Update(cx, (unsigned char *)buf, len);
+	if (rv == SECSuccess)
+	    rv = VFY_End(cx);
+    }
+
+    VFY_DestroyContext(cx, PR_TRUE);
+    return rv;
+}
+
+SECStatus
+VFY_VerifyDataDirect(const unsigned char *buf, int len, 
+		     const SECKEYPublicKey *key, const SECItem *sig,
+		     SECOidTag encAlg, SECOidTag hashAlg,
+		     SECOidTag *hash, void *wincx)
+{
+    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx);
+}
+
+SECStatus
+VFY_VerifyData(unsigned char *buf, int len, SECKEYPublicKey *key,
+	       SECItem *sig, SECOidTag algid, void *wincx)
+{
+    SECOidTag encAlg, hashAlg;
+    SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, wincx);
+}
+
+SECStatus
+VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, 
+			      const SECKEYPublicKey *key,
+			      const SECItem *sig, 
+			      const SECAlgorithmID *sigAlgorithm, 
+			      SECOidTag *hash, void *wincx)
+{
+    SECOidTag encAlg, hashAlg;
+    SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm);
+    SECStatus rv     = sec_DecodeSigAlg(key, sigAlg, 
+		                &sigAlgorithm->parameters, &encAlg, &hashAlg);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx);
+}
diff --git a/mozilla/security/nss/lib/dev/ckhelper.c b/mozilla/security/nss/lib/dev/ckhelper.c
new file mode 100644
index 0000000..24d10bc
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/ckhelper.c
@@ -0,0 +1,618 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: ckhelper.c,v $ $Revision: 1.40 $ $Date: 2010/01/08 02:00:58 $";
+#endif /* DEBUG */
+
+#include "pkcs11.h"
+
+#ifndef DEVM_H
+#include "devm.h"
+#endif /* DEVM_H */
+
+#ifndef CKHELPER_H
+#include "ckhelper.h"
+#endif /* CKHELPER_H */
+
+extern const NSSError NSS_ERROR_DEVICE_ERROR;
+
+static const CK_BBOOL s_true = CK_TRUE;
+NSS_IMPLEMENT_DATA const NSSItem
+g_ck_true = { (CK_VOID_PTR)&s_true, sizeof(s_true) };
+
+static const CK_BBOOL s_false = CK_FALSE;
+NSS_IMPLEMENT_DATA const NSSItem
+g_ck_false = { (CK_VOID_PTR)&s_false, sizeof(s_false) };
+
+static const CK_OBJECT_CLASS s_class_cert = CKO_CERTIFICATE;
+NSS_IMPLEMENT_DATA const NSSItem
+g_ck_class_cert = { (CK_VOID_PTR)&s_class_cert, sizeof(s_class_cert) };
+
+static const CK_OBJECT_CLASS s_class_pubkey = CKO_PUBLIC_KEY;
+NSS_IMPLEMENT_DATA const NSSItem
+g_ck_class_pubkey = { (CK_VOID_PTR)&s_class_pubkey, sizeof(s_class_pubkey) };
+
+static const CK_OBJECT_CLASS s_class_privkey = CKO_PRIVATE_KEY;
+NSS_IMPLEMENT_DATA const NSSItem
+g_ck_class_privkey = { (CK_VOID_PTR)&s_class_privkey, sizeof(s_class_privkey) };
+
+static PRBool
+is_string_attribute (
+  CK_ATTRIBUTE_TYPE aType
+)
+{
+    PRBool isString;
+    switch (aType) {
+    case CKA_LABEL:
+    case CKA_NETSCAPE_EMAIL:
+	isString = PR_TRUE;
+	break;
+    default:
+	isString = PR_FALSE;
+	break;
+    }
+    return isString;
+}
+
+NSS_IMPLEMENT PRStatus 
+nssCKObject_GetAttributes (
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG count,
+  NSSArena *arenaOpt,
+  nssSession *session,
+  NSSSlot *slot
+)
+{
+    nssArenaMark *mark = NULL;
+    CK_SESSION_HANDLE hSession;
+    CK_ULONG i = 0;
+    CK_RV ckrv;
+    PRStatus nssrv;
+    PRBool alloced = PR_FALSE;
+    void *epv = nssSlot_GetCryptokiEPV(slot);
+    hSession = session->handle; 
+    if (arenaOpt) {
+	mark = nssArena_Mark(arenaOpt);
+	if (!mark) {
+	    goto loser;
+	}
+    }
+    nssSession_EnterMonitor(session);
+    /* XXX kinda hacky, if the storage size is already in the first template
+     * item, then skip the alloc portion
+     */
+    if (obj_template[0].ulValueLen == 0) {
+	/* Get the storage size needed for each attribute */
+	ckrv = CKAPI(epv)->C_GetAttributeValue(hSession,
+	                                       object, obj_template, count);
+	if (ckrv != CKR_OK && 
+	    ckrv != CKR_ATTRIBUTE_TYPE_INVALID &&
+	    ckrv != CKR_ATTRIBUTE_SENSITIVE) 
+	{
+	    nssSession_ExitMonitor(session);
+	    nss_SetError(NSS_ERROR_DEVICE_ERROR);
+	    goto loser;
+	}
+	/* Allocate memory for each attribute. */
+	for (i=0; i<count; i++) {
+	    CK_ULONG ulValueLen = obj_template[i].ulValueLen;
+	    if (ulValueLen == 0 || ulValueLen == (CK_ULONG) -1) {
+		obj_template[i].pValue = NULL;
+		obj_template[i].ulValueLen = 0;
+		continue;
+	    }
+	    if (is_string_attribute(obj_template[i].type)) {
+		ulValueLen++;
+	    }
+	    obj_template[i].pValue = nss_ZAlloc(arenaOpt, ulValueLen);
+	    if (!obj_template[i].pValue) {
+		nssSession_ExitMonitor(session);
+		goto loser;
+	    }
+	}
+	alloced = PR_TRUE;
+    }
+    /* Obtain the actual attribute values. */
+    ckrv = CKAPI(epv)->C_GetAttributeValue(hSession,
+                                           object, obj_template, count);
+    nssSession_ExitMonitor(session);
+    if (ckrv != CKR_OK && 
+        ckrv != CKR_ATTRIBUTE_TYPE_INVALID &&
+        ckrv != CKR_ATTRIBUTE_SENSITIVE) 
+    {
+	nss_SetError(NSS_ERROR_DEVICE_ERROR);
+	goto loser;
+    }
+    if (alloced && arenaOpt) {
+	nssrv = nssArena_Unmark(arenaOpt, mark);
+	if (nssrv != PR_SUCCESS) {
+	    goto loser;
+	}
+    }
+
+    if (count > 1 && ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) || 
+					(ckrv == CKR_ATTRIBUTE_SENSITIVE))) {
+	/* old tokens would keep the length of '0' and not deal with any
+	 * of the attributes we passed. For those tokens read them one at
+	 * a time */
+	for (i=0; i < count; i++) {
+	    if ((obj_template[i].ulValueLen == 0) 
+				|| (obj_template[i].ulValueLen == -1)) {
+		obj_template[i].ulValueLen=0;
+		(void) nssCKObject_GetAttributes(object,&obj_template[i], 1,
+			arenaOpt, session, slot);
+	    }
+	}
+    }
+    return PR_SUCCESS;
+loser:
+    if (alloced) {
+	if (arenaOpt) {
+	    /* release all arena memory allocated before the failure. */
+	    (void)nssArena_Release(arenaOpt, mark);
+	} else {
+	    CK_ULONG j;
+	    /* free each heap object that was allocated before the failure. */
+	    for (j=0; j<i; j++) {
+		nss_ZFreeIf(obj_template[j].pValue);
+	    }
+	}
+    }
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCKObject_GetAttributeItem (
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_TYPE attribute,
+  NSSArena *arenaOpt,
+  nssSession *session,
+  NSSSlot *slot,
+  NSSItem *rvItem
+)
+{
+    CK_ATTRIBUTE attr = { 0, NULL, 0 };
+    PRStatus nssrv;
+    attr.type = attribute;
+    nssrv = nssCKObject_GetAttributes(object, &attr, 1, 
+                                      arenaOpt, session, slot);
+    if (nssrv != PR_SUCCESS) {
+	return nssrv;
+    }
+    rvItem->data = (void *)attr.pValue;
+    rvItem->size = (PRUint32)attr.ulValueLen;
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRBool
+nssCKObject_IsAttributeTrue (
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_TYPE attribute,
+  nssSession *session,
+  NSSSlot *slot,
+  PRStatus *rvStatus
+)
+{
+    CK_BBOOL bool;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE atemplate = { 0, NULL, 0 };
+    CK_RV ckrv;
+    void *epv = nssSlot_GetCryptokiEPV(slot);
+    attr = &atemplate;
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, attribute, bool);
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_GetAttributeValue(session->handle, object, 
+                                           &atemplate, 1);
+    nssSession_ExitMonitor(session);
+    if (ckrv != CKR_OK) {
+	*rvStatus = PR_FAILURE;
+	return PR_FALSE;
+    }
+    *rvStatus = PR_SUCCESS;
+    return (PRBool)(bool == CK_TRUE);
+}
+
+NSS_IMPLEMENT PRStatus 
+nssCKObject_SetAttributes (
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG count,
+  nssSession *session,
+  NSSSlot  *slot
+)
+{
+    CK_RV ckrv;
+    void *epv = nssSlot_GetCryptokiEPV(slot);
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, object, 
+                                           obj_template, count);
+    nssSession_ExitMonitor(session);
+    if (ckrv == CKR_OK) {
+	return PR_SUCCESS;
+    } else {
+	return PR_FAILURE;
+    }
+}
+
+NSS_IMPLEMENT PRBool
+nssCKObject_IsTokenObjectTemplate (
+  CK_ATTRIBUTE_PTR objectTemplate, 
+  CK_ULONG otsize
+)
+{
+    CK_ULONG ul;
+    for (ul=0; ul<otsize; ul++) {
+	if (objectTemplate[ul].type == CKA_TOKEN) {
+	    return (*((CK_BBOOL*)objectTemplate[ul].pValue) == CK_TRUE);
+	}
+    }
+    return PR_FALSE;
+}
+
+static NSSCertificateType
+nss_cert_type_from_ck_attrib(CK_ATTRIBUTE_PTR attrib)
+{
+    CK_CERTIFICATE_TYPE ckCertType;
+    if (!attrib->pValue) {
+	/* default to PKIX */
+	return NSSCertificateType_PKIX;
+    }
+    ckCertType = *((CK_ULONG *)attrib->pValue);
+    switch (ckCertType) {
+    case CKC_X_509:
+	return NSSCertificateType_PKIX;
+    default:
+	break;
+    }
+    return NSSCertificateType_Unknown;
+}
+
+/* incoming pointers must be valid */
+NSS_IMPLEMENT PRStatus
+nssCryptokiCertificate_GetAttributes (
+  nssCryptokiObject *certObject,
+  nssSession *sessionOpt,
+  NSSArena *arenaOpt,
+  NSSCertificateType *certTypeOpt,
+  NSSItem *idOpt,
+  NSSDER *encodingOpt,
+  NSSDER *issuerOpt,
+  NSSDER *serialOpt,
+  NSSDER *subjectOpt
+)
+{
+    PRStatus status;
+    PRUint32 i;
+    nssSession *session;
+    NSSSlot *slot;
+    CK_ULONG template_size;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE cert_template[6];
+    /* Set up a template of all options chosen by caller */
+    NSS_CK_TEMPLATE_START(cert_template, attr, template_size);
+    if (certTypeOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CERTIFICATE_TYPE);
+    }
+    if (idOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ID);
+    }
+    if (encodingOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
+    }
+    if (issuerOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ISSUER);
+    }
+    if (serialOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SERIAL_NUMBER);
+    }
+    if (subjectOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT);
+    }
+    NSS_CK_TEMPLATE_FINISH(cert_template, attr, template_size);
+    if (template_size == 0) {
+	/* caller didn't want anything */
+	return PR_SUCCESS;
+    }
+
+    status = nssToken_GetCachedObjectAttributes(certObject->token, arenaOpt,
+                                                certObject, CKO_CERTIFICATE,
+                                                cert_template, template_size);
+    if (status != PR_SUCCESS) {
+
+	session = sessionOpt ? 
+	          sessionOpt : 
+	          nssToken_GetDefaultSession(certObject->token);
+	if (!session) {
+	    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+	    return PR_FAILURE;
+	}
+
+	slot = nssToken_GetSlot(certObject->token);
+	status = nssCKObject_GetAttributes(certObject->handle, 
+	                                   cert_template, template_size,
+	                                   arenaOpt, session, slot);
+	nssSlot_Destroy(slot);
+	if (status != PR_SUCCESS) {
+	    return status;
+	}
+    }
+
+    i=0;
+    if (certTypeOpt) {
+	*certTypeOpt = nss_cert_type_from_ck_attrib(&cert_template[i]); i++;
+    }
+    if (idOpt) {
+	NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], idOpt); i++;
+    }
+    if (encodingOpt) {
+	NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], encodingOpt); i++;
+    }
+    if (issuerOpt) {
+	NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], issuerOpt); i++;
+    }
+    if (serialOpt) {
+	NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], serialOpt); i++;
+    }
+    if (subjectOpt) {
+	NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], subjectOpt); i++;
+    }
+    return PR_SUCCESS;
+}
+
+static nssTrustLevel 
+get_nss_trust (
+  CK_TRUST ckt
+)
+{
+    nssTrustLevel t;
+    switch (ckt) {
+    case CKT_NETSCAPE_UNTRUSTED: t = nssTrustLevel_NotTrusted; break;
+    case CKT_NETSCAPE_TRUSTED_DELEGATOR: t = nssTrustLevel_TrustedDelegator; 
+	break;
+    case CKT_NETSCAPE_VALID_DELEGATOR: t = nssTrustLevel_ValidDelegator; break;
+    case CKT_NETSCAPE_TRUSTED: t = nssTrustLevel_Trusted; break;
+    case CKT_NETSCAPE_VALID: t = nssTrustLevel_Valid; break;
+    case CKT_NETSCAPE_MUST_VERIFY:
+    case CKT_NETSCAPE_TRUST_UNKNOWN:
+    default:
+	t = nssTrustLevel_Unknown; break;
+    }
+    return t;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCryptokiTrust_GetAttributes (
+  nssCryptokiObject *trustObject,
+  nssSession *sessionOpt,
+  NSSItem *sha1_hash,
+  nssTrustLevel *serverAuth,
+  nssTrustLevel *clientAuth,
+  nssTrustLevel *codeSigning,
+  nssTrustLevel *emailProtection,
+  PRBool *stepUpApproved
+)
+{
+    PRStatus status;
+    NSSSlot *slot;
+    nssSession *session;
+    CK_BBOOL isToken = PR_FALSE;
+    CK_BBOOL stepUp = PR_FALSE;
+    CK_TRUST saTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
+    CK_TRUST caTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
+    CK_TRUST epTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
+    CK_TRUST csTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE trust_template[7];
+    CK_ULONG trust_size;
+
+    /* Use the trust object to find the trust settings */
+    NSS_CK_TEMPLATE_START(trust_template, attr, trust_size);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TOKEN,                  isToken);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      saTrust);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      caTrust);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, epTrust);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     csTrust);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_STEP_UP_APPROVED, stepUp);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH,     sha1_hash);
+    NSS_CK_TEMPLATE_FINISH(trust_template, attr, trust_size);
+
+    status = nssToken_GetCachedObjectAttributes(trustObject->token, NULL,
+                                                trustObject, 
+                                                CKO_NETSCAPE_TRUST,
+                                                trust_template, trust_size);
+    if (status != PR_SUCCESS) {
+	session = sessionOpt ? 
+	          sessionOpt : 
+	          nssToken_GetDefaultSession(trustObject->token);
+	if (!session) {
+	    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+	    return PR_FAILURE;
+	}
+
+	slot = nssToken_GetSlot(trustObject->token);
+	status = nssCKObject_GetAttributes(trustObject->handle,
+	                                   trust_template, trust_size,
+	                                   NULL, session, slot);
+	nssSlot_Destroy(slot);
+	if (status != PR_SUCCESS) {
+	    return status;
+	}
+    }
+
+    *serverAuth = get_nss_trust(saTrust);
+    *clientAuth = get_nss_trust(caTrust);
+    *emailProtection = get_nss_trust(epTrust);
+    *codeSigning = get_nss_trust(csTrust);
+    *stepUpApproved = stepUp;
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCryptokiCRL_GetAttributes (
+  nssCryptokiObject *crlObject,
+  nssSession *sessionOpt,
+  NSSArena *arenaOpt,
+  NSSItem *encodingOpt,
+  NSSItem *subjectOpt,
+  CK_ULONG* crl_class,
+  NSSUTF8 **urlOpt,
+  PRBool *isKRLOpt
+)
+{
+    PRStatus status;
+    NSSSlot *slot;
+    nssSession *session;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE crl_template[7];
+    CK_ULONG crl_size;
+    PRUint32 i;
+
+    NSS_CK_TEMPLATE_START(crl_template, attr, crl_size);
+    if (crl_class) {
+        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CLASS);
+    }
+    if (encodingOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
+    }
+    if (urlOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NETSCAPE_URL);
+    }
+    if (isKRLOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NETSCAPE_KRL);
+    }
+    if (subjectOpt) {
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT);
+    }
+    NSS_CK_TEMPLATE_FINISH(crl_template, attr, crl_size);
+
+    status = nssToken_GetCachedObjectAttributes(crlObject->token, NULL,
+                                                crlObject, 
+                                                CKO_NETSCAPE_CRL,
+                                                crl_template, crl_size);
+    if (status != PR_SUCCESS) {
+	session = sessionOpt ? 
+	          sessionOpt : 
+	          nssToken_GetDefaultSession(crlObject->token);
+	if (session == NULL) {
+	    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+	    return PR_FAILURE;
+	}
+
+	slot = nssToken_GetSlot(crlObject->token);
+	status = nssCKObject_GetAttributes(crlObject->handle, 
+	                                   crl_template, crl_size,
+	                                   arenaOpt, session, slot);
+	nssSlot_Destroy(slot);
+	if (status != PR_SUCCESS) {
+	    return status;
+	}
+    }
+
+    i=0;
+    if (crl_class) {
+        NSS_CK_ATTRIBUTE_TO_ULONG(&crl_template[i], *crl_class); i++;
+    }
+    if (encodingOpt) {
+	NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], encodingOpt); i++;
+    }
+    if (urlOpt) {
+	NSS_CK_ATTRIBUTE_TO_UTF8(&crl_template[i], *urlOpt); i++;
+    }
+    if (isKRLOpt) {
+	NSS_CK_ATTRIBUTE_TO_BOOL(&crl_template[i], *isKRLOpt); i++;
+    }
+    if (subjectOpt) {
+	NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], subjectOpt); i++;
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCryptokiPrivateKey_SetCertificate (
+  nssCryptokiObject *keyObject,
+  nssSession *sessionOpt,
+  const NSSUTF8 *nickname,
+  NSSItem *id,
+  NSSDER *subject
+)
+{
+    CK_RV ckrv;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE key_template[3];
+    CK_ULONG key_size;
+    void *epv = nssToken_GetCryptokiEPV(keyObject->token);
+    nssSession *session;
+    NSSToken *token = keyObject->token;
+    nssSession *defaultSession = nssToken_GetDefaultSession(token);
+    PRBool createdSession = PR_FALSE;
+
+    NSS_CK_TEMPLATE_START(key_template, attr, key_size);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
+    NSS_CK_TEMPLATE_FINISH(key_template, attr, key_size);
+
+    if (sessionOpt) {
+	if (!nssSession_IsReadWrite(sessionOpt)) {
+	    return PR_FAILURE;
+	} 
+	session = sessionOpt;
+    } else if (defaultSession && nssSession_IsReadWrite(defaultSession)) {
+	session = defaultSession;
+    } else {
+	NSSSlot *slot = nssToken_GetSlot(token);
+	session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
+	nssSlot_Destroy(slot);
+	if (!session) {
+	    return PR_FAILURE;
+	}
+	createdSession = PR_TRUE;
+    }
+
+    ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle,
+                                           keyObject->handle,
+                                           key_template,
+                                           key_size);
+
+    if (createdSession) {
+	nssSession_Destroy(session);
+    }
+
+    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
+}
+
diff --git a/mozilla/security/nss/lib/dev/ckhelper.h b/mozilla/security/nss/lib/dev/ckhelper.h
new file mode 100644
index 0000000..ac096b2
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/ckhelper.h
@@ -0,0 +1,193 @@
+/* ***** 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 ***** */
+
+/*
+ * ckhelper.h
+ *
+ * This file contains some helper utilities for interaction with cryptoki.
+ */
+
+#ifndef CKHELPER_H
+#define CKHELPER_H
+
+#ifdef DEBUG
+static const char CKHELPER_CVS_ID[] = "@(#) $RCSfile: ckhelper.h,v $ $Revision: 1.20 $ $Date: 2010/01/08 02:00:58 $";
+#endif /* DEBUG */
+
+PR_BEGIN_EXTERN_C
+
+/* Some globals to keep from constantly redeclaring common cryptoki
+ * attribute types on the stack.
+ */
+
+/* Boolean values */
+NSS_EXTERN_DATA const NSSItem g_ck_true;
+NSS_EXTERN_DATA const NSSItem g_ck_false;
+
+/* Object classes */
+NSS_EXTERN_DATA const NSSItem g_ck_class_cert;
+NSS_EXTERN_DATA const NSSItem g_ck_class_pubkey;
+NSS_EXTERN_DATA const NSSItem g_ck_class_privkey;
+
+#define NSS_CK_TEMPLATE_START(_template, attr, size)   \
+    attr = _template;                                  \
+    size = 0;
+
+#define NSS_CK_SET_ATTRIBUTE_ITEM(pattr, kind, item)  \
+    (pattr)->type = kind;                             \
+    (pattr)->pValue = (CK_VOID_PTR)(item)->data;      \
+    (pattr)->ulValueLen = (CK_ULONG)(item)->size;     \
+    (pattr)++;
+
+#define NSS_CK_SET_ATTRIBUTE_UTF8(pattr, kind, utf8)  \
+    (pattr)->type = kind;                             \
+    (pattr)->pValue = (CK_VOID_PTR)utf8;              \
+    (pattr)->ulValueLen = (CK_ULONG)nssUTF8_Size(utf8, NULL); \
+    if ((pattr)->ulValueLen) ((pattr)->ulValueLen)--; \
+    (pattr)++;
+
+#define NSS_CK_SET_ATTRIBUTE_VAR(pattr, kind, var)    \
+    (pattr)->type = kind;                             \
+    (pattr)->pValue = (CK_VOID_PTR)&var;              \
+    (pattr)->ulValueLen = (CK_ULONG)sizeof(var);      \
+    (pattr)++;
+
+#define NSS_CK_SET_ATTRIBUTE_NULL(pattr, kind)        \
+    (pattr)->type = kind;                             \
+    (pattr)->pValue = (CK_VOID_PTR)NULL;              \
+    (pattr)->ulValueLen = 0;                          \
+    (pattr)++;
+
+#define NSS_CK_TEMPLATE_FINISH(_template, attr, size) \
+    size = (attr) - (_template);                      \
+    PR_ASSERT(size <= sizeof(_template)/sizeof(_template[0]));
+
+/* NSS_CK_ATTRIBUTE_TO_ITEM(attrib, item)
+ *
+ * Convert a CK_ATTRIBUTE to an NSSItem.
+ */
+#define NSS_CK_ATTRIBUTE_TO_ITEM(attrib, item)         \
+    if ((CK_LONG)(attrib)->ulValueLen > 0) {           \
+	(item)->data = (void *)(attrib)->pValue;       \
+	(item)->size = (PRUint32)(attrib)->ulValueLen; \
+    } else {                                           \
+	(item)->data = 0;                              \
+	(item)->size = 0;                              \
+    }
+
+#define NSS_CK_ATTRIBUTE_TO_BOOL(attrib, boolvar)        \
+    if ((attrib)->ulValueLen > 0) {                      \
+	if (*((CK_BBOOL*)(attrib)->pValue) == CK_TRUE) { \
+	    boolvar = PR_TRUE;                           \
+	} else {                                         \
+	    boolvar = PR_FALSE;                          \
+	}                                                \
+    }
+
+#define NSS_CK_ATTRIBUTE_TO_ULONG(attrib, ulongvar)      \
+    if ((attrib)->ulValueLen > 0) {                      \
+	ulongvar = *((CK_ULONG*)(attrib)->pValue);       \
+    }
+
+/* NSS_CK_ATTRIBUTE_TO_UTF8(attrib, str)
+ *
+ * Convert a CK_ATTRIBUTE to a string.
+ */
+#define NSS_CK_ATTRIBUTE_TO_UTF8(attrib, str)      \
+    str = (NSSUTF8 *)((attrib)->pValue);
+
+/* NSS_CK_ITEM_TO_ATTRIBUTE(item, attrib)
+ *
+ * Convert an NSSItem to a  CK_ATTRIBUTE.
+ */
+#define NSS_CK_ITEM_TO_ATTRIBUTE(item, attrib)     \
+    (attrib)->pValue = (CK_VOID_PTR)(item)->data;  \
+    (attrib)->ulValueLen = (CK_ULONG)(item)->size; \
+
+/* Get an array of attributes from an object. */
+NSS_EXTERN PRStatus 
+nssCKObject_GetAttributes
+(
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG count,
+  NSSArena *arenaOpt,
+  nssSession *session,
+  NSSSlot *slot
+);
+
+/* Get a single attribute as an item. */
+NSS_EXTERN PRStatus
+nssCKObject_GetAttributeItem
+(
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_TYPE attribute,
+  NSSArena *arenaOpt,
+  nssSession *session,
+  NSSSlot *slot,
+  NSSItem *rvItem
+);
+
+NSS_EXTERN PRBool
+nssCKObject_IsAttributeTrue
+(
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_TYPE attribute,
+  nssSession *session,
+  NSSSlot *slot,
+  PRStatus *rvStatus
+);
+
+NSS_EXTERN PRStatus 
+nssCKObject_SetAttributes
+(
+  CK_OBJECT_HANDLE object,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG count,
+  nssSession *session,
+  NSSSlot  *slot
+);
+
+NSS_EXTERN PRBool
+nssCKObject_IsTokenObjectTemplate
+(
+  CK_ATTRIBUTE_PTR objectTemplate, 
+  CK_ULONG otsize
+);
+
+PR_END_EXTERN_C
+
+#endif /* CKHELPER_H */
diff --git a/mozilla/security/nss/lib/dev/dev.h b/mozilla/security/nss/lib/dev/dev.h
new file mode 100644
index 0000000..c03ddb1
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/dev.h
@@ -0,0 +1,974 @@
+/* ***** 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 ***** */
+
+#ifndef DEV_H
+#define DEV_H
+
+/*
+ * dev.h
+ *
+ * Low-level methods for interaction with cryptoki devices
+ */
+
+#ifdef DEBUG
+static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.42 $ $Date: 2010/01/08 02:00:58 $";
+#endif /* DEBUG */
+
+#ifndef NSSDEV_H
+#include "nssdev.h"
+#endif /* NSSDEV_H */
+
+#ifndef DEVT_H
+#include "devt.h"
+#endif /* DEVT_H */
+
+PR_BEGIN_EXTERN_C
+
+/* the global module list
+ *
+ * These functions are for managing the global set of modules.  Trust Domains,
+ * etc., will draw from this set.  These functions are completely internal
+ * and only invoked when there are changes to the global module state
+ * (load or unload).
+ *
+ * nss_InitializeGlobalModuleList
+ * nss_DestroyGlobalModuleList
+ * nss_GetLoadedModules
+ *
+ * nssGlobalModuleList_Add
+ * nssGlobalModuleList_Remove
+ * nssGlobalModuleList_FindModuleByName
+ * nssGlobalModuleList_FindSlotByName
+ * nssGlobalModuleList_FindTokenByName
+ */
+
+NSS_EXTERN PRStatus
+nss_InitializeGlobalModuleList
+(
+  void
+);
+
+NSS_EXTERN PRStatus
+nss_DestroyGlobalModuleList
+(
+  void
+);
+
+NSS_EXTERN NSSModule **
+nss_GetLoadedModules
+(
+  void
+);
+
+NSS_EXTERN PRStatus
+nssGlobalModuleList_Add
+(
+  NSSModule *module
+);
+
+NSS_EXTERN PRStatus
+nssGlobalModuleList_Remove
+(
+  NSSModule *module
+);
+
+NSS_EXTERN NSSModule *
+nssGlobalModuleList_FindModuleByName
+(
+  NSSUTF8 *moduleName
+);
+
+NSS_EXTERN NSSSlot *
+nssGlobalModuleList_FindSlotByName
+(
+  NSSUTF8 *slotName
+);
+
+NSS_EXTERN NSSToken *
+nssGlobalModuleList_FindTokenByName
+(
+  NSSUTF8 *tokenName
+);
+
+NSS_EXTERN NSSToken *
+nss_GetDefaultCryptoToken
+(
+  void
+);
+
+NSS_EXTERN NSSToken *
+nss_GetDefaultDatabaseToken
+(
+  void
+);
+
+/*
+ *  |-----------|<---> NSSSlot <--> NSSToken
+ *  | NSSModule |<---> NSSSlot <--> NSSToken
+ *  |-----------|<---> NSSSlot <--> NSSToken
+ */
+
+/* NSSModule
+ *
+ * nssModule_Create
+ * nssModule_CreateFromSpec
+ * nssModule_AddRef
+ * nssModule_GetName
+ * nssModule_GetSlots
+ * nssModule_FindSlotByName
+ * nssModule_FindTokenByName
+ * nssModule_GetCertOrder
+ */
+
+NSS_EXTERN NSSModule *
+nssModule_Create
+(
+  NSSUTF8 *moduleOpt,
+  NSSUTF8 *uriOpt,
+  NSSUTF8 *opaqueOpt,
+  void    *reserved
+);
+
+/* This is to use the new loading mechanism. */
+NSS_EXTERN NSSModule *
+nssModule_CreateFromSpec
+(
+  NSSUTF8 *moduleSpec,
+  NSSModule *parent,
+  PRBool loadSubModules
+);
+
+NSS_EXTERN PRStatus
+nssModule_Destroy
+(
+  NSSModule *mod
+);
+
+NSS_EXTERN NSSModule *
+nssModule_AddRef
+(
+  NSSModule *mod
+);
+
+NSS_EXTERN NSSUTF8 *
+nssModule_GetName
+(
+  NSSModule *mod
+);
+
+NSS_EXTERN NSSSlot **
+nssModule_GetSlots
+(
+  NSSModule *mod
+);
+
+NSS_EXTERN NSSSlot *
+nssModule_FindSlotByName
+(
+  NSSModule *mod,
+  NSSUTF8 *slotName
+);
+
+NSS_EXTERN NSSToken *
+nssModule_FindTokenByName
+(
+  NSSModule *mod,
+  NSSUTF8 *tokenName
+);
+
+NSS_EXTERN PRInt32
+nssModule_GetCertOrder
+(
+  NSSModule *module
+);
+
+/* NSSSlot
+ *
+ * nssSlot_Destroy
+ * nssSlot_AddRef
+ * nssSlot_GetName
+ * nssSlot_GetTokenName
+ * nssSlot_IsTokenPresent
+ * nssSlot_IsPermanent
+ * nssSlot_IsFriendly
+ * nssSlot_IsHardware
+ * nssSlot_Refresh
+ * nssSlot_GetModule
+ * nssSlot_GetToken
+ * nssSlot_Login
+ * nssSlot_Logout
+ * nssSlot_SetPassword
+ * nssSlot_CreateSession
+ */
+
+NSS_EXTERN PRStatus
+nssSlot_Destroy
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN NSSSlot *
+nssSlot_AddRef
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN void
+nssSlot_ResetDelay
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN NSSUTF8 *
+nssSlot_GetName
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN NSSUTF8 *
+nssSlot_GetTokenName
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN NSSModule *
+nssSlot_GetModule
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN NSSToken *
+nssSlot_GetToken
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN PRBool
+nssSlot_IsTokenPresent
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN PRBool
+nssSlot_IsPermanent
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN PRBool
+nssSlot_IsFriendly
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN PRBool
+nssSlot_IsHardware
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN PRBool
+nssSlot_IsLoggedIn
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN PRStatus
+nssSlot_Refresh
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN PRStatus
+nssSlot_Login
+(
+  NSSSlot *slot,
+  NSSCallback *pwcb
+);
+extern const NSSError NSS_ERROR_INVALID_PASSWORD;
+extern const NSSError NSS_ERROR_USER_CANCELED;
+
+NSS_EXTERN PRStatus
+nssSlot_Logout
+(
+  NSSSlot *slot,
+  nssSession *sessionOpt
+);
+
+NSS_EXTERN void
+nssSlot_EnterMonitor
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN void
+nssSlot_ExitMonitor
+(
+  NSSSlot *slot
+);
+
+#define NSSSLOT_ASK_PASSWORD_FIRST_TIME -1
+#define NSSSLOT_ASK_PASSWORD_EVERY_TIME  0
+NSS_EXTERN void
+nssSlot_SetPasswordDefaults
+(
+  NSSSlot *slot,
+  PRInt32 askPasswordTimeout
+);
+
+NSS_EXTERN PRStatus
+nssSlot_SetPassword
+(
+  NSSSlot *slot,
+  NSSUTF8 *oldPasswordOpt,
+  NSSUTF8 *newPassword
+);
+extern const NSSError NSS_ERROR_INVALID_PASSWORD;
+extern const NSSError NSS_ERROR_USER_CANCELED;
+
+/*
+ * nssSlot_IsLoggedIn
+ */
+
+NSS_EXTERN nssSession *
+nssSlot_CreateSession
+(
+  NSSSlot *slot,
+  NSSArena *arenaOpt,
+  PRBool readWrite /* so far, this is the only flag used */
+);
+
+/* NSSToken
+ *
+ * nssToken_Destroy
+ * nssToken_AddRef
+ * nssToken_GetName
+ * nssToken_GetModule
+ * nssToken_GetSlot
+ * nssToken_NeedsPINInitialization
+ * nssToken_ImportCertificate
+ * nssToken_ImportTrust
+ * nssToken_ImportCRL
+ * nssToken_GenerateKeyPair
+ * nssToken_GenerateSymmetricKey
+ * nssToken_DeleteStoredObject
+ * nssToken_FindObjects
+ * nssToken_FindCertificatesBySubject
+ * nssToken_FindCertificatesByNickname
+ * nssToken_FindCertificatesByEmail
+ * nssToken_FindCertificateByIssuerAndSerialNumber
+ * nssToken_FindCertificateByEncodedCertificate
+ * nssToken_FindTrustForCertificate
+ * nssToken_FindCRLsBySubject
+ * nssToken_FindPrivateKeys
+ * nssToken_FindPrivateKeyByID
+ * nssToken_Digest
+ * nssToken_BeginDigest
+ * nssToken_ContinueDigest
+ * nssToken_FinishDigest
+ */
+
+NSS_EXTERN PRStatus
+nssToken_Destroy
+(
+  NSSToken *tok
+);
+
+NSS_EXTERN NSSToken *
+nssToken_AddRef
+(
+  NSSToken *tok
+);
+
+NSS_EXTERN NSSUTF8 *
+nssToken_GetName
+(
+  NSSToken *tok
+);
+
+NSS_EXTERN NSSModule *
+nssToken_GetModule
+(
+  NSSToken *token
+);
+
+NSS_EXTERN NSSSlot *
+nssToken_GetSlot
+(
+  NSSToken *tok
+);
+
+NSS_EXTERN PRBool
+nssToken_NeedsPINInitialization
+(
+  NSSToken *token
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_ImportCertificate
+(
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSCertificateType certType,
+  NSSItem *id,
+  const NSSUTF8 *nickname,
+  NSSDER *encoding,
+  NSSDER *issuer,
+  NSSDER *subject,
+  NSSDER *serial,
+  NSSASCII7 *emailAddr,
+  PRBool asTokenObject
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_ImportTrust
+(
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSDER *certEncoding,
+  NSSDER *certIssuer,
+  NSSDER *certSerial,
+  nssTrustLevel serverAuth,
+  nssTrustLevel clientAuth,
+  nssTrustLevel codeSigning,
+  nssTrustLevel emailProtection,
+  PRBool stepUpApproved,
+  PRBool asTokenObject
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_ImportCRL
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  NSSDER *encoding,
+  PRBool isKRL,
+  NSSUTF8 *url,
+  PRBool asTokenObject
+);
+
+/* Permanently remove an object from the token. */
+NSS_EXTERN PRStatus
+nssToken_DeleteStoredObject
+(
+  nssCryptokiObject *instance
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssToken_FindObjects
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  CK_OBJECT_CLASS objclass,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssToken_FindCertificatesBySubject
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssToken_FindCertificatesByNickname
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  const NSSUTF8 *name,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssToken_FindCertificatesByEmail
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSASCII7 *email,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssToken_FindCertificatesByID
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *id,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_FindCertificateByIssuerAndSerialNumber
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *issuer,
+  NSSDER *serial,
+  nssTokenSearchType searchType,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_FindCertificateByEncodedCertificate
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSBER *encodedCertificate,
+  nssTokenSearchType searchType,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_FindTrustForCertificate
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *certEncoding,
+  NSSDER *certIssuer,
+  NSSDER *certSerial,
+  nssTokenSearchType searchType
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssToken_FindCRLsBySubject
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssToken_FindPrivateKeys
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_FindPrivateKeyByID
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *keyID
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssToken_FindPublicKeyByID
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *keyID
+);
+
+NSS_EXTERN NSSItem *
+nssToken_Digest
+(
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSAlgorithmAndParameters *ap,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN PRStatus
+nssToken_BeginDigest
+(
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSAlgorithmAndParameters *ap
+);
+
+NSS_EXTERN PRStatus
+nssToken_ContinueDigest
+(
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSItem *item
+);
+
+NSS_EXTERN NSSItem *
+nssToken_FinishDigest
+(
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/* nssSession
+ *
+ * nssSession_Destroy
+ * nssSession_EnterMonitor
+ * nssSession_ExitMonitor
+ * nssSession_IsReadWrite
+ */
+
+NSS_EXTERN PRStatus
+nssSession_Destroy
+(
+  nssSession *s
+);
+
+/* would like to inline */
+NSS_EXTERN PRStatus
+nssSession_EnterMonitor
+(
+  nssSession *s
+);
+
+/* would like to inline */
+NSS_EXTERN PRStatus
+nssSession_ExitMonitor
+(
+  nssSession *s
+);
+
+/* would like to inline */
+NSS_EXTERN PRBool
+nssSession_IsReadWrite
+(
+  nssSession *s
+);
+
+/* nssCryptokiObject
+ *
+ * An object living on a cryptoki token.
+ * Not really proper to mix up the object types just because 
+ * nssCryptokiObject itself is generic, but doing so anyway.
+ *
+ * nssCryptokiObject_Destroy
+ * nssCryptokiObject_Equal
+ * nssCryptokiObject_Clone
+ * nssCryptokiCertificate_GetAttributes
+ * nssCryptokiPrivateKey_GetAttributes
+ * nssCryptokiPublicKey_GetAttributes
+ * nssCryptokiTrust_GetAttributes
+ * nssCryptokiCRL_GetAttributes
+ */
+
+NSS_EXTERN void
+nssCryptokiObject_Destroy
+(
+  nssCryptokiObject *object
+);
+
+NSS_EXTERN PRBool
+nssCryptokiObject_Equal
+(
+  nssCryptokiObject *object1,
+  nssCryptokiObject *object2
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssCryptokiObject_Clone
+(
+  nssCryptokiObject *object
+);
+
+NSS_EXTERN PRStatus
+nssCryptokiCertificate_GetAttributes
+(
+  nssCryptokiObject *object,
+  nssSession *sessionOpt,
+  NSSArena *arenaOpt,
+  NSSCertificateType *certTypeOpt,
+  NSSItem *idOpt,
+  NSSDER *encodingOpt,
+  NSSDER *issuerOpt,
+  NSSDER *serialOpt,
+  NSSDER *subjectOpt
+);
+
+NSS_EXTERN PRStatus
+nssCryptokiTrust_GetAttributes
+(
+  nssCryptokiObject *trustObject,
+  nssSession *sessionOpt,
+  NSSItem *sha1_hash,
+  nssTrustLevel *serverAuth,
+  nssTrustLevel *clientAuth,
+  nssTrustLevel *codeSigning,
+  nssTrustLevel *emailProtection,
+  PRBool *stepUpApproved
+);
+
+NSS_EXTERN PRStatus
+nssCryptokiCRL_GetAttributes
+(
+  nssCryptokiObject *crlObject,
+  nssSession *sessionOpt,
+  NSSArena *arenaOpt,
+  NSSItem *encodingOpt,
+  NSSItem * subjectOpt,
+  CK_ULONG * crl_class,
+  NSSUTF8 **urlOpt,
+  PRBool *isKRLOpt
+);
+
+/* I'm including this to handle import of certificates in NSS 3.5.  This
+ * function will set the cert-related attributes of a key, in order to
+ * associate it with a cert.  Does it stay like this for 4.0?
+ */
+NSS_EXTERN PRStatus
+nssCryptokiPrivateKey_SetCertificate
+(
+  nssCryptokiObject *keyObject,
+  nssSession *sessionOpt,
+  const NSSUTF8 *nickname,
+  NSSItem *id,
+  NSSDER *subject
+);
+
+NSS_EXTERN void
+nssModuleArray_Destroy
+(
+  NSSModule **modules
+);
+
+/* nssSlotArray
+ *
+ * nssSlotArray_Destroy
+ */
+
+NSS_EXTERN void
+nssSlotArray_Destroy
+(
+  NSSSlot **slots
+);
+
+/* nssTokenArray
+ *
+ * nssTokenArray_Destroy
+ */
+
+NSS_EXTERN void
+nssTokenArray_Destroy
+(
+  NSSToken **tokens
+);
+
+/* nssCryptokiObjectArray
+ *
+ * nssCryptokiObjectArray_Destroy
+ */
+NSS_EXTERN void
+nssCryptokiObjectArray_Destroy
+(
+  nssCryptokiObject **object
+);
+
+/* nssSlotList
+*
+ * An ordered list of slots.  The order can be anything, it is set in the
+ * Add methods.  Perhaps it should be CreateInCertOrder, ...?
+ *
+ * nssSlotList_Create
+ * nssSlotList_Destroy
+ * nssSlotList_Add
+ * nssSlotList_AddModuleSlots
+ * nssSlotList_GetSlots
+ * nssSlotList_FindSlotByName
+ * nssSlotList_FindTokenByName
+ * nssSlotList_GetBestSlot
+ * nssSlotList_GetBestSlotForAlgorithmAndParameters
+ * nssSlotList_GetBestSlotForAlgorithmsAndParameters
+ */
+
+/* nssSlotList_Create
+ */
+NSS_EXTERN nssSlotList *
+nssSlotList_Create
+(
+  NSSArena *arenaOpt
+);
+
+/* nssSlotList_Destroy
+ */
+NSS_EXTERN void
+nssSlotList_Destroy
+(
+  nssSlotList *slotList
+);
+
+/* nssSlotList_Add
+ *
+ * Add the given slot in the given order.
+ */
+NSS_EXTERN PRStatus
+nssSlotList_Add
+(
+  nssSlotList *slotList,
+  NSSSlot *slot,
+  PRUint32 order
+);
+
+/* nssSlotList_AddModuleSlots
+ *
+ * Add all slots in the module, in the given order (the slots will have
+ * equal weight).
+ */
+NSS_EXTERN PRStatus
+nssSlotList_AddModuleSlots
+(
+  nssSlotList *slotList,
+  NSSModule *module,
+  PRUint32 order
+);
+
+/* nssSlotList_GetSlots
+ */
+NSS_EXTERN NSSSlot **
+nssSlotList_GetSlots
+(
+  nssSlotList *slotList
+);
+
+/* nssSlotList_FindSlotByName
+ */
+NSS_EXTERN NSSSlot *
+nssSlotList_FindSlotByName
+(
+  nssSlotList *slotList,
+  NSSUTF8 *slotName
+);
+
+/* nssSlotList_FindTokenByName
+ */
+NSS_EXTERN NSSToken *
+nssSlotList_FindTokenByName
+(
+  nssSlotList *slotList,
+  NSSUTF8 *tokenName
+);
+
+/* nssSlotList_GetBestSlot
+ *
+ * The best slot is the highest ranking in order, i.e., the first in the
+ * list.
+ */
+NSS_EXTERN NSSSlot *
+nssSlotList_GetBestSlot
+(
+  nssSlotList *slotList
+);
+
+/* nssSlotList_GetBestSlotForAlgorithmAndParameters
+ *
+ * Highest-ranking slot than can handle algorithm/parameters.
+ */
+NSS_EXTERN NSSSlot *
+nssSlotList_GetBestSlotForAlgorithmAndParameters
+(
+  nssSlotList *slotList,
+  NSSAlgorithmAndParameters *ap
+);
+
+/* nssSlotList_GetBestSlotForAlgorithmsAndParameters
+ *
+ * Highest-ranking slot than can handle all algorithms/parameters.
+ */
+NSS_EXTERN NSSSlot *
+nssSlotList_GetBestSlotForAlgorithmsAndParameters
+(
+  nssSlotList *slotList,
+  NSSAlgorithmAndParameters **ap
+);
+
+NSS_EXTERN PRBool
+nssToken_IsPresent
+(
+  NSSToken *token
+);
+
+NSS_EXTERN nssSession *
+nssToken_GetDefaultSession
+(
+  NSSToken *token
+);
+
+NSS_EXTERN PRStatus
+nssToken_GetTrustOrder
+(
+  NSSToken *tok
+);
+
+NSS_EXTERN PRStatus
+nssToken_NotifyCertsNotVisible
+(
+  NSSToken *tok
+);
+
+NSS_EXTERN PRStatus
+nssToken_TraverseCertificates
+(
+  NSSToken *token,
+  nssSession *sessionOpt,
+  nssTokenSearchType searchType,
+  PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
+  void *arg
+);
+
+NSS_EXTERN PRBool
+nssToken_IsPrivateKeyAvailable
+(
+  NSSToken *token,
+  NSSCertificate *c,
+  nssCryptokiObject *instance
+);
+
+PR_END_EXTERN_C
+
+#endif /* DEV_H */
diff --git a/mozilla/security/nss/lib/dev/devm.h b/mozilla/security/nss/lib/dev/devm.h
new file mode 100644
index 0000000..2474ea2
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/devm.h
@@ -0,0 +1,241 @@
+/* ***** 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 ***** */
+
+#ifndef DEVM_H
+#define DEVM_H
+
+#ifdef DEBUG
+static const char DEVM_CVS_ID[] = "@(#) $RCSfile: devm.h,v $ $Revision: 1.12 $ $Date: 2010/01/08 02:00:58 $";
+#endif /* DEBUG */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef DEVTM_H
+#include "devtm.h"
+#endif /* DEVTM_H */
+
+PR_BEGIN_EXTERN_C
+
+/* Shortcut to cryptoki API functions. */
+#define CKAPI(epv) \
+    ((CK_FUNCTION_LIST_PTR)(epv))
+
+NSS_EXTERN void
+nssDevice_AddRef
+(
+ struct nssDeviceBaseStr *device
+);
+
+NSS_EXTERN PRBool
+nssDevice_Destroy
+(
+ struct nssDeviceBaseStr *device
+);
+
+NSS_EXTERN PRBool
+nssModule_IsThreadSafe
+(
+  NSSModule *module
+);
+
+NSS_EXTERN PRBool
+nssModule_IsInternal
+(
+  NSSModule *mod
+);
+
+NSS_EXTERN PRBool
+nssModule_IsModuleDBOnly
+(
+  NSSModule *mod
+);
+
+NSS_EXTERN void *
+nssModule_GetCryptokiEPV
+(
+  NSSModule *mod
+);
+
+NSS_EXTERN NSSSlot *
+nssSlot_Create
+(
+  CK_SLOT_ID slotId,
+  NSSModule *parent
+);
+
+NSS_EXTERN void *
+nssSlot_GetCryptokiEPV
+(
+  NSSSlot *slot
+);
+
+NSS_EXTERN NSSToken *
+nssToken_Create
+(
+  CK_SLOT_ID slotID,
+  NSSSlot *peer
+);
+
+NSS_EXTERN void *
+nssToken_GetCryptokiEPV
+(
+  NSSToken *token
+);
+
+NSS_EXTERN nssSession *
+nssToken_GetDefaultSession
+(
+  NSSToken *token
+);
+
+NSS_EXTERN PRBool
+nssToken_IsLoginRequired
+(
+  NSSToken *token
+);
+
+NSS_EXTERN void
+nssToken_Remove
+(
+  NSSToken *token
+);
+
+NSS_EXTERN nssCryptokiObject *
+nssCryptokiObject_Create
+(
+  NSSToken *t, 
+  nssSession *session,
+  CK_OBJECT_HANDLE h
+);
+
+NSS_EXTERN nssTokenObjectCache *
+nssTokenObjectCache_Create
+(
+  NSSToken *token,
+  PRBool cacheCerts,
+  PRBool cacheTrust,
+  PRBool cacheCRLs
+);
+
+NSS_EXTERN void
+nssTokenObjectCache_Destroy
+(
+  nssTokenObjectCache *cache
+);
+
+NSS_EXTERN void
+nssTokenObjectCache_Clear
+(
+  nssTokenObjectCache *cache
+);
+
+NSS_EXTERN PRBool
+nssTokenObjectCache_HaveObjectClass
+(
+  nssTokenObjectCache *cache,
+  CK_OBJECT_CLASS objclass
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssTokenObjectCache_FindObjectsByTemplate
+(
+  nssTokenObjectCache *cache,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR otemplate,
+  CK_ULONG otlen,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN PRStatus
+nssTokenObjectCache_GetObjectAttributes
+(
+  nssTokenObjectCache *cache,
+  NSSArena *arenaOpt,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR atemplate,
+  CK_ULONG atlen
+);
+
+NSS_EXTERN PRStatus
+nssTokenObjectCache_ImportObject
+(
+  nssTokenObjectCache *cache,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR ot,
+  CK_ULONG otlen
+);
+
+NSS_EXTERN void
+nssTokenObjectCache_RemoveObject
+(
+  nssTokenObjectCache *cache,
+  nssCryptokiObject *object
+);
+
+/* XXX allows peek back into token */
+NSS_EXTERN PRStatus
+nssToken_GetCachedObjectAttributes
+(
+  NSSToken *token,
+  NSSArena *arenaOpt,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR atemplate,
+  CK_ULONG atlen
+);
+
+/* PKCS#11 stores strings in a fixed-length buffer padded with spaces.  This
+ * function gets the length of the actual string.
+ */
+NSS_EXTERN PRUint32
+nssPKCS11String_Length
+(
+  CK_CHAR *pkcs11str, 
+  PRUint32 bufLen
+);
+
+PR_END_EXTERN_C
+
+#endif /* DEV_H */
diff --git a/mozilla/security/nss/lib/dev/devslot.c b/mozilla/security/nss/lib/dev/devslot.c
new file mode 100644
index 0000000..f67c8f1
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/devslot.c
@@ -0,0 +1,296 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: devslot.c,v $ $Revision: 1.26 $ $Date: 2010/01/08 02:00:58 $";
+#endif /* DEBUG */
+
+#include "pkcs11.h"
+
+#ifndef DEVM_H
+#include "devm.h"
+#endif /* DEVM_H */
+
+#ifndef CKHELPER_H
+#include "ckhelper.h"
+#endif /* CKHELPER_H */
+
+#include "pk11pub.h"
+
+/* measured in seconds */
+#define NSSSLOT_TOKEN_DELAY_TIME 1
+
+/* this should track global and per-transaction login information */
+
+#define NSSSLOT_IS_FRIENDLY(slot) \
+  (slot->base.flags & NSSSLOT_FLAGS_FRIENDLY)
+
+/* measured as interval */
+static PRIntervalTime s_token_delay_time = 0;
+
+/* The flags needed to open a read-only session. */
+static const CK_FLAGS s_ck_readonly_flags = CKF_SERIAL_SESSION;
+
+NSS_IMPLEMENT PRStatus
+nssSlot_Destroy (
+  NSSSlot *slot
+)
+{
+    if (slot) {
+	if (PR_AtomicDecrement(&slot->base.refCount) == 0) {
+	    PZ_DestroyLock(slot->base.lock);
+	    return nssArena_Destroy(slot->base.arena);
+	}
+    }
+    return PR_SUCCESS;
+}
+
+void
+nssSlot_EnterMonitor(NSSSlot *slot)
+{
+    if (slot->lock) {
+	PZ_Lock(slot->lock);
+    }
+}
+
+void
+nssSlot_ExitMonitor(NSSSlot *slot)
+{
+    if (slot->lock) {
+	PZ_Unlock(slot->lock);
+    }
+}
+
+NSS_IMPLEMENT void
+NSSSlot_Destroy (
+  NSSSlot *slot
+)
+{
+    (void)nssSlot_Destroy(slot);
+}
+
+NSS_IMPLEMENT NSSSlot *
+nssSlot_AddRef (
+  NSSSlot *slot
+)
+{
+    PR_AtomicIncrement(&slot->base.refCount);
+    return slot;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssSlot_GetName (
+  NSSSlot *slot
+)
+{
+    return slot->base.name;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssSlot_GetTokenName (
+  NSSSlot *slot
+)
+{
+    return nssToken_GetName(slot->token);
+}
+
+NSS_IMPLEMENT void
+nssSlot_ResetDelay (
+  NSSSlot *slot
+)
+{
+    slot->lastTokenPing = 0;
+}
+
+static PRBool
+within_token_delay_period(NSSSlot *slot)
+{
+    PRIntervalTime time, lastTime;
+    /* Set the delay time for checking the token presence */
+    if (s_token_delay_time == 0) {
+	s_token_delay_time = PR_SecondsToInterval(NSSSLOT_TOKEN_DELAY_TIME);
+    }
+    time = PR_IntervalNow();
+    lastTime = slot->lastTokenPing;
+    if ((lastTime) && ((time - lastTime) < s_token_delay_time)) {
+	return PR_TRUE;
+    }
+    slot->lastTokenPing = time;
+    return PR_FALSE;
+}
+
+NSS_IMPLEMENT PRBool
+nssSlot_IsTokenPresent (
+  NSSSlot *slot
+)
+{
+    CK_RV ckrv;
+    PRStatus nssrv;
+    /* XXX */
+    nssSession *session;
+    CK_SLOT_INFO slotInfo;
+    void *epv;
+    /* permanent slots are always present unless they're disabled */
+    if (nssSlot_IsPermanent(slot)) {
+	return !PK11_IsDisabled(slot->pk11slot);
+    }
+    /* avoid repeated calls to check token status within set interval */
+    if (within_token_delay_period(slot)) {
+	return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0);
+    }
+
+    /* First obtain the slot info */
+    epv = slot->epv;
+    if (!epv) {
+	return PR_FALSE;
+    }
+    nssSlot_EnterMonitor(slot);
+    ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo);
+    nssSlot_ExitMonitor(slot);
+    if (ckrv != CKR_OK) {
+	slot->token->base.name[0] = 0; /* XXX */
+	return PR_FALSE;
+    }
+    slot->ckFlags = slotInfo.flags;
+    /* check for the presence of the token */
+    if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
+	if (!slot->token) {
+	    /* token was never present */
+	    return PR_FALSE;
+	}
+	session = nssToken_GetDefaultSession(slot->token);
+	if (session) {
+	    nssSession_EnterMonitor(session);
+	    /* token is not present */
+	    if (session->handle != CK_INVALID_SESSION) {
+		/* session is valid, close and invalidate it */
+		CKAPI(epv)->C_CloseSession(session->handle);
+		session->handle = CK_INVALID_SESSION;
+	    }
+	    nssSession_ExitMonitor(session);
+	}
+	if (slot->token->base.name[0] != 0) {
+	    /* notify the high-level cache that the token is removed */
+	    slot->token->base.name[0] = 0; /* XXX */
+	    nssToken_NotifyCertsNotVisible(slot->token);
+	}
+	slot->token->base.name[0] = 0; /* XXX */
+	/* clear the token cache */
+	nssToken_Remove(slot->token);
+	return PR_FALSE;
+    }
+    /* token is present, use the session info to determine if the card
+     * has been removed and reinserted.
+     */
+    session = nssToken_GetDefaultSession(slot->token);
+    if (session) {
+	PRBool isPresent = PR_FALSE;
+	nssSession_EnterMonitor(session);
+	if (session->handle != CK_INVALID_SESSION) {
+	    CK_SESSION_INFO sessionInfo;
+	    ckrv = CKAPI(epv)->C_GetSessionInfo(session->handle, &sessionInfo);
+	    if (ckrv != CKR_OK) {
+		/* session is screwy, close and invalidate it */
+		CKAPI(epv)->C_CloseSession(session->handle);
+		session->handle = CK_INVALID_SESSION;
+	    }
+	}
+	isPresent = session->handle != CK_INVALID_SESSION;
+	nssSession_ExitMonitor(session);
+	/* token not removed, finished */
+	if (isPresent)
+	    return PR_TRUE;
+    } 
+    /* the token has been removed, and reinserted, or the slot contains
+     * a token it doesn't recognize. invalidate all the old
+     * information we had on this token, if we can't refresh, clear
+     * the present flag */
+    nssToken_NotifyCertsNotVisible(slot->token);
+    nssToken_Remove(slot->token);
+    /* token has been removed, need to refresh with new session */
+    nssrv = nssSlot_Refresh(slot);
+    if (nssrv != PR_SUCCESS) {
+        slot->token->base.name[0] = 0; /* XXX */
+        slot->ckFlags &= ~CKF_TOKEN_PRESENT;
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+NSS_IMPLEMENT void *
+nssSlot_GetCryptokiEPV (
+  NSSSlot *slot
+)
+{
+    return slot->epv;
+}
+
+NSS_IMPLEMENT NSSToken *
+nssSlot_GetToken (
+  NSSSlot *slot
+)
+{
+    if (nssSlot_IsTokenPresent(slot)) {
+	return nssToken_AddRef(slot->token);
+    }
+    return (NSSToken *)NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+nssSession_EnterMonitor (
+  nssSession *s
+)
+{
+    if (s->lock) PZ_Lock(s->lock);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssSession_ExitMonitor (
+  nssSession *s
+)
+{
+    return (s->lock) ? PZ_Unlock(s->lock) : PR_SUCCESS;
+}
+
+NSS_EXTERN PRBool
+nssSession_IsReadWrite (
+  nssSession *s
+)
+{
+    return s->isRW;
+}
+
diff --git a/mozilla/security/nss/lib/dev/devt.h b/mozilla/security/nss/lib/dev/devt.h
new file mode 100644
index 0000000..317069e
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/devt.h
@@ -0,0 +1,192 @@
+/* ***** 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 ***** */
+
+#ifndef DEVT_H
+#define DEVT_H
+
+#ifdef DEBUG
+static const char DEVT_CVS_ID[] = "@(#) $RCSfile: devt.h,v $ $Revision: 1.24 $ $Date: 2010/01/08 02:00:58 $";
+#endif /* DEBUG */
+
+/*
+ * devt.h
+ *
+ * This file contains definitions for the low-level cryptoki devices.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef BASET_H
+#include "baset.h"
+#endif /* BASET_H */
+
+#include "secmodt.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct nssSessionStr nssSession;
+
+/* XXX until NSSTokenStr is moved */
+struct nssDeviceBaseStr
+{
+  NSSArena *arena;
+  PZLock *lock;
+  PRInt32 refCount;
+  NSSUTF8 *name;
+  PRUint32 flags;
+};
+
+typedef struct nssTokenObjectCacheStr nssTokenObjectCache;
+
+/* XXX until devobject.c goes away */
+struct NSSTokenStr
+{
+    struct nssDeviceBaseStr base;
+    NSSSlot *slot;  /* Parent (or peer, if you will) */
+    CK_FLAGS ckFlags; /* from CK_TOKEN_INFO.flags */
+    PRUint32 flags;
+    void *epv;
+    nssSession *defaultSession;
+    NSSTrustDomain *trustDomain;
+    PRIntervalTime lastTime;
+    nssTokenObjectCache *cache;
+    PK11SlotInfo *pk11slot;
+};
+
+typedef enum {
+  nssSlotAskPasswordTimes_FirstTime = 0,
+  nssSlotAskPasswordTimes_EveryTime = 1,
+  nssSlotAskPasswordTimes_Timeout = 2
+} 
+nssSlotAskPasswordTimes;
+
+struct nssSlotAuthInfoStr
+{
+  PRTime lastLogin;
+  nssSlotAskPasswordTimes askTimes;
+  PRIntervalTime askPasswordTimeout;
+};
+
+struct NSSSlotStr
+{
+  struct nssDeviceBaseStr base;
+  NSSModule *module; /* Parent */
+  NSSToken *token;  /* Peer */
+  CK_SLOT_ID slotID;
+  CK_FLAGS ckFlags; /* from CK_SLOT_INFO.flags */
+  struct nssSlotAuthInfoStr authInfo;
+  PRIntervalTime lastTokenPing;
+  PZLock *lock;
+  void *epv;
+  PK11SlotInfo *pk11slot;
+};
+
+struct nssSessionStr
+{
+  PZLock *lock;
+  CK_SESSION_HANDLE handle;
+  NSSSlot *slot;
+  PRBool isRW;
+  PRBool ownLock;
+};
+
+typedef enum {
+    NSSCertificateType_Unknown = 0,
+    NSSCertificateType_PKIX = 1
+} NSSCertificateType;
+
+typedef enum {
+    nssTrustLevel_Unknown = 0,
+    nssTrustLevel_NotTrusted = 1,
+    nssTrustLevel_Trusted = 2,
+    nssTrustLevel_TrustedDelegator = 3,
+    nssTrustLevel_Valid = 4,
+    nssTrustLevel_ValidDelegator = 5
+} nssTrustLevel;
+
+typedef struct nssCryptokiInstanceStr nssCryptokiInstance;
+
+struct nssCryptokiInstanceStr
+{
+    CK_OBJECT_HANDLE handle;
+    NSSToken *token;
+    PRBool isTokenObject;
+    NSSUTF8 *label;
+};
+
+typedef struct nssCryptokiInstanceStr nssCryptokiObject;
+
+typedef struct nssTokenCertSearchStr nssTokenCertSearch;
+
+typedef enum {
+    nssTokenSearchType_AllObjects = 0,
+    nssTokenSearchType_SessionOnly = 1,
+    nssTokenSearchType_TokenOnly = 2,
+    nssTokenSearchType_TokenForced = 3
+} nssTokenSearchType;
+
+struct nssTokenCertSearchStr
+{
+    nssTokenSearchType searchType;
+    PRStatus (* callback)(NSSCertificate *c, void *arg);
+    void *cbarg;
+    nssList *cached;
+    /* TODO: add a cache query callback if the list would be large 
+     *       (traversal) 
+     */
+};
+
+struct nssSlotListStr;
+typedef struct nssSlotListStr nssSlotList;
+
+struct NSSAlgorithmAndParametersStr
+{
+    CK_MECHANISM mechanism;
+};
+
+PR_END_EXTERN_C
+
+#endif /* DEVT_H */
diff --git a/mozilla/security/nss/lib/dev/devtm.h b/mozilla/security/nss/lib/dev/devtm.h
new file mode 100644
index 0000000..6fe825e
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/devtm.h
@@ -0,0 +1,61 @@
+/* ***** 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 ***** */
+
+#ifndef DEVTM_H
+#define DEVTM_H
+
+#ifdef DEBUG
+static const char DEVTM_CVS_ID[] = "@(#) $RCSfile: devtm.h,v $ $Revision: 1.4 $ $Date: 2005/01/20 02:25:47 $";
+#endif /* DEBUG */
+
+/*
+ * devtm.h
+ *
+ * This file contains module-private definitions for the low-level 
+ * cryptoki devices.
+ */
+
+#ifndef DEVT_H
+#include "devt.h"
+#endif /* DEVT_H */
+
+PR_BEGIN_EXTERN_C
+
+#define MAX_LOCAL_CACHE_OBJECTS 10
+
+PR_END_EXTERN_C
+
+#endif /* DEVTM_H */
diff --git a/mozilla/security/nss/lib/dev/devtoken.c b/mozilla/security/nss/lib/dev/devtoken.c
new file mode 100644
index 0000000..1037ddc
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/devtoken.c
@@ -0,0 +1,1618 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.53 $ $Date: 2010/01/08 02:00:58 $";
+#endif /* DEBUG */
+
+#include "pkcs11.h"
+
+#ifndef DEVM_H
+#include "devm.h"
+#endif /* DEVM_H */
+
+#ifndef CKHELPER_H
+#include "ckhelper.h"
+#endif /* CKHELPER_H */
+
+#include "pk11func.h"
+#include "dev3hack.h"
+#include "secerr.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
+extern const NSSError NSS_ERROR_PKCS11;
+
+/* The number of object handles to grab during each call to C_FindObjects */
+#define OBJECT_STACK_SIZE 16
+
+NSS_IMPLEMENT PRStatus
+nssToken_Destroy (
+  NSSToken *tok
+)
+{
+    if (tok) {
+	if (PR_AtomicDecrement(&tok->base.refCount) == 0) {
+	    PZ_DestroyLock(tok->base.lock);
+	    nssTokenObjectCache_Destroy(tok->cache);
+	    /* The token holds the first/last reference to the slot.
+	     * When the token is actually destroyed, that ref must go too.
+	     */
+	    (void)nssSlot_Destroy(tok->slot);
+	    return nssArena_Destroy(tok->base.arena);
+	}
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void
+nssToken_Remove (
+  NSSToken *tok
+)
+{
+    nssTokenObjectCache_Clear(tok->cache);
+}
+
+NSS_IMPLEMENT void
+NSSToken_Destroy (
+  NSSToken *tok
+)
+{
+    (void)nssToken_Destroy(tok);
+}
+
+NSS_IMPLEMENT NSSToken *
+nssToken_AddRef (
+  NSSToken *tok
+)
+{
+    PR_AtomicIncrement(&tok->base.refCount);
+    return tok;
+}
+
+NSS_IMPLEMENT NSSSlot *
+nssToken_GetSlot (
+  NSSToken *tok
+)
+{
+    return nssSlot_AddRef(tok->slot);
+}
+
+NSS_IMPLEMENT void *
+nssToken_GetCryptokiEPV (
+  NSSToken *token
+)
+{
+    return nssSlot_GetCryptokiEPV(token->slot);
+}
+
+NSS_IMPLEMENT nssSession *
+nssToken_GetDefaultSession (
+  NSSToken *token
+)
+{
+    return token->defaultSession;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssToken_GetName (
+  NSSToken *tok
+)
+{
+    if (tok == NULL) {
+	return "";
+    }
+    if (tok->base.name[0] == 0) {
+	(void) nssSlot_IsTokenPresent(tok->slot);
+    } 
+    return tok->base.name;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+NSSToken_GetName (
+  NSSToken *token
+)
+{
+    return nssToken_GetName(token);
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_IsLoginRequired (
+  NSSToken *token
+)
+{
+    return (token->ckFlags & CKF_LOGIN_REQUIRED);
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_NeedsPINInitialization (
+  NSSToken *token
+)
+{
+    return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_DeleteStoredObject (
+  nssCryptokiObject *instance
+)
+{
+    CK_RV ckrv;
+    PRStatus status;
+    PRBool createdSession = PR_FALSE;
+    NSSToken *token = instance->token;
+    nssSession *session = NULL;
+    void *epv = nssToken_GetCryptokiEPV(instance->token);
+    if (token->cache) {
+	nssTokenObjectCache_RemoveObject(token->cache, instance);
+    }
+    if (instance->isTokenObject) {
+       if (token->defaultSession && 
+           nssSession_IsReadWrite(token->defaultSession)) {
+	   session = token->defaultSession;
+       } else {
+	   session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
+	   createdSession = PR_TRUE;
+       }
+    }
+    if (session == NULL) {
+	return PR_FAILURE;
+    }
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
+    nssSession_ExitMonitor(session);
+    if (createdSession) {
+	nssSession_Destroy(session);
+    }
+    status = PR_SUCCESS;
+    if (ckrv != CKR_OK) {
+	status = PR_FAILURE;
+	/* use the error stack to pass the PKCS #11 error out  */
+	nss_SetError(ckrv);
+	nss_SetError(NSS_ERROR_PKCS11);
+    }
+    return status;
+}
+
+static nssCryptokiObject *
+import_object (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  CK_ATTRIBUTE_PTR objectTemplate,
+  CK_ULONG otsize
+)
+{
+    nssSession *session = NULL;
+    PRBool createdSession = PR_FALSE;
+    nssCryptokiObject *object = NULL;
+    CK_OBJECT_HANDLE handle;
+    CK_RV ckrv;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
+	if (sessionOpt) {
+	    if (!nssSession_IsReadWrite(sessionOpt)) {
+		nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+		return NULL;
+	    }
+	    session = sessionOpt;
+	} else if (tok->defaultSession && 
+	           nssSession_IsReadWrite(tok->defaultSession)) {
+	    session = tok->defaultSession;
+	} else {
+	    session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
+	    createdSession = PR_TRUE;
+	}
+    } else {
+	session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+    }
+    if (session == NULL) {
+	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+	return NULL;
+    }
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_CreateObject(session->handle, 
+                                      objectTemplate, otsize,
+                                      &handle);
+    nssSession_ExitMonitor(session);
+    if (ckrv == CKR_OK) {
+	object = nssCryptokiObject_Create(tok, session, handle);
+    } else {
+	nss_SetError(ckrv);
+	nss_SetError(NSS_ERROR_PKCS11);
+    }
+    if (createdSession) {
+	nssSession_Destroy(session);
+    }
+    return object;
+}
+
+static nssCryptokiObject **
+create_objects_from_handles (
+  NSSToken *tok,
+  nssSession *session,
+  CK_OBJECT_HANDLE *handles,
+  PRUint32 numH
+)
+{
+    nssCryptokiObject **objects;
+    objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
+    if (objects) {
+	PRInt32 i;
+	for (i=0; i<(PRInt32)numH; i++) {
+	    objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
+	    if (!objects[i]) {
+		for (--i; i>0; --i) {
+		    nssCryptokiObject_Destroy(objects[i]);
+		}
+		nss_ZFreeIf(objects);
+		objects = NULL;
+		break;
+	    }
+	}
+    }
+    return objects;
+}
+
+static nssCryptokiObject **
+find_objects (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG otsize,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_RV ckrv = CKR_OK;
+    CK_ULONG count;
+    CK_OBJECT_HANDLE *objectHandles = NULL;
+    CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
+    PRUint32 arraySize, numHandles;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssCryptokiObject **objects;
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	ckrv = CKR_SESSION_HANDLE_INVALID;
+	goto loser;                
+    }
+
+    /* the arena is only for the array of object handles */
+    if (maximumOpt > 0) {
+	arraySize = maximumOpt;
+    } else {
+	arraySize = OBJECT_STACK_SIZE;
+    }
+    numHandles = 0;
+    if (arraySize <= OBJECT_STACK_SIZE) {
+	objectHandles = staticObjects;
+    } else {
+	objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
+    }
+    if (!objectHandles) {
+	ckrv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    nssSession_EnterMonitor(session); /* ==== session lock === */
+    /* Initialize the find with the template */
+    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
+                                         obj_template, otsize);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	goto loser;
+    }
+    while (PR_TRUE) {
+	/* Issue the find for up to arraySize - numHandles objects */
+	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
+	                                 objectHandles + numHandles, 
+	                                 arraySize - numHandles, 
+	                                 &count);
+	if (ckrv != CKR_OK) {
+	    nssSession_ExitMonitor(session);
+	    goto loser;
+	}
+	/* bump the number of found objects */
+	numHandles += count;
+	if (maximumOpt > 0 || numHandles < arraySize) {
+	    /* When a maximum is provided, the search is done all at once,
+	     * so the search is finished.  If the number returned was less 
+	     * than the number sought, the search is finished.
+	     */
+	    break;
+	}
+	/* the array is filled, double it and continue */
+	arraySize *= 2;
+	if (objectHandles == staticObjects) {
+	    objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
+	    if (objectHandles) {
+		PORT_Memcpy(objectHandles, staticObjects, 
+			OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
+	    }
+	} else {
+	    objectHandles = nss_ZREALLOCARRAY(objectHandles, 
+	                                  CK_OBJECT_HANDLE, 
+	                                  arraySize);
+	}
+	if (!objectHandles) {
+	    nssSession_ExitMonitor(session);
+	    ckrv = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+    }
+    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
+    nssSession_ExitMonitor(session); /* ==== end session lock === */
+    if (ckrv != CKR_OK) {
+	goto loser;
+    }
+    if (numHandles > 0) {
+	objects = create_objects_from_handles(tok, session,
+	                                      objectHandles, numHandles);
+    } else {
+	nss_SetError(NSS_ERROR_NOT_FOUND);
+	objects = NULL;
+    }
+    if (objectHandles && objectHandles != staticObjects) {
+	nss_ZFreeIf(objectHandles);
+    }
+    if (statusOpt) *statusOpt = PR_SUCCESS;
+    return objects;
+loser:
+    if (objectHandles && objectHandles != staticObjects) {
+	nss_ZFreeIf(objectHandles);
+    }
+    /*
+     * These errors should be treated the same as if the objects just weren't
+     * found..
+     */
+    if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
+	(ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
+	(ckrv == CKR_DATA_INVALID) ||
+	(ckrv == CKR_DATA_LEN_RANGE) ||
+	(ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
+	(ckrv == CKR_TEMPLATE_INCOMPLETE) ||
+	(ckrv == CKR_TEMPLATE_INCONSISTENT)) {
+
+	nss_SetError(NSS_ERROR_NOT_FOUND);
+	if (statusOpt) *statusOpt = PR_SUCCESS;
+    } else {
+	nss_SetError(ckrv);
+	nss_SetError(NSS_ERROR_PKCS11);
+	if (statusOpt) *statusOpt = PR_FAILURE;
+    }
+    return (nssCryptokiObject **)NULL;
+}
+
+static nssCryptokiObject **
+find_objects_by_template (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG otsize,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
+    nssCryptokiObject **objects = NULL;
+    PRUint32 i;
+
+    if (!token) {
+    	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	if (statusOpt) 
+	    *statusOpt = PR_FAILURE;
+	return NULL;
+    }
+    for (i=0; i<otsize; i++) {
+	if (obj_template[i].type == CKA_CLASS) {
+	    objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
+	    break;
+	}
+    }
+    PR_ASSERT(i < otsize);
+    if (i == otsize) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	if (statusOpt) *statusOpt = PR_FAILURE;
+	return NULL;
+    }
+    /* If these objects are being cached, try looking there first */
+    if (token->cache && 
+        nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) 
+    {
+	PRStatus status;
+	objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
+	                                                    objclass,
+	                                                    obj_template,
+	                                                    otsize,
+	                                                    maximumOpt,
+	                                                    &status);
+	if (status == PR_SUCCESS) {
+	    if (statusOpt) *statusOpt = status;
+	    return objects;
+	}
+    }
+    /* Either they are not cached, or cache failed; look on token. */
+    objects = find_objects(token, sessionOpt, 
+                           obj_template, otsize, 
+                           maximumOpt, statusOpt);
+    return objects;
+}
+
+extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_ImportCertificate (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSCertificateType certType,
+  NSSItem *id,
+  const NSSUTF8 *nickname,
+  NSSDER *encoding,
+  NSSDER *issuer,
+  NSSDER *subject,
+  NSSDER *serial,
+  NSSASCII7 *email,
+  PRBool asTokenObject
+)
+{
+    PRStatus status;
+    CK_CERTIFICATE_TYPE cert_type;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE cert_tmpl[10];
+    CK_ULONG ctsize;
+    nssTokenSearchType searchType;
+    nssCryptokiObject *rvObject = NULL;
+
+    if (!tok) {
+    	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+    if (certType == NSSCertificateType_PKIX) {
+	cert_type = CKC_X_509;
+    } else {
+	return (nssCryptokiObject *)NULL;
+    }
+    NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
+    if (asTokenObject) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+	searchType = nssTokenSearchType_TokenOnly;
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+	searchType = nssTokenSearchType_SessionOnly;
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,            &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE,  cert_type);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,                id);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL,             nickname);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,             encoding);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,            issuer);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,           subject);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,     serial);
+    if (email) {
+	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL,    email);
+    }
+    NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
+    /* see if the cert is already there */
+    rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
+                                                               sessionOpt,
+                                                               issuer,
+                                                               serial,
+                                                               searchType,
+                                                               NULL);
+    if (rvObject) {
+	NSSItem existingDER;
+	NSSSlot *slot = nssToken_GetSlot(tok);
+	nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
+	if (!session) {
+	    nssCryptokiObject_Destroy(rvObject);
+	    nssSlot_Destroy(slot);
+	    return (nssCryptokiObject *)NULL;
+	}
+	/* Reject any attempt to import a new cert that has the same
+	 * issuer/serial as an existing cert, but does not have the
+	 * same encoding
+	 */
+	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
+	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
+	status = nssCKObject_GetAttributes(rvObject->handle, 
+	                                   cert_tmpl, ctsize, NULL,
+	                                   session, slot);
+	NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
+	if (status == PR_SUCCESS) {
+	    if (!nssItem_Equal(encoding, &existingDER, NULL)) {
+		nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
+		status = PR_FAILURE;
+	    }
+	    nss_ZFreeIf(existingDER.data);
+	}
+	if (status == PR_FAILURE) {
+	    nssCryptokiObject_Destroy(rvObject);
+	    nssSession_Destroy(session);
+	    nssSlot_Destroy(slot);
+	    return (nssCryptokiObject *)NULL;
+	}
+	/* according to PKCS#11, label, ID, issuer, and serial number 
+	 * may change after the object has been created.  For PKIX, the
+	 * last two attributes can't change, so for now we'll only worry
+	 * about the first two.
+	 */
+	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,    id);
+	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
+	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
+	/* reset the mutable attributes on the token */
+	nssCKObject_SetAttributes(rvObject->handle, 
+	                          cert_tmpl, ctsize,
+	                          session, slot);
+	if (!rvObject->label && nickname) {
+	    rvObject->label = nssUTF8_Duplicate(nickname, NULL);
+	}
+	nssSession_Destroy(session);
+	nssSlot_Destroy(slot);
+    } else {
+	/* Import the certificate onto the token */
+	rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
+    }
+    if (rvObject && tok->cache) {
+	/* The cache will overwrite the attributes if the object already
+	 * exists.
+	 */
+	nssTokenObjectCache_ImportObject(tok->cache, rvObject,
+	                                 CKO_CERTIFICATE,
+	                                 cert_tmpl, ctsize);
+    }
+    return rvObject;
+}
+
+/* traverse all objects of the given class - this should only happen
+ * if the token has been marked as "traversable"
+ */
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindObjects (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  CK_OBJECT_CLASS objclass,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE obj_template[2];
+    CK_ULONG obj_size;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly ||
+               searchType == nssTokenSearchType_TokenForced) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, objclass);
+    NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
+
+    if (searchType == nssTokenSearchType_TokenForced) {
+	objects = find_objects(token, sessionOpt,
+	                       obj_template, obj_size,
+	                       maximumOpt, statusOpt);
+    } else {
+	objects = find_objects_by_template(token, sessionOpt,
+	                                   obj_template, obj_size,
+	                                   maximumOpt, statusOpt);
+    }
+    return objects;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesBySubject (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE subj_template[3];
+    CK_ULONG stsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
+    NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       subj_template, stsize,
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesByNickname (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  const NSSUTF8 *name,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE nick_template[3];
+    CK_ULONG ntsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       nick_template, ntsize, 
+                                       maximumOpt, statusOpt);
+    if (!objects) {
+	/* This is to workaround the fact that PKCS#11 doesn't specify
+	 * whether the '\0' should be included.  XXX Is that still true?
+	 * im - this is not needed by the current softoken.  However, I'm 
+	 * leaving it in until I have surveyed more tokens to see if it needed.
+	 * well, its needed by the builtin token...
+	 */
+	nick_template[0].ulValueLen++;
+	objects = find_objects_by_template(token, sessionOpt,
+	                                   nick_template, ntsize, 
+	                                   maximumOpt, statusOpt);
+    }
+    return objects;
+}
+
+/* XXX
+ * This function *does not* use the token object cache, because not even
+ * the softoken will return a value for CKA_NETSCAPE_EMAIL from a call
+ * to GetAttributes.  The softoken does allow searches with that attribute,
+ * it just won't return a value for it.
+ */
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesByEmail (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSASCII7 *email,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE email_template[3];
+    CK_ULONG etsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(email_template, attr, etsize);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL, email);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects(token, sessionOpt,
+                           email_template, etsize,
+                           maximumOpt, statusOpt);
+    if (!objects) {
+	/* This is to workaround the fact that PKCS#11 doesn't specify
+	 * whether the '\0' should be included.  XXX Is that still true?
+	 * im - this is not needed by the current softoken.  However, I'm 
+	 * leaving it in until I have surveyed more tokens to see if it needed.
+	 * well, its needed by the builtin token...
+	 */
+	email_template[0].ulValueLen++;
+	objects = find_objects(token, sessionOpt,
+	                       email_template, etsize,
+	                       maximumOpt, statusOpt);
+    }
+    return objects;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesByID (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *id,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE id_template[3];
+    CK_ULONG idtsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       id_template, idtsize,
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+/*
+ * decode the serial item and return our result.
+ * NOTE serialDecode's data is really stored in serial. Don't free it.
+ */
+static PRStatus
+nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
+{
+    unsigned char *data = (unsigned char *)serial->data;
+    int data_left, data_len, index;
+
+    if ((serial->size >= 3) && (data[0] == 0x2)) {
+	/* remove the der encoding of the serial number before generating the
+	 * key.. */
+	data_left = serial->size-2;
+	data_len = data[1];
+	index = 2;
+
+	/* extended length ? (not very likely for a serial number) */
+	if (data_len & 0x80) {
+	    int len_count = data_len & 0x7f;
+
+	    data_len = 0;
+	    data_left -= len_count;
+	    if (data_left > 0) {
+		while (len_count --) {
+		    data_len = (data_len << 8) | data[index++];
+		}
+	    } 
+	}
+	/* XXX leaving any leading zeros on the serial number for backwards
+	 * compatibility
+	 */
+	/* not a valid der, must be just an unlucky serial number value */
+	if (data_len == data_left) {
+	    serialDecode->size = data_len;
+	    serialDecode->data = &data[index];
+	    return PR_SUCCESS;
+	}
+    }
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindCertificateByIssuerAndSerialNumber (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *issuer,
+  NSSDER *serial,
+  nssTokenSearchType searchType,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE_PTR serialAttr;
+    CK_ATTRIBUTE cert_template[4];
+    CK_ULONG ctsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvObject = NULL;
+    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
+
+    if (!token) {
+    	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	if (statusOpt) 
+	    *statusOpt = PR_FAILURE;
+	return NULL;
+    }
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if ((searchType == nssTokenSearchType_TokenOnly) ||
+               (searchType == nssTokenSearchType_TokenForced)) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    /* Set the unique id */
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,         &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         issuer);
+    serialAttr = attr;
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,  serial);
+    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
+    /* get the object handle */
+    if (searchType == nssTokenSearchType_TokenForced) {
+	objects = find_objects(token, sessionOpt,
+	                       cert_template, ctsize,
+	                       1, statusOpt);
+    } else {
+	objects = find_objects_by_template(token, sessionOpt,
+                                       cert_template, ctsize,
+                                       1, statusOpt);
+    }
+    if (objects) {
+	rvObject = objects[0];
+	nss_ZFreeIf(objects);
+    }
+
+    /*
+     * NSS used to incorrectly store serial numbers in their decoded form.
+     * because of this old tokens have decoded serial numbers.
+     */
+    if (!objects) {
+	NSSItem serialDecode;
+	PRStatus status;
+
+	status = nssToken_decodeSerialItem(serial, &serialDecode);
+	if (status != PR_SUCCESS) {
+	    return NULL;
+	}
+    	NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
+	if (searchType == nssTokenSearchType_TokenForced) {
+	    objects = find_objects(token, sessionOpt,
+	                       cert_template, ctsize,
+	                       1, statusOpt);
+	} else {
+	    objects = find_objects_by_template(token, sessionOpt,
+                                       cert_template, ctsize,
+                                       1, statusOpt);
+	}
+	if (objects) {
+	    rvObject = objects[0];
+	    nss_ZFreeIf(objects);
+	}
+    }
+    return rvObject;
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindCertificateByEncodedCertificate (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSBER *encodedCertificate,
+  nssTokenSearchType searchType,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE cert_template[3];
+    CK_ULONG ctsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvObject = NULL;
+    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
+    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
+    /* get the object handle */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       cert_template, ctsize,
+                                       1, statusOpt);
+    if (objects) {
+	rvObject = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return rvObject;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindPrivateKeys (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE key_template[2];
+    CK_ULONG ktsize;
+    nssCryptokiObject **objects;
+
+    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
+
+    objects = find_objects_by_template(token, sessionOpt,
+                                       key_template, ktsize, 
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+/* XXX ?there are no session cert objects, so only search token objects */
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindPrivateKeyByID (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *keyID
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE key_template[3];
+    CK_ULONG ktsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvKey = NULL;
+
+    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
+    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
+
+    objects = find_objects_by_template(token, sessionOpt,
+                                       key_template, ktsize, 
+                                       1, NULL);
+    if (objects) {
+	rvKey = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return rvKey;
+}
+
+/* XXX ?there are no session cert objects, so only search token objects */
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindPublicKeyByID (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *keyID
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE key_template[3];
+    CK_ULONG ktsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvKey = NULL;
+
+    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
+    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
+
+    objects = find_objects_by_template(token, sessionOpt,
+                                       key_template, ktsize, 
+                                       1, NULL);
+    if (objects) {
+	rvKey = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return rvKey;
+}
+
+static void
+sha1_hash(NSSItem *input, NSSItem *output)
+{
+    NSSAlgorithmAndParameters *ap;
+    PK11SlotInfo *internal = PK11_GetInternalSlot();
+    NSSToken *token = PK11Slot_GetNSSToken(internal);
+    ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
+    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
+    PK11_FreeSlot(token->pk11slot);
+    nss_ZFreeIf(ap);
+}
+
+static void
+md5_hash(NSSItem *input, NSSItem *output)
+{
+    NSSAlgorithmAndParameters *ap;
+    PK11SlotInfo *internal = PK11_GetInternalSlot();
+    NSSToken *token = PK11Slot_GetNSSToken(internal);
+    ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
+    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
+    PK11_FreeSlot(token->pk11slot);
+    nss_ZFreeIf(ap);
+}
+
+static CK_TRUST
+get_ck_trust (
+  nssTrustLevel nssTrust
+)
+{
+    CK_TRUST t;
+    switch (nssTrust) {
+    case nssTrustLevel_NotTrusted: t = CKT_NETSCAPE_UNTRUSTED; break;
+    case nssTrustLevel_TrustedDelegator: t = CKT_NETSCAPE_TRUSTED_DELEGATOR; 
+	break;
+    case nssTrustLevel_ValidDelegator: t = CKT_NETSCAPE_VALID_DELEGATOR; break;
+    case nssTrustLevel_Trusted: t = CKT_NETSCAPE_TRUSTED; break;
+    case nssTrustLevel_Valid: t = CKT_NETSCAPE_VALID; break;
+    case nssTrustLevel_Unknown:
+    default: t = CKT_NETSCAPE_TRUST_UNKNOWN; break;
+    }
+    return t;
+}
+ 
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_ImportTrust (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSDER *certEncoding,
+  NSSDER *certIssuer,
+  NSSDER *certSerial,
+  nssTrustLevel serverAuth,
+  nssTrustLevel clientAuth,
+  nssTrustLevel codeSigning,
+  nssTrustLevel emailProtection,
+  PRBool stepUpApproved,
+  PRBool asTokenObject
+)
+{
+    nssCryptokiObject *object;
+    CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
+    CK_TRUST ckSA, ckCA, ckCS, ckEP;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE trust_tmpl[11];
+    CK_ULONG tsize;
+    PRUint8 sha1[20]; /* this is cheating... */
+    PRUint8 md5[16];
+    NSSItem sha1_result, md5_result;
+    sha1_result.data = sha1; sha1_result.size = sizeof sha1;
+    md5_result.data = md5; md5_result.size = sizeof md5;
+    sha1_hash(certEncoding, &sha1_result);
+    md5_hash(certEncoding, &md5_result);
+    ckSA = get_ck_trust(serverAuth);
+    ckCA = get_ck_trust(clientAuth);
+    ckCS = get_ck_trust(codeSigning);
+    ckEP = get_ck_trust(emailProtection);
+    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
+    if (asTokenObject) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,           tobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,          certIssuer);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,   certSerial);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH,  &md5_result);
+    /* now set the trust values */
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      ckSA);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      ckCA);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     ckCS);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
+    if (stepUpApproved) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
+	                          &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
+	                          &g_ck_false);
+    }
+    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
+    /* import the trust object onto the token */
+    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
+    if (object && tok->cache) {
+	nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
+	                                 trust_tmpl, tsize);
+    }
+    return object;
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindTrustForCertificate (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *certEncoding,
+  NSSDER *certIssuer,
+  NSSDER *certSerial,
+  nssTokenSearchType searchType
+)
+{
+    CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE tobj_template[5];
+    CK_ULONG tobj_size;
+    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
+    nssCryptokiObject *object = NULL, **objects;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return object;
+    }
+
+    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,          tobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         certIssuer);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
+    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
+    objects = find_objects_by_template(token, session,
+                                       tobj_template, tobj_size,
+                                       1, NULL);
+    if (objects) {
+	object = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return object;
+}
+ 
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_ImportCRL (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  NSSDER *encoding,
+  PRBool isKRL,
+  NSSUTF8 *url,
+  PRBool asTokenObject
+)
+{
+    nssCryptokiObject *object;
+    CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE crl_tmpl[6];
+    CK_ULONG crlsize;
+
+    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
+    if (asTokenObject) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,        crlobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,      subject);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,        encoding);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_URL, url);
+    if (isKRL) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_false);
+    }
+    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
+
+    /* import the crl object onto the token */
+    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
+    if (object && token->cache) {
+	nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
+	                                 crl_tmpl, crlsize);
+    }
+    return object;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCRLsBySubject (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE crlobj_template[3];
+    CK_ULONG crlobj_size;
+    nssCryptokiObject **objects = NULL;
+    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return objects;
+    }
+
+    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly ||
+               searchType == nssTokenSearchType_TokenForced) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
+    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
+
+    objects = find_objects_by_template(token, session,
+                                       crlobj_template, crlobj_size,
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_GetCachedObjectAttributes (
+  NSSToken *token,
+  NSSArena *arenaOpt,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR atemplate,
+  CK_ULONG atlen
+)
+{
+    if (!token->cache) {
+	return PR_FAILURE;
+    }
+    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
+                                                   object, objclass,
+                                                   atemplate, atlen);
+}
+
+NSS_IMPLEMENT NSSItem *
+nssToken_Digest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSAlgorithmAndParameters *ap,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    CK_RV ckrv;
+    CK_ULONG digestLen;
+    CK_BYTE_PTR digest;
+    NSSItem *rvItem = NULL;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return rvItem;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	return NULL;
+    }
+#if 0
+    /* XXX the standard says this should work, but it doesn't */
+    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	return NULL;
+    }
+#endif
+    digestLen = 0; /* XXX for now */
+    digest = NULL;
+    if (rvOpt) {
+	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
+	    nssSession_ExitMonitor(session);
+	    /* the error should be bad args */
+	    return NULL;
+	}
+	if (rvOpt->data) {
+	    digest = rvOpt->data;
+	}
+	digestLen = rvOpt->size;
+    }
+    if (!digest) {
+	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
+	if (!digest) {
+	    nssSession_ExitMonitor(session);
+	    return NULL;
+	}
+    }
+    ckrv = CKAPI(epv)->C_Digest(session->handle, 
+                                (CK_BYTE_PTR)data->data, 
+                                (CK_ULONG)data->size,
+                                (CK_BYTE_PTR)digest,
+                                &digestLen);
+    nssSession_ExitMonitor(session);
+    if (ckrv != CKR_OK) {
+	nss_ZFreeIf(digest);
+	return NULL;
+    }
+    if (!rvOpt) {
+	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
+    }
+    return rvItem;
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_BeginDigest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSAlgorithmAndParameters *ap
+)
+{
+    CK_RV ckrv;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return PR_FAILURE;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
+    nssSession_ExitMonitor(session);
+    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_ContinueDigest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSItem *item
+)
+{
+    CK_RV ckrv;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return PR_FAILURE;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 
+                                      (CK_BYTE_PTR)item->data, 
+                                      (CK_ULONG)item->size);
+    nssSession_ExitMonitor(session);
+    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+nssToken_FinishDigest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    CK_RV ckrv;
+    CK_ULONG digestLen;
+    CK_BYTE_PTR digest;
+    NSSItem *rvItem = NULL;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
+    if (ckrv != CKR_OK || digestLen == 0) {
+	nssSession_ExitMonitor(session);
+	return NULL;
+    }
+    digest = NULL;
+    if (rvOpt) {
+	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
+	    nssSession_ExitMonitor(session);
+	    /* the error should be bad args */
+	    return NULL;
+	}
+	if (rvOpt->data) {
+	    digest = rvOpt->data;
+	}
+	digestLen = rvOpt->size;
+    }
+    if (!digest) {
+	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
+	if (!digest) {
+	    nssSession_ExitMonitor(session);
+	    return NULL;
+	}
+    }
+    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
+    nssSession_ExitMonitor(session);
+    if (ckrv != CKR_OK) {
+	nss_ZFreeIf(digest);
+	return NULL;
+    }
+    if (!rvOpt) {
+	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
+    }
+    return rvItem;
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_IsPresent (
+  NSSToken *token
+)
+{
+    return nssSlot_IsTokenPresent(token->slot);
+}
+
+/* Sigh.  The methods to find objects declared above cause problems with
+ * the low-level object cache in the softoken -- the objects are found in 
+ * toto, then one wave of GetAttributes is done, then another.  Having a 
+ * large number of objects causes the cache to be thrashed, as the objects 
+ * are gone before there's any chance to ask for their attributes.
+ * So, for now, bringing back traversal methods for certs.  This way all of 
+ * the cert's attributes can be grabbed immediately after finding it,
+ * increasing the likelihood that the cache takes care of it.
+ */
+NSS_IMPLEMENT PRStatus
+nssToken_TraverseCertificates (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  nssTokenSearchType searchType,
+  PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
+  void *arg
+)
+{
+    CK_RV ckrv;
+    CK_ULONG count;
+    CK_OBJECT_HANDLE *objectHandles;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE cert_template[2];
+    CK_ULONG ctsize;
+    NSSArena *arena;
+    PRStatus status;
+    PRUint32 arraySize, numHandles;
+    nssCryptokiObject **objects;
+    void *epv = nssToken_GetCryptokiEPV(token);
+    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return PR_FAILURE;
+    }
+
+    /* template for all certs */
+    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly ||
+               searchType == nssTokenSearchType_TokenForced) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
+
+    /* the arena is only for the array of object handles */
+    arena = nssArena_Create();
+    if (!arena) {
+	return PR_FAILURE;
+    }
+    arraySize = OBJECT_STACK_SIZE;
+    numHandles = 0;
+    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
+    if (!objectHandles) {
+	goto loser;
+    }
+    nssSession_EnterMonitor(session); /* ==== session lock === */
+    /* Initialize the find with the template */
+    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
+                                         cert_template, ctsize);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	goto loser;
+    }
+    while (PR_TRUE) {
+	/* Issue the find for up to arraySize - numHandles objects */
+	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
+	                                 objectHandles + numHandles, 
+	                                 arraySize - numHandles, 
+	                                 &count);
+	if (ckrv != CKR_OK) {
+	    nssSession_ExitMonitor(session);
+	    goto loser;
+	}
+	/* bump the number of found objects */
+	numHandles += count;
+	if (numHandles < arraySize) {
+	    break;
+	}
+	/* the array is filled, double it and continue */
+	arraySize *= 2;
+	objectHandles = nss_ZREALLOCARRAY(objectHandles, 
+	                                  CK_OBJECT_HANDLE, 
+	                                  arraySize);
+	if (!objectHandles) {
+	    nssSession_ExitMonitor(session);
+	    goto loser;
+	}
+    }
+    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
+    nssSession_ExitMonitor(session); /* ==== end session lock === */
+    if (ckrv != CKR_OK) {
+	goto loser;
+    }
+    if (numHandles > 0) {
+	objects = create_objects_from_handles(token, session,
+	                                      objectHandles, numHandles);
+	if (objects) {
+	    nssCryptokiObject **op;
+	    for (op = objects; *op; op++) {
+		status = (*callback)(*op, arg);
+	    }
+	    nss_ZFreeIf(objects);
+	}
+    }
+    nssArena_Destroy(arena);
+    return PR_SUCCESS;
+loser:
+    nssArena_Destroy(arena);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_IsPrivateKeyAvailable (
+  NSSToken *token,
+  NSSCertificate *c,
+  nssCryptokiObject *instance
+)
+{
+    CK_OBJECT_CLASS theClass;
+
+    if (token == NULL) return PR_FALSE;
+    if (c == NULL) return PR_FALSE;
+
+    theClass = CKO_PRIVATE_KEY;
+    if (!nssSlot_IsLoggedIn(token->slot)) {
+	theClass = CKO_PUBLIC_KEY;
+    }
+    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) 
+						!= CK_INVALID_HANDLE) {
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
diff --git a/mozilla/security/nss/lib/dev/devutil.c b/mozilla/security/nss/lib/dev/devutil.c
new file mode 100644
index 0000000..6799c27
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/devutil.c
@@ -0,0 +1,1043 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: devutil.c,v $ $Revision: 1.33 $ $Date: 2008/11/19 20:44:35 $";
+#endif /* DEBUG */
+
+#ifndef DEVM_H
+#include "devm.h"
+#endif /* DEVM_H */
+
+#ifndef CKHELPER_H
+#include "ckhelper.h"
+#endif /* CKHELPER_H */
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssCryptokiObject_Create (
+  NSSToken *t, 
+  nssSession *session,
+  CK_OBJECT_HANDLE h
+)
+{
+    PRStatus status;
+    NSSSlot *slot;
+    nssCryptokiObject *object;
+    CK_BBOOL *isTokenObject;
+    CK_ATTRIBUTE cert_template[] = {
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_LABEL, NULL, 0 }
+    };
+    slot = nssToken_GetSlot(t);
+    status = nssCKObject_GetAttributes(h, cert_template, 2,
+                                       NULL, session, slot);
+    nssSlot_Destroy(slot);
+    if (status != PR_SUCCESS) {
+	/* a failure here indicates a device error */
+	return (nssCryptokiObject *)NULL;
+    }
+    object = nss_ZNEW(NULL, nssCryptokiObject);
+    if (!object) {
+	return (nssCryptokiObject *)NULL;
+    }
+    object->handle = h;
+    object->token = nssToken_AddRef(t);
+    isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
+    object->isTokenObject = *isTokenObject;
+    nss_ZFreeIf(isTokenObject);
+    NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
+    return object;
+}
+
+NSS_IMPLEMENT void
+nssCryptokiObject_Destroy (
+  nssCryptokiObject *object
+)
+{
+    if (object) {
+	nssToken_Destroy(object->token);
+	nss_ZFreeIf(object->label);
+	nss_ZFreeIf(object);
+    }
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssCryptokiObject_Clone (
+  nssCryptokiObject *object
+)
+{
+    nssCryptokiObject *rvObject;
+    rvObject = nss_ZNEW(NULL, nssCryptokiObject);
+    if (rvObject) {
+	rvObject->handle = object->handle;
+	rvObject->token = nssToken_AddRef(object->token);
+	rvObject->isTokenObject = object->isTokenObject;
+	if (object->label) {
+	    rvObject->label = nssUTF8_Duplicate(object->label, NULL);
+	}
+    }
+    return rvObject;
+}
+
+NSS_EXTERN PRBool
+nssCryptokiObject_Equal (
+  nssCryptokiObject *o1,
+  nssCryptokiObject *o2
+)
+{
+    return (o1->token == o2->token && o1->handle == o2->handle);
+}
+
+NSS_IMPLEMENT PRUint32
+nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen)
+{
+    PRInt32 i;
+    for (i = bufLen - 1; i>=0; ) {
+	if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') break;
+	--i;
+    }
+    return (PRUint32)(i + 1);
+}
+
+/*
+ * Slot arrays
+ */
+
+NSS_IMPLEMENT NSSSlot **
+nssSlotArray_Clone (
+  NSSSlot **slots
+)
+{
+    NSSSlot **rvSlots = NULL;
+    NSSSlot **sp = slots;
+    PRUint32 count = 0;
+    while (sp && *sp) count++;
+    if (count > 0) {
+	rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
+	if (rvSlots) {
+	    for (sp = slots, count = 0; *sp; sp++) {
+		rvSlots[count++] = nssSlot_AddRef(*sp);
+	    }
+	}
+    }
+    return rvSlots;
+}
+
+NSS_IMPLEMENT void
+nssSlotArray_Destroy (
+  NSSSlot **slots
+)
+{
+    if (slots) {
+	NSSSlot **slotp;
+	for (slotp = slots; *slotp; slotp++) {
+	    nssSlot_Destroy(*slotp);
+	}
+	nss_ZFreeIf(slots);
+    }
+}
+
+NSS_IMPLEMENT void
+NSSSlotArray_Destroy (
+  NSSSlot **slots
+)
+{
+    nssSlotArray_Destroy(slots);
+}
+
+NSS_IMPLEMENT void
+nssTokenArray_Destroy (
+  NSSToken **tokens
+)
+{
+    if (tokens) {
+	NSSToken **tokenp;
+	for (tokenp = tokens; *tokenp; tokenp++) {
+	    nssToken_Destroy(*tokenp);
+	}
+	nss_ZFreeIf(tokens);
+    }
+}
+
+NSS_IMPLEMENT void
+NSSTokenArray_Destroy (
+  NSSToken **tokens
+)
+{
+    nssTokenArray_Destroy(tokens);
+}
+
+NSS_IMPLEMENT void
+nssCryptokiObjectArray_Destroy (
+  nssCryptokiObject **objects
+)
+{
+    if (objects) {
+	nssCryptokiObject **op;
+	for (op = objects; *op; op++) {
+	    nssCryptokiObject_Destroy(*op);
+	}
+	nss_ZFreeIf(objects);
+    }
+}
+
+/* object cache for token */
+
+typedef struct
+{
+  NSSArena *arena;
+  nssCryptokiObject *object;
+  CK_ATTRIBUTE_PTR attributes;
+  CK_ULONG numAttributes;
+}
+nssCryptokiObjectAndAttributes;
+
+enum {
+  cachedCerts = 0,
+  cachedTrust = 1,
+  cachedCRLs = 2
+} cachedObjectType;
+
+struct nssTokenObjectCacheStr
+{
+  NSSToken *token;
+  PZLock *lock;
+  PRBool loggedIn;
+  PRBool doObjectType[3];
+  PRBool searchedObjectType[3];
+  nssCryptokiObjectAndAttributes **objects[3];
+};
+
+NSS_IMPLEMENT nssTokenObjectCache *
+nssTokenObjectCache_Create (
+  NSSToken *token,
+  PRBool cacheCerts,
+  PRBool cacheTrust,
+  PRBool cacheCRLs
+)
+{
+    nssTokenObjectCache *rvCache;
+    rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
+    if (!rvCache) {
+	goto loser;
+    }
+    rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */
+    if (!rvCache->lock) {
+	goto loser;
+    }
+    rvCache->doObjectType[cachedCerts] = cacheCerts;
+    rvCache->doObjectType[cachedTrust] = cacheTrust;
+    rvCache->doObjectType[cachedCRLs] = cacheCRLs;
+    rvCache->token = token; /* cache goes away with token */
+    return rvCache;
+loser:
+    return (nssTokenObjectCache *)NULL;
+}
+
+static void
+clear_cache (
+  nssTokenObjectCache *cache
+)
+{
+    nssCryptokiObjectAndAttributes **oa;
+    PRUint32 objectType;
+    for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
+	cache->searchedObjectType[objectType] = PR_FALSE;
+	if (!cache->objects[objectType]) {
+	    continue;
+	}
+	for (oa = cache->objects[objectType]; *oa; oa++) {
+	    /* prevent the token from being destroyed */
+	    (*oa)->object->token = NULL;
+	    nssCryptokiObject_Destroy((*oa)->object);
+	    nssArena_Destroy((*oa)->arena);
+	}
+	nss_ZFreeIf(cache->objects[objectType]);
+	cache->objects[objectType] = NULL;
+    }
+}
+
+NSS_IMPLEMENT void
+nssTokenObjectCache_Clear (
+  nssTokenObjectCache *cache
+)
+{
+    if (cache) {
+	PZ_Lock(cache->lock);
+	clear_cache(cache);
+	PZ_Unlock(cache->lock);
+    }
+}
+
+NSS_IMPLEMENT void
+nssTokenObjectCache_Destroy (
+  nssTokenObjectCache *cache
+)
+{
+    if (cache) {
+	clear_cache(cache);
+	PZ_DestroyLock(cache->lock);
+	nss_ZFreeIf(cache);
+    }
+}
+
+NSS_IMPLEMENT PRBool
+nssTokenObjectCache_HaveObjectClass (
+  nssTokenObjectCache *cache,
+  CK_OBJECT_CLASS objclass
+)
+{
+    PRBool haveIt;
+    PZ_Lock(cache->lock);
+    switch (objclass) {
+    case CKO_CERTIFICATE:    haveIt = cache->doObjectType[cachedCerts]; break;
+    case CKO_NETSCAPE_TRUST: haveIt = cache->doObjectType[cachedTrust]; break;
+    case CKO_NETSCAPE_CRL:   haveIt = cache->doObjectType[cachedCRLs];  break;
+    default:                 haveIt = PR_FALSE;
+    }
+    PZ_Unlock(cache->lock);
+    return haveIt;
+}
+
+static nssCryptokiObjectAndAttributes **
+create_object_array (
+  nssCryptokiObject **objects,
+  PRBool *doObjects,
+  PRUint32 *numObjects,
+  PRStatus *status
+)
+{
+    nssCryptokiObjectAndAttributes **rvOandA = NULL;
+    *numObjects = 0;
+    /* There are no objects for this type */
+    if (!objects || !*objects) {
+	*status = PR_SUCCESS;
+	return rvOandA;
+    }
+    while (*objects++) (*numObjects)++;
+    if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
+	/* Hit the maximum allowed, so don't use a cache (there are
+	 * too many objects to make caching worthwhile, presumably, if
+	 * the token can handle that many objects, it can handle searching.
+	 */
+	*doObjects = PR_FALSE;
+	*status = PR_FAILURE;
+	*numObjects = 0;
+    } else {
+	rvOandA = nss_ZNEWARRAY(NULL, 
+	                        nssCryptokiObjectAndAttributes *, 
+	                        *numObjects + 1);
+	*status = rvOandA ? PR_SUCCESS : PR_FAILURE;
+    }
+    return rvOandA;
+}
+
+static nssCryptokiObjectAndAttributes *
+create_object (
+  nssCryptokiObject *object,
+  const CK_ATTRIBUTE_TYPE *types,
+  PRUint32 numTypes,
+  PRStatus *status
+)
+{
+    PRUint32 j;
+    NSSArena *arena = NULL;
+    NSSSlot *slot = NULL;
+    nssSession *session = NULL;
+    nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
+
+    slot = nssToken_GetSlot(object->token);
+    if (!slot) {
+        nss_SetError(NSS_ERROR_INVALID_POINTER);
+        goto loser;
+    }
+    session = nssToken_GetDefaultSession(object->token);
+    if (!session) {
+        nss_SetError(NSS_ERROR_INVALID_POINTER);
+        goto loser;
+    }
+    arena = nssArena_Create();
+    if (!arena) {
+	goto loser;
+    }
+    rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
+    if (!rvCachedObject) {
+	goto loser;
+    }
+    rvCachedObject->arena = arena;
+    /* The cache is tied to the token, and therefore the objects
+     * in it should not hold references to the token.
+     */
+    nssToken_Destroy(object->token);
+    rvCachedObject->object = object;
+    rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
+    if (!rvCachedObject->attributes) {
+	goto loser;
+    }
+    for (j=0; j<numTypes; j++) {
+	rvCachedObject->attributes[j].type = types[j];
+    }
+    *status = nssCKObject_GetAttributes(object->handle,
+                                        rvCachedObject->attributes,
+                                        numTypes,
+                                        arena,
+                                        session,
+                                        slot);
+    if (*status != PR_SUCCESS) {
+	goto loser;
+    }
+    rvCachedObject->numAttributes = numTypes;
+    *status = PR_SUCCESS;
+    nssSlot_Destroy(slot);
+
+    return rvCachedObject;
+loser:
+    *status = PR_FAILURE;
+    if (slot) {
+	nssSlot_Destroy(slot);
+    }
+    if (arena)
+	nssArena_Destroy(arena);
+    return (nssCryptokiObjectAndAttributes *)NULL;
+}
+
+/*
+ *
+ * State diagram for cache:
+ *
+ *            token !present            token removed
+ *        +-------------------------+<----------------------+
+ *        |                         ^                       |
+ *        v                         |                       |
+ *  +----------+   slot friendly    |  token present   +----------+ 
+ *  |   cache  | -----------------> % ---------------> |   cache  |
+ *  | unloaded |                                       |  loaded  |
+ *  +----------+                                       +----------+
+ *    ^   |                                                 ^   |
+ *    |   |   slot !friendly           slot logged in       |   |
+ *    |   +-----------------------> % ----------------------+   |
+ *    |                             |                           |
+ *    | slot logged out             v  slot !friendly           |
+ *    +-----------------------------+<--------------------------+
+ *
+ */
+
+/* This function must not be called with cache->lock locked. */
+static PRBool
+token_is_present (
+  nssTokenObjectCache *cache
+)
+{
+    NSSSlot *slot = nssToken_GetSlot(cache->token);
+    PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
+    nssSlot_Destroy(slot);
+    return tokenPresent;
+}
+
+static PRBool
+search_for_objects (
+  nssTokenObjectCache *cache
+)
+{
+    PRBool doSearch = PR_FALSE;
+    NSSSlot *slot = nssToken_GetSlot(cache->token);
+    /* Handle non-friendly slots (slots which require login for objects) */
+    if (!nssSlot_IsFriendly(slot)) {
+	if (nssSlot_IsLoggedIn(slot)) {
+	    /* Either no state change, or went from !logged in -> logged in */
+	    cache->loggedIn = PR_TRUE;
+	    doSearch = PR_TRUE;
+	} else {
+	    if (cache->loggedIn) {
+		/* went from logged in -> !logged in, destroy cached objects */
+		clear_cache(cache);
+		cache->loggedIn = PR_FALSE;
+	    } /* else no state change, still not logged in, so exit */
+	}
+    } else {
+	/* slot is friendly, thus always available for search */
+	doSearch = PR_TRUE;
+    }
+    nssSlot_Destroy(slot);
+    return doSearch;
+}
+
+static nssCryptokiObjectAndAttributes *
+create_cert (
+  nssCryptokiObject *object,
+  PRStatus *status
+)
+{
+    static const CK_ATTRIBUTE_TYPE certAttr[] = {
+	CKA_CLASS,
+	CKA_TOKEN,
+	CKA_LABEL,
+	CKA_CERTIFICATE_TYPE,
+	CKA_ID,
+	CKA_VALUE,
+	CKA_ISSUER,
+	CKA_SERIAL_NUMBER,
+	CKA_SUBJECT,
+	CKA_NETSCAPE_EMAIL
+    };
+    static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
+    return create_object(object, certAttr, numCertAttr, status);
+}
+
+static nssCryptokiObjectAndAttributes *
+create_trust (
+  nssCryptokiObject *object,
+  PRStatus *status
+)
+{
+    static const CK_ATTRIBUTE_TYPE trustAttr[] = {
+	CKA_CLASS,
+	CKA_TOKEN,
+	CKA_LABEL,
+	CKA_CERT_SHA1_HASH,
+	CKA_CERT_MD5_HASH,
+	CKA_ISSUER,
+	CKA_SUBJECT,
+	CKA_TRUST_SERVER_AUTH,
+	CKA_TRUST_CLIENT_AUTH,
+	CKA_TRUST_EMAIL_PROTECTION,
+	CKA_TRUST_CODE_SIGNING
+    };
+    static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]);
+    return create_object(object, trustAttr, numTrustAttr, status);
+}
+
+static nssCryptokiObjectAndAttributes *
+create_crl (
+  nssCryptokiObject *object,
+  PRStatus *status
+)
+{
+    static const CK_ATTRIBUTE_TYPE crlAttr[] = {
+	CKA_CLASS,
+	CKA_TOKEN,
+	CKA_LABEL,
+	CKA_VALUE,
+	CKA_SUBJECT,
+	CKA_NETSCAPE_KRL,
+	CKA_NETSCAPE_URL
+    };
+    static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
+    return create_object(object, crlAttr, numCRLAttr, status);
+}
+
+/* Dispatch to the create function for the object type */
+static nssCryptokiObjectAndAttributes *
+create_object_of_type (
+  nssCryptokiObject *object,
+  PRUint32 objectType,
+  PRStatus *status
+)
+{
+    if (objectType == cachedCerts) {
+	return create_cert(object, status);
+    }
+    if (objectType == cachedTrust) {
+	return create_trust(object, status);
+    }
+    if (objectType == cachedCRLs) {
+	return create_crl(object, status);
+    }
+    return (nssCryptokiObjectAndAttributes *)NULL;
+}
+
+static PRStatus
+get_token_objects_for_cache (
+  nssTokenObjectCache *cache,
+  PRUint32 objectType,
+  CK_OBJECT_CLASS objclass
+)
+{
+    PRStatus status;
+    nssCryptokiObject **objects;
+    PRBool *doIt = &cache->doObjectType[objectType];
+    PRUint32 i, numObjects;
+
+    if (!search_for_objects(cache) || 
+         cache->searchedObjectType[objectType] || 
+        !cache->doObjectType[objectType]) 
+    {
+	/* Either there was a state change that prevents a search
+	 * (token logged out), or the search was already done,
+	 * or objects of this type are not being cached.
+	 */
+	return PR_SUCCESS;
+    }
+    objects = nssToken_FindObjects(cache->token, NULL, objclass,
+                                   nssTokenSearchType_TokenForced,
+                                   MAX_LOCAL_CACHE_OBJECTS, &status);
+    if (status != PR_SUCCESS) {
+	return status;
+    }
+    cache->objects[objectType] = create_object_array(objects,
+                                                     doIt,
+                                                     &numObjects,
+                                                     &status);
+    if (status != PR_SUCCESS) {
+	return status;
+    }
+    for (i=0; i<numObjects; i++) {
+	cache->objects[objectType][i] = create_object_of_type(objects[i],
+	                                                      objectType,
+	                                                      &status);
+	if (status != PR_SUCCESS) {
+	    break;
+	}
+    }
+    if (status == PR_SUCCESS) {
+	nss_ZFreeIf(objects);
+    } else {
+	PRUint32 j;
+	for (j=0; j<i; j++) {
+	    /* sigh */
+	    nssToken_AddRef(cache->objects[objectType][j]->object->token);
+	    nssArena_Destroy(cache->objects[objectType][j]->arena);
+	}
+	nss_ZFreeIf(cache->objects[objectType]);
+	cache->objects[objectType] = NULL;
+	nssCryptokiObjectArray_Destroy(objects);
+    }
+    cache->searchedObjectType[objectType] = PR_TRUE;
+    return status;
+}
+
+static CK_ATTRIBUTE_PTR
+find_attribute_in_object (
+  nssCryptokiObjectAndAttributes *obj,
+  CK_ATTRIBUTE_TYPE attrType
+)
+{
+    PRUint32 j;
+    for (j=0; j<obj->numAttributes; j++) {
+	if (attrType == obj->attributes[j].type) {
+	    return &obj->attributes[j];
+	}
+    }
+    return (CK_ATTRIBUTE_PTR)NULL;
+}
+
+/* Find all objects in the array that match the supplied template */
+static nssCryptokiObject **
+find_objects_in_array (
+  nssCryptokiObjectAndAttributes **objArray,
+  CK_ATTRIBUTE_PTR ot,
+  CK_ULONG otlen,
+  PRUint32 maximumOpt
+)
+{
+    PRIntn oi = 0;
+    PRUint32 i;
+    NSSArena *arena;
+    PRUint32 size = 8;
+    PRUint32 numMatches = 0;
+    nssCryptokiObject **objects = NULL;
+    nssCryptokiObjectAndAttributes **matches = NULL;
+    CK_ATTRIBUTE_PTR attr;
+
+    if (!objArray) {
+	return (nssCryptokiObject **)NULL;
+    }
+    arena = nssArena_Create();
+    if (!arena) {
+	return (nssCryptokiObject **)NULL;
+    }
+    matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
+    if (!matches) {
+	goto loser;
+    }
+    if (maximumOpt == 0) maximumOpt = ~0;
+    /* loop over the cached objects */
+    for (; *objArray && numMatches < maximumOpt; objArray++) {
+	nssCryptokiObjectAndAttributes *obj = *objArray;
+	/* loop over the test template */
+	for (i=0; i<otlen; i++) {
+	    /* see if the object has the attribute */
+	    attr = find_attribute_in_object(obj, ot[i].type);
+	    if (!attr) {
+		/* nope, match failed */
+		break;
+	    }
+	    /* compare the attribute against the test value */
+	    if (ot[i].ulValueLen != attr->ulValueLen ||
+	        !nsslibc_memequal(ot[i].pValue, 
+	                          attr->pValue,
+	                          attr->ulValueLen, NULL))
+	    {
+		/* nope, match failed */
+		break;
+	    }
+	}
+	if (i == otlen) {
+	    /* all of the attributes in the test template were found
+	     * in the object's template, and they all matched
+	     */
+	    matches[numMatches++] = obj;
+	    if (numMatches == size) {
+		size *= 2;
+		matches = nss_ZREALLOCARRAY(matches, 
+		                            nssCryptokiObjectAndAttributes *, 
+		                            size);
+		if (!matches) {
+		    goto loser;
+		}
+	    }
+	}
+    }
+    if (numMatches > 0) {
+	objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
+	if (!objects) {
+	    goto loser;
+	}
+	for (oi=0; oi<(PRIntn)numMatches; oi++) {
+	    objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
+	    if (!objects[oi]) {
+		goto loser;
+	    }
+	}
+    }
+    nssArena_Destroy(arena);
+    return objects;
+loser:
+    if (objects) {
+	for (--oi; oi>=0; --oi) {
+	    nssCryptokiObject_Destroy(objects[oi]);
+	}
+    }
+    nssArena_Destroy(arena);
+    return (nssCryptokiObject **)NULL;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssTokenObjectCache_FindObjectsByTemplate (
+  nssTokenObjectCache *cache,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR otemplate,
+  CK_ULONG otlen,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    PRStatus status = PR_FAILURE;
+    nssCryptokiObject **rvObjects = NULL;
+    PRUint32 objectType;
+    if (!token_is_present(cache)) {
+	status = PR_SUCCESS;
+	goto finish;
+    }
+    switch (objclass) {
+    case CKO_CERTIFICATE:    objectType = cachedCerts; break;
+    case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
+    case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
+    default: goto finish;
+    }
+    PZ_Lock(cache->lock);
+    if (cache->doObjectType[objectType]) {
+	status = get_token_objects_for_cache(cache, objectType, objclass);
+	if (status == PR_SUCCESS) {
+	    rvObjects = find_objects_in_array(cache->objects[objectType], 
+	                                      otemplate, otlen, maximumOpt);
+	}
+    }
+    PZ_Unlock(cache->lock);
+finish:
+    if (statusOpt) {
+	*statusOpt = status;
+    }
+    return rvObjects;
+}
+
+static PRBool
+cache_available_for_object_type (
+  nssTokenObjectCache *cache,
+  PRUint32 objectType
+)
+{
+    if (!cache->doObjectType[objectType]) {
+	/* not caching this object kind */
+	return PR_FALSE;
+    }
+    if (!cache->searchedObjectType[objectType]) {
+	/* objects are not cached yet */
+	return PR_FALSE;
+    }
+    if (!search_for_objects(cache)) {
+	/* not logged in */
+	return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTokenObjectCache_GetObjectAttributes (
+  nssTokenObjectCache *cache,
+  NSSArena *arenaOpt,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR atemplate,
+  CK_ULONG atlen
+)
+{
+    PRUint32 i, j;
+    NSSArena *arena = NULL;
+    nssArenaMark *mark = NULL;
+    nssCryptokiObjectAndAttributes *cachedOA = NULL;
+    nssCryptokiObjectAndAttributes **oa = NULL;
+    PRUint32 objectType;
+    if (!token_is_present(cache)) {
+	return PR_FAILURE;
+    }
+    PZ_Lock(cache->lock);
+    switch (objclass) {
+    case CKO_CERTIFICATE:    objectType = cachedCerts; break;
+    case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
+    case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
+    default: goto loser;
+    }
+    if (!cache_available_for_object_type(cache, objectType)) {
+	goto loser;
+    }
+    oa = cache->objects[objectType];
+    if (!oa) {
+	goto loser;
+    }
+    for (; *oa; oa++) {
+	if (nssCryptokiObject_Equal((*oa)->object, object)) {
+	    cachedOA = *oa;
+	    break;
+	}
+    }
+    if (!cachedOA) {
+	goto loser; /* don't have this object */
+    }
+    if (arenaOpt) {
+	arena = arenaOpt;
+	mark = nssArena_Mark(arena);
+    }
+    for (i=0; i<atlen; i++) {
+	for (j=0; j<cachedOA->numAttributes; j++) {
+	    if (atemplate[i].type == cachedOA->attributes[j].type) {
+		CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
+		if (cachedOA->attributes[j].ulValueLen == 0 ||
+		    cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) 
+		{
+		    break; /* invalid attribute */
+		}
+		if (atemplate[i].ulValueLen > 0) {
+		    if (atemplate[i].pValue == NULL ||
+		        atemplate[i].ulValueLen < attr->ulValueLen) 
+		    {
+			goto loser;
+		    }
+		} else {
+		    atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
+		    if (!atemplate[i].pValue) {
+			goto loser;
+		    }
+		}
+		nsslibc_memcpy(atemplate[i].pValue,
+		               attr->pValue, attr->ulValueLen);
+		atemplate[i].ulValueLen = attr->ulValueLen;
+		break;
+	    }
+	}
+	if (j == cachedOA->numAttributes) {
+	    atemplate[i].ulValueLen = (CK_ULONG)-1;
+	}
+    }
+    PZ_Unlock(cache->lock);
+    if (mark) {
+	nssArena_Unmark(arena, mark);
+    }
+    return PR_SUCCESS;
+loser:
+    PZ_Unlock(cache->lock);
+    if (mark) {
+	nssArena_Release(arena, mark);
+    }
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTokenObjectCache_ImportObject (
+  nssTokenObjectCache *cache,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR ot,
+  CK_ULONG otlen
+)
+{
+    PRStatus status = PR_SUCCESS;
+    PRUint32 count;
+    nssCryptokiObjectAndAttributes **oa, ***otype;
+    PRUint32 objectType;
+    PRBool haveIt = PR_FALSE;
+
+    if (!token_is_present(cache)) {
+	return PR_SUCCESS; /* cache not active, ignored */
+    }
+    PZ_Lock(cache->lock);
+    switch (objclass) {
+    case CKO_CERTIFICATE:    objectType = cachedCerts; break;
+    case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
+    case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
+    default:
+	PZ_Unlock(cache->lock);
+	return PR_SUCCESS; /* don't need to import it here */
+    }
+    if (!cache_available_for_object_type(cache, objectType)) {
+	PZ_Unlock(cache->lock);
+	return PR_SUCCESS; /* cache not active, ignored */
+    }
+    count = 0;
+    otype = &cache->objects[objectType]; /* index into array of types */
+    oa = *otype; /* the array of objects for this type */
+    while (oa && *oa) {
+	if (nssCryptokiObject_Equal((*oa)->object, object)) {
+	    haveIt = PR_TRUE;
+	    break;
+	}
+	count++;
+	oa++;
+    }
+    if (haveIt) {
+	/* Destroy the old entry */
+	(*oa)->object->token = NULL;
+	nssCryptokiObject_Destroy((*oa)->object);
+	nssArena_Destroy((*oa)->arena);
+    } else {
+	/* Create space for a new entry */
+	if (count > 0) {
+	    *otype = nss_ZREALLOCARRAY(*otype,
+	                               nssCryptokiObjectAndAttributes *, 
+	                               count + 2);
+	} else {
+	    *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
+	}
+    }
+    if (*otype) {
+	nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
+	(*otype)[count] = create_object_of_type(copyObject, objectType,
+	                                        &status);
+    } else {
+	status = PR_FAILURE;
+    }
+    PZ_Unlock(cache->lock);
+    return status;
+}
+
+NSS_IMPLEMENT void
+nssTokenObjectCache_RemoveObject (
+  nssTokenObjectCache *cache,
+  nssCryptokiObject *object
+)
+{
+    PRUint32 oType;
+    nssCryptokiObjectAndAttributes **oa, **swp = NULL;
+    if (!token_is_present(cache)) {
+	return;
+    }
+    PZ_Lock(cache->lock);
+    for (oType=0; oType<3; oType++) {
+	if (!cache_available_for_object_type(cache, oType) ||
+	    !cache->objects[oType])
+	{
+	    continue;
+	}
+	for (oa = cache->objects[oType]; *oa; oa++) {
+	    if (nssCryptokiObject_Equal((*oa)->object, object)) {
+		swp = oa; /* the entry to remove */
+		while (oa[1]) oa++; /* go to the tail */
+		(*swp)->object->token = NULL;
+		nssCryptokiObject_Destroy((*swp)->object);
+		nssArena_Destroy((*swp)->arena); /* destroy it */
+		*swp = *oa; /* swap the last with the removed */
+		*oa = NULL; /* null-terminate the array */
+		break;
+	    }
+	}
+	if (swp) {
+	    break;
+	}
+    }
+    if ((oType <3) &&
+		cache->objects[oType] && cache->objects[oType][0] == NULL) {
+	nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
+	cache->objects[oType] = NULL;
+    }
+    PZ_Unlock(cache->lock);
+}
+
+/* These two hash algorithms are presently sufficient.
+** They are used for fingerprints of certs which are stored as the 
+** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
+** We don't need to add SHAxxx to these now.
+*/
+/* XXX of course this doesn't belong here */
+NSS_IMPLEMENT NSSAlgorithmAndParameters *
+NSSAlgorithmAndParameters_CreateSHA1Digest (
+  NSSArena *arenaOpt
+)
+{
+    NSSAlgorithmAndParameters *rvAP = NULL;
+    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
+    if (rvAP) {
+	rvAP->mechanism.mechanism = CKM_SHA_1;
+	rvAP->mechanism.pParameter = NULL;
+	rvAP->mechanism.ulParameterLen = 0;
+    }
+    return rvAP;
+}
+
+NSS_IMPLEMENT NSSAlgorithmAndParameters *
+NSSAlgorithmAndParameters_CreateMD5Digest (
+  NSSArena *arenaOpt
+)
+{
+    NSSAlgorithmAndParameters *rvAP = NULL;
+    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
+    if (rvAP) {
+	rvAP->mechanism.mechanism = CKM_MD5;
+	rvAP->mechanism.pParameter = NULL;
+	rvAP->mechanism.ulParameterLen = 0;
+    }
+    return rvAP;
+}
+
diff --git a/mozilla/security/nss/lib/dev/nssdev.h b/mozilla/security/nss/lib/dev/nssdev.h
new file mode 100644
index 0000000..9dee9e9
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/nssdev.h
@@ -0,0 +1,75 @@
+/* ***** 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 ***** */
+
+#ifndef NSSDEV_H
+#define NSSDEV_H
+
+#ifdef DEBUG
+static const char NSSDEV_CVS_ID[] = "@(#) $RCSfile: nssdev.h,v $ $Revision: 1.3 $ $Date: 2005/01/20 02:25:47 $";
+#endif /* DEBUG */
+/*
+ * nssdev.h
+ *
+ * High-level methods for interaction with cryptoki devices
+ */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+PR_BEGIN_EXTERN_C
+
+/* NSSAlgorithmAndParameters
+ *
+ * NSSAlgorithmAndParameters_CreateSHA1Digest
+ * NSSAlgorithmAndParameters_CreateMD5Digest
+ */
+
+NSS_EXTERN NSSAlgorithmAndParameters *
+NSSAlgorithmAndParameters_CreateSHA1Digest
+(
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSAlgorithmAndParameters *
+NSSAlgorithmAndParameters_CreateMD5Digest
+(
+  NSSArena *arenaOpt
+);
+
+PR_END_EXTERN_C
+
+#endif /* DEV_H */
diff --git a/mozilla/security/nss/lib/dev/nssdevt.h b/mozilla/security/nss/lib/dev/nssdevt.h
new file mode 100644
index 0000000..7b56408
--- /dev/null
+++ b/mozilla/security/nss/lib/dev/nssdevt.h
@@ -0,0 +1,72 @@
+/* ***** 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 ***** */
+
+#ifndef NSSDEVT_H
+#define NSSDEVT_H
+
+#ifdef DEBUG
+static const char NSSDEVT_CVS_ID[] = "@(#) $RCSfile: nssdevt.h,v $ $Revision: 1.5 $ $Date: 2005/01/20 02:25:47 $";
+#endif /* DEBUG */
+
+/*
+ * nssdevt.h
+ *
+ * This file contains definitions for the low-level cryptoki devices.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSModule and NSSSlot -- placeholders for the PKCS#11 types
+ */
+
+typedef struct NSSModuleStr NSSModule;
+
+typedef struct NSSSlotStr NSSSlot;
+
+typedef struct NSSTokenStr NSSToken;
+
+PR_END_EXTERN_C
+
+#endif /* NSSDEVT_H */
diff --git a/mozilla/security/nss/lib/freebl/aeskeywrap.c b/mozilla/security/nss/lib/freebl/aeskeywrap.c
new file mode 100644
index 0000000..b638e8a
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/aeskeywrap.c
@@ -0,0 +1,417 @@
+/*
+ * aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
+ *
+ * ***** 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) 2002
+ * 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 ***** */
+/* $Id: aeskeywrap.c,v 1.5 2008/11/18 19:48:21 rrelyea%redhat.com Exp $ */
+
+/* $Id: aeskeywrap.c,v 1.5 2008/11/18 19:48:21 rrelyea%redhat.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prcpucfg.h"
+#if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
+#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
+#else
+#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
+#endif
+#include "prtypes.h"	/* for PRUintXX */
+#include "secport.h"	/* for PORT_XXX */
+#include "secerr.h"
+#include "blapi.h"	/* for AES_ functions */
+#include "rijndael.h"
+
+struct AESKeyWrapContextStr {
+     unsigned char iv[AES_KEY_WRAP_IV_BYTES];
+     AESContext    aescx;
+};
+
+/******************************************/
+/*
+** AES key wrap algorithm, RFC 3394
+*/
+
+AESKeyWrapContext * 
+AESKeyWrap_AllocateContext(void)
+{
+    AESKeyWrapContext * cx = PORT_New(AESKeyWrapContext);
+    return cx;
+}
+
+SECStatus  
+AESKeyWrap_InitContext(AESKeyWrapContext *cx, 
+		       const unsigned char *key, 
+		       unsigned int keylen,
+		       const unsigned char *iv, 
+		       int x1,
+		       unsigned int encrypt,
+		       unsigned int x2)
+{
+    SECStatus rv = SECFailure;
+    if (!cx) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    	return SECFailure;
+    }
+    if (iv) {
+    	memcpy(cx->iv, iv, sizeof cx->iv);
+    } else {
+	memset(cx->iv, 0xA6, sizeof cx->iv);
+    }
+    rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt, 
+                                  AES_BLOCK_SIZE);
+    return rv;
+}
+
+/*
+** Create a new AES context suitable for AES encryption/decryption.
+** 	"key" raw key data
+** 	"keylen" the number of bytes of key data (16, 24, or 32)
+*/
+extern AESKeyWrapContext *
+AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, 
+                         int encrypt, unsigned int keylen)
+{
+    SECStatus rv;
+    AESKeyWrapContext * cx = AESKeyWrap_AllocateContext();
+    if (!cx) 
+    	return NULL;	/* error is already set */
+    rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0);
+    if (rv != SECSuccess) {
+        PORT_Free(cx);
+	cx = NULL; 	/* error should already be set */
+    }
+    return cx;
+}
+
+/*
+** Destroy a AES KeyWrap context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void 
+AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
+{
+    if (cx) {
+	AES_DestroyContext(&cx->aescx, PR_FALSE);
+/*	memset(cx, 0, sizeof *cx); */
+	if (freeit)
+	    PORT_Free(cx);
+    }
+}
+
+#if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
+
+/* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
+** (Most significant byte first) in memory.  The only ALU operations done
+** on them are increment, decrement, and XOR.  So, on little-endian CPUs,
+** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
+** are simulated in the following code.  This is thought to be faster and
+** simpler than trying to convert the data to little-endian and back.
+*/
+
+/* A and T point to two 64-bit values stored most signficant byte first
+** (big endian).  This function increments the 64-bit value T, and then
+** XORs it with A, changing A.
+*/ 
+static void
+increment_and_xor(unsigned char *A, unsigned char *T)
+{
+    if (!++T[7])
+        if (!++T[6])
+	    if (!++T[5])
+		if (!++T[4])
+		    if (!++T[3])
+			if (!++T[2])
+			    if (!++T[1])
+				 ++T[0];
+
+    A[0] ^= T[0];
+    A[1] ^= T[1];
+    A[2] ^= T[2];
+    A[3] ^= T[3];
+    A[4] ^= T[4];
+    A[5] ^= T[5];
+    A[6] ^= T[6];
+    A[7] ^= T[7];
+}
+
+/* A and T point to two 64-bit values stored most signficant byte first
+** (big endian).  This function XORs T with A, giving a new A, then 
+** decrements the 64-bit value T.
+*/ 
+static void
+xor_and_decrement(unsigned char *A, unsigned char *T)
+{
+    A[0] ^= T[0];
+    A[1] ^= T[1];
+    A[2] ^= T[2];
+    A[3] ^= T[3];
+    A[4] ^= T[4];
+    A[5] ^= T[5];
+    A[6] ^= T[6];
+    A[7] ^= T[7];
+
+    if (!T[7]--)
+        if (!T[6]--)
+	    if (!T[5]--)
+		if (!T[4]--)
+		    if (!T[3]--)
+			if (!T[2]--)
+			    if (!T[1]--)
+				 T[0]--;
+
+}
+
+/* Given an unsigned long t (in host byte order), store this value as a
+** 64-bit big-endian value (MSB first) in *pt.
+*/
+static void
+set_t(unsigned char *pt, unsigned long t)
+{
+    pt[7] = (unsigned char)t; t >>= 8;
+    pt[6] = (unsigned char)t; t >>= 8;
+    pt[5] = (unsigned char)t; t >>= 8;
+    pt[4] = (unsigned char)t; t >>= 8;
+    pt[3] = (unsigned char)t; t >>= 8;
+    pt[2] = (unsigned char)t; t >>= 8;
+    pt[1] = (unsigned char)t; t >>= 8;
+    pt[0] = (unsigned char)t;
+}
+
+#endif
+
+/*
+** Perform AES key wrap.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
+            unsigned int *pOutputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen)
+{
+    PRUint64 *     R          = NULL;
+    unsigned int   nBlocks;
+    unsigned int   i, j;
+    unsigned int   aesLen     = AES_BLOCK_SIZE;
+    unsigned int   outLen     = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
+    SECStatus      s          = SECFailure;
+    /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
+    PRUint64       t;
+    PRUint64       B[2];
+
+#define A B[0]
+
+    /* Check args */
+    if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
+	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	return s;
+    }
+#ifdef maybe
+    if (!output && pOutputLen) {	/* caller is asking for output size */
+    	*pOutputLen = outLen;
+	return SECSuccess;
+    }
+#endif
+    if (maxOutputLen < outLen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return s;
+    }
+    if (cx == NULL || output == NULL || input == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return s;
+    }
+    nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
+    R = PORT_NewArray(PRUint64, nBlocks + 1);
+    if (!R)
+    	return s;	/* error is already set. */
+    /* 
+    ** 1) Initialize variables.
+    */
+    memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
+    memcpy(&R[1], input, inputLen);
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+    t = 0;
+#else
+    memset(&t, 0, sizeof t);
+#endif
+    /* 
+    ** 2) Calculate intermediate values.
+    */
+    for (j = 0; j < 6; ++j) {
+    	for (i = 1; i <= nBlocks; ++i) {
+	    B[1] = R[i];
+	    s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen, 
+	                    sizeof B,  (unsigned char *)B, sizeof B);
+	    if (s != SECSuccess) 
+	        break;
+	    R[i] = B[1];
+	    /* here, increment t and XOR A with t (in big endian order); */
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+   	    A ^= ++t; 
+#else
+	    increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
+#endif
+	}
+    }
+    /* 
+    ** 3) Output the results.
+    */
+    if (s == SECSuccess) {
+    	R[0] =  A;
+	memcpy(output, &R[0], outLen);
+	if (pOutputLen)
+	    *pOutputLen = outLen;
+    } else if (pOutputLen) {
+    	*pOutputLen = 0;
+    }
+    PORT_ZFree(R, outLen);
+    return s;
+}
+#undef A
+
+/*
+** Perform AES key unwrap.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
+            unsigned int *pOutputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen)
+{
+    PRUint64 *     R          = NULL;
+    unsigned int   nBlocks;
+    unsigned int   i, j;
+    unsigned int   aesLen     = AES_BLOCK_SIZE;
+    unsigned int   outLen;
+    SECStatus      s          = SECFailure;
+    /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
+    PRUint64       t;
+    PRUint64       B[2];
+
+#define A B[0]
+
+    /* Check args */
+    if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || 
+        0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
+	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	return s;
+    }
+    outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
+#ifdef maybe
+    if (!output && pOutputLen) {	/* caller is asking for output size */
+    	*pOutputLen = outLen;
+	return SECSuccess;
+    }
+#endif
+    if (maxOutputLen < outLen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return s;
+    }
+    if (cx == NULL || output == NULL || input == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return s;
+    }
+    nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
+    R = PORT_NewArray(PRUint64, nBlocks);
+    if (!R)
+    	return s;	/* error is already set. */
+    nBlocks--;
+    /* 
+    ** 1) Initialize variables.
+    */
+    memcpy(&R[0], input, inputLen);
+    A = R[0];
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+    t = 6UL * nBlocks;
+#else
+    set_t((unsigned char *)&t, 6UL * nBlocks);
+#endif
+    /* 
+    ** 2) Calculate intermediate values.
+    */
+    for (j = 0; j < 6; ++j) {
+    	for (i = nBlocks; i; --i) {
+	    /* here, XOR A with t (in big endian order) and decrement t; */
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+   	    A ^= t--; 
+#else
+	    xor_and_decrement((unsigned char *)&A, (unsigned char *)&t);
+#endif
+	    B[1] = R[i];
+	    s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen, 
+	                    sizeof B,  (unsigned char *)B, sizeof B);
+	    if (s != SECSuccess) 
+	        break;
+	    R[i] = B[1];
+	}
+    }
+    /* 
+    ** 3) Output the results.
+    */
+    if (s == SECSuccess) {
+	int bad = memcmp(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
+	if (!bad) {
+	    memcpy(output, &R[1], outLen);
+	    if (pOutputLen)
+		*pOutputLen = outLen;
+	} else {
+	    PORT_SetError(SEC_ERROR_BAD_DATA);
+	    if (pOutputLen) 
+		*pOutputLen = 0;
+    	}
+    } else if (pOutputLen) {
+    	*pOutputLen = 0;
+    }
+    PORT_ZFree(R, inputLen);
+    return s;
+}
+#undef A
diff --git a/mozilla/security/nss/lib/freebl/alg2268.c b/mozilla/security/nss/lib/freebl/alg2268.c
new file mode 100644
index 0000000..1ba36c2
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/alg2268.c
@@ -0,0 +1,519 @@
+/*
+ * alg2268.c - implementation of the algorithm in RFC 2268
+ *
+ * ***** 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 ***** */
+
+/* $Id: alg2268.c,v 1.9 2009/04/09 22:11:07 julien.pierre.boogz%sun.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "blapi.h"
+#include "secerr.h"
+#ifdef XP_UNIX_XXX
+#include <stddef.h>	/* for ptrdiff_t */
+#endif
+
+/*
+** RC2 symmetric block cypher
+*/
+
+typedef SECStatus (rc2Func)(RC2Context *cx, unsigned char *output,
+		           const unsigned char *input, unsigned int inputLen);
+
+/* forward declarations */
+static rc2Func rc2_EncryptECB;
+static rc2Func rc2_DecryptECB;
+static rc2Func rc2_EncryptCBC;
+static rc2Func rc2_DecryptCBC;
+
+typedef union {
+    PRUint32	l[2];
+    PRUint16	s[4];
+    PRUint8	b[8];
+} RC2Block;
+
+struct RC2ContextStr {
+    union {
+    	PRUint8  Kb[128];
+	PRUint16 Kw[64];
+    } u;
+    RC2Block     iv;
+    rc2Func      *enc;
+    rc2Func      *dec;
+};
+
+#define B u.Kb
+#define K u.Kw
+#define BYTESWAP(x) ((x) << 8 | (x) >> 8)
+#define SWAPK(i)  cx->K[i] = (tmpS = cx->K[i], BYTESWAP(tmpS))
+#define RC2_BLOCK_SIZE 8
+
+#define LOAD_HARD(R) \
+    R[0] = (PRUint16)input[1] << 8 | input[0]; \
+    R[1] = (PRUint16)input[3] << 8 | input[2]; \
+    R[2] = (PRUint16)input[5] << 8 | input[4]; \
+    R[3] = (PRUint16)input[7] << 8 | input[6];
+#define LOAD_EASY(R) \
+    R[0] = ((PRUint16 *)input)[0]; \
+    R[1] = ((PRUint16 *)input)[1]; \
+    R[2] = ((PRUint16 *)input)[2]; \
+    R[3] = ((PRUint16 *)input)[3];
+#define STORE_HARD(R) \
+    output[0] =  (PRUint8)(R[0]);   output[1] = (PRUint8)(R[0] >> 8); \
+    output[2] =  (PRUint8)(R[1]);   output[3] = (PRUint8)(R[1] >> 8); \
+    output[4] =  (PRUint8)(R[2]);   output[5] = (PRUint8)(R[2] >> 8); \
+    output[6] =  (PRUint8)(R[3]);   output[7] = (PRUint8)(R[3] >> 8);
+#define STORE_EASY(R) \
+    ((PRUint16 *)output)[0] =  R[0]; \
+    ((PRUint16 *)output)[1] =  R[1]; \
+    ((PRUint16 *)output)[2] =  R[2]; \
+    ((PRUint16 *)output)[3] =  R[3];   
+
+#if defined (NSS_X86_OR_X64)
+#define LOAD(R)  LOAD_EASY(R)
+#define STORE(R) STORE_EASY(R)
+#elif !defined(IS_LITTLE_ENDIAN)
+#define LOAD(R)  LOAD_HARD(R)
+#define STORE(R) STORE_HARD(R)
+#else
+#define LOAD(R) if ((ptrdiff_t)input & 1) { LOAD_HARD(R) } else { LOAD_EASY(R) }
+#define STORE(R) if ((ptrdiff_t)input & 1) { STORE_HARD(R) } else { STORE_EASY(R) }
+#endif
+
+static const PRUint8 S[256] = {
+0331,0170,0371,0304,0031,0335,0265,0355,0050,0351,0375,0171,0112,0240,0330,0235,
+0306,0176,0067,0203,0053,0166,0123,0216,0142,0114,0144,0210,0104,0213,0373,0242,
+0027,0232,0131,0365,0207,0263,0117,0023,0141,0105,0155,0215,0011,0201,0175,0062,
+0275,0217,0100,0353,0206,0267,0173,0013,0360,0225,0041,0042,0134,0153,0116,0202,
+0124,0326,0145,0223,0316,0140,0262,0034,0163,0126,0300,0024,0247,0214,0361,0334,
+0022,0165,0312,0037,0073,0276,0344,0321,0102,0075,0324,0060,0243,0074,0266,0046,
+0157,0277,0016,0332,0106,0151,0007,0127,0047,0362,0035,0233,0274,0224,0103,0003,
+0370,0021,0307,0366,0220,0357,0076,0347,0006,0303,0325,0057,0310,0146,0036,0327,
+0010,0350,0352,0336,0200,0122,0356,0367,0204,0252,0162,0254,0065,0115,0152,0052,
+0226,0032,0322,0161,0132,0025,0111,0164,0113,0237,0320,0136,0004,0030,0244,0354,
+0302,0340,0101,0156,0017,0121,0313,0314,0044,0221,0257,0120,0241,0364,0160,0071,
+0231,0174,0072,0205,0043,0270,0264,0172,0374,0002,0066,0133,0045,0125,0227,0061,
+0055,0135,0372,0230,0343,0212,0222,0256,0005,0337,0051,0020,0147,0154,0272,0311,
+0323,0000,0346,0317,0341,0236,0250,0054,0143,0026,0001,0077,0130,0342,0211,0251,
+0015,0070,0064,0033,0253,0063,0377,0260,0273,0110,0014,0137,0271,0261,0315,0056,
+0305,0363,0333,0107,0345,0245,0234,0167,0012,0246,0040,0150,0376,0177,0301,0255
+};
+
+RC2Context * RC2_AllocateContext(void)
+{
+    return PORT_ZNew(RC2Context);
+}
+SECStatus   
+RC2_InitContext(RC2Context *cx, const unsigned char *key, unsigned int len,
+	        const unsigned char *input, int mode, unsigned int efLen8, 
+		unsigned int unused)
+{
+    PRUint8    *L,*L2;
+    int         i;
+#if !defined(IS_LITTLE_ENDIAN)
+    PRUint16    tmpS;
+#endif
+    PRUint8     tmpB;
+
+    if (!key || !cx || !len || len > (sizeof cx->B) || 
+	efLen8 > (sizeof cx->B)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    	return SECFailure;
+    }
+    if (mode == NSS_RC2) {
+    	/* groovy */
+    } else if (mode == NSS_RC2_CBC) {
+    	if (!input) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return SECFailure;
+	}
+    } else {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    if (mode == NSS_RC2_CBC) {
+    	cx->enc = & rc2_EncryptCBC;
+	cx->dec = & rc2_DecryptCBC;
+	LOAD(cx->iv.s);
+    } else {
+    	cx->enc = & rc2_EncryptECB;
+	cx->dec = & rc2_DecryptECB;
+    }
+
+    /* Step 0. Copy key into table. */
+    memcpy(cx->B, key, len);
+
+    /* Step 1. Compute all values to the right of the key. */
+    L2 = cx->B;
+    L = L2 + len;
+    tmpB = L[-1];
+    for (i = (sizeof cx->B) - len; i > 0; --i) {
+	*L++ = tmpB = S[ (PRUint8)(tmpB + *L2++) ];
+    }
+
+    /* step 2. Adjust left most byte of effective key. */
+    i = (sizeof cx->B) - efLen8;
+    L = cx->B + i;
+    *L = tmpB = S[*L];				/* mask is always 0xff */
+
+    /* step 3. Recompute all values to the left of effective key. */
+    L2 = --L + efLen8;
+    while(L >= cx->B) {
+	*L-- = tmpB = S[ tmpB ^ *L2-- ];
+    }
+
+#if !defined(IS_LITTLE_ENDIAN)
+    for (i = 63; i >= 0; --i) {
+        SWAPK(i);		/* candidate for unrolling */
+    }
+#endif
+    return SECSuccess;
+}
+
+/*
+** Create a new RC2 context suitable for RC2 encryption/decryption.
+** 	"key" raw key data
+** 	"len" the number of bytes of key data
+** 	"iv" is the CBC initialization vector (if mode is NSS_RC2_CBC)
+** 	"mode" one of NSS_RC2 or NSS_RC2_CBC
+**	"effectiveKeyLen" in bytes, not bits.
+**
+** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block
+** chaining" mode.
+*/
+RC2Context *
+RC2_CreateContext(const unsigned char *key, unsigned int len,
+		  const unsigned char *iv, int mode, unsigned efLen8)
+{
+    RC2Context *cx = PORT_ZNew(RC2Context);
+    if (cx) {
+	SECStatus rv = RC2_InitContext(cx, key, len, iv, mode, efLen8, 0);
+	if (rv != SECSuccess) {
+	    RC2_DestroyContext(cx, PR_TRUE);
+	    cx = NULL;
+	}
+    }
+    return cx;
+}
+
+/*
+** Destroy an RC2 encryption/decryption context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+void 
+RC2_DestroyContext(RC2Context *cx, PRBool freeit)
+{
+    if (cx) {
+	memset(cx, 0, sizeof *cx);
+	if (freeit) {
+	    PORT_Free(cx);
+	}
+    }
+}
+
+#define ROL(x,k) (x << k | x >> (16-k))
+#define MIX(j) \
+    R0 = R0 + cx->K[ 4*j+0] + (R3 & R2) + (~R3 & R1);  R0 = ROL(R0,1);\
+    R1 = R1 + cx->K[ 4*j+1] + (R0 & R3) + (~R0 & R2);  R1 = ROL(R1,2);\
+    R2 = R2 + cx->K[ 4*j+2] + (R1 & R0) + (~R1 & R3);  R2 = ROL(R2,3);\
+    R3 = R3 + cx->K[ 4*j+3] + (R2 & R1) + (~R2 & R0);  R3 = ROL(R3,5)
+#define MASH \
+    R0 = R0 + cx->K[R3 & 63];\
+    R1 = R1 + cx->K[R0 & 63];\
+    R2 = R2 + cx->K[R1 & 63];\
+    R3 = R3 + cx->K[R2 & 63]
+
+/* Encrypt one block */
+static void 
+rc2_Encrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
+{
+    register PRUint16 R0, R1, R2, R3;
+
+    /* step 1. Initialize input. */
+    R0 = input->s[0];
+    R1 = input->s[1];
+    R2 = input->s[2];
+    R3 = input->s[3];
+
+    /* step 2.  Expand Key (already done, in context) */
+    /* step 3.  j = 0 */
+    /* step 4.  Perform 5 mixing rounds. */
+
+    MIX(0);
+    MIX(1);
+    MIX(2);
+    MIX(3);
+    MIX(4);
+
+    /* step 5. Perform 1 mashing round. */
+    MASH;
+
+    /* step 6. Perform 6 mixing rounds. */
+
+    MIX(5);
+    MIX(6);
+    MIX(7);
+    MIX(8);
+    MIX(9);
+    MIX(10);
+
+    /* step 7. Perform 1 mashing round. */
+    MASH;
+
+    /* step 8. Perform 5 mixing rounds. */
+
+    MIX(11);
+    MIX(12);
+    MIX(13);
+    MIX(14);
+    MIX(15);
+
+    /* output results */
+    output->s[0] = R0;
+    output->s[1] = R1;
+    output->s[2] = R2;
+    output->s[3] = R3;
+}
+
+#define ROR(x,k) (x >> k | x << (16-k))
+#define R_MIX(j) \
+    R3 = ROR(R3,5); R3 = R3 - cx->K[ 4*j+3] - (R2 & R1) - (~R2 & R0);  \
+    R2 = ROR(R2,3); R2 = R2 - cx->K[ 4*j+2] - (R1 & R0) - (~R1 & R3);  \
+    R1 = ROR(R1,2); R1 = R1 - cx->K[ 4*j+1] - (R0 & R3) - (~R0 & R2);  \
+    R0 = ROR(R0,1); R0 = R0 - cx->K[ 4*j+0] - (R3 & R2) - (~R3 & R1)
+#define R_MASH \
+    R3 = R3 - cx->K[R2 & 63];\
+    R2 = R2 - cx->K[R1 & 63];\
+    R1 = R1 - cx->K[R0 & 63];\
+    R0 = R0 - cx->K[R3 & 63]
+
+/* Encrypt one block */
+static void 
+rc2_Decrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
+{
+    register PRUint16 R0, R1, R2, R3;
+
+    /* step 1. Initialize input. */
+    R0 = input->s[0];
+    R1 = input->s[1];
+    R2 = input->s[2];
+    R3 = input->s[3];
+
+    /* step 2.  Expand Key (already done, in context) */
+    /* step 3.  j = 63 */
+    /* step 4.  Perform 5 r_mixing rounds. */
+    R_MIX(15);
+    R_MIX(14);
+    R_MIX(13);
+    R_MIX(12);
+    R_MIX(11);
+
+    /* step 5.  Perform 1 r_mashing round. */
+    R_MASH;
+
+    /* step 6.  Perform 6 r_mixing rounds. */
+    R_MIX(10);
+    R_MIX(9);
+    R_MIX(8);
+    R_MIX(7);
+    R_MIX(6);
+    R_MIX(5);
+
+    /* step 7.  Perform 1 r_mashing round. */
+    R_MASH;
+
+    /* step 8.  Perform 5 r_mixing rounds. */
+    R_MIX(4);
+    R_MIX(3);
+    R_MIX(2);
+    R_MIX(1);
+    R_MIX(0);
+
+    /* output results */
+    output->s[0] = R0;
+    output->s[1] = R1;
+    output->s[2] = R2;
+    output->s[3] = R3;
+}
+
+static SECStatus
+rc2_EncryptECB(RC2Context *cx, unsigned char *output,
+	       const unsigned char *input, unsigned int inputLen)
+{
+    RC2Block  iBlock;
+
+    while (inputLen > 0) {
+    	LOAD(iBlock.s)
+	rc2_Encrypt1Block(cx, &iBlock, &iBlock);
+	STORE(iBlock.s)
+	output   += RC2_BLOCK_SIZE;
+	input    += RC2_BLOCK_SIZE;
+	inputLen -= RC2_BLOCK_SIZE;
+    }
+    return SECSuccess;
+}
+
+static SECStatus
+rc2_DecryptECB(RC2Context *cx, unsigned char *output,
+	       const unsigned char *input, unsigned int inputLen)
+{
+    RC2Block  iBlock;
+
+    while (inputLen > 0) {
+    	LOAD(iBlock.s)
+	rc2_Decrypt1Block(cx, &iBlock, &iBlock);
+	STORE(iBlock.s)
+	output   += RC2_BLOCK_SIZE;
+	input    += RC2_BLOCK_SIZE;
+	inputLen -= RC2_BLOCK_SIZE;
+    }
+    return SECSuccess;
+}
+
+static SECStatus
+rc2_EncryptCBC(RC2Context *cx, unsigned char *output,
+	       const unsigned char *input, unsigned int inputLen)
+{
+    RC2Block  iBlock;
+
+    while (inputLen > 0) {
+
+	LOAD(iBlock.s)
+	iBlock.l[0] ^= cx->iv.l[0];
+	iBlock.l[1] ^= cx->iv.l[1];
+	rc2_Encrypt1Block(cx, &iBlock, &iBlock);
+	cx->iv = iBlock;
+	STORE(iBlock.s)
+	output   += RC2_BLOCK_SIZE;
+	input    += RC2_BLOCK_SIZE;
+	inputLen -= RC2_BLOCK_SIZE;
+    }
+    return SECSuccess;
+}
+
+static SECStatus
+rc2_DecryptCBC(RC2Context *cx, unsigned char *output,
+	       const unsigned char *input, unsigned int inputLen)
+{
+    RC2Block  iBlock;
+    RC2Block  oBlock;
+
+    while (inputLen > 0) {
+	LOAD(iBlock.s)
+	rc2_Decrypt1Block(cx, &oBlock, &iBlock);
+	oBlock.l[0] ^= cx->iv.l[0];
+	oBlock.l[1] ^= cx->iv.l[1];
+	cx->iv = iBlock;
+	STORE(oBlock.s)
+	output   += RC2_BLOCK_SIZE;
+	input    += RC2_BLOCK_SIZE;
+	inputLen -= RC2_BLOCK_SIZE;
+    }
+    return SECSuccess;
+}
+
+
+/*
+** Perform RC2 encryption.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+SECStatus RC2_Encrypt(RC2Context *cx, unsigned char *output,
+		      unsigned int *outputLen, unsigned int maxOutputLen,
+		      const unsigned char *input, unsigned int inputLen)
+{
+    SECStatus rv = SECSuccess;
+    if (inputLen) {
+	if (inputLen % RC2_BLOCK_SIZE) {
+	    PORT_SetError(SEC_ERROR_INPUT_LEN);
+	    return SECFailure;
+	}
+	if (maxOutputLen < inputLen) {
+	    PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	    return SECFailure;
+	}
+	rv = (*cx->enc)(cx, output, input, inputLen);
+    }
+    if (rv == SECSuccess) {
+    	*outputLen = inputLen;
+    }
+    return rv;
+}
+
+/*
+** Perform RC2 decryption.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+SECStatus RC2_Decrypt(RC2Context *cx, unsigned char *output,
+		      unsigned int *outputLen, unsigned int maxOutputLen,
+		      const unsigned char *input, unsigned int inputLen)
+{
+    SECStatus rv = SECSuccess;
+    if (inputLen) {
+	if (inputLen % RC2_BLOCK_SIZE) {
+	    PORT_SetError(SEC_ERROR_INPUT_LEN);
+	    return SECFailure;
+	}
+	if (maxOutputLen < inputLen) {
+	    PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	    return SECFailure;
+	}
+	rv = (*cx->dec)(cx, output, input, inputLen);
+    }
+    if (rv == SECSuccess) {
+	*outputLen = inputLen;
+    }
+    return rv;
+}
+
diff --git a/mozilla/security/nss/lib/freebl/alghmac.c b/mozilla/security/nss/lib/freebl/alghmac.c
new file mode 100644
index 0000000..c117d2e
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/alghmac.c
@@ -0,0 +1,197 @@
+/* ***** 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "secport.h"
+#include "hasht.h"
+#include "blapit.h"
+#include "alghmac.h"
+#include "secerr.h"
+
+#define HMAC_PAD_SIZE HASH_BLOCK_LENGTH_MAX
+
+struct HMACContextStr {
+    void *hash;
+    const SECHashObject *hashobj;
+    PRBool        wasAllocated;
+    unsigned char ipad[HMAC_PAD_SIZE];
+    unsigned char opad[HMAC_PAD_SIZE];
+};
+
+void
+HMAC_Destroy(HMACContext *cx, PRBool freeit)
+{
+    if (cx == NULL)
+	return;
+
+    PORT_Assert(!freeit == !cx->wasAllocated);
+    if (cx->hash != NULL) {
+	cx->hashobj->destroy(cx->hash, PR_TRUE);
+	PORT_Memset(cx, 0, sizeof *cx);
+    }
+    if (freeit)
+	PORT_Free(cx);
+}
+
+SECStatus
+HMAC_Init( HMACContext * cx, const SECHashObject *hash_obj, 
+	   const unsigned char *secret, unsigned int secret_len, PRBool isFIPS)
+{
+    unsigned int i;
+    unsigned char hashed_secret[HASH_LENGTH_MAX];
+
+    /* required by FIPS 198 Section 3 */
+    if (isFIPS && secret_len < hash_obj->length/2) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (cx == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    cx->wasAllocated = PR_FALSE;
+    cx->hashobj = hash_obj;
+    cx->hash = cx->hashobj->create();
+    if (cx->hash == NULL)
+	goto loser;
+
+    if (secret_len > cx->hashobj->blocklength) {
+	cx->hashobj->begin( cx->hash);
+	cx->hashobj->update(cx->hash, secret, secret_len);
+	PORT_Assert(cx->hashobj->length <= sizeof hashed_secret);
+	cx->hashobj->end(   cx->hash, hashed_secret, &secret_len, 
+	                 sizeof hashed_secret);
+	if (secret_len != cx->hashobj->length) {
+	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	    goto loser;
+	}
+	secret = (const unsigned char *)&hashed_secret[0];
+    }
+
+    PORT_Memset(cx->ipad, 0x36, cx->hashobj->blocklength);
+    PORT_Memset(cx->opad, 0x5c, cx->hashobj->blocklength);
+
+    /* fold secret into padding */
+    for (i = 0; i < secret_len; i++) {
+	cx->ipad[i] ^= secret[i];
+	cx->opad[i] ^= secret[i];
+    }
+    PORT_Memset(hashed_secret, 0, sizeof hashed_secret);
+    return SECSuccess;
+
+loser:
+    PORT_Memset(hashed_secret, 0, sizeof hashed_secret);
+    if (cx->hash != NULL)
+	cx->hashobj->destroy(cx->hash, PR_TRUE);
+    return SECFailure;
+}
+
+HMACContext *
+HMAC_Create(const SECHashObject *hash_obj, const unsigned char *secret, 
+            unsigned int secret_len, PRBool isFIPS)
+{
+    SECStatus rv;
+    HMACContext * cx = PORT_ZNew(HMACContext);
+    if (cx == NULL)
+	return NULL;
+    rv = HMAC_Init(cx, hash_obj, secret, secret_len, isFIPS);
+    cx->wasAllocated = PR_TRUE;
+    if (rv != SECSuccess) {
+	PORT_Free(cx); /* contains no secret info */
+	cx = NULL;
+    }
+    return cx;
+}
+
+void
+HMAC_Begin(HMACContext *cx)
+{
+    /* start inner hash */
+    cx->hashobj->begin(cx->hash);
+    cx->hashobj->update(cx->hash, cx->ipad, cx->hashobj->blocklength);
+}
+
+void
+HMAC_Update(HMACContext *cx, const unsigned char *data, unsigned int data_len)
+{
+    cx->hashobj->update(cx->hash, data, data_len);
+}
+
+SECStatus
+HMAC_Finish(HMACContext *cx, unsigned char *result, unsigned int *result_len,
+	    unsigned int max_result_len)
+{
+    if (max_result_len < cx->hashobj->length) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    cx->hashobj->end(cx->hash, result, result_len, max_result_len);
+    if (*result_len != cx->hashobj->length)
+	return SECFailure;
+
+    cx->hashobj->begin(cx->hash);
+    cx->hashobj->update(cx->hash, cx->opad, cx->hashobj->blocklength);
+    cx->hashobj->update(cx->hash, result, *result_len);
+    cx->hashobj->end(cx->hash, result, result_len, max_result_len);
+    return SECSuccess;
+}
+
+HMACContext *
+HMAC_Clone(HMACContext *cx)
+{
+    HMACContext *newcx;
+
+    newcx = (HMACContext*)PORT_ZAlloc(sizeof(HMACContext));
+    if (newcx == NULL)
+	goto loser;
+
+    newcx->wasAllocated = PR_TRUE;
+    newcx->hashobj = cx->hashobj;
+    newcx->hash = cx->hashobj->clone(cx->hash);
+    if (newcx->hash == NULL)
+	goto loser;
+    PORT_Memcpy(newcx->ipad, cx->ipad, cx->hashobj->blocklength);
+    PORT_Memcpy(newcx->opad, cx->opad, cx->hashobj->blocklength);
+    return newcx;
+
+loser:
+    HMAC_Destroy(newcx, PR_TRUE);
+    return NULL;
+}
diff --git a/mozilla/security/nss/lib/freebl/alghmac.h b/mozilla/security/nss/lib/freebl/alghmac.h
new file mode 100644
index 0000000..81c5bfa
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/alghmac.h
@@ -0,0 +1,96 @@
+/* ***** 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 ***** */
+
+#ifndef _ALGHMAC_H_
+#define _ALGHMAC_H_
+
+typedef struct HMACContextStr HMACContext;
+
+SEC_BEGIN_PROTOS
+
+/* destroy HMAC context */
+extern void
+HMAC_Destroy(HMACContext *cx, PRBool freeit);
+
+/* create HMAC context
+ *  hash_obj    hash object from SECRawHashObjects[]
+ *  secret	the secret with which the HMAC is performed.
+ *  secret_len	the length of the secret.
+ *  isFIPS	true if conforming to FIPS 198.
+ *
+ * NULL is returned if an error occurs.
+ */
+extern HMACContext *
+HMAC_Create(const SECHashObject *hash_obj, const unsigned char *secret, 
+	    unsigned int secret_len, PRBool isFIPS);
+
+/* like HMAC_Create, except caller allocates HMACContext. */
+SECStatus
+HMAC_Init(HMACContext *cx, const SECHashObject *hash_obj, 
+	  const unsigned char *secret, unsigned int secret_len, PRBool isFIPS);
+
+/* reset HMAC for a fresh round */
+extern void
+HMAC_Begin(HMACContext *cx);
+
+/* update HMAC 
+ *  cx		HMAC Context
+ *  data	the data to perform HMAC on
+ *  data_len	the length of the data to process
+ */
+extern void 
+HMAC_Update(HMACContext *cx, const unsigned char *data, unsigned int data_len);
+
+/* Finish HMAC -- place the results within result
+ *  cx		HMAC context
+ *  result	buffer for resulting hmac'd data
+ *  result_len	where the resultant hmac length is stored
+ *  max_result_len  maximum possible length that can be stored in result
+ */
+extern SECStatus
+HMAC_Finish(HMACContext *cx, unsigned char *result, unsigned int *result_len,
+	    unsigned int max_result_len);
+
+/* clone a copy of the HMAC state.  this is usefult when you would
+ * need to keep a running hmac but also need to extract portions 
+ * partway through the process.
+ */
+extern HMACContext *
+HMAC_Clone(HMACContext *cx);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/freebl/arcfive.c b/mozilla/security/nss/lib/freebl/arcfive.c
new file mode 100644
index 0000000..8028c18
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/arcfive.c
@@ -0,0 +1,121 @@
+/*
+ * arcfive.c - stubs for RC5 - NOT a working implementation!
+ *
+ * ***** 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) 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 ***** */
+/* $Id: arcfive.c,v 1.6 2008/11/18 19:48:21 rrelyea%redhat.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "blapi.h"
+#include "prerror.h"
+
+/******************************************/
+/*
+** RC5 symmetric block cypher -- 64-bit block size
+*/
+
+/*
+** Create a new RC5 context suitable for RC5 encryption/decryption.
+**      "key" raw key data
+**      "len" the number of bytes of key data
+**      "iv" is the CBC initialization vector (if mode is NSS_RC5_CBC)
+**      "mode" one of NSS_RC5 or NSS_RC5_CBC
+**
+** When mode is set to NSS_RC5_CBC the RC5 cipher is run in "cipher block
+** chaining" mode.
+*/
+RC5Context *
+RC5_CreateContext(const SECItem *key, unsigned int rounds,
+                  unsigned int wordSize, const unsigned char *iv, int mode)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return NULL;
+}
+
+/*
+** Destroy an RC5 encryption/decryption context.
+**      "cx" the context
+**      "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+void 
+RC5_DestroyContext(RC5Context *cx, PRBool freeit) 
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+}
+
+/*
+** Perform RC5 encryption.
+**      "cx" the context
+**      "output" the output buffer to store the encrypted data.
+**      "outputLen" how much data is stored in "output". Set by the routine
+**         after some data is stored in output.
+**      "maxOutputLen" the maximum amount of data that can ever be
+**         stored in "output"
+**      "input" the input data
+**      "inputLen" the amount of input data
+*/
+SECStatus 
+RC5_Encrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen, 
+	    unsigned int maxOutputLen, 
+	    const unsigned char *input, unsigned int inputLen)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+/*
+** Perform RC5 decryption.
+**      "cx" the context
+**      "output" the output buffer to store the decrypted data.
+**      "outputLen" how much data is stored in "output". Set by the routine
+**         after some data is stored in output.
+**      "maxOutputLen" the maximum amount of data that can ever be
+**         stored in "output"
+**      "input" the input data
+**      "inputLen" the amount of input data
+*/
+SECStatus 
+RC5_Decrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen, 
+	    unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
diff --git a/mozilla/security/nss/lib/freebl/arcfour.c b/mozilla/security/nss/lib/freebl/arcfour.c
new file mode 100644
index 0000000..38693ce
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/arcfour.c
@@ -0,0 +1,646 @@
+/* arcfour.c - the arc four algorithm.
+ *
+ * ***** 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 ***** */
+
+/* See NOTES ON UMRs, Unititialized Memory Reads, below. */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prerr.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+#include "blapi.h"
+
+/* Architecture-dependent defines */
+
+#if defined(SOLARIS) || defined(HPUX) || defined(i386) || defined(IRIX) || \
+    defined(_WIN64)
+/* Convert the byte-stream to a word-stream */
+#define CONVERT_TO_WORDS
+#endif
+
+#if defined(AIX) || defined(OSF1) || defined(NSS_BEVAND_ARCFOUR)
+/* Treat array variables as words, not bytes, on CPUs that take 
+ * much longer to write bytes than to write words, or when using 
+ * assembler code that required it.
+ */
+#define USE_WORD
+#endif
+
+#if defined(_WIN32_WCE)
+#undef WORD
+#define WORD ARC4WORD
+#endif
+
+#if (defined(IS_64))
+typedef PRUint64 WORD;
+#else
+typedef PRUint32 WORD;
+#endif
+#define WORDSIZE sizeof(WORD)
+
+#if defined(USE_WORD)
+typedef WORD Stype;
+#else
+typedef PRUint8 Stype;
+#endif
+
+#define ARCFOUR_STATE_SIZE 256
+
+#define MASK1BYTE (WORD)(0xff)
+
+#define SWAP(a, b) \
+	tmp = a; \
+	a = b; \
+	b = tmp;
+
+/*
+ * State information for stream cipher.
+ */
+struct RC4ContextStr
+{
+#if defined(NSS_ARCFOUR_IJ_B4_S) || defined(NSS_BEVAND_ARCFOUR)
+	Stype i;
+	Stype j;
+	Stype S[ARCFOUR_STATE_SIZE];
+#else
+	Stype S[ARCFOUR_STATE_SIZE];
+	Stype i;
+	Stype j;
+#endif
+};
+
+/*
+ * array indices [0..255] to initialize cx->S array (faster than loop).
+ */
+static const Stype Kinit[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+RC4Context *
+RC4_AllocateContext(void)
+{
+    return PORT_ZNew(RC4Context);
+}
+
+SECStatus   
+RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
+	        const unsigned char * unused1, int unused2, 
+		unsigned int unused3, unsigned int unused4)
+{
+	int i;
+	PRUint8 j, tmp;
+	PRUint8 K[256];
+	PRUint8 *L;
+
+	/* verify the key length. */
+	PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
+	if (len < 0 || len >= ARCFOUR_STATE_SIZE) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return SECFailure;
+	}
+	if (cx == NULL) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return SECFailure;
+	}
+	/* Initialize the state using array indices. */
+	memcpy(cx->S, Kinit, sizeof cx->S);
+	/* Fill in K repeatedly with values from key. */
+	L = K;
+	for (i = sizeof K; i > len; i-= len) {
+		memcpy(L, key, len);
+		L += len;
+	}
+	memcpy(L, key, i);
+	/* Stir the state of the generator.  At this point it is assumed
+	 * that the key is the size of the state buffer.  If this is not
+	 * the case, the key bytes are repeated to fill the buffer.
+	 */
+	j = 0;
+#define ARCFOUR_STATE_STIR(ii) \
+	j = j + cx->S[ii] + K[ii]; \
+	SWAP(cx->S[ii], cx->S[j]);
+	for (i=0; i<ARCFOUR_STATE_SIZE; i++) {
+		ARCFOUR_STATE_STIR(i);
+	}
+	cx->i = 0;
+	cx->j = 0;
+	return SECSuccess;
+}
+
+
+/*
+ * Initialize a new generator.
+ */
+RC4Context *
+RC4_CreateContext(const unsigned char *key, int len)
+{
+    RC4Context *cx = RC4_AllocateContext();
+    if (cx) {
+	SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0);
+	if (rv != SECSuccess) {
+	    PORT_ZFree(cx, sizeof(*cx));
+	    cx = NULL;
+	}
+    }
+    return cx;
+}
+
+void 
+RC4_DestroyContext(RC4Context *cx, PRBool freeit)
+{
+	if (freeit)
+		PORT_ZFree(cx, sizeof(*cx));
+}
+
+#if defined(NSS_BEVAND_ARCFOUR)
+extern void ARCFOUR(RC4Context *cx, WORD inputLen, 
+	const unsigned char *input, unsigned char *output);
+#else
+/*
+ * Generate the next byte in the stream.
+ */
+#define ARCFOUR_NEXT_BYTE() \
+	tmpSi = cx->S[++tmpi]; \
+	tmpj += tmpSi; \
+	tmpSj = cx->S[tmpj]; \
+	cx->S[tmpi] = tmpSj; \
+	cx->S[tmpj] = tmpSi; \
+	t = tmpSi + tmpSj;
+
+#ifdef CONVERT_TO_WORDS
+/*
+ * Straight ARCFOUR op.  No optimization.
+ */
+static SECStatus 
+rc4_no_opt(RC4Context *cx, unsigned char *output,
+           unsigned int *outputLen, unsigned int maxOutputLen,
+           const unsigned char *input, unsigned int inputLen)
+{
+    PRUint8 t;
+	Stype tmpSi, tmpSj;
+	register PRUint8 tmpi = cx->i;
+	register PRUint8 tmpj = cx->j;
+	unsigned int index;
+	PORT_Assert(maxOutputLen >= inputLen);
+	if (maxOutputLen < inputLen) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return SECFailure;
+	}
+	for (index=0; index < inputLen; index++) {
+		/* Generate next byte from stream. */
+		ARCFOUR_NEXT_BYTE();
+		/* output = next stream byte XOR next input byte */
+		output[index] = cx->S[t] ^ input[index];
+	}
+	*outputLen = inputLen;
+	cx->i = tmpi;
+	cx->j = tmpj;
+	return SECSuccess;
+}
+
+#else
+/* !CONVERT_TO_WORDS */
+
+/*
+ * Byte-at-a-time ARCFOUR, unrolling the loop into 8 pieces.
+ */
+static SECStatus 
+rc4_unrolled(RC4Context *cx, unsigned char *output,
+             unsigned int *outputLen, unsigned int maxOutputLen,
+             const unsigned char *input, unsigned int inputLen)
+{
+	PRUint8 t;
+	Stype tmpSi, tmpSj;
+	register PRUint8 tmpi = cx->i;
+	register PRUint8 tmpj = cx->j;
+	int index;
+	PORT_Assert(maxOutputLen >= inputLen);
+	if (maxOutputLen < inputLen) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return SECFailure;
+	}
+	for (index = inputLen / 8; index-- > 0; input += 8, output += 8) {
+		ARCFOUR_NEXT_BYTE();
+		output[0] = cx->S[t] ^ input[0];
+		ARCFOUR_NEXT_BYTE();
+		output[1] = cx->S[t] ^ input[1];
+		ARCFOUR_NEXT_BYTE();
+		output[2] = cx->S[t] ^ input[2];
+		ARCFOUR_NEXT_BYTE();
+		output[3] = cx->S[t] ^ input[3];
+		ARCFOUR_NEXT_BYTE();
+		output[4] = cx->S[t] ^ input[4];
+		ARCFOUR_NEXT_BYTE();
+		output[5] = cx->S[t] ^ input[5];
+		ARCFOUR_NEXT_BYTE();
+		output[6] = cx->S[t] ^ input[6];
+		ARCFOUR_NEXT_BYTE();
+		output[7] = cx->S[t] ^ input[7];
+	}
+	index = inputLen % 8;
+	if (index) {
+		input += index;
+		output += index;
+		switch (index) {
+		case 7:
+			ARCFOUR_NEXT_BYTE();
+			output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */
+		case 6:
+			ARCFOUR_NEXT_BYTE();
+			output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */
+		case 5:
+			ARCFOUR_NEXT_BYTE();
+			output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */
+		case 4:
+			ARCFOUR_NEXT_BYTE();
+			output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */
+		case 3:
+			ARCFOUR_NEXT_BYTE();
+			output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */
+		case 2:
+			ARCFOUR_NEXT_BYTE();
+			output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */
+		case 1:
+			ARCFOUR_NEXT_BYTE();
+			output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */
+		default:
+			/* FALLTHRU */
+			; /* hp-ux build breaks without this */
+		}
+	}
+	cx->i = tmpi;
+	cx->j = tmpj;
+	*outputLen = inputLen;
+	return SECSuccess;
+}
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+#define ARCFOUR_NEXT4BYTES_L(n) \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n     ); \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n +  8); \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24);
+#else
+#define ARCFOUR_NEXT4BYTES_B(n) \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24); \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n +  8); \
+	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n     );
+#endif
+
+#if (defined(IS_64) && !defined(__sparc)) || defined(NSS_USE_64)
+/* 64-bit wordsize */
+#ifdef IS_LITTLE_ENDIAN
+#define ARCFOUR_NEXT_WORD() \
+	{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); ARCFOUR_NEXT4BYTES_L(32); }
+#else
+#define ARCFOUR_NEXT_WORD() \
+	{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(32); ARCFOUR_NEXT4BYTES_B(0); }
+#endif
+#else
+/* 32-bit wordsize */
+#ifdef IS_LITTLE_ENDIAN
+#define ARCFOUR_NEXT_WORD() \
+	{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); }
+#else
+#define ARCFOUR_NEXT_WORD() \
+	{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(0); }
+#endif
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+#define RSH <<
+#define LSH >>
+#else
+#define RSH >>
+#define LSH <<
+#endif
+
+#ifdef CONVERT_TO_WORDS
+/* NOTE about UMRs, Uninitialized Memory Reads.
+ *
+ * This code reads all input data a WORD at a time, rather than byte at 
+ * a time, and writes all output data a WORD at a time.  Shifting and 
+ * masking is used to remove unwanted data and realign bytes when 
+ * needed.  The first and last words of output are read, modified, and
+ * written when needed to preserve any unchanged bytes.  This is a huge
+ * win on machines with high memory latency.  
+ *
+ * However, when the input and output buffers do not begin and end on WORD 
+ * boundaries, and the WORDS in memory that contain the first and last 
+ * bytes of those buffers contain uninitialized data, then this code will 
+ * read those uninitialized bytes, causing a UMR error to be reported by 
+ * some tools.  
+ *
+ * These UMRs are NOT a problem, NOT errors, and do NOT need to be "fixed".
+ * 
+ * All the words read and written contain at least one byte that is 
+ * part of the input data or output data.  No words are read or written
+ * that do not contain data that is part of the buffer.  Therefore, 
+ * these UMRs cannot cause page faults or other problems unless the 
+ * buffers have been assigned to improper addresses that would cause
+ * page faults with or without UMRs.  
+ */
+static SECStatus 
+rc4_wordconv(RC4Context *cx, unsigned char *output,
+             unsigned int *outputLen, unsigned int maxOutputLen,
+             const unsigned char *input, unsigned int inputLen)
+{
+	ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE;
+	ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE;
+	register WORD streamWord, mask;
+	register WORD *pInWord, *pOutWord;
+	register WORD inWord, nextInWord;
+	PRUint8 t;
+	register Stype tmpSi, tmpSj;
+	register PRUint8 tmpi = cx->i;
+	register PRUint8 tmpj = cx->j;
+	unsigned int byteCount;
+	unsigned int bufShift, invBufShift;
+	int i;
+
+	PORT_Assert(maxOutputLen >= inputLen);
+	if (maxOutputLen < inputLen) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return SECFailure;
+	}
+	if (inputLen < 2*WORDSIZE) {
+		/* Ignore word conversion, do byte-at-a-time */
+		return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
+	}
+	*outputLen = inputLen;
+	pInWord = (WORD *)(input - inOffset);
+	if (inOffset < outOffset) {
+		bufShift = 8*(outOffset - inOffset);
+		invBufShift = 8*WORDSIZE - bufShift;
+	} else {
+		invBufShift = 8*(inOffset - outOffset);
+		bufShift = 8*WORDSIZE - invBufShift;
+	}
+	/*****************************************************************/
+	/* Step 1:                                                       */
+	/* If the first output word is partial, consume the bytes in the */
+	/* first partial output word by loading one or two words of      */
+	/* input and shifting them accordingly.  Otherwise, just load    */
+	/* in the first word of input.  At the end of this block, at     */
+	/* least one partial word of input should ALWAYS be loaded.      */
+	/*****************************************************************/
+	if (outOffset) {
+		/* Generate input and stream words aligned relative to the
+		 * partial output buffer.
+		 */
+		byteCount = WORDSIZE - outOffset; 
+		pOutWord = (WORD *)(output - outOffset);
+		mask = streamWord = 0;
+#ifdef IS_LITTLE_ENDIAN
+		for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) {
+#else
+		for (i = byteCount - 1; i >= 0; --i) {
+#endif
+			ARCFOUR_NEXT_BYTE();
+			streamWord |= (WORD)(cx->S[t]) << 8*i;
+			mask |= MASK1BYTE << 8*i;
+		} /* } */
+		inWord = *pInWord++; /* UMR? see comments above. */
+		/* If buffers are relatively misaligned, shift the bytes in inWord
+		 * to be aligned to the output buffer.
+		 */
+		nextInWord = 0;
+		if (inOffset < outOffset) {
+			/* Have more bytes than needed, shift remainder into nextInWord */
+			nextInWord = inWord LSH 8*(inOffset + byteCount);
+			inWord = inWord RSH bufShift;
+		} else if (inOffset > outOffset) {
+			/* Didn't get enough bytes from current input word, load another
+			 * word and then shift remainder into nextInWord.
+			 */
+			nextInWord = *pInWord++;
+			inWord = (inWord LSH invBufShift) | 
+			         (nextInWord RSH bufShift);
+			nextInWord = nextInWord LSH invBufShift;
+		}
+		/* Store output of first partial word */
+		*pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
+		/* UMR?  See comments above. */
+
+		/* Consumed byteCount bytes of input */
+		inputLen -= byteCount;
+		/* move to next word of output */
+		pOutWord++;
+		/* inWord has been consumed, but there may be bytes in nextInWord */
+		inWord = nextInWord;
+	} else {
+		/* output is word-aligned */
+		pOutWord = (WORD *)output;
+		if (inOffset) {
+			/* Input is not word-aligned.  The first word load of input 
+			 * will not produce a full word of input bytes, so one word
+			 * must be pre-loaded.  The main loop below will load in the
+			 * next input word and shift some of its bytes into inWord
+			 * in order to create a full input word.  Note that the main
+			 * loop must execute at least once because the input must
+			 * be at least two words.
+			 */
+			inWord = *pInWord++; /* UMR? see comments above. */
+			inWord = inWord LSH invBufShift;
+		} else {
+			/* Input is word-aligned.  The first word load of input 
+			 * will produce a full word of input bytes, so nothing
+			 * needs to be loaded here.
+			 */
+			inWord = 0;
+		}
+	}
+	/* Output buffer is aligned, inOffset is now measured relative to
+	 * outOffset (and not a word boundary).
+	 */
+	inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE;
+	/*****************************************************************/
+	/* Step 2: main loop                                             */
+	/* At this point the output buffer is word-aligned.  Any unused  */
+	/* bytes from above will be in inWord (shifted correctly).  If   */
+	/* the input buffer is unaligned relative to the output buffer,  */
+	/* shifting has to be done.                                      */
+	/*****************************************************************/
+	if (inOffset) {
+		for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
+			nextInWord = *pInWord++;
+			inWord |= nextInWord RSH bufShift;
+			nextInWord = nextInWord LSH invBufShift;
+			ARCFOUR_NEXT_WORD();
+			*pOutWord++ = inWord ^ streamWord;
+			inWord = nextInWord;
+		}
+		if (inputLen == 0) {
+			/* Nothing left to do. */
+			cx->i = tmpi;
+			cx->j = tmpj;
+			return SECSuccess;
+		}
+		/* If the amount of remaining input is greater than the amount
+		 * bytes pulled from the current input word, need to do another
+		 * word load.  What's left in inWord will be consumed in step 3.
+		 */
+		if (inputLen > WORDSIZE - inOffset)
+			inWord |= *pInWord RSH bufShift; /* UMR?  See above. */
+	} else {
+		for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
+			inWord = *pInWord++;
+			ARCFOUR_NEXT_WORD();
+			*pOutWord++ = inWord ^ streamWord;
+		}
+		if (inputLen == 0) {
+			/* Nothing left to do. */
+			cx->i = tmpi;
+			cx->j = tmpj;
+			return SECSuccess;
+		} else {
+			/* A partial input word remains at the tail.  Load it. 
+			 * The relevant bytes will be consumed in step 3.
+			 */
+			inWord = *pInWord; /* UMR?  See comments above */
+		}
+	}
+	/*****************************************************************/
+	/* Step 3:                                                       */
+	/* A partial word of input remains, and it is already loaded     */
+	/* into nextInWord.  Shift appropriately and consume the bytes   */
+	/* used in the partial word.                                     */
+	/*****************************************************************/
+	mask = streamWord = 0;
+#ifdef IS_LITTLE_ENDIAN
+	for (i = 0; i < inputLen; ++i) {
+#else
+	for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) {
+#endif
+		ARCFOUR_NEXT_BYTE();
+		streamWord |= (WORD)(cx->S[t]) << 8*i;
+		mask |= MASK1BYTE << 8*i;
+	} /* } */
+	/* UMR?  See comments above. */
+	*pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
+	cx->i = tmpi;
+	cx->j = tmpj;
+	return SECSuccess;
+}
+#endif
+#endif /* NSS_BEVAND_ARCFOUR */
+
+SECStatus 
+RC4_Encrypt(RC4Context *cx, unsigned char *output,
+            unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen)
+{
+	PORT_Assert(maxOutputLen >= inputLen);
+	if (maxOutputLen < inputLen) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return SECFailure;
+	}
+#if defined(NSS_BEVAND_ARCFOUR)
+	ARCFOUR(cx, inputLen, input, output);
+        *outputLen = inputLen;
+	return SECSuccess;
+#elif defined( CONVERT_TO_WORDS )
+	/* Convert the byte-stream to a word-stream */
+	return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
+#else
+	/* Operate on bytes, but unroll the main loop */
+	return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
+#endif
+}
+
+SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
+                      unsigned int *outputLen, unsigned int maxOutputLen,
+                      const unsigned char *input, unsigned int inputLen)
+{
+	PORT_Assert(maxOutputLen >= inputLen);
+	if (maxOutputLen < inputLen) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return SECFailure;
+	}
+	/* decrypt and encrypt are same operation. */
+#if defined(NSS_BEVAND_ARCFOUR)
+	ARCFOUR(cx, inputLen, input, output);
+        *outputLen = inputLen;
+	return SECSuccess;
+#elif defined( CONVERT_TO_WORDS )
+	/* Convert the byte-stream to a word-stream */
+	return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
+#else
+	/* Operate on bytes, but unroll the main loop */
+	return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
+#endif
+}
+
+#undef CONVERT_TO_WORDS
+#undef USE_WORD
diff --git a/mozilla/security/nss/lib/freebl/blapi.h b/mozilla/security/nss/lib/freebl/blapi.h
new file mode 100644
index 0000000..21e9353
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/blapi.h
@@ -0,0 +1,1209 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: blapi.h,v 1.33 2009/03/29 03:45:32 wtc%google.com Exp $ */
+
+#ifndef _BLAPI_H_
+#define _BLAPI_H_
+
+#include "blapit.h"
+#include "hasht.h"
+#include "alghmac.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** RSA encryption/decryption. When encrypting/decrypting the output
+** buffer must be at least the size of the public key modulus.
+*/
+
+extern SECStatus BL_Init(void);
+
+/*
+** Generate and return a new RSA public and private key.
+**	Both keys are encoded in a single RSAPrivateKey structure.
+**	"cx" is the random number generator context
+**	"keySizeInBits" is the size of the key to be generated, in bits.
+**	   512, 1024, etc.
+**	"publicExponent" when not NULL is a pointer to some data that
+**	   represents the public exponent to use. The data is a byte
+**	   encoded integer, in "big endian" order.
+*/
+extern RSAPrivateKey *RSA_NewKey(int         keySizeInBits,
+				 SECItem *   publicExponent);
+
+/*
+** Perform a raw public-key operation 
+**	Length of input and output buffers are equal to key's modulus len.
+*/
+extern SECStatus RSA_PublicKeyOp(RSAPublicKey *   key,
+				 unsigned char *  output,
+				 const unsigned char *  input);
+
+/*
+** Perform a raw private-key operation 
+**	Length of input and output buffers are equal to key's modulus len.
+*/
+extern SECStatus RSA_PrivateKeyOp(RSAPrivateKey *  key,
+				  unsigned char *  output,
+				  const unsigned char *  input);
+
+/*
+** Perform a raw private-key operation, and check the parameters used in
+** the operation for validity by performing a test operation first.
+**	Length of input and output buffers are equal to key's modulus len.
+*/
+extern SECStatus RSA_PrivateKeyOpDoubleChecked(RSAPrivateKey *  key,
+				               unsigned char *  output,
+				               const unsigned char *  input);
+
+/*
+** Perform a check of private key parameters for consistency.
+*/
+extern SECStatus RSA_PrivateKeyCheck(RSAPrivateKey *key);
+
+
+/********************************************************************
+** DSA signing algorithm
+*/
+
+/*
+** Generate and return a new DSA public and private key pair,
+**	both of which are encoded into a single DSAPrivateKey struct.
+**	"params" is a pointer to the PQG parameters for the domain
+**	Uses a random seed.
+*/
+extern SECStatus DSA_NewKey(const PQGParams *     params, 
+		            DSAPrivateKey **      privKey);
+
+/* signature is caller-supplied buffer of at least 20 bytes.
+** On input,  signature->len == size of buffer to hold signature.
+**            digest->len    == size of digest.
+** On output, signature->len == size of signature in buffer.
+** Uses a random seed.
+*/
+extern SECStatus DSA_SignDigest(DSAPrivateKey *   key,
+				SECItem *         signature,
+				const SECItem *   digest);
+
+/* signature is caller-supplied buffer of at least 20 bytes.
+** On input,  signature->len == size of buffer to hold signature.
+**            digest->len    == size of digest.
+*/
+extern SECStatus DSA_VerifyDigest(DSAPublicKey *  key,
+				  const SECItem * signature,
+				  const SECItem * digest);
+
+/* For FIPS compliance testing. Seed must be exactly 20 bytes long */
+extern SECStatus DSA_NewKeyFromSeed(const PQGParams *params, 
+                                    const unsigned char * seed,
+                                    DSAPrivateKey **privKey);
+
+/* For FIPS compliance testing. Seed must be exactly 20 bytes. */
+extern SECStatus DSA_SignDigestWithSeed(DSAPrivateKey * key,
+                                        SECItem *       signature,
+                                        const SECItem * digest,
+                                        const unsigned char * seed);
+
+/******************************************************
+** Diffie Helman key exchange algorithm 
+*/
+
+/* Generates parameters for Diffie-Helman key generation.
+**	primeLen is the length in bytes of prime P to be generated.
+*/
+extern SECStatus DH_GenParam(int primeLen, DHParams ** params);
+
+/* Generates a public and private key, both of which are encoded in a single
+**	DHPrivateKey struct. Params is input, privKey are output.  
+**	This is Phase 1 of Diffie Hellman.
+*/
+extern SECStatus DH_NewKey(DHParams *           params, 
+                           DHPrivateKey **	privKey);
+
+/* 
+** DH_Derive does the Diffie-Hellman phase 2 calculation, using the 
+** other party's publicValue, and the prime and our privateValue.
+** maxOutBytes is the requested length of the generated secret in bytes.  
+** A zero value means produce a value of any length up to the size of 
+** the prime.   If successful, derivedSecret->data is set 
+** to the address of the newly allocated buffer containing the derived 
+** secret, and derivedSecret->len is the size of the secret produced.
+** The size of the secret produced will never be larger than the length
+** of the prime, and it may be smaller than maxOutBytes.
+** It is the caller's responsibility to free the allocated buffer 
+** containing the derived secret.
+*/
+extern SECStatus DH_Derive(SECItem *    publicValue, 
+		           SECItem *    prime, 
+			   SECItem *    privateValue, 
+			   SECItem *    derivedSecret,
+			   unsigned int maxOutBytes);
+
+/* 
+** KEA_CalcKey returns octet string with the private key for a dual
+** Diffie-Helman  key generation as specified for government key exchange.
+*/
+extern SECStatus KEA_Derive(SECItem *prime, 
+                            SECItem *public1, 
+                            SECItem *public2, 
+			    SECItem *private1, 
+			    SECItem *private2,
+			    SECItem *derivedSecret);
+
+/*
+ * verify that a KEA or DSA public key is a valid key for this prime and
+ * subprime domain.
+ */
+extern PRBool KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime);
+
+/******************************************************
+** Elliptic Curve algorithms
+*/
+
+/* Generates a public and private key, both of which are encoded 
+** in a single ECPrivateKey struct. Params is input, privKey are
+** output.
+*/
+extern SECStatus EC_NewKey(ECParams *          params, 
+                           ECPrivateKey **     privKey);
+
+extern SECStatus EC_NewKeyFromSeed(ECParams *  params, 
+                           ECPrivateKey **     privKey,
+                           const unsigned char* seed,
+                           int                 seedlen);
+
+/* Validates an EC public key as described in Section 5.2.2 of
+ * X9.62. Such validation prevents against small subgroup attacks
+ * when the ECDH primitive is used with the cofactor.
+ */
+extern SECStatus EC_ValidatePublicKey(ECParams * params, 
+                           SECItem *           publicValue);
+
+/* 
+** ECDH_Derive performs a scalar point multiplication of a point
+** representing a (peer's) public key and a large integer representing
+** a private key (its own). Both keys must use the same elliptic curve
+** parameters. If the withCofactor parameter is true, the
+** multiplication also uses the cofactor associated with the curve
+** parameters.  The output of this scheme is the x-coordinate of the
+** resulting point. If successful, derivedSecret->data is set to the
+** address of the newly allocated buffer containing the derived
+** secret, and derivedSecret->len is the size of the secret
+** produced. It is the caller's responsibility to free the allocated
+** buffer containing the derived secret.
+*/
+extern SECStatus ECDH_Derive(SECItem *       publicValue,
+                             ECParams *      params,
+                             SECItem *       privateValue,
+                             PRBool          withCofactor,
+                             SECItem *       derivedSecret);
+
+/* On input,  signature->len == size of buffer to hold signature.
+**            digest->len    == size of digest.
+** On output, signature->len == size of signature in buffer.
+** Uses a random seed.
+*/
+extern SECStatus ECDSA_SignDigest(ECPrivateKey  *key, 
+                                  SECItem       *signature, 
+                                  const SECItem *digest);
+
+/* On input,  signature->len == size of buffer to hold signature.
+**            digest->len    == size of digest.
+*/
+extern SECStatus ECDSA_VerifyDigest(ECPublicKey   *key, 
+                                    const SECItem *signature, 
+                                    const SECItem *digest);
+
+/* Uses the provided seed. */
+extern SECStatus ECDSA_SignDigestWithSeed(ECPrivateKey        *key,
+                                          SECItem             *signature,
+                                          const SECItem       *digest,
+                                          const unsigned char *seed, 
+                                          const int           seedlen);
+
+/******************************************/
+/*
+** RC4 symmetric stream cypher
+*/
+
+/*
+** Create a new RC4 context suitable for RC4 encryption/decryption.
+**	"key" raw key data
+**	"len" the number of bytes of key data
+*/
+extern RC4Context *RC4_CreateContext(const unsigned char *key, int len);
+
+extern RC4Context *RC4_AllocateContext(void);
+extern SECStatus   RC4_InitContext(RC4Context *cx, 
+				   const unsigned char *key, 
+				   unsigned int keylen,
+				   const unsigned char *, 
+				   int, 
+				   unsigned int ,
+				   unsigned int );
+
+/*
+** Destroy an RC4 encryption/decryption context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void RC4_DestroyContext(RC4Context *cx, PRBool freeit);
+
+/*
+** Perform RC4 encryption.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus RC4_Encrypt(RC4Context *cx, unsigned char *output,
+			    unsigned int *outputLen, unsigned int maxOutputLen,
+			    const unsigned char *input, unsigned int inputLen);
+
+/*
+** Perform RC4 decryption.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
+			    unsigned int *outputLen, unsigned int maxOutputLen,
+			    const unsigned char *input, unsigned int inputLen);
+
+/******************************************/
+/*
+** RC2 symmetric block cypher
+*/
+
+/*
+** Create a new RC2 context suitable for RC2 encryption/decryption.
+** 	"key" raw key data
+** 	"len" the number of bytes of key data
+** 	"iv" is the CBC initialization vector (if mode is NSS_RC2_CBC)
+** 	"mode" one of NSS_RC2 or NSS_RC2_CBC
+**	"effectiveKeyLen" is the effective key length (as specified in 
+**	    RFC 2268) in bytes (not bits).
+**
+** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block
+** chaining" mode.
+*/
+extern RC2Context *RC2_CreateContext(const unsigned char *key, unsigned int len,
+				     const unsigned char *iv, int mode, 
+				     unsigned effectiveKeyLen);
+extern RC2Context *RC2_AllocateContext(void);
+extern SECStatus   RC2_InitContext(RC2Context *cx,
+				   const unsigned char *key, 
+				   unsigned int keylen,
+				   const unsigned char *iv, 
+				   int mode, 
+				   unsigned int effectiveKeyLen,
+				   unsigned int );
+
+/*
+** Destroy an RC2 encryption/decryption context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void RC2_DestroyContext(RC2Context *cx, PRBool freeit);
+
+/*
+** Perform RC2 encryption.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus RC2_Encrypt(RC2Context *cx, unsigned char *output,
+			    unsigned int *outputLen, unsigned int maxOutputLen,
+			    const unsigned char *input, unsigned int inputLen);
+
+/*
+** Perform RC2 decryption.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus RC2_Decrypt(RC2Context *cx, unsigned char *output,
+			    unsigned int *outputLen, unsigned int maxOutputLen,
+			    const unsigned char *input, unsigned int inputLen);
+
+/******************************************/
+/*
+** RC5 symmetric block cypher -- 64-bit block size
+*/
+
+/*
+** Create a new RC5 context suitable for RC5 encryption/decryption.
+**      "key" raw key data
+**      "len" the number of bytes of key data
+**      "iv" is the CBC initialization vector (if mode is NSS_RC5_CBC)
+**      "mode" one of NSS_RC5 or NSS_RC5_CBC
+**
+** When mode is set to NSS_RC5_CBC the RC5 cipher is run in "cipher block
+** chaining" mode.
+*/
+extern RC5Context *RC5_CreateContext(const SECItem *key, unsigned int rounds,
+                     unsigned int wordSize, const unsigned char *iv, int mode);
+extern RC5Context *RC5_AllocateContext(void);
+extern SECStatus   RC5_InitContext(RC5Context *cx, 
+				   const unsigned char *key, 
+				   unsigned int keylen,
+				   const unsigned char *iv, 
+				   int mode,
+				   unsigned int rounds, 
+				   unsigned int wordSize);
+
+/*
+** Destroy an RC5 encryption/decryption context.
+**      "cx" the context
+**      "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void RC5_DestroyContext(RC5Context *cx, PRBool freeit);
+
+/*
+** Perform RC5 encryption.
+**      "cx" the context
+**      "output" the output buffer to store the encrypted data.
+**      "outputLen" how much data is stored in "output". Set by the routine
+**         after some data is stored in output.
+**      "maxOutputLen" the maximum amount of data that can ever be
+**         stored in "output"
+**      "input" the input data
+**      "inputLen" the amount of input data
+*/
+extern SECStatus RC5_Encrypt(RC5Context *cx, unsigned char *output,
+                            unsigned int *outputLen, unsigned int maxOutputLen,
+                            const unsigned char *input, unsigned int inputLen);
+
+/*
+** Perform RC5 decryption.
+**      "cx" the context
+**      "output" the output buffer to store the decrypted data.
+**      "outputLen" how much data is stored in "output". Set by the routine
+**         after some data is stored in output.
+**      "maxOutputLen" the maximum amount of data that can ever be
+**         stored in "output"
+**      "input" the input data
+**      "inputLen" the amount of input data
+*/
+
+extern SECStatus RC5_Decrypt(RC5Context *cx, unsigned char *output,
+                            unsigned int *outputLen, unsigned int maxOutputLen,
+                            const unsigned char *input, unsigned int inputLen);
+
+
+
+/******************************************/
+/*
+** DES symmetric block cypher
+*/
+
+/*
+** Create a new DES context suitable for DES encryption/decryption.
+** 	"key" raw key data
+** 	"len" the number of bytes of key data
+** 	"iv" is the CBC initialization vector (if mode is NSS_DES_CBC or
+** 	   mode is DES_EDE3_CBC)
+** 	"mode" one of NSS_DES, NSS_DES_CBC, NSS_DES_EDE3 or NSS_DES_EDE3_CBC
+**	"encrypt" is PR_TRUE if the context will be used for encryption
+**
+** When mode is set to NSS_DES_CBC or NSS_DES_EDE3_CBC then the DES
+** cipher is run in "cipher block chaining" mode.
+*/
+extern DESContext *DES_CreateContext(const unsigned char *key, 
+                                     const unsigned char *iv,
+				     int mode, PRBool encrypt);
+extern DESContext *DES_AllocateContext(void);
+extern SECStatus   DES_InitContext(DESContext *cx,
+				   const unsigned char *key, 
+				   unsigned int keylen,
+				   const unsigned char *iv, 
+				   int mode,
+				   unsigned int encrypt,
+				   unsigned int );
+
+/*
+** Destroy an DES encryption/decryption context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void DES_DestroyContext(DESContext *cx, PRBool freeit);
+
+/*
+** Perform DES encryption.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+**
+** NOTE: the inputLen must be a multiple of DES_KEY_LENGTH
+*/
+extern SECStatus DES_Encrypt(DESContext *cx, unsigned char *output,
+			    unsigned int *outputLen, unsigned int maxOutputLen,
+			    const unsigned char *input, unsigned int inputLen);
+
+/*
+** Perform DES decryption.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+**
+** NOTE: the inputLen must be a multiple of DES_KEY_LENGTH
+*/
+extern SECStatus DES_Decrypt(DESContext *cx, unsigned char *output,
+			    unsigned int *outputLen, unsigned int maxOutputLen,
+			    const unsigned char *input, unsigned int inputLen);
+
+/******************************************/
+/* 
+** SEED symmetric block cypher		  
+*/
+extern SEEDContext *
+SEED_CreateContext(const unsigned char *key, const unsigned char *iv, 
+		   int mode, PRBool encrypt);
+extern SEEDContext *SEED_AllocateContext(void);
+extern SECStatus   SEED_InitContext(SEEDContext *cx, 
+				    const unsigned char *key, 
+				    unsigned int keylen, 
+				    const unsigned char *iv, 
+				    int mode, unsigned int encrypt, 
+				    unsigned int );
+extern void SEED_DestroyContext(SEEDContext *cx, PRBool freeit);
+extern SECStatus 
+SEED_Encrypt(SEEDContext *cx, unsigned char *output, 
+	     unsigned int *outputLen, unsigned int maxOutputLen, 
+	     const unsigned char *input, unsigned int inputLen);
+extern SECStatus 
+SEED_Decrypt(SEEDContext *cx, unsigned char *output, 
+	     unsigned int *outputLen, unsigned int maxOutputLen, 
+             const unsigned char *input, unsigned int inputLen);
+
+/******************************************/
+/*
+** AES symmetric block cypher (Rijndael)
+*/
+
+/*
+** Create a new AES context suitable for AES encryption/decryption.
+** 	"key" raw key data
+** 	"keylen" the number of bytes of key data (16, 24, or 32)
+**      "blocklen" is the blocksize to use (16, 24, or 32)
+**                        XXX currently only blocksize==16 has been tested!
+*/
+extern AESContext *
+AES_CreateContext(const unsigned char *key, const unsigned char *iv, 
+                  int mode, int encrypt,
+                  unsigned int keylen, unsigned int blocklen);
+extern AESContext *AES_AllocateContext(void);
+extern SECStatus   AES_InitContext(AESContext *cx,
+				   const unsigned char *key, 
+				   unsigned int keylen, 
+				   const unsigned char *iv, 
+				   int mode, 
+				   unsigned int encrypt,
+				   unsigned int blocklen);
+
+/*
+** Destroy a AES encryption/decryption context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void 
+AES_DestroyContext(AESContext *cx, PRBool freeit);
+
+/*
+** Perform AES encryption.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+AES_Encrypt(AESContext *cx, unsigned char *output,
+            unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen);
+
+/*
+** Perform AES decryption.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+AES_Decrypt(AESContext *cx, unsigned char *output,
+            unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen);
+
+/******************************************/
+/*
+** AES key wrap algorithm, RFC 3394
+*/
+
+/*
+** Create a new AES context suitable for AES encryption/decryption.
+** 	"key" raw key data
+**      "iv"  The 8 byte "initial value"
+**      "encrypt", a boolean, true for key wrapping, false for unwrapping.
+** 	"keylen" the number of bytes of key data (16, 24, or 32)
+*/
+extern AESKeyWrapContext *
+AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, 
+                         int encrypt, unsigned int keylen);
+extern AESKeyWrapContext * AESKeyWrap_AllocateContext(void);
+extern SECStatus  
+     AESKeyWrap_InitContext(AESKeyWrapContext *cx, 
+				   const unsigned char *key, 
+				   unsigned int keylen,
+				   const unsigned char *iv, 
+				   int ,
+				   unsigned int encrypt,
+				   unsigned int );
+
+/*
+** Destroy a AES KeyWrap context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void 
+AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit);
+
+/*
+** Perform AES key wrap.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
+            unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen);
+
+/*
+** Perform AES key unwrap.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
+            unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen);
+
+ /******************************************/
+/*
+** Camellia symmetric block cypher
+*/
+
+/*
+** Create a new Camellia context suitable for Camellia encryption/decryption.
+** 	"key" raw key data
+** 	"keylen" the number of bytes of key data (16, 24, or 32)
+*/
+extern CamelliaContext *
+Camellia_CreateContext(const unsigned char *key, const unsigned char *iv, 
+		       int mode, int encrypt, unsigned int keylen);
+
+extern CamelliaContext *Camellia_AllocateContext(void);
+extern SECStatus   Camellia_InitContext(CamelliaContext *cx,
+					const unsigned char *key, 
+					unsigned int keylen, 
+					const unsigned char *iv, 
+					int mode, 
+					unsigned int encrypt,
+					unsigned int unused);
+/*
+** Destroy a Camellia encryption/decryption context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void 
+Camellia_DestroyContext(CamelliaContext *cx, PRBool freeit);
+
+/*
+** Perform Camellia encryption.
+**	"cx" the context
+**	"output" the output buffer to store the encrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+Camellia_Encrypt(CamelliaContext *cx, unsigned char *output,
+		 unsigned int *outputLen, unsigned int maxOutputLen,
+		 const unsigned char *input, unsigned int inputLen);
+
+/*
+** Perform Camellia decryption.
+**	"cx" the context
+**	"output" the output buffer to store the decrypted data.
+**	"outputLen" how much data is stored in "output". Set by the routine
+**	   after some data is stored in output.
+**	"maxOutputLen" the maximum amount of data that can ever be
+**	   stored in "output"
+**	"input" the input data
+**	"inputLen" the amount of input data
+*/
+extern SECStatus 
+Camellia_Decrypt(CamelliaContext *cx, unsigned char *output,
+		 unsigned int *outputLen, unsigned int maxOutputLen,
+		 const unsigned char *input, unsigned int inputLen);
+
+
+/******************************************/
+/*
+** MD5 secure hash function
+*/
+
+/*
+** Hash a null terminated string "src" into "dest" using MD5
+*/
+extern SECStatus MD5_Hash(unsigned char *dest, const char *src);
+
+/*
+** Hash a non-null terminated string "src" into "dest" using MD5
+*/
+extern SECStatus MD5_HashBuf(unsigned char *dest, const unsigned char *src,
+			     uint32 src_length);
+
+/*
+** Create a new MD5 context
+*/
+extern MD5Context *MD5_NewContext(void);
+
+
+/*
+** Destroy an MD5 secure hash context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void MD5_DestroyContext(MD5Context *cx, PRBool freeit);
+
+/*
+** Reset an MD5 context, preparing it for a fresh round of hashing
+*/
+extern void MD5_Begin(MD5Context *cx);
+
+/*
+** Update the MD5 hash function with more data.
+**	"cx" the context
+**	"input" the data to hash
+**	"inputLen" the amount of data to hash
+*/
+extern void MD5_Update(MD5Context *cx,
+		       const unsigned char *input, unsigned int inputLen);
+
+/*
+** Finish the MD5 hash function. Produce the digested results in "digest"
+**	"cx" the context
+**	"digest" where the 16 bytes of digest data are stored
+**	"digestLen" where the digest length (16) is stored
+**	"maxDigestLen" the maximum amount of data that can ever be
+**	   stored in "digest"
+*/
+extern void MD5_End(MD5Context *cx, unsigned char *digest,
+		    unsigned int *digestLen, unsigned int maxDigestLen);
+
+/*
+ * Return the the size of a buffer needed to flatten the MD5 Context into
+ *    "cx" the context
+ *  returns size;
+ */
+extern unsigned int MD5_FlattenSize(MD5Context *cx);
+
+/*
+ * Flatten the MD5 Context into a buffer:
+ *    "cx" the context
+ *    "space" the buffer to flatten to
+ *  returns status;
+ */
+extern SECStatus MD5_Flatten(MD5Context *cx,unsigned char *space);
+
+/*
+ * Resurrect a flattened context into a MD5 Context
+ *    "space" the buffer of the flattend buffer
+ *    "arg" ptr to void used by cryptographic resurrect
+ *  returns resurected context;
+ */
+extern MD5Context * MD5_Resurrect(unsigned char *space, void *arg);
+extern void MD5_Clone(MD5Context *dest, MD5Context *src);
+
+/*
+** trace the intermediate state info of the MD5 hash.
+*/
+extern void MD5_TraceState(MD5Context *cx);
+
+
+/******************************************/
+/*
+** MD2 secure hash function
+*/
+
+/*
+** Hash a null terminated string "src" into "dest" using MD2
+*/
+extern SECStatus MD2_Hash(unsigned char *dest, const char *src);
+
+/*
+** Create a new MD2 context
+*/
+extern MD2Context *MD2_NewContext(void);
+
+
+/*
+** Destroy an MD2 secure hash context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void MD2_DestroyContext(MD2Context *cx, PRBool freeit);
+
+/*
+** Reset an MD2 context, preparing it for a fresh round of hashing
+*/
+extern void MD2_Begin(MD2Context *cx);
+
+/*
+** Update the MD2 hash function with more data.
+**	"cx" the context
+**	"input" the data to hash
+**	"inputLen" the amount of data to hash
+*/
+extern void MD2_Update(MD2Context *cx,
+		       const unsigned char *input, unsigned int inputLen);
+
+/*
+** Finish the MD2 hash function. Produce the digested results in "digest"
+**	"cx" the context
+**	"digest" where the 16 bytes of digest data are stored
+**	"digestLen" where the digest length (16) is stored
+**	"maxDigestLen" the maximum amount of data that can ever be
+**	   stored in "digest"
+*/
+extern void MD2_End(MD2Context *cx, unsigned char *digest,
+		    unsigned int *digestLen, unsigned int maxDigestLen);
+
+/*
+ * Return the the size of a buffer needed to flatten the MD2 Context into
+ *    "cx" the context
+ *  returns size;
+ */
+extern unsigned int MD2_FlattenSize(MD2Context *cx);
+
+/*
+ * Flatten the MD2 Context into a buffer:
+ *    "cx" the context
+ *    "space" the buffer to flatten to
+ *  returns status;
+ */
+extern SECStatus MD2_Flatten(MD2Context *cx,unsigned char *space);
+
+/*
+ * Resurrect a flattened context into a MD2 Context
+ *    "space" the buffer of the flattend buffer
+ *    "arg" ptr to void used by cryptographic resurrect
+ *  returns resurected context;
+ */
+extern MD2Context * MD2_Resurrect(unsigned char *space, void *arg);
+extern void MD2_Clone(MD2Context *dest, MD2Context *src);
+
+/******************************************/
+/*
+** SHA-1 secure hash function
+*/
+
+/*
+** Hash a null terminated string "src" into "dest" using SHA-1
+*/
+extern SECStatus SHA1_Hash(unsigned char *dest, const char *src);
+
+/*
+** Hash a non-null terminated string "src" into "dest" using SHA-1
+*/
+extern SECStatus SHA1_HashBuf(unsigned char *dest, const unsigned char *src,
+			      uint32 src_length);
+
+/*
+** Create a new SHA-1 context
+*/
+extern SHA1Context *SHA1_NewContext(void);
+
+
+/*
+** Destroy a SHA-1 secure hash context.
+**	"cx" the context
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void SHA1_DestroyContext(SHA1Context *cx, PRBool freeit);
+
+/*
+** Reset a SHA-1 context, preparing it for a fresh round of hashing
+*/
+extern void SHA1_Begin(SHA1Context *cx);
+
+/*
+** Update the SHA-1 hash function with more data.
+**	"cx" the context
+**	"input" the data to hash
+**	"inputLen" the amount of data to hash
+*/
+extern void SHA1_Update(SHA1Context *cx, const unsigned char *input,
+			unsigned int inputLen);
+
+/*
+** Finish the SHA-1 hash function. Produce the digested results in "digest"
+**	"cx" the context
+**	"digest" where the 16 bytes of digest data are stored
+**	"digestLen" where the digest length (20) is stored
+**	"maxDigestLen" the maximum amount of data that can ever be
+**	   stored in "digest"
+*/
+extern void SHA1_End(SHA1Context *cx, unsigned char *digest,
+		     unsigned int *digestLen, unsigned int maxDigestLen);
+
+/*
+** trace the intermediate state info of the SHA1 hash.
+*/
+extern void SHA1_TraceState(SHA1Context *cx);
+
+/*
+ * Return the the size of a buffer needed to flatten the SHA-1 Context into
+ *    "cx" the context
+ *  returns size;
+ */
+extern unsigned int SHA1_FlattenSize(SHA1Context *cx);
+
+/*
+ * Flatten the SHA-1 Context into a buffer:
+ *    "cx" the context
+ *    "space" the buffer to flatten to
+ *  returns status;
+ */
+extern SECStatus SHA1_Flatten(SHA1Context *cx,unsigned char *space);
+
+/*
+ * Resurrect a flattened context into a SHA-1 Context
+ *    "space" the buffer of the flattend buffer
+ *    "arg" ptr to void used by cryptographic resurrect
+ *  returns resurected context;
+ */
+extern SHA1Context * SHA1_Resurrect(unsigned char *space, void *arg);
+extern void SHA1_Clone(SHA1Context *dest, SHA1Context *src);
+
+/******************************************/
+
+extern SHA256Context *SHA256_NewContext(void);
+extern void SHA256_DestroyContext(SHA256Context *cx, PRBool freeit);
+extern void SHA256_Begin(SHA256Context *cx);
+extern void SHA256_Update(SHA256Context *cx, const unsigned char *input,
+			unsigned int inputLen);
+extern void SHA256_End(SHA256Context *cx, unsigned char *digest,
+		     unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
+			      uint32 src_length);
+extern SECStatus SHA256_Hash(unsigned char *dest, const char *src);
+extern void SHA256_TraceState(SHA256Context *cx);
+extern unsigned int SHA256_FlattenSize(SHA256Context *cx);
+extern SECStatus SHA256_Flatten(SHA256Context *cx,unsigned char *space);
+extern SHA256Context * SHA256_Resurrect(unsigned char *space, void *arg);
+extern void SHA256_Clone(SHA256Context *dest, SHA256Context *src);
+
+/******************************************/
+
+extern SHA512Context *SHA512_NewContext(void);
+extern void SHA512_DestroyContext(SHA512Context *cx, PRBool freeit);
+extern void SHA512_Begin(SHA512Context *cx);
+extern void SHA512_Update(SHA512Context *cx, const unsigned char *input,
+			unsigned int inputLen);
+extern void SHA512_End(SHA512Context *cx, unsigned char *digest,
+		     unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
+			      uint32 src_length);
+extern SECStatus SHA512_Hash(unsigned char *dest, const char *src);
+extern void SHA512_TraceState(SHA512Context *cx);
+extern unsigned int SHA512_FlattenSize(SHA512Context *cx);
+extern SECStatus SHA512_Flatten(SHA512Context *cx,unsigned char *space);
+extern SHA512Context * SHA512_Resurrect(unsigned char *space, void *arg);
+extern void SHA512_Clone(SHA512Context *dest, SHA512Context *src);
+
+/******************************************/
+
+extern SHA384Context *SHA384_NewContext(void);
+extern void SHA384_DestroyContext(SHA384Context *cx, PRBool freeit);
+extern void SHA384_Begin(SHA384Context *cx);
+extern void SHA384_Update(SHA384Context *cx, const unsigned char *input,
+			unsigned int inputLen);
+extern void SHA384_End(SHA384Context *cx, unsigned char *digest,
+		     unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
+			      uint32 src_length);
+extern SECStatus SHA384_Hash(unsigned char *dest, const char *src);
+extern void SHA384_TraceState(SHA384Context *cx);
+extern unsigned int SHA384_FlattenSize(SHA384Context *cx);
+extern SECStatus SHA384_Flatten(SHA384Context *cx,unsigned char *space);
+extern SHA384Context * SHA384_Resurrect(unsigned char *space, void *arg);
+extern void SHA384_Clone(SHA384Context *dest, SHA384Context *src);
+
+/****************************************
+ * implement TLS Pseudo Random Function (PRF)
+ */
+
+extern SECStatus
+TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, 
+         SECItem *result, PRBool isFIPS);
+
+/******************************************/
+/*
+** Pseudo Random Number Generation.  FIPS compliance desirable.
+*/
+
+/*
+** Initialize the global RNG context and give it some seed input taken
+** from the system.  This function is thread-safe and will only allow
+** the global context to be initialized once.  The seed input is likely
+** small, so it is imperative that RNG_RandomUpdate() be called with
+** additional seed data before the generator is used.  A good way to
+** provide the generator with additional entropy is to call
+** RNG_SystemInfoForRNG().  Note that NSS_Init() does exactly that.
+*/
+extern SECStatus RNG_RNGInit(void);
+
+/*
+** Update the global random number generator with more seeding
+** material
+*/
+extern SECStatus RNG_RandomUpdate(const void *data, size_t bytes);
+
+/*
+** Generate some random bytes, using the global random number generator
+** object.
+*/
+extern SECStatus RNG_GenerateGlobalRandomBytes(void *dest, size_t len);
+
+/* Destroy the global RNG context.  After a call to RNG_RNGShutdown()
+** a call to RNG_RNGInit() is required in order to use the generator again,
+** along with seed data (see the comment above RNG_RNGInit()).
+*/
+extern void  RNG_RNGShutdown(void);
+
+extern void RNG_SystemInfoForRNG(void);
+
+/*
+ * FIPS 186-2 Change Notice 1 RNG Algorithm 1, used both to
+ * generate the DSA X parameter and as a generic purpose RNG.
+ *
+ * The following two FIPS186Change functions are needed for
+ * NIST RNG Validation System.
+ */
+
+/*
+ * FIPS186Change_GenerateX is now deprecated. It will return SECFailure with
+ * the error set to PR_NOT_IMPLEMENTED_ERROR.
+ */
+extern SECStatus
+FIPS186Change_GenerateX(unsigned char *XKEY,
+                        const unsigned char *XSEEDj,
+                        unsigned char *x_j);
+
+/*
+ * When generating the DSA X parameter, we generate 2*GSIZE bytes
+ * of random output and reduce it mod q.
+ *
+ * Input: w, 2*GSIZE bytes
+ *        q, DSA_SUBPRIME_LEN bytes
+ * Output: xj, DSA_SUBPRIME_LEN bytes
+ */
+extern SECStatus
+FIPS186Change_ReduceModQForDSA(const unsigned char *w,
+                               const unsigned char *q,
+                               unsigned char *xj);
+
+/*
+ * The following functions are for FIPS poweron self test and FIPS algorithm
+ * testing.
+ */
+extern SECStatus
+PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len, 
+		const PRUint8 *nonce, unsigned int nonce_len,
+		const PRUint8 *personal_string, unsigned int ps_len);
+
+extern SECStatus
+PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len, 
+		  const PRUint8 *additional, unsigned int additional_len);
+
+extern SECStatus
+PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len, 
+		  const PRUint8 *additional, unsigned int additional_len);
+
+extern SECStatus
+PRNGTEST_Uninstantiate(void);
+
+
+/* Generate PQGParams and PQGVerify structs.
+ * Length of seed and length of h both equal length of P. 
+ * All lengths are specified by "j", according to the table above.
+ */
+extern SECStatus
+PQG_ParamGen(unsigned int j, 	   /* input : determines length of P. */
+             PQGParams **pParams,  /* output: P Q and G returned here */
+	     PQGVerify **pVfy);    /* output: counter and seed. */
+
+/* Generate PQGParams and PQGVerify structs.
+ * Length of P specified by j.  Length of h will match length of P.
+ * Length of SEED in bytes specified in seedBytes.
+ * seedBbytes must be in the range [20..255] or an error will result.
+ */
+extern SECStatus
+PQG_ParamGenSeedLen(
+             unsigned int j, 	     /* input : determines length of P. */
+	     unsigned int seedBytes, /* input : length of seed in bytes.*/
+             PQGParams **pParams,    /* output: P Q and G returned here */
+	     PQGVerify **pVfy);      /* output: counter and seed. */
+
+
+/*  Test PQGParams for validity as DSS PQG values.
+ *  If vfy is non-NULL, test PQGParams to make sure they were generated
+ *       using the specified seed, counter, and h values.
+ *
+ *  Return value indicates whether Verification operation ran successfully
+ *  to completion, but does not indicate if PQGParams are valid or not.
+ *  If return value is SECSuccess, then *pResult has these meanings:
+ *       SECSuccess: PQGParams are valid.
+ *       SECFailure: PQGParams are invalid.
+ *
+ * Verify the following 12 facts about PQG counter SEED g and h
+ * 1.  Q is 160 bits long.
+ * 2.  P is one of the 9 valid lengths.
+ * 3.  G < P
+ * 4.  P % Q == 1
+ * 5.  Q is prime
+ * 6.  P is prime
+ * Steps 7-12 are done only if the optional PQGVerify is supplied.
+ * 7.  counter < 4096
+ * 8.  g >= 160 and g < 2048   (g is length of seed in bits)
+ * 9.  Q generated from SEED matches Q in PQGParams.
+ * 10. P generated from (L, counter, g, SEED, Q) matches P in PQGParams.
+ * 11. 1 < h < P-1
+ * 12. G generated from h matches G in PQGParams.
+ */
+
+extern SECStatus   PQG_VerifyParams(const PQGParams *params, 
+                                    const PQGVerify *vfy, SECStatus *result);
+
+extern void PQG_DestroyParams(PQGParams *params);
+
+extern void PQG_DestroyVerify(PQGVerify *vfy);
+
+
+/*
+ * clean-up any global tables freebl may have allocated after it starts up.
+ * This function is not thread safe and should be called only after the
+ * library has been quiessed.
+ */
+extern void BL_Cleanup(void);
+
+/* unload freebl shared library from memory */
+extern void BL_Unload(void);
+
+/**************************************************************************
+ *  Verify a given Shared library signature                               *
+ **************************************************************************/
+PRBool BLAPI_SHVerify(const char *name, PRFuncPtr addr);
+
+/**************************************************************************
+ *  Verify Are Own Shared library signature                               *
+ **************************************************************************/
+PRBool BLAPI_VerifySelf(const char *name);
+
+/*********************************************************************/
+extern const SECHashObject * HASH_GetRawHashObject(HASH_HashType hashType);
+
+extern void BL_SetForkState(PRBool forked);
+
+SEC_END_PROTOS
+
+#endif /* _BLAPI_H_ */
diff --git a/mozilla/security/nss/lib/freebl/blapii.h b/mozilla/security/nss/lib/freebl/blapii.h
new file mode 100644
index 0000000..7d70c47
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/blapii.h
@@ -0,0 +1,60 @@
+/*
+ * blapii.h - private data structures and prototypes for the crypto library
+ *
+ * ***** 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 Network Security Services Library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * 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 ***** */
+
+#ifndef _BLAPII_H_
+#define _BLAPII_H_
+
+#include "blapit.h"
+
+SEC_BEGIN_PROTOS
+
+#if defined(XP_UNIX) && !defined(NO_CHECK_FORK)
+
+extern PRBool bl_parentForkedAfterC_Initialize;
+
+#define SKIP_AFTER_FORK(x) if (!bl_parentForkedAfterC_Initialize) x
+
+#else
+
+#define SKIP_AFTER_FORK(x) x
+
+#endif
+
+SEC_END_PROTOS
+
+#endif /* _BLAPII_H_ */
+
diff --git a/mozilla/security/nss/lib/freebl/blapit.h b/mozilla/security/nss/lib/freebl/blapit.h
new file mode 100644
index 0000000..704f514
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/blapit.h
@@ -0,0 +1,389 @@
+/*
+ * blapit.h - public data structures for the crypto library
+ *
+ * ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: blapit.h,v 1.22 2008/12/17 06:09:12 nelson%bolyard.com Exp $ */
+
+#ifndef _BLAPIT_H_
+#define _BLAPIT_H_
+
+#include "seccomon.h"
+#include "prlink.h"
+#include "plarena.h"
+#include "ecl-exp.h"
+
+
+/* RC2 operation modes */
+#define NSS_RC2			0
+#define NSS_RC2_CBC		1
+
+/* RC5 operation modes */
+#define NSS_RC5                 0
+#define NSS_RC5_CBC             1
+
+/* DES operation modes */
+#define NSS_DES			0
+#define NSS_DES_CBC		1
+#define NSS_DES_EDE3		2
+#define NSS_DES_EDE3_CBC	3
+
+#define DES_KEY_LENGTH		8	/* Bytes */
+
+/* AES operation modes */
+#define NSS_AES                 0
+#define NSS_AES_CBC             1
+
+/* Camellia operation modes */
+#define NSS_CAMELLIA                 0
+#define NSS_CAMELLIA_CBC             1
+
+/* SEED operation modes */
+#define NSS_SEED		0
+#define NSS_SEED_CBC		1
+
+#define DSA_SIGNATURE_LEN 	40	/* Bytes */
+#define DSA_SUBPRIME_LEN	20	/* Bytes */
+
+/* XXX We shouldn't have to hard code this limit. For
+ * now, this is the quickest way to support ECDSA signature
+ * processing (ECDSA signature lengths depend on curve
+ * size). This limit is sufficient for curves upto
+ * 576 bits.
+ */
+#define MAX_ECKEY_LEN 	        72	/* Bytes */
+
+/*
+ * Number of bytes each hash algorithm produces
+ */
+#define MD2_LENGTH		16	/* Bytes */
+#define MD5_LENGTH		16	/* Bytes */
+#define SHA1_LENGTH		20	/* Bytes */
+#define SHA256_LENGTH 		32 	/* bytes */
+#define SHA384_LENGTH 		48 	/* bytes */
+#define SHA512_LENGTH 		64 	/* bytes */
+#define HASH_LENGTH_MAX         SHA512_LENGTH
+
+/*
+ * Input block size for each hash algorithm.
+ */
+
+#define MD2_BLOCK_LENGTH 	 64 	/* bytes */
+#define MD5_BLOCK_LENGTH 	 64 	/* bytes */
+#define SHA1_BLOCK_LENGTH 	 64 	/* bytes */
+#define SHA256_BLOCK_LENGTH 	 64 	/* bytes */
+#define SHA384_BLOCK_LENGTH 	128 	/* bytes */
+#define SHA512_BLOCK_LENGTH 	128 	/* bytes */
+#define HASH_BLOCK_LENGTH_MAX 	SHA512_BLOCK_LENGTH
+
+#define AES_KEY_WRAP_IV_BYTES    8
+#define AES_KEY_WRAP_BLOCK_SIZE  8  /* bytes */
+#define AES_BLOCK_SIZE          16  /* bytes */
+
+#define CAMELLIA_BLOCK_SIZE          16  /* bytes */
+
+#define SEED_BLOCK_SIZE 16              /* bytes */
+#define SEED_KEY_LENGTH 16              /* bytes */
+
+#define NSS_FREEBL_DEFAULT_CHUNKSIZE 2048
+
+/*
+ * These values come from the initial key size limits from the PKCS #11
+ * module. They may be arbitrarily adjusted to any value freebl supports.
+ */
+#define RSA_MIN_MODULUS_BITS   128
+#define RSA_MAX_MODULUS_BITS  8192
+#define RSA_MAX_EXPONENT_BITS   64
+#define DH_MIN_P_BITS	       128
+#define DH_MAX_P_BITS         2236
+
+/*
+ * The FIPS 186 algorithm for generating primes P and Q allows only 9
+ * distinct values for the length of P, and only one value for the
+ * length of Q.
+ * The algorithm uses a variable j to indicate which of the 9 lengths
+ * of P is to be used.
+ * The following table relates j to the lengths of P and Q in bits.
+ *
+ *	j	bits in P	bits in Q
+ *	_	_________	_________
+ *	0	 512		160
+ *	1	 576		160
+ *	2	 640		160
+ *	3	 704		160
+ *	4	 768		160
+ *	5	 832		160
+ *	6	 896		160
+ *	7	 960		160
+ *	8	1024		160
+ *
+ * The FIPS-186 compliant PQG generator takes j as an input parameter.
+ */
+
+#define DSA_Q_BITS       160
+#define DSA_MAX_P_BITS	1024
+#define DSA_MIN_P_BITS	 512
+
+/*
+ * function takes desired number of bits in P,
+ * returns index (0..8) or -1 if number of bits is invalid.
+ */
+#define PQG_PBITS_TO_INDEX(bits) \
+    (((bits) < 512 || (bits) > 1024 || (bits) % 64) ? \
+    -1 : (int)((bits)-512)/64)
+
+/*
+ * function takes index (0-8)
+ * returns number of bits in P for that index, or -1 if index is invalid.
+ */
+#define PQG_INDEX_TO_PBITS(j) (((unsigned)(j) > 8) ? -1 : (512 + 64 * (j)))
+
+
+/***************************************************************************
+** Opaque objects 
+*/
+
+struct DESContextStr        ;
+struct RC2ContextStr        ;
+struct RC4ContextStr        ;
+struct RC5ContextStr        ;
+struct AESContextStr        ;
+struct CamelliaContextStr   ;
+struct MD2ContextStr        ;
+struct MD5ContextStr        ;
+struct SHA1ContextStr       ;
+struct SHA256ContextStr     ;
+struct SHA512ContextStr     ;
+struct AESKeyWrapContextStr ;
+struct SEEDContextStr       ;	
+
+typedef struct DESContextStr        DESContext;
+typedef struct RC2ContextStr        RC2Context;
+typedef struct RC4ContextStr        RC4Context;
+typedef struct RC5ContextStr        RC5Context;
+typedef struct AESContextStr        AESContext;
+typedef struct CamelliaContextStr   CamelliaContext;
+typedef struct MD2ContextStr        MD2Context;
+typedef struct MD5ContextStr        MD5Context;
+typedef struct SHA1ContextStr       SHA1Context;
+typedef struct SHA256ContextStr     SHA256Context;
+typedef struct SHA512ContextStr     SHA512Context;
+/* SHA384Context is really a SHA512ContextStr.  This is not a mistake. */
+typedef struct SHA512ContextStr     SHA384Context;
+typedef struct AESKeyWrapContextStr AESKeyWrapContext;
+typedef struct SEEDContextStr	    SEEDContext;	
+
+/***************************************************************************
+** RSA Public and Private Key structures
+*/
+
+/* member names from PKCS#1, section 7.1 */
+struct RSAPublicKeyStr {
+    PLArenaPool * arena;
+    SECItem modulus;
+    SECItem publicExponent;
+};
+typedef struct RSAPublicKeyStr RSAPublicKey;
+
+/* member names from PKCS#1, section 7.2 */
+struct RSAPrivateKeyStr {
+    PLArenaPool * arena;
+    SECItem version;
+    SECItem modulus;
+    SECItem publicExponent;
+    SECItem privateExponent;
+    SECItem prime1;
+    SECItem prime2;
+    SECItem exponent1;
+    SECItem exponent2;
+    SECItem coefficient;
+};
+typedef struct RSAPrivateKeyStr RSAPrivateKey;
+
+
+/***************************************************************************
+** DSA Public and Private Key and related structures
+*/
+
+struct PQGParamsStr {
+    PLArenaPool *arena;
+    SECItem prime;    /* p */
+    SECItem subPrime; /* q */
+    SECItem base;     /* g */
+    /* XXX chrisk: this needs to be expanded to hold j and validationParms (RFC2459 7.3.2) */
+};
+typedef struct PQGParamsStr PQGParams;
+
+struct PQGVerifyStr {
+    PLArenaPool * arena;	/* includes this struct, seed, & h. */
+    unsigned int  counter;
+    SECItem       seed;
+    SECItem       h;
+};
+typedef struct PQGVerifyStr PQGVerify;
+
+struct DSAPublicKeyStr {
+    PQGParams params;
+    SECItem publicValue;
+};
+typedef struct DSAPublicKeyStr DSAPublicKey;
+
+struct DSAPrivateKeyStr {
+    PQGParams params;
+    SECItem publicValue;
+    SECItem privateValue;
+};
+typedef struct DSAPrivateKeyStr DSAPrivateKey;
+
+/***************************************************************************
+** Diffie-Hellman Public and Private Key and related structures
+** Structure member names suggested by PKCS#3.
+*/
+
+struct DHParamsStr {
+    PLArenaPool * arena;
+    SECItem prime; /* p */
+    SECItem base; /* g */
+};
+typedef struct DHParamsStr DHParams;
+
+struct DHPublicKeyStr {
+    PLArenaPool * arena;
+    SECItem prime;
+    SECItem base;
+    SECItem publicValue;
+};
+typedef struct DHPublicKeyStr DHPublicKey;
+
+struct DHPrivateKeyStr {
+    PLArenaPool * arena;
+    SECItem prime;
+    SECItem base;
+    SECItem publicValue;
+    SECItem privateValue;
+};
+typedef struct DHPrivateKeyStr DHPrivateKey;
+
+/***************************************************************************
+** Data structures used for elliptic curve parameters and
+** public and private keys.
+*/
+
+/*
+** The ECParams data structures can encode elliptic curve 
+** parameters for both GFp and GF2m curves.
+*/
+
+typedef enum { ec_params_explicit,
+	       ec_params_named
+} ECParamsType;
+
+typedef enum { ec_field_GFp = 1,
+               ec_field_GF2m
+} ECFieldType;
+
+struct ECFieldIDStr {
+    int         size;   /* field size in bits */
+    ECFieldType type;
+    union {
+        SECItem  prime; /* prime p for (GFp) */
+        SECItem  poly;  /* irreducible binary polynomial for (GF2m) */
+    } u;
+    int         k1;     /* first coefficient of pentanomial or
+                         * the only coefficient of trinomial 
+                         */
+    int         k2;     /* two remaining coefficients of pentanomial */
+    int         k3;
+};
+typedef struct ECFieldIDStr ECFieldID;
+
+struct ECCurveStr {
+    SECItem a;          /* contains octet stream encoding of
+                         * field element (X9.62 section 4.3.3) 
+			 */
+    SECItem b;
+    SECItem seed;
+};
+typedef struct ECCurveStr ECCurve;
+
+struct ECParamsStr {
+    PLArenaPool * arena;
+    ECParamsType  type;
+    ECFieldID     fieldID;
+    ECCurve       curve; 
+    SECItem       base;
+    SECItem       order; 
+    int           cofactor;
+    SECItem       DEREncoding;
+    ECCurveName   name;
+    SECItem       curveOID;
+};
+typedef struct ECParamsStr ECParams;
+
+struct ECPublicKeyStr {
+    ECParams ecParams;   
+    SECItem publicValue;   /* elliptic curve point encoded as 
+			    * octet stream.
+			    */
+};
+typedef struct ECPublicKeyStr ECPublicKey;
+
+struct ECPrivateKeyStr {
+    ECParams ecParams;   
+    SECItem publicValue;   /* encoded ec point */
+    SECItem privateValue;  /* private big integer */
+    SECItem version;       /* As per SEC 1, Appendix C, Section C.4 */
+};
+typedef struct ECPrivateKeyStr ECPrivateKey;
+
+typedef void * (*BLapiAllocateFunc)(void);
+typedef void (*BLapiDestroyContextFunc)(void *cx, PRBool freeit);
+typedef SECStatus (*BLapiInitContextFunc)(void *cx, 
+				   const unsigned char *key, 
+				   unsigned int keylen,
+				   const unsigned char *, 
+				   int, 
+				   unsigned int ,
+				   unsigned int );
+typedef SECStatus (*BLapiEncrypt)(void *cx, unsigned char *output,
+				unsigned int *outputLen, 
+				unsigned int maxOutputLen,
+				const unsigned char *input, 
+				unsigned int inputLen);
+
+#endif /* _BLAPIT_H_ */
diff --git a/mozilla/security/nss/lib/freebl/camellia.c b/mozilla/security/nss/lib/freebl/camellia.c
new file mode 100644
index 0000000..0913fea
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/camellia.c
@@ -0,0 +1,1795 @@
+/* ***** 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 Camellia code.
+ *
+ * The Initial Developer of the Original Code is
+ * NTT(Nippon Telegraph and Telephone Corporation).
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * 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 ***** */
+
+/*
+ * $Id: camellia.c,v 1.2 2008/11/18 19:48:22 rrelyea%redhat.com Exp $
+ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prinit.h"
+#include "prerr.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+#include "blapi.h"
+#include "camellia.h"
+
+
+/* key constants */
+
+#define CAMELLIA_SIGMA1L (0xA09E667FL)
+#define CAMELLIA_SIGMA1R (0x3BCC908BL)
+#define CAMELLIA_SIGMA2L (0xB67AE858L)
+#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
+#define CAMELLIA_SIGMA3L (0xC6EF372FL)
+#define CAMELLIA_SIGMA3R (0xE94F82BEL)
+#define CAMELLIA_SIGMA4L (0x54FF53A5L)
+#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
+#define CAMELLIA_SIGMA5L (0x10E527FAL)
+#define CAMELLIA_SIGMA5R (0xDE682D1DL)
+#define CAMELLIA_SIGMA6L (0xB05688C2L)
+#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
+
+/*
+ *  macros
+ */
+
+
+#if defined(_MSC_VER)
+
+# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+# define GETU32(p) SWAP(*((PRUint32 *)(p)))
+# define PUTU32(ct, st) {*((PRUint32 *)(ct)) = SWAP((st));}
+
+#else /* not MS-VC */
+
+# define GETU32(pt)					\
+    (((PRUint32)(pt)[0] << 24)				\
+     ^ ((PRUint32)(pt)[1] << 16)			\
+     ^ ((PRUint32)(pt)[2] <<  8)			\
+     ^ ((PRUint32)(pt)[3]))
+
+# define PUTU32(ct, st)  {				\
+	(ct)[0] = (PRUint8)((st) >> 24);		\
+	(ct)[1] = (PRUint8)((st) >> 16);		\
+	(ct)[2] = (PRUint8)((st) >>  8);		\
+	(ct)[3] = (PRUint8)(st); }
+
+#endif
+
+#define CamelliaSubkeyL(INDEX) (subkey[(INDEX)*2])
+#define CamelliaSubkeyR(INDEX) (subkey[(INDEX)*2 + 1])
+
+/* rotation right shift 1byte */
+#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24))
+/* rotation left shift 1bit */
+#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31))
+/* rotation left shift 1byte */
+#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24))
+
+#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits)	\
+    do {						\
+	w0 = ll;					\
+	ll = (ll << bits) + (lr >> (32 - bits));	\
+	lr = (lr << bits) + (rl >> (32 - bits));	\
+	rl = (rl << bits) + (rr >> (32 - bits));	\
+	rr = (rr << bits) + (w0 >> (32 - bits));	\
+    } while(0)
+
+#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits)	\
+    do {						\
+	w0 = ll;					\
+	w1 = lr;					\
+	ll = (lr << (bits - 32)) + (rl >> (64 - bits));	\
+	lr = (rl << (bits - 32)) + (rr >> (64 - bits));	\
+	rl = (rr << (bits - 32)) + (w0 >> (64 - bits));	\
+	rr = (w0 << (bits - 32)) + (w1 >> (64 - bits));	\
+    } while(0)
+
+#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)])
+#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)])
+#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)])
+#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)])
+
+#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)	\
+    do {							\
+	il = xl ^ kl;						\
+	ir = xr ^ kr;						\
+	t0 = il >> 16;						\
+	t1 = ir >> 16;						\
+	yl = CAMELLIA_SP1110(ir & 0xff)				\
+	    ^ CAMELLIA_SP0222((t1 >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP3033(t1 & 0xff)			\
+	    ^ CAMELLIA_SP4404((ir >> 8) & 0xff);		\
+	yr = CAMELLIA_SP1110((t0 >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP0222(t0 & 0xff)			\
+	    ^ CAMELLIA_SP3033((il >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP4404(il & 0xff);			\
+	yl ^= yr;						\
+	yr = CAMELLIA_RR8(yr);					\
+	yr ^= yl;						\
+    } while(0)
+
+
+/*
+ * for speed up
+ *
+ */
+#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \
+    do {								\
+	t0 = kll;							\
+	t0 &= ll;							\
+	lr ^= CAMELLIA_RL1(t0);						\
+	t1 = klr;							\
+	t1 |= lr;							\
+	ll ^= t1;							\
+									\
+	t2 = krr;							\
+	t2 |= rr;							\
+	rl ^= t2;							\
+	t3 = krl;							\
+	t3 &= rl;							\
+	rr ^= CAMELLIA_RL1(t3);						\
+    } while(0)
+
+#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)	\
+    do {								\
+	ir = CAMELLIA_SP1110(xr & 0xff)					\
+	    ^ CAMELLIA_SP0222((xr >> 24) & 0xff)			\
+	    ^ CAMELLIA_SP3033((xr >> 16) & 0xff)			\
+	    ^ CAMELLIA_SP4404((xr >> 8) & 0xff);			\
+	il = CAMELLIA_SP1110((xl >> 24) & 0xff)				\
+	    ^ CAMELLIA_SP0222((xl >> 16) & 0xff)			\
+	    ^ CAMELLIA_SP3033((xl >> 8) & 0xff)				\
+	    ^ CAMELLIA_SP4404(xl & 0xff);				\
+	il ^= kl;							\
+	ir ^= kr;							\
+	ir ^= il;							\
+	il = CAMELLIA_RR8(il);						\
+	il ^= ir;							\
+	yl ^= ir;							\
+	yr ^= il;							\
+    } while(0)
+
+
+static const PRUint32 camellia_sp1110[256] = {
+    0x70707000,0x82828200,0x2c2c2c00,0xececec00,
+    0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500,
+    0xe4e4e400,0x85858500,0x57575700,0x35353500,
+    0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100,
+    0x23232300,0xefefef00,0x6b6b6b00,0x93939300,
+    0x45454500,0x19191900,0xa5a5a500,0x21212100,
+    0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00,
+    0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00,
+    0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00,
+    0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00,
+    0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00,
+    0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00,
+    0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00,
+    0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00,
+    0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600,
+    0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00,
+    0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600,
+    0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00,
+    0x74747400,0x12121200,0x2b2b2b00,0x20202000,
+    0xf0f0f000,0xb1b1b100,0x84848400,0x99999900,
+    0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200,
+    0x34343400,0x7e7e7e00,0x76767600,0x05050500,
+    0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100,
+    0xd1d1d100,0x17171700,0x04040400,0xd7d7d700,
+    0x14141400,0x58585800,0x3a3a3a00,0x61616100,
+    0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00,
+    0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600,
+    0x53535300,0x18181800,0xf2f2f200,0x22222200,
+    0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200,
+    0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100,
+    0x24242400,0x08080800,0xe8e8e800,0xa8a8a800,
+    0x60606000,0xfcfcfc00,0x69696900,0x50505000,
+    0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00,
+    0xa1a1a100,0x89898900,0x62626200,0x97979700,
+    0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500,
+    0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200,
+    0x10101000,0xc4c4c400,0x00000000,0x48484800,
+    0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00,
+    0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00,
+    0x09090900,0x3f3f3f00,0xdddddd00,0x94949400,
+    0x87878700,0x5c5c5c00,0x83838300,0x02020200,
+    0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300,
+    0x73737300,0x67676700,0xf6f6f600,0xf3f3f300,
+    0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200,
+    0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600,
+    0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00,
+    0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00,
+    0x13131300,0xbebebe00,0x63636300,0x2e2e2e00,
+    0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00,
+    0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00,
+    0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600,
+    0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900,
+    0x78787800,0x98989800,0x06060600,0x6a6a6a00,
+    0xe7e7e700,0x46464600,0x71717100,0xbababa00,
+    0xd4d4d400,0x25252500,0xababab00,0x42424200,
+    0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00,
+    0x72727200,0x07070700,0xb9b9b900,0x55555500,
+    0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00,
+    0x36363600,0x49494900,0x2a2a2a00,0x68686800,
+    0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400,
+    0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00,
+    0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100,
+    0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400,
+    0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00,
+};
+
+static const PRUint32 camellia_sp0222[256] = {
+    0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9,
+    0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb,
+    0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a,
+    0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282,
+    0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727,
+    0x008a8a8a,0x00323232,0x004b4b4b,0x00424242,
+    0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c,
+    0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b,
+    0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f,
+    0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d,
+    0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe,
+    0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434,
+    0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595,
+    0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a,
+    0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad,
+    0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a,
+    0x00171717,0x001a1a1a,0x00353535,0x00cccccc,
+    0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a,
+    0x00e8e8e8,0x00242424,0x00565656,0x00404040,
+    0x00e1e1e1,0x00636363,0x00090909,0x00333333,
+    0x00bfbfbf,0x00989898,0x00979797,0x00858585,
+    0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a,
+    0x00dadada,0x006f6f6f,0x00535353,0x00626262,
+    0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf,
+    0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2,
+    0x00bdbdbd,0x00363636,0x00222222,0x00383838,
+    0x00646464,0x001e1e1e,0x00393939,0x002c2c2c,
+    0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444,
+    0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565,
+    0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323,
+    0x00484848,0x00101010,0x00d1d1d1,0x00515151,
+    0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0,
+    0x00555555,0x00a1a1a1,0x00414141,0x00fafafa,
+    0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f,
+    0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b,
+    0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5,
+    0x00202020,0x00898989,0x00000000,0x00909090,
+    0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7,
+    0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5,
+    0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929,
+    0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404,
+    0x009b9b9b,0x00949494,0x00212121,0x00666666,
+    0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7,
+    0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5,
+    0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c,
+    0x00919191,0x006e6e6e,0x008d8d8d,0x00767676,
+    0x00030303,0x002d2d2d,0x00dedede,0x00969696,
+    0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c,
+    0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919,
+    0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d,
+    0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d,
+    0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2,
+    0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4,
+    0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575,
+    0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484,
+    0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5,
+    0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa,
+    0x00f1f1f1,0x00dddddd,0x00595959,0x00141414,
+    0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0,
+    0x00787878,0x00707070,0x00e3e3e3,0x00494949,
+    0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6,
+    0x00777777,0x00939393,0x00868686,0x00838383,
+    0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9,
+    0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d,
+};
+
+static const PRUint32 camellia_sp3033[256] = {
+    0x38003838,0x41004141,0x16001616,0x76007676,
+    0xd900d9d9,0x93009393,0x60006060,0xf200f2f2,
+    0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a,
+    0x75007575,0x06000606,0x57005757,0xa000a0a0,
+    0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9,
+    0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090,
+    0xf600f6f6,0x07000707,0xa700a7a7,0x27002727,
+    0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede,
+    0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7,
+    0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767,
+    0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf,
+    0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d,
+    0x53005353,0xf000f0f0,0x9c009c9c,0x65006565,
+    0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e,
+    0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b,
+    0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6,
+    0xc500c5c5,0x86008686,0x4d004d4d,0x33003333,
+    0xfd00fdfd,0x66006666,0x58005858,0x96009696,
+    0x3a003a3a,0x09000909,0x95009595,0x10001010,
+    0x78007878,0xd800d8d8,0x42004242,0xcc00cccc,
+    0xef00efef,0x26002626,0xe500e5e5,0x61006161,
+    0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282,
+    0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898,
+    0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb,
+    0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0,
+    0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e,
+    0x19001919,0x87008787,0x4e004e4e,0x0b000b0b,
+    0xa900a9a9,0x0c000c0c,0x79007979,0x11001111,
+    0x7f007f7f,0x22002222,0xe700e7e7,0x59005959,
+    0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8,
+    0x12001212,0x04000404,0x74007474,0x54005454,
+    0x30003030,0x7e007e7e,0xb400b4b4,0x28002828,
+    0x55005555,0x68006868,0x50005050,0xbe00bebe,
+    0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb,
+    0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca,
+    0x70007070,0xff00ffff,0x32003232,0x69006969,
+    0x08000808,0x62006262,0x00000000,0x24002424,
+    0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded,
+    0x45004545,0x81008181,0x73007373,0x6d006d6d,
+    0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a,
+    0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101,
+    0xe600e6e6,0x25002525,0x48004848,0x99009999,
+    0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9,
+    0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171,
+    0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313,
+    0x64006464,0x9b009b9b,0x63006363,0x9d009d9d,
+    0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5,
+    0x89008989,0x5f005f5f,0xb100b1b1,0x17001717,
+    0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646,
+    0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747,
+    0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b,
+    0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac,
+    0x3c003c3c,0x4c004c4c,0x03000303,0x35003535,
+    0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d,
+    0x6a006a6a,0x92009292,0xd500d5d5,0x21002121,
+    0x44004444,0x51005151,0xc600c6c6,0x7d007d7d,
+    0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa,
+    0x7c007c7c,0x77007777,0x56005656,0x05000505,
+    0x1b001b1b,0xa400a4a4,0x15001515,0x34003434,
+    0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252,
+    0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd,
+    0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0,
+    0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a,
+    0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f,
+};
+
+static const PRUint32 camellia_sp4404[256] = {
+    0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0,
+    0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae,
+    0x23230023,0x6b6b006b,0x45450045,0xa5a500a5,
+    0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092,
+    0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f,
+    0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b,
+    0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d,
+    0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c,
+    0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0,
+    0x74740074,0x2b2b002b,0xf0f000f0,0x84840084,
+    0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076,
+    0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004,
+    0x14140014,0x3a3a003a,0xdede00de,0x11110011,
+    0x32320032,0x9c9c009c,0x53530053,0xf2f200f2,
+    0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a,
+    0x24240024,0xe8e800e8,0x60600060,0x69690069,
+    0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062,
+    0x54540054,0x1e1e001e,0xe0e000e0,0x64640064,
+    0x10100010,0x00000000,0xa3a300a3,0x75750075,
+    0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd,
+    0x87870087,0x83830083,0xcdcd00cd,0x90900090,
+    0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf,
+    0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6,
+    0x81810081,0x6f6f006f,0x13130013,0x63630063,
+    0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc,
+    0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4,
+    0x78780078,0x06060006,0xe7e700e7,0x71710071,
+    0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d,
+    0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac,
+    0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1,
+    0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043,
+    0x15150015,0xadad00ad,0x77770077,0x80800080,
+    0x82820082,0xecec00ec,0x27270027,0xe5e500e5,
+    0x85850085,0x35350035,0x0c0c000c,0x41410041,
+    0xefef00ef,0x93930093,0x19190019,0x21210021,
+    0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd,
+    0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce,
+    0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a,
+    0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d,
+    0x01010001,0xd6d600d6,0x56560056,0x4d4d004d,
+    0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d,
+    0x12120012,0x20200020,0xb1b100b1,0x99990099,
+    0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005,
+    0xb7b700b7,0x31310031,0x17170017,0xd7d700d7,
+    0x58580058,0x61610061,0x1b1b001b,0x1c1c001c,
+    0x0f0f000f,0x16160016,0x18180018,0x22220022,
+    0x44440044,0xb2b200b2,0xb5b500b5,0x91910091,
+    0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050,
+    0xd0d000d0,0x7d7d007d,0x89890089,0x97970097,
+    0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2,
+    0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db,
+    0x03030003,0xdada00da,0x3f3f003f,0x94940094,
+    0x5c5c005c,0x02020002,0x4a4a004a,0x33330033,
+    0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2,
+    0x9b9b009b,0x26260026,0x37370037,0x3b3b003b,
+    0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e,
+    0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e,
+    0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059,
+    0x98980098,0x6a6a006a,0x46460046,0xbaba00ba,
+    0x25250025,0x42420042,0xa2a200a2,0xfafa00fa,
+    0x07070007,0x55550055,0xeeee00ee,0x0a0a000a,
+    0x49490049,0x68680068,0x38380038,0xa4a400a4,
+    0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1,
+    0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e,
+};
+
+
+/**
+ * Stuff related to the Camellia key schedule
+ */
+#define subl(x) subL[(x)]
+#define subr(x) subR[(x)]
+
+void camellia_setup128(const unsigned char *key, PRUint32 *subkey)
+{
+    PRUint32 kll, klr, krl, krr;
+    PRUint32 il, ir, t0, t1, w0, w1;
+    PRUint32 kw4l, kw4r, dw, tl, tr;
+    PRUint32 subL[26];
+    PRUint32 subR[26];
+
+    /**
+     *  k == kll || klr || krl || krr (|| is concatination)
+     */
+    kll = GETU32(key     );
+    klr = GETU32(key +  4);
+    krl = GETU32(key +  8);
+    krr = GETU32(key + 12);
+    /**
+     * generate KL dependent subkeys
+     */
+    subl(0) = kll; subr(0) = klr;
+    subl(1) = krl; subr(1) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(4) = kll; subr(4) = klr;
+    subl(5) = krl; subr(5) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+    subl(10) = kll; subr(10) = klr;
+    subl(11) = krl; subr(11) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(13) = krl; subr(13) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(16) = kll; subr(16) = klr;
+    subl(17) = krl; subr(17) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(18) = kll; subr(18) = klr;
+    subl(19) = krl; subr(19) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(22) = kll; subr(22) = klr;
+    subl(23) = krl; subr(23) = krr;
+
+    /* generate KA */
+    kll = subl(0); klr = subr(0);
+    krl = subl(1); krr = subr(1);
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+	       w0, w1, il, ir, t0, t1);
+    krl ^= w0; krr ^= w1;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+	       kll, klr, il, ir, t0, t1);
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+	       krl, krr, il, ir, t0, t1);
+    krl ^= w0; krr ^= w1;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+	       w0, w1, il, ir, t0, t1);
+    kll ^= w0; klr ^= w1;
+
+    /* generate KA dependent subkeys */
+    subl(2) = kll; subr(2) = klr;
+    subl(3) = krl; subr(3) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(6) = kll; subr(6) = klr;
+    subl(7) = krl; subr(7) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(8) = kll; subr(8) = klr;
+    subl(9) = krl; subr(9) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(12) = kll; subr(12) = klr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(14) = kll; subr(14) = klr;
+    subl(15) = krl; subr(15) = krr;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+    subl(20) = kll; subr(20) = klr;
+    subl(21) = krl; subr(21) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(24) = kll; subr(24) = klr;
+    subl(25) = krl; subr(25) = krr;
+
+
+    /* absorb kw2 to other subkeys */
+    subl(3) ^= subl(1); subr(3) ^= subr(1);
+    subl(5) ^= subl(1); subr(5) ^= subr(1);
+    subl(7) ^= subl(1); subr(7) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(9);
+    dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(11) ^= subl(1); subr(11) ^= subr(1);
+    subl(13) ^= subl(1); subr(13) ^= subr(1);
+    subl(15) ^= subl(1); subr(15) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(17);
+    dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(19) ^= subl(1); subr(19) ^= subr(1);
+    subl(21) ^= subl(1); subr(21) ^= subr(1);
+    subl(23) ^= subl(1); subr(23) ^= subr(1);
+    subl(24) ^= subl(1); subr(24) ^= subr(1);
+
+    /* absorb kw4 to other subkeys */
+    kw4l = subl(25); kw4r = subr(25);
+    subl(22) ^= kw4l; subr(22) ^= kw4r;
+    subl(20) ^= kw4l; subr(20) ^= kw4r;
+    subl(18) ^= kw4l; subr(18) ^= kw4r;
+    kw4l ^= kw4r & ~subr(16);
+    dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw);
+    subl(14) ^= kw4l; subr(14) ^= kw4r;
+    subl(12) ^= kw4l; subr(12) ^= kw4r;
+    subl(10) ^= kw4l; subr(10) ^= kw4r;
+    kw4l ^= kw4r & ~subr(8);
+    dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw);
+    subl(6) ^= kw4l; subr(6) ^= kw4r;
+    subl(4) ^= kw4l; subr(4) ^= kw4r;
+    subl(2) ^= kw4l; subr(2) ^= kw4r;
+    subl(0) ^= kw4l; subr(0) ^= kw4r;
+
+    /* key XOR is end of F-function */
+    CamelliaSubkeyL(0) = subl(0) ^ subl(2);
+    CamelliaSubkeyR(0) = subr(0) ^ subr(2);
+    CamelliaSubkeyL(2) = subl(3);
+    CamelliaSubkeyR(2) = subr(3);
+    CamelliaSubkeyL(3) = subl(2) ^ subl(4);
+    CamelliaSubkeyR(3) = subr(2) ^ subr(4);
+    CamelliaSubkeyL(4) = subl(3) ^ subl(5);
+    CamelliaSubkeyR(4) = subr(3) ^ subr(5);
+    CamelliaSubkeyL(5) = subl(4) ^ subl(6);
+    CamelliaSubkeyR(5) = subr(4) ^ subr(6);
+    CamelliaSubkeyL(6) = subl(5) ^ subl(7);
+    CamelliaSubkeyR(6) = subr(5) ^ subr(7);
+    tl = subl(10) ^ (subr(10) & ~subr(8));
+    dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(7) = subl(6) ^ tl;
+    CamelliaSubkeyR(7) = subr(6) ^ tr;
+    CamelliaSubkeyL(8) = subl(8);
+    CamelliaSubkeyR(8) = subr(8);
+    CamelliaSubkeyL(9) = subl(9);
+    CamelliaSubkeyR(9) = subr(9);
+    tl = subl(7) ^ (subr(7) & ~subr(9));
+    dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(10) = tl ^ subl(11);
+    CamelliaSubkeyR(10) = tr ^ subr(11);
+    CamelliaSubkeyL(11) = subl(10) ^ subl(12);
+    CamelliaSubkeyR(11) = subr(10) ^ subr(12);
+    CamelliaSubkeyL(12) = subl(11) ^ subl(13);
+    CamelliaSubkeyR(12) = subr(11) ^ subr(13);
+    CamelliaSubkeyL(13) = subl(12) ^ subl(14);
+    CamelliaSubkeyR(13) = subr(12) ^ subr(14);
+    CamelliaSubkeyL(14) = subl(13) ^ subl(15);
+    CamelliaSubkeyR(14) = subr(13) ^ subr(15);
+    tl = subl(18) ^ (subr(18) & ~subr(16));
+    dw = tl & subl(16),	tr = subr(18) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(15) = subl(14) ^ tl;
+    CamelliaSubkeyR(15) = subr(14) ^ tr;
+    CamelliaSubkeyL(16) = subl(16);
+    CamelliaSubkeyR(16) = subr(16);
+    CamelliaSubkeyL(17) = subl(17);
+    CamelliaSubkeyR(17) = subr(17);
+    tl = subl(15) ^ (subr(15) & ~subr(17));
+    dw = tl & subl(17),	tr = subr(15) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(18) = tl ^ subl(19);
+    CamelliaSubkeyR(18) = tr ^ subr(19);
+    CamelliaSubkeyL(19) = subl(18) ^ subl(20);
+    CamelliaSubkeyR(19) = subr(18) ^ subr(20);
+    CamelliaSubkeyL(20) = subl(19) ^ subl(21);
+    CamelliaSubkeyR(20) = subr(19) ^ subr(21);
+    CamelliaSubkeyL(21) = subl(20) ^ subl(22);
+    CamelliaSubkeyR(21) = subr(20) ^ subr(22);
+    CamelliaSubkeyL(22) = subl(21) ^ subl(23);
+    CamelliaSubkeyR(22) = subr(21) ^ subr(23);
+    CamelliaSubkeyL(23) = subl(22);
+    CamelliaSubkeyR(23) = subr(22);
+    CamelliaSubkeyL(24) = subl(24) ^ subl(23);
+    CamelliaSubkeyR(24) = subr(24) ^ subr(23);
+
+    /* apply the inverse of the last half of P-function */
+    dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw;
+    dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw;
+    dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw;
+    dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw;
+    dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw;
+    dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw;
+    dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw;
+    dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw;
+    dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw;
+    dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw;
+    dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw;
+    dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw;
+    dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw;
+    dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw;
+    dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw;
+    dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw;
+    dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw;
+    dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw;
+
+    return;
+}
+
+void camellia_setup256(const unsigned char *key, PRUint32 *subkey)
+{
+    PRUint32 kll,klr,krl,krr;           /* left half of key */
+    PRUint32 krll,krlr,krrl,krrr;       /* right half of key */
+    PRUint32 il, ir, t0, t1, w0, w1;    /* temporary variables */
+    PRUint32 kw4l, kw4r, dw, tl, tr;
+    PRUint32 subL[34];
+    PRUint32 subR[34];
+
+    /**
+     *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
+     *  (|| is concatination)
+     */
+
+    kll  = GETU32(key     );
+    klr  = GETU32(key +  4);
+    krl  = GETU32(key +  8);
+    krr  = GETU32(key + 12);
+    krll = GETU32(key + 16);
+    krlr = GETU32(key + 20);
+    krrl = GETU32(key + 24);
+    krrr = GETU32(key + 28);
+
+    /* generate KL dependent subkeys */
+    subl(0) = kll; subr(0) = klr;
+    subl(1) = krl; subr(1) = krr;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
+    subl(12) = kll; subr(12) = klr;
+    subl(13) = krl; subr(13) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(16) = kll; subr(16) = klr;
+    subl(17) = krl; subr(17) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(22) = kll; subr(22) = klr;
+    subl(23) = krl; subr(23) = krr;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+    subl(30) = kll; subr(30) = klr;
+    subl(31) = krl; subr(31) = krr;
+
+    /* generate KR dependent subkeys */
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+    subl(4) = krll; subr(4) = krlr;
+    subl(5) = krrl; subr(5) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+    subl(8) = krll; subr(8) = krlr;
+    subl(9) = krrl; subr(9) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+    subl(18) = krll; subr(18) = krlr;
+    subl(19) = krrl; subr(19) = krrr;
+    CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+    subl(26) = krll; subr(26) = krlr;
+    subl(27) = krrl; subr(27) = krrr;
+    CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+
+    /* generate KA */
+    kll = subl(0) ^ krll; klr = subr(0) ^ krlr;
+    krl = subl(1) ^ krrl; krr = subr(1) ^ krrr;
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+	       w0, w1, il, ir, t0, t1);
+    krl ^= w0; krr ^= w1;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+	       kll, klr, il, ir, t0, t1);
+    kll ^= krll; klr ^= krlr;
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+	       krl, krr, il, ir, t0, t1);
+    krl ^= w0 ^ krrl; krr ^= w1 ^ krrr;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+	       w0, w1, il, ir, t0, t1);
+    kll ^= w0; klr ^= w1;
+
+    /* generate KB */
+    krll ^= kll; krlr ^= klr;
+    krrl ^= krl; krrr ^= krr;
+    CAMELLIA_F(krll, krlr,
+	       CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R,
+	       w0, w1, il, ir, t0, t1);
+    krrl ^= w0; krrr ^= w1;
+    CAMELLIA_F(krrl, krrr,
+	       CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R,
+	       w0, w1, il, ir, t0, t1);
+    krll ^= w0; krlr ^= w1;
+
+    /* generate KA dependent subkeys */
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(6) = kll; subr(6) = klr;
+    subl(7) = krl; subr(7) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+    subl(14) = kll; subr(14) = klr;
+    subl(15) = krl; subr(15) = krr;
+    subl(24) = klr; subr(24) = krl;
+    subl(25) = krr; subr(25) = kll;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
+    subl(28) = kll; subr(28) = klr;
+    subl(29) = krl; subr(29) = krr;
+
+    /* generate KB dependent subkeys */
+    subl(2) = krll; subr(2) = krlr;
+    subl(3) = krrl; subr(3) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+    subl(10) = krll; subr(10) = krlr;
+    subl(11) = krrl; subr(11) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+    subl(20) = krll; subr(20) = krlr;
+    subl(21) = krrl; subr(21) = krrr;
+    CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
+    subl(32) = krll; subr(32) = krlr;
+    subl(33) = krrl; subr(33) = krrr;
+
+    /* absorb kw2 to other subkeys */
+    subl(3) ^= subl(1); subr(3) ^= subr(1);
+    subl(5) ^= subl(1); subr(5) ^= subr(1);
+    subl(7) ^= subl(1); subr(7) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(9);
+    dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(11) ^= subl(1); subr(11) ^= subr(1);
+    subl(13) ^= subl(1); subr(13) ^= subr(1);
+    subl(15) ^= subl(1); subr(15) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(17);
+    dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(19) ^= subl(1); subr(19) ^= subr(1);
+    subl(21) ^= subl(1); subr(21) ^= subr(1);
+    subl(23) ^= subl(1); subr(23) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(25);
+    dw = subl(1) & subl(25), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(27) ^= subl(1); subr(27) ^= subr(1);
+    subl(29) ^= subl(1); subr(29) ^= subr(1);
+    subl(31) ^= subl(1); subr(31) ^= subr(1);
+    subl(32) ^= subl(1); subr(32) ^= subr(1);
+
+    /* absorb kw4 to other subkeys */
+    kw4l = subl(33); kw4r = subr(33);
+    subl(30) ^= kw4l; subr(30) ^= kw4r;
+    subl(28) ^= kw4l; subr(28) ^= kw4r;
+    subl(26) ^= kw4l; subr(26) ^= kw4r;
+    kw4l ^= kw4r & ~subr(24);
+    dw = kw4l & subl(24), kw4r ^= CAMELLIA_RL1(dw);
+    subl(22) ^= kw4l; subr(22) ^= kw4r;
+    subl(20) ^= kw4l; subr(20) ^= kw4r;
+    subl(18) ^= kw4l; subr(18) ^= kw4r;
+    kw4l ^= kw4r & ~subr(16);
+    dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw);
+    subl(14) ^= kw4l; subr(14) ^= kw4r;
+    subl(12) ^= kw4l; subr(12) ^= kw4r;
+    subl(10) ^= kw4l; subr(10) ^= kw4r;
+    kw4l ^= kw4r & ~subr(8);
+    dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw);
+    subl(6) ^= kw4l; subr(6) ^= kw4r;
+    subl(4) ^= kw4l; subr(4) ^= kw4r;
+    subl(2) ^= kw4l; subr(2) ^= kw4r;
+    subl(0) ^= kw4l; subr(0) ^= kw4r;
+
+    /* key XOR is end of F-function */
+    CamelliaSubkeyL(0) = subl(0) ^ subl(2);
+    CamelliaSubkeyR(0) = subr(0) ^ subr(2);
+    CamelliaSubkeyL(2) = subl(3);
+    CamelliaSubkeyR(2) = subr(3);
+    CamelliaSubkeyL(3) = subl(2) ^ subl(4);
+    CamelliaSubkeyR(3) = subr(2) ^ subr(4);
+    CamelliaSubkeyL(4) = subl(3) ^ subl(5);
+    CamelliaSubkeyR(4) = subr(3) ^ subr(5);
+    CamelliaSubkeyL(5) = subl(4) ^ subl(6);
+    CamelliaSubkeyR(5) = subr(4) ^ subr(6);
+    CamelliaSubkeyL(6) = subl(5) ^ subl(7);
+    CamelliaSubkeyR(6) = subr(5) ^ subr(7);
+    tl = subl(10) ^ (subr(10) & ~subr(8));
+    dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(7) = subl(6) ^ tl;
+    CamelliaSubkeyR(7) = subr(6) ^ tr;
+    CamelliaSubkeyL(8) = subl(8);
+    CamelliaSubkeyR(8) = subr(8);
+    CamelliaSubkeyL(9) = subl(9);
+    CamelliaSubkeyR(9) = subr(9);
+    tl = subl(7) ^ (subr(7) & ~subr(9));
+    dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(10) = tl ^ subl(11);
+    CamelliaSubkeyR(10) = tr ^ subr(11);
+    CamelliaSubkeyL(11) = subl(10) ^ subl(12);
+    CamelliaSubkeyR(11) = subr(10) ^ subr(12);
+    CamelliaSubkeyL(12) = subl(11) ^ subl(13);
+    CamelliaSubkeyR(12) = subr(11) ^ subr(13);
+    CamelliaSubkeyL(13) = subl(12) ^ subl(14);
+    CamelliaSubkeyR(13) = subr(12) ^ subr(14);
+    CamelliaSubkeyL(14) = subl(13) ^ subl(15);
+    CamelliaSubkeyR(14) = subr(13) ^ subr(15);
+    tl = subl(18) ^ (subr(18) & ~subr(16));
+    dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(15) = subl(14) ^ tl;
+    CamelliaSubkeyR(15) = subr(14) ^ tr;
+    CamelliaSubkeyL(16) = subl(16);
+    CamelliaSubkeyR(16) = subr(16);
+    CamelliaSubkeyL(17) = subl(17);
+    CamelliaSubkeyR(17) = subr(17);
+    tl = subl(15) ^ (subr(15) & ~subr(17));
+    dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(18) = tl ^ subl(19);
+    CamelliaSubkeyR(18) = tr ^ subr(19);
+    CamelliaSubkeyL(19) = subl(18) ^ subl(20);
+    CamelliaSubkeyR(19) = subr(18) ^ subr(20);
+    CamelliaSubkeyL(20) = subl(19) ^ subl(21);
+    CamelliaSubkeyR(20) = subr(19) ^ subr(21);
+    CamelliaSubkeyL(21) = subl(20) ^ subl(22);
+    CamelliaSubkeyR(21) = subr(20) ^ subr(22);
+    CamelliaSubkeyL(22) = subl(21) ^ subl(23);
+    CamelliaSubkeyR(22) = subr(21) ^ subr(23);
+    tl = subl(26) ^ (subr(26) & ~subr(24));
+    dw = tl & subl(24), tr = subr(26) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(23) = subl(22) ^ tl;
+    CamelliaSubkeyR(23) = subr(22) ^ tr;
+    CamelliaSubkeyL(24) = subl(24);
+    CamelliaSubkeyR(24) = subr(24);
+    CamelliaSubkeyL(25) = subl(25);
+    CamelliaSubkeyR(25) = subr(25);
+    tl = subl(23) ^ (subr(23) &  ~subr(25));
+    dw = tl & subl(25), tr = subr(23) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(26) = tl ^ subl(27);
+    CamelliaSubkeyR(26) = tr ^ subr(27);
+    CamelliaSubkeyL(27) = subl(26) ^ subl(28);
+    CamelliaSubkeyR(27) = subr(26) ^ subr(28);
+    CamelliaSubkeyL(28) = subl(27) ^ subl(29);
+    CamelliaSubkeyR(28) = subr(27) ^ subr(29);
+    CamelliaSubkeyL(29) = subl(28) ^ subl(30);
+    CamelliaSubkeyR(29) = subr(28) ^ subr(30);
+    CamelliaSubkeyL(30) = subl(29) ^ subl(31);
+    CamelliaSubkeyR(30) = subr(29) ^ subr(31);
+    CamelliaSubkeyL(31) = subl(30);
+    CamelliaSubkeyR(31) = subr(30);
+    CamelliaSubkeyL(32) = subl(32) ^ subl(31);
+    CamelliaSubkeyR(32) = subr(32) ^ subr(31);
+
+    /* apply the inverse of the last half of P-function */
+    dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw;
+    dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw;
+    dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw;
+    dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw;
+    dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw;
+    dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw;
+    dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw;
+    dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw;
+    dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw;
+    dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw;
+    dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw;
+    dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw;
+    dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw;
+    dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw;
+    dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw;
+    dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw;
+    dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw;
+    dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw;
+    dw = CamelliaSubkeyL(26) ^ CamelliaSubkeyR(26), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(26) = CamelliaSubkeyL(26) ^ dw, CamelliaSubkeyL(26) = dw;
+    dw = CamelliaSubkeyL(27) ^ CamelliaSubkeyR(27), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(27) = CamelliaSubkeyL(27) ^ dw, CamelliaSubkeyL(27) = dw;
+    dw = CamelliaSubkeyL(28) ^ CamelliaSubkeyR(28), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(28) = CamelliaSubkeyL(28) ^ dw, CamelliaSubkeyL(28) = dw;
+    dw = CamelliaSubkeyL(29) ^ CamelliaSubkeyR(29), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(29) = CamelliaSubkeyL(29) ^ dw, CamelliaSubkeyL(29) = dw;
+    dw = CamelliaSubkeyL(30) ^ CamelliaSubkeyR(30), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(30) = CamelliaSubkeyL(30) ^ dw, CamelliaSubkeyL(30) = dw;
+    dw = CamelliaSubkeyL(31) ^ CamelliaSubkeyR(31), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(31) = CamelliaSubkeyL(31) ^ dw,CamelliaSubkeyL(31) = dw;
+    
+    return;
+}
+
+void camellia_setup192(const unsigned char *key, PRUint32 *subkey)
+{
+    unsigned char kk[32];
+    PRUint32 krll, krlr, krrl,krrr;
+
+    memcpy(kk, key, 24);
+    memcpy((unsigned char *)&krll, key+16,4);
+    memcpy((unsigned char *)&krlr, key+20,4);
+    krrl = ~krll;
+    krrr = ~krlr;
+    memcpy(kk+24, (unsigned char *)&krrl, 4);
+    memcpy(kk+28, (unsigned char *)&krrr, 4);
+    camellia_setup256(kk, subkey);
+    return;
+}
+
+
+/**
+ * Stuff related to camellia encryption/decryption
+ *
+ */
+SECStatus
+camellia_encrypt128(const PRUint32 *subkey,
+		    unsigned char *output,
+		    const unsigned char *input)
+{
+    PRUint32 il, ir, t0, t1;
+    PRUint32 io[4];
+
+    io[0] = GETU32(input);
+    io[1] = GETU32(input+4);
+    io[2] = GETU32(input+8);
+    io[3] = GETU32(input+12);
+
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(0);
+    io[1] ^= CamelliaSubkeyR(0);
+    /* main iteration */
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(24);
+    io[3] ^= CamelliaSubkeyR(24);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+
+    PUTU32(output, io[0]);
+    PUTU32(output+4, io[1]);
+    PUTU32(output+8, io[2]);
+    PUTU32(output+12, io[3]);
+
+    return SECSuccess;
+}
+
+SECStatus
+camellia_decrypt128(const PRUint32 *subkey,
+		    unsigned char *output,
+		    const unsigned char *input)
+{
+    PRUint32 il,ir,t0,t1;               /* temporary valiables */
+    PRUint32 io[4];
+
+    io[0] = GETU32(input);
+    io[1] = GETU32(input+4);
+    io[2] = GETU32(input+8);
+    io[3] = GETU32(input+12);
+
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(24);
+    io[1] ^= CamelliaSubkeyR(24);
+
+    /* main iteration */
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(0);
+    io[3] ^= CamelliaSubkeyR(0);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+
+    PUTU32(output, io[0]);
+    PUTU32(output+4, io[1]);
+    PUTU32(output+8, io[2]);
+    PUTU32(output+12, io[3]);
+
+    return SECSuccess;
+}
+
+/**
+ * stuff for 192 and 256bit encryption/decryption
+ */
+SECStatus
+camellia_encrypt256(const PRUint32 *subkey,
+		    unsigned char *output,
+		    const unsigned char *input)
+{
+    PRUint32 il,ir,t0,t1;           /* temporary valiables */
+    PRUint32 io[4];
+
+    io[0] = GETU32(input);
+    io[1] = GETU32(input+4);
+    io[2] = GETU32(input+8);
+    io[3] = GETU32(input+12);
+
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(0);
+    io[1] ^= CamelliaSubkeyR(0);
+
+    /* main iteration */
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(24),CamelliaSubkeyR(24),
+		 CamelliaSubkeyL(25),CamelliaSubkeyR(25),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(26),CamelliaSubkeyR(26),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(27),CamelliaSubkeyR(27),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(28),CamelliaSubkeyR(28),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(29),CamelliaSubkeyR(29),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(30),CamelliaSubkeyR(30),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(31),CamelliaSubkeyR(31),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(32);
+    io[3] ^= CamelliaSubkeyR(32);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+
+    PUTU32(output, io[0]);
+    PUTU32(output+4, io[1]);
+    PUTU32(output+8, io[2]);
+    PUTU32(output+12, io[3]);
+
+    return SECSuccess;
+}
+
+SECStatus
+camellia_decrypt256(const PRUint32 *subkey,
+		    unsigned char *output,
+		    const unsigned char *input)
+{
+    PRUint32 il,ir,t0,t1;           /* temporary valiables */
+    PRUint32 io[4];
+
+    io[0] = GETU32(input);
+    io[1] = GETU32(input+4);
+    io[2] = GETU32(input+8);
+    io[3] = GETU32(input+12);
+
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(32);
+    io[1] ^= CamelliaSubkeyR(32);
+	
+    /* main iteration */
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(31),CamelliaSubkeyR(31),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(30),CamelliaSubkeyR(30),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(29),CamelliaSubkeyR(29),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(28),CamelliaSubkeyR(28),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(27),CamelliaSubkeyR(27),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(26),CamelliaSubkeyR(26),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(25),CamelliaSubkeyR(25),
+		 CamelliaSubkeyL(24),CamelliaSubkeyR(24),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(0);
+    io[3] ^= CamelliaSubkeyR(0);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+
+    PUTU32(output, io[0]);
+    PUTU32(output+4, io[1]);
+    PUTU32(output+8, io[2]);
+    PUTU32(output+12, io[3]);
+
+    return SECSuccess;
+}
+
+
+/**************************************************************************
+ *
+ * Stuff related to the Camellia key schedule
+ *
+ *************************************************************************/
+
+SECStatus 
+camellia_key_expansion(CamelliaContext *cx, 
+                       const unsigned char *key, 
+                       const unsigned int keysize)
+{
+    cx->keysize = keysize;
+
+    switch(keysize) {
+    case 16:
+	camellia_setup128(key, cx->expandedKey);
+	break;
+    case 24:
+	camellia_setup192(key, cx->expandedKey);
+	break;
+    case 32:
+	camellia_setup256(key, cx->expandedKey);
+	break;
+    default:
+	break;
+    }
+    return SECSuccess;
+}
+
+
+/**************************************************************************
+ *
+ *  Camellia modes of operation (ECB and CBC)
+ *
+ *************************************************************************/
+
+SECStatus 
+camellia_encryptECB(CamelliaContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen)
+{
+    CamelliaBlockFunc *encryptor;
+
+    encryptor = (cx->keysize == 16)
+	? &camellia_encrypt128
+	: &camellia_encrypt256;
+
+    while (inputLen > 0) {
+	(*encryptor)(cx->expandedKey, output, input);
+    
+	output += CAMELLIA_BLOCK_SIZE;
+	input += CAMELLIA_BLOCK_SIZE;
+	inputLen -= CAMELLIA_BLOCK_SIZE;
+    }
+    return SECSuccess;
+}
+
+SECStatus 
+camellia_encryptCBC(CamelliaContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen)
+{
+    unsigned int j;
+    unsigned char *lastblock;
+    unsigned char inblock[CAMELLIA_BLOCK_SIZE];
+    CamelliaBlockFunc *encryptor;
+
+    if (!inputLen)
+	return SECSuccess;
+    lastblock = cx->iv;
+
+    encryptor = (cx->keysize == 16)
+	? &camellia_encrypt128
+	: &camellia_encrypt256;
+
+    while (inputLen > 0) {
+	/* XOR with the last block (IV if first block) */
+	for (j=0; j<CAMELLIA_BLOCK_SIZE; ++j)
+	    inblock[j] = input[j] ^ lastblock[j];
+	/* encrypt */
+	(*encryptor)(cx->expandedKey, output, inblock);
+
+	/* move to the next block */
+	lastblock = output;
+	output += CAMELLIA_BLOCK_SIZE;
+	input += CAMELLIA_BLOCK_SIZE;
+	inputLen -= CAMELLIA_BLOCK_SIZE;
+    }
+    memcpy(cx->iv, lastblock, CAMELLIA_BLOCK_SIZE);
+    return SECSuccess;
+}
+
+SECStatus 
+camellia_decryptECB(CamelliaContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen)
+{
+    CamelliaBlockFunc *decryptor;
+
+    decryptor = (cx->keysize == 16)
+	? &camellia_decrypt128
+	: &camellia_decrypt256;
+
+
+    while (inputLen > 0) {
+
+	(*decryptor)(cx->expandedKey, output, input);
+
+	output += CAMELLIA_BLOCK_SIZE;
+	input += CAMELLIA_BLOCK_SIZE;
+	inputLen -= CAMELLIA_BLOCK_SIZE;
+    }
+    return SECSuccess;
+}
+
+SECStatus 
+camellia_decryptCBC(CamelliaContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen)
+{
+    const unsigned char *in;
+    unsigned char *out;
+    unsigned int j;
+    unsigned char newIV[CAMELLIA_BLOCK_SIZE];
+    CamelliaBlockFunc *decryptor;
+
+
+
+    if (!inputLen) 
+	return SECSuccess;
+
+    PORT_Assert(output - input >= 0 || input - output >= (int)inputLen );
+
+    in  = input  + (inputLen - CAMELLIA_BLOCK_SIZE);
+    memcpy(newIV, in, CAMELLIA_BLOCK_SIZE);
+    out = output + (inputLen - CAMELLIA_BLOCK_SIZE);
+
+    decryptor = (cx->keysize == 16)
+	? &camellia_decrypt128
+	: &camellia_decrypt256;
+
+    while (inputLen > CAMELLIA_BLOCK_SIZE) {
+	(*decryptor)(cx->expandedKey, out, in);
+
+	for (j=0; j<CAMELLIA_BLOCK_SIZE; ++j)
+	    out[j] ^= in[(int)(j - CAMELLIA_BLOCK_SIZE)];
+
+	out -= CAMELLIA_BLOCK_SIZE;
+	in -= CAMELLIA_BLOCK_SIZE;
+	inputLen -= CAMELLIA_BLOCK_SIZE;
+    }
+    if (in == input) {
+	(*decryptor)(cx->expandedKey, out, in);
+
+	for (j=0; j<CAMELLIA_BLOCK_SIZE; ++j)
+	    out[j] ^= cx->iv[j];
+    }
+    memcpy(cx->iv, newIV, CAMELLIA_BLOCK_SIZE);
+    return SECSuccess;
+}
+
+/**************************************************************************
+ *
+ * BLAPI Interface functions
+ *
+ *************************************************************************/
+
+CamelliaContext *
+Camellia_AllocateContext(void)
+{
+    return PORT_ZNew(CamelliaContext);
+}
+
+SECStatus   
+Camellia_InitContext(CamelliaContext *cx, const unsigned char *key,
+		     unsigned int keysize, 
+		     const unsigned char *iv, int mode, unsigned int encrypt,
+		     unsigned int unused)
+{
+    if (key == NULL ||
+	(keysize != 16 && keysize != 24 && keysize != 32)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (mode != NSS_CAMELLIA && mode != NSS_CAMELLIA_CBC) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (mode == NSS_CAMELLIA_CBC && iv == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (!cx) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    	return SECFailure;
+    }
+    if (mode == NSS_CAMELLIA_CBC) {
+	memcpy(cx->iv, iv, CAMELLIA_BLOCK_SIZE);
+	cx->worker = (encrypt) ? &camellia_encryptCBC : &camellia_decryptCBC;
+    } else {
+	cx->worker = (encrypt) ? &camellia_encryptECB : &camellia_decryptECB;
+    }
+
+    /* Generate expanded key */
+    if (camellia_key_expansion(cx, key, keysize) != SECSuccess)
+	goto cleanup;
+
+    return SECSuccess;
+cleanup:
+    return SECFailure;
+}
+
+/*
+ * Camellia_CreateContext
+ * create a new context for Camellia operations
+ */
+
+
+CamelliaContext *
+Camellia_CreateContext(const unsigned char *key, const unsigned char *iv, 
+                       int mode, int encrypt,
+                       unsigned int keysize)
+{
+    CamelliaContext *cx;
+
+    if (key == NULL ||
+	(keysize != 16 && keysize != 24 && keysize != 32)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    if (mode != NSS_CAMELLIA && mode != NSS_CAMELLIA_CBC) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    if (mode == NSS_CAMELLIA_CBC && iv == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    cx = PORT_ZNew(CamelliaContext);
+    if (!cx) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+
+    /* copy in the iv, if neccessary */
+    if (mode == NSS_CAMELLIA_CBC) {
+	memcpy(cx->iv, iv, CAMELLIA_BLOCK_SIZE);
+	cx->worker = (encrypt) ? &camellia_encryptCBC : &camellia_decryptCBC;
+    } else {
+	cx->worker = (encrypt) ? &camellia_encryptECB : &camellia_decryptECB;
+    }
+    /* copy keysize */
+    cx->keysize = keysize;
+
+    /* Generate expanded key */
+    if (camellia_key_expansion(cx, key, keysize) != SECSuccess)
+	goto cleanup;
+
+    return cx;
+  cleanup:
+    PORT_ZFree(cx, sizeof *cx);
+    return NULL;
+}
+
+/*
+ * Camellia_DestroyContext
+ * 
+ * Zero an Camellia cipher context.  If freeit is true, also free the pointer
+ * to the context.
+ */
+void 
+Camellia_DestroyContext(CamelliaContext *cx, PRBool freeit)
+{
+    if (cx)
+	memset(cx, 0, sizeof *cx);
+    if (freeit)
+	PORT_Free(cx);
+}
+
+/*
+ * Camellia_Encrypt
+ *
+ * Encrypt an arbitrary-length buffer.  The output buffer must already be
+ * allocated to at least inputLen.
+ */
+SECStatus 
+Camellia_Encrypt(CamelliaContext *cx, unsigned char *output,
+                 unsigned int *outputLen, unsigned int maxOutputLen,
+                 const unsigned char *input, unsigned int inputLen)
+{
+
+    /* Check args */
+    if (cx == NULL || output == NULL || input == NULL ||
+	outputLen == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    if (inputLen % CAMELLIA_BLOCK_SIZE != 0) {
+	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	return SECFailure;
+    }
+    if (maxOutputLen < inputLen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return SECFailure;
+    }
+    *outputLen = inputLen;
+
+    return (*cx->worker)(cx, output, outputLen, maxOutputLen,	
+			 input, inputLen);
+}
+
+/*
+ * Camellia_Decrypt
+ *
+ * Decrypt and arbitrary-length buffer.  The output buffer must already be
+ * allocated to at least inputLen.
+ */
+SECStatus 
+Camellia_Decrypt(CamelliaContext *cx, unsigned char *output,
+                 unsigned int *outputLen, unsigned int maxOutputLen,
+                 const unsigned char *input, unsigned int inputLen)
+{
+
+    /* Check args */
+    if (cx == NULL || output == NULL || input == NULL
+	|| outputLen == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (inputLen % CAMELLIA_BLOCK_SIZE != 0) {
+	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	return SECFailure;
+    }
+    if (maxOutputLen < inputLen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return SECFailure;
+    }
+    *outputLen = inputLen;
+
+    return (*cx->worker)(cx, output, outputLen, maxOutputLen,	
+			 input, inputLen);
+}
diff --git a/mozilla/security/nss/lib/freebl/camellia.h b/mozilla/security/nss/lib/freebl/camellia.h
new file mode 100644
index 0000000..d27d3f4
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/camellia.h
@@ -0,0 +1,79 @@
+/* ***** 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 Camellia code.
+ *
+ * The Initial Developer of the Original Code is
+ * NTT(Nippon Telegraph and Telephone Corporation).
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * 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 ***** */
+/*
+ * $Id: camellia.h,v 1.1 2007/02/28 19:47:37 rrelyea%redhat.com Exp $
+ */
+
+#ifndef _CAMELLIA_H_
+#define _CAMELLIA_H_ 1
+
+#define CAMELLIA_BLOCK_SIZE 16  /* bytes */
+#define CAMELLIA_MIN_KEYSIZE 16 /* bytes */
+#define CAMELLIA_MAX_KEYSIZE 32 /* bytes */
+
+#define CAMELLIA_MAX_EXPANDEDKEY (34*2) /* 32bit unit */
+
+typedef PRUint32 KEY_TABLE_TYPE[CAMELLIA_MAX_EXPANDEDKEY];
+
+typedef SECStatus CamelliaFunc(CamelliaContext *cx, unsigned char *output,
+			       unsigned int *outputLen,
+			       unsigned int maxOutputLen,
+			       const unsigned char *input,
+			       unsigned int inputLen);
+
+typedef SECStatus CamelliaBlockFunc(const PRUint32 *subkey, 
+				    unsigned char *output,
+				    const unsigned char *input);
+
+/* CamelliaContextStr
+ *
+ * Values which maintain the state for Camellia encryption/decryption.
+ *
+ * keysize     - the number of key bits
+ * worker      - the encryption/decryption function to use with this context
+ * iv          - initialization vector for CBC mode
+ * expandedKey - the round keys in 4-byte words
+ */
+struct CamelliaContextStr
+{
+    PRUint32  keysize; /* bytes */
+    CamelliaFunc  *worker;
+    PRUint32      expandedKey[CAMELLIA_MAX_EXPANDEDKEY];
+    PRUint8 iv[CAMELLIA_BLOCK_SIZE];
+};
+
+#endif /* _CAMELLIA_H_ */
diff --git a/mozilla/security/nss/lib/freebl/des.c b/mozilla/security/nss/lib/freebl/des.c
new file mode 100644
index 0000000..a3541ba
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/des.c
@@ -0,0 +1,699 @@
+/*
+ *  des.c
+ *
+ *  core source file for DES-150 library
+ *  Make key schedule from DES key.
+ *  Encrypt/Decrypt one 8-byte block.
+ *
+ * ***** 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 DES-150 library.
+ *
+ * The Initial Developer of the Original Code is
+ * Nelson B. Bolyard, nelsonb@iname.com.
+ * Portions created by the Initial Developer are Copyright (C) 1990
+ * 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 "des.h"
+#include <stddef.h>	/* for ptrdiff_t */
+/* #define USE_INDEXING 1 */
+
+/*
+ * The tables below are the 8 sbox functions, with the 6-bit input permutation 
+ * and the 32-bit output permutation pre-computed.
+ * They are shifted circularly to the left 3 bits, which removes 2 shifts
+ * and an or from each round by reducing the number of sboxes whose
+ * indices cross word broundaries from 2 to 1.  
+ */
+
+static const HALF SP[8][64] = {
+/* Box S1 */ { 
+	0x04041000, 0x00000000, 0x00040000, 0x04041010, 
+	0x04040010, 0x00041010, 0x00000010, 0x00040000, 
+	0x00001000, 0x04041000, 0x04041010, 0x00001000, 
+	0x04001010, 0x04040010, 0x04000000, 0x00000010, 
+	0x00001010, 0x04001000, 0x04001000, 0x00041000, 
+	0x00041000, 0x04040000, 0x04040000, 0x04001010, 
+	0x00040010, 0x04000010, 0x04000010, 0x00040010, 
+	0x00000000, 0x00001010, 0x00041010, 0x04000000, 
+	0x00040000, 0x04041010, 0x00000010, 0x04040000, 
+	0x04041000, 0x04000000, 0x04000000, 0x00001000, 
+	0x04040010, 0x00040000, 0x00041000, 0x04000010, 
+	0x00001000, 0x00000010, 0x04001010, 0x00041010, 
+	0x04041010, 0x00040010, 0x04040000, 0x04001010, 
+	0x04000010, 0x00001010, 0x00041010, 0x04041000, 
+	0x00001010, 0x04001000, 0x04001000, 0x00000000, 
+	0x00040010, 0x00041000, 0x00000000, 0x04040010
+    },
+/* Box S2 */ { 
+	0x00420082, 0x00020002, 0x00020000, 0x00420080, 
+	0x00400000, 0x00000080, 0x00400082, 0x00020082, 
+	0x00000082, 0x00420082, 0x00420002, 0x00000002, 
+	0x00020002, 0x00400000, 0x00000080, 0x00400082, 
+	0x00420000, 0x00400080, 0x00020082, 0x00000000, 
+	0x00000002, 0x00020000, 0x00420080, 0x00400002, 
+	0x00400080, 0x00000082, 0x00000000, 0x00420000, 
+	0x00020080, 0x00420002, 0x00400002, 0x00020080, 
+	0x00000000, 0x00420080, 0x00400082, 0x00400000, 
+	0x00020082, 0x00400002, 0x00420002, 0x00020000, 
+	0x00400002, 0x00020002, 0x00000080, 0x00420082, 
+	0x00420080, 0x00000080, 0x00020000, 0x00000002, 
+	0x00020080, 0x00420002, 0x00400000, 0x00000082, 
+	0x00400080, 0x00020082, 0x00000082, 0x00400080, 
+	0x00420000, 0x00000000, 0x00020002, 0x00020080, 
+	0x00000002, 0x00400082, 0x00420082, 0x00420000 
+    },
+/* Box S3 */ { 
+	0x00000820, 0x20080800, 0x00000000, 0x20080020, 
+	0x20000800, 0x00000000, 0x00080820, 0x20000800, 
+	0x00080020, 0x20000020, 0x20000020, 0x00080000, 
+	0x20080820, 0x00080020, 0x20080000, 0x00000820, 
+	0x20000000, 0x00000020, 0x20080800, 0x00000800, 
+	0x00080800, 0x20080000, 0x20080020, 0x00080820, 
+	0x20000820, 0x00080800, 0x00080000, 0x20000820, 
+	0x00000020, 0x20080820, 0x00000800, 0x20000000, 
+	0x20080800, 0x20000000, 0x00080020, 0x00000820, 
+	0x00080000, 0x20080800, 0x20000800, 0x00000000, 
+	0x00000800, 0x00080020, 0x20080820, 0x20000800, 
+	0x20000020, 0x00000800, 0x00000000, 0x20080020, 
+	0x20000820, 0x00080000, 0x20000000, 0x20080820, 
+	0x00000020, 0x00080820, 0x00080800, 0x20000020, 
+	0x20080000, 0x20000820, 0x00000820, 0x20080000, 
+	0x00080820, 0x00000020, 0x20080020, 0x00080800 
+    },
+/* Box S4 */ { 
+	0x02008004, 0x00008204, 0x00008204, 0x00000200, 
+	0x02008200, 0x02000204, 0x02000004, 0x00008004, 
+	0x00000000, 0x02008000, 0x02008000, 0x02008204, 
+	0x00000204, 0x00000000, 0x02000200, 0x02000004, 
+	0x00000004, 0x00008000, 0x02000000, 0x02008004, 
+	0x00000200, 0x02000000, 0x00008004, 0x00008200, 
+	0x02000204, 0x00000004, 0x00008200, 0x02000200, 
+	0x00008000, 0x02008200, 0x02008204, 0x00000204, 
+	0x02000200, 0x02000004, 0x02008000, 0x02008204, 
+	0x00000204, 0x00000000, 0x00000000, 0x02008000, 
+	0x00008200, 0x02000200, 0x02000204, 0x00000004, 
+	0x02008004, 0x00008204, 0x00008204, 0x00000200, 
+	0x02008204, 0x00000204, 0x00000004, 0x00008000, 
+	0x02000004, 0x00008004, 0x02008200, 0x02000204, 
+	0x00008004, 0x00008200, 0x02000000, 0x02008004, 
+	0x00000200, 0x02000000, 0x00008000, 0x02008200 
+    },
+/* Box S5 */ { 
+	0x00000400, 0x08200400, 0x08200000, 0x08000401, 
+	0x00200000, 0x00000400, 0x00000001, 0x08200000, 
+	0x00200401, 0x00200000, 0x08000400, 0x00200401, 
+	0x08000401, 0x08200001, 0x00200400, 0x00000001, 
+	0x08000000, 0x00200001, 0x00200001, 0x00000000, 
+	0x00000401, 0x08200401, 0x08200401, 0x08000400, 
+	0x08200001, 0x00000401, 0x00000000, 0x08000001, 
+	0x08200400, 0x08000000, 0x08000001, 0x00200400, 
+	0x00200000, 0x08000401, 0x00000400, 0x08000000, 
+	0x00000001, 0x08200000, 0x08000401, 0x00200401, 
+	0x08000400, 0x00000001, 0x08200001, 0x08200400, 
+	0x00200401, 0x00000400, 0x08000000, 0x08200001, 
+	0x08200401, 0x00200400, 0x08000001, 0x08200401, 
+	0x08200000, 0x00000000, 0x00200001, 0x08000001, 
+	0x00200400, 0x08000400, 0x00000401, 0x00200000, 
+	0x00000000, 0x00200001, 0x08200400, 0x00000401
+    },
+/* Box S6 */ { 
+	0x80000040, 0x81000000, 0x00010000, 0x81010040, 
+	0x81000000, 0x00000040, 0x81010040, 0x01000000, 
+	0x80010000, 0x01010040, 0x01000000, 0x80000040, 
+	0x01000040, 0x80010000, 0x80000000, 0x00010040, 
+	0x00000000, 0x01000040, 0x80010040, 0x00010000, 
+	0x01010000, 0x80010040, 0x00000040, 0x81000040, 
+	0x81000040, 0x00000000, 0x01010040, 0x81010000, 
+	0x00010040, 0x01010000, 0x81010000, 0x80000000, 
+	0x80010000, 0x00000040, 0x81000040, 0x01010000, 
+	0x81010040, 0x01000000, 0x00010040, 0x80000040, 
+	0x01000000, 0x80010000, 0x80000000, 0x00010040, 
+	0x80000040, 0x81010040, 0x01010000, 0x81000000, 
+	0x01010040, 0x81010000, 0x00000000, 0x81000040, 
+	0x00000040, 0x00010000, 0x81000000, 0x01010040, 
+	0x00010000, 0x01000040, 0x80010040, 0x00000000, 
+	0x81010000, 0x80000000, 0x01000040, 0x80010040 
+    },
+/* Box S7 */ { 
+	0x00800000, 0x10800008, 0x10002008, 0x00000000, 
+	0x00002000, 0x10002008, 0x00802008, 0x10802000, 
+	0x10802008, 0x00800000, 0x00000000, 0x10000008, 
+	0x00000008, 0x10000000, 0x10800008, 0x00002008, 
+	0x10002000, 0x00802008, 0x00800008, 0x10002000, 
+	0x10000008, 0x10800000, 0x10802000, 0x00800008, 
+	0x10800000, 0x00002000, 0x00002008, 0x10802008, 
+	0x00802000, 0x00000008, 0x10000000, 0x00802000, 
+	0x10000000, 0x00802000, 0x00800000, 0x10002008, 
+	0x10002008, 0x10800008, 0x10800008, 0x00000008, 
+	0x00800008, 0x10000000, 0x10002000, 0x00800000, 
+	0x10802000, 0x00002008, 0x00802008, 0x10802000, 
+	0x00002008, 0x10000008, 0x10802008, 0x10800000, 
+	0x00802000, 0x00000000, 0x00000008, 0x10802008, 
+	0x00000000, 0x00802008, 0x10800000, 0x00002000, 
+	0x10000008, 0x10002000, 0x00002000, 0x00800008 
+    },
+/* Box S8 */ { 
+	0x40004100, 0x00004000, 0x00100000, 0x40104100, 
+	0x40000000, 0x40004100, 0x00000100, 0x40000000, 
+	0x00100100, 0x40100000, 0x40104100, 0x00104000, 
+	0x40104000, 0x00104100, 0x00004000, 0x00000100, 
+	0x40100000, 0x40000100, 0x40004000, 0x00004100, 
+	0x00104000, 0x00100100, 0x40100100, 0x40104000, 
+	0x00004100, 0x00000000, 0x00000000, 0x40100100, 
+	0x40000100, 0x40004000, 0x00104100, 0x00100000, 
+	0x00104100, 0x00100000, 0x40104000, 0x00004000, 
+	0x00000100, 0x40100100, 0x00004000, 0x00104100, 
+	0x40004000, 0x00000100, 0x40000100, 0x40100000, 
+	0x40100100, 0x40000000, 0x00100000, 0x40004100, 
+	0x00000000, 0x40104100, 0x00100100, 0x40000100, 
+	0x40100000, 0x40004000, 0x40004100, 0x00000000, 
+	0x40104100, 0x00104000, 0x00104000, 0x00004100, 
+	0x00004100, 0x00100100, 0x40000000, 0x40104000 
+    }
+};
+
+static const HALF PC2[8][64] = {
+/* table 0 */ {
+    0x00000000, 0x00001000, 0x04000000, 0x04001000, 
+    0x00100000, 0x00101000, 0x04100000, 0x04101000, 
+    0x00008000, 0x00009000, 0x04008000, 0x04009000, 
+    0x00108000, 0x00109000, 0x04108000, 0x04109000, 
+    0x00000004, 0x00001004, 0x04000004, 0x04001004, 
+    0x00100004, 0x00101004, 0x04100004, 0x04101004, 
+    0x00008004, 0x00009004, 0x04008004, 0x04009004, 
+    0x00108004, 0x00109004, 0x04108004, 0x04109004, 
+    0x08000000, 0x08001000, 0x0c000000, 0x0c001000, 
+    0x08100000, 0x08101000, 0x0c100000, 0x0c101000, 
+    0x08008000, 0x08009000, 0x0c008000, 0x0c009000, 
+    0x08108000, 0x08109000, 0x0c108000, 0x0c109000, 
+    0x08000004, 0x08001004, 0x0c000004, 0x0c001004, 
+    0x08100004, 0x08101004, 0x0c100004, 0x0c101004, 
+    0x08008004, 0x08009004, 0x0c008004, 0x0c009004, 
+    0x08108004, 0x08109004, 0x0c108004, 0x0c109004
+  },
+/* table 1 */ {
+    0x00000000, 0x00002000, 0x80000000, 0x80002000, 
+    0x00000008, 0x00002008, 0x80000008, 0x80002008, 
+    0x00200000, 0x00202000, 0x80200000, 0x80202000, 
+    0x00200008, 0x00202008, 0x80200008, 0x80202008, 
+    0x20000000, 0x20002000, 0xa0000000, 0xa0002000, 
+    0x20000008, 0x20002008, 0xa0000008, 0xa0002008, 
+    0x20200000, 0x20202000, 0xa0200000, 0xa0202000, 
+    0x20200008, 0x20202008, 0xa0200008, 0xa0202008, 
+    0x00000400, 0x00002400, 0x80000400, 0x80002400, 
+    0x00000408, 0x00002408, 0x80000408, 0x80002408, 
+    0x00200400, 0x00202400, 0x80200400, 0x80202400, 
+    0x00200408, 0x00202408, 0x80200408, 0x80202408, 
+    0x20000400, 0x20002400, 0xa0000400, 0xa0002400, 
+    0x20000408, 0x20002408, 0xa0000408, 0xa0002408, 
+    0x20200400, 0x20202400, 0xa0200400, 0xa0202400, 
+    0x20200408, 0x20202408, 0xa0200408, 0xa0202408
+  },
+/* table 2 */ {
+    0x00000000, 0x00004000, 0x00000020, 0x00004020, 
+    0x00080000, 0x00084000, 0x00080020, 0x00084020, 
+    0x00000800, 0x00004800, 0x00000820, 0x00004820, 
+    0x00080800, 0x00084800, 0x00080820, 0x00084820, 
+    0x00000010, 0x00004010, 0x00000030, 0x00004030, 
+    0x00080010, 0x00084010, 0x00080030, 0x00084030, 
+    0x00000810, 0x00004810, 0x00000830, 0x00004830, 
+    0x00080810, 0x00084810, 0x00080830, 0x00084830, 
+    0x00400000, 0x00404000, 0x00400020, 0x00404020, 
+    0x00480000, 0x00484000, 0x00480020, 0x00484020, 
+    0x00400800, 0x00404800, 0x00400820, 0x00404820, 
+    0x00480800, 0x00484800, 0x00480820, 0x00484820, 
+    0x00400010, 0x00404010, 0x00400030, 0x00404030, 
+    0x00480010, 0x00484010, 0x00480030, 0x00484030, 
+    0x00400810, 0x00404810, 0x00400830, 0x00404830, 
+    0x00480810, 0x00484810, 0x00480830, 0x00484830 
+  },
+/* table 3 */ {
+    0x00000000, 0x40000000, 0x00000080, 0x40000080, 
+    0x00040000, 0x40040000, 0x00040080, 0x40040080, 
+    0x00000040, 0x40000040, 0x000000c0, 0x400000c0, 
+    0x00040040, 0x40040040, 0x000400c0, 0x400400c0, 
+    0x10000000, 0x50000000, 0x10000080, 0x50000080, 
+    0x10040000, 0x50040000, 0x10040080, 0x50040080, 
+    0x10000040, 0x50000040, 0x100000c0, 0x500000c0, 
+    0x10040040, 0x50040040, 0x100400c0, 0x500400c0, 
+    0x00800000, 0x40800000, 0x00800080, 0x40800080, 
+    0x00840000, 0x40840000, 0x00840080, 0x40840080, 
+    0x00800040, 0x40800040, 0x008000c0, 0x408000c0, 
+    0x00840040, 0x40840040, 0x008400c0, 0x408400c0, 
+    0x10800000, 0x50800000, 0x10800080, 0x50800080, 
+    0x10840000, 0x50840000, 0x10840080, 0x50840080, 
+    0x10800040, 0x50800040, 0x108000c0, 0x508000c0, 
+    0x10840040, 0x50840040, 0x108400c0, 0x508400c0 
+  },
+/* table 4 */ {
+    0x00000000, 0x00000008, 0x08000000, 0x08000008, 
+    0x00040000, 0x00040008, 0x08040000, 0x08040008, 
+    0x00002000, 0x00002008, 0x08002000, 0x08002008, 
+    0x00042000, 0x00042008, 0x08042000, 0x08042008, 
+    0x80000000, 0x80000008, 0x88000000, 0x88000008, 
+    0x80040000, 0x80040008, 0x88040000, 0x88040008, 
+    0x80002000, 0x80002008, 0x88002000, 0x88002008, 
+    0x80042000, 0x80042008, 0x88042000, 0x88042008, 
+    0x00080000, 0x00080008, 0x08080000, 0x08080008, 
+    0x000c0000, 0x000c0008, 0x080c0000, 0x080c0008, 
+    0x00082000, 0x00082008, 0x08082000, 0x08082008, 
+    0x000c2000, 0x000c2008, 0x080c2000, 0x080c2008, 
+    0x80080000, 0x80080008, 0x88080000, 0x88080008, 
+    0x800c0000, 0x800c0008, 0x880c0000, 0x880c0008, 
+    0x80082000, 0x80082008, 0x88082000, 0x88082008, 
+    0x800c2000, 0x800c2008, 0x880c2000, 0x880c2008 
+  },
+/* table 5 */ {
+    0x00000000, 0x00400000, 0x00008000, 0x00408000, 
+    0x40000000, 0x40400000, 0x40008000, 0x40408000, 
+    0x00000020, 0x00400020, 0x00008020, 0x00408020, 
+    0x40000020, 0x40400020, 0x40008020, 0x40408020, 
+    0x00001000, 0x00401000, 0x00009000, 0x00409000, 
+    0x40001000, 0x40401000, 0x40009000, 0x40409000, 
+    0x00001020, 0x00401020, 0x00009020, 0x00409020, 
+    0x40001020, 0x40401020, 0x40009020, 0x40409020, 
+    0x00100000, 0x00500000, 0x00108000, 0x00508000, 
+    0x40100000, 0x40500000, 0x40108000, 0x40508000, 
+    0x00100020, 0x00500020, 0x00108020, 0x00508020, 
+    0x40100020, 0x40500020, 0x40108020, 0x40508020, 
+    0x00101000, 0x00501000, 0x00109000, 0x00509000, 
+    0x40101000, 0x40501000, 0x40109000, 0x40509000, 
+    0x00101020, 0x00501020, 0x00109020, 0x00509020, 
+    0x40101020, 0x40501020, 0x40109020, 0x40509020 
+  },
+/* table 6 */ {
+    0x00000000, 0x00000040, 0x04000000, 0x04000040, 
+    0x00000800, 0x00000840, 0x04000800, 0x04000840, 
+    0x00800000, 0x00800040, 0x04800000, 0x04800040, 
+    0x00800800, 0x00800840, 0x04800800, 0x04800840, 
+    0x10000000, 0x10000040, 0x14000000, 0x14000040, 
+    0x10000800, 0x10000840, 0x14000800, 0x14000840, 
+    0x10800000, 0x10800040, 0x14800000, 0x14800040, 
+    0x10800800, 0x10800840, 0x14800800, 0x14800840, 
+    0x00000080, 0x000000c0, 0x04000080, 0x040000c0, 
+    0x00000880, 0x000008c0, 0x04000880, 0x040008c0, 
+    0x00800080, 0x008000c0, 0x04800080, 0x048000c0, 
+    0x00800880, 0x008008c0, 0x04800880, 0x048008c0, 
+    0x10000080, 0x100000c0, 0x14000080, 0x140000c0, 
+    0x10000880, 0x100008c0, 0x14000880, 0x140008c0, 
+    0x10800080, 0x108000c0, 0x14800080, 0x148000c0, 
+    0x10800880, 0x108008c0, 0x14800880, 0x148008c0 
+  },
+/* table 7 */ {
+    0x00000000, 0x00000010, 0x00000400, 0x00000410, 
+    0x00000004, 0x00000014, 0x00000404, 0x00000414, 
+    0x00004000, 0x00004010, 0x00004400, 0x00004410, 
+    0x00004004, 0x00004014, 0x00004404, 0x00004414, 
+    0x20000000, 0x20000010, 0x20000400, 0x20000410, 
+    0x20000004, 0x20000014, 0x20000404, 0x20000414, 
+    0x20004000, 0x20004010, 0x20004400, 0x20004410, 
+    0x20004004, 0x20004014, 0x20004404, 0x20004414, 
+    0x00200000, 0x00200010, 0x00200400, 0x00200410, 
+    0x00200004, 0x00200014, 0x00200404, 0x00200414, 
+    0x00204000, 0x00204010, 0x00204400, 0x00204410, 
+    0x00204004, 0x00204014, 0x00204404, 0x00204414, 
+    0x20200000, 0x20200010, 0x20200400, 0x20200410, 
+    0x20200004, 0x20200014, 0x20200404, 0x20200414, 
+    0x20204000, 0x20204010, 0x20204400, 0x20204410, 
+    0x20204004, 0x20204014, 0x20204404, 0x20204414 
+  }
+};
+
+/*
+ * The PC-1 Permutation
+ * If we number the bits of the 8 bytes of key input like this (in octal):
+ *     00 01 02 03 04 05 06 07 
+ *     10 11 12 13 14 15 16 17 
+ *     20 21 22 23 24 25 26 27 
+ *     30 31 32 33 34 35 36 37 
+ *     40 41 42 43 44 45 46 47 
+ *     50 51 52 53 54 55 56 57 
+ *     60 61 62 63 64 65 66 67 
+ *     70 71 72 73 74 75 76 77 
+ * then after the PC-1 permutation, 
+ * C0 is
+ *     70 60 50 40 30 20 10 00 
+ *     71 61 51 41 31 21 11 01 
+ *     72 62 52 42 32 22 12 02 
+ *     73 63 53 43 
+ * D0 is
+ *     76 66 56 46 36 26 16 06 
+ *     75 65 55 45 35 25 15 05 
+ *     74 64 54 44 34 24 14 04 
+ *                 33 23 13 03 
+ * and these parity bits have been discarded:
+ *     77 67 57 47 37 27 17 07 
+ * 
+ * We achieve this by flipping the input matrix about the diagonal from 70-07,
+ * getting left = 
+ *     77 67 57 47 37 27 17 07 	(these are the parity bits)
+ *     76 66 56 46 36 26 16 06 
+ *     75 65 55 45 35 25 15 05 
+ *     74 64 54 44 34 24 14 04 
+ * right = 
+ *     73 63 53 43 33 23 13 03 
+ *     72 62 52 42 32 22 12 02 
+ *     71 61 51 41 31 21 11 01 
+ *     70 60 50 40 30 20 10 00 
+ * then byte swap right, ala htonl() on a little endian machine.
+ * right = 
+ *     70 60 50 40 30 20 10 00 
+ *     71 67 57 47 37 27 11 07 
+ *     72 62 52 42 32 22 12 02 
+ *     73 63 53 43 33 23 13 03 
+ * then
+ *     c0 = right >> 4;
+ *     d0 = ((left & 0x00ffffff) << 4) | (right & 0xf);
+*/
+
+#define FLIP_RIGHT_DIAGONAL(word, temp) \
+    temp  = (word ^ (word >> 18)) & 0x00003333; \
+    word ^=  temp | (temp << 18); \
+    temp  = (word ^ (word >> 9)) & 0x00550055; \
+    word ^=  temp | (temp << 9);
+
+#if defined(__GNUC__) && defined(NSS_X86_OR_X64)
+#define BYTESWAP(word, temp) \
+    __asm("bswap	%0" : "+r" (word));
+#elif (_MSC_VER >= 1300) && defined(NSS_X86_OR_X64)
+#include <stdlib.h>
+#pragma intrinsic(_byteswap_ulong)
+#define BYTESWAP(word, temp) \
+    word = _byteswap_ulong(word);
+#else
+#define BYTESWAP(word, temp) \
+    word = (word >> 16) | (word << 16); \
+    temp = 0x00ff00ff; \
+    word = ((word & temp) << 8) | ((word >> 8) & temp); 
+#endif
+
+#define PC1(left, right, c0, d0, temp) \
+    right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
+    left  ^= temp << 4; \
+    FLIP_RIGHT_DIAGONAL(left, temp); \
+    FLIP_RIGHT_DIAGONAL(right, temp); \
+    BYTESWAP(right, temp); \
+    c0 = right >> 4; \
+    d0 = ((left & 0x00ffffff) << 4) | (right & 0xf); 
+
+#define LEFT_SHIFT_1( reg ) (((reg << 1) | (reg >> 27)) & 0x0FFFFFFF)
+#define LEFT_SHIFT_2( reg ) (((reg << 2) | (reg >> 26)) & 0x0FFFFFFF)
+
+/*
+ *   setup key schedules from key
+ */
+
+void 
+DES_MakeSchedule( HALF * ks, const BYTE * key,   DESDirection direction)
+{
+    register HALF left, right;
+    register HALF c0, d0;
+    register HALF temp;
+    int           delta;
+    unsigned int  ls;
+
+#if defined(NSS_X86_OR_X64)
+    left  = HALFPTR(key)[0]; 
+    right = HALFPTR(key)[1]; 
+    BYTESWAP(left, temp);
+    BYTESWAP(right, temp);
+#else
+    if (((ptrdiff_t)key & 0x03) == 0) {
+	left  = HALFPTR(key)[0]; 
+	right = HALFPTR(key)[1]; 
+#if defined(IS_LITTLE_ENDIAN)
+	BYTESWAP(left, temp);
+	BYTESWAP(right, temp);
+#endif
+    } else {
+	left    = ((HALF)key[0] << 24) | ((HALF)key[1] << 16) | 
+		  ((HALF)key[2] << 8)  | key[3];
+	right   = ((HALF)key[4] << 24) | ((HALF)key[5] << 16) | 
+		  ((HALF)key[6] << 8)  | key[7];
+    }
+#endif
+
+    PC1(left, right, c0, d0, temp);
+
+    if (direction == DES_ENCRYPT) {
+	delta = 2 * (int)sizeof(HALF);
+    } else {
+	ks += 30;
+	delta = (-2) * (int)sizeof(HALF);
+    }
+
+    for (ls = 0x8103; ls; ls >>= 1) {
+	if ( ls & 1 ) {
+	    c0 = LEFT_SHIFT_1( c0 );
+	    d0 = LEFT_SHIFT_1( d0 );
+	} else {
+	    c0 = LEFT_SHIFT_2( c0 );
+	    d0 = LEFT_SHIFT_2( d0 );
+	}
+
+#ifdef USE_INDEXING
+#define PC2LOOKUP(b,c) PC2[b][c]
+
+	left   = PC2LOOKUP(0, ((c0 >> 22) & 0x3F) );
+	left  |= PC2LOOKUP(1, ((c0 >> 13) & 0x3F) );
+	left  |= PC2LOOKUP(2, ((c0 >>  4) & 0x38) | (c0 & 0x7) );
+	left  |= PC2LOOKUP(3, ((c0>>18)&0xC) | ((c0>>11)&0x3) | (c0&0x30));
+
+	right  = PC2LOOKUP(4, ((d0 >> 22) & 0x3F) );
+	right |= PC2LOOKUP(5, ((d0 >> 15) & 0x30) | ((d0 >> 14) & 0xf) );
+	right |= PC2LOOKUP(6, ((d0 >>  7) & 0x3F) );
+	right |= PC2LOOKUP(7, ((d0 >>  1) & 0x3C) | (d0 & 0x3));
+#else
+#define PC2LOOKUP(b,c) *(HALF *)((BYTE *)&PC2[b][0]+(c))
+
+	left   = PC2LOOKUP(0, ((c0 >> 20) & 0xFC) );
+	left  |= PC2LOOKUP(1, ((c0 >> 11) & 0xFC) );
+	left  |= PC2LOOKUP(2, ((c0 >>  2) & 0xE0) | ((c0 <<  2) & 0x1C) );
+	left  |= PC2LOOKUP(3, ((c0>>16)&0x30)|((c0>>9)&0xC)|((c0<<2)&0xC0));
+
+	right  = PC2LOOKUP(4, ((d0 >> 20) & 0xFC) );
+	right |= PC2LOOKUP(5, ((d0 >> 13) & 0xC0) | ((d0 >> 12) & 0x3C) );
+	right |= PC2LOOKUP(6, ((d0 >>  5) & 0xFC) );
+	right |= PC2LOOKUP(7, ((d0 <<  1) & 0xF0) | ((d0 << 2) & 0x0C));
+#endif
+	/* left  contains key bits for S1 S3 S2 S4 */
+	/* right contains key bits for S6 S8 S5 S7 */
+	temp = (left  << 16)        /* S2 S4 XX XX */
+	     | (right >> 16);       /* XX XX S6 S8 */
+	ks[0] = temp;
+
+	temp = (left  & 0xffff0000) /* S1 S3 XX XX */
+	     | (right & 0x0000ffff);/* XX XX S5 S7 */
+	ks[1] = temp;
+
+	ks = (HALF*)((BYTE *)ks + delta);
+    }
+}
+
+/*
+ * The DES Initial Permutation
+ * if we number the bits of the 8 bytes of input like this (in octal):
+ *     00 01 02 03 04 05 06 07 
+ *     10 11 12 13 14 15 16 17 
+ *     20 21 22 23 24 25 26 27 
+ *     30 31 32 33 34 35 36 37 
+ *     40 41 42 43 44 45 46 47 
+ *     50 51 52 53 54 55 56 57 
+ *     60 61 62 63 64 65 66 67 
+ *     70 71 72 73 74 75 76 77 
+ * then after the initial permutation, they will be in this order. 
+ *     71 61 51 41 31 21 11 01 
+ *     73 63 53 43 33 23 13 03 
+ *     75 65 55 45 35 25 15 05 
+ *     77 67 57 47 37 27 17 07 
+ *     70 60 50 40 30 20 10 00 
+ *     72 62 52 42 32 22 12 02 
+ *     74 64 54 44 34 24 14 04 
+ *     76 66 56 46 36 26 16 06 
+ *
+ * One way to do this is in two steps:
+ * 1. Flip this matrix about the diagonal from 70-07 as done for PC1.
+ * 2. Rearrange the bytes (rows in the matrix above) with the following code.
+ *
+ * #define swapHiLo(word, temp) \
+ *   temp  = (word ^ (word >> 24)) & 0x000000ff; \
+ *   word ^=  temp | (temp << 24); 
+ *
+ *   right ^= temp = ((left << 8) ^ right) & 0xff00ff00; 
+ *   left  ^= temp >> 8; 
+ *   swapHiLo(left, temp);
+ *   swapHiLo(right,temp);
+ *
+ * However, the two steps can be combined, so that the rows are rearranged
+ * while the matrix is being flipped, reducing the number of bit exchange
+ * operations from 8 ot 5.  
+ *
+ * Initial Permutation */
+#define IP(left, right, temp) \
+    right ^= temp = ((left >> 4) ^  right) & 0x0f0f0f0f; \
+    left  ^= temp << 4; \
+    right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
+    left  ^= temp << 16; \
+    right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
+    left  ^= temp >> 2; \
+    right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
+    left  ^= temp >> 8; \
+    right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
+    left  ^= temp << 1; 
+
+/* The Final (Inverse Initial) permutation is done by reversing the 
+** steps of the Initital Permutation 
+*/
+
+#define FP(left, right, temp) \
+    right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
+    left  ^= temp << 1; \
+    right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
+    left  ^= temp >> 8; \
+    right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
+    left  ^= temp >> 2; \
+    right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
+    left  ^= temp << 16; \
+    right ^= temp = ((left >> 4) ^  right) & 0x0f0f0f0f; \
+    left  ^= temp << 4; 
+
+void 
+DES_Do1Block(HALF * ks, const BYTE * inbuf, BYTE * outbuf)
+{
+    register HALF left, right;
+    register HALF temp;
+
+#if defined(NSS_X86_OR_X64)
+    left  = HALFPTR(inbuf)[0]; 
+    right = HALFPTR(inbuf)[1]; 
+    BYTESWAP(left, temp);
+    BYTESWAP(right, temp);
+#else
+    if (((ptrdiff_t)inbuf & 0x03) == 0) {
+	left  = HALFPTR(inbuf)[0]; 
+	right = HALFPTR(inbuf)[1]; 
+#if defined(IS_LITTLE_ENDIAN)
+	BYTESWAP(left, temp);
+	BYTESWAP(right, temp);
+#endif
+    } else {
+	left    = ((HALF)inbuf[0] << 24) | ((HALF)inbuf[1] << 16) | 
+		  ((HALF)inbuf[2] << 8)  | inbuf[3];
+	right   = ((HALF)inbuf[4] << 24) | ((HALF)inbuf[5] << 16) | 
+		  ((HALF)inbuf[6] << 8)  | inbuf[7];
+    }
+#endif
+
+    IP(left, right, temp);
+
+    /* shift the values left circularly 3 bits. */
+    left  = (left  << 3) | (left  >> 29);
+    right = (right << 3) | (right >> 29);
+
+#ifdef USE_INDEXING
+#define KSLOOKUP(s,b) SP[s][((temp >> (b+2)) & 0x3f)]
+#else
+#define KSLOOKUP(s,b) *(HALF*)((BYTE*)&SP[s][0]+((temp >> b) & 0xFC))
+#endif
+#define ROUND(out, in, r) \
+    temp  = in ^ ks[2*r]; \
+    out ^= KSLOOKUP( 1,  24 ); \
+    out ^= KSLOOKUP( 3,  16 ); \
+    out ^= KSLOOKUP( 5,   8 ); \
+    out ^= KSLOOKUP( 7,   0 ); \
+    temp  = ((in >> 4) | (in << 28)) ^ ks[2*r+1]; \
+    out ^= KSLOOKUP( 0,  24 ); \
+    out ^= KSLOOKUP( 2,  16 ); \
+    out ^= KSLOOKUP( 4,   8 ); \
+    out ^= KSLOOKUP( 6,   0 ); 
+
+    /* Do the 16 Feistel rounds */
+    ROUND(left, right, 0)
+    ROUND(right, left, 1)
+    ROUND(left, right, 2)
+    ROUND(right, left, 3)
+    ROUND(left, right, 4)
+    ROUND(right, left, 5)
+    ROUND(left, right, 6)
+    ROUND(right, left, 7)
+    ROUND(left, right, 8)
+    ROUND(right, left, 9)
+    ROUND(left, right, 10)
+    ROUND(right, left, 11)
+    ROUND(left, right, 12)
+    ROUND(right, left, 13)
+    ROUND(left, right, 14)
+    ROUND(right, left, 15)
+
+    /* now shift circularly right 3 bits to undo the shifting done 
+    ** above.  switch left and right here. 
+    */
+    temp  = (left >> 3) | (left << 29); 
+    left  = (right >> 3) | (right << 29); 
+    right = temp;
+
+    FP(left, right, temp);
+
+#if defined(NSS_X86_OR_X64)
+    BYTESWAP(left, temp);
+    BYTESWAP(right, temp);
+    HALFPTR(outbuf)[0]  = left; 
+    HALFPTR(outbuf)[1]  = right; 
+#else
+    if (((ptrdiff_t)outbuf & 0x03) == 0) {
+#if defined(IS_LITTLE_ENDIAN)
+	BYTESWAP(left, temp);
+	BYTESWAP(right, temp);
+#endif
+	HALFPTR(outbuf)[0]  = left; 
+	HALFPTR(outbuf)[1]  = right; 
+    } else {
+	outbuf[0] = (BYTE)(left >> 24);
+	outbuf[1] = (BYTE)(left >> 16);
+	outbuf[2] = (BYTE)(left >>  8);
+	outbuf[3] = (BYTE)(left      );
+
+	outbuf[4] = (BYTE)(right >> 24);
+	outbuf[5] = (BYTE)(right >> 16);
+	outbuf[6] = (BYTE)(right >>  8);
+	outbuf[7] = (BYTE)(right      );
+    }
+#endif
+
+}
+
+/* Ackowledgements:
+** Two ideas used in this implementation were shown to me by Dennis Ferguson 
+** in 1990.  He credits them to Richard Outerbridge and Dan Hoey.  They were:
+** 1. The method of computing the Initial and Final permutations.
+** 2. Circularly rotating the SP tables and the initial values of left and 
+**	right to reduce the number of shifts required during the 16 rounds.
+*/
diff --git a/mozilla/security/nss/lib/freebl/des.h b/mozilla/security/nss/lib/freebl/des.h
new file mode 100644
index 0000000..1191f02
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/des.h
@@ -0,0 +1,75 @@
+/*
+ *  des.h
+ *
+ *  header file for DES-150 library
+ *
+ * ***** 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 DES-150 library.
+ *
+ * The Initial Developer of the Original Code is
+ * Nelson B. Bolyard, nelsonb@iname.com.
+ * Portions created by the Initial Developer are Copyright (C) 1990
+ * 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 ***** */
+
+#ifndef _DES_H_
+#define _DES_H_ 1
+
+#include "blapi.h"
+
+typedef unsigned char BYTE;
+typedef unsigned int  HALF;
+
+#define HALFPTR(x) ((HALF *)(x))
+#define SHORTPTR(x) ((unsigned short *)(x))
+#define BYTEPTR(x) ((BYTE *)(x))
+
+typedef enum {
+    DES_ENCRYPT = 0x5555,
+    DES_DECRYPT = 0xAAAA
+} DESDirection;
+
+typedef void DESFunc(struct DESContextStr *cx, BYTE *out, const BYTE *in, 
+                     unsigned int len);
+
+struct DESContextStr {
+    /* key schedule, 16 internal keys, each with 8 6-bit parts */
+    HALF ks0 [32];
+    HALF ks1 [32];
+    HALF ks2 [32];
+    HALF iv  [2];
+    DESDirection direction;
+    DESFunc  *worker;
+};
+
+void DES_MakeSchedule( HALF * ks, const BYTE * key,   DESDirection direction);
+void DES_Do1Block(     HALF * ks, const BYTE * inbuf, BYTE * outbuf);
+
+#endif
diff --git a/mozilla/security/nss/lib/freebl/desblapi.c b/mozilla/security/nss/lib/freebl/desblapi.c
new file mode 100644
index 0000000..deb789f
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/desblapi.c
@@ -0,0 +1,305 @@
+/*
+ *  desblapi.c
+ *
+ *  core source file for DES-150 library
+ *  Implement DES Modes of Operation and Triple-DES.
+ *  Adapt DES-150 to blapi API.
+ *
+ * ***** 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 DES-150 library.
+ *
+ * The Initial Developer of the Original Code is
+ * Nelson B. Bolyard, nelsonb@iname.com.
+ * Portions created by the Initial Developer are Copyright (C) 1990
+ * 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "des.h"
+#include <stddef.h>
+#include "secerr.h"
+
+#if defined(NSS_X86_OR_X64)
+/* Intel X86 CPUs do unaligned loads and stores without complaint. */
+#define COPY8B(to, from, ptr) \
+    	HALFPTR(to)[0] = HALFPTR(from)[0]; \
+    	HALFPTR(to)[1] = HALFPTR(from)[1]; 
+#elif defined(USE_MEMCPY)
+#define COPY8B(to, from, ptr) memcpy(to, from, 8)
+#else
+#define COPY8B(to, from, ptr) \
+    if (((ptrdiff_t)(ptr) & 0x3) == 0) { \
+    	HALFPTR(to)[0] = HALFPTR(from)[0]; \
+    	HALFPTR(to)[1] = HALFPTR(from)[1]; \
+    } else if (((ptrdiff_t)(ptr) & 0x1) == 0) { \
+    	SHORTPTR(to)[0] = SHORTPTR(from)[0]; \
+    	SHORTPTR(to)[1] = SHORTPTR(from)[1]; \
+    	SHORTPTR(to)[2] = SHORTPTR(from)[2]; \
+    	SHORTPTR(to)[3] = SHORTPTR(from)[3]; \
+    } else { \
+    	BYTEPTR(to)[0] = BYTEPTR(from)[0]; \
+    	BYTEPTR(to)[1] = BYTEPTR(from)[1]; \
+    	BYTEPTR(to)[2] = BYTEPTR(from)[2]; \
+    	BYTEPTR(to)[3] = BYTEPTR(from)[3]; \
+    	BYTEPTR(to)[4] = BYTEPTR(from)[4]; \
+    	BYTEPTR(to)[5] = BYTEPTR(from)[5]; \
+    	BYTEPTR(to)[6] = BYTEPTR(from)[6]; \
+    	BYTEPTR(to)[7] = BYTEPTR(from)[7]; \
+    } 
+#endif
+#define COPY8BTOHALF(to, from) COPY8B(to, from, from)
+#define COPY8BFROMHALF(to, from) COPY8B(to, from, to)
+
+static void 
+DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
+{
+    while (len) {
+	DES_Do1Block(cx->ks0, in, out);
+	len -= 8;
+	in  += 8;
+	out += 8;
+    }
+}
+
+static void 
+DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
+{
+    while (len) {
+	DES_Do1Block(cx->ks0,  in, out);
+	len -= 8;
+	in  += 8;
+	DES_Do1Block(cx->ks1, out, out);
+	DES_Do1Block(cx->ks2, out, out);
+	out += 8;
+    }
+}
+
+static void 
+DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
+{
+    const BYTE * bufend = in + len;
+    HALF  vec[2];
+
+    while (in != bufend) {
+	COPY8BTOHALF(vec, in);
+	in += 8;
+	vec[0] ^= cx->iv[0];
+	vec[1] ^= cx->iv[1];
+	DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
+	COPY8BFROMHALF(out, cx->iv);
+	out += 8;
+    }
+}
+
+static void 
+DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
+{
+    const BYTE * bufend;
+    HALF oldciphertext[2];
+    HALF plaintext    [2];
+
+    for (bufend = in + len; in != bufend; ) {
+	oldciphertext[0] = cx->iv[0];
+	oldciphertext[1] = cx->iv[1];
+	COPY8BTOHALF(cx->iv, in);
+	in += 8;
+	DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
+	plaintext[0] ^= oldciphertext[0];
+	plaintext[1] ^= oldciphertext[1];
+	COPY8BFROMHALF(out, plaintext);
+	out += 8;
+    }
+}
+
+static void 
+DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
+{
+    const BYTE * bufend = in + len;
+    HALF  vec[2];
+
+    while (in != bufend) {
+	COPY8BTOHALF(vec, in);
+	in += 8;
+	vec[0] ^= cx->iv[0];
+	vec[1] ^= cx->iv[1];
+	DES_Do1Block( cx->ks0, (BYTE *)vec,    (BYTE *)cx->iv);
+	DES_Do1Block( cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv);
+	DES_Do1Block( cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv);
+	COPY8BFROMHALF(out, cx->iv);
+	out += 8;
+    }
+}
+
+static void 
+DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
+{
+    const BYTE * bufend;
+    HALF oldciphertext[2];
+    HALF plaintext    [2];
+
+    for (bufend = in + len; in != bufend; ) {
+	oldciphertext[0] = cx->iv[0];
+	oldciphertext[1] = cx->iv[1];
+	COPY8BTOHALF(cx->iv, in);
+	in += 8;
+	DES_Do1Block(cx->ks0, (BYTE *)cx->iv,    (BYTE *)plaintext);
+	DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext);
+	DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext);
+	plaintext[0] ^= oldciphertext[0];
+	plaintext[1] ^= oldciphertext[1];
+	COPY8BFROMHALF(out, plaintext);
+	out += 8;
+    }
+}
+
+DESContext *
+DES_AllocateContext(void)
+{
+    return PORT_ZNew(DESContext);
+}
+
+SECStatus   
+DES_InitContext(DESContext *cx, const unsigned char *key, unsigned int keylen,
+	        const unsigned char *iv, int mode, unsigned int encrypt,
+	        unsigned int unused)
+{
+    DESDirection opposite;
+    if (!cx) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    	return SECFailure;
+    }
+    cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT;
+    opposite      = encrypt ? DES_DECRYPT : DES_ENCRYPT;
+    switch (mode) {
+    case NSS_DES:	/* DES ECB */
+	DES_MakeSchedule( cx->ks0, key, cx->direction);
+	cx->worker = &DES_ECB;
+	break;
+
+    case NSS_DES_EDE3:	/* DES EDE ECB */
+	cx->worker = &DES_EDE3_ECB;
+	if (encrypt) {
+	    DES_MakeSchedule(cx->ks0, key,      cx->direction);
+	    DES_MakeSchedule(cx->ks1, key +  8, opposite);
+	    DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
+	} else {
+	    DES_MakeSchedule(cx->ks2, key,      cx->direction);
+	    DES_MakeSchedule(cx->ks1, key +  8, opposite);
+	    DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
+	}
+	break;
+
+    case NSS_DES_CBC:	/* DES CBC */
+	COPY8BTOHALF(cx->iv, iv);
+	cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe;
+	DES_MakeSchedule(cx->ks0, key, cx->direction);
+	break;
+
+    case NSS_DES_EDE3_CBC:	/* DES EDE CBC */
+	COPY8BTOHALF(cx->iv, iv);
+	if (encrypt) {
+	    cx->worker = &DES_EDE3CBCEn;
+	    DES_MakeSchedule(cx->ks0, key,      cx->direction);
+	    DES_MakeSchedule(cx->ks1, key +  8, opposite);
+	    DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
+	} else {
+	    cx->worker = &DES_EDE3CBCDe;
+	    DES_MakeSchedule(cx->ks2, key,      cx->direction);
+	    DES_MakeSchedule(cx->ks1, key +  8, opposite);
+	    DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
+	}
+	break;
+
+    default:
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+DESContext *
+DES_CreateContext(const BYTE * key, const BYTE *iv, int mode, PRBool encrypt)
+{
+    DESContext *cx = PORT_ZNew(DESContext);
+    SECStatus rv   = DES_InitContext(cx, key, 0, iv, mode, encrypt, 0);
+
+    if (rv != SECSuccess) {
+    	PORT_ZFree(cx, sizeof *cx);
+	cx = NULL;
+    }
+    return cx;
+}
+
+void
+DES_DestroyContext(DESContext *cx, PRBool freeit)
+{
+    if (cx) {
+    	memset(cx, 0, sizeof *cx);
+	if (freeit)
+	    PORT_Free(cx);
+    }
+}
+
+SECStatus
+DES_Encrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
+            unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
+{
+
+    if (inLen < 0 || (inLen % 8) != 0 || maxOutLen < inLen || !cx || 
+        cx->direction != DES_ENCRYPT) {
+    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    cx->worker(cx, out, in, inLen);
+    if (outLen)
+	*outLen = inLen;
+    return SECSuccess;
+}
+
+SECStatus
+DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
+            unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
+{
+
+    if (inLen < 0 || (inLen % 8) != 0 || maxOutLen < inLen || !cx || 
+        cx->direction != DES_DECRYPT) {
+    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    cx->worker(cx, out, in, inLen);
+    if (outLen)
+	*outLen = inLen;
+    return SECSuccess;
+}
diff --git a/mozilla/security/nss/lib/freebl/dh.c b/mozilla/security/nss/lib/freebl/dh.c
new file mode 100644
index 0000000..25d3482
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/dh.c
@@ -0,0 +1,391 @@
+/* ***** 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 ***** */
+
+/*
+ * Diffie-Hellman parameter generation, key generation, and secret derivation.
+ * KEA secret generation and verification.
+ *
+ * $Id: dh.c,v 1.8 2008/11/18 19:48:22 rrelyea%redhat.com Exp $
+ */
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prerr.h"
+#include "secerr.h"
+
+#include "blapi.h"
+#include "secitem.h"
+#include "mpi.h"
+#include "mpprime.h"
+#include "secmpi.h"
+
+#define DH_SECRET_KEY_LEN      20
+#define KEA_DERIVED_SECRET_LEN 128
+
+SECStatus 
+DH_GenParam(int primeLen, DHParams **params)
+{
+    PRArenaPool *arena;
+    DHParams *dhparams;
+    unsigned char *pb = NULL;
+    unsigned char *ab = NULL;
+    unsigned long counter = 0;
+    mp_int p, q, a, h, psub1, test;
+    mp_err err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    if (!params || primeLen < 0) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams));
+    if (!dhparams) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	PORT_FreeArena(arena, PR_TRUE);
+	return SECFailure;
+    }
+    dhparams->arena = arena;
+    MP_DIGITS(&p) = 0;
+    MP_DIGITS(&q) = 0;
+    MP_DIGITS(&a) = 0;
+    MP_DIGITS(&h) = 0;
+    MP_DIGITS(&psub1) = 0;
+    MP_DIGITS(&test) = 0;
+    CHECK_MPI_OK( mp_init(&p) );
+    CHECK_MPI_OK( mp_init(&q) );
+    CHECK_MPI_OK( mp_init(&a) );
+    CHECK_MPI_OK( mp_init(&h) );
+    CHECK_MPI_OK( mp_init(&psub1) );
+    CHECK_MPI_OK( mp_init(&test) );
+    /* generate prime with MPI, uses Miller-Rabin to generate strong prime. */
+    pb = PORT_Alloc(primeLen);
+    CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) );
+    pb[0]          |= 0x80; /* set high-order bit */
+    pb[primeLen-1] |= 0x01; /* set low-order bit  */
+    CHECK_MPI_OK( mp_read_unsigned_octets(&p, pb, primeLen) );
+    CHECK_MPI_OK( mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter) );
+    /* construct Sophie-Germain prime q = (p-1)/2. */
+    CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) );
+    CHECK_MPI_OK( mp_div_2(&psub1, &q)    );
+    /* construct a generator from the prime. */
+    ab = PORT_Alloc(primeLen);
+    /* generate a candidate number a in p's field */
+    CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(ab, primeLen) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&a, ab, primeLen) );
+    /* force a < p (note that quot(a/p) <= 1) */
+    if ( mp_cmp(&a, &p) > 0 )
+	CHECK_MPI_OK( mp_sub(&a, &p, &a) );
+    do {
+	/* check that a is in the range [2..p-1] */
+	if ( mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) {
+	    /* a is outside of the allowed range.  Set a=3 and keep going. */
+            mp_set(&a, 3);
+	}
+	/* if a**q mod p != 1 then a is a generator */
+	CHECK_MPI_OK( mp_exptmod(&a, &q, &p, &test) );
+	if ( mp_cmp_d(&test, 1) != 0 )
+	    break;
+	/* increment the candidate and try again. */
+	CHECK_MPI_OK( mp_add_d(&a, 1, &a) );
+    } while (PR_TRUE);
+    MPINT_TO_SECITEM(&p, &dhparams->prime, arena);
+    MPINT_TO_SECITEM(&a, &dhparams->base, arena);
+    *params = dhparams;
+cleanup:
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&a);
+    mp_clear(&h);
+    mp_clear(&psub1);
+    mp_clear(&test);
+    if (pb) PORT_ZFree(pb, primeLen);
+    if (ab) PORT_ZFree(ab, primeLen);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    if (rv)
+	PORT_FreeArena(arena, PR_TRUE);
+    return rv;
+}
+
+SECStatus 
+DH_NewKey(DHParams *params, DHPrivateKey **privKey)
+{
+    PRArenaPool *arena;
+    DHPrivateKey *key;
+    mp_int g, xa, p, Ya;
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    if (!params || !privKey) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey));
+    if (!key) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	PORT_FreeArena(arena, PR_TRUE);
+	return SECFailure;
+    }
+    key->arena = arena;
+    MP_DIGITS(&g)  = 0;
+    MP_DIGITS(&xa) = 0;
+    MP_DIGITS(&p)  = 0;
+    MP_DIGITS(&Ya) = 0;
+    CHECK_MPI_OK( mp_init(&g)  );
+    CHECK_MPI_OK( mp_init(&xa) );
+    CHECK_MPI_OK( mp_init(&p)  );
+    CHECK_MPI_OK( mp_init(&Ya) );
+    /* Set private key's p */
+    CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, &params->prime) );
+    SECITEM_TO_MPINT(key->prime, &p);
+    /* Set private key's g */
+    CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, &params->base) );
+    SECITEM_TO_MPINT(key->base, &g);
+    /* Generate private key xa */
+    SECITEM_AllocItem(arena, &key->privateValue, DH_SECRET_KEY_LEN);
+    RNG_GenerateGlobalRandomBytes(key->privateValue.data, 
+                                  key->privateValue.len);
+    SECITEM_TO_MPINT( key->privateValue, &xa );
+    /* xa < p */
+    CHECK_MPI_OK( mp_mod(&xa, &p, &xa) );
+    /* Compute public key Ya = g ** xa mod p */
+    CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) );
+    MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena);
+    *privKey = key;
+cleanup:
+    mp_clear(&g);
+    mp_clear(&xa);
+    mp_clear(&p);
+    mp_clear(&Ya);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    if (rv)
+	PORT_FreeArena(arena, PR_TRUE);
+    return rv;
+}
+
+SECStatus 
+DH_Derive(SECItem *publicValue, 
+          SECItem *prime, 
+          SECItem *privateValue, 
+          SECItem *derivedSecret, 
+          unsigned int maxOutBytes)
+{
+    mp_int p, Xa, Yb, ZZ;
+    mp_err err = MP_OKAY;
+    unsigned int len = 0, nb;
+    unsigned char *secret = NULL;
+    if (!publicValue || !prime || !privateValue || !derivedSecret) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    memset(derivedSecret, 0, sizeof *derivedSecret);
+    MP_DIGITS(&p)  = 0;
+    MP_DIGITS(&Xa) = 0;
+    MP_DIGITS(&Yb) = 0;
+    MP_DIGITS(&ZZ) = 0;
+    CHECK_MPI_OK( mp_init(&p)  );
+    CHECK_MPI_OK( mp_init(&Xa) );
+    CHECK_MPI_OK( mp_init(&Yb) );
+    CHECK_MPI_OK( mp_init(&ZZ) );
+    SECITEM_TO_MPINT(*publicValue,  &Yb);
+    SECITEM_TO_MPINT(*privateValue, &Xa);
+    SECITEM_TO_MPINT(*prime,        &p);
+    /* ZZ = (Yb)**Xa mod p */
+    CHECK_MPI_OK( mp_exptmod(&Yb, &Xa, &p, &ZZ) );
+    /* number of bytes in the derived secret */
+    len = mp_unsigned_octet_size(&ZZ);
+    /* allocate a buffer which can hold the entire derived secret. */
+    secret = PORT_Alloc(len);
+    /* grab the derived secret */
+    err = mp_to_unsigned_octets(&ZZ, secret, len);
+    if (err >= 0) err = MP_OKAY;
+    /* Take minimum of bytes requested and bytes in derived secret,
+    ** if maxOutBytes is 0 take all of the bytes from the derived secret.
+    */
+    if (maxOutBytes > 0)
+	nb = PR_MIN(len, maxOutBytes);
+    else
+	nb = len;
+    SECITEM_AllocItem(NULL, derivedSecret, nb);
+    memcpy(derivedSecret->data, secret, nb);
+cleanup:
+    mp_clear(&p);
+    mp_clear(&Xa);
+    mp_clear(&Yb);
+    mp_clear(&ZZ);
+    if (secret) {
+	/* free the buffer allocated for the full secret. */
+	PORT_ZFree(secret, len);
+    }
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	if (derivedSecret->data) 
+	    PORT_ZFree(derivedSecret->data, derivedSecret->len);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+SECStatus 
+KEA_Derive(SECItem *prime, 
+           SECItem *public1, 
+           SECItem *public2, 
+           SECItem *private1, 
+           SECItem *private2,
+           SECItem *derivedSecret)
+{
+    mp_int p, Y, R, r, x, t, u, w;
+    mp_err err;
+    unsigned char *secret = NULL;
+    unsigned int len = 0, offset;
+    if (!prime || !public1 || !public2 || !private1 || !private2 ||
+        !derivedSecret) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    memset(derivedSecret, 0, sizeof *derivedSecret);
+    MP_DIGITS(&p) = 0;
+    MP_DIGITS(&Y) = 0;
+    MP_DIGITS(&R) = 0;
+    MP_DIGITS(&r) = 0;
+    MP_DIGITS(&x) = 0;
+    MP_DIGITS(&t) = 0;
+    MP_DIGITS(&u) = 0;
+    MP_DIGITS(&w) = 0;
+    CHECK_MPI_OK( mp_init(&p) );
+    CHECK_MPI_OK( mp_init(&Y) );
+    CHECK_MPI_OK( mp_init(&R) );
+    CHECK_MPI_OK( mp_init(&r) );
+    CHECK_MPI_OK( mp_init(&x) );
+    CHECK_MPI_OK( mp_init(&t) );
+    CHECK_MPI_OK( mp_init(&u) );
+    CHECK_MPI_OK( mp_init(&w) );
+    SECITEM_TO_MPINT(*prime,    &p);
+    SECITEM_TO_MPINT(*public1,  &Y);
+    SECITEM_TO_MPINT(*public2,  &R);
+    SECITEM_TO_MPINT(*private1, &r);
+    SECITEM_TO_MPINT(*private2, &x);
+    /* t = DH(Y, r, p) = Y ** r mod p */
+    CHECK_MPI_OK( mp_exptmod(&Y, &r, &p, &t) );
+    /* u = DH(R, x, p) = R ** x mod p */
+    CHECK_MPI_OK( mp_exptmod(&R, &x, &p, &u) );
+    /* w = (t + u) mod p */
+    CHECK_MPI_OK( mp_addmod(&t, &u, &p, &w) );
+    /* allocate a buffer for the full derived secret */
+    len = mp_unsigned_octet_size(&w);
+    secret = PORT_Alloc(len);
+    /* grab the secret */
+    err = mp_to_unsigned_octets(&w, secret, len);
+    if (err > 0) err = MP_OKAY;
+    /* allocate output buffer */
+    SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN);
+    memset(derivedSecret->data, 0, derivedSecret->len);
+    /* copy in the 128 lsb of the secret */
+    if (len >= KEA_DERIVED_SECRET_LEN) {
+	memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN),
+	       KEA_DERIVED_SECRET_LEN);
+    } else {
+	offset = KEA_DERIVED_SECRET_LEN - len;
+	memcpy(derivedSecret->data + offset, secret, len);
+    }
+cleanup:
+    mp_clear(&p);
+    mp_clear(&Y);
+    mp_clear(&R);
+    mp_clear(&r);
+    mp_clear(&x);
+    mp_clear(&t);
+    mp_clear(&u);
+    mp_clear(&w);
+    if (secret)
+	PORT_ZFree(secret, len);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+PRBool 
+KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
+{
+    mp_int p, q, y, r;
+    mp_err err;
+    int cmp = 1;  /* default is false */
+    if (!Y || !prime || !subPrime) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    MP_DIGITS(&p) = 0;
+    MP_DIGITS(&q) = 0;
+    MP_DIGITS(&y) = 0;
+    MP_DIGITS(&r) = 0;
+    CHECK_MPI_OK( mp_init(&p) );
+    CHECK_MPI_OK( mp_init(&q) );
+    CHECK_MPI_OK( mp_init(&y) );
+    CHECK_MPI_OK( mp_init(&r) );
+    SECITEM_TO_MPINT(*prime,    &p);
+    SECITEM_TO_MPINT(*subPrime, &q);
+    SECITEM_TO_MPINT(*Y,        &y);
+    /* compute r = y**q mod p */
+    CHECK_MPI_OK( mp_exptmod(&y, &q, &p, &r) );
+    /* compare to 1 */
+    cmp = mp_cmp_d(&r, 1);
+cleanup:
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&y);
+    mp_clear(&r);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	return PR_FALSE;
+    }
+    return (cmp == 0) ? PR_TRUE : PR_FALSE;
+}
diff --git a/mozilla/security/nss/lib/freebl/drbg.c b/mozilla/security/nss/lib/freebl/drbg.c
new file mode 100644
index 0000000..fb85133
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/drbg.c
@@ -0,0 +1,729 @@
+/* ***** 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 Network Security Services libraries.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Portions created by Netscape Communications Corporation
+ * 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
+ * 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 ***** */
+/* $Id: drbg.c,v 1.9 2009/06/10 03:24:01 rrelyea%redhat.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prerror.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+#include "prinit.h"
+#include "blapi.h"
+#include "blapii.h"
+#include "nssilock.h"
+#include "secitem.h"
+#include "sha_fast.h"
+#include "sha256.h"
+#include "secrng.h"	/* for RNG_SystemRNG() */
+#include "secmpi.h"
+
+/* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1 
+ * for SHA-1, SHA-224, and SHA-256 it's 440 bits.
+ * for SHA-384 and SHA-512 it's 888 bits */
+#define PRNG_SEEDLEN      (440/PR_BITS_PER_BYTE)
+static const PRInt64 PRNG_MAX_ADDITIONAL_BYTES = LL_INIT(0x1, 0x0);
+						/* 2^35 bits or 2^32 bytes */
+#define PRNG_MAX_REQUEST_SIZE 0x10000		/* 2^19 bits or 2^16 bytes */
+#define PRNG_ADDITONAL_DATA_CACHE_SIZE (8*1024) /* must be less than
+						 *  PRNG_MAX_ADDITIONAL_BYTES
+						 */
+
+
+/* RESEED_COUNT is how many calls to the prng before we need to reseed 
+ * under normal NIST rules, you must return an error. In the NSS case, we
+ * self-reseed with RNG_SystemRNG(). Count can be a large number. For code
+ * simplicity, we specify count with 2 components: RESEED_BYTE (which is 
+ * the same as LOG256(RESEED_COUNT)) and RESEED_VALUE (which is the same as
+ * RESEED_COUNT / (256 ^ RESEED_BYTE)). Another way to look at this is
+ * RESEED_COUNT = RESEED_VALUE * (256 ^ RESEED_BYTE). For Hash based DRBG
+ * we use the maximum count value, 2^48, or RESEED_BYTE=6 and RESEED_VALUE=1
+ */
+#define RESEED_BYTE 6
+#define RESEED_VALUE 1
+
+#define PRNG_RESET_RESEED_COUNT(rng) \
+	PORT_Memset((rng)->reseed_counter, 0, sizeof (rng)->reseed_counter); \
+	(rng)->reseed_counter[RESEED_BYTE] = 1;
+
+
+/*
+ * The actual values of this enum are specified in SP 800-90, 10.1.1.*
+ * The spec does not name the types, it only uses bare values 
+ */
+typedef enum {
+   prngCGenerateType = 0,   	/* used when creating a new 'C' */
+   prngReseedType = 1,	    	/* used in reseeding */
+   prngAdditionalDataType = 2,  /* used in mixing additional data */
+   prngGenerateByteType = 3	/* used when mixing internal state while
+				 * generating bytes */
+} prngVTypes;
+
+/*
+ * Global RNG context
+ */ 
+struct RNGContextStr {
+    PZLock   *lock;        /* Lock to serialize access to global rng */
+    /*
+     * NOTE, a number of steps in the drbg algorithm need to hash 
+     * V_type || V. The code, therefore, depends on the V array following 
+     * immediately after V_type to avoid extra copies. To accomplish this
+     * in a way that compiliers can't perturb, we declare V_type and V
+     * as a V_Data array and reference them by macros */
+    PRUint8  V_Data[PRNG_SEEDLEN+1]; /* internal state variables */
+#define  V_type  V_Data[0]
+#define  V(rng)       (((rng)->V_Data)+1)
+#define  VSize(rng)   ((sizeof (rng)->V_Data) -1)
+    PRUint8  C[PRNG_SEEDLEN];        /* internal state variables */
+    PRUint8  oldV[PRNG_SEEDLEN];     /* for continuous rng checking */
+    /* If we get calls for the PRNG to return less than the length of our
+     * hash, we extend the request for a full hash (since we'll be doing
+     * the full hash anyway). Future requests for random numbers are fulfilled
+     * from the remainder of the bytes we generated. Requests for bytes longer
+     * than the hash size are fulfilled directly from the HashGen function
+     * of the random number generator. */
+    PRUint8  reseed_counter[RESEED_BYTE+1]; /* number of requests since the 
+					     * last reseed. Need only be
+					     * big enough to hold the whole
+					     * reseed count */
+    PRUint8  data[SHA256_LENGTH];	/* when we request less than a block
+					 * save the rest of the rng output for 
+					 * another partial block */
+    PRUint8  dataAvail;            /* # bytes of output available in our cache,
+	                            * [0...SHA256_LENGTH] */
+    /* store additional data that has been shovelled off to us by
+     * RNG_RandomUpdate. */
+    PRUint8  additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE];
+    PRUint32 additionalAvail;
+    PRBool   isValid;          /* false if RNG reaches an invalid state */
+};
+
+typedef struct RNGContextStr RNGContext;
+static RNGContext *globalrng = NULL;
+static RNGContext theGlobalRng;
+
+
+/*
+ * The next several functions are derived from the NIST SP 800-90
+ * spec. In these functions, an attempt was made to use names consistent
+ * with the names in the spec, even if they differ from normal NSS usage.
+ */
+
+/*
+ * Hash Derive function defined in NISP SP 800-90 Section 10.4.1.
+ * This function is used in the Instantiate and Reseed functions.
+ * 
+ * NOTE: requested_bytes cannot overlap with input_string_1 or input_string_2.
+ * input_string_1 and input_string_2 are logically concatentated. 
+ * input_string_1 must be supplied.
+ * if input_string_2 is not supplied, NULL should be passed for this parameter.
+ */
+static SECStatus
+prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return, 
+	const PRUint8 *input_string_1, unsigned int input_string_1_len, 
+	const PRUint8 *input_string_2, unsigned int input_string_2_len)
+{
+    SHA256Context ctx;
+    PRUint32 tmp;
+    PRUint8 counter;
+
+    tmp=SHA_HTONL(no_of_bytes_to_return*8);
+
+    for (counter = 1 ; no_of_bytes_to_return > 0; counter++) {
+	unsigned int hash_return_len;
+ 	SHA256_Begin(&ctx);
+ 	SHA256_Update(&ctx, &counter, 1);
+ 	SHA256_Update(&ctx, (unsigned char *)&tmp, sizeof tmp);
+ 	SHA256_Update(&ctx, input_string_1, input_string_1_len);
+	if (input_string_2) {
+ 	    SHA256_Update(&ctx, input_string_2, input_string_2_len);
+	}
+	SHA256_End(&ctx, requested_bytes, &hash_return_len,
+		no_of_bytes_to_return);
+	requested_bytes += hash_return_len;
+	no_of_bytes_to_return -= hash_return_len;
+    }
+    return SECSuccess;
+}
+
+
+/*
+ * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2
+ *
+ * NOTE: bytes & len are entropy || nonce || personalization_string. In
+ * normal operation, NSS calculates them all together in a single call.
+ */
+static SECStatus
+prng_instantiate(RNGContext *rng, PRUint8 *bytes, unsigned int len)
+{
+    prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0);
+    rng->V_type = prngCGenerateType;
+    prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
+    PRNG_RESET_RESEED_COUNT(rng)
+    return SECSuccess;
+}
+    
+
+/*
+ * Update the global random number generator with more seeding
+ * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90
+ * section 10.1.1.3
+ *
+ * If entropy is NULL, it is fetched from the noise generator.
+ */
+static
+SECStatus
+prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len,
+	const PRUint8 *additional_input, unsigned int additional_input_len)
+{
+    PRUint8 noiseData[(sizeof rng->V_Data)+PRNG_SEEDLEN];
+    PRUint8 *noise = &noiseData[0];
+
+    /* if entropy wasn't supplied, fetch it. (normal operation case) */
+    if (entropy == NULL) {
+    	entropy_len = (unsigned int) RNG_SystemRNG(
+			&noiseData[sizeof rng->V_Data], PRNG_SEEDLEN);
+    } else {
+	/* NOTE: this code is only available for testing, not to applications */
+	/* if entropy was too big for the stack variable, get it from malloc */
+	if (entropy_len > PRNG_SEEDLEN) {
+	    noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data));
+	    if (noise == NULL) {
+		return SECFailure;
+	    }
+	}
+	PORT_Memcpy(&noise[sizeof rng->V_Data],entropy, entropy_len);
+    }
+
+    rng->V_type = prngReseedType;
+    PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data);
+    prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len,
+		additional_input, additional_input_len);
+    /* clear potential CSP */
+    PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len); 
+    rng->V_type = prngCGenerateType;
+    prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
+    PRNG_RESET_RESEED_COUNT(rng)
+
+    if (noise != &noiseData[0]) {
+	PORT_Free(noise);
+    }
+    return SECSuccess;
+}
+
+/*
+ * build some fast inline functions for adding.
+ */
+#define PRNG_ADD_CARRY_ONLY(dest, start, cy) \
+   carry = cy; \
+   for (k1=start; carry && k1 >=0 ; k1--) { \
+	carry = !(++dest[k1]); \
+   } 
+
+/*
+ * NOTE: dest must be an array for the following to work.
+ */
+#define PRNG_ADD_BITS(dest, dest_len, add, len) \
+    carry = 0; \
+    for (k1=dest_len -1, k2=len-1; k2 >= 0; --k1, --k2) { \
+	carry += dest[k1]+ add[k2]; \
+	dest[k1] = (PRUint8) carry; \
+	carry >>= 8; \
+    }
+
+#define PRNG_ADD_BITS_AND_CARRY(dest, dest_len, add, len) \
+    PRNG_ADD_BITS(dest, dest_len, add, len) \
+    PRNG_ADD_CARRY_ONLY(dest, k1, carry)
+
+/*
+ * This function expands the internal state of the prng to fulfill any number
+ * of bytes we need for this request. We only use this call if we need more
+ * than can be supplied by a single call to SHA256_HashBuf. 
+ *
+ * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen
+ */
+static void
+prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes, 
+	     unsigned int no_of_returned_bytes)
+{
+    PRUint8 data[VSize(rng)];
+
+    PORT_Memcpy(data, V(rng), VSize(rng));
+    while (no_of_returned_bytes) {
+	SHA256Context ctx;
+	unsigned int len;
+	unsigned int carry;
+	int k1;
+
+ 	SHA256_Begin(&ctx);
+ 	SHA256_Update(&ctx, data, sizeof data);
+	SHA256_End(&ctx, returned_bytes, &len, no_of_returned_bytes);
+	returned_bytes += len;
+	no_of_returned_bytes -= len;
+	/* The carry parameter is a bool (increment or not). 
+	 * This increments data if no_of_returned_bytes is not zero */
+	PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, no_of_returned_bytes);
+    }
+    PORT_Memset(data, 0, sizeof data); 
+}
+
+/* 
+ * Generates new random bytes and advances the internal prng state.	
+ * additional bytes are only used in algorithm testing.
+ * 
+ * This function is specified in NIST SP 800-90 section 10.1.1.4
+ */
+static SECStatus
+prng_generateNewBytes(RNGContext *rng, 
+		PRUint8 *returned_bytes, unsigned int no_of_returned_bytes,
+		const PRUint8 *additional_input,
+		unsigned int additional_input_len)
+{
+    PRUint8 H[SHA256_LENGTH]; /* both H and w since they 
+			       * aren't used concurrently */
+    unsigned int carry;
+    int k1, k2;
+
+    if (!rng->isValid) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    /* This code only triggers during tests, normal
+     * prng operation does not use additional_input */
+    if (additional_input){
+	SHA256Context ctx;
+	/* NIST SP 800-90 defines two temporaries in their calculations,
+	 * w and H. These temporaries are the same lengths, and used
+	 * at different times, so we use the following macro to collapse
+	 * them to the same variable, but keeping their unique names for
+	 * easy comparison to the spec */
+#define w H
+	rng->V_type = prngAdditionalDataType;
+ 	SHA256_Begin(&ctx);
+ 	SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data);
+ 	SHA256_Update(&ctx, additional_input, additional_input_len);
+	SHA256_End(&ctx, w, NULL, sizeof w);
+	PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w)
+	PORT_Memset(w, 0, sizeof w);
+#undef w 
+    }
+
+    if (no_of_returned_bytes == SHA256_LENGTH) {
+	/* short_cut to hashbuf and save a copy and a clear */
+	SHA256_HashBuf(returned_bytes, V(rng), VSize(rng) );
+    } else {
+    	prng_Hashgen(rng, returned_bytes, no_of_returned_bytes);
+    }
+    /* advance our internal state... */
+    rng->V_type = prngGenerateByteType;
+    SHA256_HashBuf(H, rng->V_Data, sizeof rng->V_Data);
+    PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), H, sizeof H)
+    PRNG_ADD_BITS(V(rng), VSize(rng), rng->C, sizeof rng->C);
+    PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter, 
+					sizeof rng->reseed_counter)
+    PRNG_ADD_CARRY_ONLY(rng->reseed_counter,(sizeof rng->reseed_counter)-1, 1);
+
+    /* continuous rng check */
+    if (memcmp(V(rng), rng->oldV, sizeof rng->oldV) == 0) {
+	rng->isValid = PR_FALSE;
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    PORT_Memcpy(rng->oldV, V(rng), sizeof rng->oldV);
+    return SECSuccess;
+}
+
+/* Use NSPR to prevent RNG_RNGInit from being called from separate
+ * threads, creating a race condition.
+ */
+static const PRCallOnceType pristineCallOnce;
+static PRCallOnceType coRNGInit;
+static PRStatus rng_init(void)
+{
+    PRUint8 bytes[PRNG_SEEDLEN*2]; /* entropy + nonce */
+    unsigned int numBytes;
+    if (globalrng == NULL) {
+	/* bytes needs to have enough space to hold
+	 * a SHA256 hash value. Blow up at compile time if this isn't true */
+	PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH);
+	/* create a new global RNG context */
+	globalrng = &theGlobalRng;
+        PORT_Assert(NULL == globalrng->lock);
+	/* create a lock for it */
+	globalrng->lock = PZ_NewLock(nssILockOther);
+	if (globalrng->lock == NULL) {
+	    globalrng = NULL;
+	    PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
+	    return PR_FAILURE;
+	}
+
+	/* Try to get some seed data for the RNG */
+	numBytes = (unsigned int) RNG_SystemRNG(bytes, sizeof bytes);
+	PORT_Assert(numBytes == 0 || numBytes == sizeof bytes);
+	if (numBytes != 0) {
+	    /* if this is our first call,  instantiate, otherwise reseed 
+	     * prng_instantiate gets a new clean state, we want to mix
+	     * any previous entropy we may have collected */
+	    if (V(globalrng)[0] == 0) {
+		prng_instantiate(globalrng, bytes, numBytes);
+	    } else {
+		prng_reseed(globalrng, bytes, numBytes, NULL, 0);
+	    }
+	    memset(bytes, 0, numBytes);
+	} else {
+	    PZ_DestroyLock(globalrng->lock);
+	    globalrng->lock = NULL;
+	    globalrng = NULL;
+	    return PR_FAILURE;
+	}
+	/* the RNG is in a valid state */
+	globalrng->isValid = PR_TRUE;
+
+	/* fetch one random value so that we can populate rng->oldV for our
+	 * continous random number test. */
+	prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0);
+
+	/* Fetch more entropy into the PRNG */
+	RNG_SystemInfoForRNG();
+    }
+    return PR_SUCCESS;
+}
+
+/*
+ * Clean up the global RNG context
+ */
+static void
+prng_freeRNGContext(RNGContext *rng)
+{
+    PRUint8 inputhash[VSize(rng) + (sizeof rng->C)];
+
+    /* destroy context lock */
+    SKIP_AFTER_FORK(PZ_DestroyLock(globalrng->lock));
+
+    /* zero global RNG context except for C & V to preserve entropy */
+    prng_Hash_df(inputhash, sizeof rng->C, rng->C, sizeof rng->C, NULL, 0); 
+    prng_Hash_df(&inputhash[sizeof rng->C], VSize(rng), V(rng), VSize(rng), 
+								  NULL, 0); 
+    memset(rng, 0, sizeof *rng);
+    memcpy(rng->C, inputhash, sizeof rng->C); 
+    memcpy(V(rng), &inputhash[sizeof rng->C], VSize(rng)); 
+
+    memset(inputhash, 0, sizeof inputhash);
+}
+
+/*
+ * Public functions
+ */
+
+/*
+ * Initialize the global RNG context and give it some seed input taken
+ * from the system.  This function is thread-safe and will only allow
+ * the global context to be initialized once.  The seed input is likely
+ * small, so it is imperative that RNG_RandomUpdate() be called with
+ * additional seed data before the generator is used.  A good way to
+ * provide the generator with additional entropy is to call
+ * RNG_SystemInfoForRNG().  Note that C_Initialize() does exactly that.
+ */
+SECStatus 
+RNG_RNGInit(void)
+{
+    /* Allow only one call to initialize the context */
+    PR_CallOnce(&coRNGInit, rng_init);
+    /* Make sure there is a context */
+    return (globalrng != NULL) ? PR_SUCCESS : PR_FAILURE;
+}
+
+/*
+** Update the global random number generator with more seeding
+** material.
+*/
+SECStatus 
+RNG_RandomUpdate(const void *data, size_t bytes)
+{
+    SECStatus rv;
+
+    /* Make sure our assumption that size_t is unsigned is true */
+    PR_STATIC_ASSERT(((size_t)-1) > (size_t)1);
+
+#if defined(NS_PTR_GT_32) || (defined(NSS_USE_64) && !defined(NS_PTR_LE_32))
+    /*
+     * NIST 800-90 requires us to verify our inputs. This value can
+     * come from the application, so we need to make sure it's within the
+     * spec. The spec says it must be less than 2^32 bytes (2^35 bits).
+     * This can only happen if size_t is greater than 32 bits (i.e. on
+     * most 64 bit platforms). The 90% case (perhaps 100% case), size_t
+     * is less than or equal to 32 bits if the platform is not 64 bits, and
+     * greater than 32 bits if it is a 64 bit platform. The corner
+     * cases are handled with explicit defines NS_PTR_GT_32 and NS_PTR_LE_32.
+     *
+     * In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be 
+     * defined. If you trip over the next two size ASSERTS at compile time,
+     * you will need to define them for your platform.
+     *
+     * if 'sizeof(size_t) > 4' is triggered it means that we were expecting
+     *   sizeof(size_t) to be greater than 4, but it wasn't. Setting 
+     *   NS_PTR_LE_32 will correct that mistake.
+     *
+     * if 'sizeof(size_t) <= 4' is triggered, it means that we were expecting
+     *   sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting 
+     *   NS_PTR_GT_32 will correct that mistake.
+     */
+
+    PR_STATIC_ASSERT(sizeof(size_t) > 4);
+
+    if (bytes > PRNG_MAX_ADDITIONAL_BYTES) {
+	bytes = PRNG_MAX_ADDITIONAL_BYTES;
+    }
+#else
+    PR_STATIC_ASSERT(sizeof(size_t) <= 4);
+#endif
+
+    PZ_Lock(globalrng->lock);
+    /* if we're passed more than our additionalDataCache, simply
+     * call reseed with that data */
+    if (bytes > sizeof (globalrng->additionalDataCache)) {
+	rv = prng_reseed(globalrng, NULL, 0, data, (unsigned int) bytes);
+    /* if we aren't going to fill or overflow the buffer, just cache it */
+    } else if (bytes < ((sizeof globalrng->additionalDataCache)
+				- globalrng->additionalAvail)) {
+	PORT_Memcpy(globalrng->additionalDataCache+globalrng->additionalAvail,
+		    data, bytes);
+	globalrng->additionalAvail += (PRUint32) bytes;
+	rv = SECSuccess;
+    } else {
+	/* we are going to fill or overflow the buffer. In this case we will
+	 * fill the entropy buffer, reseed with it, start a new buffer with the
+	 * remainder. We know the remainder will fit in the buffer because
+	 * we already handled the case where bytes > the size of the buffer.
+	 */
+	size_t bufRemain = (sizeof globalrng->additionalDataCache) 
+					- globalrng->additionalAvail;
+	/* fill the rest of the buffer */
+	if (bufRemain) {
+	    PORT_Memcpy(globalrng->additionalDataCache
+			+globalrng->additionalAvail, 
+			data, bufRemain);
+	    data = ((unsigned char *)data) + bufRemain;
+	    bytes -= bufRemain;
+	}
+	/* reseed from buffer */
+	rv = prng_reseed(globalrng, NULL, 0, globalrng->additionalDataCache, 
+					sizeof globalrng->additionalDataCache);
+
+	/* copy the rest into the cache */
+	PORT_Memcpy(globalrng->additionalDataCache, data, bytes);
+	globalrng->additionalAvail = (PRUint32) bytes;
+    }
+		
+    PZ_Unlock(globalrng->lock);
+    return rv;
+}
+
+/*
+** Generate some random bytes, using the global random number generator
+** object.
+*/
+static SECStatus 
+prng_GenerateGlobalRandomBytes(RNGContext *rng,
+                               void *dest, size_t len)
+{
+    SECStatus rv = SECSuccess;
+    PRUint8 *output = dest;
+    /* check for a valid global RNG context */
+    PORT_Assert(rng != NULL);
+    if (rng == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* FIPS limits the amount of entropy available in a single request */
+    if (len > PRNG_MAX_REQUEST_SIZE) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* --- LOCKED --- */
+    PZ_Lock(rng->lock);
+    /* Check the amount of seed data in the generator.  If not enough,
+     * don't produce any data.
+     */
+    if (rng->reseed_counter[0] >= RESEED_VALUE) {
+	rv = prng_reseed(rng, NULL, 0, NULL, 0);
+	PZ_Unlock(rng->lock);
+	if (rv != SECSuccess) {
+	    return rv;
+	}
+	RNG_SystemInfoForRNG();
+	PZ_Lock(rng->lock);
+    }
+    /*
+     * see if we have enough bytes to fulfill the request.
+     */
+    if (len <= rng->dataAvail) {
+	memcpy(output, rng->data + ((sizeof rng->data) - rng->dataAvail), len);
+	memset(rng->data + ((sizeof rng->data) - rng->dataAvail), 0, len);
+	rng->dataAvail -= len;
+	rv = SECSuccess;
+    /* if we are asking for a small number of bytes, cache the rest of 
+     * the bytes */
+    } else if (len < sizeof rng->data) {
+	rv = prng_generateNewBytes(rng, rng->data, sizeof rng->data, 
+			rng->additionalAvail ? rng->additionalDataCache : NULL,
+			rng->additionalAvail);
+	rng->additionalAvail = 0;
+	if (rv == SECSuccess) {
+	    memcpy(output, rng->data, len);
+	    memset(rng->data, 0, len); 
+	    rng->dataAvail = (sizeof rng->data) - len;
+	}
+    /* we are asking for lots of bytes, just ask the generator to pass them */
+    } else {
+	rv = prng_generateNewBytes(rng, output, len,
+			rng->additionalAvail ? rng->additionalDataCache : NULL,
+			rng->additionalAvail);
+	rng->additionalAvail = 0;
+    }
+    PZ_Unlock(rng->lock);
+    /* --- UNLOCKED --- */
+    return rv;
+}
+
+/*
+** Generate some random bytes, using the global random number generator
+** object.
+*/
+SECStatus 
+RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
+{
+    return prng_GenerateGlobalRandomBytes(globalrng, dest, len);
+}
+
+void
+RNG_RNGShutdown(void)
+{
+    /* check for a valid global RNG context */
+    PORT_Assert(globalrng != NULL);
+    if (globalrng == NULL) {
+	/* Should set a "not initialized" error code. */
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return;
+    }
+    /* clear */
+    prng_freeRNGContext(globalrng);
+    globalrng = NULL;
+    /* reset the callonce struct to allow a new call to RNG_RNGInit() */
+    coRNGInit = pristineCallOnce;
+}
+
+/*
+ * Test case interface. used by fips testing and power on self test
+ */
+ /* make sure the test context is separate from the global context, This
+  * allows us to test the internal random number generator without losing
+  * entropy we may have previously collected. */
+RNGContext testContext;
+
+/*
+ * Test vector API. Use NIST SP 800-90 general interface so one of the
+ * other NIST SP 800-90 algorithms may be used in the future.
+ */
+SECStatus
+PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len, 
+		const PRUint8 *nonce, unsigned int nonce_len,
+		const PRUint8 *personal_string, unsigned int ps_len)
+{
+   int bytes_len = entropy_len + nonce_len + ps_len;
+   PRUint8 *bytes = PORT_Alloc(bytes_len);
+
+   if (bytes == NULL) {
+	return SECFailure;
+   }
+   /* concatenate the various inputs, internally NSS only instantiates with
+    * a single long string */
+   PORT_Memcpy(bytes, entropy, entropy_len);
+   if (nonce) {
+	PORT_Memcpy(&bytes[entropy_len], nonce, nonce_len);
+   } else {
+	PORT_Assert(nonce_len == 0);
+   }
+   if (personal_string) {
+       PORT_Memcpy(&bytes[entropy_len+nonce_len], personal_string, ps_len);
+   } else {
+	PORT_Assert(ps_len == 0);
+   }
+   prng_instantiate(&testContext, bytes, bytes_len);
+   testContext.isValid = PR_TRUE;
+   PORT_ZFree(bytes, bytes_len);
+   return SECSuccess;
+}
+
+SECStatus
+PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len, 
+		  const PRUint8 *additional, unsigned int additional_len)
+{
+    if (!testContext.isValid) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return prng_reseed(&testContext, entropy, entropy_len, additional,
+			additional_len);
+
+}
+
+SECStatus
+PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len, 
+		  const PRUint8 *additional, unsigned int additional_len)
+{
+    if (!testContext.isValid) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return prng_generateNewBytes(&testContext, bytes, bytes_len,
+			additional, additional_len);
+
+}
+
+SECStatus
+PRNGTEST_Uninstantiate()
+{
+   PORT_Memset(&testContext, 0, sizeof testContext);
+   return SECSuccess;
+}
+
+
diff --git a/mozilla/security/nss/lib/freebl/dsa.c b/mozilla/security/nss/lib/freebl/dsa.c
new file mode 100644
index 0000000..d246262
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/dsa.c
@@ -0,0 +1,553 @@
+/*
+ *
+ * ***** 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 ***** */
+/* $Id: dsa.c,v 1.20 2009/03/29 16:51:58 wtc%google.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prerror.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+#include "prinit.h"
+#include "blapi.h"
+#include "nssilock.h"
+#include "secitem.h"
+#include "blapi.h"
+#include "mpi.h"
+#include "secmpi.h"
+
+ /* XXX to be replaced by define in blapit.h */
+#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
+
+#define FIPS_DSA_Q     160
+#define QSIZE      (FIPS_DSA_Q / PR_BITS_PER_BYTE)
+
+/*
+ * FIPS 186-2 requires result from random output to be reduced mod q when 
+ * generating random numbers for DSA. 
+ *
+ * Input: w, 2*QSIZE bytes
+ *        q, DSA_SUBPRIME_LEN bytes
+ * Output: xj, DSA_SUBPRIME_LEN bytes
+ */
+SECStatus
+FIPS186Change_ReduceModQForDSA(const PRUint8 *w,
+                               const PRUint8 *q,
+                               PRUint8 *xj)
+{
+    mp_int W, Q, Xj;
+    mp_err err;
+    SECStatus rv = SECSuccess;
+
+    /* Initialize MPI integers. */
+    MP_DIGITS(&W) = 0;
+    MP_DIGITS(&Q) = 0;
+    MP_DIGITS(&Xj) = 0;
+    CHECK_MPI_OK( mp_init(&W) );
+    CHECK_MPI_OK( mp_init(&Q) );
+    CHECK_MPI_OK( mp_init(&Xj) );
+    /*
+     * Convert input arguments into MPI integers.
+     */
+    CHECK_MPI_OK( mp_read_unsigned_octets(&W, w, 2*QSIZE) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&Q, q, DSA_SUBPRIME_LEN) );
+    /*
+     * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3
+     *
+     * xj = (w0 || w1) mod q
+     */
+    CHECK_MPI_OK( mp_mod(&W, &Q, &Xj) );
+    CHECK_MPI_OK( mp_to_fixlen_octets(&Xj, xj, DSA_SUBPRIME_LEN) );
+cleanup:
+    mp_clear(&W);
+    mp_clear(&Q);
+    mp_clear(&Xj);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+/*
+ * The core of Algorithm 1 of FIPS 186-2 Change Notice 1.
+ *
+ * We no longer support FIPS 186-2 RNG. This function was exported
+ * for power-up self tests and FIPS tests. Keep this stub, which fails,
+ * to prevent crashes, but also to signal to test code that FIPS 186-2
+ * RNG is no longer supported.
+ */
+SECStatus
+FIPS186Change_GenerateX(PRUint8 *XKEY, const PRUint8 *XSEEDj,
+                        PRUint8 *x_j)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+/*
+ * Specialized RNG for DSA
+ *
+ * As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value
+ * Xj should be reduced mod q, a 160-bit prime number.  Since this parameter
+ * is only meaningful in the context of DSA, the above RNG functions
+ * were implemented without it.  They are re-implemented below for use
+ * with DSA.
+ */
+
+/*
+** Generate some random bytes, using the global random number generator
+** object.  In DSA mode, so there is a q.
+*/
+static SECStatus 
+dsa_GenerateGlobalRandomBytes(void *dest, size_t len, const PRUint8 *q)
+{
+    SECStatus rv;
+    PRUint8 w[2*QSIZE];
+
+    PORT_Assert(q && len == DSA_SUBPRIME_LEN);
+    if (len != DSA_SUBPRIME_LEN) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return SECFailure;
+    }
+    if (*q == 0) {
+        ++q;
+    }
+    rv = RNG_GenerateGlobalRandomBytes(w, 2*QSIZE);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    FIPS186Change_ReduceModQForDSA(w, q, (PRUint8 *)dest);
+    return rv;
+}
+
+static void translate_mpi_error(mp_err err)
+{
+    MP_TO_SEC_ERROR(err);
+}
+
+SECStatus 
+dsa_NewKey(const PQGParams *params, DSAPrivateKey **privKey, 
+           const unsigned char *xb)
+{
+    mp_int p, g;
+    mp_int x, y;
+    mp_err err;
+    PRArenaPool *arena;
+    DSAPrivateKey *key;
+    /* Check args. */
+    if (!params || !privKey) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* Initialize an arena for the DSA key. */
+    arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
+    if (!key) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	PORT_FreeArena(arena, PR_TRUE);
+	return SECFailure;
+    }
+    key->params.arena = arena;
+    /* Initialize MPI integers. */
+    MP_DIGITS(&p) = 0;
+    MP_DIGITS(&g) = 0;
+    MP_DIGITS(&x) = 0;
+    MP_DIGITS(&y) = 0;
+    CHECK_MPI_OK( mp_init(&p) );
+    CHECK_MPI_OK( mp_init(&g) );
+    CHECK_MPI_OK( mp_init(&x) );
+    CHECK_MPI_OK( mp_init(&y) );
+    /* Copy over the PQG params */
+    CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.prime,
+                                          &params->prime) );
+    CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.subPrime,
+                                          &params->subPrime) );
+    CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.base, &params->base) );
+    /* Convert stored p, g, and received x into MPI integers. */
+    SECITEM_TO_MPINT(params->prime, &p);
+    SECITEM_TO_MPINT(params->base,  &g);
+    OCTETS_TO_MPINT(xb, &x, DSA_SUBPRIME_LEN);
+    /* Store x in private key */
+    SECITEM_AllocItem(arena, &key->privateValue, DSA_SUBPRIME_LEN);
+    memcpy(key->privateValue.data, xb, DSA_SUBPRIME_LEN);
+    /* Compute public key y = g**x mod p */
+    CHECK_MPI_OK( mp_exptmod(&g, &x, &p, &y) );
+    /* Store y in public key */
+    MPINT_TO_SECITEM(&y, &key->publicValue, arena);
+    *privKey = key;
+    key = NULL;
+cleanup:
+    mp_clear(&p);
+    mp_clear(&g);
+    mp_clear(&x);
+    mp_clear(&y);
+    if (key)
+	PORT_FreeArena(key->params.arena, PR_TRUE);
+    if (err) {
+	translate_mpi_error(err);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+** Generate and return a new DSA public and private key pair,
+**	both of which are encoded into a single DSAPrivateKey struct.
+**	"params" is a pointer to the PQG parameters for the domain
+**	Uses a random seed.
+*/
+SECStatus 
+DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey)
+{
+    SECStatus rv;
+    unsigned char seed[DSA_SUBPRIME_LEN];
+    int retries = 10;
+    int i;
+    PRBool good;
+
+    do {
+	/* Generate seed bytes for x according to FIPS 186-1 appendix 3 */
+	if (dsa_GenerateGlobalRandomBytes(seed, DSA_SUBPRIME_LEN,
+					  params->subPrime.data))
+	    return SECFailure;
+	/* Disallow values of 0 and 1 for x. */
+	good = PR_FALSE;
+	for (i = 0; i < DSA_SUBPRIME_LEN-1; i++) {
+	    if (seed[i] != 0) {
+		good = PR_TRUE;
+		break;
+	    }
+	}
+	if (!good && seed[i] > 1) {
+	    good = PR_TRUE;
+	}
+    } while (!good && --retries > 0);
+
+    if (!good) {
+	PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	return SECFailure;
+    }
+
+    /* Generate a new DSA key using random seed. */
+    rv = dsa_NewKey(params, privKey, seed);
+    return rv;
+}
+
+/* For FIPS compliance testing. Seed must be exactly 20 bytes long */
+SECStatus 
+DSA_NewKeyFromSeed(const PQGParams *params, 
+                   const unsigned char *seed,
+                   DSAPrivateKey **privKey)
+{
+    SECStatus rv;
+    rv = dsa_NewKey(params, privKey, seed);
+    return rv;
+}
+
+static SECStatus 
+dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
+               const unsigned char *kb)
+{
+    mp_int p, q, g;  /* PQG parameters */
+    mp_int x, k;     /* private key & pseudo-random integer */
+    mp_int r, s;     /* tuple (r, s) is signature) */
+    mp_err err   = MP_OKAY;
+    SECStatus rv = SECSuccess;
+
+    /* FIPS-compliance dictates that digest is a SHA1 hash. */
+    /* Check args. */
+    if (!key || !signature || !digest ||
+        (signature->len < DSA_SIGNATURE_LEN) ||
+	(digest->len != SHA1_LENGTH)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    /* Initialize MPI integers. */
+    MP_DIGITS(&p) = 0;
+    MP_DIGITS(&q) = 0;
+    MP_DIGITS(&g) = 0;
+    MP_DIGITS(&x) = 0;
+    MP_DIGITS(&k) = 0;
+    MP_DIGITS(&r) = 0;
+    MP_DIGITS(&s) = 0;
+    CHECK_MPI_OK( mp_init(&p) );
+    CHECK_MPI_OK( mp_init(&q) );
+    CHECK_MPI_OK( mp_init(&g) );
+    CHECK_MPI_OK( mp_init(&x) );
+    CHECK_MPI_OK( mp_init(&k) );
+    CHECK_MPI_OK( mp_init(&r) );
+    CHECK_MPI_OK( mp_init(&s) );
+    /*
+    ** Convert stored PQG and private key into MPI integers.
+    */
+    SECITEM_TO_MPINT(key->params.prime,    &p);
+    SECITEM_TO_MPINT(key->params.subPrime, &q);
+    SECITEM_TO_MPINT(key->params.base,     &g);
+    SECITEM_TO_MPINT(key->privateValue,    &x);
+    OCTETS_TO_MPINT(kb, &k, DSA_SUBPRIME_LEN);
+    /*
+    ** FIPS 186-1, Section 5, Step 1
+    **
+    ** r = (g**k mod p) mod q
+    */
+    CHECK_MPI_OK( mp_exptmod(&g, &k, &p, &r) ); /* r = g**k mod p */
+    CHECK_MPI_OK(     mp_mod(&r, &q, &r) );     /* r = r mod q    */
+    /*                                  
+    ** FIPS 186-1, Section 5, Step 2
+    **
+    ** s = (k**-1 * (SHA1(M) + x*r)) mod q
+    */
+    SECITEM_TO_MPINT(*digest, &s);         /* s = SHA1(M)     */
+    CHECK_MPI_OK( mp_invmod(&k, &q, &k) );      /* k = k**-1 mod q */
+    CHECK_MPI_OK( mp_mulmod(&x, &r, &q, &x) );  /* x = x * r mod q */
+    CHECK_MPI_OK( mp_addmod(&s, &x, &q, &s) );  /* s = s + x mod q */
+    CHECK_MPI_OK( mp_mulmod(&s, &k, &q, &s) );  /* s = s * k mod q */
+    /*
+    ** verify r != 0 and s != 0
+    ** mentioned as optional in FIPS 186-1.
+    */
+    if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
+	PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	rv = SECFailure;
+	goto cleanup;
+    }
+    /*
+    ** Step 4
+    **
+    ** Signature is tuple (r, s)
+    */
+    err = mp_to_fixlen_octets(&r, signature->data, DSA_SUBPRIME_LEN);
+    if (err < 0) goto cleanup; 
+    err = mp_to_fixlen_octets(&s, signature->data + DSA_SUBPRIME_LEN, 
+                                  DSA_SUBPRIME_LEN);
+    if (err < 0) goto cleanup; 
+    err = MP_OKAY;
+    signature->len = DSA_SIGNATURE_LEN;
+cleanup:
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&g);
+    mp_clear(&x);
+    mp_clear(&k);
+    mp_clear(&r);
+    mp_clear(&s);
+    if (err) {
+	translate_mpi_error(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+/* signature is caller-supplied buffer of at least 40 bytes.
+** On input,  signature->len == size of buffer to hold signature.
+**            digest->len    == size of digest.
+** On output, signature->len == size of signature in buffer.
+** Uses a random seed.
+*/
+SECStatus 
+DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest)
+{
+    SECStatus rv;
+    int       retries = 10;
+    unsigned char kSeed[DSA_SUBPRIME_LEN];
+    int       i;
+    PRBool    good;
+
+    PORT_SetError(0);
+    do {
+	rv = dsa_GenerateGlobalRandomBytes(kSeed, DSA_SUBPRIME_LEN, 
+					   key->params.subPrime.data);
+	if (rv != SECSuccess) 
+	    break;
+	/* Disallow a value of 0 for k. */
+	good = PR_FALSE;
+	for (i = 0; i < DSA_SUBPRIME_LEN; i++) {
+	    if (kSeed[i] != 0) {
+		good = PR_TRUE;
+		break;
+	    }
+	}
+	if (!good) {
+	    PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	    rv = SECFailure;
+	    continue;
+	}
+	rv = dsa_SignDigest(key, signature, digest, kSeed);
+    } while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM &&
+	     --retries > 0);
+    return rv;
+}
+
+/* For FIPS compliance testing. Seed must be exactly 20 bytes. */
+SECStatus 
+DSA_SignDigestWithSeed(DSAPrivateKey * key,
+                       SECItem *       signature,
+                       const SECItem * digest,
+                       const unsigned char * seed)
+{
+    SECStatus rv;
+    rv = dsa_SignDigest(key, signature, digest, seed);
+    return rv;
+}
+
+/* signature is caller-supplied buffer of at least 20 bytes.
+** On input,  signature->len == size of buffer to hold signature.
+**            digest->len    == size of digest.
+*/
+SECStatus 
+DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature, 
+                 const SECItem *digest)
+{
+    /* FIPS-compliance dictates that digest is a SHA1 hash. */
+    mp_int p, q, g;      /* PQG parameters */
+    mp_int r_, s_;       /* tuple (r', s') is received signature) */
+    mp_int u1, u2, v, w; /* intermediate values used in verification */
+    mp_int y;            /* public key */
+    mp_err err;
+    SECStatus verified = SECFailure;
+
+    /* Check args. */
+    if (!key || !signature || !digest ||
+        (signature->len != DSA_SIGNATURE_LEN) ||
+	(digest->len != SHA1_LENGTH)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* Initialize MPI integers. */
+    MP_DIGITS(&p)  = 0;
+    MP_DIGITS(&q)  = 0;
+    MP_DIGITS(&g)  = 0;
+    MP_DIGITS(&y)  = 0;
+    MP_DIGITS(&r_) = 0;
+    MP_DIGITS(&s_) = 0;
+    MP_DIGITS(&u1) = 0;
+    MP_DIGITS(&u2) = 0;
+    MP_DIGITS(&v)  = 0;
+    MP_DIGITS(&w)  = 0;
+    CHECK_MPI_OK( mp_init(&p)  );
+    CHECK_MPI_OK( mp_init(&q)  );
+    CHECK_MPI_OK( mp_init(&g)  );
+    CHECK_MPI_OK( mp_init(&y)  );
+    CHECK_MPI_OK( mp_init(&r_) );
+    CHECK_MPI_OK( mp_init(&s_) );
+    CHECK_MPI_OK( mp_init(&u1) );
+    CHECK_MPI_OK( mp_init(&u2) );
+    CHECK_MPI_OK( mp_init(&v)  );
+    CHECK_MPI_OK( mp_init(&w)  );
+    /*
+    ** Convert stored PQG and public key into MPI integers.
+    */
+    SECITEM_TO_MPINT(key->params.prime,    &p);
+    SECITEM_TO_MPINT(key->params.subPrime, &q);
+    SECITEM_TO_MPINT(key->params.base,     &g);
+    SECITEM_TO_MPINT(key->publicValue,     &y);
+    /*
+    ** Convert received signature (r', s') into MPI integers.
+    */
+    OCTETS_TO_MPINT(signature->data, &r_, DSA_SUBPRIME_LEN);
+    OCTETS_TO_MPINT(signature->data + DSA_SUBPRIME_LEN, &s_, DSA_SUBPRIME_LEN);
+    /*
+    ** Verify that 0 < r' < q and 0 < s' < q
+    */
+    if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
+        mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) {
+	/* err is zero here. */
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	goto cleanup; /* will return verified == SECFailure */
+    }
+    /*
+    ** FIPS 186-1, Section 6, Step 1
+    **
+    ** w = (s')**-1 mod q
+    */
+    CHECK_MPI_OK( mp_invmod(&s_, &q, &w) );      /* w = (s')**-1 mod q */
+    /*
+    ** FIPS 186-1, Section 6, Step 2
+    **
+    ** u1 = ((SHA1(M')) * w) mod q
+    */
+    SECITEM_TO_MPINT(*digest, &u1);              /* u1 = SHA1(M')     */
+    CHECK_MPI_OK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */
+    /*
+    ** FIPS 186-1, Section 6, Step 3
+    **
+    ** u2 = ((r') * w) mod q
+    */
+    CHECK_MPI_OK( mp_mulmod(&r_, &w, &q, &u2) );
+    /*
+    ** FIPS 186-1, Section 6, Step 4
+    **
+    ** v = ((g**u1 * y**u2) mod p) mod q
+    */
+    CHECK_MPI_OK( mp_exptmod(&g, &u1, &p, &g) ); /* g = g**u1 mod p */
+    CHECK_MPI_OK( mp_exptmod(&y, &u2, &p, &y) ); /* y = y**u2 mod p */
+    CHECK_MPI_OK(  mp_mulmod(&g, &y, &p, &v)  ); /* v = g * y mod p */
+    CHECK_MPI_OK(     mp_mod(&v, &q, &v)      ); /* v = v mod q     */
+    /*
+    ** Verification:  v == r'
+    */
+    if (mp_cmp(&v, &r_)) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	verified = SECFailure; /* Signature failed to verify. */
+    } else {
+	verified = SECSuccess; /* Signature verified. */
+    }
+cleanup:
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&g);
+    mp_clear(&y);
+    mp_clear(&r_);
+    mp_clear(&s_);
+    mp_clear(&u1);
+    mp_clear(&u2);
+    mp_clear(&v);
+    mp_clear(&w);
+    if (err) {
+	translate_mpi_error(err);
+    }
+    return verified;
+}
diff --git a/mozilla/security/nss/lib/freebl/ec.c b/mozilla/security/nss/lib/freebl/ec.c
new file mode 100644
index 0000000..afd0625
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ec.c
@@ -0,0 +1,1089 @@
+/*
+ * ***** 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 Elliptic Curve Cryptography library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+
+#include "blapi.h"
+#include "prerr.h"
+#include "secerr.h"
+#include "secmpi.h"
+#include "secitem.h"
+#include "mplogic.h"
+#include "ec.h"
+#include "ecl.h"
+
+#ifdef NSS_ENABLE_ECC
+
+/* 
+ * Returns true if pointP is the point at infinity, false otherwise
+ */
+PRBool
+ec_point_at_infinity(SECItem *pointP)
+{
+    unsigned int i;
+
+    for (i = 1; i < pointP->len; i++) {
+	if (pointP->data[i] != 0x00) return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+
+/* 
+ * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
+ * the curve whose parameters are encoded in params with base point G.
+ */
+SECStatus 
+ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
+             const SECItem *pointP, SECItem *pointQ)
+{
+    mp_int Px, Py, Qx, Qy;
+    mp_int Gx, Gy, order, irreducible, a, b;
+#if 0 /* currently don't support non-named curves */
+    unsigned int irr_arr[5];
+#endif
+    ECGroup *group = NULL;
+    SECStatus rv = SECFailure;
+    mp_err err = MP_OKAY;
+    int len;
+
+#if EC_DEBUG
+    int i;
+    char mpstr[256];
+
+    printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
+    for (i = 0; i < params->DEREncoding.len; i++) 
+	    printf("%02x:", params->DEREncoding.data[i]);
+    printf("\n");
+
+	if (k1 != NULL) {
+		mp_tohex(k1, mpstr);
+		printf("ec_points_mul: scalar k1: %s\n", mpstr);
+		mp_todecimal(k1, mpstr);
+		printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
+	}
+
+	if (k2 != NULL) {
+		mp_tohex(k2, mpstr);
+		printf("ec_points_mul: scalar k2: %s\n", mpstr);
+		mp_todecimal(k2, mpstr);
+		printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
+	}
+
+	if (pointP != NULL) {
+		printf("ec_points_mul: pointP [len=%d]:", pointP->len);
+		for (i = 0; i < pointP->len; i++) 
+			printf("%02x:", pointP->data[i]);
+		printf("\n");
+	}
+#endif
+
+	/* NOTE: We only support uncompressed points for now */
+	len = (params->fieldID.size + 7) >> 3;
+	if (pointP != NULL) {
+		if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
+			(pointP->len != (2 * len + 1))) {
+			PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+			return SECFailure;
+		};
+	}
+
+	MP_DIGITS(&Px) = 0;
+	MP_DIGITS(&Py) = 0;
+	MP_DIGITS(&Qx) = 0;
+	MP_DIGITS(&Qy) = 0;
+	MP_DIGITS(&Gx) = 0;
+	MP_DIGITS(&Gy) = 0;
+	MP_DIGITS(&order) = 0;
+	MP_DIGITS(&irreducible) = 0;
+	MP_DIGITS(&a) = 0;
+	MP_DIGITS(&b) = 0;
+	CHECK_MPI_OK( mp_init(&Px) );
+	CHECK_MPI_OK( mp_init(&Py) );
+	CHECK_MPI_OK( mp_init(&Qx) );
+	CHECK_MPI_OK( mp_init(&Qy) );
+	CHECK_MPI_OK( mp_init(&Gx) );
+	CHECK_MPI_OK( mp_init(&Gy) );
+	CHECK_MPI_OK( mp_init(&order) );
+	CHECK_MPI_OK( mp_init(&irreducible) );
+	CHECK_MPI_OK( mp_init(&a) );
+	CHECK_MPI_OK( mp_init(&b) );
+
+	if ((k2 != NULL) && (pointP != NULL)) {
+		/* Initialize Px and Py */
+		CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
+		CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
+	}
+
+	/* construct from named params, if possible */
+	if (params->name != ECCurve_noName) {
+		group = ECGroup_fromName(params->name);
+	}
+
+#if 0 /* currently don't support non-named curves */
+	if (group == NULL) {
+		/* Set up mp_ints containing the curve coefficients */
+		CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1, 
+										  (mp_size) len) );
+		CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len, 
+										  (mp_size) len) );
+		SECITEM_TO_MPINT( params->order, &order );
+		SECITEM_TO_MPINT( params->curve.a, &a );
+		SECITEM_TO_MPINT( params->curve.b, &b );
+		if (params->fieldID.type == ec_field_GFp) {
+			SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
+			group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
+		} else {
+			SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
+			irr_arr[0] = params->fieldID.size;
+			irr_arr[1] = params->fieldID.k1;
+			irr_arr[2] = params->fieldID.k2;
+			irr_arr[3] = params->fieldID.k3;
+			irr_arr[4] = 0;
+			group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
+		}
+	}
+#endif
+	if (group == NULL)
+		goto cleanup;
+
+	if ((k2 != NULL) && (pointP != NULL)) {
+		CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
+	} else {
+		CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
+    }
+
+    /* Construct the SECItem representation of point Q */
+    pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
+    CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
+	                              (mp_size) len) );
+    CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
+	                              (mp_size) len) );
+
+    rv = SECSuccess;
+
+#if EC_DEBUG
+    printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
+    for (i = 0; i < pointQ->len; i++) 
+	    printf("%02x:", pointQ->data[i]);
+    printf("\n");
+#endif
+
+cleanup:
+    ECGroup_free(group);
+    mp_clear(&Px);
+    mp_clear(&Py);
+    mp_clear(&Qx);
+    mp_clear(&Qy);
+    mp_clear(&Gx);
+    mp_clear(&Gy);
+    mp_clear(&order);
+    mp_clear(&irreducible);
+    mp_clear(&a);
+    mp_clear(&b);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+
+    return rv;
+}
+#endif /* NSS_ENABLE_ECC */
+
+/* Generates a new EC key pair. The private key is a supplied
+ * value and the public key is the result of performing a scalar 
+ * point multiplication of that value with the curve's base point.
+ */
+SECStatus 
+ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, 
+    const unsigned char *privKeyBytes, int privKeyLen)
+{
+    SECStatus rv = SECFailure;
+#ifdef NSS_ENABLE_ECC
+    PRArenaPool *arena;
+    ECPrivateKey *key;
+    mp_int k;
+    mp_err err = MP_OKAY;
+    int len;
+
+#if EC_DEBUG
+    printf("ec_NewKey called\n");
+#endif
+
+    if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    /* Initialize an arena for the EC key. */
+    if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
+	return SECFailure;
+
+    key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
+    if (!key) {
+	PORT_FreeArena(arena, PR_TRUE);
+	return SECFailure;
+    }
+
+    /* Set the version number (SEC 1 section C.4 says it should be 1) */
+    SECITEM_AllocItem(arena, &key->version, 1);
+    key->version.data[0] = 1;
+
+    /* Copy all of the fields from the ECParams argument to the
+     * ECParams structure within the private key.
+     */
+    key->ecParams.arena = arena;
+    key->ecParams.type = ecParams->type;
+    key->ecParams.fieldID.size = ecParams->fieldID.size;
+    key->ecParams.fieldID.type = ecParams->fieldID.type;
+    if (ecParams->fieldID.type == ec_field_GFp) {
+	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
+	    &ecParams->fieldID.u.prime));
+    } else {
+	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
+	    &ecParams->fieldID.u.poly));
+    }
+    key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
+    key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
+    key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
+	&ecParams->curve.a));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
+	&ecParams->curve.b));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
+	&ecParams->curve.seed));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
+	&ecParams->base));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
+	&ecParams->order));
+    key->ecParams.cofactor = ecParams->cofactor;
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
+	&ecParams->DEREncoding));
+    key->ecParams.name = ecParams->name;
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
+	&ecParams->curveOID));
+
+    len = (ecParams->fieldID.size + 7) >> 3;
+    SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1);
+    len = ecParams->order.len;
+    SECITEM_AllocItem(arena, &key->privateValue, len);
+
+    /* Copy private key */
+    if (privKeyLen >= len) {
+	memcpy(key->privateValue.data, privKeyBytes, len);
+    } else {
+	memset(key->privateValue.data, 0, (len - privKeyLen));
+	memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
+    }
+
+    /* Compute corresponding public key */
+    MP_DIGITS(&k) = 0;
+    CHECK_MPI_OK( mp_init(&k) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data, 
+	(mp_size) len) );
+
+    rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue));
+    if (rv != SECSuccess) goto cleanup;
+    *privKey = key;
+
+cleanup:
+    mp_clear(&k);
+    if (rv)
+	PORT_FreeArena(arena, PR_TRUE);
+
+#if EC_DEBUG
+    printf("ec_NewKey returning %s\n", 
+	(rv == SECSuccess) ? "success" : "failure");
+#endif
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+#endif /* NSS_ENABLE_ECC */
+
+    return rv;
+
+}
+
+/* Generates a new EC key pair. The private key is a supplied
+ * random value (in seed) and the public key is the result of 
+ * performing a scalar point multiplication of that value with 
+ * the curve's base point.
+ */
+SECStatus 
+EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, 
+    const unsigned char *seed, int seedlen)
+{
+    SECStatus rv = SECFailure;
+#ifdef NSS_ENABLE_ECC
+    rv = ec_NewKey(ecParams, privKey, seed, seedlen);
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+#endif /* NSS_ENABLE_ECC */
+    return rv;
+}
+
+#ifdef NSS_ENABLE_ECC
+/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
+ * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
+ * random number generator.
+ *
+ * Parameters
+ * - order: a buffer that holds the curve's group order
+ * - len: the length in octets of the order buffer
+ *
+ * Return Value
+ * Returns a buffer of len octets that holds the private key. The caller
+ * is responsible for freeing the buffer with PORT_ZFree.
+ */
+static unsigned char *
+ec_GenerateRandomPrivateKey(const unsigned char *order, int len)
+{
+    SECStatus rv = SECSuccess;
+    mp_err err;
+    unsigned char *privKeyBytes = NULL;
+    mp_int privKeyVal, order_1, one;
+
+    MP_DIGITS(&privKeyVal) = 0;
+    MP_DIGITS(&order_1) = 0;
+    MP_DIGITS(&one) = 0;
+    CHECK_MPI_OK( mp_init(&privKeyVal) );
+    CHECK_MPI_OK( mp_init(&order_1) );
+    CHECK_MPI_OK( mp_init(&one) );
+
+    /* Generates 2*len random bytes using the global random bit generator
+     * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then
+     * reduces modulo the group order.
+     */
+    if ((privKeyBytes = PORT_Alloc(2*len)) == NULL) goto cleanup;
+    CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
+    CHECK_MPI_OK( mp_set_int(&one, 1) );
+    CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
+    CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
+    CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
+    CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
+    memset(privKeyBytes+len, 0, len);
+cleanup:
+    mp_clear(&privKeyVal);
+    mp_clear(&order_1);
+    mp_clear(&one);
+    if (err < MP_OKAY) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    if (rv != SECSuccess && privKeyBytes) {
+	PORT_Free(privKeyBytes);
+	privKeyBytes = NULL;
+    }
+    return privKeyBytes;
+}
+#endif /* NSS_ENABLE_ECC */
+
+/* Generates a new EC key pair. The private key is a random value and
+ * the public key is the result of performing a scalar point multiplication
+ * of that value with the curve's base point.
+ */
+SECStatus 
+EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
+{
+    SECStatus rv = SECFailure;
+#ifdef NSS_ENABLE_ECC
+    int len;
+    unsigned char *privKeyBytes = NULL;
+
+    if (!ecParams) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    len = ecParams->order.len;
+    privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len);
+    if (privKeyBytes == NULL) goto cleanup;
+    /* generate public key */
+    CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) );
+
+cleanup:
+    if (privKeyBytes) {
+	PORT_ZFree(privKeyBytes, len);
+    }
+#if EC_DEBUG
+    printf("EC_NewKey returning %s\n", 
+	(rv == SECSuccess) ? "success" : "failure");
+#endif
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+#endif /* NSS_ENABLE_ECC */
+    
+    return rv;
+}
+
+/* Validates an EC public key as described in Section 5.2.2 of
+ * X9.62. The ECDH primitive when used without the cofactor does
+ * not address small subgroup attacks, which may occur when the
+ * public key is not valid. These attacks can be prevented by 
+ * validating the public key before using ECDH.
+ */
+SECStatus 
+EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
+{
+#ifdef NSS_ENABLE_ECC
+    mp_int Px, Py;
+    ECGroup *group = NULL;
+    SECStatus rv = SECFailure;
+    mp_err err = MP_OKAY;
+    int len;
+
+    if (!ecParams || !publicValue) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+	
+    /* NOTE: We only support uncompressed points for now */
+    len = (ecParams->fieldID.size + 7) >> 3;
+    if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
+	PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+	return SECFailure;
+    } else if (publicValue->len != (2 * len + 1)) {
+	PORT_SetError(SEC_ERROR_BAD_KEY);
+	return SECFailure;
+    }
+
+    MP_DIGITS(&Px) = 0;
+    MP_DIGITS(&Py) = 0;
+    CHECK_MPI_OK( mp_init(&Px) );
+    CHECK_MPI_OK( mp_init(&Py) );
+
+    /* Initialize Px and Py */
+    CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
+
+    /* construct from named params */
+    group = ECGroup_fromName(ecParams->name);
+    if (group == NULL) {
+	/*
+	 * ECGroup_fromName fails if ecParams->name is not a valid
+	 * ECCurveName value, or if we run out of memory, or perhaps
+	 * for other reasons.  Unfortunately if ecParams->name is a
+	 * valid ECCurveName value, we don't know what the right error
+	 * code should be because ECGroup_fromName doesn't return an
+	 * error code to the caller.  Set err to MP_UNDEF because
+	 * that's what ECGroup_fromName uses internally.
+	 */
+	if ((ecParams->name <= ECCurve_noName) ||
+	    (ecParams->name >= ECCurve_pastLastCurve)) {
+	    err = MP_BADARG;
+	} else {
+	    err = MP_UNDEF;
+	}
+	goto cleanup;
+    }
+
+    /* validate public point */
+    if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
+	if (err == MP_NO) {
+	    PORT_SetError(SEC_ERROR_BAD_KEY);
+	    rv = SECFailure;
+	    err = MP_OKAY;  /* don't change the error code */
+	}
+	goto cleanup;
+    }
+
+    rv = SECSuccess;
+
+cleanup:
+    ECGroup_free(group);
+    mp_clear(&Px);
+    mp_clear(&Py);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+    return SECFailure;
+#endif /* NSS_ENABLE_ECC */
+}
+
+/* 
+** Performs an ECDH key derivation by computing the scalar point
+** multiplication of privateValue and publicValue (with or without the
+** cofactor) and returns the x-coordinate of the resulting elliptic
+** curve point in derived secret.  If successful, derivedSecret->data
+** is set to the address of the newly allocated buffer containing the
+** derived secret, and derivedSecret->len is the size of the secret
+** produced. It is the caller's responsibility to free the allocated
+** buffer containing the derived secret.
+*/
+SECStatus 
+ECDH_Derive(SECItem  *publicValue, 
+            ECParams *ecParams,
+            SECItem  *privateValue,
+            PRBool    withCofactor,
+            SECItem  *derivedSecret)
+{
+    SECStatus rv = SECFailure;
+#ifdef NSS_ENABLE_ECC
+    unsigned int len = 0;
+    SECItem pointQ = {siBuffer, NULL, 0};
+    mp_int k; /* to hold the private value */
+    mp_int cofactor;
+    mp_err err = MP_OKAY;
+#if EC_DEBUG
+    int i;
+#endif
+
+    if (!publicValue || !ecParams || !privateValue || 
+	!derivedSecret) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    memset(derivedSecret, 0, sizeof *derivedSecret);
+    len = (ecParams->fieldID.size + 7) >> 3;  
+    pointQ.len = 2*len + 1;
+    if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup;
+
+    MP_DIGITS(&k) = 0;
+    CHECK_MPI_OK( mp_init(&k) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data, 
+	                                  (mp_size) privateValue->len) );
+
+    if (withCofactor && (ecParams->cofactor != 1)) {
+	    /* multiply k with the cofactor */
+	    MP_DIGITS(&cofactor) = 0;
+	    CHECK_MPI_OK( mp_init(&cofactor) );
+	    mp_set(&cofactor, ecParams->cofactor);
+	    CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
+    }
+
+    /* Multiply our private key and peer's public point */
+    if (ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ) != SECSuccess)
+	goto cleanup;
+    if (ec_point_at_infinity(&pointQ)) {
+	PORT_SetError(SEC_ERROR_BAD_KEY);  /* XXX better error code? */
+	goto cleanup;
+    }
+
+    /* Allocate memory for the derived secret and copy
+     * the x co-ordinate of pointQ into it.
+     */
+    SECITEM_AllocItem(NULL, derivedSecret, len);
+    memcpy(derivedSecret->data, pointQ.data + 1, len);
+
+    rv = SECSuccess;
+
+#if EC_DEBUG
+    printf("derived_secret:\n");
+    for (i = 0; i < derivedSecret->len; i++) 
+	printf("%02x:", derivedSecret->data[i]);
+    printf("\n");
+#endif
+
+cleanup:
+    mp_clear(&k);
+
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+    }
+
+    if (pointQ.data) {
+	PORT_ZFree(pointQ.data, 2*len + 1);
+    }
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+#endif /* NSS_ENABLE_ECC */
+
+    return rv;
+}
+
+/* Computes the ECDSA signature (a concatenation of two values r and s)
+ * on the digest using the given key and the random value kb (used in
+ * computing s).
+ */
+SECStatus 
+ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, 
+    const SECItem *digest, const unsigned char *kb, const int kblen)
+{
+    SECStatus rv = SECFailure;
+#ifdef NSS_ENABLE_ECC
+    mp_int x1;
+    mp_int d, k;     /* private key, random integer */
+    mp_int r, s;     /* tuple (r, s) is the signature */
+    mp_int n;
+    mp_err err = MP_OKAY;
+    ECParams *ecParams = NULL;
+    SECItem kGpoint = { siBuffer, NULL, 0};
+    int flen = 0;    /* length in bytes of the field size */
+    unsigned olen;   /* length in bytes of the base point order */
+
+#if EC_DEBUG
+    char mpstr[256];
+#endif
+
+    /* Initialize MPI integers. */
+    /* must happen before the first potential call to cleanup */
+    MP_DIGITS(&x1) = 0;
+    MP_DIGITS(&d) = 0;
+    MP_DIGITS(&k) = 0;
+    MP_DIGITS(&r) = 0;
+    MP_DIGITS(&s) = 0;
+    MP_DIGITS(&n) = 0;
+
+    /* Check args */
+    if (!key || !signature || !digest || !kb || (kblen < 0)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	goto cleanup;
+    }
+
+    ecParams = &(key->ecParams);
+    flen = (ecParams->fieldID.size + 7) >> 3;
+    olen = ecParams->order.len;  
+    if (signature->data == NULL) {
+	/* a call to get the signature length only */
+	goto finish;
+    }
+    if (signature->len < 2*olen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	goto cleanup;
+    }
+
+
+    CHECK_MPI_OK( mp_init(&x1) );
+    CHECK_MPI_OK( mp_init(&d) );
+    CHECK_MPI_OK( mp_init(&k) );
+    CHECK_MPI_OK( mp_init(&r) );
+    CHECK_MPI_OK( mp_init(&s) );
+    CHECK_MPI_OK( mp_init(&n) );
+
+    SECITEM_TO_MPINT( ecParams->order, &n );
+    SECITEM_TO_MPINT( key->privateValue, &d );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
+    /* Make sure k is in the interval [1, n-1] */
+    if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
+#if EC_DEBUG
+        printf("k is outside [1, n-1]\n");
+        mp_tohex(&k, mpstr);
+	printf("k : %s \n", mpstr);
+        mp_tohex(&n, mpstr);
+	printf("n : %s \n", mpstr);
+#endif
+	PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	goto cleanup;
+    }
+
+    /* 
+    ** ANSI X9.62, Section 5.3.2, Step 2
+    **
+    ** Compute kG
+    */
+    kGpoint.len = 2*flen + 1;
+    kGpoint.data = PORT_Alloc(2*flen + 1);
+    if ((kGpoint.data == NULL) ||
+	(ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint)
+	    != SECSuccess))
+	goto cleanup;
+
+    /* 
+    ** ANSI X9.62, Section 5.3.3, Step 1
+    **
+    ** Extract the x co-ordinate of kG into x1
+    */
+    CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, 
+	                                  (mp_size) flen) );
+
+    /* 
+    ** ANSI X9.62, Section 5.3.3, Step 2
+    **
+    ** r = x1 mod n  NOTE: n is the order of the curve
+    */
+    CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
+
+    /*
+    ** ANSI X9.62, Section 5.3.3, Step 3
+    **
+    ** verify r != 0 
+    */
+    if (mp_cmp_z(&r) == 0) {
+	PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	goto cleanup;
+    }
+
+    /*                                  
+    ** ANSI X9.62, Section 5.3.3, Step 4
+    **
+    ** s = (k**-1 * (HASH(M) + d*r)) mod n 
+    */
+    SECITEM_TO_MPINT(*digest, &s);        /* s = HASH(M)     */
+
+    /* In the definition of EC signing, digests are truncated
+     * to the length of n in bits. 
+     * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
+    if (digest->len*8 > ecParams->fieldID.size) {
+	mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size);
+    }
+
+#if EC_DEBUG
+    mp_todecimal(&n, mpstr);
+    printf("n : %s (dec)\n", mpstr);
+    mp_todecimal(&d, mpstr);
+    printf("d : %s (dec)\n", mpstr);
+    mp_tohex(&x1, mpstr);
+    printf("x1: %s\n", mpstr);
+    mp_todecimal(&s, mpstr);
+    printf("digest: %s (decimal)\n", mpstr);
+    mp_todecimal(&r, mpstr);
+    printf("r : %s (dec)\n", mpstr);
+    mp_tohex(&r, mpstr);
+    printf("r : %s\n", mpstr);
+#endif
+
+    CHECK_MPI_OK( mp_invmod(&k, &n, &k) );      /* k = k**-1 mod n */
+    CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) );  /* d = d * r mod n */
+    CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) );  /* s = s + d mod n */
+    CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) );  /* s = s * k mod n */
+
+#if EC_DEBUG
+    mp_todecimal(&s, mpstr);
+    printf("s : %s (dec)\n", mpstr);
+    mp_tohex(&s, mpstr);
+    printf("s : %s\n", mpstr);
+#endif
+
+    /*
+    ** ANSI X9.62, Section 5.3.3, Step 5
+    **
+    ** verify s != 0
+    */
+    if (mp_cmp_z(&s) == 0) {
+	PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	goto cleanup;
+    }
+
+   /*
+    **
+    ** Signature is tuple (r, s)
+    */
+    CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
+    CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
+finish:
+    signature->len = 2*olen;
+
+    rv = SECSuccess;
+    err = MP_OKAY;
+cleanup:
+    mp_clear(&x1);
+    mp_clear(&d);
+    mp_clear(&k);
+    mp_clear(&r);
+    mp_clear(&s);
+    mp_clear(&n);
+
+    if (kGpoint.data) {
+	PORT_ZFree(kGpoint.data, 2*flen + 1);
+    }
+
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+
+#if EC_DEBUG
+    printf("ECDSA signing with seed %s\n",
+	(rv == SECSuccess) ? "succeeded" : "failed");
+#endif
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+#endif /* NSS_ENABLE_ECC */
+
+   return rv;
+}
+
+/*
+** Computes the ECDSA signature on the digest using the given key 
+** and a random seed.
+*/
+SECStatus 
+ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
+{
+    SECStatus rv = SECFailure;
+#ifdef NSS_ENABLE_ECC
+    int len;
+    unsigned char *kBytes= NULL;
+
+    if (!key) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    /* Generate random value k */
+    len = key->ecParams.order.len;
+    kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len);
+    if (kBytes == NULL) goto cleanup;
+
+    /* Generate ECDSA signature with the specified k value */
+    rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len);
+
+cleanup:    
+    if (kBytes) {
+	PORT_ZFree(kBytes, len);
+    }
+
+#if EC_DEBUG
+    printf("ECDSA signing %s\n",
+	(rv == SECSuccess) ? "succeeded" : "failed");
+#endif
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+#endif /* NSS_ENABLE_ECC */
+
+    return rv;
+}
+
+/*
+** Checks the signature on the given digest using the key provided.
+*/
+SECStatus 
+ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, 
+                 const SECItem *digest)
+{
+    SECStatus rv = SECFailure;
+#ifdef NSS_ENABLE_ECC
+    mp_int r_, s_;           /* tuple (r', s') is received signature) */
+    mp_int c, u1, u2, v;     /* intermediate values used in verification */
+    mp_int x1;
+    mp_int n;
+    mp_err err = MP_OKAY;
+    ECParams *ecParams = NULL;
+    SECItem pointC = { siBuffer, NULL, 0 };
+    int slen;       /* length in bytes of a half signature (r or s) */
+    int flen;       /* length in bytes of the field size */
+    unsigned olen;  /* length in bytes of the base point order */
+
+#if EC_DEBUG
+    char mpstr[256];
+    printf("ECDSA verification called\n");
+#endif
+
+    /* Initialize MPI integers. */
+    /* must happen before the first potential call to cleanup */
+    MP_DIGITS(&r_) = 0;
+    MP_DIGITS(&s_) = 0;
+    MP_DIGITS(&c) = 0;
+    MP_DIGITS(&u1) = 0;
+    MP_DIGITS(&u2) = 0;
+    MP_DIGITS(&x1) = 0;
+    MP_DIGITS(&v)  = 0;
+    MP_DIGITS(&n)  = 0;
+
+    /* Check args */
+    if (!key || !signature || !digest) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	goto cleanup;
+    }
+
+    ecParams = &(key->ecParams);
+    flen = (ecParams->fieldID.size + 7) >> 3;  
+    olen = ecParams->order.len;  
+    if (signature->len == 0 || signature->len%2 != 0 ||
+	signature->len > 2*olen) {
+	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	goto cleanup;
+    }
+    slen = signature->len/2;
+
+    SECITEM_AllocItem(NULL, &pointC, 2*flen + 1);
+    if (pointC.data == NULL)
+	goto cleanup;
+
+    CHECK_MPI_OK( mp_init(&r_) );
+    CHECK_MPI_OK( mp_init(&s_) );
+    CHECK_MPI_OK( mp_init(&c)  );
+    CHECK_MPI_OK( mp_init(&u1) );
+    CHECK_MPI_OK( mp_init(&u2) );
+    CHECK_MPI_OK( mp_init(&x1)  );
+    CHECK_MPI_OK( mp_init(&v)  );
+    CHECK_MPI_OK( mp_init(&n)  );
+
+    /*
+    ** Convert received signature (r', s') into MPI integers.
+    */
+    CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
+                                          
+    /* 
+    ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
+    **
+    ** Verify that 0 < r' < n and 0 < s' < n
+    */
+    SECITEM_TO_MPINT(ecParams->order, &n);
+    if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
+        mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	goto cleanup; /* will return rv == SECFailure */
+    }
+
+    /*
+    ** ANSI X9.62, Section 5.4.2, Step 3
+    **
+    ** c = (s')**-1 mod n
+    */
+    CHECK_MPI_OK( mp_invmod(&s_, &n, &c) );      /* c = (s')**-1 mod n */
+
+    /*
+    ** ANSI X9.62, Section 5.4.2, Step 4
+    **
+    ** u1 = ((HASH(M')) * c) mod n
+    */
+    SECITEM_TO_MPINT(*digest, &u1);                  /* u1 = HASH(M)     */
+
+    /* In the definition of EC signing, digests are truncated
+     * to the length of n in bits. 
+     * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
+    if (digest->len*8 > ecParams->fieldID.size) {  /* u1 = HASH(M')     */
+	mpl_rsh(&u1,&u1,digest->len*8- ecParams->fieldID.size);
+    }
+
+#if EC_DEBUG
+    mp_todecimal(&r_, mpstr);
+    printf("r_: %s (dec)\n", mpstr);
+    mp_todecimal(&s_, mpstr);
+    printf("s_: %s (dec)\n", mpstr);
+    mp_todecimal(&c, mpstr);
+    printf("c : %s (dec)\n", mpstr);
+    mp_todecimal(&u1, mpstr);
+    printf("digest: %s (dec)\n", mpstr);
+#endif
+
+    CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) );  /* u1 = u1 * c mod n */
+
+    /*
+    ** ANSI X9.62, Section 5.4.2, Step 4
+    **
+    ** u2 = ((r') * c) mod n
+    */
+    CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
+
+    /*
+    ** ANSI X9.62, Section 5.4.3, Step 1
+    **
+    ** Compute u1*G + u2*Q
+    ** Here, A = u1.G     B = u2.Q    and   C = A + B
+    ** If the result, C, is the point at infinity, reject the signature
+    */
+    if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC)
+	!= SECSuccess) {
+	rv = SECFailure;
+	goto cleanup;
+    }
+    if (ec_point_at_infinity(&pointC)) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	rv = SECFailure;
+	goto cleanup;
+    }
+
+    CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
+
+    /*
+    ** ANSI X9.62, Section 5.4.4, Step 2
+    **
+    ** v = x1 mod n
+    */
+    CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
+
+#if EC_DEBUG
+    mp_todecimal(&r_, mpstr);
+    printf("r_: %s (dec)\n", mpstr);
+    mp_todecimal(&v, mpstr);
+    printf("v : %s (dec)\n", mpstr);
+#endif
+
+    /*
+    ** ANSI X9.62, Section 5.4.4, Step 3
+    **
+    ** Verification:  v == r'
+    */
+    if (mp_cmp(&v, &r_)) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	rv = SECFailure; /* Signature failed to verify. */
+    } else {
+	rv = SECSuccess; /* Signature verified. */
+    }
+
+#if EC_DEBUG
+    mp_todecimal(&u1, mpstr);
+    printf("u1: %s (dec)\n", mpstr);
+    mp_todecimal(&u2, mpstr);
+    printf("u2: %s (dec)\n", mpstr);
+    mp_tohex(&x1, mpstr);
+    printf("x1: %s\n", mpstr);
+    mp_todecimal(&v, mpstr);
+    printf("v : %s (dec)\n", mpstr);
+#endif
+
+cleanup:
+    mp_clear(&r_);
+    mp_clear(&s_);
+    mp_clear(&c);
+    mp_clear(&u1);
+    mp_clear(&u2);
+    mp_clear(&x1);
+    mp_clear(&v);
+    mp_clear(&n);
+
+    if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+
+#if EC_DEBUG
+    printf("ECDSA verification %s\n",
+	(rv == SECSuccess) ? "succeeded" : "failed");
+#endif
+#else
+    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+#endif /* NSS_ENABLE_ECC */
+
+    return rv;
+}
+
diff --git a/mozilla/security/nss/lib/freebl/ec.h b/mozilla/security/nss/lib/freebl/ec.h
new file mode 100644
index 0000000..3de4241
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ec.h
@@ -0,0 +1,52 @@
+/* 
+ * ***** 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 Elliptic Curve Cryptography library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifndef __ec_h_
+#define __ec_h_
+
+#define EC_DEBUG                          0
+#define EC_POINT_FORM_COMPRESSED_Y0    0x02
+#define EC_POINT_FORM_COMPRESSED_Y1    0x03
+#define EC_POINT_FORM_UNCOMPRESSED     0x04
+#define EC_POINT_FORM_HYBRID_Y0        0x06
+#define EC_POINT_FORM_HYBRID_Y1        0x07
+
+#define ANSI_X962_CURVE_OID_TOTAL_LEN    10
+#define SECG_CURVE_OID_TOTAL_LEN          7
+
+#endif /* __ec_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2.h b/mozilla/security/nss/lib/freebl/ecl/ec2.h
new file mode 100644
index 0000000..2ca8418
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2.h
@@ -0,0 +1,126 @@
+/* 
+ * ***** 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 elliptic curve math library for binary polynomial field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifndef __ec2_h_
+#define __ec2_h_
+
+#include "ecl-priv.h"
+
+/* Checks if point P(px, py) is at infinity.  Uses affine coordinates. */
+mp_err ec_GF2m_pt_is_inf_aff(const mp_int *px, const mp_int *py);
+
+/* Sets P(px, py) to be the point at infinity.  Uses affine coordinates. */
+mp_err ec_GF2m_pt_set_inf_aff(mp_int *px, mp_int *py);
+
+/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx,
+ * qy). Uses affine coordinates. */
+mp_err ec_GF2m_pt_add_aff(const mp_int *px, const mp_int *py,
+						  const mp_int *qx, const mp_int *qy, mp_int *rx,
+						  mp_int *ry, const ECGroup *group);
+
+/* Computes R = P - Q.  Uses affine coordinates. */
+mp_err ec_GF2m_pt_sub_aff(const mp_int *px, const mp_int *py,
+						  const mp_int *qx, const mp_int *qy, mp_int *rx,
+						  mp_int *ry, const ECGroup *group);
+
+/* Computes R = 2P.  Uses affine coordinates. */
+mp_err ec_GF2m_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+						  mp_int *ry, const ECGroup *group);
+
+/* Validates a point on a GF2m curve. */
+mp_err ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group);
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the irreducible that 
+ * determines the field GF2m.  Uses affine coordinates. */
+mp_err ec_GF2m_pt_mul_aff(const mp_int *n, const mp_int *px,
+						  const mp_int *py, mp_int *rx, mp_int *ry,
+						  const ECGroup *group);
+#endif
+
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the irreducible that 
+ * determines the field GF2m.  Uses Montgomery projective coordinates. */
+mp_err ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px,
+						   const mp_int *py, mp_int *rx, mp_int *ry,
+						   const ECGroup *group);
+
+#ifdef ECL_ENABLE_GF2M_PROJ
+/* Converts a point P(px, py) from affine coordinates to projective
+ * coordinates R(rx, ry, rz). */
+mp_err ec_GF2m_pt_aff2proj(const mp_int *px, const mp_int *py, mp_int *rx,
+						   mp_int *ry, mp_int *rz, const ECGroup *group);
+
+/* Converts a point P(px, py, pz) from projective coordinates to affine
+ * coordinates R(rx, ry). */
+mp_err ec_GF2m_pt_proj2aff(const mp_int *px, const mp_int *py,
+						   const mp_int *pz, mp_int *rx, mp_int *ry,
+						   const ECGroup *group);
+
+/* Checks if point P(px, py, pz) is at infinity.  Uses projective
+ * coordinates. */
+mp_err ec_GF2m_pt_is_inf_proj(const mp_int *px, const mp_int *py,
+							  const mp_int *pz);
+
+/* Sets P(px, py, pz) to be the point at infinity.  Uses projective
+ * coordinates. */
+mp_err ec_GF2m_pt_set_inf_proj(mp_int *px, mp_int *py, mp_int *pz);
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, qz).  Uses projective coordinates. */
+mp_err ec_GF2m_pt_add_proj(const mp_int *px, const mp_int *py,
+						   const mp_int *pz, const mp_int *qx,
+						   const mp_int *qy, mp_int *rx, mp_int *ry,
+						   mp_int *rz, const ECGroup *group);
+
+/* Computes R = 2P.  Uses projective coordinates. */
+mp_err ec_GF2m_pt_dbl_proj(const mp_int *px, const mp_int *py,
+						   const mp_int *pz, mp_int *rx, mp_int *ry,
+						   mp_int *rz, const ECGroup *group);
+
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GF2m.  Uses projective coordinates. */
+mp_err ec_GF2m_pt_mul_proj(const mp_int *n, const mp_int *px,
+						   const mp_int *py, mp_int *rx, mp_int *ry,
+						   const ECGroup *group);
+#endif
+
+#endif							/* __ec2_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec_naf.c b/mozilla/security/nss/lib/freebl/ecl/ec_naf.c
new file mode 100644
index 0000000..9ef3a55
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec_naf.c
@@ -0,0 +1,103 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stephen Fung <fungstep@hotmail.com>, Sun Microsystems Laboratories
+ *
+ * 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 "ecl-priv.h"
+
+/* Returns 2^e as an integer. This is meant to be used for small powers of 
+ * two. */
+int
+ec_twoTo(int e)
+{
+	int a = 1;
+	int i;
+
+	for (i = 0; i < e; i++) {
+		a *= 2;
+	}
+	return a;
+}
+
+/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
+ * be an array of signed char's to output to, bitsize should be the number 
+ * of bits of out, in is the original scalar, and w is the window size.
+ * NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
+ * Menezes, "Software implementation of elliptic curve cryptography over
+ * binary fields", Proc. CHES 2000. */
+mp_err
+ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in, int w)
+{
+	mp_int k;
+	mp_err res = MP_OKAY;
+	int i, twowm1, mask;
+
+	twowm1 = ec_twoTo(w - 1);
+	mask = 2 * twowm1 - 1;
+
+	MP_DIGITS(&k) = 0;
+	MP_CHECKOK(mp_init_copy(&k, in));
+
+	i = 0;
+	/* Compute wNAF form */
+	while (mp_cmp_z(&k) > 0) {
+		if (mp_isodd(&k)) {
+			out[i] = MP_DIGIT(&k, 0) & mask;
+			if (out[i] >= twowm1)
+				out[i] -= 2 * twowm1;
+
+			/* Subtract off out[i].  Note mp_sub_d only works with
+			 * unsigned digits */
+			if (out[i] >= 0) {
+				mp_sub_d(&k, out[i], &k);
+			} else {
+				mp_add_d(&k, -(out[i]), &k);
+			}
+		} else {
+			out[i] = 0;
+		}
+		mp_div_2(&k, &k);
+		i++;
+	}
+	/* Zero out the remaining elements of the out array. */
+	for (; i < bitsize + 1; i++) {
+		out[i] = 0;
+	}
+  CLEANUP:
+	mp_clear(&k);
+	return res;
+
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl-curve.h b/mozilla/security/nss/lib/freebl/ecl/ecl-curve.h
new file mode 100644
index 0000000..3a01dc8
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl-curve.h
@@ -0,0 +1,144 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 "ecl-exp.h"
+#include <stdlib.h>
+
+#ifndef __ecl_curve_h_
+#define __ecl_curve_h_
+
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+#error This source file is for Basic ECC only .
+#endif
+
+static const ECCurveParams ecCurve_NIST_P256 = {
+	"NIST-P256", ECField_GFp, 256,
+	"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+	"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+	"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+	"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+	"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+	"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1
+};
+
+static const ECCurveParams ecCurve_NIST_P384 = {
+	"NIST-P384", ECField_GFp, 384,
+	"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+	"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
+	"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+	"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+	"3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+	"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+	1
+};
+
+static const ECCurveParams ecCurve_NIST_P521 = {
+	"NIST-P521", ECField_GFp, 521,
+	"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+	"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
+	"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+	"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+	"011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+	"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+	1
+};
+
+/* mapping between ECCurveName enum and pointers to ECCurveParams */
+static const ECCurveParams *ecCurve_map[] = {
+	NULL,			/* ECCurve_noName */
+	NULL,			/* ECCurve_NIST_P192 */
+	NULL,			/* ECCurve_NIST_P224 */
+	&ecCurve_NIST_P256,	/* ECCurve_NIST_P256 */
+	&ecCurve_NIST_P384,	/* ECCurve_NIST_P384 */
+	&ecCurve_NIST_P521,	/* ECCurve_NIST_P521 */
+	NULL,			/* ECCurve_NIST_K163 */
+	NULL,			/* ECCurve_NIST_B163 */
+	NULL,			/* ECCurve_NIST_K233 */
+	NULL,			/* ECCurve_NIST_B233 */
+	NULL,			/* ECCurve_NIST_K283 */
+	NULL,			/* ECCurve_NIST_B283 */
+	NULL,			/* ECCurve_NIST_K409 */
+	NULL,			/* ECCurve_NIST_B409 */
+	NULL,			/* ECCurve_NIST_K571 */
+	NULL,			/* ECCurve_NIST_B571 */
+	NULL,			/* ECCurve_X9_62_PRIME_192V2 */
+	NULL,			/* ECCurve_X9_62_PRIME_192V3 */
+	NULL,			/* ECCurve_X9_62_PRIME_239V1 */
+	NULL,			/* ECCurve_X9_62_PRIME_239V2 */
+	NULL,			/* ECCurve_X9_62_PRIME_239V3 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB163V1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB163V2 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB163V3 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB176V1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB191V1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB191V2 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB191V3 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB208W1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB239V1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB239V2 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB239V3 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB272W1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB304W1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB359V1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_PNB368W1 */
+	NULL,			/* ECCurve_X9_62_CHAR2_TNB431R1 */
+	NULL,			/* ECCurve_SECG_PRIME_112R1 */
+	NULL,			/* ECCurve_SECG_PRIME_112R2 */
+	NULL,			/* ECCurve_SECG_PRIME_128R1 */
+	NULL,			/* ECCurve_SECG_PRIME_128R2 */
+	NULL,			/* ECCurve_SECG_PRIME_160K1 */
+	NULL,			/* ECCurve_SECG_PRIME_160R1 */
+	NULL,			/* ECCurve_SECG_PRIME_160R2 */
+	NULL,			/* ECCurve_SECG_PRIME_192K1 */
+	NULL,			/* ECCurve_SECG_PRIME_224K1 */
+	NULL,			/* ECCurve_SECG_PRIME_256K1 */
+	NULL,			/* ECCurve_SECG_CHAR2_113R1 */
+	NULL,			/* ECCurve_SECG_CHAR2_113R2 */
+	NULL,			/* ECCurve_SECG_CHAR2_131R1 */
+	NULL,			/* ECCurve_SECG_CHAR2_131R2 */
+	NULL,			/* ECCurve_SECG_CHAR2_163R1 */
+	NULL,			/* ECCurve_SECG_CHAR2_193R1 */
+	NULL,			/* ECCurve_SECG_CHAR2_193R2 */
+	NULL,			/* ECCurve_SECG_CHAR2_239K1 */
+	NULL,			/* ECCurve_WTLS_1 */
+	NULL,			/* ECCurve_WTLS_8 */
+	NULL,			/* ECCurve_WTLS_9 */
+	NULL			/* ECCurve_pastLastCurve */
+};
+
+#endif
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl-exp.h b/mozilla/security/nss/lib/freebl/ecl/ecl-exp.h
new file mode 100644
index 0000000..77f3ebb
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl-exp.h
@@ -0,0 +1,196 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifndef __ecl_exp_h_
+#define __ecl_exp_h_
+
+/* Curve field type */
+typedef enum {
+	ECField_GFp,
+	ECField_GF2m
+} ECField;
+
+/* Hexadecimal encoding of curve parameters */
+struct ECCurveParamsStr {
+	char *text;
+	ECField field;
+	unsigned int size;
+	char *irr;
+	char *curvea;
+	char *curveb;
+	char *genx;
+	char *geny;
+	char *order;
+	int cofactor;
+};
+typedef struct ECCurveParamsStr ECCurveParams;
+
+/* Named curve parameters */
+typedef enum {
+
+	ECCurve_noName = 0,
+
+	/* NIST prime curves */
+	ECCurve_NIST_P192,
+	ECCurve_NIST_P224,
+	ECCurve_NIST_P256,
+	ECCurve_NIST_P384,
+	ECCurve_NIST_P521,
+
+	/* NIST binary curves */
+	ECCurve_NIST_K163,
+	ECCurve_NIST_B163,
+	ECCurve_NIST_K233,
+	ECCurve_NIST_B233,
+	ECCurve_NIST_K283,
+	ECCurve_NIST_B283,
+	ECCurve_NIST_K409,
+	ECCurve_NIST_B409,
+	ECCurve_NIST_K571,
+	ECCurve_NIST_B571,
+
+	/* ANSI X9.62 prime curves */
+	/* ECCurve_X9_62_PRIME_192V1 == ECCurve_NIST_P192 */
+	ECCurve_X9_62_PRIME_192V2,
+	ECCurve_X9_62_PRIME_192V3,
+	ECCurve_X9_62_PRIME_239V1,
+	ECCurve_X9_62_PRIME_239V2,
+	ECCurve_X9_62_PRIME_239V3,
+	/* ECCurve_X9_62_PRIME_256V1 == ECCurve_NIST_P256 */
+
+	/* ANSI X9.62 binary curves */
+	ECCurve_X9_62_CHAR2_PNB163V1,
+	ECCurve_X9_62_CHAR2_PNB163V2,
+	ECCurve_X9_62_CHAR2_PNB163V3,
+	ECCurve_X9_62_CHAR2_PNB176V1,
+	ECCurve_X9_62_CHAR2_TNB191V1,
+	ECCurve_X9_62_CHAR2_TNB191V2,
+	ECCurve_X9_62_CHAR2_TNB191V3,
+	ECCurve_X9_62_CHAR2_PNB208W1,
+	ECCurve_X9_62_CHAR2_TNB239V1,
+	ECCurve_X9_62_CHAR2_TNB239V2,
+	ECCurve_X9_62_CHAR2_TNB239V3,
+	ECCurve_X9_62_CHAR2_PNB272W1,
+	ECCurve_X9_62_CHAR2_PNB304W1,
+	ECCurve_X9_62_CHAR2_TNB359V1,
+	ECCurve_X9_62_CHAR2_PNB368W1,
+	ECCurve_X9_62_CHAR2_TNB431R1,
+
+	/* SEC2 prime curves */
+	ECCurve_SECG_PRIME_112R1,
+	ECCurve_SECG_PRIME_112R2,
+	ECCurve_SECG_PRIME_128R1,
+	ECCurve_SECG_PRIME_128R2,
+	ECCurve_SECG_PRIME_160K1,
+	ECCurve_SECG_PRIME_160R1,
+	ECCurve_SECG_PRIME_160R2,
+	ECCurve_SECG_PRIME_192K1,
+	/* ECCurve_SECG_PRIME_192R1 == ECCurve_NIST_P192 */
+	ECCurve_SECG_PRIME_224K1,
+	/* ECCurve_SECG_PRIME_224R1 == ECCurve_NIST_P224 */
+	ECCurve_SECG_PRIME_256K1,
+	/* ECCurve_SECG_PRIME_256R1 == ECCurve_NIST_P256 */
+	/* ECCurve_SECG_PRIME_384R1 == ECCurve_NIST_P384 */
+	/* ECCurve_SECG_PRIME_521R1 == ECCurve_NIST_P521 */
+
+	/* SEC2 binary curves */
+	ECCurve_SECG_CHAR2_113R1,
+	ECCurve_SECG_CHAR2_113R2,
+	ECCurve_SECG_CHAR2_131R1,
+	ECCurve_SECG_CHAR2_131R2,
+	/* ECCurve_SECG_CHAR2_163K1 == ECCurve_NIST_K163 */
+	ECCurve_SECG_CHAR2_163R1,
+	/* ECCurve_SECG_CHAR2_163R2 == ECCurve_NIST_B163 */
+	ECCurve_SECG_CHAR2_193R1,
+	ECCurve_SECG_CHAR2_193R2,
+	/* ECCurve_SECG_CHAR2_233K1 == ECCurve_NIST_K233 */
+	/* ECCurve_SECG_CHAR2_233R1 == ECCurve_NIST_B233 */
+	ECCurve_SECG_CHAR2_239K1,
+	/* ECCurve_SECG_CHAR2_283K1 == ECCurve_NIST_K283 */
+	/* ECCurve_SECG_CHAR2_283R1 == ECCurve_NIST_B283 */
+	/* ECCurve_SECG_CHAR2_409K1 == ECCurve_NIST_K409 */
+	/* ECCurve_SECG_CHAR2_409R1 == ECCurve_NIST_B409 */
+	/* ECCurve_SECG_CHAR2_571K1 == ECCurve_NIST_K571 */
+	/* ECCurve_SECG_CHAR2_571R1 == ECCurve_NIST_B571 */
+
+	/* WTLS curves */
+	ECCurve_WTLS_1,
+	/* there is no WTLS 2 curve */
+	/* ECCurve_WTLS_3 == ECCurve_NIST_K163 */
+	/* ECCurve_WTLS_4 == ECCurve_SECG_CHAR2_113R1 */
+	/* ECCurve_WTLS_5 == ECCurve_X9_62_CHAR2_PNB163V1 */
+	/* ECCurve_WTLS_6 == ECCurve_SECG_PRIME_112R1 */
+	/* ECCurve_WTLS_7 == ECCurve_SECG_PRIME_160R1 */
+	ECCurve_WTLS_8,
+	ECCurve_WTLS_9,
+	/* ECCurve_WTLS_10 == ECCurve_NIST_K233 */
+	/* ECCurve_WTLS_11 == ECCurve_NIST_B233 */
+	/* ECCurve_WTLS_12 == ECCurve_NIST_P224 */
+
+	ECCurve_pastLastCurve
+} ECCurveName;
+
+/* Aliased named curves */
+
+#define ECCurve_X9_62_PRIME_192V1 ECCurve_NIST_P192
+#define ECCurve_X9_62_PRIME_256V1 ECCurve_NIST_P256
+#define ECCurve_SECG_PRIME_192R1 ECCurve_NIST_P192
+#define ECCurve_SECG_PRIME_224R1 ECCurve_NIST_P224
+#define ECCurve_SECG_PRIME_256R1 ECCurve_NIST_P256
+#define ECCurve_SECG_PRIME_384R1 ECCurve_NIST_P384
+#define ECCurve_SECG_PRIME_521R1 ECCurve_NIST_P521
+#define ECCurve_SECG_CHAR2_163K1 ECCurve_NIST_K163
+#define ECCurve_SECG_CHAR2_163R2 ECCurve_NIST_B163
+#define ECCurve_SECG_CHAR2_233K1 ECCurve_NIST_K233
+#define ECCurve_SECG_CHAR2_233R1 ECCurve_NIST_B233
+#define ECCurve_SECG_CHAR2_283K1 ECCurve_NIST_K283
+#define ECCurve_SECG_CHAR2_283R1 ECCurve_NIST_B283
+#define ECCurve_SECG_CHAR2_409K1 ECCurve_NIST_K409
+#define ECCurve_SECG_CHAR2_409R1 ECCurve_NIST_B409
+#define ECCurve_SECG_CHAR2_571K1 ECCurve_NIST_K571
+#define ECCurve_SECG_CHAR2_571R1 ECCurve_NIST_B571
+#define ECCurve_WTLS_3 ECCurve_NIST_K163
+#define ECCurve_WTLS_4 ECCurve_SECG_CHAR2_113R1
+#define ECCurve_WTLS_5 ECCurve_X9_62_CHAR2_PNB163V1
+#define ECCurve_WTLS_6 ECCurve_SECG_PRIME_112R1
+#define ECCurve_WTLS_7 ECCurve_SECG_PRIME_160R1
+#define ECCurve_WTLS_10 ECCurve_NIST_K233
+#define ECCurve_WTLS_11 ECCurve_NIST_B233
+#define ECCurve_WTLS_12 ECCurve_NIST_P224
+
+#endif							/* __ecl_exp_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl-priv.h b/mozilla/security/nss/lib/freebl/ecl/ecl-priv.h
new file mode 100644
index 0000000..05abb4d
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl-priv.h
@@ -0,0 +1,281 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stephen Fung <fungstep@hotmail.com> and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifndef __ecl_priv_h_
+#define __ecl_priv_h_
+
+#include "ecl.h"
+#include "mpi.h"
+#include "mplogic.h"
+
+/* MAX_FIELD_SIZE_DIGITS is the maximum size of field element supported */
+/* the following needs to go away... */
+#if defined(MP_USE_LONG_LONG_DIGIT) || defined(MP_USE_LONG_DIGIT)
+#define ECL_SIXTY_FOUR_BIT
+#else
+#define ECL_THIRTY_TWO_BIT
+#endif
+
+#define ECL_CURVE_DIGITS(curve_size_in_bits) \
+	(((curve_size_in_bits)+(sizeof(mp_digit)*8-1))/(sizeof(mp_digit)*8))
+#define ECL_BITS (sizeof(mp_digit)*8)
+#define ECL_MAX_FIELD_SIZE_DIGITS (80/sizeof(mp_digit))
+
+/* Gets the i'th bit in the binary representation of a. If i >= length(a), 
+ * then return 0. (The above behaviour differs from mpl_get_bit, which
+ * causes an error if i >= length(a).) */
+#define MP_GET_BIT(a, i) \
+	((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
+
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+#define MP_ADD_CARRY(a1, a2, s, cin, cout)   \
+    { mp_word w; \
+    w = ((mp_word)(cin)) + (a1) + (a2); \
+    s = ACCUM(w); \
+    cout = CARRYOUT(w); }
+
+#define MP_SUB_BORROW(a1, a2, s, bin, bout)   \
+    { mp_word w; \
+    w = ((mp_word)(a1)) - (a2) - (bin); \
+    s = ACCUM(w); \
+    bout = (w >> MP_DIGIT_BIT) & 1; }
+
+#else
+/* NOTE, 
+ * cin and cout could be the same variable.
+ * bin and bout could be the same variable.
+ * a1 or a2 and s could be the same variable.
+ * don't trash those outputs until their respective inputs have
+ * been read. */
+#define MP_ADD_CARRY(a1, a2, s, cin, cout)   \
+    { mp_digit tmp,sum; \
+    tmp = (a1); \
+    sum = tmp + (a2); \
+    tmp = (sum < tmp);                     /* detect overflow */ \
+    s = sum += (cin); \
+    cout = tmp + (sum < (cin)); }
+
+#define MP_SUB_BORROW(a1, a2, s, bin, bout)   \
+    { mp_digit tmp; \
+    tmp = (a1); \
+    s = tmp - (a2); \
+    tmp = (s > tmp);                    /* detect borrow */ \
+    if ((bin) && !s--) tmp++;	\
+    bout = tmp; }
+#endif
+
+
+struct GFMethodStr;
+typedef struct GFMethodStr GFMethod;
+struct GFMethodStr {
+	/* Indicates whether the structure was constructed from dynamic memory 
+	 * or statically created. */
+	int constructed;
+	/* Irreducible that defines the field. For prime fields, this is the
+	 * prime p. For binary polynomial fields, this is the bitstring
+	 * representation of the irreducible polynomial. */
+	mp_int irr;
+	/* For prime fields, the value irr_arr[0] is the number of bits in the 
+	 * field. For binary polynomial fields, the irreducible polynomial
+	 * f(t) is represented as an array of unsigned int[], where f(t) is
+	 * of the form: f(t) = t^p[0] + t^p[1] + ... + t^p[4] where m = p[0]
+	 * > p[1] > ... > p[4] = 0. */
+	unsigned int irr_arr[5];
+	/* Field arithmetic methods. All methods (except field_enc and
+	 * field_dec) are assumed to take field-encoded parameters and return
+	 * field-encoded values. All methods (except field_enc and field_dec)
+	 * are required to be implemented. */
+	mp_err (*field_add) (const mp_int *a, const mp_int *b, mp_int *r,
+						 const GFMethod *meth);
+	mp_err (*field_neg) (const mp_int *a, mp_int *r, const GFMethod *meth);
+	mp_err (*field_sub) (const mp_int *a, const mp_int *b, mp_int *r,
+						 const GFMethod *meth);
+	mp_err (*field_mod) (const mp_int *a, mp_int *r, const GFMethod *meth);
+	mp_err (*field_mul) (const mp_int *a, const mp_int *b, mp_int *r,
+						 const GFMethod *meth);
+	mp_err (*field_sqr) (const mp_int *a, mp_int *r, const GFMethod *meth);
+	mp_err (*field_div) (const mp_int *a, const mp_int *b, mp_int *r,
+						 const GFMethod *meth);
+	mp_err (*field_enc) (const mp_int *a, mp_int *r, const GFMethod *meth);
+	mp_err (*field_dec) (const mp_int *a, mp_int *r, const GFMethod *meth);
+	/* Extra storage for implementation-specific data.  Any memory
+	 * allocated to these extra fields will be cleared by extra_free. */
+	void *extra1;
+	void *extra2;
+	void (*extra_free) (GFMethod *meth);
+};
+
+/* Construct generic GFMethods. */
+GFMethod *GFMethod_consGFp(const mp_int *irr);
+GFMethod *GFMethod_consGFp_mont(const mp_int *irr);
+GFMethod *GFMethod_consGF2m(const mp_int *irr,
+							const unsigned int irr_arr[5]);
+/* Free the memory allocated (if any) to a GFMethod object. */
+void GFMethod_free(GFMethod *meth);
+
+struct ECGroupStr {
+	/* Indicates whether the structure was constructed from dynamic memory 
+	 * or statically created. */
+	int constructed;
+	/* Field definition and arithmetic. */
+	GFMethod *meth;
+	/* Textual representation of curve name, if any. */
+	char *text;
+	/* Curve parameters, field-encoded. */
+	mp_int curvea, curveb;
+	/* x and y coordinates of the base point, field-encoded. */
+	mp_int genx, geny;
+	/* Order and cofactor of the base point. */
+	mp_int order;
+	int cofactor;
+	/* Point arithmetic methods. All methods are assumed to take
+	 * field-encoded parameters and return field-encoded values. All
+	 * methods (except base_point_mul and points_mul) are required to be
+	 * implemented. */
+	mp_err (*point_add) (const mp_int *px, const mp_int *py,
+						 const mp_int *qx, const mp_int *qy, mp_int *rx,
+						 mp_int *ry, const ECGroup *group);
+	mp_err (*point_sub) (const mp_int *px, const mp_int *py,
+						 const mp_int *qx, const mp_int *qy, mp_int *rx,
+						 mp_int *ry, const ECGroup *group);
+	mp_err (*point_dbl) (const mp_int *px, const mp_int *py, mp_int *rx,
+						 mp_int *ry, const ECGroup *group);
+	mp_err (*point_mul) (const mp_int *n, const mp_int *px,
+						 const mp_int *py, mp_int *rx, mp_int *ry,
+						 const ECGroup *group);
+	mp_err (*base_point_mul) (const mp_int *n, mp_int *rx, mp_int *ry,
+							  const ECGroup *group);
+	mp_err (*points_mul) (const mp_int *k1, const mp_int *k2,
+						  const mp_int *px, const mp_int *py, mp_int *rx,
+						  mp_int *ry, const ECGroup *group);
+	mp_err (*validate_point) (const mp_int *px, const mp_int *py, const ECGroup *group);
+	/* Extra storage for implementation-specific data.  Any memory
+	 * allocated to these extra fields will be cleared by extra_free. */
+	void *extra1;
+	void *extra2;
+	void (*extra_free) (ECGroup *group);
+};
+
+/* Wrapper functions for generic prime field arithmetic. */
+mp_err ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+
+/* fixed length in-line adds. Count is in words */
+mp_err ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+
+mp_err ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+mp_err ec_GFp_sqr(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r,
+				  const GFMethod *meth);
+/* Wrapper functions for generic binary polynomial field arithmetic. */
+mp_err ec_GF2m_add(const mp_int *a, const mp_int *b, mp_int *r,
+				   const GFMethod *meth);
+mp_err ec_GF2m_neg(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GF2m_mod(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GF2m_mul(const mp_int *a, const mp_int *b, mp_int *r,
+				   const GFMethod *meth);
+mp_err ec_GF2m_sqr(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r,
+				   const GFMethod *meth);
+
+/* Montgomery prime field arithmetic. */
+mp_err ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r,
+					   const GFMethod *meth);
+mp_err ec_GFp_sqr_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r,
+					   const GFMethod *meth);
+mp_err ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
+void ec_GFp_extra_free_mont(GFMethod *meth);
+
+/* point multiplication */
+mp_err ec_pts_mul_basic(const mp_int *k1, const mp_int *k2,
+						const mp_int *px, const mp_int *py, mp_int *rx,
+						mp_int *ry, const ECGroup *group);
+mp_err ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2,
+						   const mp_int *px, const mp_int *py, mp_int *rx,
+						   mp_int *ry, const ECGroup *group);
+
+/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
+ * be an array of signed char's to output to, bitsize should be the number 
+ * of bits of out, in is the original scalar, and w is the window size.
+ * NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
+ * Menezes, "Software implementation of elliptic curve cryptography over
+ * binary fields", Proc. CHES 2000. */
+mp_err ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in,
+					   int w);
+
+/* Optimized field arithmetic */
+mp_err ec_group_set_gfp192(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp224(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp256(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp384(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp521(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gf2m163(ECGroup *group, ECCurveName name);
+mp_err ec_group_set_gf2m193(ECGroup *group, ECCurveName name);
+mp_err ec_group_set_gf2m233(ECGroup *group, ECCurveName name);
+
+/* Optimized floating-point arithmetic */
+#ifdef ECL_USE_FP
+mp_err ec_group_set_secp160r1_fp(ECGroup *group);
+mp_err ec_group_set_nistp192_fp(ECGroup *group);
+mp_err ec_group_set_nistp224_fp(ECGroup *group);
+#endif
+
+#endif							/* __ecl_priv_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl.c b/mozilla/security/nss/lib/freebl/ecl/ecl.c
new file mode 100644
index 0000000..84080df
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl.c
@@ -0,0 +1,429 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 "mpi.h"
+#include "mplogic.h"
+#include "ecl.h"
+#include "ecl-priv.h"
+#include "ec2.h"
+#include "ecp.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Allocate memory for a new ECGroup object. */
+ECGroup *
+ECGroup_new()
+{
+	mp_err res = MP_OKAY;
+	ECGroup *group;
+	group = (ECGroup *) malloc(sizeof(ECGroup));
+	if (group == NULL)
+		return NULL;
+	group->constructed = MP_YES;
+        group->meth = NULL;
+	group->text = NULL;
+	MP_DIGITS(&group->curvea) = 0;
+	MP_DIGITS(&group->curveb) = 0;
+	MP_DIGITS(&group->genx) = 0;
+	MP_DIGITS(&group->geny) = 0;
+	MP_DIGITS(&group->order) = 0;
+	group->base_point_mul = NULL;
+	group->points_mul = NULL;
+	group->validate_point = NULL;
+	group->extra1 = NULL;
+	group->extra2 = NULL;
+	group->extra_free = NULL;
+	MP_CHECKOK(mp_init(&group->curvea));
+	MP_CHECKOK(mp_init(&group->curveb));
+	MP_CHECKOK(mp_init(&group->genx));
+	MP_CHECKOK(mp_init(&group->geny));
+	MP_CHECKOK(mp_init(&group->order));
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		ECGroup_free(group);
+		return NULL;
+	}
+	return group;
+}
+
+/* Construct a generic ECGroup for elliptic curves over prime fields. */
+ECGroup *
+ECGroup_consGFp(const mp_int *irr, const mp_int *curvea,
+				const mp_int *curveb, const mp_int *genx,
+				const mp_int *geny, const mp_int *order, int cofactor)
+{
+	mp_err res = MP_OKAY;
+	ECGroup *group = NULL;
+
+	group = ECGroup_new();
+	if (group == NULL)
+		return NULL;
+
+	group->meth = GFMethod_consGFp(irr);
+	if (group->meth == NULL) {
+		res = MP_MEM;
+		goto CLEANUP;
+	}
+	MP_CHECKOK(mp_copy(curvea, &group->curvea));
+	MP_CHECKOK(mp_copy(curveb, &group->curveb));
+	MP_CHECKOK(mp_copy(genx, &group->genx));
+	MP_CHECKOK(mp_copy(geny, &group->geny));
+	MP_CHECKOK(mp_copy(order, &group->order));
+	group->cofactor = cofactor;
+	group->point_add = &ec_GFp_pt_add_aff;
+	group->point_sub = &ec_GFp_pt_sub_aff;
+	group->point_dbl = &ec_GFp_pt_dbl_aff;
+	group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
+	group->base_point_mul = NULL;
+	group->points_mul = &ec_GFp_pts_mul_jac;
+	group->validate_point = &ec_GFp_validate_point;
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		ECGroup_free(group);
+		return NULL;
+	}
+	return group;
+}
+
+/* Construct a generic ECGroup for elliptic curves over prime fields with
+ * field arithmetic implemented in Montgomery coordinates. */
+ECGroup *
+ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea,
+					 const mp_int *curveb, const mp_int *genx,
+					 const mp_int *geny, const mp_int *order, int cofactor)
+{
+	mp_err res = MP_OKAY;
+	ECGroup *group = NULL;
+
+	group = ECGroup_new();
+	if (group == NULL)
+		return NULL;
+
+	group->meth = GFMethod_consGFp_mont(irr);
+	if (group->meth == NULL) {
+		res = MP_MEM;
+		goto CLEANUP;
+	}
+	MP_CHECKOK(group->meth->
+			   field_enc(curvea, &group->curvea, group->meth));
+	MP_CHECKOK(group->meth->
+			   field_enc(curveb, &group->curveb, group->meth));
+	MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth));
+	MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth));
+	MP_CHECKOK(mp_copy(order, &group->order));
+	group->cofactor = cofactor;
+	group->point_add = &ec_GFp_pt_add_aff;
+	group->point_sub = &ec_GFp_pt_sub_aff;
+	group->point_dbl = &ec_GFp_pt_dbl_aff;
+	group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
+	group->base_point_mul = NULL;
+	group->points_mul = &ec_GFp_pts_mul_jac;
+	group->validate_point = &ec_GFp_validate_point;
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		ECGroup_free(group);
+		return NULL;
+	}
+	return group;
+}
+
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+/* Construct a generic ECGroup for elliptic curves over binary polynomial
+ * fields. */
+ECGroup *
+ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5],
+				 const mp_int *curvea, const mp_int *curveb,
+				 const mp_int *genx, const mp_int *geny,
+				 const mp_int *order, int cofactor)
+{
+	mp_err res = MP_OKAY;
+	ECGroup *group = NULL;
+
+	group = ECGroup_new();
+	if (group == NULL)
+		return NULL;
+
+	group->meth = GFMethod_consGF2m(irr, irr_arr);
+	if (group->meth == NULL) {
+		res = MP_MEM;
+		goto CLEANUP;
+	}
+	MP_CHECKOK(mp_copy(curvea, &group->curvea));
+	MP_CHECKOK(mp_copy(curveb, &group->curveb));
+	MP_CHECKOK(mp_copy(genx, &group->genx));
+	MP_CHECKOK(mp_copy(geny, &group->geny));
+	MP_CHECKOK(mp_copy(order, &group->order));
+	group->cofactor = cofactor;
+	group->point_add = &ec_GF2m_pt_add_aff;
+	group->point_sub = &ec_GF2m_pt_sub_aff;
+	group->point_dbl = &ec_GF2m_pt_dbl_aff;
+	group->point_mul = &ec_GF2m_pt_mul_mont;
+	group->base_point_mul = NULL;
+	group->points_mul = &ec_pts_mul_basic;
+	group->validate_point = &ec_GF2m_validate_point;
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		ECGroup_free(group);
+		return NULL;
+	}
+	return group;
+}
+#endif
+
+/* Construct ECGroup from hex parameters and name, if any. Called by
+ * ECGroup_fromHex and ECGroup_fromName. */
+ECGroup *
+ecgroup_fromNameAndHex(const ECCurveName name,
+					   const ECCurveParams * params)
+{
+	mp_int irr, curvea, curveb, genx, geny, order;
+	int bits;
+	ECGroup *group = NULL;
+	mp_err res = MP_OKAY;
+
+	/* initialize values */
+	MP_DIGITS(&irr) = 0;
+	MP_DIGITS(&curvea) = 0;
+	MP_DIGITS(&curveb) = 0;
+	MP_DIGITS(&genx) = 0;
+	MP_DIGITS(&geny) = 0;
+	MP_DIGITS(&order) = 0;
+	MP_CHECKOK(mp_init(&irr));
+	MP_CHECKOK(mp_init(&curvea));
+	MP_CHECKOK(mp_init(&curveb));
+	MP_CHECKOK(mp_init(&genx));
+	MP_CHECKOK(mp_init(&geny));
+	MP_CHECKOK(mp_init(&order));
+	MP_CHECKOK(mp_read_radix(&irr, params->irr, 16));
+	MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16));
+	MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16));
+	MP_CHECKOK(mp_read_radix(&genx, params->genx, 16));
+	MP_CHECKOK(mp_read_radix(&geny, params->geny, 16));
+	MP_CHECKOK(mp_read_radix(&order, params->order, 16));
+
+	/* determine number of bits */
+	bits = mpl_significant_bits(&irr) - 1;
+	if (bits < MP_OKAY) {
+		res = bits;
+		goto CLEANUP;
+	}
+
+	/* determine which optimizations (if any) to use */
+	if (params->field == ECField_GFp) {
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+	    switch (name) {
+#ifdef ECL_USE_FP
+		case ECCurve_SECG_PRIME_160R1:
+			group =
+				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+								&order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+			MP_CHECKOK(ec_group_set_secp160r1_fp(group));
+			break;
+#endif
+		case ECCurve_SECG_PRIME_192R1:
+#ifdef ECL_USE_FP
+			group =
+				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+								&order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+			MP_CHECKOK(ec_group_set_nistp192_fp(group));
+#else
+			group =
+				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+								&order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+			MP_CHECKOK(ec_group_set_gfp192(group, name));
+#endif
+			break;
+		case ECCurve_SECG_PRIME_224R1:
+#ifdef ECL_USE_FP
+			group =
+				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+								&order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+			MP_CHECKOK(ec_group_set_nistp224_fp(group));
+#else
+			group =
+				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+								&order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+			MP_CHECKOK(ec_group_set_gfp224(group, name));
+#endif
+			break;
+		case ECCurve_SECG_PRIME_256R1:
+			group =
+				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+								&order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+			MP_CHECKOK(ec_group_set_gfp256(group, name));
+			break;
+		case ECCurve_SECG_PRIME_521R1:
+			group =
+				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+								&order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+			MP_CHECKOK(ec_group_set_gfp521(group, name));
+			break;
+		default:
+			/* use generic arithmetic */
+#endif
+			group =
+				ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny,
+									 &order, params->cofactor);
+			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+		}
+	} else if (params->field == ECField_GF2m) {
+		group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor);
+		if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+		if ((name == ECCurve_NIST_K163) ||
+		    (name == ECCurve_NIST_B163) ||
+		    (name == ECCurve_SECG_CHAR2_163R1)) {
+			MP_CHECKOK(ec_group_set_gf2m163(group, name));
+		} else if ((name == ECCurve_SECG_CHAR2_193R1) ||
+		           (name == ECCurve_SECG_CHAR2_193R2)) {
+			MP_CHECKOK(ec_group_set_gf2m193(group, name));
+		} else if ((name == ECCurve_NIST_K233) ||
+		           (name == ECCurve_NIST_B233)) {
+			MP_CHECKOK(ec_group_set_gf2m233(group, name));
+		}
+#endif
+	} else {
+		res = MP_UNDEF;
+		goto CLEANUP;
+	}
+
+	/* set name, if any */
+	if ((group != NULL) && (params->text != NULL)) {
+		group->text = strdup(params->text);
+		if (group->text == NULL) {
+			res = MP_MEM;
+		}
+	}
+
+  CLEANUP:
+	mp_clear(&irr);
+	mp_clear(&curvea);
+	mp_clear(&curveb);
+	mp_clear(&genx);
+	mp_clear(&geny);
+	mp_clear(&order);
+	if (res != MP_OKAY) {
+		ECGroup_free(group);
+		return NULL;
+	}
+	return group;
+}
+
+/* Construct ECGroup from hexadecimal representations of parameters. */
+ECGroup *
+ECGroup_fromHex(const ECCurveParams * params)
+{
+	return ecgroup_fromNameAndHex(ECCurve_noName, params);
+}
+
+/* Construct ECGroup from named parameters. */
+ECGroup *
+ECGroup_fromName(const ECCurveName name)
+{
+	ECGroup *group = NULL;
+	ECCurveParams *params = NULL;
+	mp_err res = MP_OKAY;
+
+	params = EC_GetNamedCurveParams(name);
+	if (params == NULL) {
+		res = MP_UNDEF;
+		goto CLEANUP;
+	}
+
+	/* construct actual group */
+	group = ecgroup_fromNameAndHex(name, params);
+	if (group == NULL) {
+		res = MP_UNDEF;
+		goto CLEANUP;
+	}
+
+  CLEANUP:
+	EC_FreeCurveParams(params);
+	if (res != MP_OKAY) {
+		ECGroup_free(group);
+		return NULL;
+	}
+	return group;
+}
+
+/* Validates an EC public key as described in Section 5.2.2 of X9.62. */
+mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const 
+					mp_int *py)
+{
+    /* 1: Verify that publicValue is not the point at infinity */
+    /* 2: Verify that the coordinates of publicValue are elements 
+     *    of the field.
+     */
+    /* 3: Verify that publicValue is on the curve. */
+    /* 4: Verify that the order of the curve times the publicValue
+     *    is the point at infinity.
+     */
+	return group->validate_point(px, py, group);
+}
+
+/* Free the memory allocated (if any) to an ECGroup object. */
+void
+ECGroup_free(ECGroup *group)
+{
+	if (group == NULL)
+		return;
+	GFMethod_free(group->meth);
+	if (group->constructed == MP_NO)
+		return;
+	mp_clear(&group->curvea);
+	mp_clear(&group->curveb);
+	mp_clear(&group->genx);
+	mp_clear(&group->geny);
+	mp_clear(&group->order);
+	if (group->text != NULL)
+		free(group->text);
+	if (group->extra_free != NULL)
+		group->extra_free(group);
+	free(group);
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl.h b/mozilla/security/nss/lib/freebl/ecl/ecl.h
new file mode 100644
index 0000000..dbd86c2
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl.h
@@ -0,0 +1,91 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+/* Although this is not an exported header file, code which uses elliptic
+ * curve point operations will need to include it. */
+
+#ifndef __ecl_h_
+#define __ecl_h_
+
+#include "ecl-exp.h"
+#include "mpi.h"
+
+struct ECGroupStr;
+typedef struct ECGroupStr ECGroup;
+
+/* Construct ECGroup from hexadecimal representations of parameters. */
+ECGroup *ECGroup_fromHex(const ECCurveParams * params);
+
+/* Construct ECGroup from named parameters. */
+ECGroup *ECGroup_fromName(const ECCurveName name);
+
+/* Free an allocated ECGroup. */
+void ECGroup_free(ECGroup *group);
+
+/* Construct ECCurveParams from an ECCurveName */
+ECCurveParams *EC_GetNamedCurveParams(const ECCurveName name);
+
+/* Duplicates an ECCurveParams */
+ECCurveParams *ECCurveParams_dup(const ECCurveParams * params);
+
+/* Free an allocated ECCurveParams */
+void EC_FreeCurveParams(ECCurveParams * params);
+
+/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k * P(x, 
+ * y).  If x, y = NULL, then P is assumed to be the generator (base point) 
+ * of the group of points on the elliptic curve. Input and output values
+ * are assumed to be NOT field-encoded. */
+mp_err ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
+				   const mp_int *py, mp_int *qx, mp_int *qy);
+
+/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k1 * G + 
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Input and output values are assumed to
+ * be NOT field-encoded. */
+mp_err ECPoints_mul(const ECGroup *group, const mp_int *k1,
+					const mp_int *k2, const mp_int *px, const mp_int *py,
+					mp_int *qx, mp_int *qy);
+
+/* Validates an EC public key as described in Section 5.2.2 of X9.62.
+ * Returns MP_YES if the public key is valid, MP_NO if the public key
+ * is invalid, or an error code if the validation could not be
+ * performed. */
+mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const 
+					mp_int *py);
+
+#endif							/* __ecl_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl_curve.c b/mozilla/security/nss/lib/freebl/ecl/ecl_curve.c
new file mode 100644
index 0000000..a0a7bd3
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl_curve.c
@@ -0,0 +1,123 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 "ecl.h"
+#include "ecl-curve.h"
+#include "ecl-priv.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK(func) if ((func) == NULL) { res = 0; goto CLEANUP; }
+
+/* Duplicates an ECCurveParams */
+ECCurveParams *
+ECCurveParams_dup(const ECCurveParams * params)
+{
+	int res = 1;
+	ECCurveParams *ret = NULL;
+
+	CHECK(ret = (ECCurveParams *) calloc(1, sizeof(ECCurveParams)));
+	if (params->text != NULL) {
+		CHECK(ret->text = strdup(params->text));
+	}
+	ret->field = params->field;
+	ret->size = params->size;
+	if (params->irr != NULL) {
+		CHECK(ret->irr = strdup(params->irr));
+	}
+	if (params->curvea != NULL) {
+		CHECK(ret->curvea = strdup(params->curvea));
+	}
+	if (params->curveb != NULL) {
+		CHECK(ret->curveb = strdup(params->curveb));
+	}
+	if (params->genx != NULL) {
+		CHECK(ret->genx = strdup(params->genx));
+	}
+	if (params->geny != NULL) {
+		CHECK(ret->geny = strdup(params->geny));
+	}
+	if (params->order != NULL) {
+		CHECK(ret->order = strdup(params->order));
+	}
+	ret->cofactor = params->cofactor;
+
+  CLEANUP:
+	if (res != 1) {
+		EC_FreeCurveParams(ret);
+		return NULL;
+	}
+	return ret;
+}
+
+#undef CHECK
+
+/* Construct ECCurveParams from an ECCurveName */
+ECCurveParams *
+EC_GetNamedCurveParams(const ECCurveName name)
+{
+	if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name) ||
+					(ecCurve_map[name] == NULL)) {
+		return NULL;
+	} else {
+		return ECCurveParams_dup(ecCurve_map[name]);
+	}
+}
+
+/* Free the memory allocated (if any) to an ECCurveParams object. */
+void
+EC_FreeCurveParams(ECCurveParams * params)
+{
+	if (params == NULL)
+		return;
+	if (params->text != NULL)
+		free(params->text);
+	if (params->irr != NULL)
+		free(params->irr);
+	if (params->curvea != NULL)
+		free(params->curvea);
+	if (params->curveb != NULL)
+		free(params->curveb);
+	if (params->genx != NULL)
+		free(params->genx);
+	if (params->geny != NULL)
+		free(params->geny);
+	if (params->order != NULL)
+		free(params->order);
+	free(params);
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl_gf.c b/mozilla/security/nss/lib/freebl/ecl/ecl_gf.c
new file mode 100644
index 0000000..08fa0c3
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl_gf.c
@@ -0,0 +1,1032 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stephen Fung <fungstep@hotmail.com> and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 "mpi.h"
+#include "mp_gf2m.h"
+#include "ecl-priv.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+/* Allocate memory for a new GFMethod object. */
+GFMethod *
+GFMethod_new()
+{
+	mp_err res = MP_OKAY;
+	GFMethod *meth;
+	meth = (GFMethod *) malloc(sizeof(GFMethod));
+	if (meth == NULL)
+		return NULL;
+	meth->constructed = MP_YES;
+	MP_DIGITS(&meth->irr) = 0;
+	meth->extra_free = NULL;
+	MP_CHECKOK(mp_init(&meth->irr));
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		GFMethod_free(meth);
+		return NULL;
+	}
+	return meth;
+}
+
+/* Construct a generic GFMethod for arithmetic over prime fields with
+ * irreducible irr. */
+GFMethod *
+GFMethod_consGFp(const mp_int *irr)
+{
+	mp_err res = MP_OKAY;
+	GFMethod *meth = NULL;
+
+	meth = GFMethod_new();
+	if (meth == NULL)
+		return NULL;
+
+	MP_CHECKOK(mp_copy(irr, &meth->irr));
+	meth->irr_arr[0] = mpl_significant_bits(irr);
+	meth->irr_arr[1] = meth->irr_arr[2] = meth->irr_arr[3] =
+		meth->irr_arr[4] = 0;
+	switch(MP_USED(&meth->irr)) {
+	/* maybe we need 1 and 2 words here as well?*/
+	case 3:
+		meth->field_add = &ec_GFp_add_3;
+		meth->field_sub = &ec_GFp_sub_3;
+		break;
+	case 4:
+		meth->field_add = &ec_GFp_add_4;
+		meth->field_sub = &ec_GFp_sub_4;
+		break;
+	case 5:
+		meth->field_add = &ec_GFp_add_5;
+		meth->field_sub = &ec_GFp_sub_5;
+		break;
+	case 6:
+		meth->field_add = &ec_GFp_add_6;
+		meth->field_sub = &ec_GFp_sub_6;
+		break;
+	default:
+		meth->field_add = &ec_GFp_add;
+		meth->field_sub = &ec_GFp_sub;
+	}
+	meth->field_neg = &ec_GFp_neg;
+	meth->field_mod = &ec_GFp_mod;
+	meth->field_mul = &ec_GFp_mul;
+	meth->field_sqr = &ec_GFp_sqr;
+	meth->field_div = &ec_GFp_div;
+	meth->field_enc = NULL;
+	meth->field_dec = NULL;
+	meth->extra1 = NULL;
+	meth->extra2 = NULL;
+	meth->extra_free = NULL;
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		GFMethod_free(meth);
+		return NULL;
+	}
+	return meth;
+}
+
+/* Construct a generic GFMethod for arithmetic over binary polynomial
+ * fields with irreducible irr that has array representation irr_arr (see
+ * ecl-priv.h for description of the representation).  If irr_arr is NULL, 
+ * then it is constructed from the bitstring representation. */
+GFMethod *
+GFMethod_consGF2m(const mp_int *irr, const unsigned int irr_arr[5])
+{
+	mp_err res = MP_OKAY;
+	int ret;
+	GFMethod *meth = NULL;
+
+	meth = GFMethod_new();
+	if (meth == NULL)
+		return NULL;
+
+	MP_CHECKOK(mp_copy(irr, &meth->irr));
+	if (irr_arr != NULL) {
+		/* Irreducible polynomials are either trinomials or pentanomials. */
+		meth->irr_arr[0] = irr_arr[0];
+		meth->irr_arr[1] = irr_arr[1];
+		meth->irr_arr[2] = irr_arr[2];
+		if (irr_arr[2] > 0) {
+			meth->irr_arr[3] = irr_arr[3];
+			meth->irr_arr[4] = irr_arr[4];
+		} else {
+			meth->irr_arr[3] = meth->irr_arr[4] = 0;
+		}
+	} else {
+		ret = mp_bpoly2arr(irr, meth->irr_arr, 5);
+		/* Irreducible polynomials are either trinomials or pentanomials. */
+		if ((ret != 5) && (ret != 3)) {
+			res = MP_UNDEF;
+			goto CLEANUP;
+		}
+	}
+	meth->field_add = &ec_GF2m_add;
+	meth->field_neg = &ec_GF2m_neg;
+	meth->field_sub = &ec_GF2m_add;
+	meth->field_mod = &ec_GF2m_mod;
+	meth->field_mul = &ec_GF2m_mul;
+	meth->field_sqr = &ec_GF2m_sqr;
+	meth->field_div = &ec_GF2m_div;
+	meth->field_enc = NULL;
+	meth->field_dec = NULL;
+	meth->extra1 = NULL;
+	meth->extra2 = NULL;
+	meth->extra_free = NULL;
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		GFMethod_free(meth);
+		return NULL;
+	}
+	return meth;
+}
+
+/* Free the memory allocated (if any) to a GFMethod object. */
+void
+GFMethod_free(GFMethod *meth)
+{
+	if (meth == NULL)
+		return;
+	if (meth->constructed == MP_NO)
+		return;
+	mp_clear(&meth->irr);
+	if (meth->extra_free != NULL)
+		meth->extra_free(meth);
+	free(meth);
+}
+
+/* Wrapper functions for generic prime field arithmetic. */
+
+/* Add two field elements.  Assumes that 0 <= a, b < meth->irr */
+mp_err
+ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r,
+		   const GFMethod *meth)
+{
+	/* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a + b (mod p) */
+	mp_err res;
+
+	if ((res = mp_add(a, b, r)) != MP_OKAY) {
+		return res;
+	}
+	if (mp_cmp(r, &meth->irr) >= 0) {
+		return mp_sub(r, &meth->irr, r);
+	}
+	return res;
+}
+
+/* Negates a field element.  Assumes that 0 <= a < meth->irr */
+mp_err
+ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	/* PRE: 0 <= a < p = meth->irr POST: 0 <= r < p, r = -a (mod p) */
+
+	if (mp_cmp_z(a) == 0) {
+		mp_zero(r);
+		return MP_OKAY;
+	}
+	return mp_sub(&meth->irr, a, r);
+}
+
+/* Subtracts two field elements.  Assumes that 0 <= a, b < meth->irr */
+mp_err
+ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r,
+		   const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+
+	/* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a - b (mod p) */
+	res = mp_sub(a, b, r);
+	if (res == MP_RANGE) {
+		MP_CHECKOK(mp_sub(b, a, r));
+		if (mp_cmp_z(r) < 0) {
+			MP_CHECKOK(mp_add(r, &meth->irr, r));
+		}
+		MP_CHECKOK(ec_GFp_neg(r, r, meth));
+	}
+	if (mp_cmp_z(r) < 0) {
+		MP_CHECKOK(mp_add(r, &meth->irr, r));
+	}
+  CLEANUP:
+	return res;
+}
+/* 
+ * Inline adds for small curve lengths.
+ */
+/* 3 words */
+mp_err
+ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit a0 = 0, a1 = 0, a2 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0;
+	mp_digit carry;
+
+	switch(MP_USED(a)) {
+	case 3:
+		a2 = MP_DIGIT(a,2);
+	case 2:
+		a1 = MP_DIGIT(a,1);
+	case 1:
+		a0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 3:
+		r2 = MP_DIGIT(b,2);
+	case 2:
+		r1 = MP_DIGIT(b,1);
+	case 1:
+		r0 = MP_DIGIT(b,0);
+	}
+
+#ifndef MPI_AMD64_ADD
+	MP_ADD_CARRY(a0, r0, r0, 0,     carry);
+	MP_ADD_CARRY(a1, r1, r1, carry, carry);
+	MP_ADD_CARRY(a2, r2, r2, carry, carry);
+#else
+	__asm__ (
+                "xorq   %3,%3           \n\t"
+                "addq   %4,%0           \n\t"
+                "adcq   %5,%1           \n\t"
+                "adcq   %6,%2           \n\t"
+                "adcq   $0,%3           \n\t"
+                : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry)
+                : "r" (a0), "r" (a1), "r" (a2),
+		  "0" (r0), "1" (r1), "2" (r2)
+                : "%cc" );
+#endif
+
+	MP_CHECKOK(s_mp_pad(r, 3));
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 3;
+
+	/* Do quick 'subract' if we've gone over 
+	 * (add the 2's complement of the curve field) */
+	 a2 = MP_DIGIT(&meth->irr,2);
+	if (carry ||  r2 >  a2 ||
+		((r2 == a2) && mp_cmp(r,&meth->irr) != MP_LT)) {
+		a1 = MP_DIGIT(&meth->irr,1);
+		a0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+		MP_SUB_BORROW(r0, a0, r0, 0,     carry);
+		MP_SUB_BORROW(r1, a1, r1, carry, carry);
+		MP_SUB_BORROW(r2, a2, r2, carry, carry);
+#else
+		__asm__ (
+			"subq   %3,%0           \n\t"
+			"sbbq   %4,%1           \n\t"
+			"sbbq   %5,%2           \n\t"
+			: "=r"(r0), "=r"(r1), "=r"(r2)
+			: "r" (a0), "r" (a1), "r" (a2),
+			  "0" (r0), "1" (r1), "2" (r2)
+			: "%cc" );
+#endif
+		MP_DIGIT(r, 2) = r2;
+		MP_DIGIT(r, 1) = r1;
+		MP_DIGIT(r, 0) = r0;
+	}
+	
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+/* 4 words */
+mp_err
+ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0;
+	mp_digit carry;
+
+	switch(MP_USED(a)) {
+	case 4:
+		a3 = MP_DIGIT(a,3);
+	case 3:
+		a2 = MP_DIGIT(a,2);
+	case 2:
+		a1 = MP_DIGIT(a,1);
+	case 1:
+		a0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 4:
+		r3 = MP_DIGIT(b,3);
+	case 3:
+		r2 = MP_DIGIT(b,2);
+	case 2:
+		r1 = MP_DIGIT(b,1);
+	case 1:
+		r0 = MP_DIGIT(b,0);
+	}
+
+#ifndef MPI_AMD64_ADD
+	MP_ADD_CARRY(a0, r0, r0, 0,     carry);
+	MP_ADD_CARRY(a1, r1, r1, carry, carry);
+	MP_ADD_CARRY(a2, r2, r2, carry, carry);
+	MP_ADD_CARRY(a3, r3, r3, carry, carry);
+#else
+	__asm__ (
+                "xorq   %4,%4           \n\t"
+                "addq   %5,%0           \n\t"
+                "adcq   %6,%1           \n\t"
+                "adcq   %7,%2           \n\t"
+                "adcq   %8,%3           \n\t"
+                "adcq   $0,%4           \n\t"
+                : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(carry)
+                : "r" (a0), "r" (a1), "r" (a2), "r" (a3),
+		  "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+                : "%cc" );
+#endif
+
+	MP_CHECKOK(s_mp_pad(r, 4));
+	MP_DIGIT(r, 3) = r3;
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 4;
+
+	/* Do quick 'subract' if we've gone over 
+	 * (add the 2's complement of the curve field) */
+	 a3 = MP_DIGIT(&meth->irr,3);
+	if (carry ||  r3 >  a3 ||
+		((r3 == a3) && mp_cmp(r,&meth->irr) != MP_LT)) {
+		a2 = MP_DIGIT(&meth->irr,2);
+		a1 = MP_DIGIT(&meth->irr,1);
+		a0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+		MP_SUB_BORROW(r0, a0, r0, 0,     carry);
+		MP_SUB_BORROW(r1, a1, r1, carry, carry);
+		MP_SUB_BORROW(r2, a2, r2, carry, carry);
+		MP_SUB_BORROW(r3, a3, r3, carry, carry);
+#else
+		__asm__ (
+			"subq   %4,%0           \n\t"
+			"sbbq   %5,%1           \n\t"
+			"sbbq   %6,%2           \n\t"
+			"sbbq   %7,%3           \n\t"
+			: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3)
+			: "r" (a0), "r" (a1), "r" (a2), "r" (a3),
+			  "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+			: "%cc" );
+#endif
+		MP_DIGIT(r, 3) = r3;
+		MP_DIGIT(r, 2) = r2;
+		MP_DIGIT(r, 1) = r1;
+		MP_DIGIT(r, 0) = r0;
+	}
+	
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+/* 5 words */
+mp_err
+ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0;
+	mp_digit carry;
+
+	switch(MP_USED(a)) {
+	case 5:
+		a4 = MP_DIGIT(a,4);
+	case 4:
+		a3 = MP_DIGIT(a,3);
+	case 3:
+		a2 = MP_DIGIT(a,2);
+	case 2:
+		a1 = MP_DIGIT(a,1);
+	case 1:
+		a0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 5:
+		r4 = MP_DIGIT(b,4);
+	case 4:
+		r3 = MP_DIGIT(b,3);
+	case 3:
+		r2 = MP_DIGIT(b,2);
+	case 2:
+		r1 = MP_DIGIT(b,1);
+	case 1:
+		r0 = MP_DIGIT(b,0);
+	}
+
+	MP_ADD_CARRY(a0, r0, r0, 0,     carry);
+	MP_ADD_CARRY(a1, r1, r1, carry, carry);
+	MP_ADD_CARRY(a2, r2, r2, carry, carry);
+	MP_ADD_CARRY(a3, r3, r3, carry, carry);
+	MP_ADD_CARRY(a4, r4, r4, carry, carry);
+
+	MP_CHECKOK(s_mp_pad(r, 5));
+	MP_DIGIT(r, 4) = r4;
+	MP_DIGIT(r, 3) = r3;
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 5;
+
+	/* Do quick 'subract' if we've gone over 
+	 * (add the 2's complement of the curve field) */
+	 a4 = MP_DIGIT(&meth->irr,4);
+	if (carry ||  r4 >  a4 ||
+		((r4 == a4) && mp_cmp(r,&meth->irr) != MP_LT)) {
+		a3 = MP_DIGIT(&meth->irr,3);
+		a2 = MP_DIGIT(&meth->irr,2);
+		a1 = MP_DIGIT(&meth->irr,1);
+		a0 = MP_DIGIT(&meth->irr,0);
+		MP_SUB_BORROW(r0, a0, r0, 0,     carry);
+		MP_SUB_BORROW(r1, a1, r1, carry, carry);
+		MP_SUB_BORROW(r2, a2, r2, carry, carry);
+		MP_SUB_BORROW(r3, a3, r3, carry, carry);
+		MP_SUB_BORROW(r4, a4, r4, carry, carry);
+		MP_DIGIT(r, 4) = r4;
+		MP_DIGIT(r, 3) = r3;
+		MP_DIGIT(r, 2) = r2;
+		MP_DIGIT(r, 1) = r1;
+		MP_DIGIT(r, 0) = r0;
+	}
+	
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+/* 6 words */
+mp_err
+ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0;
+	mp_digit carry;
+
+	switch(MP_USED(a)) {
+	case 6:
+		a5 = MP_DIGIT(a,5);
+	case 5:
+		a4 = MP_DIGIT(a,4);
+	case 4:
+		a3 = MP_DIGIT(a,3);
+	case 3:
+		a2 = MP_DIGIT(a,2);
+	case 2:
+		a1 = MP_DIGIT(a,1);
+	case 1:
+		a0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 6:
+		r5 = MP_DIGIT(b,5);
+	case 5:
+		r4 = MP_DIGIT(b,4);
+	case 4:
+		r3 = MP_DIGIT(b,3);
+	case 3:
+		r2 = MP_DIGIT(b,2);
+	case 2:
+		r1 = MP_DIGIT(b,1);
+	case 1:
+		r0 = MP_DIGIT(b,0);
+	}
+
+	MP_ADD_CARRY(a0, r0, r0, 0,     carry);
+	MP_ADD_CARRY(a1, r1, r1, carry, carry);
+	MP_ADD_CARRY(a2, r2, r2, carry, carry);
+	MP_ADD_CARRY(a3, r3, r3, carry, carry);
+	MP_ADD_CARRY(a4, r4, r4, carry, carry);
+	MP_ADD_CARRY(a5, r5, r5, carry, carry);
+
+	MP_CHECKOK(s_mp_pad(r, 6));
+	MP_DIGIT(r, 5) = r5;
+	MP_DIGIT(r, 4) = r4;
+	MP_DIGIT(r, 3) = r3;
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 6;
+
+	/* Do quick 'subract' if we've gone over 
+	 * (add the 2's complement of the curve field) */
+	a5 = MP_DIGIT(&meth->irr,5);
+	if (carry ||  r5 >  a5 ||
+		((r5 == a5) && mp_cmp(r,&meth->irr) != MP_LT)) {
+		a4 = MP_DIGIT(&meth->irr,4);
+		a3 = MP_DIGIT(&meth->irr,3);
+		a2 = MP_DIGIT(&meth->irr,2);
+		a1 = MP_DIGIT(&meth->irr,1);
+		a0 = MP_DIGIT(&meth->irr,0);
+		MP_SUB_BORROW(r0, a0, r0, 0,     carry);
+		MP_SUB_BORROW(r1, a1, r1, carry, carry);
+		MP_SUB_BORROW(r2, a2, r2, carry, carry);
+		MP_SUB_BORROW(r3, a3, r3, carry, carry);
+		MP_SUB_BORROW(r4, a4, r4, carry, carry);
+		MP_SUB_BORROW(r5, a5, r5, carry, carry);
+		MP_DIGIT(r, 5) = r5;
+		MP_DIGIT(r, 4) = r4;
+		MP_DIGIT(r, 3) = r3;
+		MP_DIGIT(r, 2) = r2;
+		MP_DIGIT(r, 1) = r1;
+		MP_DIGIT(r, 0) = r0;
+	}
+	
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+/*
+ * The following subraction functions do in-line subractions based
+ * on our curve size.
+ *
+ * ... 3 words
+ */
+mp_err
+ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit b0 = 0, b1 = 0, b2 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0;
+	mp_digit borrow;
+
+	switch(MP_USED(a)) {
+	case 3:
+		r2 = MP_DIGIT(a,2);
+	case 2:
+		r1 = MP_DIGIT(a,1);
+	case 1:
+		r0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 3:
+		b2 = MP_DIGIT(b,2);
+	case 2:
+		b1 = MP_DIGIT(b,1);
+	case 1:
+		b0 = MP_DIGIT(b,0);
+	}
+
+#ifndef MPI_AMD64_ADD
+	MP_SUB_BORROW(r0, b0, r0, 0,     borrow);
+	MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+	MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+#else
+	__asm__ (
+                "xorq   %3,%3           \n\t"
+                "subq   %4,%0           \n\t"
+                "sbbq   %5,%1           \n\t"
+                "sbbq   %6,%2           \n\t"
+                "adcq   $0,%3           \n\t"
+                : "=r"(r0), "=r"(r1), "=r"(r2), "=r" (borrow)
+                : "r" (b0), "r" (b1), "r" (b2), 
+		  "0" (r0), "1" (r1), "2" (r2)
+                : "%cc" );
+#endif
+
+	/* Do quick 'add' if we've gone under 0
+	 * (subtract the 2's complement of the curve field) */
+	if (borrow) {
+	 	b2 = MP_DIGIT(&meth->irr,2);
+		b1 = MP_DIGIT(&meth->irr,1);
+		b0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+		MP_ADD_CARRY(b0, r0, r0, 0,      borrow);
+		MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+		MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+#else
+		__asm__ (
+			"addq   %3,%0           \n\t"
+			"adcq   %4,%1           \n\t"
+			"adcq   %5,%2           \n\t"
+			: "=r"(r0), "=r"(r1), "=r"(r2)
+			: "r" (b0), "r" (b1), "r" (b2),
+  			  "0" (r0), "1" (r1), "2" (r2)
+			: "%cc" );
+#endif
+	}
+
+#ifdef MPI_AMD64_ADD
+	/* compiler fakeout? */
+	if ((r2 == b0) && (r1 == b0) && (r0 == b0)) { 
+		MP_CHECKOK(s_mp_pad(r, 4));
+	} 
+#endif
+	MP_CHECKOK(s_mp_pad(r, 3));
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 3;
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+/* 4 words */
+mp_err
+ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0;
+	mp_digit borrow;
+
+	switch(MP_USED(a)) {
+	case 4:
+		r3 = MP_DIGIT(a,3);
+	case 3:
+		r2 = MP_DIGIT(a,2);
+	case 2:
+		r1 = MP_DIGIT(a,1);
+	case 1:
+		r0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 4:
+		b3 = MP_DIGIT(b,3);
+	case 3:
+		b2 = MP_DIGIT(b,2);
+	case 2:
+		b1 = MP_DIGIT(b,1);
+	case 1:
+		b0 = MP_DIGIT(b,0);
+	}
+
+#ifndef MPI_AMD64_ADD
+	MP_SUB_BORROW(r0, b0, r0, 0,     borrow);
+	MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+	MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+	MP_SUB_BORROW(r3, b3, r3, borrow, borrow);
+#else
+	__asm__ (
+                "xorq   %4,%4           \n\t"
+                "subq   %5,%0           \n\t"
+                "sbbq   %6,%1           \n\t"
+                "sbbq   %7,%2           \n\t"
+                "sbbq   %8,%3           \n\t"
+                "adcq   $0,%4           \n\t"
+                : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r" (borrow)
+                : "r" (b0), "r" (b1), "r" (b2), "r" (b3),
+		  "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+                : "%cc" );
+#endif
+
+	/* Do quick 'add' if we've gone under 0
+	 * (subtract the 2's complement of the curve field) */
+	if (borrow) {
+	 	b3 = MP_DIGIT(&meth->irr,3);
+	 	b2 = MP_DIGIT(&meth->irr,2);
+		b1 = MP_DIGIT(&meth->irr,1);
+		b0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+		MP_ADD_CARRY(b0, r0, r0, 0,      borrow);
+		MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+		MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+		MP_ADD_CARRY(b3, r3, r3, borrow, borrow);
+#else
+		__asm__ (
+			"addq   %4,%0           \n\t"
+			"adcq   %5,%1           \n\t"
+			"adcq   %6,%2           \n\t"
+			"adcq   %7,%3           \n\t"
+			: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3)
+			: "r" (b0), "r" (b1), "r" (b2), "r" (b3),
+  			  "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+			: "%cc" );
+#endif
+	}
+#ifdef MPI_AMD64_ADD
+	/* compiler fakeout? */
+	if ((r3 == b0) && (r1 == b0) && (r0 == b0)) { 
+		MP_CHECKOK(s_mp_pad(r, 4));
+	} 
+#endif
+	MP_CHECKOK(s_mp_pad(r, 4));
+	MP_DIGIT(r, 3) = r3;
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 4;
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+/* 5 words */
+mp_err
+ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0;
+	mp_digit borrow;
+
+	switch(MP_USED(a)) {
+	case 5:
+		r4 = MP_DIGIT(a,4);
+	case 4:
+		r3 = MP_DIGIT(a,3);
+	case 3:
+		r2 = MP_DIGIT(a,2);
+	case 2:
+		r1 = MP_DIGIT(a,1);
+	case 1:
+		r0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 5:
+		b4 = MP_DIGIT(b,4);
+	case 4:
+		b3 = MP_DIGIT(b,3);
+	case 3:
+		b2 = MP_DIGIT(b,2);
+	case 2:
+		b1 = MP_DIGIT(b,1);
+	case 1:
+		b0 = MP_DIGIT(b,0);
+	}
+
+	MP_SUB_BORROW(r0, b0, r0, 0,     borrow);
+	MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+	MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+	MP_SUB_BORROW(r3, b3, r3, borrow, borrow);
+	MP_SUB_BORROW(r4, b4, r4, borrow, borrow);
+
+	/* Do quick 'add' if we've gone under 0
+	 * (subtract the 2's complement of the curve field) */
+	if (borrow) {
+	 	b4 = MP_DIGIT(&meth->irr,4);
+	 	b3 = MP_DIGIT(&meth->irr,3);
+	 	b2 = MP_DIGIT(&meth->irr,2);
+		b1 = MP_DIGIT(&meth->irr,1);
+		b0 = MP_DIGIT(&meth->irr,0);
+		MP_ADD_CARRY(b0, r0, r0, 0,      borrow);
+		MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+		MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+		MP_ADD_CARRY(b3, r3, r3, borrow, borrow);
+	}
+	MP_CHECKOK(s_mp_pad(r, 5));
+	MP_DIGIT(r, 4) = r4;
+	MP_DIGIT(r, 3) = r3;
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 5;
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+/* 6 words */
+mp_err
+ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r, 
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0;
+	mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0;
+	mp_digit borrow;
+
+	switch(MP_USED(a)) {
+	case 6:
+		r5 = MP_DIGIT(a,5);
+	case 5:
+		r4 = MP_DIGIT(a,4);
+	case 4:
+		r3 = MP_DIGIT(a,3);
+	case 3:
+		r2 = MP_DIGIT(a,2);
+	case 2:
+		r1 = MP_DIGIT(a,1);
+	case 1:
+		r0 = MP_DIGIT(a,0);
+	}
+	switch(MP_USED(b)) {
+	case 6:
+		b5 = MP_DIGIT(b,5);
+	case 5:
+		b4 = MP_DIGIT(b,4);
+	case 4:
+		b3 = MP_DIGIT(b,3);
+	case 3:
+		b2 = MP_DIGIT(b,2);
+	case 2:
+		b1 = MP_DIGIT(b,1);
+	case 1:
+		b0 = MP_DIGIT(b,0);
+	}
+
+	MP_SUB_BORROW(r0, b0, r0, 0,     borrow);
+	MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+	MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+	MP_SUB_BORROW(r3, b3, r3, borrow, borrow);
+	MP_SUB_BORROW(r4, b4, r4, borrow, borrow);
+	MP_SUB_BORROW(r5, b5, r5, borrow, borrow);
+
+	/* Do quick 'add' if we've gone under 0
+	 * (subtract the 2's complement of the curve field) */
+	if (borrow) {
+	 	b5 = MP_DIGIT(&meth->irr,5);
+	 	b4 = MP_DIGIT(&meth->irr,4);
+	 	b3 = MP_DIGIT(&meth->irr,3);
+	 	b2 = MP_DIGIT(&meth->irr,2);
+		b1 = MP_DIGIT(&meth->irr,1);
+		b0 = MP_DIGIT(&meth->irr,0);
+		MP_ADD_CARRY(b0, r0, r0, 0,      borrow);
+		MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+		MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+		MP_ADD_CARRY(b3, r3, r3, borrow, borrow);
+		MP_ADD_CARRY(b4, r4, r4, borrow, borrow);
+	}
+
+	MP_CHECKOK(s_mp_pad(r, 6));
+	MP_DIGIT(r, 5) = r5;
+	MP_DIGIT(r, 4) = r4;
+	MP_DIGIT(r, 3) = r3;
+	MP_DIGIT(r, 2) = r2;
+	MP_DIGIT(r, 1) = r1;
+	MP_DIGIT(r, 0) = r0;
+	MP_SIGN(r) = MP_ZPOS;
+	MP_USED(r) = 6;
+	s_mp_clamp(r);
+
+  CLEANUP:
+	return res;
+}
+
+
+/* Reduces an integer to a field element. */
+mp_err
+ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	return mp_mod(a, &meth->irr, r);
+}
+
+/* Multiplies two field elements. */
+mp_err
+ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r,
+		   const GFMethod *meth)
+{
+	return mp_mulmod(a, b, &meth->irr, r);
+}
+
+/* Squares a field element. */
+mp_err
+ec_GFp_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	return mp_sqrmod(a, &meth->irr, r);
+}
+
+/* Divides two field elements. If a is NULL, then returns the inverse of
+ * b. */
+mp_err
+ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r,
+		   const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_int t;
+
+	/* If a is NULL, then return the inverse of b, otherwise return a/b. */
+	if (a == NULL) {
+		return mp_invmod(b, &meth->irr, r);
+	} else {
+		/* MPI doesn't support divmod, so we implement it using invmod and 
+		 * mulmod. */
+		MP_CHECKOK(mp_init(&t));
+		MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+		MP_CHECKOK(mp_mulmod(a, &t, &meth->irr, r));
+	  CLEANUP:
+		mp_clear(&t);
+		return res;
+	}
+}
+
+/* Wrapper functions for generic binary polynomial field arithmetic. */
+
+/* Adds two field elements. */
+mp_err
+ec_GF2m_add(const mp_int *a, const mp_int *b, mp_int *r,
+			const GFMethod *meth)
+{
+	return mp_badd(a, b, r);
+}
+
+/* Negates a field element. Note that for binary polynomial fields, the
+ * negation of a field element is the field element itself. */
+mp_err
+ec_GF2m_neg(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	if (a == r) {
+		return MP_OKAY;
+	} else {
+		return mp_copy(a, r);
+	}
+}
+
+/* Reduces a binary polynomial to a field element. */
+mp_err
+ec_GF2m_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	return mp_bmod(a, meth->irr_arr, r);
+}
+
+/* Multiplies two field elements. */
+mp_err
+ec_GF2m_mul(const mp_int *a, const mp_int *b, mp_int *r,
+			const GFMethod *meth)
+{
+	return mp_bmulmod(a, b, meth->irr_arr, r);
+}
+
+/* Squares a field element. */
+mp_err
+ec_GF2m_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	return mp_bsqrmod(a, meth->irr_arr, r);
+}
+
+/* Divides two field elements. If a is NULL, then returns the inverse of
+ * b. */
+mp_err
+ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r,
+			const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+	mp_int t;
+
+	/* If a is NULL, then return the inverse of b, otherwise return a/b. */
+	if (a == NULL) {
+		/* The GF(2^m) portion of MPI doesn't support invmod, so we
+		 * compute 1/b. */
+		MP_CHECKOK(mp_init(&t));
+		MP_CHECKOK(mp_set_int(&t, 1));
+		MP_CHECKOK(mp_bdivmod(&t, b, &meth->irr, meth->irr_arr, r));
+	  CLEANUP:
+		mp_clear(&t);
+		return res;
+	} else {
+		return mp_bdivmod(a, b, &meth->irr, meth->irr_arr, r);
+	}
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl_mult.c b/mozilla/security/nss/lib/freebl/ecl/ecl_mult.c
new file mode 100644
index 0000000..050d0a7
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl_mult.c
@@ -0,0 +1,356 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 "mpi.h"
+#include "mplogic.h"
+#include "ecl.h"
+#include "ecl-priv.h"
+#include <stdlib.h>
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k * P(x, 
+ * y).  If x, y = NULL, then P is assumed to be the generator (base point) 
+ * of the group of points on the elliptic curve. Input and output values
+ * are assumed to be NOT field-encoded. */
+mp_err
+ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
+			const mp_int *py, mp_int *rx, mp_int *ry)
+{
+	mp_err res = MP_OKAY;
+	mp_int kt;
+
+	ARGCHK((k != NULL) && (group != NULL), MP_BADARG);
+	MP_DIGITS(&kt) = 0;
+
+	/* want scalar to be less than or equal to group order */
+	if (mp_cmp(k, &group->order) > 0) {
+		MP_CHECKOK(mp_init(&kt));
+		MP_CHECKOK(mp_mod(k, &group->order, &kt));
+	} else {
+		MP_SIGN(&kt) = MP_ZPOS;
+		MP_USED(&kt) = MP_USED(k);
+		MP_ALLOC(&kt) = MP_ALLOC(k);
+		MP_DIGITS(&kt) = MP_DIGITS(k);
+	}
+
+	if ((px == NULL) || (py == NULL)) {
+		if (group->base_point_mul) {
+			MP_CHECKOK(group->base_point_mul(&kt, rx, ry, group));
+		} else {
+			MP_CHECKOK(group->
+					   point_mul(&kt, &group->genx, &group->geny, rx, ry,
+								 group));
+		}
+	} else {
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->field_enc(px, rx, group->meth));
+			MP_CHECKOK(group->meth->field_enc(py, ry, group->meth));
+			MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group));
+		} else {
+			MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group));
+		}
+	}
+	if (group->meth->field_dec) {
+		MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+		MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+	}
+
+  CLEANUP:
+	if (MP_DIGITS(&kt) != MP_DIGITS(k)) {
+		mp_clear(&kt);
+	}
+	return res;
+}
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + 
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Input and output values are assumed to be NOT field-encoded. */
+mp_err
+ec_pts_mul_basic(const mp_int *k1, const mp_int *k2, const mp_int *px,
+				 const mp_int *py, mp_int *rx, mp_int *ry,
+				 const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int sx, sy;
+
+	ARGCHK(group != NULL, MP_BADARG);
+	ARGCHK(!((k1 == NULL)
+			 && ((k2 == NULL) || (px == NULL)
+				 || (py == NULL))), MP_BADARG);
+
+	/* if some arguments are not defined used ECPoint_mul */
+	if (k1 == NULL) {
+		return ECPoint_mul(group, k2, px, py, rx, ry);
+	} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
+		return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+	}
+
+	MP_DIGITS(&sx) = 0;
+	MP_DIGITS(&sy) = 0;
+	MP_CHECKOK(mp_init(&sx));
+	MP_CHECKOK(mp_init(&sy));
+
+	MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy));
+	MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry));
+
+	if (group->meth->field_enc) {
+		MP_CHECKOK(group->meth->field_enc(&sx, &sx, group->meth));
+		MP_CHECKOK(group->meth->field_enc(&sy, &sy, group->meth));
+		MP_CHECKOK(group->meth->field_enc(rx, rx, group->meth));
+		MP_CHECKOK(group->meth->field_enc(ry, ry, group->meth));
+	}
+
+	MP_CHECKOK(group->point_add(&sx, &sy, rx, ry, rx, ry, group));
+
+	if (group->meth->field_dec) {
+		MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+		MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+	}
+
+  CLEANUP:
+	mp_clear(&sx);
+	mp_clear(&sy);
+	return res;
+}
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + 
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Input and output values are assumed to be NOT field-encoded. Uses
+ * algorithm 15 (simultaneous multiple point multiplication) from Brown,
+ * Hankerson, Lopez, Menezes. Software Implementation of the NIST
+ * Elliptic Curves over Prime Fields. */
+mp_err
+ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2, const mp_int *px,
+					const mp_int *py, mp_int *rx, mp_int *ry,
+					const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int precomp[4][4][2];
+	const mp_int *a, *b;
+	int i, j;
+	int ai, bi, d;
+
+	ARGCHK(group != NULL, MP_BADARG);
+	ARGCHK(!((k1 == NULL)
+			 && ((k2 == NULL) || (px == NULL)
+				 || (py == NULL))), MP_BADARG);
+
+	/* if some arguments are not defined used ECPoint_mul */
+	if (k1 == NULL) {
+		return ECPoint_mul(group, k2, px, py, rx, ry);
+	} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
+		return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+	}
+
+	/* initialize precomputation table */
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			MP_DIGITS(&precomp[i][j][0]) = 0;
+			MP_DIGITS(&precomp[i][j][1]) = 0;
+		}
+	}
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			 MP_CHECKOK( mp_init_size(&precomp[i][j][0],
+						 ECL_MAX_FIELD_SIZE_DIGITS) );
+			 MP_CHECKOK( mp_init_size(&precomp[i][j][1],
+						 ECL_MAX_FIELD_SIZE_DIGITS) );
+		}
+	}
+
+	/* fill precomputation table */
+	/* assign {k1, k2} = {a, b} such that len(a) >= len(b) */
+	if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) {
+		a = k2;
+		b = k1;
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->
+					   field_enc(px, &precomp[1][0][0], group->meth));
+			MP_CHECKOK(group->meth->
+					   field_enc(py, &precomp[1][0][1], group->meth));
+		} else {
+			MP_CHECKOK(mp_copy(px, &precomp[1][0][0]));
+			MP_CHECKOK(mp_copy(py, &precomp[1][0][1]));
+		}
+		MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0]));
+		MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1]));
+	} else {
+		a = k1;
+		b = k2;
+		MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0]));
+		MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1]));
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->
+					   field_enc(px, &precomp[0][1][0], group->meth));
+			MP_CHECKOK(group->meth->
+					   field_enc(py, &precomp[0][1][1], group->meth));
+		} else {
+			MP_CHECKOK(mp_copy(px, &precomp[0][1][0]));
+			MP_CHECKOK(mp_copy(py, &precomp[0][1][1]));
+		}
+	}
+	/* precompute [*][0][*] */
+	mp_zero(&precomp[0][0][0]);
+	mp_zero(&precomp[0][0][1]);
+	MP_CHECKOK(group->
+			   point_dbl(&precomp[1][0][0], &precomp[1][0][1],
+						 &precomp[2][0][0], &precomp[2][0][1], group));
+	MP_CHECKOK(group->
+			   point_add(&precomp[1][0][0], &precomp[1][0][1],
+						 &precomp[2][0][0], &precomp[2][0][1],
+						 &precomp[3][0][0], &precomp[3][0][1], group));
+	/* precompute [*][1][*] */
+	for (i = 1; i < 4; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[0][1][0], &precomp[0][1][1],
+							 &precomp[i][0][0], &precomp[i][0][1],
+							 &precomp[i][1][0], &precomp[i][1][1], group));
+	}
+	/* precompute [*][2][*] */
+	MP_CHECKOK(group->
+			   point_dbl(&precomp[0][1][0], &precomp[0][1][1],
+						 &precomp[0][2][0], &precomp[0][2][1], group));
+	for (i = 1; i < 4; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[0][2][0], &precomp[0][2][1],
+							 &precomp[i][0][0], &precomp[i][0][1],
+							 &precomp[i][2][0], &precomp[i][2][1], group));
+	}
+	/* precompute [*][3][*] */
+	MP_CHECKOK(group->
+			   point_add(&precomp[0][1][0], &precomp[0][1][1],
+						 &precomp[0][2][0], &precomp[0][2][1],
+						 &precomp[0][3][0], &precomp[0][3][1], group));
+	for (i = 1; i < 4; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[0][3][0], &precomp[0][3][1],
+							 &precomp[i][0][0], &precomp[i][0][1],
+							 &precomp[i][3][0], &precomp[i][3][1], group));
+	}
+
+	d = (mpl_significant_bits(a) + 1) / 2;
+
+	/* R = inf */
+	mp_zero(rx);
+	mp_zero(ry);
+
+	for (i = d - 1; i >= 0; i--) {
+		ai = MP_GET_BIT(a, 2 * i + 1);
+		ai <<= 1;
+		ai |= MP_GET_BIT(a, 2 * i);
+		bi = MP_GET_BIT(b, 2 * i + 1);
+		bi <<= 1;
+		bi |= MP_GET_BIT(b, 2 * i);
+		/* R = 2^2 * R */
+		MP_CHECKOK(group->point_dbl(rx, ry, rx, ry, group));
+		MP_CHECKOK(group->point_dbl(rx, ry, rx, ry, group));
+		/* R = R + (ai * A + bi * B) */
+		MP_CHECKOK(group->
+				   point_add(rx, ry, &precomp[ai][bi][0],
+							 &precomp[ai][bi][1], rx, ry, group));
+	}
+
+	if (group->meth->field_dec) {
+		MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+		MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+	}
+
+  CLEANUP:
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			mp_clear(&precomp[i][j][0]);
+			mp_clear(&precomp[i][j][1]);
+		}
+	}
+	return res;
+}
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + 
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Input and output values are assumed to be NOT field-encoded. */
+mp_err
+ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2,
+			 const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry)
+{
+	mp_err res = MP_OKAY;
+	mp_int k1t, k2t;
+	const mp_int *k1p, *k2p;
+
+	MP_DIGITS(&k1t) = 0;
+	MP_DIGITS(&k2t) = 0;
+
+	ARGCHK(group != NULL, MP_BADARG);
+
+	/* want scalar to be less than or equal to group order */
+	if (k1 != NULL) {
+		if (mp_cmp(k1, &group->order) >= 0) {
+			MP_CHECKOK(mp_init(&k1t));
+			MP_CHECKOK(mp_mod(k1, &group->order, &k1t));
+			k1p = &k1t;
+		} else {
+			k1p = k1;
+		}
+	} else {
+		k1p = k1;
+	}
+	if (k2 != NULL) {
+		if (mp_cmp(k2, &group->order) >= 0) {
+			MP_CHECKOK(mp_init(&k2t));
+			MP_CHECKOK(mp_mod(k2, &group->order, &k2t));
+			k2p = &k2t;
+		} else {
+			k2p = k2;
+		}
+	} else {
+		k2p = k2;
+	}
+
+	/* if points_mul is defined, then use it */
+	if (group->points_mul) {
+		res = group->points_mul(k1p, k2p, px, py, rx, ry, group);
+	} else {
+		res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group);
+	}
+
+  CLEANUP:
+	mp_clear(&k1t);
+	mp_clear(&k2t);
+	return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp.h b/mozilla/security/nss/lib/freebl/ecl/ecp.h
new file mode 100644
index 0000000..1d247b1
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp.h
@@ -0,0 +1,140 @@
+/* 
+ * ***** 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 elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifndef __ecp_h_
+#define __ecp_h_
+
+#include "ecl-priv.h"
+
+/* Checks if point P(px, py) is at infinity.  Uses affine coordinates. */
+mp_err ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py);
+
+/* Sets P(px, py) to be the point at infinity.  Uses affine coordinates. */
+mp_err ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py);
+
+/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx,
+ * qy). Uses affine coordinates. */
+mp_err ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py,
+						 const mp_int *qx, const mp_int *qy, mp_int *rx,
+						 mp_int *ry, const ECGroup *group);
+
+/* Computes R = P - Q.  Uses affine coordinates. */
+mp_err ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py,
+						 const mp_int *qx, const mp_int *qy, mp_int *rx,
+						 mp_int *ry, const ECGroup *group);
+
+/* Computes R = 2P.  Uses affine coordinates. */
+mp_err ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+						 mp_int *ry, const ECGroup *group);
+
+/* Validates a point on a GFp curve. */
+mp_err ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group);
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp.  Uses affine coordinates. */
+mp_err ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px,
+						 const mp_int *py, mp_int *rx, mp_int *ry,
+						 const ECGroup *group);
+#endif
+
+/* Converts a point P(px, py) from affine coordinates to Jacobian
+ * projective coordinates R(rx, ry, rz). */
+mp_err ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
+						 mp_int *ry, mp_int *rz, const ECGroup *group);
+
+/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
+ * affine coordinates R(rx, ry). */
+mp_err ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py,
+						 const mp_int *pz, mp_int *rx, mp_int *ry,
+						 const ECGroup *group);
+
+/* Checks if point P(px, py, pz) is at infinity.  Uses Jacobian
+ * coordinates. */
+mp_err ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py,
+							const mp_int *pz);
+
+/* Sets P(px, py, pz) to be the point at infinity.  Uses Jacobian
+ * coordinates. */
+mp_err ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz);
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, qz).  Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py,
+							 const mp_int *pz, const mp_int *qx,
+							 const mp_int *qy, mp_int *rx, mp_int *ry,
+							 mp_int *rz, const ECGroup *group);
+
+/* Computes R = 2P.  Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py,
+						 const mp_int *pz, mp_int *rx, mp_int *ry,
+						 mp_int *rz, const ECGroup *group);
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp.  Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px,
+						 const mp_int *py, mp_int *rx, mp_int *ry,
+						 const ECGroup *group);
+#endif
+
+/* Computes R(x, y) = k1 * G + k2 * P(x, y), where G is the generator
+ * (base point) of the group of points on the elliptic curve. Allows k1 =
+ * NULL or { k2, P } = NULL.  Implemented using mixed Jacobian-affine
+ * coordinates. Input and output values are assumed to be NOT
+ * field-encoded and are in affine form. */
+mp_err
+ ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
+					const mp_int *py, mp_int *rx, mp_int *ry,
+					const ECGroup *group);
+
+/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
+ * curve points P and R can be identical. Uses mixed Modified-Jacobian
+ * co-ordinates for doubling and Chudnovsky Jacobian coordinates for
+ * additions. Assumes input is already field-encoded using field_enc, and
+ * returns output that is still field-encoded. Uses 5-bit window NAF
+ * method (algorithm 11) for scalar-point multiplication from Brown,
+ * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic 
+ * Curves Over Prime Fields. */
+mp_err
+ ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
+					   mp_int *rx, mp_int *ry, const ECGroup *group);
+
+#endif							/* __ecp_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_aff.c b/mozilla/security/nss/lib/freebl/ecl/ecp_aff.c
new file mode 100644
index 0000000..cda04ed
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_aff.c
@@ -0,0 +1,357 @@
+/* 
+ * ***** 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 elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ *   Stephen Fung <fungstep@hotmail.com>, and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ *   Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>,
+ *   Nils Larsch <nla@trustcenter.de>, and
+ *   Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
+ *
+ * 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 "ecp.h"
+#include "mplogic.h"
+#include <stdlib.h>
+
+/* Checks if point P(px, py) is at infinity.  Uses affine coordinates. */
+mp_err
+ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py)
+{
+
+	if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
+		return MP_YES;
+	} else {
+		return MP_NO;
+	}
+
+}
+
+/* Sets P(px, py) to be the point at infinity.  Uses affine coordinates. */
+mp_err
+ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py)
+{
+	mp_zero(px);
+	mp_zero(py);
+	return MP_OKAY;
+}
+
+/* Computes R = P + Q based on IEEE P1363 A.10.1. Elliptic curve points P, 
+ * Q, and R can all be identical. Uses affine coordinates. Assumes input
+ * is already field-encoded using field_enc, and returns output that is
+ * still field-encoded. */
+mp_err
+ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
+				  const mp_int *qy, mp_int *rx, mp_int *ry,
+				  const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int lambda, temp, tempx, tempy;
+
+	MP_DIGITS(&lambda) = 0;
+	MP_DIGITS(&temp) = 0;
+	MP_DIGITS(&tempx) = 0;
+	MP_DIGITS(&tempy) = 0;
+	MP_CHECKOK(mp_init(&lambda));
+	MP_CHECKOK(mp_init(&temp));
+	MP_CHECKOK(mp_init(&tempx));
+	MP_CHECKOK(mp_init(&tempy));
+	/* if P = inf, then R = Q */
+	if (ec_GFp_pt_is_inf_aff(px, py) == 0) {
+		MP_CHECKOK(mp_copy(qx, rx));
+		MP_CHECKOK(mp_copy(qy, ry));
+		res = MP_OKAY;
+		goto CLEANUP;
+	}
+	/* if Q = inf, then R = P */
+	if (ec_GFp_pt_is_inf_aff(qx, qy) == 0) {
+		MP_CHECKOK(mp_copy(px, rx));
+		MP_CHECKOK(mp_copy(py, ry));
+		res = MP_OKAY;
+		goto CLEANUP;
+	}
+	/* if px != qx, then lambda = (py-qy) / (px-qx) */
+	if (mp_cmp(px, qx) != 0) {
+		MP_CHECKOK(group->meth->field_sub(py, qy, &tempy, group->meth));
+		MP_CHECKOK(group->meth->field_sub(px, qx, &tempx, group->meth));
+		MP_CHECKOK(group->meth->
+				   field_div(&tempy, &tempx, &lambda, group->meth));
+	} else {
+		/* if py != qy or qy = 0, then R = inf */
+		if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) {
+			mp_zero(rx);
+			mp_zero(ry);
+			res = MP_OKAY;
+			goto CLEANUP;
+		}
+		/* lambda = (3qx^2+a) / (2qy) */
+		MP_CHECKOK(group->meth->field_sqr(qx, &tempx, group->meth));
+		MP_CHECKOK(mp_set_int(&temp, 3));
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth));
+		}
+		MP_CHECKOK(group->meth->
+				   field_mul(&tempx, &temp, &tempx, group->meth));
+		MP_CHECKOK(group->meth->
+				   field_add(&tempx, &group->curvea, &tempx, group->meth));
+		MP_CHECKOK(mp_set_int(&temp, 2));
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth));
+		}
+		MP_CHECKOK(group->meth->field_mul(qy, &temp, &tempy, group->meth));
+		MP_CHECKOK(group->meth->
+				   field_div(&tempx, &tempy, &lambda, group->meth));
+	}
+	/* rx = lambda^2 - px - qx */
+	MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth));
+	MP_CHECKOK(group->meth->field_sub(&tempx, px, &tempx, group->meth));
+	MP_CHECKOK(group->meth->field_sub(&tempx, qx, &tempx, group->meth));
+	/* ry = (x1-x2) * lambda - y1 */
+	MP_CHECKOK(group->meth->field_sub(qx, &tempx, &tempy, group->meth));
+	MP_CHECKOK(group->meth->
+			   field_mul(&tempy, &lambda, &tempy, group->meth));
+	MP_CHECKOK(group->meth->field_sub(&tempy, qy, &tempy, group->meth));
+	MP_CHECKOK(mp_copy(&tempx, rx));
+	MP_CHECKOK(mp_copy(&tempy, ry));
+
+  CLEANUP:
+	mp_clear(&lambda);
+	mp_clear(&temp);
+	mp_clear(&tempx);
+	mp_clear(&tempy);
+	return res;
+}
+
+/* Computes R = P - Q. Elliptic curve points P, Q, and R can all be
+ * identical. Uses affine coordinates. Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
+				  const mp_int *qy, mp_int *rx, mp_int *ry,
+				  const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int nqy;
+
+	MP_DIGITS(&nqy) = 0;
+	MP_CHECKOK(mp_init(&nqy));
+	/* nqy = -qy */
+	MP_CHECKOK(group->meth->field_neg(qy, &nqy, group->meth));
+	res = group->point_add(px, py, qx, &nqy, rx, ry, group);
+  CLEANUP:
+	mp_clear(&nqy);
+	return res;
+}
+
+/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
+ * affine coordinates. Assumes input is already field-encoded using
+ * field_enc, and returns output that is still field-encoded. */
+mp_err
+ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+				  mp_int *ry, const ECGroup *group)
+{
+	return ec_GFp_pt_add_aff(px, py, px, py, rx, ry, group);
+}
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+/* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and 
+ * R can be identical. Uses affine coordinates. Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py,
+				  mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int k, k3, qx, qy, sx, sy;
+	int b1, b3, i, l;
+
+	MP_DIGITS(&k) = 0;
+	MP_DIGITS(&k3) = 0;
+	MP_DIGITS(&qx) = 0;
+	MP_DIGITS(&qy) = 0;
+	MP_DIGITS(&sx) = 0;
+	MP_DIGITS(&sy) = 0;
+	MP_CHECKOK(mp_init(&k));
+	MP_CHECKOK(mp_init(&k3));
+	MP_CHECKOK(mp_init(&qx));
+	MP_CHECKOK(mp_init(&qy));
+	MP_CHECKOK(mp_init(&sx));
+	MP_CHECKOK(mp_init(&sy));
+
+	/* if n = 0 then r = inf */
+	if (mp_cmp_z(n) == 0) {
+		mp_zero(rx);
+		mp_zero(ry);
+		res = MP_OKAY;
+		goto CLEANUP;
+	}
+	/* Q = P, k = n */
+	MP_CHECKOK(mp_copy(px, &qx));
+	MP_CHECKOK(mp_copy(py, &qy));
+	MP_CHECKOK(mp_copy(n, &k));
+	/* if n < 0 then Q = -Q, k = -k */
+	if (mp_cmp_z(n) < 0) {
+		MP_CHECKOK(group->meth->field_neg(&qy, &qy, group->meth));
+		MP_CHECKOK(mp_neg(&k, &k));
+	}
+#ifdef ECL_DEBUG				/* basic double and add method */
+	l = mpl_significant_bits(&k) - 1;
+	MP_CHECKOK(mp_copy(&qx, &sx));
+	MP_CHECKOK(mp_copy(&qy, &sy));
+	for (i = l - 1; i >= 0; i--) {
+		/* S = 2S */
+		MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
+		/* if k_i = 1, then S = S + Q */
+		if (mpl_get_bit(&k, i) != 0) {
+			MP_CHECKOK(group->
+					   point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
+		}
+	}
+#else							/* double and add/subtract method from
+								 * standard */
+	/* k3 = 3 * k */
+	MP_CHECKOK(mp_set_int(&k3, 3));
+	MP_CHECKOK(mp_mul(&k, &k3, &k3));
+	/* S = Q */
+	MP_CHECKOK(mp_copy(&qx, &sx));
+	MP_CHECKOK(mp_copy(&qy, &sy));
+	/* l = index of high order bit in binary representation of 3*k */
+	l = mpl_significant_bits(&k3) - 1;
+	/* for i = l-1 downto 1 */
+	for (i = l - 1; i >= 1; i--) {
+		/* S = 2S */
+		MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
+		b3 = MP_GET_BIT(&k3, i);
+		b1 = MP_GET_BIT(&k, i);
+		/* if k3_i = 1 and k_i = 0, then S = S + Q */
+		if ((b3 == 1) && (b1 == 0)) {
+			MP_CHECKOK(group->
+					   point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
+			/* if k3_i = 0 and k_i = 1, then S = S - Q */
+		} else if ((b3 == 0) && (b1 == 1)) {
+			MP_CHECKOK(group->
+					   point_sub(&sx, &sy, &qx, &qy, &sx, &sy, group));
+		}
+	}
+#endif
+	/* output S */
+	MP_CHECKOK(mp_copy(&sx, rx));
+	MP_CHECKOK(mp_copy(&sy, ry));
+
+  CLEANUP:
+	mp_clear(&k);
+	mp_clear(&k3);
+	mp_clear(&qx);
+	mp_clear(&qy);
+	mp_clear(&sx);
+	mp_clear(&sy);
+	return res;
+}
+#endif
+
+/* Validates a point on a GFp curve. */
+mp_err 
+ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group)
+{
+	mp_err res = MP_NO;
+	mp_int accl, accr, tmp, pxt, pyt;
+
+	MP_DIGITS(&accl) = 0;
+	MP_DIGITS(&accr) = 0;
+	MP_DIGITS(&tmp) = 0;
+	MP_DIGITS(&pxt) = 0;
+	MP_DIGITS(&pyt) = 0;
+	MP_CHECKOK(mp_init(&accl));
+	MP_CHECKOK(mp_init(&accr));
+	MP_CHECKOK(mp_init(&tmp));
+	MP_CHECKOK(mp_init(&pxt));
+	MP_CHECKOK(mp_init(&pyt));
+
+    /* 1: Verify that publicValue is not the point at infinity */
+	if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) {
+		res = MP_NO;
+		goto CLEANUP;
+	}
+    /* 2: Verify that the coordinates of publicValue are elements 
+     *    of the field.
+     */
+	if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) || 
+		(MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) {
+		res = MP_NO;
+		goto CLEANUP;
+	}
+    /* 3: Verify that publicValue is on the curve. */
+	if (group->meth->field_enc) {
+		group->meth->field_enc(px, &pxt, group->meth);
+		group->meth->field_enc(py, &pyt, group->meth);
+	} else {
+		mp_copy(px, &pxt);
+		mp_copy(py, &pyt);
+	}
+	/* left-hand side: y^2  */
+	MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) );
+	/* right-hand side: x^3 + a*x + b */
+	MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) );
+	MP_CHECKOK( group->meth->field_mul(&pxt, &tmp, &accr, group->meth) );
+	MP_CHECKOK( group->meth->field_mul(&group->curvea, &pxt, &tmp, group->meth) );
+	MP_CHECKOK( group->meth->field_add(&tmp, &accr, &accr, group->meth) );
+	MP_CHECKOK( group->meth->field_add(&accr, &group->curveb, &accr, group->meth) );
+	/* check LHS - RHS == 0 */
+	MP_CHECKOK( group->meth->field_sub(&accl, &accr, &accr, group->meth) );
+	if (mp_cmp_z(&accr) != 0) {
+		res = MP_NO;
+		goto CLEANUP;
+	}
+    /* 4: Verify that the order of the curve times the publicValue
+     *    is the point at infinity.
+     */
+	MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) );
+	if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
+		res = MP_NO;
+		goto CLEANUP;
+	}
+
+	res = MP_YES;
+
+CLEANUP:
+	mp_clear(&accl);
+	mp_clear(&accr);
+	mp_clear(&tmp);
+	mp_clear(&pxt);
+	mp_clear(&pyt);
+	return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c b/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c
new file mode 100644
index 0000000..2659dbb
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c
@@ -0,0 +1,553 @@
+/* 
+ * ***** 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 elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ *   Stephen Fung <fungstep@hotmail.com>, and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ *   Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>,
+ *   Nils Larsch <nla@trustcenter.de>, and
+ *   Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
+ *
+ * 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 "ecp.h"
+#include "mplogic.h"
+#include <stdlib.h>
+#ifdef ECL_DEBUG
+#include <assert.h>
+#endif
+
+/* Converts a point P(px, py) from affine coordinates to Jacobian
+ * projective coordinates R(rx, ry, rz). Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
+				  mp_int *ry, mp_int *rz, const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+
+	if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) {
+		MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+	} else {
+		MP_CHECKOK(mp_copy(px, rx));
+		MP_CHECKOK(mp_copy(py, ry));
+		MP_CHECKOK(mp_set_int(rz, 1));
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth));
+		}
+	}
+  CLEANUP:
+	return res;
+}
+
+/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
+ * affine coordinates R(rx, ry).  P and R can share x and y coordinates.
+ * Assumes input is already field-encoded using field_enc, and returns
+ * output that is still field-encoded. */
+mp_err
+ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz,
+				  mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int z1, z2, z3;
+
+	MP_DIGITS(&z1) = 0;
+	MP_DIGITS(&z2) = 0;
+	MP_DIGITS(&z3) = 0;
+	MP_CHECKOK(mp_init(&z1));
+	MP_CHECKOK(mp_init(&z2));
+	MP_CHECKOK(mp_init(&z3));
+
+	/* if point at infinity, then set point at infinity and exit */
+	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+		MP_CHECKOK(ec_GFp_pt_set_inf_aff(rx, ry));
+		goto CLEANUP;
+	}
+
+	/* transform (px, py, pz) into (px / pz^2, py / pz^3) */
+	if (mp_cmp_d(pz, 1) == 0) {
+		MP_CHECKOK(mp_copy(px, rx));
+		MP_CHECKOK(mp_copy(py, ry));
+	} else {
+		MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth));
+		MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth));
+		MP_CHECKOK(group->meth->field_mul(&z1, &z2, &z3, group->meth));
+		MP_CHECKOK(group->meth->field_mul(px, &z2, rx, group->meth));
+		MP_CHECKOK(group->meth->field_mul(py, &z3, ry, group->meth));
+	}
+
+  CLEANUP:
+	mp_clear(&z1);
+	mp_clear(&z2);
+	mp_clear(&z3);
+	return res;
+}
+
+/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
+ * coordinates. */
+mp_err
+ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz)
+{
+	return mp_cmp_z(pz);
+}
+
+/* Sets P(px, py, pz) to be the point at infinity.  Uses Jacobian
+ * coordinates. */
+mp_err
+ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz)
+{
+	mp_zero(pz);
+	return MP_OKAY;
+}
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, 1).  Elliptic curve points P, Q, and R can all be identical.
+ * Uses mixed Jacobian-affine coordinates. Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. Uses equation (2) from Brown, Hankerson, Lopez, and
+ * Menezes. Software Implementation of the NIST Elliptic Curves Over Prime
+ * Fields. */
+mp_err
+ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
+					  const mp_int *qx, const mp_int *qy, mp_int *rx,
+					  mp_int *ry, mp_int *rz, const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int A, B, C, D, C2, C3;
+
+	MP_DIGITS(&A) = 0;
+	MP_DIGITS(&B) = 0;
+	MP_DIGITS(&C) = 0;
+	MP_DIGITS(&D) = 0;
+	MP_DIGITS(&C2) = 0;
+	MP_DIGITS(&C3) = 0;
+	MP_CHECKOK(mp_init(&A));
+	MP_CHECKOK(mp_init(&B));
+	MP_CHECKOK(mp_init(&C));
+	MP_CHECKOK(mp_init(&D));
+	MP_CHECKOK(mp_init(&C2));
+	MP_CHECKOK(mp_init(&C3));
+
+	/* If either P or Q is the point at infinity, then return the other
+	 * point */
+	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+		MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group));
+		goto CLEANUP;
+	}
+	if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) {
+		MP_CHECKOK(mp_copy(px, rx));
+		MP_CHECKOK(mp_copy(py, ry));
+		MP_CHECKOK(mp_copy(pz, rz));
+		goto CLEANUP;
+	}
+
+	/* A = qx * pz^2, B = qy * pz^3 */
+	MP_CHECKOK(group->meth->field_sqr(pz, &A, group->meth));
+	MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth));
+	MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth));
+	MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth));
+
+	/* C = A - px, D = B - py */
+	MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth));
+	MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth));
+
+	/* C2 = C^2, C3 = C^3 */
+	MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth));
+	MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth));
+
+	/* rz = pz * C */
+	MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth));
+
+	/* C = px * C^2 */
+	MP_CHECKOK(group->meth->field_mul(px, &C2, &C, group->meth));
+	/* A = D^2 */
+	MP_CHECKOK(group->meth->field_sqr(&D, &A, group->meth));
+
+	/* rx = D^2 - (C^3 + 2 * (px * C^2)) */
+	MP_CHECKOK(group->meth->field_add(&C, &C, rx, group->meth));
+	MP_CHECKOK(group->meth->field_add(&C3, rx, rx, group->meth));
+	MP_CHECKOK(group->meth->field_sub(&A, rx, rx, group->meth));
+
+	/* C3 = py * C^3 */
+	MP_CHECKOK(group->meth->field_mul(py, &C3, &C3, group->meth));
+
+	/* ry = D * (px * C^2 - rx) - py * C^3 */
+	MP_CHECKOK(group->meth->field_sub(&C, rx, ry, group->meth));
+	MP_CHECKOK(group->meth->field_mul(&D, ry, ry, group->meth));
+	MP_CHECKOK(group->meth->field_sub(ry, &C3, ry, group->meth));
+
+  CLEANUP:
+	mp_clear(&A);
+	mp_clear(&B);
+	mp_clear(&C);
+	mp_clear(&D);
+	mp_clear(&C2);
+	mp_clear(&C3);
+	return res;
+}
+
+/* Computes R = 2P.  Elliptic curve points P and R can be identical.  Uses 
+ * Jacobian coordinates.
+ *
+ * Assumes input is already field-encoded using field_enc, and returns 
+ * output that is still field-encoded.
+ *
+ * This routine implements Point Doubling in the Jacobian Projective 
+ * space as described in the paper "Efficient elliptic curve exponentiation 
+ * using mixed coordinates", by H. Cohen, A Miyaji, T. Ono.
+ */
+mp_err
+ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py, const mp_int *pz,
+				  mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int t0, t1, M, S;
+
+	MP_DIGITS(&t0) = 0;
+	MP_DIGITS(&t1) = 0;
+	MP_DIGITS(&M) = 0;
+	MP_DIGITS(&S) = 0;
+	MP_CHECKOK(mp_init(&t0));
+	MP_CHECKOK(mp_init(&t1));
+	MP_CHECKOK(mp_init(&M));
+	MP_CHECKOK(mp_init(&S));
+
+	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+		MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+		goto CLEANUP;
+	}
+
+	if (mp_cmp_d(pz, 1) == 0) {
+		/* M = 3 * px^2 + a */
+		MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
+		MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth));
+		MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth));
+		MP_CHECKOK(group->meth->
+				   field_add(&t0, &group->curvea, &M, group->meth));
+	} else if (mp_cmp_int(&group->curvea, -3) == 0) {
+		/* M = 3 * (px + pz^2) * (px - pz^2) */
+		MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth));
+		MP_CHECKOK(group->meth->field_add(px, &M, &t0, group->meth));
+		MP_CHECKOK(group->meth->field_sub(px, &M, &t1, group->meth));
+		MP_CHECKOK(group->meth->field_mul(&t0, &t1, &M, group->meth));
+		MP_CHECKOK(group->meth->field_add(&M, &M, &t0, group->meth));
+		MP_CHECKOK(group->meth->field_add(&t0, &M, &M, group->meth));
+	} else {
+		/* M = 3 * (px^2) + a * (pz^4) */
+		MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
+		MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth));
+		MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth));
+		MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth));
+		MP_CHECKOK(group->meth->field_sqr(&M, &M, group->meth));
+		MP_CHECKOK(group->meth->
+				   field_mul(&M, &group->curvea, &M, group->meth));
+		MP_CHECKOK(group->meth->field_add(&M, &t0, &M, group->meth));
+	}
+
+	/* rz = 2 * py * pz */
+	/* t0 = 4 * py^2 */
+	if (mp_cmp_d(pz, 1) == 0) {
+		MP_CHECKOK(group->meth->field_add(py, py, rz, group->meth));
+		MP_CHECKOK(group->meth->field_sqr(rz, &t0, group->meth));
+	} else {
+		MP_CHECKOK(group->meth->field_add(py, py, &t0, group->meth));
+		MP_CHECKOK(group->meth->field_mul(&t0, pz, rz, group->meth));
+		MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth));
+	}
+
+	/* S = 4 * px * py^2 = px * (2 * py)^2 */
+	MP_CHECKOK(group->meth->field_mul(px, &t0, &S, group->meth));
+
+	/* rx = M^2 - 2 * S */
+	MP_CHECKOK(group->meth->field_add(&S, &S, &t1, group->meth));
+	MP_CHECKOK(group->meth->field_sqr(&M, rx, group->meth));
+	MP_CHECKOK(group->meth->field_sub(rx, &t1, rx, group->meth));
+
+	/* ry = M * (S - rx) - 8 * py^4 */
+	MP_CHECKOK(group->meth->field_sqr(&t0, &t1, group->meth));
+	if (mp_isodd(&t1)) {
+		MP_CHECKOK(mp_add(&t1, &group->meth->irr, &t1));
+	}
+	MP_CHECKOK(mp_div_2(&t1, &t1));
+	MP_CHECKOK(group->meth->field_sub(&S, rx, &S, group->meth));
+	MP_CHECKOK(group->meth->field_mul(&M, &S, &M, group->meth));
+	MP_CHECKOK(group->meth->field_sub(&M, &t1, ry, group->meth));
+
+  CLEANUP:
+	mp_clear(&t0);
+	mp_clear(&t1);
+	mp_clear(&M);
+	mp_clear(&S);
+	return res;
+}
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp.  Elliptic curve points P and R can be
+ * identical.  Uses mixed Jacobian-affine coordinates. Assumes input is
+ * already field-encoded using field_enc, and returns output that is still 
+ * field-encoded. Uses 4-bit window method. */
+mp_err
+ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px, const mp_int *py,
+				  mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int precomp[16][2], rz;
+	int i, ni, d;
+
+	MP_DIGITS(&rz) = 0;
+	for (i = 0; i < 16; i++) {
+		MP_DIGITS(&precomp[i][0]) = 0;
+		MP_DIGITS(&precomp[i][1]) = 0;
+	}
+
+	ARGCHK(group != NULL, MP_BADARG);
+	ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
+
+	/* initialize precomputation table */
+	for (i = 0; i < 16; i++) {
+		MP_CHECKOK(mp_init(&precomp[i][0]));
+		MP_CHECKOK(mp_init(&precomp[i][1]));
+	}
+
+	/* fill precomputation table */
+	mp_zero(&precomp[0][0]);
+	mp_zero(&precomp[0][1]);
+	MP_CHECKOK(mp_copy(px, &precomp[1][0]));
+	MP_CHECKOK(mp_copy(py, &precomp[1][1]));
+	for (i = 2; i < 16; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[1][0], &precomp[1][1],
+							 &precomp[i - 1][0], &precomp[i - 1][1],
+							 &precomp[i][0], &precomp[i][1], group));
+	}
+
+	d = (mpl_significant_bits(n) + 3) / 4;
+
+	/* R = inf */
+	MP_CHECKOK(mp_init(&rz));
+	MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
+
+	for (i = d - 1; i >= 0; i--) {
+		/* compute window ni */
+		ni = MP_GET_BIT(n, 4 * i + 3);
+		ni <<= 1;
+		ni |= MP_GET_BIT(n, 4 * i + 2);
+		ni <<= 1;
+		ni |= MP_GET_BIT(n, 4 * i + 1);
+		ni <<= 1;
+		ni |= MP_GET_BIT(n, 4 * i);
+		/* R = 2^4 * R */
+		MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+		MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+		MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+		MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+		/* R = R + (ni * P) */
+		MP_CHECKOK(ec_GFp_pt_add_jac_aff
+				   (rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry,
+					&rz, group));
+	}
+
+	/* convert result S to affine coordinates */
+	MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
+
+  CLEANUP:
+	mp_clear(&rz);
+	for (i = 0; i < 16; i++) {
+		mp_clear(&precomp[i][0]);
+		mp_clear(&precomp[i][1]);
+	}
+	return res;
+}
+#endif
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + 
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Uses mixed Jacobian-affine coordinates. Input and output values are
+ * assumed to be NOT field-encoded. Uses algorithm 15 (simultaneous
+ * multiple point multiplication) from Brown, Hankerson, Lopez, Menezes.
+ * Software Implementation of the NIST Elliptic Curves over Prime Fields. */
+mp_err
+ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
+				   const mp_int *py, mp_int *rx, mp_int *ry,
+				   const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int precomp[4][4][2];
+	mp_int rz;
+	const mp_int *a, *b;
+	int i, j;
+	int ai, bi, d;
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			MP_DIGITS(&precomp[i][j][0]) = 0;
+			MP_DIGITS(&precomp[i][j][1]) = 0;
+		}
+	}
+	MP_DIGITS(&rz) = 0;
+
+	ARGCHK(group != NULL, MP_BADARG);
+	ARGCHK(!((k1 == NULL)
+			 && ((k2 == NULL) || (px == NULL)
+				 || (py == NULL))), MP_BADARG);
+
+	/* if some arguments are not defined used ECPoint_mul */
+	if (k1 == NULL) {
+		return ECPoint_mul(group, k2, px, py, rx, ry);
+	} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
+		return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+	}
+
+	/* initialize precomputation table */
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			MP_CHECKOK(mp_init(&precomp[i][j][0]));
+			MP_CHECKOK(mp_init(&precomp[i][j][1]));
+		}
+	}
+
+	/* fill precomputation table */
+	/* assign {k1, k2} = {a, b} such that len(a) >= len(b) */
+	if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) {
+		a = k2;
+		b = k1;
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->
+					   field_enc(px, &precomp[1][0][0], group->meth));
+			MP_CHECKOK(group->meth->
+					   field_enc(py, &precomp[1][0][1], group->meth));
+		} else {
+			MP_CHECKOK(mp_copy(px, &precomp[1][0][0]));
+			MP_CHECKOK(mp_copy(py, &precomp[1][0][1]));
+		}
+		MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0]));
+		MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1]));
+	} else {
+		a = k1;
+		b = k2;
+		MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0]));
+		MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1]));
+		if (group->meth->field_enc) {
+			MP_CHECKOK(group->meth->
+					   field_enc(px, &precomp[0][1][0], group->meth));
+			MP_CHECKOK(group->meth->
+					   field_enc(py, &precomp[0][1][1], group->meth));
+		} else {
+			MP_CHECKOK(mp_copy(px, &precomp[0][1][0]));
+			MP_CHECKOK(mp_copy(py, &precomp[0][1][1]));
+		}
+	}
+	/* precompute [*][0][*] */
+	mp_zero(&precomp[0][0][0]);
+	mp_zero(&precomp[0][0][1]);
+	MP_CHECKOK(group->
+			   point_dbl(&precomp[1][0][0], &precomp[1][0][1],
+						 &precomp[2][0][0], &precomp[2][0][1], group));
+	MP_CHECKOK(group->
+			   point_add(&precomp[1][0][0], &precomp[1][0][1],
+						 &precomp[2][0][0], &precomp[2][0][1],
+						 &precomp[3][0][0], &precomp[3][0][1], group));
+	/* precompute [*][1][*] */
+	for (i = 1; i < 4; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[0][1][0], &precomp[0][1][1],
+							 &precomp[i][0][0], &precomp[i][0][1],
+							 &precomp[i][1][0], &precomp[i][1][1], group));
+	}
+	/* precompute [*][2][*] */
+	MP_CHECKOK(group->
+			   point_dbl(&precomp[0][1][0], &precomp[0][1][1],
+						 &precomp[0][2][0], &precomp[0][2][1], group));
+	for (i = 1; i < 4; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[0][2][0], &precomp[0][2][1],
+							 &precomp[i][0][0], &precomp[i][0][1],
+							 &precomp[i][2][0], &precomp[i][2][1], group));
+	}
+	/* precompute [*][3][*] */
+	MP_CHECKOK(group->
+			   point_add(&precomp[0][1][0], &precomp[0][1][1],
+						 &precomp[0][2][0], &precomp[0][2][1],
+						 &precomp[0][3][0], &precomp[0][3][1], group));
+	for (i = 1; i < 4; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[0][3][0], &precomp[0][3][1],
+							 &precomp[i][0][0], &precomp[i][0][1],
+							 &precomp[i][3][0], &precomp[i][3][1], group));
+	}
+
+	d = (mpl_significant_bits(a) + 1) / 2;
+
+	/* R = inf */
+	MP_CHECKOK(mp_init(&rz));
+	MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
+
+	for (i = d - 1; i >= 0; i--) {
+		ai = MP_GET_BIT(a, 2 * i + 1);
+		ai <<= 1;
+		ai |= MP_GET_BIT(a, 2 * i);
+		bi = MP_GET_BIT(b, 2 * i + 1);
+		bi <<= 1;
+		bi |= MP_GET_BIT(b, 2 * i);
+		/* R = 2^2 * R */
+		MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+		MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+		/* R = R + (ai * A + bi * B) */
+		MP_CHECKOK(ec_GFp_pt_add_jac_aff
+				   (rx, ry, &rz, &precomp[ai][bi][0], &precomp[ai][bi][1],
+					rx, ry, &rz, group));
+	}
+
+	MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
+
+	if (group->meth->field_dec) {
+		MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+		MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+	}
+
+  CLEANUP:
+	mp_clear(&rz);
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			mp_clear(&precomp[i][j][0]);
+			mp_clear(&precomp[i][j][1]);
+		}
+	}
+	return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_jm.c b/mozilla/security/nss/lib/freebl/ecl/ecp_jm.c
new file mode 100644
index 0000000..f015a61
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_jm.c
@@ -0,0 +1,323 @@
+/* 
+ * ***** 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 elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stephen Fung <fungstep@hotmail.com>, Sun Microsystems Laboratories
+ *
+ * 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 "ecp.h"
+#include "ecl-priv.h"
+#include "mplogic.h"
+#include <stdlib.h>
+
+#define MAX_SCRATCH 6
+
+/* Computes R = 2P.  Elliptic curve points P and R can be identical.  Uses 
+ * Modified Jacobian coordinates.
+ *
+ * Assumes input is already field-encoded using field_enc, and returns 
+ * output that is still field-encoded.
+ *
+ */
+mp_err
+ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz,
+				 const mp_int *paz4, mp_int *rx, mp_int *ry, mp_int *rz,
+				 mp_int *raz4, mp_int scratch[], const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int *t0, *t1, *M, *S;
+
+	t0 = &scratch[0];
+	t1 = &scratch[1];
+	M = &scratch[2];
+	S = &scratch[3];
+
+#if MAX_SCRATCH < 4
+#error "Scratch array defined too small "
+#endif
+
+	/* Check for point at infinity */
+	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+		/* Set r = pt at infinity by setting rz = 0 */
+
+		MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+		goto CLEANUP;
+	}
+
+	/* M = 3 (px^2) + a*(pz^4) */
+	MP_CHECKOK(group->meth->field_sqr(px, t0, group->meth));
+	MP_CHECKOK(group->meth->field_add(t0, t0, M, group->meth));
+	MP_CHECKOK(group->meth->field_add(t0, M, t0, group->meth));
+	MP_CHECKOK(group->meth->field_add(t0, paz4, M, group->meth));
+
+	/* rz = 2 * py * pz */
+	MP_CHECKOK(group->meth->field_mul(py, pz, S, group->meth));
+	MP_CHECKOK(group->meth->field_add(S, S, rz, group->meth));
+
+	/* t0 = 2y^2 , t1 = 8y^4 */
+	MP_CHECKOK(group->meth->field_sqr(py, t0, group->meth));
+	MP_CHECKOK(group->meth->field_add(t0, t0, t0, group->meth));
+	MP_CHECKOK(group->meth->field_sqr(t0, t1, group->meth));
+	MP_CHECKOK(group->meth->field_add(t1, t1, t1, group->meth));
+
+	/* S = 4 * px * py^2 = 2 * px * t0 */
+	MP_CHECKOK(group->meth->field_mul(px, t0, S, group->meth));
+	MP_CHECKOK(group->meth->field_add(S, S, S, group->meth));
+
+
+	/* rx = M^2 - 2S */
+	MP_CHECKOK(group->meth->field_sqr(M, rx, group->meth));
+	MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));
+	MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));
+
+	/* ry = M * (S - rx) - t1 */
+	MP_CHECKOK(group->meth->field_sub(S, rx, S, group->meth));
+	MP_CHECKOK(group->meth->field_mul(S, M, ry, group->meth));
+	MP_CHECKOK(group->meth->field_sub(ry, t1, ry, group->meth));
+
+	/* ra*z^4 = 2*t1*(apz4) */
+	MP_CHECKOK(group->meth->field_mul(paz4, t1, raz4, group->meth));
+	MP_CHECKOK(group->meth->field_add(raz4, raz4, raz4, group->meth));
+
+
+  CLEANUP:
+	return res;
+}
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, 1).  Elliptic curve points P, Q, and R can all be identical.
+ * Uses mixed Modified_Jacobian-affine coordinates. Assumes input is
+ * already field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
+					 const mp_int *paz4, const mp_int *qx,
+					 const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz,
+					 mp_int *raz4, mp_int scratch[], const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int *A, *B, *C, *D, *C2, *C3;
+
+	A = &scratch[0];
+	B = &scratch[1];
+	C = &scratch[2];
+	D = &scratch[3];
+	C2 = &scratch[4];
+	C3 = &scratch[5];
+
+#if MAX_SCRATCH < 6
+#error "Scratch array defined too small "
+#endif
+
+	/* If either P or Q is the point at infinity, then return the other
+	 * point */
+	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+		MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group));
+		MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth));
+		MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth));
+		MP_CHECKOK(group->meth->
+				   field_mul(raz4, &group->curvea, raz4, group->meth));
+		goto CLEANUP;
+	}
+	if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) {
+		MP_CHECKOK(mp_copy(px, rx));
+		MP_CHECKOK(mp_copy(py, ry));
+		MP_CHECKOK(mp_copy(pz, rz));
+		MP_CHECKOK(mp_copy(paz4, raz4));
+		goto CLEANUP;
+	}
+
+	/* A = qx * pz^2, B = qy * pz^3 */
+	MP_CHECKOK(group->meth->field_sqr(pz, A, group->meth));
+	MP_CHECKOK(group->meth->field_mul(A, pz, B, group->meth));
+	MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth));
+	MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth));
+
+	/* C = A - px, D = B - py */
+	MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth));
+	MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth));
+
+	/* C2 = C^2, C3 = C^3 */
+	MP_CHECKOK(group->meth->field_sqr(C, C2, group->meth));
+	MP_CHECKOK(group->meth->field_mul(C, C2, C3, group->meth));
+
+	/* rz = pz * C */
+	MP_CHECKOK(group->meth->field_mul(pz, C, rz, group->meth));
+
+	/* C = px * C^2 */
+	MP_CHECKOK(group->meth->field_mul(px, C2, C, group->meth));
+	/* A = D^2 */
+	MP_CHECKOK(group->meth->field_sqr(D, A, group->meth));
+
+	/* rx = D^2 - (C^3 + 2 * (px * C^2)) */
+	MP_CHECKOK(group->meth->field_add(C, C, rx, group->meth));
+	MP_CHECKOK(group->meth->field_add(C3, rx, rx, group->meth));
+	MP_CHECKOK(group->meth->field_sub(A, rx, rx, group->meth));
+
+	/* C3 = py * C^3 */
+	MP_CHECKOK(group->meth->field_mul(py, C3, C3, group->meth));
+
+	/* ry = D * (px * C^2 - rx) - py * C^3 */
+	MP_CHECKOK(group->meth->field_sub(C, rx, ry, group->meth));
+	MP_CHECKOK(group->meth->field_mul(D, ry, ry, group->meth));
+	MP_CHECKOK(group->meth->field_sub(ry, C3, ry, group->meth));
+
+	/* raz4 = a * rz^4 */
+	MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth));
+	MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth));
+	MP_CHECKOK(group->meth->
+			   field_mul(raz4, &group->curvea, raz4, group->meth));
+CLEANUP:
+	return res;
+}
+
+/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
+ * curve points P and R can be identical. Uses mixed Modified-Jacobian
+ * co-ordinates for doubling and Chudnovsky Jacobian coordinates for
+ * additions. Assumes input is already field-encoded using field_enc, and
+ * returns output that is still field-encoded. Uses 5-bit window NAF
+ * method (algorithm 11) for scalar-point multiplication from Brown,
+ * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic 
+ * Curves Over Prime Fields. */
+mp_err
+ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
+					  mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+	mp_err res = MP_OKAY;
+	mp_int precomp[16][2], rz, tpx, tpy;
+	mp_int raz4;
+	mp_int scratch[MAX_SCRATCH];
+	signed char *naf = NULL;
+	int i, orderBitSize;
+
+	MP_DIGITS(&rz) = 0;
+	MP_DIGITS(&raz4) = 0;
+	MP_DIGITS(&tpx) = 0;
+	MP_DIGITS(&tpy) = 0;
+	for (i = 0; i < 16; i++) {
+		MP_DIGITS(&precomp[i][0]) = 0;
+		MP_DIGITS(&precomp[i][1]) = 0;
+	}
+	for (i = 0; i < MAX_SCRATCH; i++) {
+		MP_DIGITS(&scratch[i]) = 0;
+	}
+
+	ARGCHK(group != NULL, MP_BADARG);
+	ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
+
+	/* initialize precomputation table */
+	MP_CHECKOK(mp_init(&tpx));
+	MP_CHECKOK(mp_init(&tpy));;
+	MP_CHECKOK(mp_init(&rz));
+	MP_CHECKOK(mp_init(&raz4));
+
+	for (i = 0; i < 16; i++) {
+		MP_CHECKOK(mp_init(&precomp[i][0]));
+		MP_CHECKOK(mp_init(&precomp[i][1]));
+	}
+	for (i = 0; i < MAX_SCRATCH; i++) {
+		MP_CHECKOK(mp_init(&scratch[i]));
+	}
+
+	/* Set out[8] = P */
+	MP_CHECKOK(mp_copy(px, &precomp[8][0]));
+	MP_CHECKOK(mp_copy(py, &precomp[8][1]));
+
+	/* Set (tpx, tpy) = 2P */
+	MP_CHECKOK(group->
+			   point_dbl(&precomp[8][0], &precomp[8][1], &tpx, &tpy,
+						 group));
+
+	/* Set 3P, 5P, ..., 15P */
+	for (i = 8; i < 15; i++) {
+		MP_CHECKOK(group->
+				   point_add(&precomp[i][0], &precomp[i][1], &tpx, &tpy,
+							 &precomp[i + 1][0], &precomp[i + 1][1],
+							 group));
+	}
+
+	/* Set -15P, -13P, ..., -P */
+	for (i = 0; i < 8; i++) {
+		MP_CHECKOK(mp_copy(&precomp[15 - i][0], &precomp[i][0]));
+		MP_CHECKOK(group->meth->
+				   field_neg(&precomp[15 - i][1], &precomp[i][1],
+							 group->meth));
+	}
+
+	/* R = inf */
+	MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
+
+	orderBitSize = mpl_significant_bits(&group->order);
+
+	/* Allocate memory for NAF */
+	naf = (signed char *) malloc(sizeof(signed char) * (orderBitSize + 1));
+	if (naf == NULL) {
+		res = MP_MEM;
+		goto CLEANUP;
+	}
+
+	/* Compute 5NAF */
+	ec_compute_wNAF(naf, orderBitSize, n, 5);
+
+	/* wNAF method */
+	for (i = orderBitSize; i >= 0; i--) {
+		/* R = 2R */
+		ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz, 
+					     &raz4, scratch, group);
+		if (naf[i] != 0) {
+			ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4,
+								 &precomp[(naf[i] + 15) / 2][0],
+								 &precomp[(naf[i] + 15) / 2][1], rx, ry,
+								 &rz, &raz4, scratch, group);
+		}
+	}
+
+	/* convert result S to affine coordinates */
+	MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
+
+  CLEANUP:
+	for (i = 0; i < MAX_SCRATCH; i++) {
+		mp_clear(&scratch[i]);
+	}
+	for (i = 0; i < 16; i++) {
+		mp_clear(&precomp[i][0]);
+		mp_clear(&precomp[i][1]);
+	}
+	mp_clear(&tpx);
+	mp_clear(&tpy);
+	mp_clear(&rz);
+	mp_clear(&raz4);
+	free(naf);
+	return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_mont.c b/mozilla/security/nss/lib/freebl/ecl/ecp_mont.c
new file mode 100644
index 0000000..c8829b6
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_mont.c
@@ -0,0 +1,192 @@
+/* 
+ * ***** 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 elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+/* Uses Montgomery reduction for field arithmetic.  See mpi/mpmontg.c for
+ * code implementation. */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#include "ecl-priv.h"
+#include "ecp.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Construct a generic GFMethod for arithmetic over prime fields with
+ * irreducible irr. */
+GFMethod *
+GFMethod_consGFp_mont(const mp_int *irr)
+{
+	mp_err res = MP_OKAY;
+	int i;
+	GFMethod *meth = NULL;
+	mp_mont_modulus *mmm;
+
+	meth = GFMethod_consGFp(irr);
+	if (meth == NULL)
+		return NULL;
+
+	mmm = (mp_mont_modulus *) malloc(sizeof(mp_mont_modulus));
+	if (mmm == NULL) {
+		res = MP_MEM;
+		goto CLEANUP;
+	}
+
+	meth->field_mul = &ec_GFp_mul_mont;
+	meth->field_sqr = &ec_GFp_sqr_mont;
+	meth->field_div = &ec_GFp_div_mont;
+	meth->field_enc = &ec_GFp_enc_mont;
+	meth->field_dec = &ec_GFp_dec_mont;
+	meth->extra1 = mmm;
+	meth->extra2 = NULL;
+	meth->extra_free = &ec_GFp_extra_free_mont;
+
+	mmm->N = meth->irr;
+	i = mpl_significant_bits(&meth->irr);
+	i += MP_DIGIT_BIT - 1;
+	mmm->b = i - i % MP_DIGIT_BIT;
+	mmm->n0prime = 0 - s_mp_invmod_radix(MP_DIGIT(&meth->irr, 0));
+
+  CLEANUP:
+	if (res != MP_OKAY) {
+		GFMethod_free(meth);
+		return NULL;
+	}
+	return meth;
+}
+
+/* Wrapper functions for generic prime field arithmetic. */
+
+/* Field multiplication using Montgomery reduction. */
+mp_err
+ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r,
+				const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+
+#ifdef MP_MONT_USE_MP_MUL
+	/* if MP_MONT_USE_MP_MUL is defined, then the function s_mp_mul_mont
+	 * is not implemented and we have to use mp_mul and s_mp_redc directly 
+	 */
+	MP_CHECKOK(mp_mul(a, b, r));
+	MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1));
+#else
+	mp_int s;
+
+	MP_DIGITS(&s) = 0;
+	/* s_mp_mul_mont doesn't allow source and destination to be the same */
+	if ((a == r) || (b == r)) {
+		MP_CHECKOK(mp_init(&s));
+		MP_CHECKOK(s_mp_mul_mont
+				   (a, b, &s, (mp_mont_modulus *) meth->extra1));
+		MP_CHECKOK(mp_copy(&s, r));
+		mp_clear(&s);
+	} else {
+		return s_mp_mul_mont(a, b, r, (mp_mont_modulus *) meth->extra1);
+	}
+#endif
+  CLEANUP:
+	return res;
+}
+
+/* Field squaring using Montgomery reduction. */
+mp_err
+ec_GFp_sqr_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	return ec_GFp_mul_mont(a, a, r, meth);
+}
+
+/* Field division using Montgomery reduction. */
+mp_err
+ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r,
+				const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+
+	/* if A=aZ represents a encoded in montgomery coordinates with Z and # 
+	 * and \ respectively represent multiplication and division in
+	 * montgomery coordinates, then A\B = (a/b)Z = (A/B)Z and Binv =
+	 * (1/b)Z = (1/B)(Z^2) where B # Binv = Z */
+	MP_CHECKOK(ec_GFp_div(a, b, r, meth));
+	MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
+	if (a == NULL) {
+		MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
+	}
+  CLEANUP:
+	return res;
+}
+
+/* Encode a field element in Montgomery form. See s_mp_to_mont in
+ * mpi/mpmontg.c */
+mp_err
+ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	mp_mont_modulus *mmm;
+	mp_err res = MP_OKAY;
+
+	mmm = (mp_mont_modulus *) meth->extra1;
+	MP_CHECKOK(mpl_lsh(a, r, mmm->b));
+	MP_CHECKOK(mp_mod(r, &mmm->N, r));
+  CLEANUP:
+	return res;
+}
+
+/* Decode a field element from Montgomery form. */
+mp_err
+ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+	mp_err res = MP_OKAY;
+
+	if (a != r) {
+		MP_CHECKOK(mp_copy(a, r));
+	}
+	MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1));
+  CLEANUP:
+	return res;
+}
+
+/* Free the memory allocated to the extra fields of Montgomery GFMethod
+ * object. */
+void
+ec_GFp_extra_free_mont(GFMethod *meth)
+{
+	if (meth->extra1 != NULL) {
+		free(meth->extra1);
+		meth->extra1 = NULL;
+	}
+}
diff --git a/mozilla/security/nss/lib/freebl/hasht.h b/mozilla/security/nss/lib/freebl/hasht.h
new file mode 100644
index 0000000..fd2332a
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/hasht.h
@@ -0,0 +1,102 @@
+/* ***** 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 ***** */
+/* $Id: hasht.h,v 1.7 2008/12/10 22:48:03 wtchang%redhat.com Exp $ */
+
+#ifndef _HASHT_H_
+#define _HASHT_H_
+
+/* Opaque objects */
+typedef struct SECHashObjectStr SECHashObject;
+typedef struct HASHContextStr HASHContext;
+
+/*
+ * The hash functions the security library supports
+ * NOTE the order must match the definition of SECHashObjects[]!
+ */
+typedef enum {
+    HASH_AlgNULL   = 0,
+    HASH_AlgMD2    = 1,
+    HASH_AlgMD5    = 2,
+    HASH_AlgSHA1   = 3,
+    HASH_AlgSHA256 = 4,
+    HASH_AlgSHA384 = 5,
+    HASH_AlgSHA512 = 6,
+    HASH_AlgTOTAL
+} HASH_HashType;
+
+/*
+ * Number of bytes each hash algorithm produces
+ */
+#define MD2_LENGTH	16
+#define MD5_LENGTH	16
+#define SHA1_LENGTH	20
+#define SHA256_LENGTH 	32
+#define SHA384_LENGTH 	48
+#define SHA512_LENGTH 	64
+#define HASH_LENGTH_MAX SHA512_LENGTH
+
+/*
+ * Structure to hold hash computation info and routines
+ */
+struct SECHashObjectStr {
+    unsigned int length;  /* hash output length (in bytes) */
+    void * (*create)(void);
+    void * (*clone)(void *);
+    void (*destroy)(void *, PRBool);
+    void (*begin)(void *);
+    void (*update)(void *, const unsigned char *, unsigned int);
+    void (*end)(void *, unsigned char *, unsigned int *, unsigned int);
+    unsigned int blocklength;  /* hash input block size (in bytes) */
+    HASH_HashType type;
+};
+
+struct HASHContextStr {
+    const struct SECHashObjectStr *hashobj;
+    void *hash_context;
+};
+
+/* This symbol is NOT exported from the NSS DLL.  Code that needs a 
+ * pointer to one of the SECHashObjects should call HASH_GetHashObject()
+ * instead. See "sechash.h".
+ */
+extern const SECHashObject SECHashObjects[];
+
+/* Only those functions below the PKCS #11 line should use SECRawHashObjects.
+ * This symbol is not exported from the NSS DLL.
+ */
+extern const SECHashObject SECRawHashObjects[];
+
+#endif /* _HASHT_H_ */
diff --git a/mozilla/security/nss/lib/freebl/md2.c b/mozilla/security/nss/lib/freebl/md2.c
new file mode 100644
index 0000000..04af3eb
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/md2.c
@@ -0,0 +1,300 @@
+/* ***** 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prerr.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+
+#include "blapi.h"
+
+#define MD2_DIGEST_LEN    16
+#define MD2_BUFSIZE       16
+#define MD2_X_SIZE        48  /* The X array, [CV | INPUT | TMP VARS] */
+#define MD2_CV             0  /* index into X for chaining variables */
+#define MD2_INPUT         16  /* index into X for input */
+#define MD2_TMPVARS       32  /* index into X for temporary variables */
+#define MD2_CHECKSUM_SIZE 16
+
+struct MD2ContextStr {
+	unsigned char checksum[MD2_BUFSIZE];
+	unsigned char X[MD2_X_SIZE];
+	PRUint8 unusedBuffer;
+};
+
+static const PRUint8 MD2S[256] = {
+ 0051, 0056, 0103, 0311, 0242, 0330, 0174, 0001,
+ 0075, 0066, 0124, 0241, 0354, 0360, 0006, 0023,
+ 0142, 0247, 0005, 0363, 0300, 0307, 0163, 0214,
+ 0230, 0223, 0053, 0331, 0274, 0114, 0202, 0312,
+ 0036, 0233, 0127, 0074, 0375, 0324, 0340, 0026,
+ 0147, 0102, 0157, 0030, 0212, 0027, 0345, 0022,
+ 0276, 0116, 0304, 0326, 0332, 0236, 0336, 0111,
+ 0240, 0373, 0365, 0216, 0273, 0057, 0356, 0172,
+ 0251, 0150, 0171, 0221, 0025, 0262, 0007, 0077,
+ 0224, 0302, 0020, 0211, 0013, 0042, 0137, 0041,
+ 0200, 0177, 0135, 0232, 0132, 0220, 0062, 0047,
+ 0065, 0076, 0314, 0347, 0277, 0367, 0227, 0003,
+ 0377, 0031, 0060, 0263, 0110, 0245, 0265, 0321,
+ 0327, 0136, 0222, 0052, 0254, 0126, 0252, 0306,
+ 0117, 0270, 0070, 0322, 0226, 0244, 0175, 0266,
+ 0166, 0374, 0153, 0342, 0234, 0164, 0004, 0361,
+ 0105, 0235, 0160, 0131, 0144, 0161, 0207, 0040,
+ 0206, 0133, 0317, 0145, 0346, 0055, 0250, 0002,
+ 0033, 0140, 0045, 0255, 0256, 0260, 0271, 0366,
+ 0034, 0106, 0141, 0151, 0064, 0100, 0176, 0017,
+ 0125, 0107, 0243, 0043, 0335, 0121, 0257, 0072,
+ 0303, 0134, 0371, 0316, 0272, 0305, 0352, 0046,
+ 0054, 0123, 0015, 0156, 0205, 0050, 0204, 0011,
+ 0323, 0337, 0315, 0364, 0101, 0201, 0115, 0122,
+ 0152, 0334, 0067, 0310, 0154, 0301, 0253, 0372,
+ 0044, 0341, 0173, 0010, 0014, 0275, 0261, 0112,
+ 0170, 0210, 0225, 0213, 0343, 0143, 0350, 0155,
+ 0351, 0313, 0325, 0376, 0073, 0000, 0035, 0071,
+ 0362, 0357, 0267, 0016, 0146, 0130, 0320, 0344,
+ 0246, 0167, 0162, 0370, 0353, 0165, 0113, 0012,
+ 0061, 0104, 0120, 0264, 0217, 0355, 0037, 0032,
+ 0333, 0231, 0215, 0063, 0237, 0021, 0203, 0024
+};
+
+SECStatus 
+MD2_Hash(unsigned char *dest, const char *src)
+{
+	unsigned int len;
+	MD2Context *cx = MD2_NewContext();
+	if (!cx) {
+		PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
+		return SECFailure;
+	}
+	MD2_Begin(cx);
+	MD2_Update(cx, (const unsigned char *)src, PORT_Strlen(src));
+	MD2_End(cx, dest, &len, MD2_DIGEST_LEN);
+	MD2_DestroyContext(cx, PR_TRUE);
+	return SECSuccess;
+}
+
+MD2Context *
+MD2_NewContext(void)
+{
+	MD2Context *cx = (MD2Context *)PORT_ZAlloc(sizeof(MD2Context));
+	if (cx == NULL) {
+		PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
+		return NULL;
+	}
+	return cx;
+}
+
+void 
+MD2_DestroyContext(MD2Context *cx, PRBool freeit)
+{
+	if (freeit)
+		PORT_ZFree(cx, sizeof(*cx));
+}
+
+void 
+MD2_Begin(MD2Context *cx)
+{
+	memset(cx, 0, sizeof(*cx));
+	cx->unusedBuffer = MD2_BUFSIZE;
+}
+
+static void
+md2_compress(MD2Context *cx)
+{
+	int j;
+	unsigned char P;
+	P = cx->checksum[MD2_CHECKSUM_SIZE-1];
+	/* Compute the running checksum, and set the tmp variables to be 
+	 * CV[i] XOR input[i] 
+	 */
+#define CKSUMFN(n) \
+	P = cx->checksum[n] ^ MD2S[cx->X[MD2_INPUT+n] ^ P]; \
+	cx->checksum[n] = P; \
+	cx->X[MD2_TMPVARS+n] = cx->X[n] ^ cx->X[MD2_INPUT+n];
+	CKSUMFN(0);
+	CKSUMFN(1);
+	CKSUMFN(2);
+	CKSUMFN(3);
+	CKSUMFN(4);
+	CKSUMFN(5);
+	CKSUMFN(6);
+	CKSUMFN(7);
+	CKSUMFN(8);
+	CKSUMFN(9);
+	CKSUMFN(10);
+	CKSUMFN(11);
+	CKSUMFN(12);
+	CKSUMFN(13);
+	CKSUMFN(14);
+	CKSUMFN(15);
+	/* The compression function. */
+#define COMPRESS(n) \
+	P = cx->X[n] ^ MD2S[P]; \
+	cx->X[n] = P;
+	P = 0x00;
+	for (j=0; j<18; j++) {
+		COMPRESS(0);
+		COMPRESS(1);
+		COMPRESS(2);
+		COMPRESS(3);
+		COMPRESS(4);
+		COMPRESS(5);
+		COMPRESS(6);
+		COMPRESS(7);
+		COMPRESS(8);
+		COMPRESS(9);
+		COMPRESS(10);
+		COMPRESS(11);
+		COMPRESS(12);
+		COMPRESS(13);
+		COMPRESS(14);
+		COMPRESS(15);
+		COMPRESS(16);
+		COMPRESS(17);
+		COMPRESS(18);
+		COMPRESS(19);
+		COMPRESS(20);
+		COMPRESS(21);
+		COMPRESS(22);
+		COMPRESS(23);
+		COMPRESS(24);
+		COMPRESS(25);
+		COMPRESS(26);
+		COMPRESS(27);
+		COMPRESS(28);
+		COMPRESS(29);
+		COMPRESS(30);
+		COMPRESS(31);
+		COMPRESS(32);
+		COMPRESS(33);
+		COMPRESS(34);
+		COMPRESS(35);
+		COMPRESS(36);
+		COMPRESS(37);
+		COMPRESS(38);
+		COMPRESS(39);
+		COMPRESS(40);
+		COMPRESS(41);
+		COMPRESS(42);
+		COMPRESS(43);
+		COMPRESS(44);
+		COMPRESS(45);
+		COMPRESS(46);
+		COMPRESS(47);
+		P = (P + j) % 256;
+	}
+	cx->unusedBuffer = MD2_BUFSIZE;
+}
+
+void 
+MD2_Update(MD2Context *cx, const unsigned char *input, unsigned int inputLen)
+{
+	PRUint32 bytesToConsume;
+	
+	/* Fill the remaining input buffer. */
+	if (cx->unusedBuffer != MD2_BUFSIZE) {
+		bytesToConsume = PR_MIN(inputLen, cx->unusedBuffer);
+		memcpy(&cx->X[MD2_INPUT + (MD2_BUFSIZE - cx->unusedBuffer)],
+		            input, bytesToConsume);
+		if (cx->unusedBuffer + bytesToConsume >= MD2_BUFSIZE)
+			md2_compress(cx);
+		inputLen -= bytesToConsume;
+		input += bytesToConsume;
+	}
+
+	/* Iterate over 16-byte chunks of the input. */
+	while (inputLen >= MD2_BUFSIZE) {
+		memcpy(&cx->X[MD2_INPUT], input, MD2_BUFSIZE);
+		md2_compress(cx);
+		inputLen -= MD2_BUFSIZE;
+		input += MD2_BUFSIZE;
+	}
+
+	/* Copy any input that remains into the buffer. */
+	if (inputLen)
+		memcpy(&cx->X[MD2_INPUT], input, inputLen);
+	cx->unusedBuffer = MD2_BUFSIZE - inputLen;
+}
+
+void 
+MD2_End(MD2Context *cx, unsigned char *digest,
+        unsigned int *digestLen, unsigned int maxDigestLen)
+{
+	PRUint8 padStart;
+	if (maxDigestLen < MD2_BUFSIZE) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return;
+	}
+	padStart = MD2_BUFSIZE - cx->unusedBuffer;
+	memset(&cx->X[MD2_INPUT + padStart], cx->unusedBuffer, 
+	            cx->unusedBuffer);
+	md2_compress(cx);
+	memcpy(&cx->X[MD2_INPUT], cx->checksum, MD2_BUFSIZE);
+	md2_compress(cx);
+	*digestLen = MD2_DIGEST_LEN;
+	memcpy(digest, &cx->X[MD2_CV], MD2_DIGEST_LEN);
+}
+
+unsigned int 
+MD2_FlattenSize(MD2Context *cx)
+{
+	return sizeof(*cx);
+}
+
+SECStatus 
+MD2_Flatten(MD2Context *cx, unsigned char *space)
+{
+	memcpy(space, cx, sizeof(*cx));
+	return SECSuccess;
+}
+
+MD2Context * 
+MD2_Resurrect(unsigned char *space, void *arg)
+{
+	MD2Context *cx = MD2_NewContext();
+	if (cx)
+		memcpy(cx, space, sizeof(*cx));
+	return cx;
+}
+
+void MD2_Clone(MD2Context *dest, MD2Context *src) 
+{
+	memcpy(dest, src, sizeof *dest);
+}
diff --git a/mozilla/security/nss/lib/freebl/md5.c b/mozilla/security/nss/lib/freebl/md5.c
new file mode 100644
index 0000000..4acfe74
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/md5.c
@@ -0,0 +1,599 @@
+/* ***** 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prerr.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+#include "prlong.h"
+
+#include "blapi.h"
+
+#define MD5_HASH_LEN 16
+#define MD5_BUFFER_SIZE 64
+#define MD5_END_BUFFER (MD5_BUFFER_SIZE - 8)
+
+#define CV0_1 0x67452301
+#define CV0_2 0xefcdab89
+#define CV0_3 0x98badcfe
+#define CV0_4 0x10325476
+
+#define T1_0  0xd76aa478
+#define T1_1  0xe8c7b756
+#define T1_2  0x242070db
+#define T1_3  0xc1bdceee
+#define T1_4  0xf57c0faf
+#define T1_5  0x4787c62a
+#define T1_6  0xa8304613
+#define T1_7  0xfd469501
+#define T1_8  0x698098d8
+#define T1_9  0x8b44f7af
+#define T1_10 0xffff5bb1
+#define T1_11 0x895cd7be
+#define T1_12 0x6b901122
+#define T1_13 0xfd987193
+#define T1_14 0xa679438e
+#define T1_15 0x49b40821
+
+#define T2_0  0xf61e2562
+#define T2_1  0xc040b340
+#define T2_2  0x265e5a51
+#define T2_3  0xe9b6c7aa
+#define T2_4  0xd62f105d
+#define T2_5  0x02441453
+#define T2_6  0xd8a1e681
+#define T2_7  0xe7d3fbc8
+#define T2_8  0x21e1cde6
+#define T2_9  0xc33707d6
+#define T2_10 0xf4d50d87
+#define T2_11 0x455a14ed
+#define T2_12 0xa9e3e905
+#define T2_13 0xfcefa3f8
+#define T2_14 0x676f02d9
+#define T2_15 0x8d2a4c8a
+
+#define T3_0  0xfffa3942
+#define T3_1  0x8771f681
+#define T3_2  0x6d9d6122
+#define T3_3  0xfde5380c
+#define T3_4  0xa4beea44
+#define T3_5  0x4bdecfa9
+#define T3_6  0xf6bb4b60
+#define T3_7  0xbebfbc70
+#define T3_8  0x289b7ec6
+#define T3_9  0xeaa127fa
+#define T3_10 0xd4ef3085
+#define T3_11 0x04881d05
+#define T3_12 0xd9d4d039
+#define T3_13 0xe6db99e5
+#define T3_14 0x1fa27cf8
+#define T3_15 0xc4ac5665
+
+#define T4_0  0xf4292244
+#define T4_1  0x432aff97
+#define T4_2  0xab9423a7
+#define T4_3  0xfc93a039
+#define T4_4  0x655b59c3
+#define T4_5  0x8f0ccc92
+#define T4_6  0xffeff47d
+#define T4_7  0x85845dd1
+#define T4_8  0x6fa87e4f
+#define T4_9  0xfe2ce6e0
+#define T4_10 0xa3014314
+#define T4_11 0x4e0811a1
+#define T4_12 0xf7537e82
+#define T4_13 0xbd3af235
+#define T4_14 0x2ad7d2bb
+#define T4_15 0xeb86d391
+
+#define R1B0  0
+#define R1B1  1
+#define R1B2  2
+#define R1B3  3
+#define R1B4  4
+#define R1B5  5
+#define R1B6  6
+#define R1B7  7
+#define R1B8  8
+#define R1B9  9
+#define R1B10 10
+#define R1B11 11
+#define R1B12 12
+#define R1B13 13
+#define R1B14 14
+#define R1B15 15
+
+#define R2B0  1
+#define R2B1  6
+#define R2B2  11
+#define R2B3  0
+#define R2B4  5
+#define R2B5  10
+#define R2B6  15
+#define R2B7  4
+#define R2B8  9
+#define R2B9  14
+#define R2B10 3 
+#define R2B11 8 
+#define R2B12 13
+#define R2B13 2 
+#define R2B14 7 
+#define R2B15 12
+
+#define R3B0  5
+#define R3B1  8
+#define R3B2  11
+#define R3B3  14
+#define R3B4  1
+#define R3B5  4
+#define R3B6  7
+#define R3B7  10
+#define R3B8  13
+#define R3B9  0
+#define R3B10 3 
+#define R3B11 6 
+#define R3B12 9 
+#define R3B13 12
+#define R3B14 15
+#define R3B15 2 
+
+#define R4B0  0
+#define R4B1  7
+#define R4B2  14
+#define R4B3  5
+#define R4B4  12
+#define R4B5  3
+#define R4B6  10
+#define R4B7  1
+#define R4B8  8
+#define R4B9  15
+#define R4B10 6 
+#define R4B11 13
+#define R4B12 4 
+#define R4B13 11
+#define R4B14 2 
+#define R4B15 9 
+
+#define S1_0 7
+#define S1_1 12
+#define S1_2 17
+#define S1_3 22
+
+#define S2_0 5
+#define S2_1 9
+#define S2_2 14
+#define S2_3 20
+
+#define S3_0 4
+#define S3_1 11
+#define S3_2 16
+#define S3_3 23
+
+#define S4_0 6
+#define S4_1 10
+#define S4_2 15
+#define S4_3 21
+
+struct MD5ContextStr {
+	PRUint32      lsbInput;
+	PRUint32      msbInput;
+	PRUint32      cv[4];
+	union {
+		PRUint8 b[64];
+		PRUint32 w[16];
+	} u;
+};
+
+#define inBuf u.b
+
+SECStatus 
+MD5_Hash(unsigned char *dest, const char *src)
+{
+	return MD5_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+SECStatus 
+MD5_HashBuf(unsigned char *dest, const unsigned char *src, uint32 src_length)
+{
+	unsigned int len;
+	MD5Context cx;
+
+	MD5_Begin(&cx);
+	MD5_Update(&cx, src, src_length);
+	MD5_End(&cx, dest, &len, MD5_HASH_LEN);
+/*	memset(&cx, 0, sizeof cx); */
+	return SECSuccess;
+}
+
+MD5Context *
+MD5_NewContext(void)
+{
+	/* no need to ZAlloc, MD5_Begin will init the context */
+	MD5Context *cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context));
+	if (cx == NULL) {
+		PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
+		return NULL;
+	}
+	return cx;
+}
+
+void 
+MD5_DestroyContext(MD5Context *cx, PRBool freeit)
+{
+/*	memset(cx, 0, sizeof *cx); */
+	if (freeit) {
+	    PORT_Free(cx);
+	}
+}
+
+void 
+MD5_Begin(MD5Context *cx)
+{
+	cx->lsbInput = 0;
+	cx->msbInput = 0;
+/*	memset(cx->inBuf, 0, sizeof(cx->inBuf)); */
+	cx->cv[0] = CV0_1;
+	cx->cv[1] = CV0_2;
+	cx->cv[2] = CV0_3;
+	cx->cv[3] = CV0_4;
+}
+
+#define cls(i32, s) (tmp = i32, tmp << s | tmp >> (32 - s))
+
+#if defined(SOLARIS) || defined(HPUX)
+#define addto64(sumhigh, sumlow, addend) \
+	sumlow += addend; sumhigh += (sumlow < addend);
+#else
+#define addto64(sumhigh, sumlow, addend) \
+	sumlow += addend; if (sumlow < addend) ++sumhigh;
+#endif
+
+#define MASK 0x00ff00ff
+#ifdef IS_LITTLE_ENDIAN
+#define lendian(i32) \
+	(i32)
+#else
+#define lendian(i32) \
+	(tmp = i32 >> 16 | i32 << 16, (tmp & MASK) << 8 | tmp >> 8 & MASK)
+#endif
+
+#ifndef IS_LITTLE_ENDIAN
+
+#define lebytes(b4) \
+	((b4)[3] << 24 | (b4)[2] << 16 | (b4)[1] << 8 | (b4)[0])
+
+static void
+md5_prep_state_le(MD5Context *cx)
+{
+	PRUint32 tmp;
+	cx->u.w[0] = lendian(cx->u.w[0]);
+	cx->u.w[1] = lendian(cx->u.w[1]);
+	cx->u.w[2] = lendian(cx->u.w[2]);
+	cx->u.w[3] = lendian(cx->u.w[3]);
+	cx->u.w[4] = lendian(cx->u.w[4]);
+	cx->u.w[5] = lendian(cx->u.w[5]);
+	cx->u.w[6] = lendian(cx->u.w[6]);
+	cx->u.w[7] = lendian(cx->u.w[7]);
+	cx->u.w[8] = lendian(cx->u.w[8]);
+	cx->u.w[9] = lendian(cx->u.w[9]);
+	cx->u.w[10] = lendian(cx->u.w[10]);
+	cx->u.w[11] = lendian(cx->u.w[11]);
+	cx->u.w[12] = lendian(cx->u.w[12]);
+	cx->u.w[13] = lendian(cx->u.w[13]);
+	cx->u.w[14] = lendian(cx->u.w[14]);
+	cx->u.w[15] = lendian(cx->u.w[15]);
+}
+
+static void
+md5_prep_buffer_le(MD5Context *cx, const PRUint8 *beBuf)
+{
+	cx->u.w[0] = lebytes(&beBuf[0]);
+	cx->u.w[1] = lebytes(&beBuf[4]);
+	cx->u.w[2] = lebytes(&beBuf[8]);
+	cx->u.w[3] = lebytes(&beBuf[12]);
+	cx->u.w[4] = lebytes(&beBuf[16]);
+	cx->u.w[5] = lebytes(&beBuf[20]);
+	cx->u.w[6] = lebytes(&beBuf[24]);
+	cx->u.w[7] = lebytes(&beBuf[28]);
+	cx->u.w[8] = lebytes(&beBuf[32]);
+	cx->u.w[9] = lebytes(&beBuf[36]);
+	cx->u.w[10] = lebytes(&beBuf[40]);
+	cx->u.w[11] = lebytes(&beBuf[44]);
+	cx->u.w[12] = lebytes(&beBuf[48]);
+	cx->u.w[13] = lebytes(&beBuf[52]);
+	cx->u.w[14] = lebytes(&beBuf[56]);
+	cx->u.w[15] = lebytes(&beBuf[60]);
+}
+#endif
+
+
+#define F(X, Y, Z) \
+	((X & Y) | ((~X) & Z))
+
+#define G(X, Y, Z) \
+	((X & Z) | (Y & (~Z)))
+
+#define H(X, Y, Z) \
+	(X ^ Y ^ Z)
+
+#define I(X, Y, Z) \
+	(Y ^ (X | (~Z)))
+
+#define FF(a, b, c, d, bufint, s, ti) \
+	a = b + cls(a + F(b, c, d) + bufint + ti, s)
+
+#define GG(a, b, c, d, bufint, s, ti) \
+	a = b + cls(a + G(b, c, d) + bufint + ti, s)
+
+#define HH(a, b, c, d, bufint, s, ti) \
+	a = b + cls(a + H(b, c, d) + bufint + ti, s)
+
+#define II(a, b, c, d, bufint, s, ti) \
+	a = b + cls(a + I(b, c, d) + bufint + ti, s)
+
+static void
+md5_compress(MD5Context *cx, const PRUint32 *wBuf)
+{
+	PRUint32 a, b, c, d;
+	PRUint32 tmp;
+	a = cx->cv[0];
+	b = cx->cv[1];
+	c = cx->cv[2];
+	d = cx->cv[3];
+	FF(a, b, c, d, wBuf[R1B0 ], S1_0, T1_0);
+	FF(d, a, b, c, wBuf[R1B1 ], S1_1, T1_1);
+	FF(c, d, a, b, wBuf[R1B2 ], S1_2, T1_2);
+	FF(b, c, d, a, wBuf[R1B3 ], S1_3, T1_3);
+	FF(a, b, c, d, wBuf[R1B4 ], S1_0, T1_4);
+	FF(d, a, b, c, wBuf[R1B5 ], S1_1, T1_5);
+	FF(c, d, a, b, wBuf[R1B6 ], S1_2, T1_6);
+	FF(b, c, d, a, wBuf[R1B7 ], S1_3, T1_7);
+	FF(a, b, c, d, wBuf[R1B8 ], S1_0, T1_8);
+	FF(d, a, b, c, wBuf[R1B9 ], S1_1, T1_9);
+	FF(c, d, a, b, wBuf[R1B10], S1_2, T1_10);
+	FF(b, c, d, a, wBuf[R1B11], S1_3, T1_11);
+	FF(a, b, c, d, wBuf[R1B12], S1_0, T1_12);
+	FF(d, a, b, c, wBuf[R1B13], S1_1, T1_13);
+	FF(c, d, a, b, wBuf[R1B14], S1_2, T1_14);
+	FF(b, c, d, a, wBuf[R1B15], S1_3, T1_15);
+	GG(a, b, c, d, wBuf[R2B0 ], S2_0, T2_0);
+	GG(d, a, b, c, wBuf[R2B1 ], S2_1, T2_1);
+	GG(c, d, a, b, wBuf[R2B2 ], S2_2, T2_2);
+	GG(b, c, d, a, wBuf[R2B3 ], S2_3, T2_3);
+	GG(a, b, c, d, wBuf[R2B4 ], S2_0, T2_4);
+	GG(d, a, b, c, wBuf[R2B5 ], S2_1, T2_5);
+	GG(c, d, a, b, wBuf[R2B6 ], S2_2, T2_6);
+	GG(b, c, d, a, wBuf[R2B7 ], S2_3, T2_7);
+	GG(a, b, c, d, wBuf[R2B8 ], S2_0, T2_8);
+	GG(d, a, b, c, wBuf[R2B9 ], S2_1, T2_9);
+	GG(c, d, a, b, wBuf[R2B10], S2_2, T2_10);
+	GG(b, c, d, a, wBuf[R2B11], S2_3, T2_11);
+	GG(a, b, c, d, wBuf[R2B12], S2_0, T2_12);
+	GG(d, a, b, c, wBuf[R2B13], S2_1, T2_13);
+	GG(c, d, a, b, wBuf[R2B14], S2_2, T2_14);
+	GG(b, c, d, a, wBuf[R2B15], S2_3, T2_15);
+	HH(a, b, c, d, wBuf[R3B0 ], S3_0, T3_0);
+	HH(d, a, b, c, wBuf[R3B1 ], S3_1, T3_1);
+	HH(c, d, a, b, wBuf[R3B2 ], S3_2, T3_2);
+	HH(b, c, d, a, wBuf[R3B3 ], S3_3, T3_3);
+	HH(a, b, c, d, wBuf[R3B4 ], S3_0, T3_4);
+	HH(d, a, b, c, wBuf[R3B5 ], S3_1, T3_5);
+	HH(c, d, a, b, wBuf[R3B6 ], S3_2, T3_6);
+	HH(b, c, d, a, wBuf[R3B7 ], S3_3, T3_7);
+	HH(a, b, c, d, wBuf[R3B8 ], S3_0, T3_8);
+	HH(d, a, b, c, wBuf[R3B9 ], S3_1, T3_9);
+	HH(c, d, a, b, wBuf[R3B10], S3_2, T3_10);
+	HH(b, c, d, a, wBuf[R3B11], S3_3, T3_11);
+	HH(a, b, c, d, wBuf[R3B12], S3_0, T3_12);
+	HH(d, a, b, c, wBuf[R3B13], S3_1, T3_13);
+	HH(c, d, a, b, wBuf[R3B14], S3_2, T3_14);
+	HH(b, c, d, a, wBuf[R3B15], S3_3, T3_15);
+	II(a, b, c, d, wBuf[R4B0 ], S4_0, T4_0);
+	II(d, a, b, c, wBuf[R4B1 ], S4_1, T4_1);
+	II(c, d, a, b, wBuf[R4B2 ], S4_2, T4_2);
+	II(b, c, d, a, wBuf[R4B3 ], S4_3, T4_3);
+	II(a, b, c, d, wBuf[R4B4 ], S4_0, T4_4);
+	II(d, a, b, c, wBuf[R4B5 ], S4_1, T4_5);
+	II(c, d, a, b, wBuf[R4B6 ], S4_2, T4_6);
+	II(b, c, d, a, wBuf[R4B7 ], S4_3, T4_7);
+	II(a, b, c, d, wBuf[R4B8 ], S4_0, T4_8);
+	II(d, a, b, c, wBuf[R4B9 ], S4_1, T4_9);
+	II(c, d, a, b, wBuf[R4B10], S4_2, T4_10);
+	II(b, c, d, a, wBuf[R4B11], S4_3, T4_11);
+	II(a, b, c, d, wBuf[R4B12], S4_0, T4_12);
+	II(d, a, b, c, wBuf[R4B13], S4_1, T4_13);
+	II(c, d, a, b, wBuf[R4B14], S4_2, T4_14);
+	II(b, c, d, a, wBuf[R4B15], S4_3, T4_15);
+	cx->cv[0] += a;
+	cx->cv[1] += b;
+	cx->cv[2] += c;
+	cx->cv[3] += d;
+}
+
+void 
+MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen)
+{
+	PRUint32 bytesToConsume;
+	PRUint32 inBufIndex = cx->lsbInput & 63;
+	const PRUint32 *wBuf;
+
+	/* Add the number of input bytes to the 64-bit input counter. */
+	addto64(cx->msbInput, cx->lsbInput, inputLen);
+	if (inBufIndex) {
+		/* There is already data in the buffer.  Fill with input. */
+		bytesToConsume = PR_MIN(inputLen, MD5_BUFFER_SIZE - inBufIndex);
+		memcpy(&cx->inBuf[inBufIndex], input, bytesToConsume);
+		if (inBufIndex + bytesToConsume >= MD5_BUFFER_SIZE) {
+			/* The buffer is filled.  Run the compression function. */
+#ifndef IS_LITTLE_ENDIAN
+			md5_prep_state_le(cx);
+#endif
+			md5_compress(cx, cx->u.w);
+		}
+		/* Remaining input. */
+		inputLen -= bytesToConsume;
+		input += bytesToConsume;
+	}
+
+	/* Iterate over 64-byte chunks of the message. */
+	while (inputLen >= MD5_BUFFER_SIZE) {
+#ifdef IS_LITTLE_ENDIAN
+#ifdef NSS_X86_OR_X64
+		/* x86 can handle arithmetic on non-word-aligned buffers */
+		wBuf = (PRUint32 *)input;
+#else
+		if ((ptrdiff_t)input & 0x3) {
+			/* buffer not aligned, copy it to force alignment */
+			memcpy(cx->inBuf, input, MD5_BUFFER_SIZE);
+			wBuf = cx->u.w;
+		} else {
+			/* buffer is aligned */
+			wBuf = (PRUint32 *)input;
+		}
+#endif
+#else
+		md5_prep_buffer_le(cx, input);
+		wBuf = cx->u.w;
+#endif
+		md5_compress(cx, wBuf);
+		inputLen -= MD5_BUFFER_SIZE;
+		input += MD5_BUFFER_SIZE;
+	}
+
+	/* Tail of message (message bytes mod 64). */
+	if (inputLen)
+		memcpy(cx->inBuf, input, inputLen);
+}
+
+static const unsigned char padbytes[] = {
+	0x80, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+	0x00, 0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00
+};
+
+void 
+MD5_End(MD5Context *cx, unsigned char *digest,
+        unsigned int *digestLen, unsigned int maxDigestLen)
+{
+#ifndef IS_LITTLE_ENDIAN
+	PRUint32 tmp;
+#endif
+	PRUint32 lowInput, highInput;
+	PRUint32 inBufIndex = cx->lsbInput & 63;
+
+	if (maxDigestLen < MD5_HASH_LEN) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return;
+	}
+
+	/* Copy out the length of bits input before padding. */
+	lowInput = cx->lsbInput; 
+	highInput = (cx->msbInput << 3) | (lowInput >> 29);
+	lowInput <<= 3;
+
+	if (inBufIndex < MD5_END_BUFFER) {
+		MD5_Update(cx, padbytes, MD5_END_BUFFER - inBufIndex);
+	} else {
+		MD5_Update(cx, padbytes, 
+		           MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex);
+	}
+
+	/* Store the number of bytes input (before padding) in final 64 bits. */
+	cx->u.w[14] = lendian(lowInput);
+	cx->u.w[15] = lendian(highInput);
+
+	/* Final call to compress. */
+#ifndef IS_LITTLE_ENDIAN
+	md5_prep_state_le(cx);
+#endif
+	md5_compress(cx, cx->u.w);
+
+	/* Copy the resulting values out of the chain variables into return buf. */
+	*digestLen = MD5_HASH_LEN;
+#ifndef IS_LITTLE_ENDIAN
+	cx->cv[0] = lendian(cx->cv[0]);
+	cx->cv[1] = lendian(cx->cv[1]);
+	cx->cv[2] = lendian(cx->cv[2]);
+	cx->cv[3] = lendian(cx->cv[3]);
+#endif
+	memcpy(digest, cx->cv, MD5_HASH_LEN);
+}
+
+unsigned int 
+MD5_FlattenSize(MD5Context *cx)
+{
+	return sizeof(*cx);
+}
+
+SECStatus 
+MD5_Flatten(MD5Context *cx, unsigned char *space)
+{
+	memcpy(space, cx, sizeof(*cx));
+	return SECSuccess;
+}
+
+MD5Context * 
+MD5_Resurrect(unsigned char *space, void *arg)
+{
+	MD5Context *cx = MD5_NewContext();
+	if (cx)
+		memcpy(cx, space, sizeof(*cx));
+	return cx;
+}
+
+void MD5_Clone(MD5Context *dest, MD5Context *src) 
+{
+	memcpy(dest, src, sizeof *dest);
+}
+
+void 
+MD5_TraceState(MD5Context *cx)
+{
+	PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+}
diff --git a/mozilla/security/nss/lib/freebl/mpi/logtab.h b/mozilla/security/nss/lib/freebl/mpi/logtab.h
new file mode 100644
index 0000000..41badfc
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/logtab.h
@@ -0,0 +1,62 @@
+/*
+ *  logtab.h
+ *
+ *  Arbitrary precision integer arithmetic library
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * 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 ***** */
+/* $Id: logtab.h,v 1.5 2004/04/27 23:04:36 gerv%gerv.net Exp $ */
+
+const float s_logv_2[] = {
+   0.000000000f, 0.000000000f, 1.000000000f, 0.630929754f,  /*  0  1  2  3 */
+   0.500000000f, 0.430676558f, 0.386852807f, 0.356207187f,  /*  4  5  6  7 */
+   0.333333333f, 0.315464877f, 0.301029996f, 0.289064826f,  /*  8  9 10 11 */
+   0.278942946f, 0.270238154f, 0.262649535f, 0.255958025f,  /* 12 13 14 15 */
+   0.250000000f, 0.244650542f, 0.239812467f, 0.235408913f,  /* 16 17 18 19 */
+   0.231378213f, 0.227670249f, 0.224243824f, 0.221064729f,  /* 20 21 22 23 */
+   0.218104292f, 0.215338279f, 0.212746054f, 0.210309918f,  /* 24 25 26 27 */
+   0.208014598f, 0.205846832f, 0.203795047f, 0.201849087f,  /* 28 29 30 31 */
+   0.200000000f, 0.198239863f, 0.196561632f, 0.194959022f,  /* 32 33 34 35 */
+   0.193426404f, 0.191958720f, 0.190551412f, 0.189200360f,  /* 36 37 38 39 */
+   0.187901825f, 0.186652411f, 0.185449023f, 0.184288833f,  /* 40 41 42 43 */
+   0.183169251f, 0.182087900f, 0.181042597f, 0.180031327f,  /* 44 45 46 47 */
+   0.179052232f, 0.178103594f, 0.177183820f, 0.176291434f,  /* 48 49 50 51 */
+   0.175425064f, 0.174583430f, 0.173765343f, 0.172969690f,  /* 52 53 54 55 */
+   0.172195434f, 0.171441601f, 0.170707280f, 0.169991616f,  /* 56 57 58 59 */
+   0.169293808f, 0.168613099f, 0.167948779f, 0.167300179f,  /* 60 61 62 63 */
+   0.166666667f
+};
+
diff --git a/mozilla/security/nss/lib/freebl/mpi/mp_gf2m-priv.h b/mozilla/security/nss/lib/freebl/mpi/mp_gf2m-priv.h
new file mode 100644
index 0000000..f93597d
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mp_gf2m-priv.h
@@ -0,0 +1,102 @@
+/*
+ * ***** 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 Multi-precision Binary Polynomial Arithmetic Library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sheueling Chang Shantz <sheueling.chang@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ * 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 ***** */
+
+#ifndef _MP_GF2M_PRIV_H_
+#define _MP_GF2M_PRIV_H_
+
+#include "mpi-priv.h"
+
+extern const mp_digit mp_gf2m_sqr_tb[16];
+
+#if defined(MP_USE_UINT_DIGIT)
+#define MP_DIGIT_BITS 32
+#else
+#define MP_DIGIT_BITS 64
+#endif
+
+/* Platform-specific macros for fast binary polynomial squaring. */
+#if MP_DIGIT_BITS == 32
+#define gf2m_SQR1(w) \
+    mp_gf2m_sqr_tb[(w) >> 28 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >> 24 & 0xF] << 16 | \
+    mp_gf2m_sqr_tb[(w) >> 20 & 0xF] <<  8 | mp_gf2m_sqr_tb[(w) >> 16 & 0xF]
+#define gf2m_SQR0(w) \
+    mp_gf2m_sqr_tb[(w) >> 12 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >>  8 & 0xF] << 16 | \
+    mp_gf2m_sqr_tb[(w) >>  4 & 0xF] <<  8 | mp_gf2m_sqr_tb[(w)       & 0xF]
+#else
+#define gf2m_SQR1(w) \
+    mp_gf2m_sqr_tb[(w) >> 60 & 0xF] << 56 | mp_gf2m_sqr_tb[(w) >> 56 & 0xF] << 48 | \
+    mp_gf2m_sqr_tb[(w) >> 52 & 0xF] << 40 | mp_gf2m_sqr_tb[(w) >> 48 & 0xF] << 32 | \
+    mp_gf2m_sqr_tb[(w) >> 44 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >> 40 & 0xF] << 16 | \
+    mp_gf2m_sqr_tb[(w) >> 36 & 0xF] <<  8 | mp_gf2m_sqr_tb[(w) >> 32 & 0xF]
+#define gf2m_SQR0(w) \
+    mp_gf2m_sqr_tb[(w) >> 28 & 0xF] << 56 | mp_gf2m_sqr_tb[(w) >> 24 & 0xF] << 48 | \
+    mp_gf2m_sqr_tb[(w) >> 20 & 0xF] << 40 | mp_gf2m_sqr_tb[(w) >> 16 & 0xF] << 32 | \
+    mp_gf2m_sqr_tb[(w) >> 12 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >>  8 & 0xF] << 16 | \
+    mp_gf2m_sqr_tb[(w) >>  4 & 0xF] <<  8 | mp_gf2m_sqr_tb[(w)       & 0xF]
+#endif
+
+/* Multiply two binary polynomials mp_digits a, b.
+ * Result is a polynomial with degree < 2 * MP_DIGIT_BITS - 1.
+ * Output in two mp_digits rh, rl.
+ */
+void s_bmul_1x1(mp_digit *rh, mp_digit *rl, const mp_digit a, const mp_digit b);
+
+/* Compute xor-multiply of two binary polynomials  (a1, a0) x (b1, b0)  
+ * result is a binary polynomial in 4 mp_digits r[4].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_2x2(mp_digit *r, const mp_digit a1, const mp_digit a0, const mp_digit b1,
+	const mp_digit b0);
+
+/* Compute xor-multiply of two binary polynomials  (a2, a1, a0) x (b2, b1, b0)  
+ * result is a binary polynomial in 6 mp_digits r[6].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_3x3(mp_digit *r, const mp_digit a2, const mp_digit a1, const mp_digit a0, 
+	const mp_digit b2, const mp_digit b1, const mp_digit b0);
+
+/* Compute xor-multiply of two binary polynomials  (a3, a2, a1, a0) x (b3, b2, b1, b0)  
+ * result is a binary polynomial in 8 mp_digits r[8].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_4x4(mp_digit *r, const mp_digit a3, const mp_digit a2, const mp_digit a1, 
+	const mp_digit a0, const mp_digit b3, const mp_digit b2, const mp_digit b1, 
+	const mp_digit b0);
+
+#endif /* _MP_GF2M_PRIV_H_ */
diff --git a/mozilla/security/nss/lib/freebl/mpi/mp_gf2m.c b/mozilla/security/nss/lib/freebl/mpi/mp_gf2m.c
new file mode 100644
index 0000000..a68e880
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mp_gf2m.c
@@ -0,0 +1,603 @@
+/*
+ * ***** 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 Multi-precision Binary Polynomial Arithmetic Library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sheueling Chang Shantz <sheueling.chang@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ * 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 "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+
+const mp_digit mp_gf2m_sqr_tb[16] =
+{
+      0,     1,     4,     5,    16,    17,    20,    21,
+     64,    65,    68,    69,    80,    81,    84,    85
+};
+
+/* Multiply two binary polynomials mp_digits a, b.
+ * Result is a polynomial with degree < 2 * MP_DIGIT_BITS - 1.
+ * Output in two mp_digits rh, rl.
+ */
+#if MP_DIGIT_BITS == 32
+void 
+s_bmul_1x1(mp_digit *rh, mp_digit *rl, const mp_digit a, const mp_digit b)
+{
+    register mp_digit h, l, s;
+    mp_digit tab[8], top2b = a >> 30; 
+    register mp_digit a1, a2, a4;
+
+    a1 = a & (0x3FFFFFFF); a2 = a1 << 1; a4 = a2 << 1;
+
+    tab[0] =  0; tab[1] = a1;    tab[2] = a2;    tab[3] = a1^a2;
+    tab[4] = a4; tab[5] = a1^a4; tab[6] = a2^a4; tab[7] = a1^a2^a4;
+
+    s = tab[b       & 0x7]; l  = s;
+    s = tab[b >>  3 & 0x7]; l ^= s <<  3; h  = s >> 29;
+    s = tab[b >>  6 & 0x7]; l ^= s <<  6; h ^= s >> 26;
+    s = tab[b >>  9 & 0x7]; l ^= s <<  9; h ^= s >> 23;
+    s = tab[b >> 12 & 0x7]; l ^= s << 12; h ^= s >> 20;
+    s = tab[b >> 15 & 0x7]; l ^= s << 15; h ^= s >> 17;
+    s = tab[b >> 18 & 0x7]; l ^= s << 18; h ^= s >> 14;
+    s = tab[b >> 21 & 0x7]; l ^= s << 21; h ^= s >> 11;
+    s = tab[b >> 24 & 0x7]; l ^= s << 24; h ^= s >>  8;
+    s = tab[b >> 27 & 0x7]; l ^= s << 27; h ^= s >>  5;
+    s = tab[b >> 30      ]; l ^= s << 30; h ^= s >>  2;
+
+    /* compensate for the top two bits of a */
+
+    if (top2b & 01) { l ^= b << 30; h ^= b >> 2; } 
+    if (top2b & 02) { l ^= b << 31; h ^= b >> 1; } 
+
+    *rh = h; *rl = l;
+} 
+#else
+void 
+s_bmul_1x1(mp_digit *rh, mp_digit *rl, const mp_digit a, const mp_digit b)
+{
+    register mp_digit h, l, s;
+    mp_digit tab[16], top3b = a >> 61;
+    register mp_digit a1, a2, a4, a8;
+
+    a1 = a & (0x1FFFFFFFFFFFFFFFULL); a2 = a1 << 1; 
+    a4 = a2 << 1; a8 = a4 << 1;
+    tab[ 0] = 0;     tab[ 1] = a1;       tab[ 2] = a2;       tab[ 3] = a1^a2;
+    tab[ 4] = a4;    tab[ 5] = a1^a4;    tab[ 6] = a2^a4;    tab[ 7] = a1^a2^a4;
+    tab[ 8] = a8;    tab[ 9] = a1^a8;    tab[10] = a2^a8;    tab[11] = a1^a2^a8;
+    tab[12] = a4^a8; tab[13] = a1^a4^a8; tab[14] = a2^a4^a8; tab[15] = a1^a2^a4^a8;
+
+    s = tab[b       & 0xF]; l  = s;
+    s = tab[b >>  4 & 0xF]; l ^= s <<  4; h  = s >> 60;
+    s = tab[b >>  8 & 0xF]; l ^= s <<  8; h ^= s >> 56;
+    s = tab[b >> 12 & 0xF]; l ^= s << 12; h ^= s >> 52;
+    s = tab[b >> 16 & 0xF]; l ^= s << 16; h ^= s >> 48;
+    s = tab[b >> 20 & 0xF]; l ^= s << 20; h ^= s >> 44;
+    s = tab[b >> 24 & 0xF]; l ^= s << 24; h ^= s >> 40;
+    s = tab[b >> 28 & 0xF]; l ^= s << 28; h ^= s >> 36;
+    s = tab[b >> 32 & 0xF]; l ^= s << 32; h ^= s >> 32;
+    s = tab[b >> 36 & 0xF]; l ^= s << 36; h ^= s >> 28;
+    s = tab[b >> 40 & 0xF]; l ^= s << 40; h ^= s >> 24;
+    s = tab[b >> 44 & 0xF]; l ^= s << 44; h ^= s >> 20;
+    s = tab[b >> 48 & 0xF]; l ^= s << 48; h ^= s >> 16;
+    s = tab[b >> 52 & 0xF]; l ^= s << 52; h ^= s >> 12;
+    s = tab[b >> 56 & 0xF]; l ^= s << 56; h ^= s >>  8;
+    s = tab[b >> 60      ]; l ^= s << 60; h ^= s >>  4;
+
+    /* compensate for the top three bits of a */
+
+    if (top3b & 01) { l ^= b << 61; h ^= b >> 3; } 
+    if (top3b & 02) { l ^= b << 62; h ^= b >> 2; } 
+    if (top3b & 04) { l ^= b << 63; h ^= b >> 1; } 
+
+    *rh = h; *rl = l;
+} 
+#endif
+
+/* Compute xor-multiply of two binary polynomials  (a1, a0) x (b1, b0)  
+ * result is a binary polynomial in 4 mp_digits r[4].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void 
+s_bmul_2x2(mp_digit *r, const mp_digit a1, const mp_digit a0, const mp_digit b1,
+           const mp_digit b0)
+{
+    mp_digit m1, m0;
+    /* r[3] = h1, r[2] = h0; r[1] = l1; r[0] = l0 */
+    s_bmul_1x1(r+3, r+2, a1, b1);
+    s_bmul_1x1(r+1, r, a0, b0);
+    s_bmul_1x1(&m1, &m0, a0 ^ a1, b0 ^ b1);
+    /* Correction on m1 ^= l1 ^ h1; m0 ^= l0 ^ h0; */
+    r[2] ^= m1 ^ r[1] ^ r[3];  /* h0 ^= m1 ^ l1 ^ h1; */
+    r[1]  = r[3] ^ r[2] ^ r[0] ^ m1 ^ m0;  /* l1 ^= l0 ^ h0 ^ m0; */
+}
+
+/* Compute xor-multiply of two binary polynomials  (a2, a1, a0) x (b2, b1, b0)  
+ * result is a binary polynomial in 6 mp_digits r[6].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void 
+s_bmul_3x3(mp_digit *r, const mp_digit a2, const mp_digit a1, const mp_digit a0, 
+	const mp_digit b2, const mp_digit b1, const mp_digit b0)
+{
+	mp_digit zm[4];
+
+	s_bmul_1x1(r+5, r+4, a2, b2);         /* fill top 2 words */
+	s_bmul_2x2(zm, a1, a2^a0, b1, b2^b0); /* fill middle 4 words */
+	s_bmul_2x2(r, a1, a0, b1, b0);        /* fill bottom 4 words */
+
+	zm[3] ^= r[3];
+	zm[2] ^= r[2]; 
+	zm[1] ^= r[1] ^ r[5];
+	zm[0] ^= r[0] ^ r[4];
+
+	r[5]  ^= zm[3];
+	r[4]  ^= zm[2];
+	r[3]  ^= zm[1];
+	r[2]  ^= zm[0];
+}
+
+/* Compute xor-multiply of two binary polynomials  (a3, a2, a1, a0) x (b3, b2, b1, b0)  
+ * result is a binary polynomial in 8 mp_digits r[8].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_4x4(mp_digit *r, const mp_digit a3, const mp_digit a2, const mp_digit a1, 
+	const mp_digit a0, const mp_digit b3, const mp_digit b2, const mp_digit b1, 
+	const mp_digit b0)
+{
+	mp_digit zm[4];
+
+	s_bmul_2x2(r+4, a3, a2, b3, b2);            /* fill top 4 words */
+	s_bmul_2x2(zm, a3^a1, a2^a0, b3^b1, b2^b0); /* fill middle 4 words */
+	s_bmul_2x2(r, a1, a0, b1, b0);              /* fill bottom 4 words */
+
+	zm[3] ^= r[3] ^ r[7]; 
+	zm[2] ^= r[2] ^ r[6]; 
+	zm[1] ^= r[1] ^ r[5]; 
+	zm[0] ^= r[0] ^ r[4]; 
+
+	r[5]  ^= zm[3];    
+	r[4]  ^= zm[2];
+	r[3]  ^= zm[1];    
+	r[2]  ^= zm[0];
+}
+
+/* Compute addition of two binary polynomials a and b,
+ * store result in c; c could be a or b, a and b could be equal; 
+ * c is the bitwise XOR of a and b.
+ */
+mp_err
+mp_badd(const mp_int *a, const mp_int *b, mp_int *c)
+{
+    mp_digit *pa, *pb, *pc;
+    mp_size ix;
+    mp_size used_pa, used_pb;
+    mp_err res = MP_OKAY;
+
+    /* Add all digits up to the precision of b.  If b had more
+     * precision than a initially, swap a, b first
+     */
+    if (MP_USED(a) >= MP_USED(b)) {
+        pa = MP_DIGITS(a);
+        pb = MP_DIGITS(b);
+        used_pa = MP_USED(a);
+        used_pb = MP_USED(b);
+    } else {
+        pa = MP_DIGITS(b);
+        pb = MP_DIGITS(a);
+        used_pa = MP_USED(b);
+        used_pb = MP_USED(a);
+    }
+
+    /* Make sure c has enough precision for the output value */
+    MP_CHECKOK( s_mp_pad(c, used_pa) );
+
+    /* Do word-by-word xor */
+    pc = MP_DIGITS(c);
+    for (ix = 0; ix < used_pb; ix++) {
+        (*pc++) = (*pa++) ^ (*pb++);
+    }
+
+    /* Finish the rest of digits until we're actually done */
+    for (; ix < used_pa; ++ix) {
+        *pc++ = *pa++;
+    }
+
+    MP_USED(c) = used_pa;
+    MP_SIGN(c) = ZPOS;
+    s_mp_clamp(c);
+
+CLEANUP:
+    return res;
+} 
+
+#define s_mp_div2(a) MP_CHECKOK( mpl_rsh((a), (a), 1) );
+
+/* Compute binary polynomial multiply d = a * b */
+static void 
+s_bmul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *d)
+{
+    mp_digit a_i, a0b0, a1b1, carry = 0;
+    while (a_len--) {
+        a_i = *a++;
+        s_bmul_1x1(&a1b1, &a0b0, a_i, b);
+        *d++ = a0b0 ^ carry;
+        carry = a1b1;
+    }
+    *d = carry;
+}
+
+/* Compute binary polynomial xor multiply accumulate d ^= a * b */
+static void 
+s_bmul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *d)
+{
+    mp_digit a_i, a0b0, a1b1, carry = 0;
+    while (a_len--) {
+        a_i = *a++;
+        s_bmul_1x1(&a1b1, &a0b0, a_i, b);
+        *d++ ^= a0b0 ^ carry;
+        carry = a1b1;
+    }
+    *d ^= carry;
+}
+
+/* Compute binary polynomial xor multiply c = a * b.  
+ * All parameters may be identical.
+ */
+mp_err 
+mp_bmul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+    mp_digit *pb, b_i;
+    mp_int tmp;
+    mp_size ib, a_used, b_used;
+    mp_err res = MP_OKAY;
+
+    MP_DIGITS(&tmp) = 0;
+
+    ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+    if (a == c) {
+        MP_CHECKOK( mp_init_copy(&tmp, a) );
+        if (a == b)
+            b = &tmp;
+        a = &tmp;
+    } else if (b == c) {
+        MP_CHECKOK( mp_init_copy(&tmp, b) );
+        b = &tmp;
+    }
+
+    if (MP_USED(a) < MP_USED(b)) {
+        const mp_int *xch = b;      /* switch a and b if b longer */
+        b = a;
+        a = xch;
+    }
+
+    MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
+    MP_CHECKOK( s_mp_pad(c, USED(a) + USED(b)) );
+
+    pb = MP_DIGITS(b);
+    s_bmul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c));
+
+    /* Outer loop:  Digits of b */
+    a_used = MP_USED(a);
+    b_used = MP_USED(b);
+	MP_USED(c) = a_used + b_used;
+    for (ib = 1; ib < b_used; ib++) {
+        b_i = *pb++;
+
+        /* Inner product:  Digits of a */
+        if (b_i)
+            s_bmul_d_add(MP_DIGITS(a), a_used, b_i, MP_DIGITS(c) + ib);
+        else
+            MP_DIGIT(c, ib + a_used) = b_i;
+    }
+
+    s_mp_clamp(c);
+
+    SIGN(c) = ZPOS;
+
+CLEANUP:
+    mp_clear(&tmp);
+    return res;
+}
+
+
+/* Compute modular reduction of a and store result in r.  
+ * r could be a. 
+ * For modular arithmetic, the irreducible polynomial f(t) is represented 
+ * as an array of int[], where f(t) is of the form: 
+ *     f(t) = t^p[0] + t^p[1] + ... + t^p[k]
+ * where m = p[0] > p[1] > ... > p[k] = 0.
+ */
+mp_err
+mp_bmod(const mp_int *a, const unsigned int p[], mp_int *r)
+{
+    int j, k;
+    int n, dN, d0, d1;
+    mp_digit zz, *z, tmp;
+    mp_size used;
+    mp_err res = MP_OKAY;
+
+    /* The algorithm does the reduction in place in r, 
+     * if a != r, copy a into r first so reduction can be done in r
+     */
+    if (a != r) {
+        MP_CHECKOK( mp_copy(a, r) );
+    }
+    z = MP_DIGITS(r);
+
+    /* start reduction */
+    dN = p[0] / MP_DIGIT_BITS;
+    used = MP_USED(r);
+
+    for (j = used - 1; j > dN;) {
+
+        zz = z[j];
+        if (zz == 0) {
+            j--; continue;
+        }
+        z[j] = 0;
+
+        for (k = 1; p[k] > 0; k++) {
+            /* reducing component t^p[k] */
+            n = p[0] - p[k];
+            d0 = n % MP_DIGIT_BITS;  
+            d1 = MP_DIGIT_BITS - d0;
+            n /= MP_DIGIT_BITS;
+            z[j-n] ^= (zz>>d0);
+            if (d0) 
+                z[j-n-1] ^= (zz<<d1);
+        }
+
+        /* reducing component t^0 */
+        n = dN;  
+        d0 = p[0] % MP_DIGIT_BITS;
+        d1 = MP_DIGIT_BITS - d0;
+        z[j-n] ^= (zz >> d0);
+        if (d0) 
+            z[j-n-1] ^= (zz << d1);
+
+    }
+
+    /* final round of reduction */
+    while (j == dN) {
+
+        d0 = p[0] % MP_DIGIT_BITS;
+        zz = z[dN] >> d0;  
+        if (zz == 0) break;
+        d1 = MP_DIGIT_BITS - d0;
+
+        /* clear up the top d1 bits */
+        if (d0) z[dN] = (z[dN] << d1) >> d1; 
+        *z ^= zz; /* reduction t^0 component */
+
+        for (k = 1; p[k] > 0; k++) {
+            /* reducing component t^p[k]*/
+            n = p[k] / MP_DIGIT_BITS;
+            d0 = p[k] % MP_DIGIT_BITS;
+            d1 = MP_DIGIT_BITS - d0;
+            z[n] ^= (zz << d0);
+            tmp = zz >> d1;
+            if (d0 && tmp)
+                z[n+1] ^= tmp;
+        }
+    }
+
+    s_mp_clamp(r);
+CLEANUP:
+    return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p, 
+ * Store the result in r.  r could be a or b; a could be b.
+ */
+mp_err 
+mp_bmulmod(const mp_int *a, const mp_int *b, const unsigned int p[], mp_int *r)
+{
+    mp_err res;
+    
+    if (a == b) return mp_bsqrmod(a, p, r);
+    if ((res = mp_bmul(a, b, r) ) != MP_OKAY)
+	return res;
+    return mp_bmod(r, p, r);
+}
+
+/* Compute binary polynomial squaring c = a*a mod p .  
+ * Parameter r and a can be identical.
+ */
+
+mp_err 
+mp_bsqrmod(const mp_int *a, const unsigned int p[], mp_int *r)
+{
+    mp_digit *pa, *pr, a_i;
+    mp_int tmp;
+    mp_size ia, a_used;
+    mp_err res;
+
+    ARGCHK(a != NULL && r != NULL, MP_BADARG);
+    MP_DIGITS(&tmp) = 0;
+
+    if (a == r) {
+        MP_CHECKOK( mp_init_copy(&tmp, a) );
+        a = &tmp;
+    }
+
+    MP_USED(r) = 1; MP_DIGIT(r, 0) = 0;
+    MP_CHECKOK( s_mp_pad(r, 2*USED(a)) );
+
+    pa = MP_DIGITS(a);
+    pr = MP_DIGITS(r);
+    a_used = MP_USED(a);
+	MP_USED(r) = 2 * a_used;
+
+    for (ia = 0; ia < a_used; ia++) {
+        a_i = *pa++;
+        *pr++ = gf2m_SQR0(a_i);
+        *pr++ = gf2m_SQR1(a_i);
+    }
+
+    MP_CHECKOK( mp_bmod(r, p, r) );
+    s_mp_clamp(r);
+    SIGN(r) = ZPOS;
+
+CLEANUP:
+    mp_clear(&tmp);
+    return res;
+}
+
+/* Compute binary polynomial y/x mod p, y divided by x, reduce modulo p.
+ * Store the result in r. r could be x or y, and x could equal y.
+ * Uses algorithm Modular_Division_GF(2^m) from 
+ *     Chang-Shantz, S.  "From Euclid's GCD to Montgomery Multiplication to 
+ *     the Great Divide".
+ */
+int 
+mp_bdivmod(const mp_int *y, const mp_int *x, const mp_int *pp, 
+    const unsigned int p[], mp_int *r)
+{
+    mp_int aa, bb, uu;
+    mp_int *a, *b, *u, *v;
+    mp_err res = MP_OKAY;
+
+    MP_DIGITS(&aa) = 0;
+    MP_DIGITS(&bb) = 0;
+    MP_DIGITS(&uu) = 0;
+
+    MP_CHECKOK( mp_init_copy(&aa, x) );
+    MP_CHECKOK( mp_init_copy(&uu, y) );
+    MP_CHECKOK( mp_init_copy(&bb, pp) );
+    MP_CHECKOK( s_mp_pad(r, USED(pp)) );
+    MP_USED(r) = 1; MP_DIGIT(r, 0) = 0;
+
+    a = &aa; b= &bb; u=&uu; v=r;
+    /* reduce x and y mod p */
+    MP_CHECKOK( mp_bmod(a, p, a) );
+    MP_CHECKOK( mp_bmod(u, p, u) );
+
+    while (!mp_isodd(a)) {
+        s_mp_div2(a);
+        if (mp_isodd(u)) {
+            MP_CHECKOK( mp_badd(u, pp, u) );
+        }
+        s_mp_div2(u);
+    }
+
+    do {
+        if (mp_cmp_mag(b, a) > 0) {
+            MP_CHECKOK( mp_badd(b, a, b) );
+            MP_CHECKOK( mp_badd(v, u, v) );
+            do {
+                s_mp_div2(b);
+                if (mp_isodd(v)) {
+                    MP_CHECKOK( mp_badd(v, pp, v) );
+                }
+                s_mp_div2(v);
+            } while (!mp_isodd(b));
+        }
+        else if ((MP_DIGIT(a,0) == 1) && (MP_USED(a) == 1))
+            break;
+        else {
+            MP_CHECKOK( mp_badd(a, b, a) );
+            MP_CHECKOK( mp_badd(u, v, u) );
+            do {
+                s_mp_div2(a);
+                if (mp_isodd(u)) {
+                    MP_CHECKOK( mp_badd(u, pp, u) );
+                }
+                s_mp_div2(u);
+            } while (!mp_isodd(a));
+        }
+    } while (1);
+
+    MP_CHECKOK( mp_copy(u, r) );
+
+CLEANUP:
+    mp_clear(&aa);
+    mp_clear(&bb);
+    mp_clear(&uu);
+    return res;
+
+}
+
+/* Convert the bit-string representation of a polynomial a into an array
+ * of integers corresponding to the bits with non-zero coefficient.
+ * Up to max elements of the array will be filled.  Return value is total
+ * number of coefficients that would be extracted if array was large enough.
+ */
+int
+mp_bpoly2arr(const mp_int *a, unsigned int p[], int max)
+{
+    int i, j, k;
+    mp_digit top_bit, mask;
+
+    top_bit = 1;
+    top_bit <<= MP_DIGIT_BIT - 1;
+
+    for (k = 0; k < max; k++) p[k] = 0;
+    k = 0;
+
+    for (i = MP_USED(a) - 1; i >= 0; i--) {
+        mask = top_bit;
+        for (j = MP_DIGIT_BIT - 1; j >= 0; j--) {
+            if (MP_DIGITS(a)[i] & mask) {
+                if (k < max) p[k] = MP_DIGIT_BIT * i + j;
+                k++;
+            }
+            mask >>= 1;
+        }
+    }
+
+    return k;
+}
+
+/* Convert the coefficient array representation of a polynomial to a 
+ * bit-string.  The array must be terminated by 0.
+ */
+mp_err
+mp_barr2poly(const unsigned int p[], mp_int *a)
+{
+
+    mp_err res = MP_OKAY;
+    int i;
+
+    mp_zero(a);
+    for (i = 0; p[i] > 0; i++) {
+	MP_CHECKOK( mpl_set_bit(a, p[i], 1) );
+    }
+    MP_CHECKOK( mpl_set_bit(a, 0, 1) );
+	
+CLEANUP:
+    return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/mpi/mp_gf2m.h b/mozilla/security/nss/lib/freebl/mpi/mp_gf2m.h
new file mode 100644
index 0000000..1a305f3
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mp_gf2m.h
@@ -0,0 +1,63 @@
+/*
+ * ***** 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 Multi-precision Binary Polynomial Arithmetic Library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sheueling Chang Shantz <sheueling.chang@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ * 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 ***** */
+
+#ifndef _MP_GF2M_H_
+#define _MP_GF2M_H_
+
+#include "mpi.h"
+
+mp_err mp_badd(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err mp_bmul(const mp_int *a, const mp_int *b, mp_int *c);
+
+/* For modular arithmetic, the irreducible polynomial f(t) is represented 
+ * as an array of int[], where f(t) is of the form: 
+ *     f(t) = t^p[0] + t^p[1] + ... + t^p[k]
+ * where m = p[0] > p[1] > ... > p[k] = 0.
+ */
+mp_err mp_bmod(const mp_int *a, const unsigned int p[], mp_int *r);
+mp_err mp_bmulmod(const mp_int *a, const mp_int *b, const unsigned int p[], 
+    mp_int *r);
+mp_err mp_bsqrmod(const mp_int *a, const unsigned int p[], mp_int *r);
+mp_err mp_bdivmod(const mp_int *y, const mp_int *x, const mp_int *pp, 
+    const unsigned int p[], mp_int *r);
+
+int mp_bpoly2arr(const mp_int *a, unsigned int p[], int max);
+mp_err mp_barr2poly(const unsigned int p[], mp_int *a);
+
+#endif /* _MP_GF2M_H_ */
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpcpucache.c b/mozilla/security/nss/lib/freebl/mpi/mpcpucache.c
new file mode 100644
index 0000000..6efa072
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpcpucache.c
@@ -0,0 +1,838 @@
+/* ***** 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
+ * Red Hat, Inc
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert Relyea <rrelyea@redhat.com>
+ *
+ * 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 "mpi.h"
+
+/*
+ * This file implements a single function: s_mpi_getProcessorLineSize();
+ * s_mpi_getProcessorLineSize() returns the size in bytes of the cache line
+ * if a cache exists, or zero if there is no cache. If more than one
+ * cache line exists, it should return the smallest line size (which is 
+ * usually the L1 cache).
+ *
+ * mp_modexp uses this information to make sure that private key information
+ * isn't being leaked through the cache.
+ *
+ * Currently the file returns good data for most modern x86 processors, and
+ * reasonable data on 64-bit ppc processors. All other processors are assumed
+ * to have a cache line size of 32 bytes unless modified by target.mk.
+ * 
+ */
+
+#if defined(i386) || defined(__i386) || defined(__X86__) || defined (_M_IX86) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
+/* X86 processors have special instructions that tell us about the cache */
+#include "string.h"
+
+#if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
+#define AMD_64 1
+#endif
+
+/* Generic CPUID function */
+#if defined(AMD_64)
+
+#if defined(__GNUC__)
+
+void freebl_cpuid(unsigned long op, unsigned long *eax, 
+	                 unsigned long *ebx, unsigned long *ecx, 
+                         unsigned long *edx)
+{
+	__asm__("cpuid\n\t"
+		: "=a" (*eax),
+		  "=b" (*ebx),
+		  "=c" (*ecx),
+		  "=d" (*edx)
+		: "0" (op));
+}
+
+#elif defined(_MSC_VER)
+
+#include <intrin.h>
+
+void freebl_cpuid(unsigned long op, unsigned long *eax, 
+           unsigned long *ebx, unsigned long *ecx, 
+           unsigned long *edx)
+{
+    int intrinsic_out[4];
+
+    __cpuid(intrinsic_out, op);
+    *eax = intrinsic_out[0];
+    *ebx = intrinsic_out[1];
+    *ecx = intrinsic_out[2];
+    *edx = intrinsic_out[3];
+}
+
+#endif
+
+#else /* !defined(AMD_64) */
+
+/* x86 */
+
+#if defined(__GNUC__)
+void freebl_cpuid(unsigned long op, unsigned long *eax, 
+	                 unsigned long *ebx, unsigned long *ecx, 
+                         unsigned long *edx)
+{
+/* sigh GCC isn't smart enough to save the ebx PIC register on it's own
+ * in this case, so do it by hand. */
+	__asm__("pushl %%ebx\n\t"
+		  "cpuid\n\t"
+		  "mov %%ebx,%1\n\t"
+		  "popl %%ebx\n\t"
+		: "=a" (*eax),
+		  "=r" (*ebx),
+		  "=c" (*ecx),
+		  "=d" (*edx)
+		: "0" (op));
+}
+
+/*
+ * try flipping a processor flag to determine CPU type
+ */
+static unsigned long changeFlag(unsigned long flag)
+{
+	unsigned long changedFlags, originalFlags;
+	__asm__("pushfl\n\t"            /* get the flags */
+	        "popl %0\n\t"
+	        "movl %0,%1\n\t"	/* save the original flags */
+	        "xorl %2,%0\n\t" 	/* flip the bit */
+		"pushl %0\n\t"  	/* set the flags */
+	        "popfl\n\t"
+		"pushfl\n\t"		/* get the flags again (for return) */
+		"popl %0\n\t"
+		"pushl %1\n\t"		/* restore the original flags */
+		 "popfl\n\t"
+		: "=r" (changedFlags),
+		  "=r" (originalFlags),
+		  "=r" (flag)
+		: "2" (flag));
+	return changedFlags ^ originalFlags;
+}
+
+#elif defined(_MSC_VER)
+
+/*
+ * windows versions of the above assembler
+ */
+#define wcpuid __asm __emit 0fh __asm __emit 0a2h
+void freebl_cpuid(unsigned long op,    unsigned long *Reax, 
+    unsigned long *Rebx, unsigned long *Recx, unsigned long *Redx)
+{
+        unsigned long  Leax, Lebx, Lecx, Ledx;
+        __asm {
+        pushad
+        mov     eax,op
+        wcpuid
+        mov     Leax,eax
+        mov     Lebx,ebx
+        mov     Lecx,ecx
+        mov     Ledx,edx
+        popad
+        }
+        *Reax = Leax;
+        *Rebx = Lebx;
+        *Recx = Lecx;
+        *Redx = Ledx;
+}
+
+static unsigned long changeFlag(unsigned long flag)
+{
+	unsigned long changedFlags, originalFlags;
+	__asm {
+		push eax
+		push ebx
+		pushfd 	                /* get the flags */
+	        pop  eax
+		push eax		/* save the flags on the stack */
+	        mov  originalFlags,eax  /* save the original flags */
+		mov  ebx,flag
+	        xor  eax,ebx            /* flip the bit */
+		push eax                /* set the flags */
+	        popfd
+		pushfd                  /* get the flags again (for return) */
+		pop  eax	
+		popfd                   /* restore the original flags */
+		mov changedFlags,eax
+		pop ebx
+		pop eax
+	}
+	return changedFlags ^ originalFlags;
+}
+#endif
+
+#endif
+
+#if !defined(AMD_64)
+#define AC_FLAG 0x40000
+#define ID_FLAG 0x200000
+
+/* 386 processors can't flip the AC_FLAG, intel AP Note AP-485 */
+static int is386()
+{
+    return changeFlag(AC_FLAG) == 0;
+}
+
+/* 486 processors can't flip the ID_FLAG, intel AP Note AP-485 */
+static int is486()
+{
+    return changeFlag(ID_FLAG) == 0;
+}
+#endif
+
+
+/*
+ * table for Intel Cache.
+ * See Intel Application Note AP-485 for more information 
+ */
+
+typedef unsigned char CacheTypeEntry;
+
+typedef enum {
+    Cache_NONE    = 0,
+    Cache_UNKNOWN = 1,
+    Cache_TLB     = 2,
+    Cache_TLBi    = 3,
+    Cache_TLBd    = 4,
+    Cache_Trace   = 5,
+    Cache_L1      = 6,
+    Cache_L1i     = 7,
+    Cache_L1d     = 8,
+    Cache_L2      = 9 ,
+    Cache_L2i     = 10 ,
+    Cache_L2d     = 11 ,
+    Cache_L3      = 12 ,
+    Cache_L3i     = 13,
+    Cache_L3d     = 14
+} CacheType;
+
+struct _cache {
+    CacheTypeEntry type;
+    unsigned char lineSize;
+};
+static const struct _cache CacheMap[256] = {
+/* 00 */ {Cache_NONE,    0   },
+/* 01 */ {Cache_TLBi,    0   },
+/* 02 */ {Cache_TLBi,    0   },
+/* 03 */ {Cache_TLBd,    0   },
+/* 04 */ {Cache_TLBd,        },
+/* 05 */ {Cache_UNKNOWN, 0   },
+/* 06 */ {Cache_L1i,     32  },
+/* 07 */ {Cache_UNKNOWN, 0   },
+/* 08 */ {Cache_L1i,     32  },
+/* 09 */ {Cache_UNKNOWN, 0   },
+/* 0a */ {Cache_L1d,     32  },
+/* 0b */ {Cache_UNKNOWN, 0   },
+/* 0c */ {Cache_L1d,     32  },
+/* 0d */ {Cache_UNKNOWN, 0   },
+/* 0e */ {Cache_UNKNOWN, 0   },
+/* 0f */ {Cache_UNKNOWN, 0   },
+/* 10 */ {Cache_UNKNOWN, 0   },
+/* 11 */ {Cache_UNKNOWN, 0   },
+/* 12 */ {Cache_UNKNOWN, 0   },
+/* 13 */ {Cache_UNKNOWN, 0   },
+/* 14 */ {Cache_UNKNOWN, 0   },
+/* 15 */ {Cache_UNKNOWN, 0   },
+/* 16 */ {Cache_UNKNOWN, 0   },
+/* 17 */ {Cache_UNKNOWN, 0   },
+/* 18 */ {Cache_UNKNOWN, 0   },
+/* 19 */ {Cache_UNKNOWN, 0   },
+/* 1a */ {Cache_UNKNOWN, 0   },
+/* 1b */ {Cache_UNKNOWN, 0   },
+/* 1c */ {Cache_UNKNOWN, 0   },
+/* 1d */ {Cache_UNKNOWN, 0   },
+/* 1e */ {Cache_UNKNOWN, 0   },
+/* 1f */ {Cache_UNKNOWN, 0   },
+/* 20 */ {Cache_UNKNOWN, 0   },
+/* 21 */ {Cache_UNKNOWN, 0   },
+/* 22 */ {Cache_L3,      64  },
+/* 23 */ {Cache_L3,      64  },
+/* 24 */ {Cache_UNKNOWN, 0   },
+/* 25 */ {Cache_L3,      64  },
+/* 26 */ {Cache_UNKNOWN, 0   },
+/* 27 */ {Cache_UNKNOWN, 0   },
+/* 28 */ {Cache_UNKNOWN, 0   },
+/* 29 */ {Cache_L3,      64  },
+/* 2a */ {Cache_UNKNOWN, 0   },
+/* 2b */ {Cache_UNKNOWN, 0   },
+/* 2c */ {Cache_L1d,     64  },
+/* 2d */ {Cache_UNKNOWN, 0   },
+/* 2e */ {Cache_UNKNOWN, 0   },
+/* 2f */ {Cache_UNKNOWN, 0   },
+/* 30 */ {Cache_L1i,     64  },
+/* 31 */ {Cache_UNKNOWN, 0   },
+/* 32 */ {Cache_UNKNOWN, 0   },
+/* 33 */ {Cache_UNKNOWN, 0   },
+/* 34 */ {Cache_UNKNOWN, 0   },
+/* 35 */ {Cache_UNKNOWN, 0   },
+/* 36 */ {Cache_UNKNOWN, 0   },
+/* 37 */ {Cache_UNKNOWN, 0   },
+/* 38 */ {Cache_UNKNOWN, 0   },
+/* 39 */ {Cache_L2,      64  },
+/* 3a */ {Cache_UNKNOWN, 0   },
+/* 3b */ {Cache_L2,      64  },
+/* 3c */ {Cache_L2,      64  },
+/* 3d */ {Cache_UNKNOWN, 0   },
+/* 3e */ {Cache_UNKNOWN, 0   },
+/* 3f */ {Cache_UNKNOWN, 0   },
+/* 40 */ {Cache_L2,      0   },
+/* 41 */ {Cache_L2,      32  },
+/* 42 */ {Cache_L2,      32  },
+/* 43 */ {Cache_L2,      32  },
+/* 44 */ {Cache_L2,      32  },
+/* 45 */ {Cache_L2,      32  },
+/* 46 */ {Cache_UNKNOWN, 0   },
+/* 47 */ {Cache_UNKNOWN, 0   },
+/* 48 */ {Cache_UNKNOWN, 0   },
+/* 49 */ {Cache_UNKNOWN, 0   },
+/* 4a */ {Cache_UNKNOWN, 0   },
+/* 4b */ {Cache_UNKNOWN, 0   },
+/* 4c */ {Cache_UNKNOWN, 0   },
+/* 4d */ {Cache_UNKNOWN, 0   },
+/* 4e */ {Cache_UNKNOWN, 0   },
+/* 4f */ {Cache_UNKNOWN, 0   },
+/* 50 */ {Cache_TLBi,    0   },
+/* 51 */ {Cache_TLBi,    0   },
+/* 52 */ {Cache_TLBi,    0   },
+/* 53 */ {Cache_UNKNOWN, 0   },
+/* 54 */ {Cache_UNKNOWN, 0   },
+/* 55 */ {Cache_UNKNOWN, 0   },
+/* 56 */ {Cache_UNKNOWN, 0   },
+/* 57 */ {Cache_UNKNOWN, 0   },
+/* 58 */ {Cache_UNKNOWN, 0   },
+/* 59 */ {Cache_UNKNOWN, 0   },
+/* 5a */ {Cache_UNKNOWN, 0   },
+/* 5b */ {Cache_TLBd,    0   },
+/* 5c */ {Cache_TLBd,    0   },
+/* 5d */ {Cache_TLBd,    0   },
+/* 5e */ {Cache_UNKNOWN, 0   },
+/* 5f */ {Cache_UNKNOWN, 0   },
+/* 60 */ {Cache_UNKNOWN, 0   },
+/* 61 */ {Cache_UNKNOWN, 0   },
+/* 62 */ {Cache_UNKNOWN, 0   },
+/* 63 */ {Cache_UNKNOWN, 0   },
+/* 64 */ {Cache_UNKNOWN, 0   },
+/* 65 */ {Cache_UNKNOWN, 0   },
+/* 66 */ {Cache_L1d,     64  },
+/* 67 */ {Cache_L1d,     64  },
+/* 68 */ {Cache_L1d,     64  },
+/* 69 */ {Cache_UNKNOWN, 0   },
+/* 6a */ {Cache_UNKNOWN, 0   },
+/* 6b */ {Cache_UNKNOWN, 0   },
+/* 6c */ {Cache_UNKNOWN, 0   },
+/* 6d */ {Cache_UNKNOWN, 0   },
+/* 6e */ {Cache_UNKNOWN, 0   },
+/* 6f */ {Cache_UNKNOWN, 0   },
+/* 70 */ {Cache_Trace,   1   },
+/* 71 */ {Cache_Trace,   1   },
+/* 72 */ {Cache_Trace,   1   },
+/* 73 */ {Cache_UNKNOWN, 0   },
+/* 74 */ {Cache_UNKNOWN, 0   },
+/* 75 */ {Cache_UNKNOWN, 0   },
+/* 76 */ {Cache_UNKNOWN, 0   },
+/* 77 */ {Cache_UNKNOWN, 0   },
+/* 78 */ {Cache_UNKNOWN, 0   },
+/* 79 */ {Cache_L2,      64  },
+/* 7a */ {Cache_L2,      64  },
+/* 7b */ {Cache_L2,      64  },
+/* 7c */ {Cache_L2,      64  },
+/* 7d */ {Cache_UNKNOWN, 0   },
+/* 7e */ {Cache_UNKNOWN, 0   },
+/* 7f */ {Cache_UNKNOWN, 0   },
+/* 80 */ {Cache_UNKNOWN, 0   },
+/* 81 */ {Cache_UNKNOWN, 0   },
+/* 82 */ {Cache_L2,      32  },
+/* 83 */ {Cache_L2,      32  },
+/* 84 */ {Cache_L2,      32  },
+/* 85 */ {Cache_L2,      32  },
+/* 86 */ {Cache_L2,      64  },
+/* 87 */ {Cache_L2,      64  },
+/* 88 */ {Cache_UNKNOWN, 0   },
+/* 89 */ {Cache_UNKNOWN, 0   },
+/* 8a */ {Cache_UNKNOWN, 0   },
+/* 8b */ {Cache_UNKNOWN, 0   },
+/* 8c */ {Cache_UNKNOWN, 0   },
+/* 8d */ {Cache_UNKNOWN, 0   },
+/* 8e */ {Cache_UNKNOWN, 0   },
+/* 8f */ {Cache_UNKNOWN, 0   },
+/* 90 */ {Cache_UNKNOWN, 0   },
+/* 91 */ {Cache_UNKNOWN, 0   },
+/* 92 */ {Cache_UNKNOWN, 0   },
+/* 93 */ {Cache_UNKNOWN, 0   },
+/* 94 */ {Cache_UNKNOWN, 0   },
+/* 95 */ {Cache_UNKNOWN, 0   },
+/* 96 */ {Cache_UNKNOWN, 0   },
+/* 97 */ {Cache_UNKNOWN, 0   },
+/* 98 */ {Cache_UNKNOWN, 0   },
+/* 99 */ {Cache_UNKNOWN, 0   },
+/* 9a */ {Cache_UNKNOWN, 0   },
+/* 9b */ {Cache_UNKNOWN, 0   },
+/* 9c */ {Cache_UNKNOWN, 0   },
+/* 9d */ {Cache_UNKNOWN, 0   },
+/* 9e */ {Cache_UNKNOWN, 0   },
+/* 9f */ {Cache_UNKNOWN, 0   },
+/* a0 */ {Cache_UNKNOWN, 0   },
+/* a1 */ {Cache_UNKNOWN, 0   },
+/* a2 */ {Cache_UNKNOWN, 0   },
+/* a3 */ {Cache_UNKNOWN, 0   },
+/* a4 */ {Cache_UNKNOWN, 0   },
+/* a5 */ {Cache_UNKNOWN, 0   },
+/* a6 */ {Cache_UNKNOWN, 0   },
+/* a7 */ {Cache_UNKNOWN, 0   },
+/* a8 */ {Cache_UNKNOWN, 0   },
+/* a9 */ {Cache_UNKNOWN, 0   },
+/* aa */ {Cache_UNKNOWN, 0   },
+/* ab */ {Cache_UNKNOWN, 0   },
+/* ac */ {Cache_UNKNOWN, 0   },
+/* ad */ {Cache_UNKNOWN, 0   },
+/* ae */ {Cache_UNKNOWN, 0   },
+/* af */ {Cache_UNKNOWN, 0   },
+/* b0 */ {Cache_TLBi,    0   },
+/* b1 */ {Cache_UNKNOWN, 0   },
+/* b2 */ {Cache_UNKNOWN, 0   },
+/* b3 */ {Cache_TLBd,    0   },
+/* b4 */ {Cache_UNKNOWN, 0   },
+/* b5 */ {Cache_UNKNOWN, 0   },
+/* b6 */ {Cache_UNKNOWN, 0   },
+/* b7 */ {Cache_UNKNOWN, 0   },
+/* b8 */ {Cache_UNKNOWN, 0   },
+/* b9 */ {Cache_UNKNOWN, 0   },
+/* ba */ {Cache_UNKNOWN, 0   },
+/* bb */ {Cache_UNKNOWN, 0   },
+/* bc */ {Cache_UNKNOWN, 0   },
+/* bd */ {Cache_UNKNOWN, 0   },
+/* be */ {Cache_UNKNOWN, 0   },
+/* bf */ {Cache_UNKNOWN, 0   },
+/* c0 */ {Cache_UNKNOWN, 0   },
+/* c1 */ {Cache_UNKNOWN, 0   },
+/* c2 */ {Cache_UNKNOWN, 0   },
+/* c3 */ {Cache_UNKNOWN, 0   },
+/* c4 */ {Cache_UNKNOWN, 0   },
+/* c5 */ {Cache_UNKNOWN, 0   },
+/* c6 */ {Cache_UNKNOWN, 0   },
+/* c7 */ {Cache_UNKNOWN, 0   },
+/* c8 */ {Cache_UNKNOWN, 0   },
+/* c9 */ {Cache_UNKNOWN, 0   },
+/* ca */ {Cache_UNKNOWN, 0   },
+/* cb */ {Cache_UNKNOWN, 0   },
+/* cc */ {Cache_UNKNOWN, 0   },
+/* cd */ {Cache_UNKNOWN, 0   },
+/* ce */ {Cache_UNKNOWN, 0   },
+/* cf */ {Cache_UNKNOWN, 0   },
+/* d0 */ {Cache_UNKNOWN, 0   },
+/* d1 */ {Cache_UNKNOWN, 0   },
+/* d2 */ {Cache_UNKNOWN, 0   },
+/* d3 */ {Cache_UNKNOWN, 0   },
+/* d4 */ {Cache_UNKNOWN, 0   },
+/* d5 */ {Cache_UNKNOWN, 0   },
+/* d6 */ {Cache_UNKNOWN, 0   },
+/* d7 */ {Cache_UNKNOWN, 0   },
+/* d8 */ {Cache_UNKNOWN, 0   },
+/* d9 */ {Cache_UNKNOWN, 0   },
+/* da */ {Cache_UNKNOWN, 0   },
+/* db */ {Cache_UNKNOWN, 0   },
+/* dc */ {Cache_UNKNOWN, 0   },
+/* dd */ {Cache_UNKNOWN, 0   },
+/* de */ {Cache_UNKNOWN, 0   },
+/* df */ {Cache_UNKNOWN, 0   },
+/* e0 */ {Cache_UNKNOWN, 0   },
+/* e1 */ {Cache_UNKNOWN, 0   },
+/* e2 */ {Cache_UNKNOWN, 0   },
+/* e3 */ {Cache_UNKNOWN, 0   },
+/* e4 */ {Cache_UNKNOWN, 0   },
+/* e5 */ {Cache_UNKNOWN, 0   },
+/* e6 */ {Cache_UNKNOWN, 0   },
+/* e7 */ {Cache_UNKNOWN, 0   },
+/* e8 */ {Cache_UNKNOWN, 0   },
+/* e9 */ {Cache_UNKNOWN, 0   },
+/* ea */ {Cache_UNKNOWN, 0   },
+/* eb */ {Cache_UNKNOWN, 0   },
+/* ec */ {Cache_UNKNOWN, 0   },
+/* ed */ {Cache_UNKNOWN, 0   },
+/* ee */ {Cache_UNKNOWN, 0   },
+/* ef */ {Cache_UNKNOWN, 0   },
+/* f0 */ {Cache_UNKNOWN, 0   },
+/* f1 */ {Cache_UNKNOWN, 0   },
+/* f2 */ {Cache_UNKNOWN, 0   },
+/* f3 */ {Cache_UNKNOWN, 0   },
+/* f4 */ {Cache_UNKNOWN, 0   },
+/* f5 */ {Cache_UNKNOWN, 0   },
+/* f6 */ {Cache_UNKNOWN, 0   },
+/* f7 */ {Cache_UNKNOWN, 0   },
+/* f8 */ {Cache_UNKNOWN, 0   },
+/* f9 */ {Cache_UNKNOWN, 0   },
+/* fa */ {Cache_UNKNOWN, 0   },
+/* fb */ {Cache_UNKNOWN, 0   },
+/* fc */ {Cache_UNKNOWN, 0   },
+/* fd */ {Cache_UNKNOWN, 0   },
+/* fe */ {Cache_UNKNOWN, 0   },
+/* ff */ {Cache_UNKNOWN, 0   }
+};
+
+
+/*
+ * use the above table to determine the CacheEntryLineSize.
+ */
+static void
+getIntelCacheEntryLineSize(unsigned long val, int *level, 
+						unsigned long *lineSize)
+{
+    CacheType type;
+
+    type = CacheMap[val].type;
+    /* only interested in data caches */
+    /* NOTE val = 0x40 is a special value that means no L2 or L3 cache.
+     * this data check has the side effect of rejecting that entry. If
+     * that wasn't the case, we could have to reject it explicitly */
+    if (CacheMap[val].lineSize == 0) {
+	return;
+    }
+    /* look at the caches, skip types we aren't interested in.
+     * if we already have a value for a lower level cache, skip the
+     * current entry */
+    if ((type == Cache_L1)|| (type == Cache_L1d)) {
+	*level = 1;
+	*lineSize = CacheMap[val].lineSize;
+    } else if ((*level >= 2) && ((type == Cache_L2) || (type == Cache_L2d))) {
+	*level = 2;
+	*lineSize = CacheMap[val].lineSize;
+    } else if ((*level >= 3) && ((type == Cache_L3) || (type == Cache_L3d))) {
+	*level = 3;
+	*lineSize = CacheMap[val].lineSize;
+    }
+    return;
+}
+
+
+static void
+getIntelRegisterCacheLineSize(unsigned long val, 
+			int *level, unsigned long *lineSize)
+{
+    getIntelCacheEntryLineSize(val >> 24 & 0xff, level, lineSize);
+    getIntelCacheEntryLineSize(val >> 16 & 0xff, level, lineSize);
+    getIntelCacheEntryLineSize(val >> 8 & 0xff, level, lineSize);
+    getIntelCacheEntryLineSize(val & 0xff, level, lineSize);
+}
+
+/*
+ * returns '0' if no recognized cache is found, or if the cache
+ * information is supported by this processor 
+ */
+static unsigned long
+getIntelCacheLineSize(int cpuidLevel)
+{
+    int level = 4;
+    unsigned long lineSize = 0;
+    unsigned long eax, ebx, ecx, edx;
+    int repeat, count;
+
+    if (cpuidLevel < 2) {
+	return 0;
+    }
+
+    /* command '2' of the cpuid is intel's cache info call. Each byte of the
+     * 4 registers contain a potential descriptor for the cache. The CacheMap	
+     * table maps the cache entry with the processor cache. Register 'al'
+     * contains a count value that cpuid '2' needs to be called in order to 
+     * find all the cache descriptors. Only registers with the high bit set
+     * to 'zero' have valid descriptors. This code loops through all the
+     * required calls to cpuid '2' and passes any valid descriptors it finds
+     * to the getIntelRegisterCacheLineSize code, which breaks the registers
+     * down into their component descriptors. In the end the lineSize of the
+     * lowest level cache data cache is returned. */
+    freebl_cpuid(2, &eax, &ebx, &ecx, &edx);
+    repeat = eax & 0xf;
+    for (count = 0; count < repeat; count++) {
+	if ((eax & 0x80000000) == 0) {
+	    getIntelRegisterCacheLineSize(eax & 0xffffff00, &level, &lineSize);
+	}
+	if ((ebx & 0x80000000) == 0) {
+	    getIntelRegisterCacheLineSize(ebx, &level, &lineSize);
+	}
+	if ((ecx & 0x80000000) == 0) {
+	    getIntelRegisterCacheLineSize(ecx, &level, &lineSize);
+	}
+	if ((edx & 0x80000000) == 0) {
+	    getIntelRegisterCacheLineSize(edx, &level, &lineSize);
+	}
+	if (count+1 != repeat) {
+	    freebl_cpuid(2, &eax, &ebx, &ecx, &edx);
+	}
+    }
+    return lineSize;
+}
+
+/*
+ * returns '0' if the cache info is not supported by this processor.
+ * This is based on the AMD extended cache commands for cpuid. 
+ * (see "AMD Processor Recognition Application Note" Publication 20734).
+ * Some other processors use the identical scheme.
+ * (see "Processor Recognition, Transmeta Corporation").
+ */
+static unsigned long
+getOtherCacheLineSize(unsigned long cpuidLevel)
+{
+    unsigned long lineSize = 0;
+    unsigned long eax, ebx, ecx, edx;
+
+    /* get the Extended CPUID level */
+    freebl_cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
+    cpuidLevel = eax;
+
+    if (cpuidLevel >= 0x80000005) {
+	freebl_cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+	lineSize = ecx & 0xff; /* line Size, L1 Data Cache */
+    }
+    return lineSize;
+}
+
+static const char * const manMap[] = {
+#define INTEL     0
+    "GenuineIntel",
+#define AMD       1
+    "AuthenticAMD",
+#define CYRIX     2
+    "CyrixInstead",
+#define CENTAUR   2
+    "CentaurHauls",
+#define NEXGEN    3
+    "NexGenDriven",
+#define TRANSMETA 4
+    "GenuineTMx86",
+#define RISE      5
+    "RiseRiseRise",
+#define UMC       6
+    "UMC UMC UMC ",
+#define SIS       7
+    "Sis Sis Sis ",
+#define NATIONAL  8
+    "Geode by NSC",
+};
+
+static const int n_manufacturers = sizeof(manMap)/sizeof(manMap[0]);
+
+
+#define MAN_UNKNOWN 9
+
+#if !defined(AMD_64)
+#define SSE2_FLAG (1<<26)
+unsigned long
+s_mpi_is_sse2()
+{
+    unsigned long eax, ebx, ecx, edx;
+    int manufacturer = MAN_UNKNOWN;
+    int i;
+    char string[13];
+
+    if (is386() || is486()) {
+	return 0;
+    }
+    freebl_cpuid(0, &eax, &ebx, &ecx, &edx);
+    *(int *)string = ebx;
+    *(int *)&string[4] = edx;
+    *(int *)&string[8] = ecx;
+    string[12] = 0;
+
+    /* has no SSE2 extensions */
+    if (eax == 0) {
+	return 0;
+    }
+
+    for (i=0; i < n_manufacturers; i++) {
+	if ( strcmp(manMap[i],string) == 0) {
+	    manufacturer = i;
+	    break;
+	}
+    }
+
+    freebl_cpuid(1,&eax,&ebx,&ecx,&edx);
+    return (edx & SSE2_FLAG) == SSE2_FLAG;
+}
+#endif
+
+unsigned long
+s_mpi_getProcessorLineSize()
+{
+    unsigned long eax, ebx, ecx, edx;
+    unsigned long cpuidLevel;
+    unsigned long cacheLineSize = 0;
+    int manufacturer = MAN_UNKNOWN;
+    int i;
+    char string[65];
+
+#if !defined(AMD_64)
+    if (is386()) {
+	return 0; /* 386 had no cache */
+    } if (is486()) {
+	return 32; /* really? need more info */
+    }
+#endif
+
+    /* Pentium, cpuid command is available */
+    freebl_cpuid(0, &eax, &ebx, &ecx, &edx);
+    cpuidLevel = eax;
+    *(int *)string = ebx;
+    *(int *)&string[4] = edx;
+    *(int *)&string[8] = ecx;
+    string[12] = 0;
+
+    manufacturer = MAN_UNKNOWN;
+    for (i=0; i < n_manufacturers; i++) {
+	if ( strcmp(manMap[i],string) == 0) {
+	    manufacturer = i;
+	}
+    }
+
+    if (manufacturer == INTEL) {
+	cacheLineSize = getIntelCacheLineSize(cpuidLevel);
+    } else {
+	cacheLineSize = getOtherCacheLineSize(cpuidLevel);
+    }
+    /* doesn't support cache info based on cpuid. This means
+     * an old pentium class processor, which have cache lines of
+     * 32. If we learn differently, we can use a switch based on
+     * the Manufacturer id  */
+    if (cacheLineSize == 0) {
+	cacheLineSize = 32;
+    }
+    return cacheLineSize;
+}
+#define MPI_GET_PROCESSOR_LINE_SIZE_DEFINED 1
+#endif
+
+#if defined(__ppc64__) 
+/*
+ *  Sigh, The PPC has some really nice features to help us determine cache
+ *  size, since it had lots of direct control functions to do so. The POWER
+ *  processor even has an instruction to do this, but it was dropped in
+ *  PowerPC. Unfortunately most of them are not available in user mode.
+ *
+ *  The dcbz function would be a great way to determine cache line size except
+ *  1) it only works on write-back memory (it throws an exception otherwise), 
+ *  and 2) because so many mac programs 'knew' the processor cache size was
+ *  32 bytes, they used this instruction as a fast 'zero 32 bytes'. Now the new
+ *  G5 processor has 128 byte cache, but dcbz only clears 32 bytes to keep
+ *  these programs happy. dcbzl work if 64 bit instructions are supported.
+ *  If you know 64 bit instructions are supported, and that stack is 
+ *  write-back, you can use this code.
+ */
+#include "memory.h"
+
+/* clear the cache line that contains 'array' */
+static inline void dcbzl(char *array)
+{
+	register char *a asm("r2") = array;
+	__asm__ __volatile__( "dcbzl %0,r0" : "=r" (a): "0"(a) );
+}
+
+
+#define PPC_DO_ALIGN(x,y) ((char *)\
+			((((long long) (x))+((y)-1))&~((y)-1)))
+
+#define PPC_MAX_LINE_SIZE 256
+unsigned long
+s_mpi_getProcessorLineSize()
+{
+    char testArray[2*PPC_MAX_LINE_SIZE+1];
+    char *test;
+    int i;
+
+    /* align the array on a maximum line size boundary, so we
+     * know we are starting to clear from the first address */
+    test = PPC_DO_ALIGN(testArray, PPC_MAX_LINE_SIZE); 
+    /* set all the values to 1's */
+    memset(test, 0xff, PPC_MAX_LINE_SIZE);
+    /* clear one cache block starting at 'test' */
+    dcbzl(test);
+
+    /* find the size of the cleared area, that's our block size */
+    for (i=PPC_MAX_LINE_SIZE; i != 0; i = i/2) {
+	if (test[i-1] == 0) {
+	    return i;
+	}
+    }
+    return 0;
+}
+
+#define MPI_GET_PROCESSOR_LINE_SIZE_DEFINED 1
+#endif
+
+
+/*
+ * put other processor and platform specific cache code here
+ * return the smallest cache line size in bytes on the processor 
+ * (usually the L1 cache). If the OS has a call, this would be
+ * a greate place to put it.
+ *
+ * If there is no cache, return 0;
+ * 
+ * define MPI_GET_PROCESSOR_LINE_SIZE_DEFINED so the generic functions
+ * below aren't compiled.
+ *
+ */
+
+
+/* target.mk can define MPI_CACHE_LINE_SIZE if it's common for the family or 
+ * OS */
+#if defined(MPI_CACHE_LINE_SIZE) && !defined(MPI_GET_PROCESSOR_LINE_SIZE_DEFINED)
+
+unsigned long
+s_mpi_getProcessorLineSize()
+{
+   return MPI_CACHE_LINE_SIZE;
+}
+#define MPI_GET_PROCESSOR_LINE_SIZE_DEFINED 1
+#endif
+
+
+/* If no way to get the processor cache line size has been defined, assume
+ * it's 32 bytes (most common value, does not significantly impact performance)
+ */ 
+#ifndef MPI_GET_PROCESSOR_LINE_SIZE_DEFINED
+unsigned long
+s_mpi_getProcessorLineSize()
+{
+   return 32;
+}
+#endif
+
+#ifdef TEST_IT
+#include <stdio.h>
+
+main()
+{
+    printf("line size = %d\n", s_mpi_getProcessorLineSize());
+} 
+#endif
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpi-config.h b/mozilla/security/nss/lib/freebl/mpi/mpi-config.h
new file mode 100644
index 0000000..00a0acf
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpi-config.h
@@ -0,0 +1,112 @@
+/* Default configuration for MPI library 
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1997
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Netscape Communications Corporation
+ *
+ * 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 ***** */
+/* $Id: mpi-config.h,v 1.5 2004/04/25 15:03:10 gerv%gerv.net Exp $ */
+
+#ifndef MPI_CONFIG_H_
+#define MPI_CONFIG_H_
+
+/*
+  For boolean options, 
+  0 = no
+  1 = yes
+
+  Other options are documented individually.
+
+ */
+
+#ifndef MP_IOFUNC
+#define MP_IOFUNC     0  /* include mp_print() ?                */
+#endif
+
+#ifndef MP_MODARITH
+#define MP_MODARITH   1  /* include modular arithmetic ?        */
+#endif
+
+#ifndef MP_NUMTH
+#define MP_NUMTH      1  /* include number theoretic functions? */
+#endif
+
+#ifndef MP_LOGTAB
+#define MP_LOGTAB     1  /* use table of logs instead of log()? */
+#endif
+
+#ifndef MP_MEMSET
+#define MP_MEMSET     1  /* use memset() to zero buffers?       */
+#endif
+
+#ifndef MP_MEMCPY
+#define MP_MEMCPY     1  /* use memcpy() to copy buffers?       */
+#endif
+
+#ifndef MP_CRYPTO
+#define MP_CRYPTO     1  /* erase memory on free?               */
+#endif
+
+#ifndef MP_ARGCHK
+/*
+  0 = no parameter checks
+  1 = runtime checks, continue execution and return an error to caller
+  2 = assertions; dump core on parameter errors
+ */
+#ifdef DEBUG
+#define MP_ARGCHK     2  /* how to check input arguments        */
+#else
+#define MP_ARGCHK     1  /* how to check input arguments        */
+#endif
+#endif
+
+#ifndef MP_DEBUG
+#define MP_DEBUG      0  /* print diagnostic output?            */
+#endif
+
+#ifndef MP_DEFPREC
+#define MP_DEFPREC    64 /* default precision, in digits        */
+#endif
+
+#ifndef MP_MACRO
+#define MP_MACRO      0  /* use macros for frequent calls?      */
+#endif
+
+#ifndef MP_SQUARE
+#define MP_SQUARE     1  /* use separate squaring code?         */
+#endif
+
+#endif /* ifndef MPI_CONFIG_H_ */
+
+
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpi-priv.h b/mozilla/security/nss/lib/freebl/mpi/mpi-priv.h
new file mode 100644
index 0000000..92c8fbf
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpi-priv.h
@@ -0,0 +1,319 @@
+/*
+ *  mpi-priv.h	- Private header file for MPI 
+ *  Arbitrary precision integer arithmetic library
+ *
+ *  NOTE WELL: the content of this header file is NOT part of the "public"
+ *  API for the MPI library, and may change at any time.  
+ *  Application programs that use libmpi should NOT include this header file.
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Netscape Communications Corporation
+ *
+ * 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 ***** */
+/* $Id: mpi-priv.h,v 1.21 2009/03/19 02:26:48 julien.pierre.boogz%sun.com Exp $ */
+#ifndef _MPI_PRIV_H_
+#define _MPI_PRIV_H_ 1
+
+#include "mpi.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#if MP_DEBUG
+#include <stdio.h>
+
+#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);}
+#else
+#define DIAG(T,V)
+#endif
+
+/* If we aren't using a wired-in logarithm table, we need to include
+   the math library to get the log() function
+ */
+
+/* {{{ s_logv_2[] - log table for 2 in various bases */
+
+#if MP_LOGTAB
+/*
+  A table of the logs of 2 for various bases (the 0 and 1 entries of
+  this table are meaningless and should not be referenced).  
+
+  This table is used to compute output lengths for the mp_toradix()
+  function.  Since a number n in radix r takes up about log_r(n)
+  digits, we estimate the output size by taking the least integer
+  greater than log_r(n), where:
+
+  log_r(n) = log_2(n) * log_r(2)
+
+  This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
+  which are the output bases supported.  
+ */
+
+extern const float s_logv_2[];
+#define LOG_V_2(R)  s_logv_2[(R)]
+
+#else
+
+/* 
+   If MP_LOGTAB is not defined, use the math library to compute the
+   logarithms on the fly.  Otherwise, use the table.
+   Pick which works best for your system.
+ */
+
+#include <math.h>
+#define LOG_V_2(R)  (log(2.0)/log(R))
+
+#endif /* if MP_LOGTAB */
+
+/* }}} */
+
+/* {{{ Digit arithmetic macros */
+
+/*
+  When adding and multiplying digits, the results can be larger than
+  can be contained in an mp_digit.  Thus, an mp_word is used.  These
+  macros mask off the upper and lower digits of the mp_word (the
+  mp_word may be more than 2 mp_digits wide, but we only concern
+  ourselves with the low-order 2 mp_digits)
+ */
+
+#define  CARRYOUT(W)  (mp_digit)((W)>>DIGIT_BIT)
+#define  ACCUM(W)     (mp_digit)(W)
+
+#define MP_MIN(a,b)   (((a) < (b)) ? (a) : (b))
+#define MP_MAX(a,b)   (((a) > (b)) ? (a) : (b))
+#define MP_HOWMANY(a,b) (((a) + (b) - 1)/(b))
+#define MP_ROUNDUP(a,b) (MP_HOWMANY(a,b) * (b))
+
+/* }}} */
+
+/* {{{ Comparison constants */
+
+#define  MP_LT       -1
+#define  MP_EQ        0
+#define  MP_GT        1
+
+/* }}} */
+
+/* {{{ private function declarations */
+
+/* 
+   If MP_MACRO is false, these will be defined as actual functions;
+   otherwise, suitable macro definitions will be used.  This works
+   around the fact that ANSI C89 doesn't support an 'inline' keyword
+   (although I hear C9x will ... about bloody time).  At present, the
+   macro definitions are identical to the function bodies, but they'll
+   expand in place, instead of generating a function call.
+
+   I chose these particular functions to be made into macros because
+   some profiling showed they are called a lot on a typical workload,
+   and yet they are primarily housekeeping.
+ */
+#if MP_MACRO == 0
+ void     s_mp_setz(mp_digit *dp, mp_size count); /* zero digits           */
+ void     s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count); /* copy */
+ void    *s_mp_alloc(size_t nb, size_t ni);       /* general allocator     */
+ void     s_mp_free(void *ptr);                   /* general free function */
+extern unsigned long mp_allocs;
+extern unsigned long mp_frees;
+extern unsigned long mp_copies;
+#else
+
+ /* Even if these are defined as macros, we need to respect the settings
+    of the MP_MEMSET and MP_MEMCPY configuration options...
+  */
+ #if MP_MEMSET == 0
+  #define  s_mp_setz(dp, count) \
+       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;}
+ #else
+  #define  s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit))
+ #endif /* MP_MEMSET */
+
+ #if MP_MEMCPY == 0
+  #define  s_mp_copy(sp, dp, count) \
+       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];}
+ #else
+  #define  s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit))
+ #endif /* MP_MEMCPY */
+
+ #define  s_mp_alloc(nb, ni)  calloc(nb, ni)
+ #define  s_mp_free(ptr) {if(ptr) free(ptr);}
+#endif /* MP_MACRO */
+
+mp_err   s_mp_grow(mp_int *mp, mp_size min);   /* increase allocated size */
+mp_err   s_mp_pad(mp_int *mp, mp_size min);    /* left pad with zeroes    */
+
+#if MP_MACRO == 0
+ void     s_mp_clamp(mp_int *mp);               /* clip leading zeroes     */
+#else
+ #define  s_mp_clamp(mp)\
+  { mp_size used = MP_USED(mp); \
+    while (used > 1 && DIGIT(mp, used - 1) == 0) --used; \
+    MP_USED(mp) = used; \
+  } 
+#endif /* MP_MACRO */
+
+void     s_mp_exch(mp_int *a, mp_int *b);      /* swap a and b in place   */
+
+mp_err   s_mp_lshd(mp_int *mp, mp_size p);     /* left-shift by p digits  */
+void     s_mp_rshd(mp_int *mp, mp_size p);     /* right-shift by p digits */
+mp_err   s_mp_mul_2d(mp_int *mp, mp_digit d);  /* multiply by 2^d in place */
+void     s_mp_div_2d(mp_int *mp, mp_digit d);  /* divide by 2^d in place  */
+void     s_mp_mod_2d(mp_int *mp, mp_digit d);  /* modulo 2^d in place     */
+void     s_mp_div_2(mp_int *mp);               /* divide by 2 in place    */
+mp_err   s_mp_mul_2(mp_int *mp);               /* multiply by 2 in place  */
+mp_err   s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd); 
+                                               /* normalize for division  */
+mp_err   s_mp_add_d(mp_int *mp, mp_digit d);   /* unsigned digit addition */
+mp_err   s_mp_sub_d(mp_int *mp, mp_digit d);   /* unsigned digit subtract */
+mp_err   s_mp_mul_d(mp_int *mp, mp_digit d);   /* unsigned digit multiply */
+mp_err   s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r);
+		                               /* unsigned digit divide   */
+mp_err   s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu);
+                                               /* Barrett reduction       */
+mp_err   s_mp_add(mp_int *a, const mp_int *b); /* magnitude addition      */
+mp_err   s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err   s_mp_sub(mp_int *a, const mp_int *b); /* magnitude subtract      */
+mp_err   s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err   s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset);
+                                               /* a += b * RADIX^offset   */
+mp_err   s_mp_mul(mp_int *a, const mp_int *b); /* magnitude multiply      */
+#if MP_SQUARE
+mp_err   s_mp_sqr(mp_int *a);                  /* magnitude square        */
+#else
+#define  s_mp_sqr(a) s_mp_mul(a, a)
+#endif
+mp_err   s_mp_div(mp_int *rem, mp_int *div, mp_int *quot); /* magnitude div */
+mp_err   s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err   s_mp_2expt(mp_int *a, mp_digit k);    /* a = 2^k                 */
+int      s_mp_cmp(const mp_int *a, const mp_int *b); /* magnitude comparison */
+int      s_mp_cmp_d(const mp_int *a, mp_digit d); /* magnitude digit compare */
+int      s_mp_ispow2(const mp_int *v);         /* is v a power of 2?      */
+int      s_mp_ispow2d(mp_digit d);             /* is d a power of 2?      */
+
+int      s_mp_tovalue(char ch, int r);          /* convert ch to value    */
+char     s_mp_todigit(mp_digit val, int r, int low); /* convert val to digit */
+int      s_mp_outlen(int bits, int r);          /* output length in bytes */
+mp_digit s_mp_invmod_radix(mp_digit P);   /* returns (P ** -1) mod RADIX */
+mp_err   s_mp_invmod_odd_m( const mp_int *a, const mp_int *m, mp_int *c);
+mp_err   s_mp_invmod_2d(    const mp_int *a, mp_size k,       mp_int *c);
+mp_err   s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c);
+
+#ifdef NSS_USE_COMBA
+
+#define IS_POWER_OF_2(a) ((a) && !((a) & ((a)-1)))
+
+void s_mp_mul_comba_4(const mp_int *A, const mp_int *B, mp_int *C);
+void s_mp_mul_comba_8(const mp_int *A, const mp_int *B, mp_int *C);
+void s_mp_mul_comba_16(const mp_int *A, const mp_int *B, mp_int *C);
+void s_mp_mul_comba_32(const mp_int *A, const mp_int *B, mp_int *C);
+
+void s_mp_sqr_comba_4(const mp_int *A, mp_int *B);
+void s_mp_sqr_comba_8(const mp_int *A, mp_int *B);
+void s_mp_sqr_comba_16(const mp_int *A, mp_int *B);
+void s_mp_sqr_comba_32(const mp_int *A, mp_int *B);
+
+#endif /* end NSS_USE_COMBA */
+
+/* ------ mpv functions, operate on arrays of digits, not on mp_int's ------ */
+#if defined (__OS2__) && defined (__IBMC__)
+#define MPI_ASM_DECL __cdecl
+#else
+#define MPI_ASM_DECL
+#endif
+
+#ifdef MPI_AMD64
+
+mp_digit MPI_ASM_DECL s_mpv_mul_set_vec64(mp_digit*, mp_digit *, mp_size, mp_digit);
+mp_digit MPI_ASM_DECL s_mpv_mul_add_vec64(mp_digit*, const mp_digit*, mp_size, mp_digit);
+
+/* c = a * b */
+#define s_mpv_mul_d(a, a_len, b, c) \
+	((mp_digit *)c)[a_len] = s_mpv_mul_set_vec64(c, a, a_len, b)
+
+/* c += a * b */
+#define s_mpv_mul_d_add(a, a_len, b, c) \
+	((mp_digit *)c)[a_len] = s_mpv_mul_add_vec64(c, a, a_len, b)
+
+
+#else
+
+void     MPI_ASM_DECL s_mpv_mul_d(const mp_digit *a, mp_size a_len,
+                                        mp_digit b, mp_digit *c);
+void     MPI_ASM_DECL s_mpv_mul_d_add(const mp_digit *a, mp_size a_len,
+                                            mp_digit b, mp_digit *c);
+
+#endif
+
+void     MPI_ASM_DECL s_mpv_mul_d_add_prop(const mp_digit *a,
+                                                mp_size a_len, mp_digit b, 
+			                        mp_digit *c);
+void     MPI_ASM_DECL s_mpv_sqr_add_prop(const mp_digit *a,
+                                                mp_size a_len,
+                                                mp_digit *sqrs);
+
+mp_err   MPI_ASM_DECL s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo,
+                            mp_digit divisor, mp_digit *quot, mp_digit *rem);
+
+/* c += a * b * (MP_RADIX ** offset);  */
+#define s_mp_mul_d_add_offset(a, b, c, off) \
+(s_mpv_mul_d_add_prop(MP_DIGITS(a), MP_USED(a), b, MP_DIGITS(c) + off), MP_OKAY)
+
+typedef struct {
+  mp_int       N;	/* modulus N */
+  mp_digit     n0prime; /* n0' = - (n0 ** -1) mod MP_RADIX */
+  mp_size      b;	/* R == 2 ** b,  also b = # significant bits in N */
+} mp_mont_modulus;
+
+mp_err s_mp_mul_mont(const mp_int *a, const mp_int *b, mp_int *c, 
+	               mp_mont_modulus *mmm);
+mp_err s_mp_redc(mp_int *T, mp_mont_modulus *mmm);
+
+/*
+ * s_mpi_getProcessorLineSize() returns the size in bytes of the cache line
+ * if a cache exists, or zero if there is no cache. If more than one
+ * cache line exists, it should return the smallest line size (which is
+ * usually the L1 cache).
+ *
+ * mp_modexp uses this information to make sure that private key information
+ * isn't being leaked through the cache.
+ *
+ * see mpcpucache.c for the implementation.
+ */
+unsigned long s_mpi_getProcessorLineSize();
+
+/* }}} */
+#endif
+
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpi.c b/mozilla/security/nss/lib/freebl/mpi/mpi.c
new file mode 100644
index 0000000..2fcde38
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpi.c
@@ -0,0 +1,4850 @@
+/*
+ *  mpi.c
+ *
+ *  Arbitrary precision integer arithmetic library
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Netscape Communications Corporation
+ *   Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ * 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 ***** */
+/* $Id: mpi.c,v 1.45 2006/09/29 20:12:21 alexei.volkov.bugs%sun.com Exp $ */
+
+#include "mpi-priv.h"
+#if defined(OSF1)
+#include <c_asm.h>
+#endif
+
+#if MP_LOGTAB
+/*
+  A table of the logs of 2 for various bases (the 0 and 1 entries of
+  this table are meaningless and should not be referenced).  
+
+  This table is used to compute output lengths for the mp_toradix()
+  function.  Since a number n in radix r takes up about log_r(n)
+  digits, we estimate the output size by taking the least integer
+  greater than log_r(n), where:
+
+  log_r(n) = log_2(n) * log_r(2)
+
+  This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
+  which are the output bases supported.  
+ */
+#include "logtab.h"
+#endif
+
+/* {{{ Constant strings */
+
+/* Constant strings returned by mp_strerror() */
+static const char *mp_err_string[] = {
+  "unknown result code",     /* say what?            */
+  "boolean true",            /* MP_OKAY, MP_YES      */
+  "boolean false",           /* MP_NO                */
+  "out of memory",           /* MP_MEM               */
+  "argument out of range",   /* MP_RANGE             */
+  "invalid input parameter", /* MP_BADARG            */
+  "result is undefined"      /* MP_UNDEF             */
+};
+
+/* Value to digit maps for radix conversion   */
+
+/* s_dmap_1 - standard digits and letters */
+static const char *s_dmap_1 = 
+  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+/* }}} */
+
+unsigned long mp_allocs;
+unsigned long mp_frees;
+unsigned long mp_copies;
+
+/* {{{ Default precision manipulation */
+
+/* Default precision for newly created mp_int's      */
+static mp_size s_mp_defprec = MP_DEFPREC;
+
+mp_size mp_get_prec(void)
+{
+  return s_mp_defprec;
+
+} /* end mp_get_prec() */
+
+void         mp_set_prec(mp_size prec)
+{
+  if(prec == 0)
+    s_mp_defprec = MP_DEFPREC;
+  else
+    s_mp_defprec = prec;
+
+} /* end mp_set_prec() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mp_init(mp) */
+
+/*
+  mp_init(mp)
+
+  Initialize a new zero-valued mp_int.  Returns MP_OKAY if successful,
+  MP_MEM if memory could not be allocated for the structure.
+ */
+
+mp_err mp_init(mp_int *mp)
+{
+  return mp_init_size(mp, s_mp_defprec);
+
+} /* end mp_init() */
+
+/* }}} */
+
+/* {{{ mp_init_size(mp, prec) */
+
+/*
+  mp_init_size(mp, prec)
+
+  Initialize a new zero-valued mp_int with at least the given
+  precision; returns MP_OKAY if successful, or MP_MEM if memory could
+  not be allocated for the structure.
+ */
+
+mp_err mp_init_size(mp_int *mp, mp_size prec)
+{
+  ARGCHK(mp != NULL && prec > 0, MP_BADARG);
+
+  prec = MP_ROUNDUP(prec, s_mp_defprec);
+  if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL)
+    return MP_MEM;
+
+  SIGN(mp) = ZPOS;
+  USED(mp) = 1;
+  ALLOC(mp) = prec;
+
+  return MP_OKAY;
+
+} /* end mp_init_size() */
+
+/* }}} */
+
+/* {{{ mp_init_copy(mp, from) */
+
+/*
+  mp_init_copy(mp, from)
+
+  Initialize mp as an exact copy of from.  Returns MP_OKAY if
+  successful, MP_MEM if memory could not be allocated for the new
+  structure.
+ */
+
+mp_err mp_init_copy(mp_int *mp, const mp_int *from)
+{
+  ARGCHK(mp != NULL && from != NULL, MP_BADARG);
+
+  if(mp == from)
+    return MP_OKAY;
+
+  if((DIGITS(mp) = s_mp_alloc(ALLOC(from), sizeof(mp_digit))) == NULL)
+    return MP_MEM;
+
+  s_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
+  USED(mp) = USED(from);
+  ALLOC(mp) = ALLOC(from);
+  SIGN(mp) = SIGN(from);
+
+  return MP_OKAY;
+
+} /* end mp_init_copy() */
+
+/* }}} */
+
+/* {{{ mp_copy(from, to) */
+
+/*
+  mp_copy(from, to)
+
+  Copies the mp_int 'from' to the mp_int 'to'.  It is presumed that
+  'to' has already been initialized (if not, use mp_init_copy()
+  instead). If 'from' and 'to' are identical, nothing happens.
+ */
+
+mp_err mp_copy(const mp_int *from, mp_int *to)
+{
+  ARGCHK(from != NULL && to != NULL, MP_BADARG);
+
+  if(from == to)
+    return MP_OKAY;
+
+  ++mp_copies;
+  { /* copy */
+    mp_digit   *tmp;
+
+    /*
+      If the allocated buffer in 'to' already has enough space to hold
+      all the used digits of 'from', we'll re-use it to avoid hitting
+      the memory allocater more than necessary; otherwise, we'd have
+      to grow anyway, so we just allocate a hunk and make the copy as
+      usual
+     */
+    if(ALLOC(to) >= USED(from)) {
+      s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
+      s_mp_copy(DIGITS(from), DIGITS(to), USED(from));
+      
+    } else {
+      if((tmp = s_mp_alloc(ALLOC(from), sizeof(mp_digit))) == NULL)
+	return MP_MEM;
+
+      s_mp_copy(DIGITS(from), tmp, USED(from));
+
+      if(DIGITS(to) != NULL) {
+#if MP_CRYPTO
+	s_mp_setz(DIGITS(to), ALLOC(to));
+#endif
+	s_mp_free(DIGITS(to));
+      }
+
+      DIGITS(to) = tmp;
+      ALLOC(to) = ALLOC(from);
+    }
+
+    /* Copy the precision and sign from the original */
+    USED(to) = USED(from);
+    SIGN(to) = SIGN(from);
+  } /* end copy */
+
+  return MP_OKAY;
+
+} /* end mp_copy() */
+
+/* }}} */
+
+/* {{{ mp_exch(mp1, mp2) */
+
+/*
+  mp_exch(mp1, mp2)
+
+  Exchange mp1 and mp2 without allocating any intermediate memory
+  (well, unless you count the stack space needed for this call and the
+  locals it creates...).  This cannot fail.
+ */
+
+void mp_exch(mp_int *mp1, mp_int *mp2)
+{
+#if MP_ARGCHK == 2
+  assert(mp1 != NULL && mp2 != NULL);
+#else
+  if(mp1 == NULL || mp2 == NULL)
+    return;
+#endif
+
+  s_mp_exch(mp1, mp2);
+
+} /* end mp_exch() */
+
+/* }}} */
+
+/* {{{ mp_clear(mp) */
+
+/*
+  mp_clear(mp)
+
+  Release the storage used by an mp_int, and void its fields so that
+  if someone calls mp_clear() again for the same int later, we won't
+  get tollchocked.
+ */
+
+void   mp_clear(mp_int *mp)
+{
+  if(mp == NULL)
+    return;
+
+  if(DIGITS(mp) != NULL) {
+#if MP_CRYPTO
+    s_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+    s_mp_free(DIGITS(mp));
+    DIGITS(mp) = NULL;
+  }
+
+  USED(mp) = 0;
+  ALLOC(mp) = 0;
+
+} /* end mp_clear() */
+
+/* }}} */
+
+/* {{{ mp_zero(mp) */
+
+/*
+  mp_zero(mp) 
+
+  Set mp to zero.  Does not change the allocated size of the structure,
+  and therefore cannot fail (except on a bad argument, which we ignore)
+ */
+void   mp_zero(mp_int *mp)
+{
+  if(mp == NULL)
+    return;
+
+  s_mp_setz(DIGITS(mp), ALLOC(mp));
+  USED(mp) = 1;
+  SIGN(mp) = ZPOS;
+
+} /* end mp_zero() */
+
+/* }}} */
+
+/* {{{ mp_set(mp, d) */
+
+void   mp_set(mp_int *mp, mp_digit d)
+{
+  if(mp == NULL)
+    return;
+
+  mp_zero(mp);
+  DIGIT(mp, 0) = d;
+
+} /* end mp_set() */
+
+/* }}} */
+
+/* {{{ mp_set_int(mp, z) */
+
+mp_err mp_set_int(mp_int *mp, long z)
+{
+  int            ix;
+  unsigned long  v = labs(z);
+  mp_err         res;
+
+  ARGCHK(mp != NULL, MP_BADARG);
+
+  mp_zero(mp);
+  if(z == 0)
+    return MP_OKAY;  /* shortcut for zero */
+
+  if (sizeof v <= sizeof(mp_digit)) {
+    DIGIT(mp,0) = v;
+  } else {
+    for (ix = sizeof(long) - 1; ix >= 0; ix--) {
+      if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
+	return res;
+
+      res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
+      if (res != MP_OKAY)
+	return res;
+    }
+  }
+  if(z < 0)
+    SIGN(mp) = NEG;
+
+  return MP_OKAY;
+
+} /* end mp_set_int() */
+
+/* }}} */
+
+/* {{{ mp_set_ulong(mp, z) */
+
+mp_err mp_set_ulong(mp_int *mp, unsigned long z)
+{
+  int            ix;
+  mp_err         res;
+
+  ARGCHK(mp != NULL, MP_BADARG);
+
+  mp_zero(mp);
+  if(z == 0)
+    return MP_OKAY;  /* shortcut for zero */
+
+  if (sizeof z <= sizeof(mp_digit)) {
+    DIGIT(mp,0) = z;
+  } else {
+    for (ix = sizeof(long) - 1; ix >= 0; ix--) {
+      if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
+	return res;
+
+      res = s_mp_add_d(mp, (mp_digit)((z >> (ix * CHAR_BIT)) & UCHAR_MAX));
+      if (res != MP_OKAY)
+	return res;
+    }
+  }
+  return MP_OKAY;
+} /* end mp_set_ulong() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Digit arithmetic */
+
+/* {{{ mp_add_d(a, d, b) */
+
+/*
+  mp_add_d(a, d, b)
+
+  Compute the sum b = a + d, for a single digit d.  Respects the sign of
+  its primary addend (single digits are unsigned anyway).
+ */
+
+mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b)
+{
+  mp_int   tmp;
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+    return res;
+
+  if(SIGN(&tmp) == ZPOS) {
+    if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
+      goto CLEANUP;
+  } else if(s_mp_cmp_d(&tmp, d) >= 0) {
+    if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
+      goto CLEANUP;
+  } else {
+    mp_neg(&tmp, &tmp);
+
+    DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
+  }
+
+  if(s_mp_cmp_d(&tmp, 0) == 0)
+    SIGN(&tmp) = ZPOS;
+
+  s_mp_exch(&tmp, b);
+
+CLEANUP:
+  mp_clear(&tmp);
+  return res;
+
+} /* end mp_add_d() */
+
+/* }}} */
+
+/* {{{ mp_sub_d(a, d, b) */
+
+/*
+  mp_sub_d(a, d, b)
+
+  Compute the difference b = a - d, for a single digit d.  Respects the
+  sign of its subtrahend (single digits are unsigned anyway).
+ */
+
+mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b)
+{
+  mp_int   tmp;
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+    return res;
+
+  if(SIGN(&tmp) == NEG) {
+    if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
+      goto CLEANUP;
+  } else if(s_mp_cmp_d(&tmp, d) >= 0) {
+    if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
+      goto CLEANUP;
+  } else {
+    mp_neg(&tmp, &tmp);
+
+    DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
+    SIGN(&tmp) = NEG;
+  }
+
+  if(s_mp_cmp_d(&tmp, 0) == 0)
+    SIGN(&tmp) = ZPOS;
+
+  s_mp_exch(&tmp, b);
+
+CLEANUP:
+  mp_clear(&tmp);
+  return res;
+
+} /* end mp_sub_d() */
+
+/* }}} */
+
+/* {{{ mp_mul_d(a, d, b) */
+
+/*
+  mp_mul_d(a, d, b)
+
+  Compute the product b = a * d, for a single digit d.  Respects the sign
+  of its multiplicand (single digits are unsigned anyway)
+ */
+
+mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if(d == 0) {
+    mp_zero(b);
+    return MP_OKAY;
+  }
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  res = s_mp_mul_d(b, d);
+
+  return res;
+
+} /* end mp_mul_d() */
+
+/* }}} */
+
+/* {{{ mp_mul_2(a, c) */
+
+mp_err mp_mul_2(const mp_int *a, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, c)) != MP_OKAY)
+    return res;
+
+  return s_mp_mul_2(c);
+
+} /* end mp_mul_2() */
+
+/* }}} */
+
+/* {{{ mp_div_d(a, d, q, r) */
+
+/*
+  mp_div_d(a, d, q, r)
+
+  Compute the quotient q = a / d and remainder r = a mod d, for a
+  single digit d.  Respects the sign of its divisor (single digits are
+  unsigned anyway).
+ */
+
+mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r)
+{
+  mp_err   res;
+  mp_int   qp;
+  mp_digit rem;
+  int      pow;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  if(d == 0)
+    return MP_RANGE;
+
+  /* Shortcut for powers of two ... */
+  if((pow = s_mp_ispow2d(d)) >= 0) {
+    mp_digit  mask;
+
+    mask = ((mp_digit)1 << pow) - 1;
+    rem = DIGIT(a, 0) & mask;
+
+    if(q) {
+      mp_copy(a, q);
+      s_mp_div_2d(q, pow);
+    }
+
+    if(r)
+      *r = rem;
+
+    return MP_OKAY;
+  }
+
+  if((res = mp_init_copy(&qp, a)) != MP_OKAY)
+    return res;
+
+  res = s_mp_div_d(&qp, d, &rem);
+
+  if(s_mp_cmp_d(&qp, 0) == 0)
+    SIGN(q) = ZPOS;
+
+  if(r)
+    *r = rem;
+
+  if(q)
+    s_mp_exch(&qp, q);
+
+  mp_clear(&qp);
+  return res;
+
+} /* end mp_div_d() */
+
+/* }}} */
+
+/* {{{ mp_div_2(a, c) */
+
+/*
+  mp_div_2(a, c)
+
+  Compute c = a / 2, disregarding the remainder.
+ */
+
+mp_err mp_div_2(const mp_int *a, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, c)) != MP_OKAY)
+    return res;
+
+  s_mp_div_2(c);
+
+  return MP_OKAY;
+
+} /* end mp_div_2() */
+
+/* }}} */
+
+/* {{{ mp_expt_d(a, d, b) */
+
+mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c)
+{
+  mp_int   s, x;
+  mp_err   res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  DIGIT(&s, 0) = 1;
+
+  while(d != 0) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d /= 2;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  s_mp_exch(&s, c);
+
+CLEANUP:
+  mp_clear(&x);
+X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end mp_expt_d() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Full arithmetic */
+
+/* {{{ mp_abs(a, b) */
+
+/*
+  mp_abs(a, b)
+
+  Compute b = |a|.  'a' and 'b' may be identical.
+ */
+
+mp_err mp_abs(const mp_int *a, mp_int *b)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  SIGN(b) = ZPOS;
+
+  return MP_OKAY;
+
+} /* end mp_abs() */
+
+/* }}} */
+
+/* {{{ mp_neg(a, b) */
+
+/*
+  mp_neg(a, b)
+
+  Compute b = -a.  'a' and 'b' may be identical.
+ */
+
+mp_err mp_neg(const mp_int *a, mp_int *b)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  if(s_mp_cmp_d(b, 0) == MP_EQ) 
+    SIGN(b) = ZPOS;
+  else 
+    SIGN(b) = (SIGN(b) == NEG) ? ZPOS : NEG;
+
+  return MP_OKAY;
+
+} /* end mp_neg() */
+
+/* }}} */
+
+/* {{{ mp_add(a, b, c) */
+
+/*
+  mp_add(a, b, c)
+
+  Compute c = a + b.  All parameters may be identical.
+ */
+
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(SIGN(a) == SIGN(b)) { /* same sign:  add values, keep sign */
+    MP_CHECKOK( s_mp_add_3arg(a, b, c) );
+  } else if(s_mp_cmp(a, b) >= 0) {  /* different sign: |a| >= |b|   */
+    MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
+  } else {                          /* different sign: |a|  < |b|   */
+    MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
+  }
+
+  if (s_mp_cmp_d(c, 0) == MP_EQ)
+    SIGN(c) = ZPOS;
+
+CLEANUP:
+  return res;
+
+} /* end mp_add() */
+
+/* }}} */
+
+/* {{{ mp_sub(a, b, c) */
+
+/*
+  mp_sub(a, b, c)
+
+  Compute c = a - b.  All parameters may be identical.
+ */
+
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
+{
+  mp_err  res;
+  int     magDiff;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if (a == b) {
+    mp_zero(c);
+    return MP_OKAY;
+  }
+
+  if (MP_SIGN(a) != MP_SIGN(b)) {
+    MP_CHECKOK( s_mp_add_3arg(a, b, c) );
+  } else if (!(magDiff = s_mp_cmp(a, b))) {
+    mp_zero(c);
+    res = MP_OKAY;
+  } else if (magDiff > 0) {
+    MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
+  } else {
+    MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
+    MP_SIGN(c) = !MP_SIGN(a);
+  }
+
+  if (s_mp_cmp_d(c, 0) == MP_EQ)
+    MP_SIGN(c) = MP_ZPOS;
+
+CLEANUP:
+  return res;
+
+} /* end mp_sub() */
+
+/* }}} */
+
+/* {{{ mp_mul(a, b, c) */
+
+/*
+  mp_mul(a, b, c)
+
+  Compute c = a * b.  All parameters may be identical.
+ */
+mp_err   mp_mul(const mp_int *a, const mp_int *b, mp_int * c)
+{
+  mp_digit *pb;
+  mp_int   tmp;
+  mp_err   res;
+  mp_size  ib;
+  mp_size  useda, usedb;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if (a == c) {
+    if ((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+      return res;
+    if (a == b) 
+      b = &tmp;
+    a = &tmp;
+  } else if (b == c) {
+    if ((res = mp_init_copy(&tmp, b)) != MP_OKAY)
+      return res;
+    b = &tmp;
+  } else {
+    MP_DIGITS(&tmp) = 0;
+  }
+
+  if (MP_USED(a) < MP_USED(b)) {
+    const mp_int *xch = b;	/* switch a and b, to do fewer outer loops */
+    b = a;
+    a = xch;
+  }
+
+  MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
+  if((res = s_mp_pad(c, USED(a) + USED(b))) != MP_OKAY)
+    goto CLEANUP;
+
+#ifdef NSS_USE_COMBA
+  if ((MP_USED(a) == MP_USED(b)) && IS_POWER_OF_2(MP_USED(b))) {
+      if (MP_USED(a) == 4) {
+          s_mp_mul_comba_4(a, b, c);
+          goto CLEANUP;
+      }
+      if (MP_USED(a) == 8) {
+          s_mp_mul_comba_8(a, b, c);
+          goto CLEANUP;
+      }
+      if (MP_USED(a) == 16) {
+          s_mp_mul_comba_16(a, b, c);
+          goto CLEANUP;
+      }
+      if (MP_USED(a) == 32) {
+          s_mp_mul_comba_32(a, b, c);
+          goto CLEANUP;
+      } 
+  }
+#endif
+
+  pb = MP_DIGITS(b);
+  s_mpv_mul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c));
+
+  /* Outer loop:  Digits of b */
+  useda = MP_USED(a);
+  usedb = MP_USED(b);
+  for (ib = 1; ib < usedb; ib++) {
+    mp_digit b_i    = *pb++;
+
+    /* Inner product:  Digits of a */
+    if (b_i)
+      s_mpv_mul_d_add(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
+    else
+      MP_DIGIT(c, ib + useda) = b_i;
+  }
+
+  s_mp_clamp(c);
+
+  if(SIGN(a) == SIGN(b) || s_mp_cmp_d(c, 0) == MP_EQ)
+    SIGN(c) = ZPOS;
+  else
+    SIGN(c) = NEG;
+
+CLEANUP:
+  mp_clear(&tmp);
+  return res;
+} /* end mp_mul() */
+
+/* }}} */
+
+/* {{{ mp_sqr(a, sqr) */
+
+#if MP_SQUARE
+/*
+  Computes the square of a.  This can be done more
+  efficiently than a general multiplication, because many of the
+  computation steps are redundant when squaring.  The inner product
+  step is a bit more complicated, but we save a fair number of
+  iterations of the multiplication loop.
+ */
+
+/* sqr = a^2;   Caller provides both a and tmp; */
+mp_err   mp_sqr(const mp_int *a, mp_int *sqr)
+{
+  mp_digit *pa;
+  mp_digit d;
+  mp_err   res;
+  mp_size  ix;
+  mp_int   tmp;
+  int      count;
+
+  ARGCHK(a != NULL && sqr != NULL, MP_BADARG);
+
+  if (a == sqr) {
+    if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+      return res;
+    a = &tmp;
+  } else {
+    DIGITS(&tmp) = 0;
+    res = MP_OKAY;
+  }
+
+  ix = 2 * MP_USED(a);
+  if (ix > MP_ALLOC(sqr)) {
+    MP_USED(sqr) = 1; 
+    MP_CHECKOK( s_mp_grow(sqr, ix) );
+  } 
+  MP_USED(sqr) = ix;
+  MP_DIGIT(sqr, 0) = 0;
+
+#ifdef NSS_USE_COMBA
+  if (IS_POWER_OF_2(MP_USED(a))) {
+      if (MP_USED(a) == 4) {
+          s_mp_sqr_comba_4(a, sqr);
+          goto CLEANUP;
+      }
+      if (MP_USED(a) == 8) {
+          s_mp_sqr_comba_8(a, sqr);
+          goto CLEANUP;
+      }
+      if (MP_USED(a) == 16) {
+          s_mp_sqr_comba_16(a, sqr);
+          goto CLEANUP;
+      }
+      if (MP_USED(a) == 32) {
+          s_mp_sqr_comba_32(a, sqr);
+          goto CLEANUP;
+      } 
+  }
+#endif
+
+  pa = MP_DIGITS(a);
+  count = MP_USED(a) - 1;
+  if (count > 0) {
+    d = *pa++;
+    s_mpv_mul_d(pa, count, d, MP_DIGITS(sqr) + 1);
+    for (ix = 3; --count > 0; ix += 2) {
+      d = *pa++;
+      s_mpv_mul_d_add(pa, count, d, MP_DIGITS(sqr) + ix);
+    } /* for(ix ...) */
+    MP_DIGIT(sqr, MP_USED(sqr)-1) = 0; /* above loop stopped short of this. */
+
+    /* now sqr *= 2 */
+    s_mp_mul_2(sqr);
+  } else {
+    MP_DIGIT(sqr, 1) = 0;
+  }
+
+  /* now add the squares of the digits of a to sqr. */
+  s_mpv_sqr_add_prop(MP_DIGITS(a), MP_USED(a), MP_DIGITS(sqr));
+
+  SIGN(sqr) = ZPOS;
+  s_mp_clamp(sqr);
+
+CLEANUP:
+  mp_clear(&tmp);
+  return res;
+
+} /* end mp_sqr() */
+#endif
+
+/* }}} */
+
+/* {{{ mp_div(a, b, q, r) */
+
+/*
+  mp_div(a, b, q, r)
+
+  Compute q = a / b and r = a mod b.  Input parameters may be re-used
+  as output parameters.  If q or r is NULL, that portion of the
+  computation will be discarded (although it will still be computed)
+ */
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r)
+{
+  mp_err   res;
+  mp_int   *pQ, *pR;
+  mp_int   qtmp, rtmp, btmp;
+  int      cmp;
+  mp_sign  signA;
+  mp_sign  signB;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+  
+  signA = MP_SIGN(a);
+  signB = MP_SIGN(b);
+
+  if(mp_cmp_z(b) == MP_EQ)
+    return MP_RANGE;
+
+  DIGITS(&qtmp) = 0;
+  DIGITS(&rtmp) = 0;
+  DIGITS(&btmp) = 0;
+
+  /* Set up some temporaries... */
+  if (!r || r == a || r == b) {
+    MP_CHECKOK( mp_init_copy(&rtmp, a) );
+    pR = &rtmp;
+  } else {
+    MP_CHECKOK( mp_copy(a, r) );
+    pR = r;
+  }
+
+  if (!q || q == a || q == b) {
+    MP_CHECKOK( mp_init_size(&qtmp, MP_USED(a)) );
+    pQ = &qtmp;
+  } else {
+    MP_CHECKOK( s_mp_pad(q, MP_USED(a)) );
+    pQ = q;
+    mp_zero(pQ);
+  }
+
+  /*
+    If |a| <= |b|, we can compute the solution without division;
+    otherwise, we actually do the work required.
+   */
+  if ((cmp = s_mp_cmp(a, b)) <= 0) {
+    if (cmp) {
+      /* r was set to a above. */
+      mp_zero(pQ);
+    } else {
+      mp_set(pQ, 1);
+      mp_zero(pR);
+    }
+  } else {
+    MP_CHECKOK( mp_init_copy(&btmp, b) );
+    MP_CHECKOK( s_mp_div(pR, &btmp, pQ) );
+  }
+
+  /* Compute the signs for the output  */
+  MP_SIGN(pR) = signA;   /* Sr = Sa              */
+  /* Sq = ZPOS if Sa == Sb */ /* Sq = NEG if Sa != Sb */
+  MP_SIGN(pQ) = (signA == signB) ? ZPOS : NEG;
+
+  if(s_mp_cmp_d(pQ, 0) == MP_EQ)
+    SIGN(pQ) = ZPOS;
+  if(s_mp_cmp_d(pR, 0) == MP_EQ)
+    SIGN(pR) = ZPOS;
+
+  /* Copy output, if it is needed      */
+  if(q && q != pQ) 
+    s_mp_exch(pQ, q);
+
+  if(r && r != pR) 
+    s_mp_exch(pR, r);
+
+CLEANUP:
+  mp_clear(&btmp);
+  mp_clear(&rtmp);
+  mp_clear(&qtmp);
+
+  return res;
+
+} /* end mp_div() */
+
+/* }}} */
+
+/* {{{ mp_div_2d(a, d, q, r) */
+
+mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  if(q) {
+    if((res = mp_copy(a, q)) != MP_OKAY)
+      return res;
+  }
+  if(r) {
+    if((res = mp_copy(a, r)) != MP_OKAY)
+      return res;
+  }
+  if(q) {
+    s_mp_div_2d(q, d);
+  }
+  if(r) {
+    s_mp_mod_2d(r, d);
+  }
+
+  return MP_OKAY;
+
+} /* end mp_div_2d() */
+
+/* }}} */
+
+/* {{{ mp_expt(a, b, c) */
+
+/*
+  mp_expt(a, b, c)
+
+  Compute c = a ** b, that is, raise a to the b power.  Uses a
+  standard iterative square-and-multiply technique.
+ */
+
+mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_int   s, x;
+  mp_err   res;
+  mp_digit d;
+  int      dig, bit;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(mp_cmp_z(b) < 0)
+    return MP_RANGE;
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+
+  mp_set(&s, 1);
+
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  /* Loop over low-order digits in ascending order */
+  for(dig = 0; dig < (USED(b) - 1); dig++) {
+    d = DIGIT(b, dig);
+
+    /* Loop over bits of each non-maximal digit */
+    for(bit = 0; bit < DIGIT_BIT; bit++) {
+      if(d & 1) {
+	if((res = s_mp_mul(&s, &x)) != MP_OKAY) 
+	  goto CLEANUP;
+      }
+
+      d >>= 1;
+      
+      if((res = s_mp_sqr(&x)) != MP_OKAY)
+	goto CLEANUP;
+    }
+  }
+
+  /* Consider now the last digit... */
+  d = DIGIT(b, dig);
+
+  while(d) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d >>= 1;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+  
+  if(mp_iseven(b))
+    SIGN(&s) = SIGN(a);
+
+  res = mp_copy(&s, c);
+
+CLEANUP:
+  mp_clear(&x);
+X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end mp_expt() */
+
+/* }}} */
+
+/* {{{ mp_2expt(a, k) */
+
+/* Compute a = 2^k */
+
+mp_err mp_2expt(mp_int *a, mp_digit k)
+{
+  ARGCHK(a != NULL, MP_BADARG);
+
+  return s_mp_2expt(a, k);
+
+} /* end mp_2expt() */
+
+/* }}} */
+
+/* {{{ mp_mod(a, m, c) */
+
+/*
+  mp_mod(a, m, c)
+
+  Compute c = a (mod m).  Result will always be 0 <= c < m.
+ */
+
+mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c)
+{
+  mp_err  res;
+  int     mag;
+
+  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if(SIGN(m) == NEG)
+    return MP_RANGE;
+
+  /*
+     If |a| > m, we need to divide to get the remainder and take the
+     absolute value.  
+
+     If |a| < m, we don't need to do any division, just copy and adjust
+     the sign (if a is negative).
+
+     If |a| == m, we can simply set the result to zero.
+
+     This order is intended to minimize the average path length of the
+     comparison chain on common workloads -- the most frequent cases are
+     that |a| != m, so we do those first.
+   */
+  if((mag = s_mp_cmp(a, m)) > 0) {
+    if((res = mp_div(a, m, NULL, c)) != MP_OKAY)
+      return res;
+    
+    if(SIGN(c) == NEG) {
+      if((res = mp_add(c, m, c)) != MP_OKAY)
+	return res;
+    }
+
+  } else if(mag < 0) {
+    if((res = mp_copy(a, c)) != MP_OKAY)
+      return res;
+
+    if(mp_cmp_z(a) < 0) {
+      if((res = mp_add(c, m, c)) != MP_OKAY)
+	return res;
+
+    }
+    
+  } else {
+    mp_zero(c);
+
+  }
+
+  return MP_OKAY;
+
+} /* end mp_mod() */
+
+/* }}} */
+
+/* {{{ mp_mod_d(a, d, c) */
+
+/*
+  mp_mod_d(a, d, c)
+
+  Compute c = a (mod d).  Result will always be 0 <= c < d
+ */
+mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c)
+{
+  mp_err   res;
+  mp_digit rem;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if(s_mp_cmp_d(a, d) > 0) {
+    if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
+      return res;
+
+  } else {
+    if(SIGN(a) == NEG)
+      rem = d - DIGIT(a, 0);
+    else
+      rem = DIGIT(a, 0);
+  }
+
+  if(c)
+    *c = rem;
+
+  return MP_OKAY;
+
+} /* end mp_mod_d() */
+
+/* }}} */
+
+/* {{{ mp_sqrt(a, b) */
+
+/*
+  mp_sqrt(a, b)
+
+  Compute the integer square root of a, and store the result in b.
+  Uses an integer-arithmetic version of Newton's iterative linear
+  approximation technique to determine this value; the result has the
+  following two properties:
+
+     b^2 <= a
+     (b+1)^2 >= a
+
+  It is a range error to pass a negative value.
+ */
+mp_err mp_sqrt(const mp_int *a, mp_int *b)
+{
+  mp_int   x, t;
+  mp_err   res;
+  mp_size  used;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  /* Cannot take square root of a negative value */
+  if(SIGN(a) == NEG)
+    return MP_RANGE;
+
+  /* Special cases for zero and one, trivial     */
+  if(mp_cmp_d(a, 1) <= 0)
+    return mp_copy(a, b);
+    
+  /* Initialize the temporaries we'll use below  */
+  if((res = mp_init_size(&t, USED(a))) != MP_OKAY)
+    return res;
+
+  /* Compute an initial guess for the iteration as a itself */
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  used = MP_USED(&x);
+  if (used > 1) {
+    s_mp_rshd(&x, used / 2);
+  }
+
+  for(;;) {
+    /* t = (x * x) - a */
+    mp_copy(&x, &t);      /* can't fail, t is big enough for original x */
+    if((res = mp_sqr(&t, &t)) != MP_OKAY ||
+       (res = mp_sub(&t, a, &t)) != MP_OKAY)
+      goto CLEANUP;
+
+    /* t = t / 2x       */
+    s_mp_mul_2(&x);
+    if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY)
+      goto CLEANUP;
+    s_mp_div_2(&x);
+
+    /* Terminate the loop, if the quotient is zero */
+    if(mp_cmp_z(&t) == MP_EQ)
+      break;
+
+    /* x = x - t       */
+    if((res = mp_sub(&x, &t, &x)) != MP_OKAY)
+      goto CLEANUP;
+
+  }
+
+  /* Copy result to output parameter */
+  mp_sub_d(&x, 1, &x);
+  s_mp_exch(&x, b);
+
+ CLEANUP:
+  mp_clear(&x);
+ X:
+  mp_clear(&t); 
+
+  return res;
+
+} /* end mp_sqrt() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Modular arithmetic */
+
+#if MP_MODARITH
+/* {{{ mp_addmod(a, b, m, c) */
+
+/*
+  mp_addmod(a, b, m, c)
+
+  Compute c = (a + b) mod m
+ */
+
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_add(a, b, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_submod(a, b, m, c) */
+
+/*
+  mp_submod(a, b, m, c)
+
+  Compute c = (a - b) mod m
+ */
+
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_sub(a, b, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_mulmod(a, b, m, c) */
+
+/*
+  mp_mulmod(a, b, m, c)
+
+  Compute c = (a * b) mod m
+ */
+
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_mul(a, b, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_sqrmod(a, m, c) */
+
+#if MP_SQUARE
+mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_sqr(a, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+} /* end mp_sqrmod() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_exptmod(a, b, m, c) */
+
+/*
+  s_mp_exptmod(a, b, m, c)
+
+  Compute c = (a ** b) mod m.  Uses a standard square-and-multiply
+  method with modular reductions at each step. (This is basically the
+  same code as mp_expt(), except for the addition of the reductions)
+  
+  The modular reductions are done using Barrett's algorithm (see
+  s_mp_reduce() below for details)
+ */
+
+mp_err s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+  mp_int   s, x, mu;
+  mp_err   res;
+  mp_digit d;
+  int      dig, bit;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0)
+    return MP_RANGE;
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&x, a)) != MP_OKAY ||
+     (res = mp_mod(&x, m, &x)) != MP_OKAY)
+    goto X;
+  if((res = mp_init(&mu)) != MP_OKAY)
+    goto MU;
+
+  mp_set(&s, 1);
+
+  /* mu = b^2k / m */
+  s_mp_add_d(&mu, 1); 
+  s_mp_lshd(&mu, 2 * USED(m));
+  if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
+    goto CLEANUP;
+
+  /* Loop over digits of b in ascending order, except highest order */
+  for(dig = 0; dig < (USED(b) - 1); dig++) {
+    d = DIGIT(b, dig);
+
+    /* Loop over the bits of the lower-order digits */
+    for(bit = 0; bit < DIGIT_BIT; bit++) {
+      if(d & 1) {
+	if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	  goto CLEANUP;
+	if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
+	  goto CLEANUP;
+      }
+
+      d >>= 1;
+
+      if((res = s_mp_sqr(&x)) != MP_OKAY)
+	goto CLEANUP;
+      if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
+	goto CLEANUP;
+    }
+  }
+
+  /* Now do the last digit... */
+  d = DIGIT(b, dig);
+
+  while(d) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	goto CLEANUP;
+      if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d >>= 1;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY)
+      goto CLEANUP;
+    if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  s_mp_exch(&s, c);
+
+ CLEANUP:
+  mp_clear(&mu);
+ MU:
+  mp_clear(&x);
+ X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end s_mp_exptmod() */
+
+/* }}} */
+
+/* {{{ mp_exptmod_d(a, d, m, c) */
+
+mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c)
+{
+  mp_int   s, x;
+  mp_err   res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  mp_set(&s, 1);
+
+  while(d != 0) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY ||
+	 (res = mp_mod(&s, m, &s)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d /= 2;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY ||
+       (res = mp_mod(&x, m, &x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  s_mp_exch(&s, c);
+
+CLEANUP:
+  mp_clear(&x);
+X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end mp_exptmod_d() */
+
+/* }}} */
+#endif /* if MP_MODARITH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Comparison functions */
+
+/* {{{ mp_cmp_z(a) */
+
+/*
+  mp_cmp_z(a)
+
+  Compare a <=> 0.  Returns <0 if a<0, 0 if a=0, >0 if a>0.
+ */
+
+int    mp_cmp_z(const mp_int *a)
+{
+  if(SIGN(a) == NEG)
+    return MP_LT;
+  else if(USED(a) == 1 && DIGIT(a, 0) == 0)
+    return MP_EQ;
+  else
+    return MP_GT;
+
+} /* end mp_cmp_z() */
+
+/* }}} */
+
+/* {{{ mp_cmp_d(a, d) */
+
+/*
+  mp_cmp_d(a, d)
+
+  Compare a <=> d.  Returns <0 if a<d, 0 if a=d, >0 if a>d
+ */
+
+int    mp_cmp_d(const mp_int *a, mp_digit d)
+{
+  ARGCHK(a != NULL, MP_EQ);
+
+  if(SIGN(a) == NEG)
+    return MP_LT;
+
+  return s_mp_cmp_d(a, d);
+
+} /* end mp_cmp_d() */
+
+/* }}} */
+
+/* {{{ mp_cmp(a, b) */
+
+int    mp_cmp(const mp_int *a, const mp_int *b)
+{
+  ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+  if(SIGN(a) == SIGN(b)) {
+    int  mag;
+
+    if((mag = s_mp_cmp(a, b)) == MP_EQ)
+      return MP_EQ;
+
+    if(SIGN(a) == ZPOS)
+      return mag;
+    else
+      return -mag;
+
+  } else if(SIGN(a) == ZPOS) {
+    return MP_GT;
+  } else {
+    return MP_LT;
+  }
+
+} /* end mp_cmp() */
+
+/* }}} */
+
+/* {{{ mp_cmp_mag(a, b) */
+
+/*
+  mp_cmp_mag(a, b)
+
+  Compares |a| <=> |b|, and returns an appropriate comparison result
+ */
+
+int    mp_cmp_mag(mp_int *a, mp_int *b)
+{
+  ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+  return s_mp_cmp(a, b);
+
+} /* end mp_cmp_mag() */
+
+/* }}} */
+
+/* {{{ mp_cmp_int(a, z) */
+
+/*
+  This just converts z to an mp_int, and uses the existing comparison
+  routines.  This is sort of inefficient, but it's not clear to me how
+  frequently this wil get used anyway.  For small positive constants,
+  you can always use mp_cmp_d(), and for zero, there is mp_cmp_z().
+ */
+int    mp_cmp_int(const mp_int *a, long z)
+{
+  mp_int  tmp;
+  int     out;
+
+  ARGCHK(a != NULL, MP_EQ);
+  
+  mp_init(&tmp); mp_set_int(&tmp, z);
+  out = mp_cmp(a, &tmp);
+  mp_clear(&tmp);
+
+  return out;
+
+} /* end mp_cmp_int() */
+
+/* }}} */
+
+/* {{{ mp_isodd(a) */
+
+/*
+  mp_isodd(a)
+
+  Returns a true (non-zero) value if a is odd, false (zero) otherwise.
+ */
+int    mp_isodd(const mp_int *a)
+{
+  ARGCHK(a != NULL, 0);
+
+  return (int)(DIGIT(a, 0) & 1);
+
+} /* end mp_isodd() */
+
+/* }}} */
+
+/* {{{ mp_iseven(a) */
+
+int    mp_iseven(const mp_int *a)
+{
+  return !mp_isodd(a);
+
+} /* end mp_iseven() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Number theoretic functions */
+
+#if MP_NUMTH
+/* {{{ mp_gcd(a, b, c) */
+
+/*
+  Like the old mp_gcd() function, except computes the GCD using the
+  binary algorithm due to Josef Stein in 1961 (via Knuth).
+ */
+mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_err   res;
+  mp_int   u, v, t;
+  mp_size  k = 0;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ)
+      return MP_RANGE;
+  if(mp_cmp_z(a) == MP_EQ) {
+    return mp_copy(b, c);
+  } else if(mp_cmp_z(b) == MP_EQ) {
+    return mp_copy(a, c);
+  }
+
+  if((res = mp_init(&t)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&u, a)) != MP_OKAY)
+    goto U;
+  if((res = mp_init_copy(&v, b)) != MP_OKAY)
+    goto V;
+
+  SIGN(&u) = ZPOS;
+  SIGN(&v) = ZPOS;
+
+  /* Divide out common factors of 2 until at least 1 of a, b is even */
+  while(mp_iseven(&u) && mp_iseven(&v)) {
+    s_mp_div_2(&u);
+    s_mp_div_2(&v);
+    ++k;
+  }
+
+  /* Initialize t */
+  if(mp_isodd(&u)) {
+    if((res = mp_copy(&v, &t)) != MP_OKAY)
+      goto CLEANUP;
+    
+    /* t = -v */
+    if(SIGN(&v) == ZPOS)
+      SIGN(&t) = NEG;
+    else
+      SIGN(&t) = ZPOS;
+    
+  } else {
+    if((res = mp_copy(&u, &t)) != MP_OKAY)
+      goto CLEANUP;
+
+  }
+
+  for(;;) {
+    while(mp_iseven(&t)) {
+      s_mp_div_2(&t);
+    }
+
+    if(mp_cmp_z(&t) == MP_GT) {
+      if((res = mp_copy(&t, &u)) != MP_OKAY)
+	goto CLEANUP;
+
+    } else {
+      if((res = mp_copy(&t, &v)) != MP_OKAY)
+	goto CLEANUP;
+
+      /* v = -t */
+      if(SIGN(&t) == ZPOS)
+	SIGN(&v) = NEG;
+      else
+	SIGN(&v) = ZPOS;
+    }
+
+    if((res = mp_sub(&u, &v, &t)) != MP_OKAY)
+      goto CLEANUP;
+
+    if(s_mp_cmp_d(&t, 0) == MP_EQ)
+      break;
+  }
+
+  s_mp_2expt(&v, k);       /* v = 2^k   */
+  res = mp_mul(&u, &v, c); /* c = u * v */
+
+ CLEANUP:
+  mp_clear(&v);
+ V:
+  mp_clear(&u);
+ U:
+  mp_clear(&t);
+
+  return res;
+
+} /* end mp_gcd() */
+
+/* }}} */
+
+/* {{{ mp_lcm(a, b, c) */
+
+/* We compute the least common multiple using the rule:
+
+   ab = [a, b](a, b)
+
+   ... by computing the product, and dividing out the gcd.
+ */
+
+mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_int  gcd, prod;
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  /* Set up temporaries */
+  if((res = mp_init(&gcd)) != MP_OKAY)
+    return res;
+  if((res = mp_init(&prod)) != MP_OKAY)
+    goto GCD;
+
+  if((res = mp_mul(a, b, &prod)) != MP_OKAY)
+    goto CLEANUP;
+  if((res = mp_gcd(a, b, &gcd)) != MP_OKAY)
+    goto CLEANUP;
+
+  res = mp_div(&prod, &gcd, c, NULL);
+
+ CLEANUP:
+  mp_clear(&prod);
+ GCD:
+  mp_clear(&gcd);
+
+  return res;
+
+} /* end mp_lcm() */
+
+/* }}} */
+
+/* {{{ mp_xgcd(a, b, g, x, y) */
+
+/*
+  mp_xgcd(a, b, g, x, y)
+
+  Compute g = (a, b) and values x and y satisfying Bezout's identity
+  (that is, ax + by = g).  This uses the binary extended GCD algorithm
+  based on the Stein algorithm used for mp_gcd()
+  See algorithm 14.61 in Handbook of Applied Cryptogrpahy.
+ */
+
+mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y)
+{
+  mp_int   gx, xc, yc, u, v, A, B, C, D;
+  mp_int  *clean[9];
+  mp_err   res;
+  int      last = -1;
+
+  if(mp_cmp_z(b) == 0)
+    return MP_RANGE;
+
+  /* Initialize all these variables we need */
+  MP_CHECKOK( mp_init(&u) );
+  clean[++last] = &u;
+  MP_CHECKOK( mp_init(&v) );
+  clean[++last] = &v;
+  MP_CHECKOK( mp_init(&gx) );
+  clean[++last] = &gx;
+  MP_CHECKOK( mp_init(&A) );
+  clean[++last] = &A;
+  MP_CHECKOK( mp_init(&B) );
+  clean[++last] = &B;
+  MP_CHECKOK( mp_init(&C) );
+  clean[++last] = &C;
+  MP_CHECKOK( mp_init(&D) );
+  clean[++last] = &D;
+  MP_CHECKOK( mp_init_copy(&xc, a) );
+  clean[++last] = &xc;
+  mp_abs(&xc, &xc);
+  MP_CHECKOK( mp_init_copy(&yc, b) );
+  clean[++last] = &yc;
+  mp_abs(&yc, &yc);
+
+  mp_set(&gx, 1);
+
+  /* Divide by two until at least one of them is odd */
+  while(mp_iseven(&xc) && mp_iseven(&yc)) {
+    mp_size nx = mp_trailing_zeros(&xc);
+    mp_size ny = mp_trailing_zeros(&yc);
+    mp_size n  = MP_MIN(nx, ny);
+    s_mp_div_2d(&xc,n);
+    s_mp_div_2d(&yc,n);
+    MP_CHECKOK( s_mp_mul_2d(&gx,n) );
+  }
+
+  mp_copy(&xc, &u);
+  mp_copy(&yc, &v);
+  mp_set(&A, 1); mp_set(&D, 1);
+
+  /* Loop through binary GCD algorithm */
+  do {
+    while(mp_iseven(&u)) {
+      s_mp_div_2(&u);
+
+      if(mp_iseven(&A) && mp_iseven(&B)) {
+	s_mp_div_2(&A); s_mp_div_2(&B);
+      } else {
+	MP_CHECKOK( mp_add(&A, &yc, &A) );
+	s_mp_div_2(&A);
+	MP_CHECKOK( mp_sub(&B, &xc, &B) );
+	s_mp_div_2(&B);
+      }
+    }
+
+    while(mp_iseven(&v)) {
+      s_mp_div_2(&v);
+
+      if(mp_iseven(&C) && mp_iseven(&D)) {
+	s_mp_div_2(&C); s_mp_div_2(&D);
+      } else {
+	MP_CHECKOK( mp_add(&C, &yc, &C) );
+	s_mp_div_2(&C);
+	MP_CHECKOK( mp_sub(&D, &xc, &D) );
+	s_mp_div_2(&D);
+      }
+    }
+
+    if(mp_cmp(&u, &v) >= 0) {
+      MP_CHECKOK( mp_sub(&u, &v, &u) );
+      MP_CHECKOK( mp_sub(&A, &C, &A) );
+      MP_CHECKOK( mp_sub(&B, &D, &B) );
+    } else {
+      MP_CHECKOK( mp_sub(&v, &u, &v) );
+      MP_CHECKOK( mp_sub(&C, &A, &C) );
+      MP_CHECKOK( mp_sub(&D, &B, &D) );
+    }
+  } while (mp_cmp_z(&u) != 0);
+
+  /* copy results to output */
+  if(x)
+    MP_CHECKOK( mp_copy(&C, x) );
+
+  if(y)
+    MP_CHECKOK( mp_copy(&D, y) );
+      
+  if(g)
+    MP_CHECKOK( mp_mul(&gx, &v, g) );
+
+ CLEANUP:
+  while(last >= 0)
+    mp_clear(clean[last--]);
+
+  return res;
+
+} /* end mp_xgcd() */
+
+/* }}} */
+
+mp_size mp_trailing_zeros(const mp_int *mp)
+{
+  mp_digit d;
+  mp_size  n = 0;
+  int      ix;
+
+  if (!mp || !MP_DIGITS(mp) || !mp_cmp_z(mp))
+    return n;
+
+  for (ix = 0; !(d = MP_DIGIT(mp,ix)) && (ix < MP_USED(mp)); ++ix)
+    n += MP_DIGIT_BIT;
+  if (!d)
+    return 0;	/* shouldn't happen, but ... */
+#if !defined(MP_USE_UINT_DIGIT)
+  if (!(d & 0xffffffffU)) {
+    d >>= 32;
+    n  += 32;
+  }
+#endif
+  if (!(d & 0xffffU)) {
+    d >>= 16;
+    n  += 16;
+  }
+  if (!(d & 0xffU)) {
+    d >>= 8;
+    n  += 8;
+  }
+  if (!(d & 0xfU)) {
+    d >>= 4;
+    n  += 4;
+  }
+  if (!(d & 0x3U)) {
+    d >>= 2;
+    n  += 2;
+  }
+  if (!(d & 0x1U)) {
+    d >>= 1;
+    n  += 1;
+  }
+#if MP_ARGCHK == 2
+  assert(0 != (d & 1));
+#endif
+  return n;
+}
+
+/* Given a and prime p, computes c and k such that a*c == 2**k (mod p).
+** Returns k (positive) or error (negative).
+** This technique from the paper "Fast Modular Reciprocals" (unpublished)
+** by Richard Schroeppel (a.k.a. Captain Nemo).
+*/
+mp_err s_mp_almost_inverse(const mp_int *a, const mp_int *p, mp_int *c)
+{
+  mp_err res;
+  mp_err k    = 0;
+  mp_int d, f, g;
+
+  ARGCHK(a && p && c, MP_BADARG);
+
+  MP_DIGITS(&d) = 0;
+  MP_DIGITS(&f) = 0;
+  MP_DIGITS(&g) = 0;
+  MP_CHECKOK( mp_init(&d) );
+  MP_CHECKOK( mp_init_copy(&f, a) );	/* f = a */
+  MP_CHECKOK( mp_init_copy(&g, p) );	/* g = p */
+
+  mp_set(c, 1);
+  mp_zero(&d);
+
+  if (mp_cmp_z(&f) == 0) {
+    res = MP_UNDEF;
+  } else 
+  for (;;) {
+    int diff_sign;
+    while (mp_iseven(&f)) {
+      mp_size n = mp_trailing_zeros(&f);
+      if (!n) {
+	res = MP_UNDEF;
+	goto CLEANUP;
+      }
+      s_mp_div_2d(&f, n);
+      MP_CHECKOK( s_mp_mul_2d(&d, n) );
+      k += n;
+    }
+    if (mp_cmp_d(&f, 1) == MP_EQ) {	/* f == 1 */
+      res = k;
+      break;
+    }
+    diff_sign = mp_cmp(&f, &g);
+    if (diff_sign < 0) {		/* f < g */
+      s_mp_exch(&f, &g);
+      s_mp_exch(c, &d);
+    } else if (diff_sign == 0) {		/* f == g */
+      res = MP_UNDEF;		/* a and p are not relatively prime */
+      break;
+    }
+    if ((MP_DIGIT(&f,0) % 4) == (MP_DIGIT(&g,0) % 4)) {
+      MP_CHECKOK( mp_sub(&f, &g, &f) );	/* f = f - g */
+      MP_CHECKOK( mp_sub(c,  &d,  c) );	/* c = c - d */
+    } else {
+      MP_CHECKOK( mp_add(&f, &g, &f) );	/* f = f + g */
+      MP_CHECKOK( mp_add(c,  &d,  c) );	/* c = c + d */
+    }
+  }
+  if (res >= 0) {
+    while (MP_SIGN(c) != MP_ZPOS) {
+      MP_CHECKOK( mp_add(c, p, c) );
+    }
+    res = k;
+  }
+
+CLEANUP:
+  mp_clear(&d);
+  mp_clear(&f);
+  mp_clear(&g);
+  return res;
+}
+
+/* Compute T = (P ** -1) mod MP_RADIX.  Also works for 16-bit mp_digits.
+** This technique from the paper "Fast Modular Reciprocals" (unpublished)
+** by Richard Schroeppel (a.k.a. Captain Nemo).
+*/
+mp_digit  s_mp_invmod_radix(mp_digit P)
+{
+  mp_digit T = P;
+  T *= 2 - (P * T);
+  T *= 2 - (P * T);
+  T *= 2 - (P * T);
+  T *= 2 - (P * T);
+#if !defined(MP_USE_UINT_DIGIT)
+  T *= 2 - (P * T);
+  T *= 2 - (P * T);
+#endif
+  return T;
+}
+
+/* Given c, k, and prime p, where a*c == 2**k (mod p), 
+** Compute x = (a ** -1) mod p.  This is similar to Montgomery reduction.
+** This technique from the paper "Fast Modular Reciprocals" (unpublished)
+** by Richard Schroeppel (a.k.a. Captain Nemo).
+*/
+mp_err  s_mp_fixup_reciprocal(const mp_int *c, const mp_int *p, int k, mp_int *x)
+{
+  int      k_orig = k;
+  mp_digit r;
+  mp_size  ix;
+  mp_err   res;
+
+  if (mp_cmp_z(c) < 0) {		/* c < 0 */
+    MP_CHECKOK( mp_add(c, p, x) );	/* x = c + p */
+  } else {
+    MP_CHECKOK( mp_copy(c, x) );	/* x = c */
+  }
+
+  /* make sure x is large enough */
+  ix = MP_HOWMANY(k, MP_DIGIT_BIT) + MP_USED(p) + 1;
+  ix = MP_MAX(ix, MP_USED(x));
+  MP_CHECKOK( s_mp_pad(x, ix) );
+
+  r = 0 - s_mp_invmod_radix(MP_DIGIT(p,0));
+
+  for (ix = 0; k > 0; ix++) {
+    int      j = MP_MIN(k, MP_DIGIT_BIT);
+    mp_digit v = r * MP_DIGIT(x, ix);
+    if (j < MP_DIGIT_BIT) {
+      v &= ((mp_digit)1 << j) - 1;	/* v = v mod (2 ** j) */
+    }
+    s_mp_mul_d_add_offset(p, v, x, ix); /* x += p * v * (RADIX ** ix) */
+    k -= j;
+  }
+  s_mp_clamp(x);
+  s_mp_div_2d(x, k_orig);
+  res = MP_OKAY;
+
+CLEANUP:
+  return res;
+}
+
+/* compute mod inverse using Schroeppel's method, only if m is odd */
+mp_err s_mp_invmod_odd_m(const mp_int *a, const mp_int *m, mp_int *c)
+{
+  int k;
+  mp_err  res;
+  mp_int  x;
+
+  ARGCHK(a && m && c, MP_BADARG);
+
+  if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
+    return MP_RANGE;
+  if (mp_iseven(m))
+    return MP_UNDEF;
+
+  MP_DIGITS(&x) = 0;
+
+  if (a == c) {
+    if ((res = mp_init_copy(&x, a)) != MP_OKAY)
+      return res;
+    if (a == m) 
+      m = &x;
+    a = &x;
+  } else if (m == c) {
+    if ((res = mp_init_copy(&x, m)) != MP_OKAY)
+      return res;
+    m = &x;
+  } else {
+    MP_DIGITS(&x) = 0;
+  }
+
+  MP_CHECKOK( s_mp_almost_inverse(a, m, c) );
+  k = res;
+  MP_CHECKOK( s_mp_fixup_reciprocal(c, m, k, c) );
+CLEANUP:
+  mp_clear(&x);
+  return res;
+}
+
+/* Known good algorithm for computing modular inverse.  But slow. */
+mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c)
+{
+  mp_int  g, x;
+  mp_err  res;
+
+  ARGCHK(a && m && c, MP_BADARG);
+
+  if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
+    return MP_RANGE;
+
+  MP_DIGITS(&g) = 0;
+  MP_DIGITS(&x) = 0;
+  MP_CHECKOK( mp_init(&x) );
+  MP_CHECKOK( mp_init(&g) );
+
+  MP_CHECKOK( mp_xgcd(a, m, &g, &x, NULL) );
+
+  if (mp_cmp_d(&g, 1) != MP_EQ) {
+    res = MP_UNDEF;
+    goto CLEANUP;
+  }
+
+  res = mp_mod(&x, m, c);
+  SIGN(c) = SIGN(a);
+
+CLEANUP:
+  mp_clear(&x);
+  mp_clear(&g);
+
+  return res;
+}
+
+/* modular inverse where modulus is 2**k. */
+/* c = a**-1 mod 2**k */
+mp_err s_mp_invmod_2d(const mp_int *a, mp_size k, mp_int *c)
+{
+  mp_err res;
+  mp_size ix = k + 4;
+  mp_int t0, t1, val, tmp, two2k;
+
+  static const mp_digit d2 = 2;
+  static const mp_int two = { MP_ZPOS, 1, 1, (mp_digit *)&d2 };
+
+  if (mp_iseven(a))
+    return MP_UNDEF;
+  if (k <= MP_DIGIT_BIT) {
+    mp_digit i = s_mp_invmod_radix(MP_DIGIT(a,0));
+    if (k < MP_DIGIT_BIT)
+      i &= ((mp_digit)1 << k) - (mp_digit)1;
+    mp_set(c, i);
+    return MP_OKAY;
+  }
+  MP_DIGITS(&t0) = 0;
+  MP_DIGITS(&t1) = 0;
+  MP_DIGITS(&val) = 0;
+  MP_DIGITS(&tmp) = 0;
+  MP_DIGITS(&two2k) = 0;
+  MP_CHECKOK( mp_init_copy(&val, a) );
+  s_mp_mod_2d(&val, k);
+  MP_CHECKOK( mp_init_copy(&t0, &val) );
+  MP_CHECKOK( mp_init_copy(&t1, &t0)  );
+  MP_CHECKOK( mp_init(&tmp) );
+  MP_CHECKOK( mp_init(&two2k) );
+  MP_CHECKOK( s_mp_2expt(&two2k, k) );
+  do {
+    MP_CHECKOK( mp_mul(&val, &t1, &tmp)  );
+    MP_CHECKOK( mp_sub(&two, &tmp, &tmp) );
+    MP_CHECKOK( mp_mul(&t1, &tmp, &t1)   );
+    s_mp_mod_2d(&t1, k);
+    while (MP_SIGN(&t1) != MP_ZPOS) {
+      MP_CHECKOK( mp_add(&t1, &two2k, &t1) );
+    }
+    if (mp_cmp(&t1, &t0) == MP_EQ) 
+      break;
+    MP_CHECKOK( mp_copy(&t1, &t0) );
+  } while (--ix > 0);
+  if (!ix) {
+    res = MP_UNDEF;
+  } else {
+    mp_exch(c, &t1);
+  }
+
+CLEANUP:
+  mp_clear(&t0);
+  mp_clear(&t1);
+  mp_clear(&val);
+  mp_clear(&tmp);
+  mp_clear(&two2k);
+  return res;
+}
+
+mp_err s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c)
+{
+  mp_err res;
+  mp_size k;
+  mp_int oddFactor, evenFactor;	/* factors of the modulus */
+  mp_int oddPart, evenPart;	/* parts to combine via CRT. */
+  mp_int C2, tmp1, tmp2;
+
+  /*static const mp_digit d1 = 1; */
+  /*static const mp_int one = { MP_ZPOS, 1, 1, (mp_digit *)&d1 }; */
+
+  if ((res = s_mp_ispow2(m)) >= 0) {
+    k = res;
+    return s_mp_invmod_2d(a, k, c);
+  }
+  MP_DIGITS(&oddFactor) = 0;
+  MP_DIGITS(&evenFactor) = 0;
+  MP_DIGITS(&oddPart) = 0;
+  MP_DIGITS(&evenPart) = 0;
+  MP_DIGITS(&C2)     = 0;
+  MP_DIGITS(&tmp1)   = 0;
+  MP_DIGITS(&tmp2)   = 0;
+
+  MP_CHECKOK( mp_init_copy(&oddFactor, m) );    /* oddFactor = m */
+  MP_CHECKOK( mp_init(&evenFactor) );
+  MP_CHECKOK( mp_init(&oddPart) );
+  MP_CHECKOK( mp_init(&evenPart) );
+  MP_CHECKOK( mp_init(&C2)     );
+  MP_CHECKOK( mp_init(&tmp1)   );
+  MP_CHECKOK( mp_init(&tmp2)   );
+
+  k = mp_trailing_zeros(m);
+  s_mp_div_2d(&oddFactor, k);
+  MP_CHECKOK( s_mp_2expt(&evenFactor, k) );
+
+  /* compute a**-1 mod oddFactor. */
+  MP_CHECKOK( s_mp_invmod_odd_m(a, &oddFactor, &oddPart) );
+  /* compute a**-1 mod evenFactor, where evenFactor == 2**k. */
+  MP_CHECKOK( s_mp_invmod_2d(   a,       k,    &evenPart) );
+
+  /* Use Chinese Remainer theorem to compute a**-1 mod m. */
+  /* let m1 = oddFactor,  v1 = oddPart, 
+   * let m2 = evenFactor, v2 = evenPart.
+   */
+
+  /* Compute C2 = m1**-1 mod m2. */
+  MP_CHECKOK( s_mp_invmod_2d(&oddFactor, k,    &C2) );
+
+  /* compute u = (v2 - v1)*C2 mod m2 */
+  MP_CHECKOK( mp_sub(&evenPart, &oddPart,   &tmp1) );
+  MP_CHECKOK( mp_mul(&tmp1,     &C2,        &tmp2) );
+  s_mp_mod_2d(&tmp2, k);
+  while (MP_SIGN(&tmp2) != MP_ZPOS) {
+    MP_CHECKOK( mp_add(&tmp2, &evenFactor, &tmp2) );
+  }
+
+  /* compute answer = v1 + u*m1 */
+  MP_CHECKOK( mp_mul(&tmp2,     &oddFactor, c) );
+  MP_CHECKOK( mp_add(&oddPart,  c,          c) );
+  /* not sure this is necessary, but it's low cost if not. */
+  MP_CHECKOK( mp_mod(c,         m,          c) );
+
+CLEANUP:
+  mp_clear(&oddFactor);
+  mp_clear(&evenFactor);
+  mp_clear(&oddPart);
+  mp_clear(&evenPart);
+  mp_clear(&C2);
+  mp_clear(&tmp1);
+  mp_clear(&tmp2);
+  return res;
+}
+
+
+/* {{{ mp_invmod(a, m, c) */
+
+/*
+  mp_invmod(a, m, c)
+
+  Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
+  This is equivalent to the question of whether (a, m) = 1.  If not,
+  MP_UNDEF is returned, and there is no inverse.
+ */
+
+mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c)
+{
+
+  ARGCHK(a && m && c, MP_BADARG);
+
+  if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
+    return MP_RANGE;
+
+  if (mp_isodd(m)) {
+    return s_mp_invmod_odd_m(a, m, c);
+  }
+  if (mp_iseven(a))
+    return MP_UNDEF;	/* not invertable */
+
+  return s_mp_invmod_even_m(a, m, c);
+
+} /* end mp_invmod() */
+
+/* }}} */
+#endif /* if MP_NUMTH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mp_print(mp, ofp) */
+
+#if MP_IOFUNC
+/*
+  mp_print(mp, ofp)
+
+  Print a textual representation of the given mp_int on the output
+  stream 'ofp'.  Output is generated using the internal radix.
+ */
+
+void   mp_print(mp_int *mp, FILE *ofp)
+{
+  int   ix;
+
+  if(mp == NULL || ofp == NULL)
+    return;
+
+  fputc((SIGN(mp) == NEG) ? '-' : '+', ofp);
+
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
+  }
+
+} /* end mp_print() */
+
+#endif /* if MP_IOFUNC */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ More I/O Functions */
+
+/* {{{ mp_read_raw(mp, str, len) */
+
+/* 
+   mp_read_raw(mp, str, len)
+
+   Read in a raw value (base 256) into the given mp_int
+ */
+
+mp_err  mp_read_raw(mp_int *mp, char *str, int len)
+{
+  int            ix;
+  mp_err         res;
+  unsigned char *ustr = (unsigned char *)str;
+
+  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+  mp_zero(mp);
+
+  /* Get sign from first byte */
+  if(ustr[0])
+    SIGN(mp) = NEG;
+  else
+    SIGN(mp) = ZPOS;
+
+  /* Read the rest of the digits */
+  for(ix = 1; ix < len; ix++) {
+    if((res = mp_mul_d(mp, 256, mp)) != MP_OKAY)
+      return res;
+    if((res = mp_add_d(mp, ustr[ix], mp)) != MP_OKAY)
+      return res;
+  }
+
+  return MP_OKAY;
+
+} /* end mp_read_raw() */
+
+/* }}} */
+
+/* {{{ mp_raw_size(mp) */
+
+int    mp_raw_size(mp_int *mp)
+{
+  ARGCHK(mp != NULL, 0);
+
+  return (USED(mp) * sizeof(mp_digit)) + 1;
+
+} /* end mp_raw_size() */
+
+/* }}} */
+
+/* {{{ mp_toraw(mp, str) */
+
+mp_err mp_toraw(mp_int *mp, char *str)
+{
+  int  ix, jx, pos = 1;
+
+  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+
+  str[0] = (char)SIGN(mp);
+
+  /* Iterate over each digit... */
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    mp_digit  d = DIGIT(mp, ix);
+
+    /* Unpack digit bytes, high order first */
+    for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+      str[pos++] = (char)(d >> (jx * CHAR_BIT));
+    }
+  }
+
+  return MP_OKAY;
+
+} /* end mp_toraw() */
+
+/* }}} */
+
+/* {{{ mp_read_radix(mp, str, radix) */
+
+/*
+  mp_read_radix(mp, str, radix)
+
+  Read an integer from the given string, and set mp to the resulting
+  value.  The input is presumed to be in base 10.  Leading non-digit
+  characters are ignored, and the function reads until a non-digit
+  character or the end of the string.
+ */
+
+mp_err  mp_read_radix(mp_int *mp, const char *str, int radix)
+{
+  int     ix = 0, val = 0;
+  mp_err  res;
+  mp_sign sig = ZPOS;
+
+  ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, 
+	 MP_BADARG);
+
+  mp_zero(mp);
+
+  /* Skip leading non-digit characters until a digit or '-' or '+' */
+  while(str[ix] && 
+	(s_mp_tovalue(str[ix], radix) < 0) && 
+	str[ix] != '-' &&
+	str[ix] != '+') {
+    ++ix;
+  }
+
+  if(str[ix] == '-') {
+    sig = NEG;
+    ++ix;
+  } else if(str[ix] == '+') {
+    sig = ZPOS; /* this is the default anyway... */
+    ++ix;
+  }
+
+  while((val = s_mp_tovalue(str[ix], radix)) >= 0) {
+    if((res = s_mp_mul_d(mp, radix)) != MP_OKAY)
+      return res;
+    if((res = s_mp_add_d(mp, val)) != MP_OKAY)
+      return res;
+    ++ix;
+  }
+
+  if(s_mp_cmp_d(mp, 0) == MP_EQ)
+    SIGN(mp) = ZPOS;
+  else
+    SIGN(mp) = sig;
+
+  return MP_OKAY;
+
+} /* end mp_read_radix() */
+
+mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix)
+{
+  int     radix = default_radix;
+  int     cx;
+  mp_sign sig   = ZPOS;
+  mp_err  res;
+
+  /* Skip leading non-digit characters until a digit or '-' or '+' */
+  while ((cx = *str) != 0 && 
+	(s_mp_tovalue(cx, radix) < 0) && 
+	cx != '-' &&
+	cx != '+') {
+    ++str;
+  }
+
+  if (cx == '-') {
+    sig = NEG;
+    ++str;
+  } else if (cx == '+') {
+    sig = ZPOS; /* this is the default anyway... */
+    ++str;
+  }
+
+  if (str[0] == '0') {
+    if ((str[1] | 0x20) == 'x') {
+      radix = 16;
+      str += 2;
+    } else {
+      radix = 8;
+      str++;
+    }
+  }
+  res = mp_read_radix(a, str, radix);
+  if (res == MP_OKAY) {
+    MP_SIGN(a) = (s_mp_cmp_d(a, 0) == MP_EQ) ? ZPOS : sig;
+  }
+  return res;
+}
+
+/* }}} */
+
+/* {{{ mp_radix_size(mp, radix) */
+
+int    mp_radix_size(mp_int *mp, int radix)
+{
+  int  bits;
+
+  if(!mp || radix < 2 || radix > MAX_RADIX)
+    return 0;
+
+  bits = USED(mp) * DIGIT_BIT - 1;
+ 
+  return s_mp_outlen(bits, radix);
+
+} /* end mp_radix_size() */
+
+/* }}} */
+
+/* {{{ mp_toradix(mp, str, radix) */
+
+mp_err mp_toradix(mp_int *mp, char *str, int radix)
+{
+  int  ix, pos = 0;
+
+  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+  ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
+
+  if(mp_cmp_z(mp) == MP_EQ) {
+    str[0] = '0';
+    str[1] = '\0';
+  } else {
+    mp_err   res;
+    mp_int   tmp;
+    mp_sign  sgn;
+    mp_digit rem, rdx = (mp_digit)radix;
+    char     ch;
+
+    if((res = mp_init_copy(&tmp, mp)) != MP_OKAY)
+      return res;
+
+    /* Save sign for later, and take absolute value */
+    sgn = SIGN(&tmp); SIGN(&tmp) = ZPOS;
+
+    /* Generate output digits in reverse order      */
+    while(mp_cmp_z(&tmp) != 0) {
+      if((res = mp_div_d(&tmp, rdx, &tmp, &rem)) != MP_OKAY) {
+	mp_clear(&tmp);
+	return res;
+      }
+
+      /* Generate digits, use capital letters */
+      ch = s_mp_todigit(rem, radix, 0);
+
+      str[pos++] = ch;
+    }
+
+    /* Add - sign if original value was negative */
+    if(sgn == NEG)
+      str[pos++] = '-';
+
+    /* Add trailing NUL to end the string        */
+    str[pos--] = '\0';
+
+    /* Reverse the digits and sign indicator     */
+    ix = 0;
+    while(ix < pos) {
+      char tmp = str[ix];
+
+      str[ix] = str[pos];
+      str[pos] = tmp;
+      ++ix;
+      --pos;
+    }
+    
+    mp_clear(&tmp);
+  }
+
+  return MP_OKAY;
+
+} /* end mp_toradix() */
+
+/* }}} */
+
+/* {{{ mp_tovalue(ch, r) */
+
+int    mp_tovalue(char ch, int r)
+{
+  return s_mp_tovalue(ch, r);
+
+} /* end mp_tovalue() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ mp_strerror(ec) */
+
+/*
+  mp_strerror(ec)
+
+  Return a string describing the meaning of error code 'ec'.  The
+  string returned is allocated in static memory, so the caller should
+  not attempt to modify or free the memory associated with this
+  string.
+ */
+const char  *mp_strerror(mp_err ec)
+{
+  int   aec = (ec < 0) ? -ec : ec;
+
+  /* Code values are negative, so the senses of these comparisons
+     are accurate */
+  if(ec < MP_LAST_CODE || ec > MP_OKAY) {
+    return mp_err_string[0];  /* unknown error code */
+  } else {
+    return mp_err_string[aec + 1];
+  }
+
+} /* end mp_strerror() */
+
+/* }}} */
+
+/*========================================================================*/
+/*------------------------------------------------------------------------*/
+/* Static function definitions (internal use only)                        */
+
+/* {{{ Memory management */
+
+/* {{{ s_mp_grow(mp, min) */
+
+/* Make sure there are at least 'min' digits allocated to mp              */
+mp_err   s_mp_grow(mp_int *mp, mp_size min)
+{
+  if(min > ALLOC(mp)) {
+    mp_digit   *tmp;
+
+    /* Set min to next nearest default precision block size */
+    min = MP_ROUNDUP(min, s_mp_defprec);
+
+    if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL)
+      return MP_MEM;
+
+    s_mp_copy(DIGITS(mp), tmp, USED(mp));
+
+#if MP_CRYPTO
+    s_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+    s_mp_free(DIGITS(mp));
+    DIGITS(mp) = tmp;
+    ALLOC(mp) = min;
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_grow() */
+
+/* }}} */
+
+/* {{{ s_mp_pad(mp, min) */
+
+/* Make sure the used size of mp is at least 'min', growing if needed     */
+mp_err   s_mp_pad(mp_int *mp, mp_size min)
+{
+  if(min > USED(mp)) {
+    mp_err  res;
+
+    /* Make sure there is room to increase precision  */
+    if (min > ALLOC(mp)) {
+      if ((res = s_mp_grow(mp, min)) != MP_OKAY)
+	return res;
+    } else {
+      s_mp_setz(DIGITS(mp) + USED(mp), min - USED(mp));
+    }
+
+    /* Increase precision; should already be 0-filled */
+    USED(mp) = min;
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_pad() */
+
+/* }}} */
+
+/* {{{ s_mp_setz(dp, count) */
+
+#if MP_MACRO == 0
+/* Set 'count' digits pointed to by dp to be zeroes                       */
+void s_mp_setz(mp_digit *dp, mp_size count)
+{
+#if MP_MEMSET == 0
+  int  ix;
+
+  for(ix = 0; ix < count; ix++)
+    dp[ix] = 0;
+#else
+  memset(dp, 0, count * sizeof(mp_digit));
+#endif
+
+} /* end s_mp_setz() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_copy(sp, dp, count) */
+
+#if MP_MACRO == 0
+/* Copy 'count' digits from sp to dp                                      */
+void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count)
+{
+#if MP_MEMCPY == 0
+  int  ix;
+
+  for(ix = 0; ix < count; ix++)
+    dp[ix] = sp[ix];
+#else
+  memcpy(dp, sp, count * sizeof(mp_digit));
+#endif
+
+} /* end s_mp_copy() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_alloc(nb, ni) */
+
+#if MP_MACRO == 0
+/* Allocate ni records of nb bytes each, and return a pointer to that     */
+void    *s_mp_alloc(size_t nb, size_t ni)
+{
+  ++mp_allocs;
+  return calloc(nb, ni);
+
+} /* end s_mp_alloc() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_free(ptr) */
+
+#if MP_MACRO == 0
+/* Free the memory pointed to by ptr                                      */
+void     s_mp_free(void *ptr)
+{
+  if(ptr) {
+    ++mp_frees;
+    free(ptr);
+  }
+} /* end s_mp_free() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_clamp(mp) */
+
+#if MP_MACRO == 0
+/* Remove leading zeroes from the given value                             */
+void     s_mp_clamp(mp_int *mp)
+{
+  mp_size used = MP_USED(mp);
+  while (used > 1 && DIGIT(mp, used - 1) == 0)
+    --used;
+  MP_USED(mp) = used;
+} /* end s_mp_clamp() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_exch(a, b) */
+
+/* Exchange the data for a and b; (b, a) = (a, b)                         */
+void     s_mp_exch(mp_int *a, mp_int *b)
+{
+  mp_int   tmp;
+
+  tmp = *a;
+  *a = *b;
+  *b = tmp;
+
+} /* end s_mp_exch() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Arithmetic helpers */
+
+/* {{{ s_mp_lshd(mp, p) */
+
+/* 
+   Shift mp leftward by p digits, growing if needed, and zero-filling
+   the in-shifted digits at the right end.  This is a convenient
+   alternative to multiplication by powers of the radix
+   The value of USED(mp) must already have been set to the value for
+   the shifted result.
+ */   
+
+mp_err   s_mp_lshd(mp_int *mp, mp_size p)
+{
+  mp_err  res;
+  mp_size pos;
+  int     ix;
+
+  if(p == 0)
+    return MP_OKAY;
+
+  if (MP_USED(mp) == 1 && MP_DIGIT(mp, 0) == 0)
+    return MP_OKAY;
+
+  if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
+    return res;
+
+  pos = USED(mp) - 1;
+
+  /* Shift all the significant figures over as needed */
+  for(ix = pos - p; ix >= 0; ix--) 
+    DIGIT(mp, ix + p) = DIGIT(mp, ix);
+
+  /* Fill the bottom digits with zeroes */
+  for(ix = 0; ix < p; ix++)
+    DIGIT(mp, ix) = 0;
+
+  return MP_OKAY;
+
+} /* end s_mp_lshd() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_2d(mp, d) */
+
+/*
+  Multiply the integer by 2^d, where d is a number of bits.  This
+  amounts to a bitwise shift of the value.
+ */
+mp_err   s_mp_mul_2d(mp_int *mp, mp_digit d)
+{
+  mp_err   res;
+  mp_digit dshift, bshift;
+  mp_digit mask;
+
+  ARGCHK(mp != NULL,  MP_BADARG);
+
+  dshift = d / MP_DIGIT_BIT;
+  bshift = d % MP_DIGIT_BIT;
+  /* bits to be shifted out of the top word */
+  mask   = ((mp_digit)~0 << (MP_DIGIT_BIT - bshift)); 
+  mask  &= MP_DIGIT(mp, MP_USED(mp) - 1);
+
+  if (MP_OKAY != (res = s_mp_pad(mp, MP_USED(mp) + dshift + (mask != 0) )))
+    return res;
+
+  if (dshift && MP_OKAY != (res = s_mp_lshd(mp, dshift)))
+    return res;
+
+  if (bshift) { 
+    mp_digit *pa = MP_DIGITS(mp);
+    mp_digit *alim = pa + MP_USED(mp);
+    mp_digit  prev = 0;
+
+    for (pa += dshift; pa < alim; ) {
+      mp_digit x = *pa;
+      *pa++ = (x << bshift) | prev;
+      prev = x >> (DIGIT_BIT - bshift);
+    }
+  }
+
+  s_mp_clamp(mp);
+  return MP_OKAY;
+} /* end s_mp_mul_2d() */
+
+/* {{{ s_mp_rshd(mp, p) */
+
+/* 
+   Shift mp rightward by p digits.  Maintains the invariant that
+   digits above the precision are all zero.  Digits shifted off the
+   end are lost.  Cannot fail.
+ */
+
+void     s_mp_rshd(mp_int *mp, mp_size p)
+{
+  mp_size  ix;
+  mp_digit *src, *dst;
+
+  if(p == 0)
+    return;
+
+  /* Shortcut when all digits are to be shifted off */
+  if(p >= USED(mp)) {
+    s_mp_setz(DIGITS(mp), ALLOC(mp));
+    USED(mp) = 1;
+    SIGN(mp) = ZPOS;
+    return;
+  }
+
+  /* Shift all the significant figures over as needed */
+  dst = MP_DIGITS(mp);
+  src = dst + p;
+  for (ix = USED(mp) - p; ix > 0; ix--)
+    *dst++ = *src++;
+
+  MP_USED(mp) -= p;
+  /* Fill the top digits with zeroes */
+  while (p-- > 0)
+    *dst++ = 0;
+
+#if 0
+  /* Strip off any leading zeroes    */
+  s_mp_clamp(mp);
+#endif
+
+} /* end s_mp_rshd() */
+
+/* }}} */
+
+/* {{{ s_mp_div_2(mp) */
+
+/* Divide by two -- take advantage of radix properties to do it fast      */
+void     s_mp_div_2(mp_int *mp)
+{
+  s_mp_div_2d(mp, 1);
+
+} /* end s_mp_div_2() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_2(mp) */
+
+mp_err s_mp_mul_2(mp_int *mp)
+{
+  mp_digit *pd;
+  int      ix, used;
+  mp_digit kin = 0;
+
+  /* Shift digits leftward by 1 bit */
+  used = MP_USED(mp);
+  pd = MP_DIGITS(mp);
+  for (ix = 0; ix < used; ix++) {
+    mp_digit d = *pd;
+    *pd++ = (d << 1) | kin;
+    kin = (d >> (DIGIT_BIT - 1));
+  }
+
+  /* Deal with rollover from last digit */
+  if (kin) {
+    if (ix >= ALLOC(mp)) {
+      mp_err res;
+      if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
+	return res;
+    }
+
+    DIGIT(mp, ix) = kin;
+    USED(mp) += 1;
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_mul_2() */
+
+/* }}} */
+
+/* {{{ s_mp_mod_2d(mp, d) */
+
+/*
+  Remainder the integer by 2^d, where d is a number of bits.  This
+  amounts to a bitwise AND of the value, and does not require the full
+  division code
+ */
+void     s_mp_mod_2d(mp_int *mp, mp_digit d)
+{
+  mp_size  ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
+  mp_size  ix;
+  mp_digit dmask;
+
+  if(ndig >= USED(mp))
+    return;
+
+  /* Flush all the bits above 2^d in its digit */
+  dmask = ((mp_digit)1 << nbit) - 1;
+  DIGIT(mp, ndig) &= dmask;
+
+  /* Flush all digits above the one with 2^d in it */
+  for(ix = ndig + 1; ix < USED(mp); ix++)
+    DIGIT(mp, ix) = 0;
+
+  s_mp_clamp(mp);
+
+} /* end s_mp_mod_2d() */
+
+/* }}} */
+
+/* {{{ s_mp_div_2d(mp, d) */
+
+/*
+  Divide the integer by 2^d, where d is a number of bits.  This
+  amounts to a bitwise shift of the value, and does not require the
+  full division code (used in Barrett reduction, see below)
+ */
+void     s_mp_div_2d(mp_int *mp, mp_digit d)
+{
+  int       ix;
+  mp_digit  save, next, mask;
+
+  s_mp_rshd(mp, d / DIGIT_BIT);
+  d %= DIGIT_BIT;
+  if (d) {
+    mask = ((mp_digit)1 << d) - 1;
+    save = 0;
+    for(ix = USED(mp) - 1; ix >= 0; ix--) {
+      next = DIGIT(mp, ix) & mask;
+      DIGIT(mp, ix) = (DIGIT(mp, ix) >> d) | (save << (DIGIT_BIT - d));
+      save = next;
+    }
+  }
+  s_mp_clamp(mp);
+
+} /* end s_mp_div_2d() */
+
+/* }}} */
+
+/* {{{ s_mp_norm(a, b, *d) */
+
+/*
+  s_mp_norm(a, b, *d)
+
+  Normalize a and b for division, where b is the divisor.  In order
+  that we might make good guesses for quotient digits, we want the
+  leading digit of b to be at least half the radix, which we
+  accomplish by multiplying a and b by a power of 2.  The exponent 
+  (shift count) is placed in *pd, so that the remainder can be shifted 
+  back at the end of the division process.
+ */
+
+mp_err   s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd)
+{
+  mp_digit  d;
+  mp_digit  mask;
+  mp_digit  b_msd;
+  mp_err    res    = MP_OKAY;
+
+  d = 0;
+  mask  = DIGIT_MAX & ~(DIGIT_MAX >> 1);	/* mask is msb of digit */
+  b_msd = DIGIT(b, USED(b) - 1);
+  while (!(b_msd & mask)) {
+    b_msd <<= 1;
+    ++d;
+  }
+
+  if (d) {
+    MP_CHECKOK( s_mp_mul_2d(a, d) );
+    MP_CHECKOK( s_mp_mul_2d(b, d) );
+  }
+
+  *pd = d;
+CLEANUP:
+  return res;
+
+} /* end s_mp_norm() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive digit arithmetic */
+
+/* {{{ s_mp_add_d(mp, d) */
+
+/* Add d to |mp| in place                                                 */
+mp_err   s_mp_add_d(mp_int *mp, mp_digit d)    /* unsigned digit addition */
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  mp_word   w, k = 0;
+  mp_size   ix = 1;
+
+  w = (mp_word)DIGIT(mp, 0) + d;
+  DIGIT(mp, 0) = ACCUM(w);
+  k = CARRYOUT(w);
+
+  while(ix < USED(mp) && k) {
+    w = (mp_word)DIGIT(mp, ix) + k;
+    DIGIT(mp, ix) = ACCUM(w);
+    k = CARRYOUT(w);
+    ++ix;
+  }
+
+  if(k != 0) {
+    mp_err  res;
+
+    if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(mp, ix) = (mp_digit)k;
+  }
+
+  return MP_OKAY;
+#else
+  mp_digit * pmp = MP_DIGITS(mp);
+  mp_digit sum, mp_i, carry = 0;
+  mp_err   res = MP_OKAY;
+  int used = (int)MP_USED(mp);
+
+  mp_i = *pmp;
+  *pmp++ = sum = d + mp_i;
+  carry = (sum < d);
+  while (carry && --used > 0) {
+    mp_i = *pmp;
+    *pmp++ = sum = carry + mp_i;
+    carry = !sum;
+  }
+  if (carry && !used) {
+    /* mp is growing */
+    used = MP_USED(mp);
+    MP_CHECKOK( s_mp_pad(mp, used + 1) );
+    MP_DIGIT(mp, used) = carry;
+  }
+CLEANUP:
+  return res;
+#endif
+} /* end s_mp_add_d() */
+
+/* }}} */
+
+/* {{{ s_mp_sub_d(mp, d) */
+
+/* Subtract d from |mp| in place, assumes |mp| > d                        */
+mp_err   s_mp_sub_d(mp_int *mp, mp_digit d)    /* unsigned digit subtract */
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+  mp_word   w, b = 0;
+  mp_size   ix = 1;
+
+  /* Compute initial subtraction    */
+  w = (RADIX + (mp_word)DIGIT(mp, 0)) - d;
+  b = CARRYOUT(w) ? 0 : 1;
+  DIGIT(mp, 0) = ACCUM(w);
+
+  /* Propagate borrows leftward     */
+  while(b && ix < USED(mp)) {
+    w = (RADIX + (mp_word)DIGIT(mp, ix)) - b;
+    b = CARRYOUT(w) ? 0 : 1;
+    DIGIT(mp, ix) = ACCUM(w);
+    ++ix;
+  }
+
+  /* Remove leading zeroes          */
+  s_mp_clamp(mp);
+
+  /* If we have a borrow out, it's a violation of the input invariant */
+  if(b)
+    return MP_RANGE;
+  else
+    return MP_OKAY;
+#else
+  mp_digit *pmp = MP_DIGITS(mp);
+  mp_digit mp_i, diff, borrow;
+  mp_size  used = MP_USED(mp);
+
+  mp_i = *pmp;
+  *pmp++ = diff = mp_i - d;
+  borrow = (diff > mp_i);
+  while (borrow && --used) {
+    mp_i = *pmp;
+    *pmp++ = diff = mp_i - borrow;
+    borrow = (diff > mp_i);
+  }
+  s_mp_clamp(mp);
+  return (borrow && !used) ? MP_RANGE : MP_OKAY;
+#endif
+} /* end s_mp_sub_d() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_d(a, d) */
+
+/* Compute a = a * d, single digit multiplication                         */
+mp_err   s_mp_mul_d(mp_int *a, mp_digit d)
+{
+  mp_err  res;
+  mp_size used;
+  int     pow;
+
+  if (!d) {
+    mp_zero(a);
+    return MP_OKAY;
+  }
+  if (d == 1)
+    return MP_OKAY;
+  if (0 <= (pow = s_mp_ispow2d(d))) {
+    return s_mp_mul_2d(a, (mp_digit)pow);
+  }
+
+  used = MP_USED(a);
+  MP_CHECKOK( s_mp_pad(a, used + 1) );
+
+  s_mpv_mul_d(MP_DIGITS(a), used, d, MP_DIGITS(a));
+
+  s_mp_clamp(a);
+
+CLEANUP:
+  return res;
+  
+} /* end s_mp_mul_d() */
+
+/* }}} */
+
+/* {{{ s_mp_div_d(mp, d, r) */
+
+/*
+  s_mp_div_d(mp, d, r)
+
+  Compute the quotient mp = mp / d and remainder r = mp mod d, for a
+  single digit d.  If r is null, the remainder will be discarded.
+ */
+
+mp_err   s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+  mp_word   w = 0, q;
+#else
+  mp_digit  w, q;
+#endif
+  int       ix;
+  mp_err    res;
+  mp_int    quot;
+  mp_int    rem;
+
+  if(d == 0)
+    return MP_RANGE;
+  if (d == 1) {
+    if (r)
+      *r = 0;
+    return MP_OKAY;
+  }
+  /* could check for power of 2 here, but mp_div_d does that. */
+  if (MP_USED(mp) == 1) {
+    mp_digit n   = MP_DIGIT(mp,0);
+    mp_digit rem;
+
+    q   = n / d;
+    rem = n % d;
+    MP_DIGIT(mp,0) = q;
+    if (r)
+      *r = rem;
+    return MP_OKAY;
+  }
+
+  MP_DIGITS(&rem)  = 0;
+  MP_DIGITS(&quot) = 0;
+  /* Make room for the quotient */
+  MP_CHECKOK( mp_init_size(&quot, USED(mp)) );
+
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    w = (w << DIGIT_BIT) | DIGIT(mp, ix);
+
+    if(w >= d) {
+      q = w / d;
+      w = w % d;
+    } else {
+      q = 0;
+    }
+
+    s_mp_lshd(&quot, 1);
+    DIGIT(&quot, 0) = (mp_digit)q;
+  }
+#else
+  {
+    mp_digit p;
+#if !defined(MP_ASSEMBLY_DIV_2DX1D)
+    mp_digit norm;
+#endif
+
+    MP_CHECKOK( mp_init_copy(&rem, mp) );
+
+#if !defined(MP_ASSEMBLY_DIV_2DX1D)
+    MP_DIGIT(&quot, 0) = d;
+    MP_CHECKOK( s_mp_norm(&rem, &quot, &norm) );
+    if (norm)
+      d <<= norm;
+    MP_DIGIT(&quot, 0) = 0;
+#endif
+
+    p = 0;
+    for (ix = USED(&rem) - 1; ix >= 0; ix--) {
+      w = DIGIT(&rem, ix);
+
+      if (p) {
+        MP_CHECKOK( s_mpv_div_2dx1d(p, w, d, &q, &w) );
+      } else if (w >= d) {
+	q = w / d;
+	w = w % d;
+      } else {
+	q = 0;
+      }
+
+      MP_CHECKOK( s_mp_lshd(&quot, 1) );
+      DIGIT(&quot, 0) = q;
+      p = w;
+    }
+#if !defined(MP_ASSEMBLY_DIV_2DX1D)
+    if (norm)
+      w >>= norm;
+#endif
+  }
+#endif
+
+  /* Deliver the remainder, if desired */
+  if(r)
+    *r = (mp_digit)w;
+
+  s_mp_clamp(&quot);
+  mp_exch(&quot, mp);
+CLEANUP:
+  mp_clear(&quot);
+  mp_clear(&rem);
+
+  return res;
+} /* end s_mp_div_d() */
+
+/* }}} */
+
+
+/* }}} */
+
+/* {{{ Primitive full arithmetic */
+
+/* {{{ s_mp_add(a, b) */
+
+/* Compute a = |a| + |b|                                                  */
+mp_err   s_mp_add(mp_int *a, const mp_int *b)  /* magnitude addition      */
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  mp_word   w = 0;
+#else
+  mp_digit  d, sum, carry = 0;
+#endif
+  mp_digit *pa, *pb;
+  mp_size   ix;
+  mp_size   used;
+  mp_err    res;
+
+  /* Make sure a has enough precision for the output value */
+  if((USED(b) > USED(a)) && (res = s_mp_pad(a, USED(b))) != MP_OKAY)
+    return res;
+
+  /*
+    Add up all digits up to the precision of b.  If b had initially
+    the same precision as a, or greater, we took care of it by the
+    padding step above, so there is no problem.  If b had initially
+    less precision, we'll have to make sure the carry out is duly
+    propagated upward among the higher-order digits of the sum.
+   */
+  pa = MP_DIGITS(a);
+  pb = MP_DIGITS(b);
+  used = MP_USED(b);
+  for(ix = 0; ix < used; ix++) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+    w = w + *pa + *pb++;
+    *pa++ = ACCUM(w);
+    w = CARRYOUT(w);
+#else
+    d = *pa;
+    sum = d + *pb++;
+    d = (sum < d);			/* detect overflow */
+    *pa++ = sum += carry;
+    carry = d + (sum < carry);		/* detect overflow */
+#endif
+  }
+
+  /* If we run out of 'b' digits before we're actually done, make
+     sure the carries get propagated upward...  
+   */
+  used = MP_USED(a);
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  while (w && ix < used) {
+    w = w + *pa;
+    *pa++ = ACCUM(w);
+    w = CARRYOUT(w);
+    ++ix;
+  }
+#else
+  while (carry && ix < used) {
+    sum = carry + *pa;
+    *pa++ = sum;
+    carry = !sum;
+    ++ix;
+  }
+#endif
+
+  /* If there's an overall carry out, increase precision and include
+     it.  We could have done this initially, but why touch the memory
+     allocator unless we're sure we have to?
+   */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  if (w) {
+    if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(a, ix) = (mp_digit)w;
+  }
+#else
+  if (carry) {
+    if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(a, used) = carry;
+  }
+#endif
+
+  return MP_OKAY;
+} /* end s_mp_add() */
+
+/* }}} */
+
+/* Compute c = |a| + |b|         */ /* magnitude addition      */
+mp_err   s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c)  
+{
+  mp_digit *pa, *pb, *pc;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  mp_word   w = 0;
+#else
+  mp_digit  sum, carry = 0, d;
+#endif
+  mp_size   ix;
+  mp_size   used;
+  mp_err    res;
+
+  MP_SIGN(c) = MP_SIGN(a);
+  if (MP_USED(a) < MP_USED(b)) {
+    const mp_int *xch = a;
+    a = b;
+    b = xch;
+  }
+
+  /* Make sure a has enough precision for the output value */
+  if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
+    return res;
+
+  /*
+    Add up all digits up to the precision of b.  If b had initially
+    the same precision as a, or greater, we took care of it by the
+    exchange step above, so there is no problem.  If b had initially
+    less precision, we'll have to make sure the carry out is duly
+    propagated upward among the higher-order digits of the sum.
+   */
+  pa = MP_DIGITS(a);
+  pb = MP_DIGITS(b);
+  pc = MP_DIGITS(c);
+  used = MP_USED(b);
+  for (ix = 0; ix < used; ix++) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+    w = w + *pa++ + *pb++;
+    *pc++ = ACCUM(w);
+    w = CARRYOUT(w);
+#else
+    d = *pa++;
+    sum = d + *pb++;
+    d = (sum < d);			/* detect overflow */
+    *pc++ = sum += carry;
+    carry = d + (sum < carry);		/* detect overflow */
+#endif
+  }
+
+  /* If we run out of 'b' digits before we're actually done, make
+     sure the carries get propagated upward...  
+   */
+  for (used = MP_USED(a); ix < used; ++ix) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+    w = w + *pa++;
+    *pc++ = ACCUM(w);
+    w = CARRYOUT(w);
+#else
+    *pc++ = sum = carry + *pa++;
+    carry = (sum < carry);
+#endif
+  }
+
+  /* If there's an overall carry out, increase precision and include
+     it.  We could have done this initially, but why touch the memory
+     allocator unless we're sure we have to?
+   */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  if (w) {
+    if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(c, used) = (mp_digit)w;
+    ++used;
+  }
+#else
+  if (carry) {
+    if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(c, used) = carry;
+    ++used;
+  }
+#endif
+  MP_USED(c) = used;
+  return MP_OKAY;
+}
+/* {{{ s_mp_add_offset(a, b, offset) */
+
+/* Compute a = |a| + ( |b| * (RADIX ** offset) )             */
+mp_err   s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset)   
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  mp_word   w, k = 0;
+#else
+  mp_digit  d, sum, carry = 0;
+#endif
+  mp_size   ib;
+  mp_size   ia;
+  mp_size   lim;
+  mp_err    res;
+
+  /* Make sure a has enough precision for the output value */
+  lim = MP_USED(b) + offset;
+  if((lim > USED(a)) && (res = s_mp_pad(a, lim)) != MP_OKAY)
+    return res;
+
+  /*
+    Add up all digits up to the precision of b.  If b had initially
+    the same precision as a, or greater, we took care of it by the
+    padding step above, so there is no problem.  If b had initially
+    less precision, we'll have to make sure the carry out is duly
+    propagated upward among the higher-order digits of the sum.
+   */
+  lim = USED(b);
+  for(ib = 0, ia = offset; ib < lim; ib++, ia++) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+    w = (mp_word)DIGIT(a, ia) + DIGIT(b, ib) + k;
+    DIGIT(a, ia) = ACCUM(w);
+    k = CARRYOUT(w);
+#else
+    d = MP_DIGIT(a, ia);
+    sum = d + MP_DIGIT(b, ib);
+    d = (sum < d);
+    MP_DIGIT(a,ia) = sum += carry;
+    carry = d + (sum < carry);
+#endif
+  }
+
+  /* If we run out of 'b' digits before we're actually done, make
+     sure the carries get propagated upward...  
+   */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  for (lim = MP_USED(a); k && (ia < lim); ++ia) {
+    w = (mp_word)DIGIT(a, ia) + k;
+    DIGIT(a, ia) = ACCUM(w);
+    k = CARRYOUT(w);
+  }
+#else
+  for (lim = MP_USED(a); carry && (ia < lim); ++ia) {
+    d = MP_DIGIT(a, ia);
+    MP_DIGIT(a,ia) = sum = d + carry;
+    carry = (sum < d);
+  }
+#endif
+
+  /* If there's an overall carry out, increase precision and include
+     it.  We could have done this initially, but why touch the memory
+     allocator unless we're sure we have to?
+   */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+  if(k) {
+    if((res = s_mp_pad(a, USED(a) + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(a, ia) = (mp_digit)k;
+  }
+#else
+  if (carry) {
+    if((res = s_mp_pad(a, lim + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(a, lim) = carry;
+  }
+#endif
+  s_mp_clamp(a);
+
+  return MP_OKAY;
+
+} /* end s_mp_add_offset() */
+
+/* }}} */
+
+/* {{{ s_mp_sub(a, b) */
+
+/* Compute a = |a| - |b|, assumes |a| >= |b|                              */
+mp_err   s_mp_sub(mp_int *a, const mp_int *b)  /* magnitude subtract      */
+{
+  mp_digit *pa, *pb, *limit;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+  mp_sword  w = 0;
+#else
+  mp_digit  d, diff, borrow = 0;
+#endif
+
+  /*
+    Subtract and propagate borrow.  Up to the precision of b, this
+    accounts for the digits of b; after that, we just make sure the
+    carries get to the right place.  This saves having to pad b out to
+    the precision of a just to make the loops work right...
+   */
+  pa = MP_DIGITS(a);
+  pb = MP_DIGITS(b);
+  limit = pb + MP_USED(b);
+  while (pb < limit) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+    w = w + *pa - *pb++;
+    *pa++ = ACCUM(w);
+    w >>= MP_DIGIT_BIT;
+#else
+    d = *pa;
+    diff = d - *pb++;
+    d = (diff > d);				/* detect borrow */
+    if (borrow && --diff == MP_DIGIT_MAX)
+      ++d;
+    *pa++ = diff;
+    borrow = d;	
+#endif
+  }
+  limit = MP_DIGITS(a) + MP_USED(a);
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+  while (w && pa < limit) {
+    w = w + *pa;
+    *pa++ = ACCUM(w);
+    w >>= MP_DIGIT_BIT;
+  }
+#else
+  while (borrow && pa < limit) {
+    d = *pa;
+    *pa++ = diff = d - borrow;
+    borrow = (diff > d);
+  }
+#endif
+
+  /* Clobber any leading zeroes we created    */
+  s_mp_clamp(a);
+
+  /* 
+     If there was a borrow out, then |b| > |a| in violation
+     of our input invariant.  We've already done the work,
+     but we'll at least complain about it...
+   */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+  return w ? MP_RANGE : MP_OKAY;
+#else
+  return borrow ? MP_RANGE : MP_OKAY;
+#endif
+} /* end s_mp_sub() */
+
+/* }}} */
+
+/* Compute c = |a| - |b|, assumes |a| >= |b| */ /* magnitude subtract      */
+mp_err   s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c)  
+{
+  mp_digit *pa, *pb, *pc;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+  mp_sword  w = 0;
+#else
+  mp_digit  d, diff, borrow = 0;
+#endif
+  int       ix, limit;
+  mp_err    res;
+
+  MP_SIGN(c) = MP_SIGN(a);
+
+  /* Make sure a has enough precision for the output value */
+  if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
+    return res;
+
+  /*
+    Subtract and propagate borrow.  Up to the precision of b, this
+    accounts for the digits of b; after that, we just make sure the
+    carries get to the right place.  This saves having to pad b out to
+    the precision of a just to make the loops work right...
+   */
+  pa = MP_DIGITS(a);
+  pb = MP_DIGITS(b);
+  pc = MP_DIGITS(c);
+  limit = MP_USED(b);
+  for (ix = 0; ix < limit; ++ix) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+    w = w + *pa++ - *pb++;
+    *pc++ = ACCUM(w);
+    w >>= MP_DIGIT_BIT;
+#else
+    d = *pa++;
+    diff = d - *pb++;
+    d = (diff > d);
+    if (borrow && --diff == MP_DIGIT_MAX)
+      ++d;
+    *pc++ = diff;
+    borrow = d;
+#endif
+  }
+  for (limit = MP_USED(a); ix < limit; ++ix) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+    w = w + *pa++;
+    *pc++ = ACCUM(w);
+    w >>= MP_DIGIT_BIT;
+#else
+    d = *pa++;
+    *pc++ = diff = d - borrow;
+    borrow = (diff > d);
+#endif
+  }
+
+  /* Clobber any leading zeroes we created    */
+  MP_USED(c) = ix;
+  s_mp_clamp(c);
+
+  /* 
+     If there was a borrow out, then |b| > |a| in violation
+     of our input invariant.  We've already done the work,
+     but we'll at least complain about it...
+   */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+  return w ? MP_RANGE : MP_OKAY;
+#else
+  return borrow ? MP_RANGE : MP_OKAY;
+#endif
+}
+/* {{{ s_mp_mul(a, b) */
+
+/* Compute a = |a| * |b|                                                  */
+mp_err   s_mp_mul(mp_int *a, const mp_int *b)
+{
+  return mp_mul(a, b, a);
+} /* end s_mp_mul() */
+
+/* }}} */
+
+#if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
+/* This trick works on Sparc V8 CPUs with the Workshop compilers. */
+#define MP_MUL_DxD(a, b, Phi, Plo) \
+  { unsigned long long product = (unsigned long long)a * b; \
+    Plo = (mp_digit)product; \
+    Phi = (mp_digit)(product >> MP_DIGIT_BIT); }
+#elif defined(OSF1)
+#define MP_MUL_DxD(a, b, Phi, Plo) \
+  { Plo = asm ("mulq %a0, %a1, %v0", a, b);\
+    Phi = asm ("umulh %a0, %a1, %v0", a, b); }
+#else
+#define MP_MUL_DxD(a, b, Phi, Plo) \
+  { mp_digit a0b1, a1b0; \
+    Plo = (a & MP_HALF_DIGIT_MAX) * (b & MP_HALF_DIGIT_MAX); \
+    Phi = (a >> MP_HALF_DIGIT_BIT) * (b >> MP_HALF_DIGIT_BIT); \
+    a0b1 = (a & MP_HALF_DIGIT_MAX) * (b >> MP_HALF_DIGIT_BIT); \
+    a1b0 = (a >> MP_HALF_DIGIT_BIT) * (b & MP_HALF_DIGIT_MAX); \
+    a1b0 += a0b1; \
+    Phi += a1b0 >> MP_HALF_DIGIT_BIT; \
+    if (a1b0 < a0b1)  \
+      Phi += MP_HALF_RADIX; \
+    a1b0 <<= MP_HALF_DIGIT_BIT; \
+    Plo += a1b0; \
+    if (Plo < a1b0) \
+      ++Phi; \
+  }
+#endif
+
+#if !defined(MP_ASSEMBLY_MULTIPLY)
+/* c = a * b */
+void s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+  mp_digit   d = 0;
+
+  /* Inner product:  Digits of a */
+  while (a_len--) {
+    mp_word w = ((mp_word)b * *a++) + d;
+    *c++ = ACCUM(w);
+    d = CARRYOUT(w);
+  }
+  *c = d;
+#else
+  mp_digit carry = 0;
+  while (a_len--) {
+    mp_digit a_i = *a++;
+    mp_digit a0b0, a1b1;
+
+    MP_MUL_DxD(a_i, b, a1b1, a0b0);
+
+    a0b0 += carry;
+    if (a0b0 < carry)
+      ++a1b1;
+    *c++ = a0b0;
+    carry = a1b1;
+  }
+  *c = carry;
+#endif
+}
+
+/* c += a * b */
+void s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, 
+			      mp_digit *c)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+  mp_digit   d = 0;
+
+  /* Inner product:  Digits of a */
+  while (a_len--) {
+    mp_word w = ((mp_word)b * *a++) + *c + d;
+    *c++ = ACCUM(w);
+    d = CARRYOUT(w);
+  }
+  *c = d;
+#else
+  mp_digit carry = 0;
+  while (a_len--) {
+    mp_digit a_i = *a++;
+    mp_digit a0b0, a1b1;
+
+    MP_MUL_DxD(a_i, b, a1b1, a0b0);
+
+    a0b0 += carry;
+    if (a0b0 < carry)
+      ++a1b1;
+    a0b0 += a_i = *c;
+    if (a0b0 < a_i)
+      ++a1b1;
+    *c++ = a0b0;
+    carry = a1b1;
+  }
+  *c = carry;
+#endif
+}
+
+/* Presently, this is only used by the Montgomery arithmetic code. */
+/* c += a * b */
+void s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+  mp_digit   d = 0;
+
+  /* Inner product:  Digits of a */
+  while (a_len--) {
+    mp_word w = ((mp_word)b * *a++) + *c + d;
+    *c++ = ACCUM(w);
+    d = CARRYOUT(w);
+  }
+
+  while (d) {
+    mp_word w = (mp_word)*c + d;
+    *c++ = ACCUM(w);
+    d = CARRYOUT(w);
+  }
+#else
+  mp_digit carry = 0;
+  while (a_len--) {
+    mp_digit a_i = *a++;
+    mp_digit a0b0, a1b1;
+
+    MP_MUL_DxD(a_i, b, a1b1, a0b0);
+
+    a0b0 += carry;
+    if (a0b0 < carry)
+      ++a1b1;
+
+    a0b0 += a_i = *c;
+    if (a0b0 < a_i)
+      ++a1b1;
+
+    *c++ = a0b0;
+    carry = a1b1;
+  }
+  while (carry) {
+    mp_digit c_i = *c;
+    carry += c_i;
+    *c++ = carry;
+    carry = carry < c_i;
+  }
+#endif
+}
+#endif
+
+#if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
+/* This trick works on Sparc V8 CPUs with the Workshop compilers. */
+#define MP_SQR_D(a, Phi, Plo) \
+  { unsigned long long square = (unsigned long long)a * a; \
+    Plo = (mp_digit)square; \
+    Phi = (mp_digit)(square >> MP_DIGIT_BIT); }
+#elif defined(OSF1)
+#define MP_SQR_D(a, Phi, Plo) \
+  { Plo = asm ("mulq  %a0, %a0, %v0", a);\
+    Phi = asm ("umulh %a0, %a0, %v0", a); }
+#else
+#define MP_SQR_D(a, Phi, Plo) \
+  { mp_digit Pmid; \
+    Plo  = (a  & MP_HALF_DIGIT_MAX) * (a  & MP_HALF_DIGIT_MAX); \
+    Phi  = (a >> MP_HALF_DIGIT_BIT) * (a >> MP_HALF_DIGIT_BIT); \
+    Pmid = (a  & MP_HALF_DIGIT_MAX) * (a >> MP_HALF_DIGIT_BIT); \
+    Phi += Pmid >> (MP_HALF_DIGIT_BIT - 1);  \
+    Pmid <<= (MP_HALF_DIGIT_BIT + 1);  \
+    Plo += Pmid;  \
+    if (Plo < Pmid)  \
+      ++Phi;  \
+  }
+#endif
+
+#if !defined(MP_ASSEMBLY_SQUARE)
+/* Add the squares of the digits of a to the digits of b. */
+void s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+  mp_word  w;
+  mp_digit d;
+  mp_size  ix;
+
+  w  = 0;
+#define ADD_SQUARE(n) \
+    d = pa[n]; \
+    w += (d * (mp_word)d) + ps[2*n]; \
+    ps[2*n] = ACCUM(w); \
+    w = (w >> DIGIT_BIT) + ps[2*n+1]; \
+    ps[2*n+1] = ACCUM(w); \
+    w = (w >> DIGIT_BIT)
+
+  for (ix = a_len; ix >= 4; ix -= 4) {
+    ADD_SQUARE(0);
+    ADD_SQUARE(1);
+    ADD_SQUARE(2);
+    ADD_SQUARE(3);
+    pa += 4;
+    ps += 8;
+  }
+  if (ix) {
+    ps += 2*ix;
+    pa += ix;
+    switch (ix) {
+    case 3: ADD_SQUARE(-3); /* FALLTHRU */
+    case 2: ADD_SQUARE(-2); /* FALLTHRU */
+    case 1: ADD_SQUARE(-1); /* FALLTHRU */
+    case 0: break;
+    }
+  }
+  while (w) {
+    w += *ps;
+    *ps++ = ACCUM(w);
+    w = (w >> DIGIT_BIT);
+  }
+#else
+  mp_digit carry = 0;
+  while (a_len--) {
+    mp_digit a_i = *pa++;
+    mp_digit a0a0, a1a1;
+
+    MP_SQR_D(a_i, a1a1, a0a0);
+
+    /* here a1a1 and a0a0 constitute a_i ** 2 */
+    a0a0 += carry;
+    if (a0a0 < carry)
+      ++a1a1;
+
+    /* now add to ps */
+    a0a0 += a_i = *ps;
+    if (a0a0 < a_i)
+      ++a1a1;
+    *ps++ = a0a0;
+    a1a1 += a_i = *ps;
+    carry = (a1a1 < a_i);
+    *ps++ = a1a1;
+  }
+  while (carry) {
+    mp_digit s_i = *ps;
+    carry += s_i;
+    *ps++ = carry;
+    carry = carry < s_i;
+  }
+#endif
+}
+#endif
+
+#if (defined(MP_NO_MP_WORD) || defined(MP_NO_DIV_WORD)) \
+&& !defined(MP_ASSEMBLY_DIV_2DX1D)
+/*
+** Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized 
+** so its high bit is 1.   This code is from NSPR.
+*/
+mp_err s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor, 
+		       mp_digit *qp, mp_digit *rp)
+{
+    mp_digit d1, d0, q1, q0;
+    mp_digit r1, r0, m;
+
+    d1 = divisor >> MP_HALF_DIGIT_BIT;
+    d0 = divisor & MP_HALF_DIGIT_MAX;
+    r1 = Nhi % d1;
+    q1 = Nhi / d1;
+    m = q1 * d0;
+    r1 = (r1 << MP_HALF_DIGIT_BIT) | (Nlo >> MP_HALF_DIGIT_BIT);
+    if (r1 < m) {
+        q1--, r1 += divisor;
+        if (r1 >= divisor && r1 < m) {
+	    q1--, r1 += divisor;
+	}
+    }
+    r1 -= m;
+    r0 = r1 % d1;
+    q0 = r1 / d1;
+    m = q0 * d0;
+    r0 = (r0 << MP_HALF_DIGIT_BIT) | (Nlo & MP_HALF_DIGIT_MAX);
+    if (r0 < m) {
+        q0--, r0 += divisor;
+        if (r0 >= divisor && r0 < m) {
+	    q0--, r0 += divisor;
+	}
+    }
+    if (qp)
+	*qp = (q1 << MP_HALF_DIGIT_BIT) | q0;
+    if (rp)
+	*rp = r0 - m;
+    return MP_OKAY;
+}
+#endif
+
+#if MP_SQUARE
+/* {{{ s_mp_sqr(a) */
+
+mp_err   s_mp_sqr(mp_int *a)
+{
+  mp_err   res;
+  mp_int   tmp;
+
+  if((res = mp_init_size(&tmp, 2 * USED(a))) != MP_OKAY)
+    return res;
+  res = mp_sqr(a, &tmp);
+  if (res == MP_OKAY) {
+    s_mp_exch(&tmp, a);
+  }
+  mp_clear(&tmp);
+  return res;
+}
+
+/* }}} */
+#endif
+
+/* {{{ s_mp_div(a, b) */
+
+/*
+  s_mp_div(a, b)
+
+  Compute a = a / b and b = a mod b.  Assumes b > a.
+ */
+
+mp_err   s_mp_div(mp_int *rem, 	/* i: dividend, o: remainder */
+                  mp_int *div, 	/* i: divisor                */
+		  mp_int *quot)	/* i: 0;        o: quotient  */
+{
+  mp_int   part, t;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+  mp_word  q_msd;
+#else
+  mp_digit q_msd;
+#endif
+  mp_err   res;
+  mp_digit d;
+  mp_digit div_msd;
+  int      ix;
+
+  if(mp_cmp_z(div) == 0)
+    return MP_RANGE;
+
+  /* Shortcut if divisor is power of two */
+  if((ix = s_mp_ispow2(div)) >= 0) {
+    MP_CHECKOK( mp_copy(rem, quot) );
+    s_mp_div_2d(quot, (mp_digit)ix);
+    s_mp_mod_2d(rem,  (mp_digit)ix);
+
+    return MP_OKAY;
+  }
+
+  DIGITS(&t) = 0;
+  MP_SIGN(rem) = ZPOS;
+  MP_SIGN(div) = ZPOS;
+
+  /* A working temporary for division     */
+  MP_CHECKOK( mp_init_size(&t, MP_ALLOC(rem)));
+
+  /* Normalize to optimize guessing       */
+  MP_CHECKOK( s_mp_norm(rem, div, &d) );
+
+  part = *rem;
+
+  /* Perform the division itself...woo!   */
+  MP_USED(quot) = MP_ALLOC(quot);
+
+  /* Find a partial substring of rem which is at least div */
+  /* If we didn't find one, we're finished dividing    */
+  while (MP_USED(rem) > MP_USED(div) || s_mp_cmp(rem, div) >= 0) {
+    int i;
+    int unusedRem;
+
+    unusedRem = MP_USED(rem) - MP_USED(div);
+    MP_DIGITS(&part) = MP_DIGITS(rem) + unusedRem;
+    MP_ALLOC(&part)  = MP_ALLOC(rem)  - unusedRem;
+    MP_USED(&part)   = MP_USED(div);
+    if (s_mp_cmp(&part, div) < 0) {
+      -- unusedRem;
+#if MP_ARGCHK == 2
+      assert(unusedRem >= 0);
+#endif
+      -- MP_DIGITS(&part);
+      ++ MP_USED(&part);
+      ++ MP_ALLOC(&part);
+    }
+
+    /* Compute a guess for the next quotient digit       */
+    q_msd = MP_DIGIT(&part, MP_USED(&part) - 1);
+    div_msd = MP_DIGIT(div, MP_USED(div) - 1);
+    if (q_msd >= div_msd) {
+      q_msd = 1;
+    } else if (MP_USED(&part) > 1) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+      q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2);
+      q_msd /= div_msd;
+      if (q_msd == RADIX)
+        --q_msd;
+#else
+      mp_digit r;
+      MP_CHECKOK( s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2), 
+				  div_msd, &q_msd, &r) );
+#endif
+    } else {
+      q_msd = 0;
+    }
+#if MP_ARGCHK == 2
+    assert(q_msd > 0); /* This case should never occur any more. */
+#endif
+    if (q_msd <= 0)
+      break;
+
+    /* See what that multiplies out to                   */
+    mp_copy(div, &t);
+    MP_CHECKOK( s_mp_mul_d(&t, (mp_digit)q_msd) );
+
+    /* 
+       If it's too big, back it off.  We should not have to do this
+       more than once, or, in rare cases, twice.  Knuth describes a
+       method by which this could be reduced to a maximum of once, but
+       I didn't implement that here.
+     * When using s_mpv_div_2dx1d, we may have to do this 3 times.
+     */
+    for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) {
+      --q_msd;
+      s_mp_sub(&t, div);	/* t -= div */
+    }
+    if (i < 0) {
+      res = MP_RANGE;
+      goto CLEANUP;
+    }
+
+    /* At this point, q_msd should be the right next digit   */
+    MP_CHECKOK( s_mp_sub(&part, &t) );	/* part -= t */
+    s_mp_clamp(rem);
+
+    /*
+      Include the digit in the quotient.  We allocated enough memory
+      for any quotient we could ever possibly get, so we should not
+      have to check for failures here
+     */
+    MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd;
+  }
+
+  /* Denormalize remainder                */
+  if (d) {
+    s_mp_div_2d(rem, d);
+  }
+
+  s_mp_clamp(quot);
+
+CLEANUP:
+  mp_clear(&t);
+
+  return res;
+
+} /* end s_mp_div() */
+
+
+/* }}} */
+
+/* {{{ s_mp_2expt(a, k) */
+
+mp_err   s_mp_2expt(mp_int *a, mp_digit k)
+{
+  mp_err    res;
+  mp_size   dig, bit;
+
+  dig = k / DIGIT_BIT;
+  bit = k % DIGIT_BIT;
+
+  mp_zero(a);
+  if((res = s_mp_pad(a, dig + 1)) != MP_OKAY)
+    return res;
+  
+  DIGIT(a, dig) |= ((mp_digit)1 << bit);
+
+  return MP_OKAY;
+
+} /* end s_mp_2expt() */
+
+/* }}} */
+
+/* {{{ s_mp_reduce(x, m, mu) */
+
+/*
+  Compute Barrett reduction, x (mod m), given a precomputed value for
+  mu = b^2k / m, where b = RADIX and k = #digits(m).  This should be
+  faster than straight division, when many reductions by the same
+  value of m are required (such as in modular exponentiation).  This
+  can nearly halve the time required to do modular exponentiation,
+  as compared to using the full integer divide to reduce.
+
+  This algorithm was derived from the _Handbook of Applied
+  Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
+  pp. 603-604.  
+ */
+
+mp_err   s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
+{
+  mp_int   q;
+  mp_err   res;
+
+  if((res = mp_init_copy(&q, x)) != MP_OKAY)
+    return res;
+
+  s_mp_rshd(&q, USED(m) - 1);  /* q1 = x / b^(k-1)  */
+  s_mp_mul(&q, mu);            /* q2 = q1 * mu      */
+  s_mp_rshd(&q, USED(m) + 1);  /* q3 = q2 / b^(k+1) */
+
+  /* x = x mod b^(k+1), quick (no division) */
+  s_mp_mod_2d(x, DIGIT_BIT * (USED(m) + 1));
+
+  /* q = q * m mod b^(k+1), quick (no division) */
+  s_mp_mul(&q, m);
+  s_mp_mod_2d(&q, DIGIT_BIT * (USED(m) + 1));
+
+  /* x = x - q */
+  if((res = mp_sub(x, &q, x)) != MP_OKAY)
+    goto CLEANUP;
+
+  /* If x < 0, add b^(k+1) to it */
+  if(mp_cmp_z(x) < 0) {
+    mp_set(&q, 1);
+    if((res = s_mp_lshd(&q, USED(m) + 1)) != MP_OKAY)
+      goto CLEANUP;
+    if((res = mp_add(x, &q, x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  /* Back off if it's too big */
+  while(mp_cmp(x, m) >= 0) {
+    if((res = s_mp_sub(x, m)) != MP_OKAY)
+      break;
+  }
+
+ CLEANUP:
+  mp_clear(&q);
+
+  return res;
+
+} /* end s_mp_reduce() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive comparisons */
+
+/* {{{ s_mp_cmp(a, b) */
+
+/* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b           */
+int      s_mp_cmp(const mp_int *a, const mp_int *b)
+{
+  mp_size used_a = MP_USED(a);
+  {
+    mp_size used_b = MP_USED(b);
+
+    if (used_a > used_b)
+      goto IS_GT;
+    if (used_a < used_b)
+      goto IS_LT;
+  }
+  {
+    mp_digit *pa, *pb;
+    mp_digit da = 0, db = 0;
+
+#define CMP_AB(n) if ((da = pa[n]) != (db = pb[n])) goto done
+
+    pa = MP_DIGITS(a) + used_a;
+    pb = MP_DIGITS(b) + used_a;
+    while (used_a >= 4) {
+      pa     -= 4;
+      pb     -= 4;
+      used_a -= 4;
+      CMP_AB(3);
+      CMP_AB(2);
+      CMP_AB(1);
+      CMP_AB(0);
+    }
+    while (used_a-- > 0 && ((da = *--pa) == (db = *--pb))) 
+      /* do nothing */;
+done:
+    if (da > db)
+      goto IS_GT;
+    if (da < db) 
+      goto IS_LT;
+  }
+  return MP_EQ;
+IS_LT:
+  return MP_LT;
+IS_GT:
+  return MP_GT;
+} /* end s_mp_cmp() */
+
+/* }}} */
+
+/* {{{ s_mp_cmp_d(a, d) */
+
+/* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d             */
+int      s_mp_cmp_d(const mp_int *a, mp_digit d)
+{
+  if(USED(a) > 1)
+    return MP_GT;
+
+  if(DIGIT(a, 0) < d)
+    return MP_LT;
+  else if(DIGIT(a, 0) > d)
+    return MP_GT;
+  else
+    return MP_EQ;
+
+} /* end s_mp_cmp_d() */
+
+/* }}} */
+
+/* {{{ s_mp_ispow2(v) */
+
+/*
+  Returns -1 if the value is not a power of two; otherwise, it returns
+  k such that v = 2^k, i.e. lg(v).
+ */
+int      s_mp_ispow2(const mp_int *v)
+{
+  mp_digit d;
+  int      extra = 0, ix;
+
+  ix = MP_USED(v) - 1;
+  d = MP_DIGIT(v, ix); /* most significant digit of v */
+
+  extra = s_mp_ispow2d(d);
+  if (extra < 0 || ix == 0)
+    return extra;
+
+  while (--ix >= 0) {
+    if (DIGIT(v, ix) != 0)
+      return -1; /* not a power of two */
+    extra += MP_DIGIT_BIT;
+  }
+
+  return extra;
+
+} /* end s_mp_ispow2() */
+
+/* }}} */
+
+/* {{{ s_mp_ispow2d(d) */
+
+int      s_mp_ispow2d(mp_digit d)
+{
+  if ((d != 0) && ((d & (d-1)) == 0)) { /* d is a power of 2 */
+    int pow = 0;
+#if defined (MP_USE_UINT_DIGIT)
+    if (d & 0xffff0000U)
+      pow += 16;
+    if (d & 0xff00ff00U)
+      pow += 8;
+    if (d & 0xf0f0f0f0U)
+      pow += 4;
+    if (d & 0xccccccccU)
+      pow += 2;
+    if (d & 0xaaaaaaaaU)
+      pow += 1;
+#elif defined(MP_USE_LONG_LONG_DIGIT)
+    if (d & 0xffffffff00000000ULL)
+      pow += 32;
+    if (d & 0xffff0000ffff0000ULL)
+      pow += 16;
+    if (d & 0xff00ff00ff00ff00ULL)
+      pow += 8;
+    if (d & 0xf0f0f0f0f0f0f0f0ULL)
+      pow += 4;
+    if (d & 0xccccccccccccccccULL)
+      pow += 2;
+    if (d & 0xaaaaaaaaaaaaaaaaULL)
+      pow += 1;
+#elif defined(MP_USE_LONG_DIGIT)
+    if (d & 0xffffffff00000000UL)
+      pow += 32;
+    if (d & 0xffff0000ffff0000UL)
+      pow += 16;
+    if (d & 0xff00ff00ff00ff00UL)
+      pow += 8;
+    if (d & 0xf0f0f0f0f0f0f0f0UL)
+      pow += 4;
+    if (d & 0xccccccccccccccccUL)
+      pow += 2;
+    if (d & 0xaaaaaaaaaaaaaaaaUL)
+      pow += 1;
+#else
+#error "unknown type for mp_digit"
+#endif
+    return pow;
+  }
+  return -1;
+
+} /* end s_mp_ispow2d() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive I/O helpers */
+
+/* {{{ s_mp_tovalue(ch, r) */
+
+/*
+  Convert the given character to its digit value, in the given radix.
+  If the given character is not understood in the given radix, -1 is
+  returned.  Otherwise the digit's numeric value is returned.
+
+  The results will be odd if you use a radix < 2 or > 62, you are
+  expected to know what you're up to.
+ */
+int      s_mp_tovalue(char ch, int r)
+{
+  int    val, xch;
+  
+  if(r > 36)
+    xch = ch;
+  else
+    xch = toupper(ch);
+
+  if(isdigit(xch))
+    val = xch - '0';
+  else if(isupper(xch))
+    val = xch - 'A' + 10;
+  else if(islower(xch))
+    val = xch - 'a' + 36;
+  else if(xch == '+')
+    val = 62;
+  else if(xch == '/')
+    val = 63;
+  else 
+    return -1;
+
+  if(val < 0 || val >= r)
+    return -1;
+
+  return val;
+
+} /* end s_mp_tovalue() */
+
+/* }}} */
+
+/* {{{ s_mp_todigit(val, r, low) */
+
+/*
+  Convert val to a radix-r digit, if possible.  If val is out of range
+  for r, returns zero.  Otherwise, returns an ASCII character denoting
+  the value in the given radix.
+
+  The results may be odd if you use a radix < 2 or > 64, you are
+  expected to know what you're doing.
+ */
+  
+char     s_mp_todigit(mp_digit val, int r, int low)
+{
+  char   ch;
+
+  if(val >= r)
+    return 0;
+
+  ch = s_dmap_1[val];
+
+  if(r <= 36 && low)
+    ch = tolower(ch);
+
+  return ch;
+
+} /* end s_mp_todigit() */
+
+/* }}} */
+
+/* {{{ s_mp_outlen(bits, radix) */
+
+/* 
+   Return an estimate for how long a string is needed to hold a radix
+   r representation of a number with 'bits' significant bits, plus an
+   extra for a zero terminator (assuming C style strings here)
+ */
+int      s_mp_outlen(int bits, int r)
+{
+  return (int)((double)bits * LOG_V_2(r) + 1.5) + 1;
+
+} /* end s_mp_outlen() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ mp_read_unsigned_octets(mp, str, len) */
+/* mp_read_unsigned_octets(mp, str, len)
+   Read in a raw value (base 256) into the given mp_int
+   No sign bit, number is positive.  Leading zeros ignored.
+ */
+
+mp_err  
+mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len)
+{
+  int            count;
+  mp_err         res;
+  mp_digit       d;
+
+  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+  mp_zero(mp);
+
+  count = len % sizeof(mp_digit);
+  if (count) {
+    for (d = 0; count-- > 0; --len) {
+      d = (d << 8) | *str++;
+    }
+    MP_DIGIT(mp, 0) = d;
+  }
+
+  /* Read the rest of the digits */
+  for(; len > 0; len -= sizeof(mp_digit)) {
+    for (d = 0, count = sizeof(mp_digit); count > 0; --count) {
+      d = (d << 8) | *str++;
+    }
+    if (MP_EQ == mp_cmp_z(mp)) {
+      if (!d)
+	continue;
+    } else {
+      if((res = s_mp_lshd(mp, 1)) != MP_OKAY)
+	return res;
+    }
+    MP_DIGIT(mp, 0) = d;
+  }
+  return MP_OKAY;
+} /* end mp_read_unsigned_octets() */
+/* }}} */
+
+/* {{{ mp_unsigned_octet_size(mp) */
+int    
+mp_unsigned_octet_size(const mp_int *mp)
+{
+  int  bytes;
+  int  ix;
+  mp_digit  d = 0;
+
+  ARGCHK(mp != NULL, MP_BADARG);
+  ARGCHK(MP_ZPOS == SIGN(mp), MP_BADARG);
+
+  bytes = (USED(mp) * sizeof(mp_digit));
+
+  /* subtract leading zeros. */
+  /* Iterate over each digit... */
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    d = DIGIT(mp, ix);
+    if (d) 
+	break;
+    bytes -= sizeof(d);
+  }
+  if (!bytes)
+    return 1;
+
+  /* Have MSD, check digit bytes, high order first */
+  for(ix = sizeof(mp_digit) - 1; ix >= 0; ix--) {
+    unsigned char x = (unsigned char)(d >> (ix * CHAR_BIT));
+    if (x) 
+	break;
+    --bytes;
+  }
+  return bytes;
+} /* end mp_unsigned_octet_size() */
+/* }}} */
+
+/* {{{ mp_to_unsigned_octets(mp, str) */
+/* output a buffer of big endian octets no longer than specified. */
+mp_err 
+mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
+{
+  int  ix, pos = 0;
+  int  bytes;
+
+  ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
+
+  bytes = mp_unsigned_octet_size(mp);
+  ARGCHK(bytes <= maxlen, MP_BADARG);
+
+  /* Iterate over each digit... */
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    mp_digit  d = DIGIT(mp, ix);
+    int       jx;
+
+    /* Unpack digit bytes, high order first */
+    for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+      unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
+      if (!pos && !x)	/* suppress leading zeros */
+	continue;
+      str[pos++] = x;
+    }
+  }
+  if (!pos)
+    str[pos++] = 0;
+  return pos;
+} /* end mp_to_unsigned_octets() */
+/* }}} */
+
+/* {{{ mp_to_signed_octets(mp, str) */
+/* output a buffer of big endian octets no longer than specified. */
+mp_err 
+mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
+{
+  int  ix, pos = 0;
+  int  bytes;
+
+  ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
+
+  bytes = mp_unsigned_octet_size(mp);
+  ARGCHK(bytes <= maxlen, MP_BADARG);
+
+  /* Iterate over each digit... */
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    mp_digit  d = DIGIT(mp, ix);
+    int       jx;
+
+    /* Unpack digit bytes, high order first */
+    for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+      unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
+      if (!pos) {
+	if (!x)		/* suppress leading zeros */
+	  continue;
+	if (x & 0x80) { /* add one leading zero to make output positive.  */
+	  ARGCHK(bytes + 1 <= maxlen, MP_BADARG);
+	  if (bytes + 1 > maxlen)
+	    return MP_BADARG;
+	  str[pos++] = 0;
+	}
+      }
+      str[pos++] = x;
+    }
+  }
+  if (!pos)
+    str[pos++] = 0;
+  return pos;
+} /* end mp_to_signed_octets() */
+/* }}} */
+
+/* {{{ mp_to_fixlen_octets(mp, str) */
+/* output a buffer of big endian octets exactly as long as requested. */
+mp_err 
+mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length)
+{
+  int  ix, pos = 0;
+  int  bytes;
+
+  ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
+
+  bytes = mp_unsigned_octet_size(mp);
+  ARGCHK(bytes <= length, MP_BADARG);
+
+  /* place any needed leading zeros */
+  for (;length > bytes; --length) {
+	*str++ = 0;
+  }
+
+  /* Iterate over each digit... */
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    mp_digit  d = DIGIT(mp, ix);
+    int       jx;
+
+    /* Unpack digit bytes, high order first */
+    for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+      unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
+      if (!pos && !x)	/* suppress leading zeros */
+	continue;
+      str[pos++] = x;
+    }
+  }
+  if (!pos)
+    str[pos++] = 0;
+  return MP_OKAY;
+} /* end mp_to_fixlen_octets() */
+/* }}} */
+
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS                                                  */
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpi.h b/mozilla/security/nss/lib/freebl/mpi/mpi.h
new file mode 100644
index 0000000..79503f3
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpi.h
@@ -0,0 +1,340 @@
+/*
+ *  mpi.h
+ *
+ *  Arbitrary precision integer arithmetic library
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Netscape Communications Corporation
+ *
+ * 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 ***** */
+/* $Id: mpi.h,v 1.23 2008/12/04 18:16:34 rrelyea%redhat.com Exp $ */
+
+#ifndef _H_MPI_
+#define _H_MPI_
+
+#include "mpi-config.h"
+
+#if MP_DEBUG
+#undef MP_IOFUNC
+#define MP_IOFUNC 1
+#endif
+
+#if MP_IOFUNC
+#include <stdio.h>
+#include <ctype.h>
+#endif
+
+#include <limits.h>
+
+#if defined(BSDI)
+#undef ULLONG_MAX
+#endif
+
+#if defined( macintosh )
+#include <Types.h>
+#elif defined( _WIN32_WCE)
+/* #include <sys/types.h> What do we need here ?? */
+#else
+#include <sys/types.h>
+#endif
+
+#define  MP_NEG    1
+#define  MP_ZPOS   0
+
+#define  MP_OKAY          0 /* no error, all is well */
+#define  MP_YES           0 /* yes (boolean result)  */
+#define  MP_NO           -1 /* no (boolean result)   */
+#define  MP_MEM          -2 /* out of memory         */
+#define  MP_RANGE        -3 /* argument out of range */
+#define  MP_BADARG       -4 /* invalid parameter     */
+#define  MP_UNDEF        -5 /* answer is undefined   */
+#define  MP_LAST_CODE    MP_UNDEF
+
+typedef unsigned int      mp_sign;
+typedef unsigned int      mp_size;
+typedef int               mp_err;
+
+#define MP_32BIT_MAX 4294967295U
+
+#if !defined(ULONG_MAX) 
+#error "ULONG_MAX not defined"
+#elif !defined(UINT_MAX)
+#error "UINT_MAX not defined"
+#elif !defined(USHRT_MAX)
+#error "USHRT_MAX not defined"
+#endif
+
+#if defined(ULONG_LONG_MAX)			/* GCC, HPUX */
+#define MP_ULONG_LONG_MAX ULONG_LONG_MAX
+#elif defined(ULLONG_MAX)			/* Solaris */
+#define MP_ULONG_LONG_MAX ULLONG_MAX
+/* MP_ULONG_LONG_MAX was defined to be ULLONG_MAX */
+#elif defined(ULONGLONG_MAX)			/* IRIX, AIX */
+#define MP_ULONG_LONG_MAX ULONGLONG_MAX
+#endif
+
+/* We only use unsigned long for mp_digit iff long is more than 32 bits. */
+#if !defined(MP_USE_UINT_DIGIT) && ULONG_MAX > MP_32BIT_MAX
+typedef unsigned long     mp_digit;
+#define MP_DIGIT_MAX      ULONG_MAX
+#define MP_DIGIT_FMT      "%016lX"   /* printf() format for 1 digit */
+#define MP_HALF_DIGIT_MAX UINT_MAX
+#undef  MP_NO_MP_WORD
+#define MP_NO_MP_WORD 1
+#undef  MP_USE_LONG_DIGIT
+#define MP_USE_LONG_DIGIT 1
+#undef  MP_USE_LONG_LONG_DIGIT
+
+#elif !defined(MP_USE_UINT_DIGIT) && defined(MP_ULONG_LONG_MAX) 
+typedef unsigned long long mp_digit;
+#define MP_DIGIT_MAX       MP_ULONG_LONG_MAX
+#define MP_DIGIT_FMT      "%016llX"  /* printf() format for 1 digit */
+#define MP_HALF_DIGIT_MAX  UINT_MAX
+#undef  MP_NO_MP_WORD
+#define MP_NO_MP_WORD 1
+#undef  MP_USE_LONG_LONG_DIGIT
+#define MP_USE_LONG_LONG_DIGIT 1
+#undef  MP_USE_LONG_DIGIT
+
+#else
+typedef unsigned int      mp_digit;
+#define MP_DIGIT_MAX      UINT_MAX
+#define MP_DIGIT_FMT      "%08X"     /* printf() format for 1 digit */
+#define MP_HALF_DIGIT_MAX USHRT_MAX
+#undef  MP_USE_UINT_DIGIT
+#define MP_USE_UINT_DIGIT 1
+#undef  MP_USE_LONG_LONG_DIGIT
+#undef  MP_USE_LONG_DIGIT
+#endif
+
+#if !defined(MP_NO_MP_WORD) 
+#if  defined(MP_USE_UINT_DIGIT) && \
+    (defined(MP_ULONG_LONG_MAX) || (ULONG_MAX > UINT_MAX))
+
+#if (ULONG_MAX > UINT_MAX)
+typedef unsigned long     mp_word;
+typedef          long     mp_sword;
+#define MP_WORD_MAX       ULONG_MAX
+
+#else
+typedef unsigned long long mp_word;
+typedef          long long mp_sword;
+#define MP_WORD_MAX       MP_ULONG_LONG_MAX
+#endif
+
+#else 
+#define MP_NO_MP_WORD 1
+#endif
+#endif /* !defined(MP_NO_MP_WORD) */
+
+#if !defined(MP_WORD_MAX) && defined(MP_DEFINE_SMALL_WORD)
+typedef unsigned int      mp_word;
+typedef          int      mp_sword;
+#define MP_WORD_MAX       UINT_MAX
+#endif
+
+#define MP_DIGIT_BIT      (CHAR_BIT*sizeof(mp_digit))
+#define MP_WORD_BIT       (CHAR_BIT*sizeof(mp_word))
+#define MP_RADIX          (1+(mp_word)MP_DIGIT_MAX)
+
+#define MP_HALF_DIGIT_BIT (MP_DIGIT_BIT/2)
+#define MP_HALF_RADIX     (1+(mp_digit)MP_HALF_DIGIT_MAX)
+/* MP_HALF_RADIX really ought to be called MP_SQRT_RADIX, but it's named 
+** MP_HALF_RADIX because it's the radix for MP_HALF_DIGITs, and it's 
+** consistent with the other _HALF_ names.
+*/
+
+
+/* Macros for accessing the mp_int internals           */
+#define  MP_SIGN(MP)     ((MP)->sign)
+#define  MP_USED(MP)     ((MP)->used)
+#define  MP_ALLOC(MP)    ((MP)->alloc)
+#define  MP_DIGITS(MP)   ((MP)->dp)
+#define  MP_DIGIT(MP,N)  (MP)->dp[(N)]
+
+/* This defines the maximum I/O base (minimum is 2)   */
+#define MP_MAX_RADIX         64
+
+typedef struct {
+  mp_sign       sign;    /* sign of this quantity      */
+  mp_size       alloc;   /* how many digits allocated  */
+  mp_size       used;    /* how many digits used       */
+  mp_digit     *dp;      /* the digits themselves      */
+} mp_int;
+
+/* Default precision       */
+mp_size mp_get_prec(void);
+void    mp_set_prec(mp_size prec);
+
+/* Memory management       */
+mp_err mp_init(mp_int *mp);
+mp_err mp_init_size(mp_int *mp, mp_size prec);
+mp_err mp_init_copy(mp_int *mp, const mp_int *from);
+mp_err mp_copy(const mp_int *from, mp_int *to);
+void   mp_exch(mp_int *mp1, mp_int *mp2);
+void   mp_clear(mp_int *mp);
+void   mp_zero(mp_int *mp);
+void   mp_set(mp_int *mp, mp_digit d);
+mp_err mp_set_int(mp_int *mp, long z);
+#define mp_set_long(mp,z) mp_set_int(mp,z)
+mp_err mp_set_ulong(mp_int *mp, unsigned long z);
+
+/* Single digit arithmetic */
+mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_mul_2(const mp_int *a, mp_int *c);
+mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r);
+mp_err mp_div_2(const mp_int *a, mp_int *c);
+mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c);
+
+/* Sign manipulations      */
+mp_err mp_abs(const mp_int *a, mp_int *b);
+mp_err mp_neg(const mp_int *a, mp_int *b);
+
+/* Full arithmetic         */
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c);
+#if MP_SQUARE
+mp_err mp_sqr(const mp_int *a, mp_int *b);
+#else
+#define mp_sqr(a, b) mp_mul(a, a, b)
+#endif
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r);
+mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r);
+mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_2expt(mp_int *a, mp_digit k);
+mp_err mp_sqrt(const mp_int *a, mp_int *b);
+
+/* Modular arithmetic      */
+#if MP_MODARITH
+mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c);
+mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c);
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+#if MP_SQUARE
+mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c);
+#else
+#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c)
+#endif
+mp_err mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c);
+#endif /* MP_MODARITH */
+
+/* Comparisons             */
+int    mp_cmp_z(const mp_int *a);
+int    mp_cmp_d(const mp_int *a, mp_digit d);
+int    mp_cmp(const mp_int *a, const mp_int *b);
+int    mp_cmp_mag(mp_int *a, mp_int *b);
+int    mp_cmp_int(const mp_int *a, long z);
+int    mp_isodd(const mp_int *a);
+int    mp_iseven(const mp_int *a);
+
+/* Number theoretic        */
+#if MP_NUMTH
+mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y);
+mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c);
+mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c);
+#endif /* end MP_NUMTH */
+
+/* Input and output        */
+#if MP_IOFUNC
+void   mp_print(mp_int *mp, FILE *ofp);
+#endif /* end MP_IOFUNC */
+
+/* Base conversion         */
+mp_err mp_read_raw(mp_int *mp, char *str, int len);
+int    mp_raw_size(mp_int *mp);
+mp_err mp_toraw(mp_int *mp, char *str);
+mp_err mp_read_radix(mp_int *mp, const char *str, int radix);
+mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix);
+int    mp_radix_size(mp_int *mp, int radix);
+mp_err mp_toradix(mp_int *mp, char *str, int radix);
+int    mp_tovalue(char ch, int r);
+
+#define mp_tobinary(M, S)  mp_toradix((M), (S), 2)
+#define mp_tooctal(M, S)   mp_toradix((M), (S), 8)
+#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
+#define mp_tohex(M, S)     mp_toradix((M), (S), 16)
+
+/* Error strings           */
+const  char  *mp_strerror(mp_err ec);
+
+/* Octet string conversion functions */
+mp_err mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len);
+int    mp_unsigned_octet_size(const mp_int *mp);
+mp_err mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen);
+mp_err mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen);
+mp_err mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size len);
+
+/* Miscellaneous */
+mp_size mp_trailing_zeros(const mp_int *mp);
+void freebl_cpuid(unsigned long op, unsigned long *eax,
+                         unsigned long *ebx, unsigned long *ecx,
+                         unsigned long *edx);
+
+
+#define MP_CHECKOK(x)  if (MP_OKAY > (res = (x))) goto CLEANUP
+#define MP_CHECKERR(x) if (MP_OKAY > (res = (x))) goto CLEANUP
+
+#if defined(MP_API_COMPATIBLE)
+#define NEG             MP_NEG
+#define ZPOS            MP_ZPOS
+#define DIGIT_MAX       MP_DIGIT_MAX
+#define DIGIT_BIT       MP_DIGIT_BIT
+#define DIGIT_FMT       MP_DIGIT_FMT
+#define RADIX           MP_RADIX
+#define MAX_RADIX       MP_MAX_RADIX
+#define SIGN(MP)        MP_SIGN(MP)
+#define USED(MP)        MP_USED(MP)
+#define ALLOC(MP)       MP_ALLOC(MP)
+#define DIGITS(MP)      MP_DIGITS(MP)
+#define DIGIT(MP,N)     MP_DIGIT(MP,N)
+
+#if MP_ARGCHK == 1
+#define  ARGCHK(X,Y)  {if(!(X)){return (Y);}}
+#elif MP_ARGCHK == 2
+#include <assert.h>
+#define  ARGCHK(X,Y)  assert(X)
+#else
+#define  ARGCHK(X,Y)  /*  */
+#endif
+#endif /* defined MP_API_COMPATIBLE */
+
+#endif /* end _H_MPI_ */
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpi_amd64.c b/mozilla/security/nss/lib/freebl/mpi/mpi_amd64.c
new file mode 100644
index 0000000..5befb87
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpi_amd64.c
@@ -0,0 +1,65 @@
+/* ***** 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 Solaris software cryptographic token.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sun Microsystems, Inc.
+ *
+ * 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 ***** */
+
+#ifndef MPI_AMD64
+#error This file only works on AMD64 platforms.
+#endif
+
+#include <mpi-priv.h>
+
+/*
+ * MPI glue
+ *
+ */
+
+/* Presently, this is only used by the Montgomery arithmetic code. */
+/* c += a * b */
+void MPI_ASM_DECL s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len,
+                                       mp_digit b, mp_digit *c)
+{
+  mp_digit w;
+  mp_digit d;
+
+  d = s_mpv_mul_add_vec64(c, a, a_len, b);
+  c += a_len;
+  while (d) {
+    w = c[0] + d;
+    d = (w < c[0] || w < d);
+    *c++ = w;
+  }
+}
+
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpi_x86_asm.c b/mozilla/security/nss/lib/freebl/mpi/mpi_x86_asm.c
new file mode 100644
index 0000000..9539699
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpi_x86_asm.c
@@ -0,0 +1,568 @@
+/*
+ *  mpi_x86.c - MSVC inline assembly implementation of s_mpv_ functions.
+ * 
+ * ***** 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) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ *
+ * 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 "mpi-priv.h"
+
+static int is_sse = -1;
+extern unsigned long s_mpi_is_sse2();
+
+/*
+ *   ebp - 36:	caller's esi
+ *   ebp - 32:	caller's edi
+ *   ebp - 28:	
+ *   ebp - 24:	
+ *   ebp - 20:	
+ *   ebp - 16:	
+ *   ebp - 12:	
+ *   ebp - 8:	
+ *   ebp - 4:	
+ *   ebp + 0:	caller's ebp
+ *   ebp + 4:	return address
+ *   ebp + 8:	a	argument
+ *   ebp + 12:	a_len	argument
+ *   ebp + 16:	b	argument
+ *   ebp + 20:	c	argument
+ *   registers:
+ *  	eax:
+ * 	ebx:	carry
+ * 	ecx:	a_len
+ * 	edx:
+ * 	esi:	a ptr
+ * 	edi:	c ptr
+ */
+__declspec(naked) void
+s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
+{
+  __asm {
+    mov    eax, is_sse
+    cmp    eax, 0
+    je     s_mpv_mul_d_x86
+    jg     s_mpv_mul_d_sse2
+    call   s_mpi_is_sse2
+    mov    is_sse, eax
+    cmp    eax, 0
+    jg     s_mpv_mul_d_sse2
+s_mpv_mul_d_x86:
+    push   ebp
+    mov    ebp,esp
+    sub    esp,28
+    push   edi
+    push   esi
+    push   ebx
+    mov    ebx,0		; carry = 0
+    mov    ecx,[ebp+12]		; ecx = a_len
+    mov    edi,[ebp+20]
+    cmp    ecx,0
+    je     L_2			; jmp if a_len == 0
+    mov    esi,[ebp+8]		; esi = a
+    cld
+L_1:
+    lodsd			; eax = [ds:esi]; esi += 4
+    mov    edx,[ebp+16]		; edx = b
+    mul    edx			; edx:eax = Phi:Plo = a_i * b
+
+    add    eax,ebx		; add carry (ebx) to edx:eax
+    adc    edx,0
+    mov    ebx,edx		; high half of product becomes next carry
+
+    stosd			; [es:edi] = ax; edi += 4;
+    dec    ecx			; --a_len
+    jnz    L_1			; jmp if a_len != 0
+L_2:
+    mov    [edi],ebx		; *c = carry
+    pop    ebx
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+s_mpv_mul_d_sse2:
+    push   ebp
+    mov    ebp, esp
+    push   edi
+    push   esi
+    psubq  mm2, mm2		; carry = 0
+    mov    ecx, [ebp+12]	; ecx = a_len
+    movd   mm1, [ebp+16]	; mm1 = b
+    mov    edi, [ebp+20]
+    cmp    ecx, 0
+    je     L_6			; jmp if a_len == 0
+    mov    esi, [ebp+8]		; esi = a
+    cld
+L_5:
+    movd   mm0, [esi]		; mm0 = *a++
+    add    esi, 4
+    pmuludq mm0, mm1		; mm0 = b * *a++
+    paddq  mm2, mm0		; add the carry
+    movd   [edi], mm2		; store the 32bit result
+    add    edi, 4
+    psrlq  mm2, 32		; save the carry
+    dec    ecx			; --a_len
+    jnz    L_5			; jmp if a_len != 0
+L_6:
+    movd   [edi], mm2		; *c = carry
+    emms
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+  }
+}
+
+/*
+ *   ebp - 36:	caller's esi
+ *   ebp - 32:	caller's edi
+ *   ebp - 28:	
+ *   ebp - 24:	
+ *   ebp - 20:	
+ *   ebp - 16:	
+ *   ebp - 12:	
+ *   ebp - 8:	
+ *   ebp - 4:	
+ *   ebp + 0:	caller's ebp
+ *   ebp + 4:	return address
+ *   ebp + 8:	a	argument
+ *   ebp + 12:	a_len	argument
+ *   ebp + 16:	b	argument
+ *   ebp + 20:	c	argument
+ *   registers:
+ *  	eax:
+ * 	ebx:	carry
+ * 	ecx:	a_len
+ * 	edx:
+ * 	esi:	a ptr
+ * 	edi:	c ptr
+ */
+__declspec(naked) void
+s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
+{
+  __asm {
+    mov    eax, is_sse
+    cmp    eax, 0
+    je     s_mpv_mul_d_add_x86
+    jg     s_mpv_mul_d_add_sse2
+    call   s_mpi_is_sse2
+    mov    is_sse, eax
+    cmp    eax, 0
+    jg     s_mpv_mul_d_add_sse2
+s_mpv_mul_d_add_x86:
+    push   ebp
+    mov    ebp,esp
+    sub    esp,28
+    push   edi
+    push   esi
+    push   ebx
+    mov    ebx,0		; carry = 0
+    mov    ecx,[ebp+12]		; ecx = a_len
+    mov    edi,[ebp+20]
+    cmp    ecx,0
+    je     L_11			; jmp if a_len == 0
+    mov    esi,[ebp+8]		; esi = a
+    cld
+L_10:
+    lodsd			; eax = [ds:esi]; esi += 4
+    mov    edx,[ebp+16]		; edx = b
+    mul    edx			; edx:eax = Phi:Plo = a_i * b
+
+    add    eax,ebx		; add carry (ebx) to edx:eax
+    adc    edx,0
+    mov    ebx,[edi]		; add in current word from *c
+    add    eax,ebx		
+    adc    edx,0
+    mov    ebx,edx		; high half of product becomes next carry
+
+    stosd			; [es:edi] = ax; edi += 4;
+    dec    ecx			; --a_len
+    jnz    L_10			; jmp if a_len != 0
+L_11:
+    mov    [edi],ebx		; *c = carry
+    pop    ebx
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+s_mpv_mul_d_add_sse2:
+    push   ebp
+    mov    ebp, esp
+    push   edi
+    push   esi
+    psubq  mm2, mm2		; carry = 0
+    mov    ecx, [ebp+12]	; ecx = a_len
+    movd   mm1, [ebp+16]	; mm1 = b
+    mov    edi, [ebp+20]
+    cmp    ecx, 0
+    je     L_16			; jmp if a_len == 0
+    mov    esi, [ebp+8]		; esi = a
+    cld
+L_15:
+    movd   mm0, [esi]		; mm0 = *a++
+    add    esi, 4
+    pmuludq mm0, mm1		; mm0 = b * *a++
+    paddq  mm2, mm0		; add the carry
+    movd   mm0, [edi]
+    paddq  mm2, mm0		; add the carry
+    movd   [edi], mm2		; store the 32bit result
+    add    edi, 4
+    psrlq  mm2, 32		; save the carry
+    dec    ecx			; --a_len
+    jnz    L_15			; jmp if a_len != 0
+L_16:
+    movd   [edi], mm2		; *c = carry
+    emms
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+  }
+}
+
+/*
+ *   ebp - 36:	caller's esi
+ *   ebp - 32:	caller's edi
+ *   ebp - 28:	
+ *   ebp - 24:	
+ *   ebp - 20:	
+ *   ebp - 16:	
+ *   ebp - 12:	
+ *   ebp - 8:	
+ *   ebp - 4:	
+ *   ebp + 0:	caller's ebp
+ *   ebp + 4:	return address
+ *   ebp + 8:	a	argument
+ *   ebp + 12:	a_len	argument
+ *   ebp + 16:	b	argument
+ *   ebp + 20:	c	argument
+ *   registers:
+ *  	eax:
+ * 	ebx:	carry
+ * 	ecx:	a_len
+ * 	edx:
+ * 	esi:	a ptr
+ * 	edi:	c ptr
+ */
+__declspec(naked) void
+s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
+{
+  __asm {
+    mov    eax, is_sse
+    cmp    eax, 0
+    je     s_mpv_mul_d_add_prop_x86
+    jg     s_mpv_mul_d_add_prop_sse2
+    call   s_mpi_is_sse2
+    mov    is_sse, eax
+    cmp    eax, 0
+    jg     s_mpv_mul_d_add_prop_sse2
+s_mpv_mul_d_add_prop_x86:
+    push   ebp
+    mov    ebp,esp
+    sub    esp,28
+    push   edi
+    push   esi
+    push   ebx
+    mov    ebx,0		; carry = 0
+    mov    ecx,[ebp+12]		; ecx = a_len
+    mov    edi,[ebp+20]
+    cmp    ecx,0
+    je     L_21			; jmp if a_len == 0
+    cld
+    mov    esi,[ebp+8]		; esi = a
+L_20:
+    lodsd			; eax = [ds:esi]; esi += 4
+    mov    edx,[ebp+16]		; edx = b
+    mul    edx			; edx:eax = Phi:Plo = a_i * b
+
+    add    eax,ebx		; add carry (ebx) to edx:eax
+    adc    edx,0
+    mov    ebx,[edi]		; add in current word from *c
+    add    eax,ebx		
+    adc    edx,0
+    mov    ebx,edx		; high half of product becomes next carry
+
+    stosd			; [es:edi] = ax; edi += 4;
+    dec    ecx			; --a_len
+    jnz    L_20			; jmp if a_len != 0
+L_21:
+    cmp    ebx,0		; is carry zero?
+    jz     L_23
+    mov    eax,[edi]		; add in current word from *c
+    add    eax,ebx
+    stosd			; [es:edi] = ax; edi += 4;
+    jnc    L_23
+L_22:
+    mov    eax,[edi]		; add in current word from *c
+    adc    eax,0
+    stosd			; [es:edi] = ax; edi += 4;
+    jc     L_22
+L_23:
+    pop    ebx
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+s_mpv_mul_d_add_prop_sse2:
+    push   ebp
+    mov    ebp, esp
+    push   edi
+    push   esi
+    push   ebx
+    psubq  mm2, mm2		; carry = 0
+    mov    ecx, [ebp+12]	; ecx = a_len
+    movd   mm1, [ebp+16]	; mm1 = b
+    mov    edi, [ebp+20]
+    cmp    ecx, 0
+    je     L_26			; jmp if a_len == 0
+    mov    esi, [ebp+8]		; esi = a
+    cld
+L_25:
+    movd   mm0, [esi]		; mm0 = *a++
+    movd   mm3, [edi]		; fetch the sum
+    add    esi, 4
+    pmuludq mm0, mm1		; mm0 = b * *a++
+    paddq  mm2, mm0		; add the carry
+    paddq  mm2, mm3		; add *c++
+    movd   [edi], mm2		; store the 32bit result
+    add    edi, 4
+    psrlq  mm2, 32		; save the carry
+    dec    ecx			; --a_len
+    jnz    L_25			; jmp if a_len != 0
+L_26:
+    movd   ebx, mm2
+    cmp    ebx, 0		; is carry zero?
+    jz     L_28
+    mov    eax, [edi]
+    add    eax, ebx
+    stosd
+    jnc    L_28
+L_27:
+    mov    eax, [edi]		; add in current word from *c
+    adc	   eax, 0
+    stosd			; [es:edi] = ax; edi += 4;
+    jc     L_27
+L_28:
+    emms
+    pop    ebx
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+  }
+}
+
+/*
+ *   ebp - 20:	caller's esi
+ *   ebp - 16:	caller's edi
+ *   ebp - 12:	
+ *   ebp - 8:	carry
+ *   ebp - 4:	a_len	local
+ *   ebp + 0:	caller's ebp
+ *   ebp + 4:	return address
+ *   ebp + 8:	pa	argument
+ *   ebp + 12:	a_len	argument
+ *   ebp + 16:	ps	argument
+ *   ebp + 20:	
+ *   registers:
+ *  	eax:
+ * 	ebx:	carry
+ * 	ecx:	a_len
+ * 	edx:
+ * 	esi:	a ptr
+ * 	edi:	c ptr
+ */
+__declspec(naked) void
+s_mpv_sqr_add_prop(const mp_digit *a, mp_size a_len, mp_digit *sqrs)
+{
+  __asm {
+     mov    eax, is_sse
+     cmp    eax, 0
+     je     s_mpv_sqr_add_prop_x86
+     jg     s_mpv_sqr_add_prop_sse2
+     call   s_mpi_is_sse2
+     mov    is_sse, eax
+     cmp    eax, 0
+     jg     s_mpv_sqr_add_prop_sse2
+s_mpv_sqr_add_prop_x86:
+     push   ebp
+     mov    ebp,esp
+     sub    esp,12
+     push   edi
+     push   esi
+     push   ebx
+     mov    ebx,0		; carry = 0
+     mov    ecx,[ebp+12]	; a_len
+     mov    edi,[ebp+16]	; edi = ps
+     cmp    ecx,0
+     je     L_31		; jump if a_len == 0
+     cld
+     mov    esi,[ebp+8]		; esi = pa
+L_30:
+     lodsd			; eax = [ds:si]; si += 4;
+     mul    eax
+
+     add    eax,ebx		; add "carry"
+     adc    edx,0
+     mov    ebx,[edi]
+     add    eax,ebx		; add low word from result
+     mov    ebx,[edi+4]
+     stosd			; [es:di] = eax; di += 4;
+     adc    edx,ebx		; add high word from result
+     mov    ebx,0
+     mov    eax,edx
+     adc    ebx,0
+     stosd			; [es:di] = eax; di += 4;
+     dec    ecx			; --a_len
+     jnz    L_30		; jmp if a_len != 0
+L_31:
+    cmp    ebx,0		; is carry zero?
+    jz     L_34
+    mov    eax,[edi]		; add in current word from *c
+    add    eax,ebx
+    stosd			; [es:edi] = ax; edi += 4;
+    jnc    L_34
+L_32:
+    mov    eax,[edi]		; add in current word from *c
+    adc    eax,0
+    stosd			; [es:edi] = ax; edi += 4;
+    jc     L_32
+L_34:
+    pop    ebx
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+s_mpv_sqr_add_prop_sse2:
+    push   ebp
+    mov    ebp, esp
+    push   edi
+    push   esi
+    push   ebx
+    psubq  mm2, mm2		; carry = 0
+    mov    ecx, [ebp+12]	; ecx = a_len
+    mov    edi, [ebp+16]
+    cmp    ecx, 0
+    je     L_36		; jmp if a_len == 0
+    mov    esi, [ebp+8]		; esi = a
+    cld
+L_35:
+    movd   mm0, [esi]		; mm0 = *a
+    movd   mm3, [edi]		; fetch the sum
+    add	   esi, 4
+    pmuludq mm0, mm0		; mm0 = sqr(a)
+    paddq  mm2, mm0		; add the carry
+    paddq  mm2, mm3		; add the low word
+    movd   mm3, [edi+4]
+    movd   [edi], mm2		; store the 32bit result
+    psrlq  mm2, 32	
+    paddq  mm2, mm3		; add the high word
+    movd   [edi+4], mm2		; store the 32bit result
+    psrlq  mm2, 32		; save the carry.
+    add    edi, 8
+    dec    ecx			; --a_len
+    jnz    L_35			; jmp if a_len != 0
+L_36:
+    movd   ebx, mm2
+    cmp    ebx, 0		; is carry zero?
+    jz     L_38
+    mov    eax, [edi]
+    add    eax, ebx
+    stosd
+    jnc    L_38
+L_37:
+    mov    eax, [edi]		; add in current word from *c
+    adc	   eax, 0
+    stosd			; [es:edi] = ax; edi += 4;
+    jc     L_37
+L_38:
+    emms
+    pop    ebx
+    pop    esi
+    pop    edi
+    leave  
+    ret    
+    nop
+  }
+}
+
+/* 
+ *  Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized
+ *  so its high bit is 1.   This code is from NSPR.
+ *
+ *  Dump of assembler code for function s_mpv_div_2dx1d:
+ *  
+ *   esp +  0:   Caller's ebx
+ *   esp +  4:	return address
+ *   esp +  8:	Nhi	argument
+ *   esp + 12:	Nlo	argument
+ *   esp + 16:	divisor	argument
+ *   esp + 20:	qp	argument
+ *   esp + 24:   rp	argument
+ *   registers:
+ *  	eax:
+ * 	ebx:	carry
+ * 	ecx:	a_len
+ * 	edx:
+ * 	esi:	a ptr
+ * 	edi:	c ptr
+ */  
+__declspec(naked) mp_err
+s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor,
+		mp_digit *qp, mp_digit *rp)
+{
+  __asm {
+       push   ebx
+       mov    edx,[esp+8]
+       mov    eax,[esp+12]
+       mov    ebx,[esp+16]
+       div    ebx
+       mov    ebx,[esp+20]
+       mov    [ebx],eax
+       mov    ebx,[esp+24]
+       mov    [ebx],edx
+       xor    eax,eax		; return zero
+       pop    ebx
+       ret    
+       nop
+  }
+}
diff --git a/mozilla/security/nss/lib/freebl/mpi/mplogic.c b/mozilla/security/nss/lib/freebl/mpi/mplogic.c
new file mode 100644
index 0000000..71701a1
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mplogic.c
@@ -0,0 +1,465 @@
+/*
+ *  mplogic.c
+ *
+ *  Bitwise logical operations on MPI values
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * 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 ***** */
+/* $Id: mplogic.c,v 1.15 2004/04/27 23:04:36 gerv%gerv.net Exp $ */
+
+#include "mpi-priv.h"
+#include "mplogic.h"
+
+/* {{{ Lookup table for population count */
+
+static unsigned char bitc[] = {
+   0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
+   4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/*
+  mpl_not(a, b)    - compute b = ~a
+  mpl_and(a, b, c) - compute c = a & b
+  mpl_or(a, b, c)  - compute c = a | b
+  mpl_xor(a, b, c) - compute c = a ^ b
+ */
+
+/* {{{ mpl_not(a, b) */
+
+mp_err mpl_not(mp_int *a, mp_int *b)
+{
+  mp_err   res;
+  unsigned int      ix;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  /* This relies on the fact that the digit type is unsigned */
+  for(ix = 0; ix < USED(b); ix++) 
+    DIGIT(b, ix) = ~DIGIT(b, ix);
+
+  s_mp_clamp(b);
+
+  return MP_OKAY;
+
+} /* end mpl_not() */
+
+/* }}} */
+
+/* {{{ mpl_and(a, b, c) */
+
+mp_err mpl_and(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_int  *which, *other;
+  mp_err   res;
+  unsigned int      ix;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(USED(a) <= USED(b)) {
+    which = a;
+    other = b;
+  } else {
+    which = b;
+    other = a;
+  }
+
+  if((res = mp_copy(which, c)) != MP_OKAY)
+    return res;
+
+  for(ix = 0; ix < USED(which); ix++)
+    DIGIT(c, ix) &= DIGIT(other, ix);
+
+  s_mp_clamp(c);
+
+  return MP_OKAY;
+
+} /* end mpl_and() */
+
+/* }}} */
+
+/* {{{ mpl_or(a, b, c) */
+
+mp_err mpl_or(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_int  *which, *other;
+  mp_err   res;
+  unsigned int      ix;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(USED(a) >= USED(b)) {
+    which = a;
+    other = b;
+  } else {
+    which = b;
+    other = a;
+  }
+
+  if((res = mp_copy(which, c)) != MP_OKAY)
+    return res;
+
+  for(ix = 0; ix < USED(which); ix++)
+    DIGIT(c, ix) |= DIGIT(other, ix);
+
+  return MP_OKAY;
+
+} /* end mpl_or() */
+
+/* }}} */
+
+/* {{{ mpl_xor(a, b, c) */
+
+mp_err mpl_xor(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_int  *which, *other;
+  mp_err   res;
+  unsigned int      ix;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(USED(a) >= USED(b)) {
+    which = a;
+    other = b;
+  } else {
+    which = b;
+    other = a;
+  }
+
+  if((res = mp_copy(which, c)) != MP_OKAY)
+    return res;
+
+  for(ix = 0; ix < USED(which); ix++)
+    DIGIT(c, ix) ^= DIGIT(other, ix);
+
+  s_mp_clamp(c);
+
+  return MP_OKAY;
+
+} /* end mpl_xor() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/*
+  mpl_rsh(a, b, d)     - b = a >> d
+  mpl_lsh(a, b, d)     - b = a << d
+ */
+
+/* {{{ mpl_rsh(a, b, d) */
+
+mp_err mpl_rsh(const mp_int *a, mp_int *b, mp_digit d)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  s_mp_div_2d(b, d);
+
+  return MP_OKAY;
+
+} /* end mpl_rsh() */
+
+/* }}} */
+
+/* {{{ mpl_lsh(a, b, d) */
+
+mp_err mpl_lsh(const mp_int *a, mp_int *b, mp_digit d)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  return s_mp_mul_2d(b, d);
+
+} /* end mpl_lsh() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/*
+  mpl_num_set(a, num)
+
+  Count the number of set bits in the binary representation of a.
+  Returns MP_OKAY and sets 'num' to be the number of such bits, if
+  possible.  If num is NULL, the result is thrown away, but it is
+  not considered an error.
+
+  mpl_num_clear() does basically the same thing for clear bits.
+ */
+
+/* {{{ mpl_num_set(a, num) */
+
+mp_err mpl_num_set(mp_int *a, int *num)
+{
+  unsigned int   ix;
+  int            db, nset = 0;
+  mp_digit       cur;
+  unsigned char  reg;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  for(ix = 0; ix < USED(a); ix++) {
+    cur = DIGIT(a, ix);
+    
+    for(db = 0; db < sizeof(mp_digit); db++) {
+      reg = (unsigned char)(cur >> (CHAR_BIT * db));
+
+      nset += bitc[reg];
+    }
+  }
+
+  if(num)
+    *num = nset;
+
+  return MP_OKAY;
+
+} /* end mpl_num_set() */
+
+/* }}} */
+
+/* {{{ mpl_num_clear(a, num) */
+
+mp_err mpl_num_clear(mp_int *a, int *num)
+{
+  unsigned int   ix;
+  int            db, nset = 0;
+  mp_digit       cur;
+  unsigned char  reg;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  for(ix = 0; ix < USED(a); ix++) {
+    cur = DIGIT(a, ix);
+    
+    for(db = 0; db < sizeof(mp_digit); db++) {
+      reg = (unsigned char)(cur >> (CHAR_BIT * db));
+
+      nset += bitc[UCHAR_MAX - reg];
+    }
+  }
+
+  if(num)
+    *num = nset;
+
+  return MP_OKAY;
+
+
+} /* end mpl_num_clear() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/*
+  mpl_parity(a)
+
+  Determines the bitwise parity of the value given.  Returns MP_EVEN
+  if an even number of digits are set, MP_ODD if an odd number are
+  set.
+ */
+
+/* {{{ mpl_parity(a) */
+
+mp_err mpl_parity(mp_int *a)
+{
+  unsigned int ix;
+  int      par = 0;
+  mp_digit cur;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  for(ix = 0; ix < USED(a); ix++) {
+    int   shft = (sizeof(mp_digit) * CHAR_BIT) / 2;
+
+    cur = DIGIT(a, ix);
+
+    /* Compute parity for current digit */
+    while(shft != 0) {
+      cur ^= (cur >> shft);
+      shft >>= 1;
+    }
+    cur &= 1;
+
+    /* XOR with running parity so far   */
+    par ^= cur;
+  }
+
+  if(par)
+    return MP_ODD;
+  else
+    return MP_EVEN;
+
+} /* end mpl_parity() */
+
+/* }}} */
+
+/*
+  mpl_set_bit
+
+  Returns MP_OKAY or some error code.
+  Grows a if needed to set a bit to 1.
+ */
+mp_err mpl_set_bit(mp_int *a, mp_size bitNum, mp_size value)
+{
+  mp_size      ix;
+  mp_err       rv;
+  mp_digit     mask;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  ix = bitNum / MP_DIGIT_BIT;
+  if (ix + 1 > MP_USED(a)) {
+    rv = s_mp_pad(a, ix + 1);
+    if (rv != MP_OKAY)
+      return rv;
+  }
+
+  bitNum = bitNum % MP_DIGIT_BIT;
+  mask = (mp_digit)1 << bitNum;
+  if (value)
+    MP_DIGIT(a,ix) |= mask;
+  else
+    MP_DIGIT(a,ix) &= ~mask;
+  s_mp_clamp(a);
+  return MP_OKAY;
+}
+
+/*
+  mpl_get_bit
+
+  returns 0 or 1 or some (negative) error code.
+ */
+mp_err mpl_get_bit(const mp_int *a, mp_size bitNum)
+{
+  mp_size      bit, ix;
+  mp_err       rv;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  ix = bitNum / MP_DIGIT_BIT;
+  ARGCHK(ix <= MP_USED(a) - 1, MP_RANGE);
+
+  bit   = bitNum % MP_DIGIT_BIT;
+  rv = (mp_err)(MP_DIGIT(a, ix) >> bit) & 1;
+  return rv;
+}
+
+/*
+  mpl_get_bits
+  - Extracts numBits bits from a, where the least significant extracted bit
+  is bit lsbNum.  Returns a negative value if error occurs.
+  - Because sign bit is used to indicate error, maximum number of bits to 
+  be returned is the lesser of (a) the number of bits in an mp_digit, or
+  (b) one less than the number of bits in an mp_err.
+  - lsbNum + numbits can be greater than the number of significant bits in
+  integer a, as long as bit lsbNum is in the high order digit of a.
+ */
+mp_err mpl_get_bits(const mp_int *a, mp_size lsbNum, mp_size numBits) 
+{
+  mp_size    rshift = (lsbNum % MP_DIGIT_BIT);
+  mp_size    lsWndx = (lsbNum / MP_DIGIT_BIT);
+  mp_digit * digit  = MP_DIGITS(a) + lsWndx;
+  mp_digit   mask   = ((1 << numBits) - 1);
+
+  ARGCHK(numBits < CHAR_BIT * sizeof mask, MP_BADARG);
+  ARGCHK(MP_HOWMANY(lsbNum, MP_DIGIT_BIT) <= MP_USED(a), MP_RANGE);
+
+  if ((numBits + lsbNum % MP_DIGIT_BIT <= MP_DIGIT_BIT) ||
+      (lsWndx + 1 >= MP_USED(a))) {
+    mask &= (digit[0] >> rshift);
+  } else {
+    mask &= ((digit[0] >> rshift) | (digit[1] << (MP_DIGIT_BIT - rshift)));
+  }
+  return (mp_err)mask;
+}
+
+/*
+  mpl_significant_bits
+  returns number of significnant bits in abs(a).
+  returns 1 if value is zero.
+ */
+mp_err mpl_significant_bits(const mp_int *a)
+{
+  mp_err bits 	= 0;
+  int    ix;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  ix = MP_USED(a);
+  for (ix = MP_USED(a); ix > 0; ) {
+    mp_digit d;
+    d = MP_DIGIT(a, --ix);
+    if (d) {
+      while (d) {
+	++bits;
+	d >>= 1;
+      }
+      break;
+    }
+  }
+  bits += ix * MP_DIGIT_BIT;
+  if (!bits)
+    bits = 1;
+  return bits;
+}
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS                                                  */
diff --git a/mozilla/security/nss/lib/freebl/mpi/mplogic.h b/mozilla/security/nss/lib/freebl/mpi/mplogic.h
new file mode 100644
index 0000000..de831dc
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mplogic.h
@@ -0,0 +1,85 @@
+/*
+ *  mplogic.h
+ *
+ *  Bitwise logical operations on MPI values
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * 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 ***** */
+/* $Id: mplogic.h,v 1.7 2004/04/27 23:04:36 gerv%gerv.net Exp $ */
+
+#ifndef _H_MPLOGIC_
+#define _H_MPLOGIC_
+
+#include "mpi.h"
+
+/*
+  The logical operations treat an mp_int as if it were a bit vector,
+  without regard to its sign (an mp_int is represented in a signed
+  magnitude format).  Values are treated as if they had an infinite
+  string of zeros left of the most-significant bit.
+ */
+
+/* Parity results                    */
+
+#define MP_EVEN       MP_YES
+#define MP_ODD        MP_NO
+
+/* Bitwise functions                 */
+
+mp_err mpl_not(mp_int *a, mp_int *b);            /* one's complement  */
+mp_err mpl_and(mp_int *a, mp_int *b, mp_int *c); /* bitwise AND       */
+mp_err mpl_or(mp_int *a, mp_int *b, mp_int *c);  /* bitwise OR        */
+mp_err mpl_xor(mp_int *a, mp_int *b, mp_int *c); /* bitwise XOR       */
+
+/* Shift functions                   */
+
+mp_err mpl_rsh(const mp_int *a, mp_int *b, mp_digit d);   /* right shift    */
+mp_err mpl_lsh(const mp_int *a, mp_int *b, mp_digit d);   /* left shift     */
+
+/* Bit count and parity              */
+
+mp_err mpl_num_set(mp_int *a, int *num);         /* count set bits    */
+mp_err mpl_num_clear(mp_int *a, int *num);       /* count clear bits  */
+mp_err mpl_parity(mp_int *a);                    /* determine parity  */
+
+/* Get & Set the value of a bit */
+
+mp_err mpl_set_bit(mp_int *a, mp_size bitNum, mp_size value);
+mp_err mpl_get_bit(const mp_int *a, mp_size bitNum);
+mp_err mpl_get_bits(const mp_int *a, mp_size lsbNum, mp_size numBits);
+mp_err mpl_significant_bits(const mp_int *a);
+
+#endif /* end _H_MPLOGIC_ */
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpmontg.c b/mozilla/security/nss/lib/freebl/mpi/mpmontg.c
new file mode 100644
index 0000000..3dea5e7
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpmontg.c
@@ -0,0 +1,1209 @@
+/* ***** 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) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sheueling Chang Shantz <sheueling.chang@sun.com>,
+ *   Stephen Fung <stephen.fung@sun.com>, and
+ *   Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ * 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 ***** */
+/* $Id: mpmontg.c,v 1.20 2006/08/29 02:41:38 nelson%bolyard.com Exp $ */
+
+/* This file implements moduluar exponentiation using Montgomery's
+ * method for modular reduction.  This file implements the method
+ * described as "Improvement 1" in the paper "A Cryptogrpahic Library for
+ * the Motorola DSP56000" by Stephen R. Dusse' and Burton S. Kaliski Jr.
+ * published in "Advances in Cryptology: Proceedings of EUROCRYPT '90"
+ * "Lecture Notes in Computer Science" volume 473, 1991, pg 230-244,
+ * published by Springer Verlag.
+ */
+
+#define MP_USING_CACHE_SAFE_MOD_EXP 1 
+#include <string.h>
+#include "mpi-priv.h"
+#include "mplogic.h"
+#include "mpprime.h"
+#ifdef MP_USING_MONT_MULF
+#include "montmulf.h"
+#endif
+#include <stddef.h> /* ptrdiff_t */
+
+/* if MP_CHAR_STORE_SLOW is defined, we  */
+/* need to know endianness of this platform. */
+#ifdef MP_CHAR_STORE_SLOW
+#if !defined(MP_IS_BIG_ENDIAN) && !defined(MP_IS_LITTLE_ENDIAN)
+#error "You must define MP_IS_BIG_ENDIAN or MP_IS_LITTLE_ENDIAN\n" \
+       "  if you define MP_CHAR_STORE_SLOW."
+#endif
+#endif
+
+#define STATIC
+
+#define MAX_ODD_INTS    32   /* 2 ** (WINDOW_BITS - 1) */
+
+#if defined(_WIN32_WCE)
+#define ABORT  res = MP_UNDEF; goto CLEANUP
+#else
+#define ABORT abort()
+#endif
+
+/* computes T = REDC(T), 2^b == R */
+mp_err s_mp_redc(mp_int *T, mp_mont_modulus *mmm)
+{
+  mp_err res;
+  mp_size i;
+
+  i = MP_USED(T) + MP_USED(&mmm->N) + 2;
+  MP_CHECKOK( s_mp_pad(T, i) );
+  for (i = 0; i < MP_USED(&mmm->N); ++i ) {
+    mp_digit m_i = MP_DIGIT(T, i) * mmm->n0prime;
+    /* T += N * m_i * (MP_RADIX ** i); */
+    MP_CHECKOK( s_mp_mul_d_add_offset(&mmm->N, m_i, T, i) );
+  }
+  s_mp_clamp(T);
+
+  /* T /= R */
+  s_mp_div_2d(T, mmm->b); 
+
+  if ((res = s_mp_cmp(T, &mmm->N)) >= 0) {
+    /* T = T - N */
+    MP_CHECKOK( s_mp_sub(T, &mmm->N) );
+#ifdef DEBUG
+    if ((res = mp_cmp(T, &mmm->N)) >= 0) {
+      res = MP_UNDEF;
+      goto CLEANUP;
+    }
+#endif
+  }
+  res = MP_OKAY;
+CLEANUP:
+  return res;
+}
+
+#if !defined(MP_ASSEMBLY_MUL_MONT) && !defined(MP_MONT_USE_MP_MUL)
+mp_err s_mp_mul_mont(const mp_int *a, const mp_int *b, mp_int *c, 
+	           mp_mont_modulus *mmm)
+{
+  mp_digit *pb;
+  mp_digit m_i;
+  mp_err   res;
+  mp_size  ib;
+  mp_size  useda, usedb;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if (MP_USED(a) < MP_USED(b)) {
+    const mp_int *xch = b;	/* switch a and b, to do fewer outer loops */
+    b = a;
+    a = xch;
+  }
+
+  MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
+  ib = MP_USED(a) + MP_MAX(MP_USED(b), MP_USED(&mmm->N)) + 2;
+  if((res = s_mp_pad(c, ib)) != MP_OKAY)
+    goto CLEANUP;
+
+  useda = MP_USED(a);
+  pb = MP_DIGITS(b);
+  s_mpv_mul_d(MP_DIGITS(a), useda, *pb++, MP_DIGITS(c));
+  s_mp_setz(MP_DIGITS(c) + useda + 1, ib - (useda + 1));
+  m_i = MP_DIGIT(c, 0) * mmm->n0prime;
+  s_mp_mul_d_add_offset(&mmm->N, m_i, c, 0);
+
+  /* Outer loop:  Digits of b */
+  usedb = MP_USED(b);
+  for (ib = 1; ib < usedb; ib++) {
+    mp_digit b_i    = *pb++;
+
+    /* Inner product:  Digits of a */
+    if (b_i)
+      s_mpv_mul_d_add_prop(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
+    m_i = MP_DIGIT(c, ib) * mmm->n0prime;
+    s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib);
+  }
+  if (usedb < MP_USED(&mmm->N)) {
+    for (usedb = MP_USED(&mmm->N); ib < usedb; ++ib ) {
+      m_i = MP_DIGIT(c, ib) * mmm->n0prime;
+      s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib);
+    }
+  }
+  s_mp_clamp(c);
+  s_mp_div_2d(c, mmm->b); 
+  if (s_mp_cmp(c, &mmm->N) >= 0) {
+    MP_CHECKOK( s_mp_sub(c, &mmm->N) );
+  }
+  res = MP_OKAY;
+
+CLEANUP:
+  return res;
+}
+#endif
+
+STATIC
+mp_err s_mp_to_mont(const mp_int *x, mp_mont_modulus *mmm, mp_int *xMont)
+{
+  mp_err res;
+
+  /* xMont = x * R mod N   where  N is modulus */
+  MP_CHECKOK( mpl_lsh(x, xMont, mmm->b) );  		/* xMont = x << b */
+  MP_CHECKOK( mp_div(xMont, &mmm->N, 0, xMont) );	/*         mod N */
+CLEANUP:
+  return res;
+}
+
+#ifdef MP_USING_MONT_MULF
+
+/* the floating point multiply is already cache safe,
+ * don't turn on cache safe unless we specifically
+ * force it */
+#ifndef MP_FORCE_CACHE_SAFE
+#undef MP_USING_CACHE_SAFE_MOD_EXP
+#endif
+
+unsigned int mp_using_mont_mulf = 1;
+
+/* computes montgomery square of the integer in mResult */
+#define SQR \
+  conv_i32_to_d32_and_d16(dm1, d16Tmp, mResult, nLen); \
+  mont_mulf_noconv(mResult, dm1, d16Tmp, \
+		   dTmp, dn, MP_DIGITS(modulus), nLen, dn0)
+
+/* computes montgomery product of x and the integer in mResult */
+#define MUL(x) \
+  conv_i32_to_d32(dm1, mResult, nLen); \
+  mont_mulf_noconv(mResult, dm1, oddPowers[x], \
+		   dTmp, dn, MP_DIGITS(modulus), nLen, dn0)
+
+/* Do modular exponentiation using floating point multiply code. */
+mp_err mp_exptmod_f(const mp_int *   montBase, 
+                    const mp_int *   exponent, 
+		    const mp_int *   modulus, 
+		    mp_int *         result, 
+		    mp_mont_modulus *mmm, 
+		    int              nLen, 
+		    mp_size          bits_in_exponent, 
+		    mp_size          window_bits,
+		    mp_size          odd_ints)
+{
+  mp_digit *mResult;
+  double   *dBuf = 0, *dm1, *dn, *dSqr, *d16Tmp, *dTmp;
+  double    dn0;
+  mp_size   i;
+  mp_err    res;
+  int       expOff;
+  int       dSize = 0, oddPowSize, dTmpSize;
+  mp_int    accum1;
+  double   *oddPowers[MAX_ODD_INTS];
+
+  /* function for computing n0prime only works if n0 is odd */
+
+  MP_DIGITS(&accum1) = 0;
+
+  for (i = 0; i < MAX_ODD_INTS; ++i)
+    oddPowers[i] = 0;
+
+  MP_CHECKOK( mp_init_size(&accum1, 3 * nLen + 2) );
+
+  mp_set(&accum1, 1);
+  MP_CHECKOK( s_mp_to_mont(&accum1, mmm, &accum1) );
+  MP_CHECKOK( s_mp_pad(&accum1, nLen) );
+
+  oddPowSize = 2 * nLen + 1;
+  dTmpSize   = 2 * oddPowSize;
+  dSize = sizeof(double) * (nLen * 4 + 1 + 
+			    ((odd_ints + 1) * oddPowSize) + dTmpSize);
+  dBuf   = (double *)malloc(dSize);
+  dm1    = dBuf;		/* array of d32 */
+  dn     = dBuf   + nLen;	/* array of d32 */
+  dSqr   = dn     + nLen;    	/* array of d32 */
+  d16Tmp = dSqr   + nLen;	/* array of d16 */
+  dTmp   = d16Tmp + oddPowSize;
+
+  for (i = 0; i < odd_ints; ++i) {
+      oddPowers[i] = dTmp;
+      dTmp += oddPowSize;
+  }
+  mResult = (mp_digit *)(dTmp + dTmpSize);	/* size is nLen + 1 */
+
+  /* Make dn and dn0 */
+  conv_i32_to_d32(dn, MP_DIGITS(modulus), nLen);
+  dn0 = (double)(mmm->n0prime & 0xffff);
+
+  /* Make dSqr */
+  conv_i32_to_d32_and_d16(dm1, oddPowers[0], MP_DIGITS(montBase), nLen);
+  mont_mulf_noconv(mResult, dm1, oddPowers[0], 
+		   dTmp, dn, MP_DIGITS(modulus), nLen, dn0);
+  conv_i32_to_d32(dSqr, mResult, nLen);
+
+  for (i = 1; i < odd_ints; ++i) {
+    mont_mulf_noconv(mResult, dSqr, oddPowers[i - 1], 
+		     dTmp, dn, MP_DIGITS(modulus), nLen, dn0);
+    conv_i32_to_d16(oddPowers[i], mResult, nLen);
+  }
+
+  s_mp_copy(MP_DIGITS(&accum1), mResult, nLen); /* from, to, len */
+
+  for (expOff = bits_in_exponent - window_bits; expOff >= 0; expOff -= window_bits) {
+    mp_size smallExp;
+    MP_CHECKOK( mpl_get_bits(exponent, expOff, window_bits) );
+    smallExp = (mp_size)res;
+
+    if (window_bits == 1) {
+      if (!smallExp) {
+	SQR;
+      } else if (smallExp & 1) {
+	SQR; MUL(0); 
+      } else {
+	ABORT;
+      }
+    } else if (window_bits == 4) {
+      if (!smallExp) {
+	SQR; SQR; SQR; SQR;
+      } else if (smallExp & 1) {
+	SQR; SQR; SQR; SQR; MUL(smallExp/2); 
+      } else if (smallExp & 2) {
+	SQR; SQR; SQR; MUL(smallExp/4); SQR; 
+      } else if (smallExp & 4) {
+	SQR; SQR; MUL(smallExp/8); SQR; SQR; 
+      } else if (smallExp & 8) {
+	SQR; MUL(smallExp/16); SQR; SQR; SQR; 
+      } else {
+	ABORT;
+      }
+    } else if (window_bits == 5) {
+      if (!smallExp) {
+	SQR; SQR; SQR; SQR; SQR; 
+      } else if (smallExp & 1) {
+	SQR; SQR; SQR; SQR; SQR; MUL(smallExp/2);
+      } else if (smallExp & 2) {
+	SQR; SQR; SQR; SQR; MUL(smallExp/4); SQR;
+      } else if (smallExp & 4) {
+	SQR; SQR; SQR; MUL(smallExp/8); SQR; SQR;
+      } else if (smallExp & 8) {
+	SQR; SQR; MUL(smallExp/16); SQR; SQR; SQR;
+      } else if (smallExp & 0x10) {
+	SQR; MUL(smallExp/32); SQR; SQR; SQR; SQR;
+      } else {
+	ABORT;
+      }
+    } else if (window_bits == 6) {
+      if (!smallExp) {
+	SQR; SQR; SQR; SQR; SQR; SQR;
+      } else if (smallExp & 1) {
+	SQR; SQR; SQR; SQR; SQR; SQR; MUL(smallExp/2); 
+      } else if (smallExp & 2) {
+	SQR; SQR; SQR; SQR; SQR; MUL(smallExp/4); SQR; 
+      } else if (smallExp & 4) {
+	SQR; SQR; SQR; SQR; MUL(smallExp/8); SQR; SQR; 
+      } else if (smallExp & 8) {
+	SQR; SQR; SQR; MUL(smallExp/16); SQR; SQR; SQR; 
+      } else if (smallExp & 0x10) {
+	SQR; SQR; MUL(smallExp/32); SQR; SQR; SQR; SQR; 
+      } else if (smallExp & 0x20) {
+	SQR; MUL(smallExp/64); SQR; SQR; SQR; SQR; SQR; 
+      } else {
+	ABORT;
+      }
+    } else {
+      ABORT;
+    }
+  }
+
+  s_mp_copy(mResult, MP_DIGITS(&accum1), nLen); /* from, to, len */
+
+  res = s_mp_redc(&accum1, mmm);
+  mp_exch(&accum1, result);
+
+CLEANUP:
+  mp_clear(&accum1);
+  if (dBuf) {
+    if (dSize)
+      memset(dBuf, 0, dSize);
+    free(dBuf);
+  }
+
+  return res;
+}
+#undef SQR
+#undef MUL
+#endif
+
+#define SQR(a,b) \
+  MP_CHECKOK( mp_sqr(a, b) );\
+  MP_CHECKOK( s_mp_redc(b, mmm) )
+
+#if defined(MP_MONT_USE_MP_MUL)
+#define MUL(x,a,b) \
+  MP_CHECKOK( mp_mul(a, oddPowers + (x), b) ); \
+  MP_CHECKOK( s_mp_redc(b, mmm) ) 
+#else
+#define MUL(x,a,b) \
+  MP_CHECKOK( s_mp_mul_mont(a, oddPowers + (x), b, mmm) )
+#endif
+
+#define SWAPPA ptmp = pa1; pa1 = pa2; pa2 = ptmp
+
+/* Do modular exponentiation using integer multiply code. */
+mp_err mp_exptmod_i(const mp_int *   montBase, 
+                    const mp_int *   exponent, 
+		    const mp_int *   modulus, 
+		    mp_int *         result, 
+		    mp_mont_modulus *mmm, 
+		    int              nLen, 
+		    mp_size          bits_in_exponent, 
+		    mp_size          window_bits,
+		    mp_size          odd_ints)
+{
+  mp_int *pa1, *pa2, *ptmp;
+  mp_size i;
+  mp_err  res;
+  int     expOff;
+  mp_int  accum1, accum2, power2, oddPowers[MAX_ODD_INTS];
+
+  /* power2 = base ** 2; oddPowers[i] = base ** (2*i + 1); */
+  /* oddPowers[i] = base ** (2*i + 1); */
+
+  MP_DIGITS(&accum1) = 0;
+  MP_DIGITS(&accum2) = 0;
+  MP_DIGITS(&power2) = 0;
+  for (i = 0; i < MAX_ODD_INTS; ++i) {
+    MP_DIGITS(oddPowers + i) = 0;
+  }
+
+  MP_CHECKOK( mp_init_size(&accum1, 3 * nLen + 2) );
+  MP_CHECKOK( mp_init_size(&accum2, 3 * nLen + 2) );
+
+  MP_CHECKOK( mp_init_copy(&oddPowers[0], montBase) );
+
+  mp_init_size(&power2, nLen + 2 * MP_USED(montBase) + 2);
+  MP_CHECKOK( mp_sqr(montBase, &power2) );	/* power2 = montBase ** 2 */
+  MP_CHECKOK( s_mp_redc(&power2, mmm) );
+
+  for (i = 1; i < odd_ints; ++i) {
+    mp_init_size(oddPowers + i, nLen + 2 * MP_USED(&power2) + 2);
+    MP_CHECKOK( mp_mul(oddPowers + (i - 1), &power2, oddPowers + i) );
+    MP_CHECKOK( s_mp_redc(oddPowers + i, mmm) );
+  }
+
+  /* set accumulator to montgomery residue of 1 */
+  mp_set(&accum1, 1);
+  MP_CHECKOK( s_mp_to_mont(&accum1, mmm, &accum1) );
+  pa1 = &accum1;
+  pa2 = &accum2;
+
+  for (expOff = bits_in_exponent - window_bits; expOff >= 0; expOff -= window_bits) {
+    mp_size smallExp;
+    MP_CHECKOK( mpl_get_bits(exponent, expOff, window_bits) );
+    smallExp = (mp_size)res;
+
+    if (window_bits == 1) {
+      if (!smallExp) {
+	SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 1) {
+	SQR(pa1,pa2); MUL(0,pa2,pa1);
+      } else {
+	ABORT;
+      }
+    } else if (window_bits == 4) {
+      if (!smallExp) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1);
+      } else if (smallExp & 1) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	MUL(smallExp/2, pa1,pa2); SWAPPA;
+      } else if (smallExp & 2) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); 
+	MUL(smallExp/4,pa2,pa1); SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 4) {
+	SQR(pa1,pa2); SQR(pa2,pa1); MUL(smallExp/8,pa1,pa2); 
+	SQR(pa2,pa1); SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 8) {
+	SQR(pa1,pa2); MUL(smallExp/16,pa2,pa1); SQR(pa1,pa2); 
+	SQR(pa2,pa1); SQR(pa1,pa2); SWAPPA;
+      } else {
+	ABORT;
+      }
+    } else if (window_bits == 5) {
+      if (!smallExp) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 1) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	SQR(pa1,pa2); MUL(smallExp/2,pa2,pa1);
+      } else if (smallExp & 2) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	MUL(smallExp/4,pa1,pa2); SQR(pa2,pa1);
+      } else if (smallExp & 4) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); 
+	MUL(smallExp/8,pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1);
+      } else if (smallExp & 8) {
+	SQR(pa1,pa2); SQR(pa2,pa1); MUL(smallExp/16,pa1,pa2); 
+	SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1);
+      } else if (smallExp & 0x10) {
+	SQR(pa1,pa2); MUL(smallExp/32,pa2,pa1); SQR(pa1,pa2); 
+	SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1);
+      } else {
+	ABORT;
+      }
+    } else if (window_bits == 6) {
+      if (!smallExp) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	SQR(pa1,pa2); SQR(pa2,pa1);
+      } else if (smallExp & 1) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	SQR(pa1,pa2); SQR(pa2,pa1); MUL(smallExp/2,pa1,pa2); SWAPPA;
+      } else if (smallExp & 2) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	SQR(pa1,pa2); MUL(smallExp/4,pa2,pa1); SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 4) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	MUL(smallExp/8,pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 8) {
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); 
+	MUL(smallExp/16,pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 0x10) {
+	SQR(pa1,pa2); SQR(pa2,pa1); MUL(smallExp/32,pa1,pa2); 
+	SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SWAPPA;
+      } else if (smallExp & 0x20) {
+	SQR(pa1,pa2); MUL(smallExp/64,pa2,pa1); SQR(pa1,pa2); 
+	SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SWAPPA;
+      } else {
+	ABORT;
+      }
+    } else {
+      ABORT;
+    }
+  }
+
+  res = s_mp_redc(pa1, mmm);
+  mp_exch(pa1, result);
+
+CLEANUP:
+  mp_clear(&accum1);
+  mp_clear(&accum2);
+  mp_clear(&power2);
+  for (i = 0; i < odd_ints; ++i) {
+    mp_clear(oddPowers + i);
+  }
+  return res;
+}
+#undef SQR
+#undef MUL
+
+#ifdef MP_USING_CACHE_SAFE_MOD_EXP
+unsigned int mp_using_cache_safe_exp = 1;
+#endif
+
+mp_err mp_set_safe_modexp(int value) 
+{
+#ifdef MP_USING_CACHE_SAFE_MOD_EXP
+ mp_using_cache_safe_exp = value;
+ return MP_OKAY;
+#else
+ if (value == 0) {
+   return MP_OKAY;
+ }
+ return MP_BADARG;
+#endif
+}
+
+#ifdef MP_USING_CACHE_SAFE_MOD_EXP
+#define WEAVE_WORD_SIZE 4
+
+#ifndef MP_CHAR_STORE_SLOW
+/*
+ * mpi_to_weave takes an array of bignums, a matrix in which each bignum 
+ * occupies all the columns of a row, and transposes it into a matrix in 
+ * which each bignum occupies a column of every row.  The first row of the
+ * input matrix becomes the first column of the output matrix.  The n'th
+ * row of input becomes the n'th column of output.  The input data is said
+ * to be "interleaved" or "woven" into the output matrix.
+ *
+ * The array of bignums is left in this woven form.  Each time a single
+ * bignum value is needed, it is recreated by fetching the n'th column, 
+ * forming a single row which is the new bignum.
+ *
+ * The purpose of this interleaving is make it impossible to determine which
+ * of the bignums is being used in any one operation by examining the pattern
+ * of cache misses.
+ *
+ * The weaving function does not transpose the entire input matrix in one call.
+ * It transposes 4 rows of mp_ints into their respective columns of output.
+ *
+ * There are two different implementations of the weaving and unweaving code
+ * in this file.  One uses byte loads and stores.  The second uses loads and
+ * stores of mp_weave_word size values.  The weaved forms of these two 
+ * implementations differ.  Consequently, each one has its own explanation.
+ *
+ * Here is the explanation for the byte-at-a-time implementation.
+ *
+ * This implementation treats each mp_int bignum as an array of bytes, 
+ * rather than as an array of mp_digits.  It stores those bytes as a 
+ * column of bytes in the output matrix.  It doesn't care if the machine
+ * uses big-endian or little-endian byte ordering within mp_digits.
+ * The first byte of the mp_digit array becomes the first byte in the output
+ * column, regardless of whether that byte is the MSB or LSB of the mp_digit.
+ *
+ * "bignums" is an array of mp_ints.
+ * It points to four rows, four mp_ints, a subset of a larger array of mp_ints.
+ *
+ * "weaved" is the weaved output matrix. 
+ * The first byte of bignums[0] is stored in weaved[0].
+ * 
+ * "nBignums" is the total number of bignums in the array of which "bignums" 
+ * is a part.  
+ *
+ * "nDigits" is the size in mp_digits of each mp_int in the "bignums" array. 
+ * mp_ints that use less than nDigits digits are logically padded with zeros 
+ * while being stored in the weaved array.
+ */
+mp_err mpi_to_weave(const mp_int  *bignums, 
+                    unsigned char *weaved, 
+		    mp_size nDigits,  /* in each mp_int of input */
+		    mp_size nBignums) /* in the entire source array */
+{
+  mp_size i;
+  unsigned char * endDest = weaved + (nDigits * nBignums * sizeof(mp_digit));
+
+  for (i=0; i < WEAVE_WORD_SIZE; i++) {
+    mp_size used = MP_USED(&bignums[i]);
+    unsigned char *pSrc   = (unsigned char *)MP_DIGITS(&bignums[i]);
+    unsigned char *endSrc = pSrc + (used * sizeof(mp_digit));
+    unsigned char *pDest  = weaved + i;
+
+    ARGCHK(MP_SIGN(&bignums[i]) == MP_ZPOS, MP_BADARG);
+    ARGCHK(used <= nDigits, MP_BADARG);
+
+    for (; pSrc < endSrc; pSrc++) {
+      *pDest = *pSrc;
+      pDest += nBignums;
+    }
+    while (pDest < endDest) {
+      *pDest = 0;
+      pDest += nBignums;
+    }
+  }
+
+  return MP_OKAY;
+}
+
+/* Reverse the operation above for one mp_int.
+ * Reconstruct one mp_int from its column in the weaved array.
+ * "pSrc" points to the offset into the weave array of the bignum we 
+ * are going to reconstruct.
+ */
+mp_err weave_to_mpi(mp_int *a,                /* output, result */
+                    const unsigned char *pSrc, /* input, byte matrix */
+		    mp_size nDigits,          /* per mp_int output */
+		    mp_size nBignums)         /* bignums in weaved matrix */
+{
+  unsigned char *pDest   = (unsigned char *)MP_DIGITS(a);
+  unsigned char *endDest = pDest + (nDigits * sizeof(mp_digit));
+
+  MP_SIGN(a) = MP_ZPOS;
+  MP_USED(a) = nDigits;
+
+  for (; pDest < endDest; pSrc += nBignums, pDest++) {
+    *pDest = *pSrc;
+  }
+  s_mp_clamp(a);
+  return MP_OKAY;
+}
+
+#else
+
+/* Need a primitive that we know is 32 bits long... */
+/* this is true on all modern processors we know of today*/
+typedef unsigned int mp_weave_word;
+
+/*
+ * on some platforms character stores into memory is very expensive since they
+ * generate a read/modify/write operation on the bus. On those platforms
+ * we need to do integer writes to the bus. Because of some unrolled code,
+ * in this current code the size of mp_weave_word must be four. The code that
+ * makes this assumption explicity is called out. (on some platforms a write
+ * of 4 bytes still requires a single read-modify-write operation.
+ *
+ * This function is takes the identical parameters as the function above, 
+ * however it lays out the final array differently. Where the previous function
+ * treats the mpi_int as an byte array, this function treats it as an array of
+ * mp_digits where each digit is stored in big endian order.
+ * 
+ * since we need to interleave on a byte by byte basis, we need to collect 
+ * several mpi structures together into a single uint32 before we write. We
+ * also need to make sure the uint32 is arranged so that the first value of 
+ * the first array winds up in b[0]. This means construction of that uint32
+ * is endian specific (even though the layout of the mp_digits in the array 
+ * is always big endian).
+ *
+ * The final data is stored as follows :
+ *
+ * Our same logical array p array, m is sizeof(mp_digit),
+ * N is still count and n is now b_size. If we define p[i].digit[j]0 as the 
+ * most significant byte of the word p[i].digit[j], p[i].digit[j]1 as 
+ * the next most significant byte of p[i].digit[j], ...  and p[i].digit[j]m-1
+ * is the least significant byte. 
+ * Our array would look like:
+ * p[0].digit[0]0     p[1].digit[0]0    ...  p[N-2].digit[0]0    p[N-1].digit[0]0
+ * p[0].digit[0]1     p[1].digit[0]1    ...  p[N-2].digit[0]1    p[N-1].digit[0]1
+ *                .                                         .
+ * p[0].digit[0]m-1   p[1].digit[0]m-1  ...  p[N-2].digit[0]m-1  p[N-1].digit[0]m-1
+ * p[0].digit[1]0     p[1].digit[1]0    ...  p[N-2].digit[1]0    p[N-1].digit[1]0
+ *                .                                         .
+ *                .                                         .
+ * p[0].digit[n-1]m-2 p[1].digit[n-1]m-2 ... p[N-2].digit[n-1]m-2 p[N-1].digit[n-1]m-2
+ * p[0].digit[n-1]m-1 p[1].digit[n-1]m-1 ... p[N-2].digit[n-1]m-1 p[N-1].digit[n-1]m-1 
+ *
+ */
+mp_err mpi_to_weave(const mp_int *a, unsigned char *b, 
+					mp_size b_size, mp_size count)
+{
+  mp_size i;
+  mp_digit *digitsa0;
+  mp_digit *digitsa1;
+  mp_digit *digitsa2;
+  mp_digit *digitsa3;
+  mp_size   useda0;
+  mp_size   useda1;
+  mp_size   useda2;
+  mp_size   useda3;
+  mp_weave_word *weaved = (mp_weave_word *)b;
+
+  count = count/sizeof(mp_weave_word);
+
+  /* this code pretty much depends on this ! */
+#if MP_ARGCHK == 2
+  assert(WEAVE_WORD_SIZE == 4); 
+  assert(sizeof(mp_weave_word) == 4);
+#endif
+
+  digitsa0 = MP_DIGITS(&a[0]);
+  digitsa1 = MP_DIGITS(&a[1]);
+  digitsa2 = MP_DIGITS(&a[2]);
+  digitsa3 = MP_DIGITS(&a[3]);
+  useda0 = MP_USED(&a[0]);
+  useda1 = MP_USED(&a[1]);
+  useda2 = MP_USED(&a[2]);
+  useda3 = MP_USED(&a[3]);
+
+  ARGCHK(MP_SIGN(&a[0]) == MP_ZPOS, MP_BADARG);
+  ARGCHK(MP_SIGN(&a[1]) == MP_ZPOS, MP_BADARG);
+  ARGCHK(MP_SIGN(&a[2]) == MP_ZPOS, MP_BADARG);
+  ARGCHK(MP_SIGN(&a[3]) == MP_ZPOS, MP_BADARG);
+  ARGCHK(useda0 <= b_size, MP_BADARG);
+  ARGCHK(useda1 <= b_size, MP_BADARG);
+  ARGCHK(useda2 <= b_size, MP_BADARG);
+  ARGCHK(useda3 <= b_size, MP_BADARG);
+
+#define SAFE_FETCH(digit, used, word) ((word) < (used) ? (digit[word]) : 0)
+
+  for (i=0; i < b_size; i++) {
+    mp_digit d0 = SAFE_FETCH(digitsa0,useda0,i);
+    mp_digit d1 = SAFE_FETCH(digitsa1,useda1,i);
+    mp_digit d2 = SAFE_FETCH(digitsa2,useda2,i);
+    mp_digit d3 = SAFE_FETCH(digitsa3,useda3,i);
+    register mp_weave_word acc;
+
+/*
+ * ONE_STEP takes the MSB of each of our current digits and places that
+ * byte in the appropriate position for writing to the weaved array.
+ *  On little endian:
+ *   b3 b2 b1 b0
+ *  On big endian:
+ *   b0 b1 b2 b3
+ *  When the data is written it would always wind up:
+ *   b[0] = b0
+ *   b[1] = b1
+ *   b[2] = b2
+ *   b[3] = b3
+ *
+ * Once we've written the MSB, we shift the whole digit up left one
+ * byte, putting the Next Most Significant Byte in the MSB position,
+ * so we we repeat the next one step that byte will be written.
+ * NOTE: This code assumes sizeof(mp_weave_word) and MP_WEAVE_WORD_SIZE
+ * is 4.
+ */
+#ifdef MP_IS_LITTLE_ENDIAN 
+#define MPI_WEAVE_ONE_STEP \
+    acc  = (d0 >> (MP_DIGIT_BIT-8))  & 0x000000ff; d0 <<= 8; /*b0*/ \
+    acc |= (d1 >> (MP_DIGIT_BIT-16)) & 0x0000ff00; d1 <<= 8; /*b1*/ \
+    acc |= (d2 >> (MP_DIGIT_BIT-24)) & 0x00ff0000; d2 <<= 8; /*b2*/ \
+    acc |= (d3 >> (MP_DIGIT_BIT-32)) & 0xff000000; d3 <<= 8; /*b3*/ \
+    *weaved = acc; weaved += count;
+#else 
+#define MPI_WEAVE_ONE_STEP \
+    acc  = (d0 >> (MP_DIGIT_BIT-32)) & 0xff000000; d0 <<= 8; /*b0*/ \
+    acc |= (d1 >> (MP_DIGIT_BIT-24)) & 0x00ff0000; d1 <<= 8; /*b1*/ \
+    acc |= (d2 >> (MP_DIGIT_BIT-16)) & 0x0000ff00; d2 <<= 8; /*b2*/ \
+    acc |= (d3 >> (MP_DIGIT_BIT-8))  & 0x000000ff; d3 <<= 8; /*b3*/ \
+    *weaved = acc; weaved += count;
+#endif 
+   switch (sizeof(mp_digit)) {
+   case 32:
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+   case 16:
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+   case 8:
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+   case 4:
+    MPI_WEAVE_ONE_STEP
+    MPI_WEAVE_ONE_STEP
+   case 2:
+    MPI_WEAVE_ONE_STEP
+   case 1:
+    MPI_WEAVE_ONE_STEP
+    break;
+   }
+  }
+
+  return MP_OKAY;
+}
+
+/* reverse the operation above for one entry.
+ * b points to the offset into the weave array of the power we are
+ * calculating */
+mp_err weave_to_mpi(mp_int *a, const unsigned char *b, 
+					mp_size b_size, mp_size count)
+{
+  mp_digit *pb = MP_DIGITS(a);
+  mp_digit *end = &pb[b_size];
+
+  MP_SIGN(a) = MP_ZPOS;
+  MP_USED(a) = b_size;
+
+  for (; pb < end; pb++) {
+    register mp_digit digit;
+
+    digit = *b << 8; b += count;
+#define MPI_UNWEAVE_ONE_STEP  digit |= *b; b += count; digit = digit << 8;
+    switch (sizeof(mp_digit)) {
+    case 32:
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+    case 16:
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+    case 8:
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+    case 4:
+	MPI_UNWEAVE_ONE_STEP 
+	MPI_UNWEAVE_ONE_STEP 
+    case 2:
+	break;
+    }
+    digit |= *b; b += count; 
+
+    *pb = digit;
+  }
+  s_mp_clamp(a);
+  return MP_OKAY;
+}
+#endif
+
+
+#define SQR(a,b) \
+  MP_CHECKOK( mp_sqr(a, b) );\
+  MP_CHECKOK( s_mp_redc(b, mmm) )
+
+#if defined(MP_MONT_USE_MP_MUL)
+#define MUL_NOWEAVE(x,a,b) \
+  MP_CHECKOK( mp_mul(a, x, b) ); \
+  MP_CHECKOK( s_mp_redc(b, mmm) ) 
+#else
+#define MUL_NOWEAVE(x,a,b) \
+  MP_CHECKOK( s_mp_mul_mont(a, x, b, mmm) )
+#endif
+
+#define MUL(x,a,b) \
+  MP_CHECKOK( weave_to_mpi(&tmp, powers + (x), nLen, num_powers) ); \
+  MUL_NOWEAVE(&tmp,a,b)
+
+#define SWAPPA ptmp = pa1; pa1 = pa2; pa2 = ptmp
+#define MP_ALIGN(x,y) ((((ptrdiff_t)(x))+((y)-1))&(((ptrdiff_t)0)-(y)))
+
+/* Do modular exponentiation using integer multiply code. */
+mp_err mp_exptmod_safe_i(const mp_int *   montBase, 
+                    const mp_int *   exponent, 
+		    const mp_int *   modulus, 
+		    mp_int *         result, 
+		    mp_mont_modulus *mmm, 
+		    int              nLen, 
+		    mp_size          bits_in_exponent, 
+		    mp_size          window_bits,
+		    mp_size          num_powers)
+{
+  mp_int *pa1, *pa2, *ptmp;
+  mp_size i;
+  mp_size first_window;
+  mp_err  res;
+  int     expOff;
+  mp_int  accum1, accum2, accum[WEAVE_WORD_SIZE];
+  mp_int  tmp;
+  unsigned char *powersArray;
+  unsigned char *powers;
+
+  MP_DIGITS(&accum1) = 0;
+  MP_DIGITS(&accum2) = 0;
+  MP_DIGITS(&accum[0]) = 0;
+  MP_DIGITS(&accum[1]) = 0;
+  MP_DIGITS(&accum[2]) = 0;
+  MP_DIGITS(&accum[3]) = 0;
+  MP_DIGITS(&tmp) = 0;
+
+  powersArray = (unsigned char *)malloc(num_powers*(nLen*sizeof(mp_digit)+1));
+  if (powersArray == NULL) {
+    res = MP_MEM;
+    goto CLEANUP;
+  }
+
+  /* powers[i] = base ** (i); */
+  powers = (unsigned char *)MP_ALIGN(powersArray,num_powers);
+
+  /* grab the first window value. This allows us to preload accumulator1
+   * and save a conversion, some squares and a multiple*/
+  MP_CHECKOK( mpl_get_bits(exponent, 
+				bits_in_exponent-window_bits, window_bits) );
+  first_window = (mp_size)res;
+
+  MP_CHECKOK( mp_init_size(&accum1, 3 * nLen + 2) );
+  MP_CHECKOK( mp_init_size(&accum2, 3 * nLen + 2) );
+  MP_CHECKOK( mp_init_size(&tmp, 3 * nLen + 2) );
+
+  /* build the first WEAVE_WORD powers inline */
+  /* if WEAVE_WORD_SIZE is not 4, this code will have to change */
+  if (num_powers > 2) {
+    MP_CHECKOK( mp_init_size(&accum[0], 3 * nLen + 2) );
+    MP_CHECKOK( mp_init_size(&accum[1], 3 * nLen + 2) );
+    MP_CHECKOK( mp_init_size(&accum[2], 3 * nLen + 2) );
+    MP_CHECKOK( mp_init_size(&accum[3], 3 * nLen + 2) );
+    mp_set(&accum[0], 1);
+    MP_CHECKOK( s_mp_to_mont(&accum[0], mmm, &accum[0]) );
+    MP_CHECKOK( mp_copy(montBase, &accum[1]) );
+    SQR(montBase, &accum[2]);
+    MUL_NOWEAVE(montBase, &accum[2], &accum[3]);
+    MP_CHECKOK( mpi_to_weave(accum, powers, nLen, num_powers) );
+    if (first_window < 4) {
+      MP_CHECKOK( mp_copy(&accum[first_window], &accum1) );
+      first_window = num_powers;
+    }
+  } else {
+      if (first_window == 0) {
+        mp_set(&accum1, 1);
+        MP_CHECKOK( s_mp_to_mont(&accum1, mmm, &accum1) );
+      } else {
+        /* assert first_window == 1? */
+        MP_CHECKOK( mp_copy(montBase, &accum1) );
+      }
+  }
+
+  /*
+   * calculate all the powers in the powers array.
+   * this adds 2**(k-1)-2 square operations over just calculating the
+   * odd powers where k is the window size in the two other mp_modexpt
+   * implementations in this file. We will get some of that
+   * back by not needing the first 'k' squares and one multiply for the 
+   * first window */ 
+  for (i = WEAVE_WORD_SIZE; i < num_powers; i++) {
+    int acc_index = i & (WEAVE_WORD_SIZE-1); /* i % WEAVE_WORD_SIZE */
+    if ( i & 1 ) {
+      MUL_NOWEAVE(montBase, &accum[acc_index-1] , &accum[acc_index]);
+      /* we've filled the array do our 'per array' processing */
+      if (acc_index == (WEAVE_WORD_SIZE-1)) {
+        MP_CHECKOK( mpi_to_weave(accum, powers + i - (WEAVE_WORD_SIZE-1),
+							 nLen, num_powers) );
+
+        if (first_window <= i) {
+          MP_CHECKOK( mp_copy(&accum[first_window & (WEAVE_WORD_SIZE-1)], 
+								&accum1) );
+          first_window = num_powers;
+        }
+      }
+    } else {
+      /* up to 8 we can find 2^i-1 in the accum array, but at 8 we our source
+       * and target are the same so we need to copy.. After that, the
+       * value is overwritten, so we need to fetch it from the stored
+       * weave array */
+      if (i > 2* WEAVE_WORD_SIZE) {
+        MP_CHECKOK(weave_to_mpi(&accum2, powers+i/2, nLen, num_powers));
+        SQR(&accum2, &accum[acc_index]);
+      } else {
+	int half_power_index = (i/2) & (WEAVE_WORD_SIZE-1);
+	if (half_power_index == acc_index) {
+	   /* copy is cheaper than weave_to_mpi */
+	   MP_CHECKOK(mp_copy(&accum[half_power_index], &accum2));
+	   SQR(&accum2,&accum[acc_index]);
+	} else {
+	   SQR(&accum[half_power_index],&accum[acc_index]);
+	}
+      }
+    }
+  }
+  /* if the accum1 isn't set, Then there is something wrong with our logic 
+   * above and is an internal programming error. 
+   */
+#if MP_ARGCHK == 2
+  assert(MP_USED(&accum1) != 0);
+#endif
+
+  /* set accumulator to montgomery residue of 1 */
+  pa1 = &accum1;
+  pa2 = &accum2;
+
+  for (expOff = bits_in_exponent - window_bits*2; expOff >= 0; expOff -= window_bits) {
+    mp_size smallExp;
+    MP_CHECKOK( mpl_get_bits(exponent, expOff, window_bits) );
+    smallExp = (mp_size)res;
+
+    /* handle unroll the loops */
+    switch (window_bits) {
+    case 1:
+	if (!smallExp) {
+	    SQR(pa1,pa2); SWAPPA;
+	} else if (smallExp & 1) {
+	    SQR(pa1,pa2); MUL_NOWEAVE(montBase,pa2,pa1);
+	} else {
+	    ABORT;
+	}
+	break;
+    case 6:
+	SQR(pa1,pa2); SQR(pa2,pa1); 
+	/* fall through */
+    case 4:
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1);
+	MUL(smallExp, pa1,pa2); SWAPPA;
+	break;
+    case 5:
+	SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); 
+	SQR(pa1,pa2); MUL(smallExp,pa2,pa1);
+	break;
+    default:
+	ABORT; /* could do a loop? */
+    }
+  }
+
+  res = s_mp_redc(pa1, mmm);
+  mp_exch(pa1, result);
+
+CLEANUP:
+  mp_clear(&accum1);
+  mp_clear(&accum2);
+  mp_clear(&accum[0]);
+  mp_clear(&accum[1]);
+  mp_clear(&accum[2]);
+  mp_clear(&accum[3]);
+  mp_clear(&tmp);
+  /* PORT_Memset(powers,0,num_powers*nLen*sizeof(mp_digit)); */
+  free(powersArray);
+  return res;
+}
+#undef SQR
+#undef MUL
+#endif
+
+mp_err mp_exptmod(const mp_int *inBase, const mp_int *exponent, 
+		  const mp_int *modulus, mp_int *result)
+{
+  const mp_int *base;
+  mp_size bits_in_exponent, i, window_bits, odd_ints;
+  mp_err  res;
+  int     nLen;
+  mp_int  montBase, goodBase;
+  mp_mont_modulus mmm;
+#ifdef MP_USING_CACHE_SAFE_MOD_EXP
+  static unsigned int max_window_bits;
+#endif
+
+  /* function for computing n0prime only works if n0 is odd */
+  if (!mp_isodd(modulus))
+    return s_mp_exptmod(inBase, exponent, modulus, result);
+
+  MP_DIGITS(&montBase) = 0;
+  MP_DIGITS(&goodBase) = 0;
+
+  if (mp_cmp(inBase, modulus) < 0) {
+    base = inBase;
+  } else {
+    MP_CHECKOK( mp_init(&goodBase) );
+    base = &goodBase;
+    MP_CHECKOK( mp_mod(inBase, modulus, &goodBase) );
+  }
+
+  nLen  = MP_USED(modulus);
+  MP_CHECKOK( mp_init_size(&montBase, 2 * nLen + 2) );
+
+  mmm.N = *modulus;			/* a copy of the mp_int struct */
+  i = mpl_significant_bits(modulus);
+  i += MP_DIGIT_BIT - 1;
+  mmm.b = i - i % MP_DIGIT_BIT;
+
+  /* compute n0', given n0, n0' = -(n0 ** -1) mod MP_RADIX
+  **		where n0 = least significant mp_digit of N, the modulus.
+  */
+  mmm.n0prime = 0 - s_mp_invmod_radix( MP_DIGIT(modulus, 0) );
+
+  MP_CHECKOK( s_mp_to_mont(base, &mmm, &montBase) );
+
+  bits_in_exponent = mpl_significant_bits(exponent);
+#ifdef MP_USING_CACHE_SAFE_MOD_EXP
+  if (mp_using_cache_safe_exp) {
+    if (bits_in_exponent > 780)
+	window_bits = 6;
+    else if (bits_in_exponent > 256)
+	window_bits = 5;
+    else if (bits_in_exponent > 20)
+	window_bits = 4;
+       /* RSA public key exponents are typically under 20 bits (common values 
+        * are: 3, 17, 65537) and a 4-bit window is inefficient
+        */
+    else 
+	window_bits = 1;
+  } else
+#endif
+  if (bits_in_exponent > 480)
+    window_bits = 6;
+  else if (bits_in_exponent > 160)
+    window_bits = 5;
+  else if (bits_in_exponent > 20)
+    window_bits = 4;
+  /* RSA public key exponents are typically under 20 bits (common values 
+   * are: 3, 17, 65537) and a 4-bit window is inefficient
+   */
+  else 
+    window_bits = 1;
+
+#ifdef MP_USING_CACHE_SAFE_MOD_EXP
+  /*
+   * clamp the window size based on
+   * the cache line size.
+   */
+  if (!max_window_bits) {
+    unsigned long cache_size = s_mpi_getProcessorLineSize();
+    /* processor has no cache, use 'fast' code always */
+    if (cache_size == 0) {
+      mp_using_cache_safe_exp = 0;
+    } 
+    if ((cache_size == 0) || (cache_size >= 64)) {
+      max_window_bits = 6;
+    } else if (cache_size >= 32) {
+      max_window_bits = 5;
+    } else if (cache_size >= 16) {
+      max_window_bits = 4;
+    } else max_window_bits = 1; /* should this be an assert? */
+  }
+
+  /* clamp the window size down before we caclulate bits_in_exponent */
+  if (mp_using_cache_safe_exp) {
+    if (window_bits > max_window_bits) {
+      window_bits = max_window_bits;
+    }
+  }
+#endif
+
+  odd_ints = 1 << (window_bits - 1);
+  i = bits_in_exponent % window_bits;
+  if (i != 0) {
+    bits_in_exponent += window_bits - i;
+  } 
+
+#ifdef MP_USING_MONT_MULF
+  if (mp_using_mont_mulf) {
+    MP_CHECKOK( s_mp_pad(&montBase, nLen) );
+    res = mp_exptmod_f(&montBase, exponent, modulus, result, &mmm, nLen, 
+		     bits_in_exponent, window_bits, odd_ints);
+  } else
+#endif
+#ifdef MP_USING_CACHE_SAFE_MOD_EXP
+  if (mp_using_cache_safe_exp) {
+    res = mp_exptmod_safe_i(&montBase, exponent, modulus, result, &mmm, nLen, 
+		     bits_in_exponent, window_bits, 1 << window_bits);
+  } else
+#endif
+  res = mp_exptmod_i(&montBase, exponent, modulus, result, &mmm, nLen, 
+		     bits_in_exponent, window_bits, odd_ints);
+
+CLEANUP:
+  mp_clear(&montBase);
+  mp_clear(&goodBase);
+  /* Don't mp_clear mmm.N because it is merely a copy of modulus.
+  ** Just zap it.
+  */
+  memset(&mmm, 0, sizeof mmm);
+  return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpprime.c b/mozilla/security/nss/lib/freebl/mpi/mpprime.c
new file mode 100644
index 0000000..ae8e496
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpprime.c
@@ -0,0 +1,617 @@
+/*
+ *  mpprime.c
+ *
+ *  Utilities for finding and working with prime and pseudo-prime
+ *  integers
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1997
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Netscape Communications Corporation
+ *
+ * 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 "mpi-priv.h"
+#include "mpprime.h"
+#include "mplogic.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define SMALL_TABLE 0 /* determines size of hard-wired prime table */
+
+#define RANDOM() rand()
+
+#include "primes.c"  /* pull in the prime digit table */
+
+/* 
+   Test if any of a given vector of digits divides a.  If not, MP_NO
+   is returned; otherwise, MP_YES is returned and 'which' is set to
+   the index of the integer in the vector which divided a.
+ */
+mp_err    s_mpp_divp(mp_int *a, const mp_digit *vec, int size, int *which);
+
+/* {{{ mpp_divis(a, b) */
+
+/*
+  mpp_divis(a, b)
+
+  Returns MP_YES if a is divisible by b, or MP_NO if it is not.
+ */
+
+mp_err  mpp_divis(mp_int *a, mp_int *b)
+{
+  mp_err  res;
+  mp_int  rem;
+
+  if((res = mp_init(&rem)) != MP_OKAY)
+    return res;
+
+  if((res = mp_mod(a, b, &rem)) != MP_OKAY)
+    goto CLEANUP;
+
+  if(mp_cmp_z(&rem) == 0)
+    res = MP_YES;
+  else
+    res = MP_NO;
+
+CLEANUP:
+  mp_clear(&rem);
+  return res;
+
+} /* end mpp_divis() */
+
+/* }}} */
+
+/* {{{ mpp_divis_d(a, d) */
+
+/*
+  mpp_divis_d(a, d)
+
+  Return MP_YES if a is divisible by d, or MP_NO if it is not.
+ */
+
+mp_err  mpp_divis_d(mp_int *a, mp_digit d)
+{
+  mp_err     res;
+  mp_digit   rem;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  if(d == 0)
+    return MP_NO;
+
+  if((res = mp_mod_d(a, d, &rem)) != MP_OKAY)
+    return res;
+
+  if(rem == 0)
+    return MP_YES;
+  else
+    return MP_NO;
+
+} /* end mpp_divis_d() */
+
+/* }}} */
+
+/* {{{ mpp_random(a) */
+
+/*
+  mpp_random(a)
+
+  Assigns a random value to a.  This value is generated using the
+  standard C library's rand() function, so it should not be used for
+  cryptographic purposes, but it should be fine for primality testing,
+  since all we really care about there is good statistical properties.
+
+  As many digits as a currently has are filled with random digits.
+ */
+
+mp_err  mpp_random(mp_int *a)
+
+{
+  mp_digit  next = 0;
+  unsigned int       ix, jx;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  for(ix = 0; ix < USED(a); ix++) {
+    for(jx = 0; jx < sizeof(mp_digit); jx++) {
+      next = (next << CHAR_BIT) | (RANDOM() & UCHAR_MAX);
+    }
+    DIGIT(a, ix) = next;
+  }
+
+  return MP_OKAY;
+
+} /* end mpp_random() */
+
+/* }}} */
+
+/* {{{ mpp_random_size(a, prec) */
+
+mp_err  mpp_random_size(mp_int *a, mp_size prec)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && prec > 0, MP_BADARG);
+  
+  if((res = s_mp_pad(a, prec)) != MP_OKAY)
+    return res;
+
+  return mpp_random(a);
+
+} /* end mpp_random_size() */
+
+/* }}} */
+
+/* {{{ mpp_divis_vector(a, vec, size, which) */
+
+/*
+  mpp_divis_vector(a, vec, size, which)
+
+  Determines if a is divisible by any of the 'size' digits in vec.
+  Returns MP_YES and sets 'which' to the index of the offending digit,
+  if it is; returns MP_NO if it is not.
+ */
+
+mp_err  mpp_divis_vector(mp_int *a, const mp_digit *vec, int size, int *which)
+{
+  ARGCHK(a != NULL && vec != NULL && size > 0, MP_BADARG);
+  
+  return s_mpp_divp(a, vec, size, which);
+
+} /* end mpp_divis_vector() */
+
+/* }}} */
+
+/* {{{ mpp_divis_primes(a, np) */
+
+/*
+  mpp_divis_primes(a, np)
+
+  Test whether a is divisible by any of the first 'np' primes.  If it
+  is, returns MP_YES and sets *np to the value of the digit that did
+  it.  If not, returns MP_NO.
+ */
+mp_err  mpp_divis_primes(mp_int *a, mp_digit *np)
+{
+  int     size, which;
+  mp_err  res;
+
+  ARGCHK(a != NULL && np != NULL, MP_BADARG);
+
+  size = (int)*np;
+  if(size > prime_tab_size)
+    size = prime_tab_size;
+
+  res = mpp_divis_vector(a, prime_tab, size, &which);
+  if(res == MP_YES) 
+    *np = prime_tab[which];
+
+  return res;
+
+} /* end mpp_divis_primes() */
+
+/* }}} */
+
+/* {{{ mpp_fermat(a, w) */
+
+/*
+  Using w as a witness, try pseudo-primality testing based on Fermat's
+  little theorem.  If a is prime, and (w, a) = 1, then w^a == w (mod
+  a).  So, we compute z = w^a (mod a) and compare z to w; if they are
+  equal, the test passes and we return MP_YES.  Otherwise, we return
+  MP_NO.
+ */
+mp_err  mpp_fermat(mp_int *a, mp_digit w)
+{
+  mp_int  base, test;
+  mp_err  res;
+  
+  if((res = mp_init(&base)) != MP_OKAY)
+    return res;
+
+  mp_set(&base, w);
+
+  if((res = mp_init(&test)) != MP_OKAY)
+    goto TEST;
+
+  /* Compute test = base^a (mod a) */
+  if((res = mp_exptmod(&base, a, a, &test)) != MP_OKAY)
+    goto CLEANUP;
+
+  
+  if(mp_cmp(&base, &test) == 0)
+    res = MP_YES;
+  else
+    res = MP_NO;
+
+ CLEANUP:
+  mp_clear(&test);
+ TEST:
+  mp_clear(&base);
+
+  return res;
+
+} /* end mpp_fermat() */
+
+/* }}} */
+
+/*
+  Perform the fermat test on each of the primes in a list until
+  a) one of them shows a is not prime, or 
+  b) the list is exhausted.
+  Returns:  MP_YES if it passes tests.
+	    MP_NO  if fermat test reveals it is composite
+	    Some MP error code if some other error occurs.
+ */
+mp_err mpp_fermat_list(mp_int *a, const mp_digit *primes, mp_size nPrimes)
+{
+  mp_err rv = MP_YES;
+
+  while (nPrimes-- > 0 && rv == MP_YES) {
+    rv = mpp_fermat(a, *primes++);
+  }
+  return rv;
+}
+
+/* {{{ mpp_pprime(a, nt) */
+
+/*
+  mpp_pprime(a, nt)
+
+  Performs nt iteration of the Miller-Rabin probabilistic primality
+  test on a.  Returns MP_YES if the tests pass, MP_NO if one fails.
+  If MP_NO is returned, the number is definitely composite.  If MP_YES
+  is returned, it is probably prime (but that is not guaranteed).
+ */
+
+mp_err  mpp_pprime(mp_int *a, int nt)
+{
+  mp_err   res;
+  mp_int   x, amo, m, z;	/* "amo" = "a minus one" */
+  int      iter;
+  unsigned int jx;
+  mp_size  b;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  MP_DIGITS(&x) = 0;
+  MP_DIGITS(&amo) = 0;
+  MP_DIGITS(&m) = 0;
+  MP_DIGITS(&z) = 0;
+
+  /* Initialize temporaries... */
+  MP_CHECKOK( mp_init(&amo));
+  /* Compute amo = a - 1 for what follows...    */
+  MP_CHECKOK( mp_sub_d(a, 1, &amo) );
+
+  b = mp_trailing_zeros(&amo);
+  if (!b) { /* a was even ? */
+    res = MP_NO;
+    goto CLEANUP;
+  }
+
+  MP_CHECKOK( mp_init_size(&x, MP_USED(a)) );
+  MP_CHECKOK( mp_init(&z) );
+  MP_CHECKOK( mp_init(&m) );
+  MP_CHECKOK( mp_div_2d(&amo, b, &m, 0) );
+
+  /* Do the test nt times... */
+  for(iter = 0; iter < nt; iter++) {
+
+    /* Choose a random value for 1 < x < a      */
+    s_mp_pad(&x, USED(a));
+    mpp_random(&x);
+    MP_CHECKOK( mp_mod(&x, a, &x) );
+    if(mp_cmp_d(&x, 1) <= 0) {
+      iter--;    /* don't count this iteration */
+      continue;  /* choose a new x */
+    }
+
+    /* Compute z = (x ** m) mod a               */
+    MP_CHECKOK( mp_exptmod(&x, &m, a, &z) );
+    
+    if(mp_cmp_d(&z, 1) == 0 || mp_cmp(&z, &amo) == 0) {
+      res = MP_YES;
+      continue;
+    }
+    
+    res = MP_NO;  /* just in case the following for loop never executes. */
+    for (jx = 1; jx < b; jx++) {
+      /* z = z^2 (mod a) */
+      MP_CHECKOK( mp_sqrmod(&z, a, &z) );
+      res = MP_NO;	/* previous line set res to MP_YES */
+
+      if(mp_cmp_d(&z, 1) == 0) {
+	break;
+      }
+      if(mp_cmp(&z, &amo) == 0) {
+	res = MP_YES;
+	break;
+      } 
+    } /* end testing loop */
+
+    /* If the test passes, we will continue iterating, but a failed
+       test means the candidate is definitely NOT prime, so we will
+       immediately break out of this loop
+     */
+    if(res == MP_NO)
+      break;
+
+  } /* end iterations loop */
+  
+CLEANUP:
+  mp_clear(&m);
+  mp_clear(&z);
+  mp_clear(&x);
+  mp_clear(&amo);
+  return res;
+
+} /* end mpp_pprime() */
+
+/* }}} */
+
+/* Produce table of composites from list of primes and trial value.  
+** trial must be odd. List of primes must not include 2.
+** sieve should have dimension >= MAXPRIME/2, where MAXPRIME is largest 
+** prime in list of primes.  After this function is finished,
+** if sieve[i] is non-zero, then (trial + 2*i) is composite.
+** Each prime used in the sieve costs one division of trial, and eliminates
+** one or more values from the search space. (3 eliminates 1/3 of the values
+** alone!)  Each value left in the search space costs 1 or more modular 
+** exponentations.  So, these divisions are a bargain!
+*/
+mp_err mpp_sieve(mp_int *trial, const mp_digit *primes, mp_size nPrimes, 
+		 unsigned char *sieve, mp_size nSieve)
+{
+  mp_err       res;
+  mp_digit     rem;
+  mp_size      ix;
+  unsigned long offset;
+
+  memset(sieve, 0, nSieve);
+
+  for(ix = 0; ix < nPrimes; ix++) {
+    mp_digit prime = primes[ix];
+    mp_size  i;
+    if((res = mp_mod_d(trial, prime, &rem)) != MP_OKAY) 
+      return res;
+
+    if (rem == 0) {
+      offset = 0;
+    } else {
+      offset = prime - (rem / 2);
+    }
+    for (i = offset; i < nSieve ; i += prime) {
+      sieve[i] = 1;
+    }
+  }
+
+  return MP_OKAY;
+}
+
+#define SIEVE_SIZE 32*1024
+
+mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong,
+		      unsigned long * nTries)
+{
+  mp_digit      np;
+  mp_err        res;
+  int           i	= 0;
+  mp_int        trial;
+  mp_int        q;
+  mp_size       num_tests;
+  unsigned char *sieve;
+  
+  ARGCHK(start != 0, MP_BADARG);
+  ARGCHK(nBits > 16, MP_RANGE);
+
+  sieve = malloc(SIEVE_SIZE);
+  ARGCHK(sieve != NULL, MP_MEM);
+
+  MP_DIGITS(&trial) = 0;
+  MP_DIGITS(&q) = 0;
+  MP_CHECKOK( mp_init(&trial) );
+  MP_CHECKOK( mp_init(&q)     );
+  /* values taken from table 4.4, HandBook of Applied Cryptography */
+  if (nBits >= 1300) {
+    num_tests = 2;
+  } else if (nBits >= 850) {
+    num_tests = 3;
+  } else if (nBits >= 650) {
+    num_tests = 4;
+  } else if (nBits >= 550) {
+    num_tests = 5;
+  } else if (nBits >= 450) {
+    num_tests = 6;
+  } else if (nBits >= 400) {
+    num_tests = 7;
+  } else if (nBits >= 350) {
+    num_tests = 8;
+  } else if (nBits >= 300) {
+    num_tests = 9;
+  } else if (nBits >= 250) {
+    num_tests = 12;
+  } else if (nBits >= 200) {
+    num_tests = 15;
+  } else if (nBits >= 150) {
+    num_tests = 18;
+  } else if (nBits >= 100) {
+    num_tests = 27;
+  } else
+    num_tests = 50;
+
+  if (strong) 
+    --nBits;
+  MP_CHECKOK( mpl_set_bit(start, nBits - 1, 1) );
+  MP_CHECKOK( mpl_set_bit(start,         0, 1) );
+  for (i = mpl_significant_bits(start) - 1; i >= nBits; --i) {
+    MP_CHECKOK( mpl_set_bit(start, i, 0) );
+  }
+  /* start sieveing with prime value of 3. */
+  MP_CHECKOK(mpp_sieve(start, prime_tab + 1, prime_tab_size - 1, 
+		       sieve, SIEVE_SIZE) );
+
+#ifdef DEBUG_SIEVE
+  res = 0;
+  for (i = 0; i < SIEVE_SIZE; ++i) {
+    if (!sieve[i])
+      ++res;
+  }
+  fprintf(stderr,"sieve found %d potential primes.\n", res);
+#define FPUTC(x,y) fputc(x,y)
+#else
+#define FPUTC(x,y) 
+#endif
+
+  res = MP_NO;
+  for(i = 0; i < SIEVE_SIZE; ++i) {
+    if (sieve[i])	/* this number is composite */
+      continue;
+    MP_CHECKOK( mp_add_d(start, 2 * i, &trial) );
+    FPUTC('.', stderr);
+    /* run a Fermat test */
+    res = mpp_fermat(&trial, 2);
+    if (res != MP_OKAY) {
+      if (res == MP_NO)
+	continue;	/* was composite */
+      goto CLEANUP;
+    }
+      
+    FPUTC('+', stderr);
+    /* If that passed, run some Miller-Rabin tests	*/
+    res = mpp_pprime(&trial, num_tests);
+    if (res != MP_OKAY) {
+      if (res == MP_NO)
+	continue;	/* was composite */
+      goto CLEANUP;
+    }
+    FPUTC('!', stderr);
+
+    if (!strong) 
+      break;	/* success !! */
+
+    /* At this point, we have strong evidence that our candidate
+       is itself prime.  If we want a strong prime, we need now
+       to test q = 2p + 1 for primality...
+     */
+    MP_CHECKOK( mp_mul_2(&trial, &q) );
+    MP_CHECKOK( mp_add_d(&q, 1, &q)  );
+
+    /* Test q for small prime divisors ... */
+    np = prime_tab_size;
+    res = mpp_divis_primes(&q, &np);
+    if (res == MP_YES) { /* is composite */
+      mp_clear(&q);
+      continue;
+    }
+    if (res != MP_NO) 
+      goto CLEANUP;
+
+    /* And test with Fermat, as with its parent ... */
+    res = mpp_fermat(&q, 2);
+    if (res != MP_YES) {
+      mp_clear(&q);
+      if (res == MP_NO)
+	continue;	/* was composite */
+      goto CLEANUP;
+    }
+
+    /* And test with Miller-Rabin, as with its parent ... */
+    res = mpp_pprime(&q, num_tests);
+    if (res != MP_YES) {
+      mp_clear(&q);
+      if (res == MP_NO)
+	continue;	/* was composite */
+      goto CLEANUP;
+    }
+
+    /* If it passed, we've got a winner */
+    mp_exch(&q, &trial);
+    mp_clear(&q);
+    break;
+
+  } /* end of loop through sieved values */
+  if (res == MP_YES) 
+    mp_exch(&trial, start);
+CLEANUP:
+  mp_clear(&trial);
+  mp_clear(&q);
+  if (nTries)
+    *nTries += i;
+  if (sieve != NULL) {
+  	memset(sieve, 0, SIEVE_SIZE);
+  	free (sieve);
+  }
+  return res;
+}
+
+/*========================================================================*/
+/*------------------------------------------------------------------------*/
+/* Static functions visible only to the library internally                */
+
+/* {{{ s_mpp_divp(a, vec, size, which) */
+
+/* 
+   Test for divisibility by members of a vector of digits.  Returns
+   MP_NO if a is not divisible by any of them; returns MP_YES and sets
+   'which' to the index of the offender, if it is.  Will stop on the
+   first digit against which a is divisible.
+ */
+
+mp_err    s_mpp_divp(mp_int *a, const mp_digit *vec, int size, int *which)
+{
+  mp_err    res;
+  mp_digit  rem;
+
+  int     ix;
+
+  for(ix = 0; ix < size; ix++) {
+    if((res = mp_mod_d(a, vec[ix], &rem)) != MP_OKAY) 
+      return res;
+
+    if(rem == 0) {
+      if(which)
+	*which = ix;
+      return MP_YES;
+    }
+  }
+
+  return MP_NO;
+
+} /* end s_mpp_divp() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS                                                  */
diff --git a/mozilla/security/nss/lib/freebl/mpi/mpprime.h b/mozilla/security/nss/lib/freebl/mpi/mpprime.h
new file mode 100644
index 0000000..486d4a1
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/mpprime.h
@@ -0,0 +1,70 @@
+/*
+ *  mpprime.h
+ *
+ *  Utilities for finding and working with prime and pseudo-prime
+ *  integers
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1997
+ * 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 ***** */
+
+#ifndef _H_MP_PRIME_
+#define _H_MP_PRIME_
+
+#include "mpi.h"
+
+extern const int prime_tab_size;   /* number of primes available */
+extern const mp_digit prime_tab[];
+
+/* Tests for divisibility    */
+mp_err  mpp_divis(mp_int *a, mp_int *b);
+mp_err  mpp_divis_d(mp_int *a, mp_digit d);
+
+/* Random selection          */
+mp_err  mpp_random(mp_int *a);
+mp_err  mpp_random_size(mp_int *a, mp_size prec);
+
+/* Pseudo-primality testing  */
+mp_err  mpp_divis_vector(mp_int *a, const mp_digit *vec, int size, int *which);
+mp_err  mpp_divis_primes(mp_int *a, mp_digit *np);
+mp_err  mpp_fermat(mp_int *a, mp_digit w);
+mp_err mpp_fermat_list(mp_int *a, const mp_digit *primes, mp_size nPrimes);
+mp_err  mpp_pprime(mp_int *a, int nt);
+mp_err mpp_sieve(mp_int *trial, const mp_digit *primes, mp_size nPrimes, 
+		 unsigned char *sieve, mp_size nSieve);
+mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong,
+		      unsigned long * nTries);
+
+#endif /* end _H_MP_PRIME_ */
diff --git a/mozilla/security/nss/lib/freebl/mpi/primes.c b/mozilla/security/nss/lib/freebl/mpi/primes.c
new file mode 100644
index 0000000..2391c5e
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/mpi/primes.c
@@ -0,0 +1,874 @@
+/*
+ * These tables of primes wwere generated using the 'sieve' program
+ * (sieve.c) and converted to this format with 'ptab.pl'.  
+ *
+ * The 'small' table is just the first 128 primes.  The 'large' table
+ * is a table of all the prime values that will fit into a single
+ * mp_digit (given the current size of an mp_digit, which is two bytes).
+ *
+ * ***** 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 MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1997
+ * 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 ***** */
+
+#if SMALL_TABLE
+#define MP_PRIME_TAB_SIZE 128
+#else
+#define MP_PRIME_TAB_SIZE 6542
+#endif
+
+const int prime_tab_size = MP_PRIME_TAB_SIZE;
+const mp_digit  prime_tab[] = {
+	0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, 
+	0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, 
+	0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, 
+	0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, 
+	0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, 
+	0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, 
+	0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, 
+	0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, 
+	0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, 
+	0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, 
+	0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, 
+	0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, 
+	0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, 
+	0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, 
+	0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, 
+	0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, 
+#if ! SMALL_TABLE
+	0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, 
+	0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, 
+	0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, 
+	0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, 
+	0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, 
+	0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, 
+	0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, 
+	0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, 
+	0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, 
+	0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, 
+	0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, 
+	0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, 
+	0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, 
+	0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, 
+	0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, 
+	0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653, 
+	0x0655, 0x065B, 0x0665, 0x0679, 0x067F, 0x0683, 0x0685, 0x069D, 
+	0x06A1, 0x06A3, 0x06AD, 0x06B9, 0x06BB, 0x06C5, 0x06CD, 0x06D3, 
+	0x06D9, 0x06DF, 0x06F1, 0x06F7, 0x06FB, 0x06FD, 0x0709, 0x0713, 
+	0x071F, 0x0727, 0x0737, 0x0745, 0x074B, 0x074F, 0x0751, 0x0755, 
+	0x0757, 0x0761, 0x076D, 0x0773, 0x0779, 0x078B, 0x078D, 0x079D, 
+	0x079F, 0x07B5, 0x07BB, 0x07C3, 0x07C9, 0x07CD, 0x07CF, 0x07D3, 
+	0x07DB, 0x07E1, 0x07EB, 0x07ED, 0x07F7, 0x0805, 0x080F, 0x0815, 
+	0x0821, 0x0823, 0x0827, 0x0829, 0x0833, 0x083F, 0x0841, 0x0851, 
+	0x0853, 0x0859, 0x085D, 0x085F, 0x0869, 0x0871, 0x0883, 0x089B, 
+	0x089F, 0x08A5, 0x08AD, 0x08BD, 0x08BF, 0x08C3, 0x08CB, 0x08DB, 
+	0x08DD, 0x08E1, 0x08E9, 0x08EF, 0x08F5, 0x08F9, 0x0905, 0x0907, 
+	0x091D, 0x0923, 0x0925, 0x092B, 0x092F, 0x0935, 0x0943, 0x0949, 
+	0x094D, 0x094F, 0x0955, 0x0959, 0x095F, 0x096B, 0x0971, 0x0977, 
+	0x0985, 0x0989, 0x098F, 0x099B, 0x09A3, 0x09A9, 0x09AD, 0x09C7, 
+	0x09D9, 0x09E3, 0x09EB, 0x09EF, 0x09F5, 0x09F7, 0x09FD, 0x0A13, 
+	0x0A1F, 0x0A21, 0x0A31, 0x0A39, 0x0A3D, 0x0A49, 0x0A57, 0x0A61, 
+	0x0A63, 0x0A67, 0x0A6F, 0x0A75, 0x0A7B, 0x0A7F, 0x0A81, 0x0A85, 
+	0x0A8B, 0x0A93, 0x0A97, 0x0A99, 0x0A9F, 0x0AA9, 0x0AAB, 0x0AB5, 
+	0x0ABD, 0x0AC1, 0x0ACF, 0x0AD9, 0x0AE5, 0x0AE7, 0x0AED, 0x0AF1, 
+	0x0AF3, 0x0B03, 0x0B11, 0x0B15, 0x0B1B, 0x0B23, 0x0B29, 0x0B2D, 
+	0x0B3F, 0x0B47, 0x0B51, 0x0B57, 0x0B5D, 0x0B65, 0x0B6F, 0x0B7B, 
+	0x0B89, 0x0B8D, 0x0B93, 0x0B99, 0x0B9B, 0x0BB7, 0x0BB9, 0x0BC3, 
+	0x0BCB, 0x0BCF, 0x0BDD, 0x0BE1, 0x0BE9, 0x0BF5, 0x0BFB, 0x0C07, 
+	0x0C0B, 0x0C11, 0x0C25, 0x0C2F, 0x0C31, 0x0C41, 0x0C5B, 0x0C5F, 
+	0x0C61, 0x0C6D, 0x0C73, 0x0C77, 0x0C83, 0x0C89, 0x0C91, 0x0C95, 
+	0x0C9D, 0x0CB3, 0x0CB5, 0x0CB9, 0x0CBB, 0x0CC7, 0x0CE3, 0x0CE5, 
+	0x0CEB, 0x0CF1, 0x0CF7, 0x0CFB, 0x0D01, 0x0D03, 0x0D0F, 0x0D13, 
+	0x0D1F, 0x0D21, 0x0D2B, 0x0D2D, 0x0D3D, 0x0D3F, 0x0D4F, 0x0D55, 
+	0x0D69, 0x0D79, 0x0D81, 0x0D85, 0x0D87, 0x0D8B, 0x0D8D, 0x0DA3, 
+	0x0DAB, 0x0DB7, 0x0DBD, 0x0DC7, 0x0DC9, 0x0DCD, 0x0DD3, 0x0DD5, 
+	0x0DDB, 0x0DE5, 0x0DE7, 0x0DF3, 0x0DFD, 0x0DFF, 0x0E09, 0x0E17, 
+	0x0E1D, 0x0E21, 0x0E27, 0x0E2F, 0x0E35, 0x0E3B, 0x0E4B, 0x0E57, 
+	0x0E59, 0x0E5D, 0x0E6B, 0x0E71, 0x0E75, 0x0E7D, 0x0E87, 0x0E8F, 
+	0x0E95, 0x0E9B, 0x0EB1, 0x0EB7, 0x0EB9, 0x0EC3, 0x0ED1, 0x0ED5, 
+	0x0EDB, 0x0EED, 0x0EEF, 0x0EF9, 0x0F07, 0x0F0B, 0x0F0D, 0x0F17, 
+	0x0F25, 0x0F29, 0x0F31, 0x0F43, 0x0F47, 0x0F4D, 0x0F4F, 0x0F53, 
+	0x0F59, 0x0F5B, 0x0F67, 0x0F6B, 0x0F7F, 0x0F95, 0x0FA1, 0x0FA3, 
+	0x0FA7, 0x0FAD, 0x0FB3, 0x0FB5, 0x0FBB, 0x0FD1, 0x0FD3, 0x0FD9, 
+	0x0FE9, 0x0FEF, 0x0FFB, 0x0FFD, 0x1003, 0x100F, 0x101F, 0x1021, 
+	0x1025, 0x102B, 0x1039, 0x103D, 0x103F, 0x1051, 0x1069, 0x1073, 
+	0x1079, 0x107B, 0x1085, 0x1087, 0x1091, 0x1093, 0x109D, 0x10A3, 
+	0x10A5, 0x10AF, 0x10B1, 0x10BB, 0x10C1, 0x10C9, 0x10E7, 0x10F1, 
+	0x10F3, 0x10FD, 0x1105, 0x110B, 0x1115, 0x1127, 0x112D, 0x1139, 
+	0x1145, 0x1147, 0x1159, 0x115F, 0x1163, 0x1169, 0x116F, 0x1181, 
+	0x1183, 0x118D, 0x119B, 0x11A1, 0x11A5, 0x11A7, 0x11AB, 0x11C3, 
+	0x11C5, 0x11D1, 0x11D7, 0x11E7, 0x11EF, 0x11F5, 0x11FB, 0x120D, 
+	0x121D, 0x121F, 0x1223, 0x1229, 0x122B, 0x1231, 0x1237, 0x1241, 
+	0x1247, 0x1253, 0x125F, 0x1271, 0x1273, 0x1279, 0x127D, 0x128F, 
+	0x1297, 0x12AF, 0x12B3, 0x12B5, 0x12B9, 0x12BF, 0x12C1, 0x12CD, 
+	0x12D1, 0x12DF, 0x12FD, 0x1307, 0x130D, 0x1319, 0x1327, 0x132D, 
+	0x1337, 0x1343, 0x1345, 0x1349, 0x134F, 0x1357, 0x135D, 0x1367, 
+	0x1369, 0x136D, 0x137B, 0x1381, 0x1387, 0x138B, 0x1391, 0x1393, 
+	0x139D, 0x139F, 0x13AF, 0x13BB, 0x13C3, 0x13D5, 0x13D9, 0x13DF, 
+	0x13EB, 0x13ED, 0x13F3, 0x13F9, 0x13FF, 0x141B, 0x1421, 0x142F, 
+	0x1433, 0x143B, 0x1445, 0x144D, 0x1459, 0x146B, 0x146F, 0x1471, 
+	0x1475, 0x148D, 0x1499, 0x149F, 0x14A1, 0x14B1, 0x14B7, 0x14BD, 
+	0x14CB, 0x14D5, 0x14E3, 0x14E7, 0x1505, 0x150B, 0x1511, 0x1517, 
+	0x151F, 0x1525, 0x1529, 0x152B, 0x1537, 0x153D, 0x1541, 0x1543, 
+	0x1549, 0x155F, 0x1565, 0x1567, 0x156B, 0x157D, 0x157F, 0x1583, 
+	0x158F, 0x1591, 0x1597, 0x159B, 0x15B5, 0x15BB, 0x15C1, 0x15C5, 
+	0x15CD, 0x15D7, 0x15F7, 0x1607, 0x1609, 0x160F, 0x1613, 0x1615, 
+	0x1619, 0x161B, 0x1625, 0x1633, 0x1639, 0x163D, 0x1645, 0x164F, 
+	0x1655, 0x1669, 0x166D, 0x166F, 0x1675, 0x1693, 0x1697, 0x169F, 
+	0x16A9, 0x16AF, 0x16B5, 0x16BD, 0x16C3, 0x16CF, 0x16D3, 0x16D9, 
+	0x16DB, 0x16E1, 0x16E5, 0x16EB, 0x16ED, 0x16F7, 0x16F9, 0x1709, 
+	0x170F, 0x1723, 0x1727, 0x1733, 0x1741, 0x175D, 0x1763, 0x1777, 
+	0x177B, 0x178D, 0x1795, 0x179B, 0x179F, 0x17A5, 0x17B3, 0x17B9, 
+	0x17BF, 0x17C9, 0x17CB, 0x17D5, 0x17E1, 0x17E9, 0x17F3, 0x17F5, 
+	0x17FF, 0x1807, 0x1813, 0x181D, 0x1835, 0x1837, 0x183B, 0x1843, 
+	0x1849, 0x184D, 0x1855, 0x1867, 0x1871, 0x1877, 0x187D, 0x187F, 
+	0x1885, 0x188F, 0x189B, 0x189D, 0x18A7, 0x18AD, 0x18B3, 0x18B9, 
+	0x18C1, 0x18C7, 0x18D1, 0x18D7, 0x18D9, 0x18DF, 0x18E5, 0x18EB, 
+	0x18F5, 0x18FD, 0x1915, 0x191B, 0x1931, 0x1933, 0x1945, 0x1949, 
+	0x1951, 0x195B, 0x1979, 0x1981, 0x1993, 0x1997, 0x1999, 0x19A3, 
+	0x19A9, 0x19AB, 0x19B1, 0x19B5, 0x19C7, 0x19CF, 0x19DB, 0x19ED, 
+	0x19FD, 0x1A03, 0x1A05, 0x1A11, 0x1A17, 0x1A21, 0x1A23, 0x1A2D, 
+	0x1A2F, 0x1A35, 0x1A3F, 0x1A4D, 0x1A51, 0x1A69, 0x1A6B, 0x1A7B, 
+	0x1A7D, 0x1A87, 0x1A89, 0x1A93, 0x1AA7, 0x1AAB, 0x1AAD, 0x1AB1, 
+	0x1AB9, 0x1AC9, 0x1ACF, 0x1AD5, 0x1AD7, 0x1AE3, 0x1AF3, 0x1AFB, 
+	0x1AFF, 0x1B05, 0x1B23, 0x1B25, 0x1B2F, 0x1B31, 0x1B37, 0x1B3B, 
+	0x1B41, 0x1B47, 0x1B4F, 0x1B55, 0x1B59, 0x1B65, 0x1B6B, 0x1B73, 
+	0x1B7F, 0x1B83, 0x1B91, 0x1B9D, 0x1BA7, 0x1BBF, 0x1BC5, 0x1BD1, 
+	0x1BD7, 0x1BD9, 0x1BEF, 0x1BF7, 0x1C09, 0x1C13, 0x1C19, 0x1C27, 
+	0x1C2B, 0x1C2D, 0x1C33, 0x1C3D, 0x1C45, 0x1C4B, 0x1C4F, 0x1C55, 
+	0x1C73, 0x1C81, 0x1C8B, 0x1C8D, 0x1C99, 0x1CA3, 0x1CA5, 0x1CB5, 
+	0x1CB7, 0x1CC9, 0x1CE1, 0x1CF3, 0x1CF9, 0x1D09, 0x1D1B, 0x1D21, 
+	0x1D23, 0x1D35, 0x1D39, 0x1D3F, 0x1D41, 0x1D4B, 0x1D53, 0x1D5D, 
+	0x1D63, 0x1D69, 0x1D71, 0x1D75, 0x1D7B, 0x1D7D, 0x1D87, 0x1D89, 
+	0x1D95, 0x1D99, 0x1D9F, 0x1DA5, 0x1DA7, 0x1DB3, 0x1DB7, 0x1DC5, 
+	0x1DD7, 0x1DDB, 0x1DE1, 0x1DF5, 0x1DF9, 0x1E01, 0x1E07, 0x1E0B, 
+	0x1E13, 0x1E17, 0x1E25, 0x1E2B, 0x1E2F, 0x1E3D, 0x1E49, 0x1E4D, 
+	0x1E4F, 0x1E6D, 0x1E71, 0x1E89, 0x1E8F, 0x1E95, 0x1EA1, 0x1EAD, 
+	0x1EBB, 0x1EC1, 0x1EC5, 0x1EC7, 0x1ECB, 0x1EDD, 0x1EE3, 0x1EEF, 
+	0x1EF7, 0x1EFD, 0x1F01, 0x1F0D, 0x1F0F, 0x1F1B, 0x1F39, 0x1F49, 
+	0x1F4B, 0x1F51, 0x1F67, 0x1F75, 0x1F7B, 0x1F85, 0x1F91, 0x1F97, 
+	0x1F99, 0x1F9D, 0x1FA5, 0x1FAF, 0x1FB5, 0x1FBB, 0x1FD3, 0x1FE1, 
+	0x1FE7, 0x1FEB, 0x1FF3, 0x1FFF, 0x2011, 0x201B, 0x201D, 0x2027, 
+	0x2029, 0x202D, 0x2033, 0x2047, 0x204D, 0x2051, 0x205F, 0x2063, 
+	0x2065, 0x2069, 0x2077, 0x207D, 0x2089, 0x20A1, 0x20AB, 0x20B1, 
+	0x20B9, 0x20C3, 0x20C5, 0x20E3, 0x20E7, 0x20ED, 0x20EF, 0x20FB, 
+	0x20FF, 0x210D, 0x2113, 0x2135, 0x2141, 0x2149, 0x214F, 0x2159, 
+	0x215B, 0x215F, 0x2173, 0x217D, 0x2185, 0x2195, 0x2197, 0x21A1, 
+	0x21AF, 0x21B3, 0x21B5, 0x21C1, 0x21C7, 0x21D7, 0x21DD, 0x21E5, 
+	0x21E9, 0x21F1, 0x21F5, 0x21FB, 0x2203, 0x2209, 0x220F, 0x221B, 
+	0x2221, 0x2225, 0x222B, 0x2231, 0x2239, 0x224B, 0x224F, 0x2263, 
+	0x2267, 0x2273, 0x2275, 0x227F, 0x2285, 0x2287, 0x2291, 0x229D, 
+	0x229F, 0x22A3, 0x22B7, 0x22BD, 0x22DB, 0x22E1, 0x22E5, 0x22ED, 
+	0x22F7, 0x2303, 0x2309, 0x230B, 0x2327, 0x2329, 0x232F, 0x2333, 
+	0x2335, 0x2345, 0x2351, 0x2353, 0x2359, 0x2363, 0x236B, 0x2383, 
+	0x238F, 0x2395, 0x23A7, 0x23AD, 0x23B1, 0x23BF, 0x23C5, 0x23C9, 
+	0x23D5, 0x23DD, 0x23E3, 0x23EF, 0x23F3, 0x23F9, 0x2405, 0x240B, 
+	0x2417, 0x2419, 0x2429, 0x243D, 0x2441, 0x2443, 0x244D, 0x245F, 
+	0x2467, 0x246B, 0x2479, 0x247D, 0x247F, 0x2485, 0x249B, 0x24A1, 
+	0x24AF, 0x24B5, 0x24BB, 0x24C5, 0x24CB, 0x24CD, 0x24D7, 0x24D9, 
+	0x24DD, 0x24DF, 0x24F5, 0x24F7, 0x24FB, 0x2501, 0x2507, 0x2513, 
+	0x2519, 0x2527, 0x2531, 0x253D, 0x2543, 0x254B, 0x254F, 0x2573, 
+	0x2581, 0x258D, 0x2593, 0x2597, 0x259D, 0x259F, 0x25AB, 0x25B1, 
+	0x25BD, 0x25CD, 0x25CF, 0x25D9, 0x25E1, 0x25F7, 0x25F9, 0x2605, 
+	0x260B, 0x260F, 0x2615, 0x2627, 0x2629, 0x2635, 0x263B, 0x263F, 
+	0x264B, 0x2653, 0x2659, 0x2665, 0x2669, 0x266F, 0x267B, 0x2681, 
+	0x2683, 0x268F, 0x269B, 0x269F, 0x26AD, 0x26B3, 0x26C3, 0x26C9, 
+	0x26CB, 0x26D5, 0x26DD, 0x26EF, 0x26F5, 0x2717, 0x2719, 0x2735, 
+	0x2737, 0x274D, 0x2753, 0x2755, 0x275F, 0x276B, 0x276D, 0x2773, 
+	0x2777, 0x277F, 0x2795, 0x279B, 0x279D, 0x27A7, 0x27AF, 0x27B3, 
+	0x27B9, 0x27C1, 0x27C5, 0x27D1, 0x27E3, 0x27EF, 0x2803, 0x2807, 
+	0x280D, 0x2813, 0x281B, 0x281F, 0x2821, 0x2831, 0x283D, 0x283F, 
+	0x2849, 0x2851, 0x285B, 0x285D, 0x2861, 0x2867, 0x2875, 0x2881, 
+	0x2897, 0x289F, 0x28BB, 0x28BD, 0x28C1, 0x28D5, 0x28D9, 0x28DB, 
+	0x28DF, 0x28ED, 0x28F7, 0x2903, 0x2905, 0x2911, 0x2921, 0x2923, 
+	0x293F, 0x2947, 0x295D, 0x2965, 0x2969, 0x296F, 0x2975, 0x2983, 
+	0x2987, 0x298F, 0x299B, 0x29A1, 0x29A7, 0x29AB, 0x29BF, 0x29C3, 
+	0x29D5, 0x29D7, 0x29E3, 0x29E9, 0x29ED, 0x29F3, 0x2A01, 0x2A13, 
+	0x2A1D, 0x2A25, 0x2A2F, 0x2A4F, 0x2A55, 0x2A5F, 0x2A65, 0x2A6B, 
+	0x2A6D, 0x2A73, 0x2A83, 0x2A89, 0x2A8B, 0x2A97, 0x2A9D, 0x2AB9, 
+	0x2ABB, 0x2AC5, 0x2ACD, 0x2ADD, 0x2AE3, 0x2AEB, 0x2AF1, 0x2AFB, 
+	0x2B13, 0x2B27, 0x2B31, 0x2B33, 0x2B3D, 0x2B3F, 0x2B4B, 0x2B4F, 
+	0x2B55, 0x2B69, 0x2B6D, 0x2B6F, 0x2B7B, 0x2B8D, 0x2B97, 0x2B99, 
+	0x2BA3, 0x2BA5, 0x2BA9, 0x2BBD, 0x2BCD, 0x2BE7, 0x2BEB, 0x2BF3, 
+	0x2BF9, 0x2BFD, 0x2C09, 0x2C0F, 0x2C17, 0x2C23, 0x2C2F, 0x2C35, 
+	0x2C39, 0x2C41, 0x2C57, 0x2C59, 0x2C69, 0x2C77, 0x2C81, 0x2C87, 
+	0x2C93, 0x2C9F, 0x2CAD, 0x2CB3, 0x2CB7, 0x2CCB, 0x2CCF, 0x2CDB, 
+	0x2CE1, 0x2CE3, 0x2CE9, 0x2CEF, 0x2CFF, 0x2D07, 0x2D1D, 0x2D1F, 
+	0x2D3B, 0x2D43, 0x2D49, 0x2D4D, 0x2D61, 0x2D65, 0x2D71, 0x2D89, 
+	0x2D9D, 0x2DA1, 0x2DA9, 0x2DB3, 0x2DB5, 0x2DC5, 0x2DC7, 0x2DD3, 
+	0x2DDF, 0x2E01, 0x2E03, 0x2E07, 0x2E0D, 0x2E19, 0x2E1F, 0x2E25, 
+	0x2E2D, 0x2E33, 0x2E37, 0x2E39, 0x2E3F, 0x2E57, 0x2E5B, 0x2E6F, 
+	0x2E79, 0x2E7F, 0x2E85, 0x2E93, 0x2E97, 0x2E9D, 0x2EA3, 0x2EA5, 
+	0x2EB1, 0x2EB7, 0x2EC1, 0x2EC3, 0x2ECD, 0x2ED3, 0x2EE7, 0x2EEB, 
+	0x2F05, 0x2F09, 0x2F0B, 0x2F11, 0x2F27, 0x2F29, 0x2F41, 0x2F45, 
+	0x2F4B, 0x2F4D, 0x2F51, 0x2F57, 0x2F6F, 0x2F75, 0x2F7D, 0x2F81, 
+	0x2F83, 0x2FA5, 0x2FAB, 0x2FB3, 0x2FC3, 0x2FCF, 0x2FD1, 0x2FDB, 
+	0x2FDD, 0x2FE7, 0x2FED, 0x2FF5, 0x2FF9, 0x3001, 0x300D, 0x3023, 
+	0x3029, 0x3037, 0x303B, 0x3055, 0x3059, 0x305B, 0x3067, 0x3071, 
+	0x3079, 0x307D, 0x3085, 0x3091, 0x3095, 0x30A3, 0x30A9, 0x30B9, 
+	0x30BF, 0x30C7, 0x30CB, 0x30D1, 0x30D7, 0x30DF, 0x30E5, 0x30EF, 
+	0x30FB, 0x30FD, 0x3103, 0x3109, 0x3119, 0x3121, 0x3127, 0x312D, 
+	0x3139, 0x3143, 0x3145, 0x314B, 0x315D, 0x3161, 0x3167, 0x316D, 
+	0x3173, 0x317F, 0x3191, 0x3199, 0x319F, 0x31A9, 0x31B1, 0x31C3, 
+	0x31C7, 0x31D5, 0x31DB, 0x31ED, 0x31F7, 0x31FF, 0x3209, 0x3215, 
+	0x3217, 0x321D, 0x3229, 0x3235, 0x3259, 0x325D, 0x3263, 0x326B, 
+	0x326F, 0x3275, 0x3277, 0x327B, 0x328D, 0x3299, 0x329F, 0x32A7, 
+	0x32AD, 0x32B3, 0x32B7, 0x32C9, 0x32CB, 0x32CF, 0x32D1, 0x32E9, 
+	0x32ED, 0x32F3, 0x32F9, 0x3307, 0x3325, 0x332B, 0x332F, 0x3335, 
+	0x3341, 0x3347, 0x335B, 0x335F, 0x3367, 0x336B, 0x3373, 0x3379, 
+	0x337F, 0x3383, 0x33A1, 0x33A3, 0x33AD, 0x33B9, 0x33C1, 0x33CB, 
+	0x33D3, 0x33EB, 0x33F1, 0x33FD, 0x3401, 0x340F, 0x3413, 0x3419, 
+	0x341B, 0x3437, 0x3445, 0x3455, 0x3457, 0x3463, 0x3469, 0x346D, 
+	0x3481, 0x348B, 0x3491, 0x3497, 0x349D, 0x34A5, 0x34AF, 0x34BB, 
+	0x34C9, 0x34D3, 0x34E1, 0x34F1, 0x34FF, 0x3509, 0x3517, 0x351D, 
+	0x352D, 0x3533, 0x353B, 0x3541, 0x3551, 0x3565, 0x356F, 0x3571, 
+	0x3577, 0x357B, 0x357D, 0x3581, 0x358D, 0x358F, 0x3599, 0x359B, 
+	0x35A1, 0x35B7, 0x35BD, 0x35BF, 0x35C3, 0x35D5, 0x35DD, 0x35E7, 
+	0x35EF, 0x3605, 0x3607, 0x3611, 0x3623, 0x3631, 0x3635, 0x3637, 
+	0x363B, 0x364D, 0x364F, 0x3653, 0x3659, 0x3661, 0x366B, 0x366D, 
+	0x368B, 0x368F, 0x36AD, 0x36AF, 0x36B9, 0x36BB, 0x36CD, 0x36D1, 
+	0x36E3, 0x36E9, 0x36F7, 0x3701, 0x3703, 0x3707, 0x371B, 0x373F, 
+	0x3745, 0x3749, 0x374F, 0x375D, 0x3761, 0x3775, 0x377F, 0x378D, 
+	0x37A3, 0x37A9, 0x37AB, 0x37C9, 0x37D5, 0x37DF, 0x37F1, 0x37F3, 
+	0x37F7, 0x3805, 0x380B, 0x3821, 0x3833, 0x3835, 0x3841, 0x3847, 
+	0x384B, 0x3853, 0x3857, 0x385F, 0x3865, 0x386F, 0x3871, 0x387D, 
+	0x388F, 0x3899, 0x38A7, 0x38B7, 0x38C5, 0x38C9, 0x38CF, 0x38D5, 
+	0x38D7, 0x38DD, 0x38E1, 0x38E3, 0x38FF, 0x3901, 0x391D, 0x3923, 
+	0x3925, 0x3929, 0x392F, 0x393D, 0x3941, 0x394D, 0x395B, 0x396B, 
+	0x3979, 0x397D, 0x3983, 0x398B, 0x3991, 0x3995, 0x399B, 0x39A1, 
+	0x39A7, 0x39AF, 0x39B3, 0x39BB, 0x39BF, 0x39CD, 0x39DD, 0x39E5, 
+	0x39EB, 0x39EF, 0x39FB, 0x3A03, 0x3A13, 0x3A15, 0x3A1F, 0x3A27, 
+	0x3A2B, 0x3A31, 0x3A4B, 0x3A51, 0x3A5B, 0x3A63, 0x3A67, 0x3A6D, 
+	0x3A79, 0x3A87, 0x3AA5, 0x3AA9, 0x3AB7, 0x3ACD, 0x3AD5, 0x3AE1, 
+	0x3AE5, 0x3AEB, 0x3AF3, 0x3AFD, 0x3B03, 0x3B11, 0x3B1B, 0x3B21, 
+	0x3B23, 0x3B2D, 0x3B39, 0x3B45, 0x3B53, 0x3B59, 0x3B5F, 0x3B71, 
+	0x3B7B, 0x3B81, 0x3B89, 0x3B9B, 0x3B9F, 0x3BA5, 0x3BA7, 0x3BAD, 
+	0x3BB7, 0x3BB9, 0x3BC3, 0x3BCB, 0x3BD1, 0x3BD7, 0x3BE1, 0x3BE3, 
+	0x3BF5, 0x3BFF, 0x3C01, 0x3C0D, 0x3C11, 0x3C17, 0x3C1F, 0x3C29, 
+	0x3C35, 0x3C43, 0x3C4F, 0x3C53, 0x3C5B, 0x3C65, 0x3C6B, 0x3C71, 
+	0x3C85, 0x3C89, 0x3C97, 0x3CA7, 0x3CB5, 0x3CBF, 0x3CC7, 0x3CD1, 
+	0x3CDD, 0x3CDF, 0x3CF1, 0x3CF7, 0x3D03, 0x3D0D, 0x3D19, 0x3D1B, 
+	0x3D1F, 0x3D21, 0x3D2D, 0x3D33, 0x3D37, 0x3D3F, 0x3D43, 0x3D6F, 
+	0x3D73, 0x3D75, 0x3D79, 0x3D7B, 0x3D85, 0x3D91, 0x3D97, 0x3D9D, 
+	0x3DAB, 0x3DAF, 0x3DB5, 0x3DBB, 0x3DC1, 0x3DC9, 0x3DCF, 0x3DF3, 
+	0x3E05, 0x3E09, 0x3E0F, 0x3E11, 0x3E1D, 0x3E23, 0x3E29, 0x3E2F, 
+	0x3E33, 0x3E41, 0x3E57, 0x3E63, 0x3E65, 0x3E77, 0x3E81, 0x3E87, 
+	0x3EA1, 0x3EB9, 0x3EBD, 0x3EBF, 0x3EC3, 0x3EC5, 0x3EC9, 0x3ED7, 
+	0x3EDB, 0x3EE1, 0x3EE7, 0x3EEF, 0x3EFF, 0x3F0B, 0x3F0D, 0x3F37, 
+	0x3F3B, 0x3F3D, 0x3F41, 0x3F59, 0x3F5F, 0x3F65, 0x3F67, 0x3F79, 
+	0x3F7D, 0x3F8B, 0x3F91, 0x3FAD, 0x3FBF, 0x3FCD, 0x3FD3, 0x3FDD, 
+	0x3FE9, 0x3FEB, 0x3FF1, 0x3FFD, 0x401B, 0x4021, 0x4025, 0x402B, 
+	0x4031, 0x403F, 0x4043, 0x4045, 0x405D, 0x4061, 0x4067, 0x406D, 
+	0x4087, 0x4091, 0x40A3, 0x40A9, 0x40B1, 0x40B7, 0x40BD, 0x40DB, 
+	0x40DF, 0x40EB, 0x40F7, 0x40F9, 0x4109, 0x410B, 0x4111, 0x4115, 
+	0x4121, 0x4133, 0x4135, 0x413B, 0x413F, 0x4159, 0x4165, 0x416B, 
+	0x4177, 0x417B, 0x4193, 0x41AB, 0x41B7, 0x41BD, 0x41BF, 0x41CB, 
+	0x41E7, 0x41EF, 0x41F3, 0x41F9, 0x4205, 0x4207, 0x4219, 0x421F, 
+	0x4223, 0x4229, 0x422F, 0x4243, 0x4253, 0x4255, 0x425B, 0x4261, 
+	0x4273, 0x427D, 0x4283, 0x4285, 0x4289, 0x4291, 0x4297, 0x429D, 
+	0x42B5, 0x42C5, 0x42CB, 0x42D3, 0x42DD, 0x42E3, 0x42F1, 0x4307, 
+	0x430F, 0x431F, 0x4325, 0x4327, 0x4333, 0x4337, 0x4339, 0x434F, 
+	0x4357, 0x4369, 0x438B, 0x438D, 0x4393, 0x43A5, 0x43A9, 0x43AF, 
+	0x43B5, 0x43BD, 0x43C7, 0x43CF, 0x43E1, 0x43E7, 0x43EB, 0x43ED, 
+	0x43F1, 0x43F9, 0x4409, 0x440B, 0x4417, 0x4423, 0x4429, 0x443B, 
+	0x443F, 0x4445, 0x444B, 0x4451, 0x4453, 0x4459, 0x4465, 0x446F, 
+	0x4483, 0x448F, 0x44A1, 0x44A5, 0x44AB, 0x44AD, 0x44BD, 0x44BF, 
+	0x44C9, 0x44D7, 0x44DB, 0x44F9, 0x44FB, 0x4505, 0x4511, 0x4513, 
+	0x452B, 0x4531, 0x4541, 0x4549, 0x4553, 0x4555, 0x4561, 0x4577, 
+	0x457D, 0x457F, 0x458F, 0x45A3, 0x45AD, 0x45AF, 0x45BB, 0x45C7, 
+	0x45D9, 0x45E3, 0x45EF, 0x45F5, 0x45F7, 0x4601, 0x4603, 0x4609, 
+	0x4613, 0x4625, 0x4627, 0x4633, 0x4639, 0x463D, 0x4643, 0x4645, 
+	0x465D, 0x4679, 0x467B, 0x467F, 0x4681, 0x468B, 0x468D, 0x469D, 
+	0x46A9, 0x46B1, 0x46C7, 0x46C9, 0x46CF, 0x46D3, 0x46D5, 0x46DF, 
+	0x46E5, 0x46F9, 0x4705, 0x470F, 0x4717, 0x4723, 0x4729, 0x472F, 
+	0x4735, 0x4739, 0x474B, 0x474D, 0x4751, 0x475D, 0x476F, 0x4771, 
+	0x477D, 0x4783, 0x4787, 0x4789, 0x4799, 0x47A5, 0x47B1, 0x47BF, 
+	0x47C3, 0x47CB, 0x47DD, 0x47E1, 0x47ED, 0x47FB, 0x4801, 0x4807, 
+	0x480B, 0x4813, 0x4819, 0x481D, 0x4831, 0x483D, 0x4847, 0x4855, 
+	0x4859, 0x485B, 0x486B, 0x486D, 0x4879, 0x4897, 0x489B, 0x48A1, 
+	0x48B9, 0x48CD, 0x48E5, 0x48EF, 0x48F7, 0x4903, 0x490D, 0x4919, 
+	0x491F, 0x492B, 0x4937, 0x493D, 0x4945, 0x4955, 0x4963, 0x4969, 
+	0x496D, 0x4973, 0x4997, 0x49AB, 0x49B5, 0x49D3, 0x49DF, 0x49E1, 
+	0x49E5, 0x49E7, 0x4A03, 0x4A0F, 0x4A1D, 0x4A23, 0x4A39, 0x4A41, 
+	0x4A45, 0x4A57, 0x4A5D, 0x4A6B, 0x4A7D, 0x4A81, 0x4A87, 0x4A89, 
+	0x4A8F, 0x4AB1, 0x4AC3, 0x4AC5, 0x4AD5, 0x4ADB, 0x4AED, 0x4AEF, 
+	0x4B07, 0x4B0B, 0x4B0D, 0x4B13, 0x4B1F, 0x4B25, 0x4B31, 0x4B3B, 
+	0x4B43, 0x4B49, 0x4B59, 0x4B65, 0x4B6D, 0x4B77, 0x4B85, 0x4BAD, 
+	0x4BB3, 0x4BB5, 0x4BBB, 0x4BBF, 0x4BCB, 0x4BD9, 0x4BDD, 0x4BDF, 
+	0x4BE3, 0x4BE5, 0x4BE9, 0x4BF1, 0x4BF7, 0x4C01, 0x4C07, 0x4C0D, 
+	0x4C0F, 0x4C15, 0x4C1B, 0x4C21, 0x4C2D, 0x4C33, 0x4C4B, 0x4C55, 
+	0x4C57, 0x4C61, 0x4C67, 0x4C73, 0x4C79, 0x4C7F, 0x4C8D, 0x4C93, 
+	0x4C99, 0x4CCD, 0x4CE1, 0x4CE7, 0x4CF1, 0x4CF3, 0x4CFD, 0x4D05, 
+	0x4D0F, 0x4D1B, 0x4D27, 0x4D29, 0x4D2F, 0x4D33, 0x4D41, 0x4D51, 
+	0x4D59, 0x4D65, 0x4D6B, 0x4D81, 0x4D83, 0x4D8D, 0x4D95, 0x4D9B, 
+	0x4DB1, 0x4DB3, 0x4DC9, 0x4DCF, 0x4DD7, 0x4DE1, 0x4DED, 0x4DF9, 
+	0x4DFB, 0x4E05, 0x4E0B, 0x4E17, 0x4E19, 0x4E1D, 0x4E2B, 0x4E35, 
+	0x4E37, 0x4E3D, 0x4E4F, 0x4E53, 0x4E5F, 0x4E67, 0x4E79, 0x4E85, 
+	0x4E8B, 0x4E91, 0x4E95, 0x4E9B, 0x4EA1, 0x4EAF, 0x4EB3, 0x4EB5, 
+	0x4EC1, 0x4ECD, 0x4ED1, 0x4ED7, 0x4EE9, 0x4EFB, 0x4F07, 0x4F09, 
+	0x4F19, 0x4F25, 0x4F2D, 0x4F3F, 0x4F49, 0x4F63, 0x4F67, 0x4F6D, 
+	0x4F75, 0x4F7B, 0x4F81, 0x4F85, 0x4F87, 0x4F91, 0x4FA5, 0x4FA9, 
+	0x4FAF, 0x4FB7, 0x4FBB, 0x4FCF, 0x4FD9, 0x4FDB, 0x4FFD, 0x4FFF, 
+	0x5003, 0x501B, 0x501D, 0x5029, 0x5035, 0x503F, 0x5045, 0x5047, 
+	0x5053, 0x5071, 0x5077, 0x5083, 0x5093, 0x509F, 0x50A1, 0x50B7, 
+	0x50C9, 0x50D5, 0x50E3, 0x50ED, 0x50EF, 0x50FB, 0x5107, 0x510B, 
+	0x510D, 0x5111, 0x5117, 0x5123, 0x5125, 0x5135, 0x5147, 0x5149, 
+	0x5171, 0x5179, 0x5189, 0x518F, 0x5197, 0x51A1, 0x51A3, 0x51A7, 
+	0x51B9, 0x51C1, 0x51CB, 0x51D3, 0x51DF, 0x51E3, 0x51F5, 0x51F7, 
+	0x5209, 0x5213, 0x5215, 0x5219, 0x521B, 0x521F, 0x5227, 0x5243, 
+	0x5245, 0x524B, 0x5261, 0x526D, 0x5273, 0x5281, 0x5293, 0x5297, 
+	0x529D, 0x52A5, 0x52AB, 0x52B1, 0x52BB, 0x52C3, 0x52C7, 0x52C9, 
+	0x52DB, 0x52E5, 0x52EB, 0x52FF, 0x5315, 0x531D, 0x5323, 0x5341, 
+	0x5345, 0x5347, 0x534B, 0x535D, 0x5363, 0x5381, 0x5383, 0x5387, 
+	0x538F, 0x5395, 0x5399, 0x539F, 0x53AB, 0x53B9, 0x53DB, 0x53E9, 
+	0x53EF, 0x53F3, 0x53F5, 0x53FB, 0x53FF, 0x540D, 0x5411, 0x5413, 
+	0x5419, 0x5435, 0x5437, 0x543B, 0x5441, 0x5449, 0x5453, 0x5455, 
+	0x545F, 0x5461, 0x546B, 0x546D, 0x5471, 0x548F, 0x5491, 0x549D, 
+	0x54A9, 0x54B3, 0x54C5, 0x54D1, 0x54DF, 0x54E9, 0x54EB, 0x54F7, 
+	0x54FD, 0x5507, 0x550D, 0x551B, 0x5527, 0x552B, 0x5539, 0x553D, 
+	0x554F, 0x5551, 0x555B, 0x5563, 0x5567, 0x556F, 0x5579, 0x5585, 
+	0x5597, 0x55A9, 0x55B1, 0x55B7, 0x55C9, 0x55D9, 0x55E7, 0x55ED, 
+	0x55F3, 0x55FD, 0x560B, 0x560F, 0x5615, 0x5617, 0x5623, 0x562F, 
+	0x5633, 0x5639, 0x563F, 0x564B, 0x564D, 0x565D, 0x565F, 0x566B, 
+	0x5671, 0x5675, 0x5683, 0x5689, 0x568D, 0x568F, 0x569B, 0x56AD, 
+	0x56B1, 0x56D5, 0x56E7, 0x56F3, 0x56FF, 0x5701, 0x5705, 0x5707, 
+	0x570B, 0x5713, 0x571F, 0x5723, 0x5747, 0x574D, 0x575F, 0x5761, 
+	0x576D, 0x5777, 0x577D, 0x5789, 0x57A1, 0x57A9, 0x57AF, 0x57B5, 
+	0x57C5, 0x57D1, 0x57D3, 0x57E5, 0x57EF, 0x5803, 0x580D, 0x580F, 
+	0x5815, 0x5827, 0x582B, 0x582D, 0x5855, 0x585B, 0x585D, 0x586D, 
+	0x586F, 0x5873, 0x587B, 0x588D, 0x5897, 0x58A3, 0x58A9, 0x58AB, 
+	0x58B5, 0x58BD, 0x58C1, 0x58C7, 0x58D3, 0x58D5, 0x58DF, 0x58F1, 
+	0x58F9, 0x58FF, 0x5903, 0x5917, 0x591B, 0x5921, 0x5945, 0x594B, 
+	0x594D, 0x5957, 0x595D, 0x5975, 0x597B, 0x5989, 0x5999, 0x599F, 
+	0x59B1, 0x59B3, 0x59BD, 0x59D1, 0x59DB, 0x59E3, 0x59E9, 0x59ED, 
+	0x59F3, 0x59F5, 0x59FF, 0x5A01, 0x5A0D, 0x5A11, 0x5A13, 0x5A17, 
+	0x5A1F, 0x5A29, 0x5A2F, 0x5A3B, 0x5A4D, 0x5A5B, 0x5A67, 0x5A77, 
+	0x5A7F, 0x5A85, 0x5A95, 0x5A9D, 0x5AA1, 0x5AA3, 0x5AA9, 0x5ABB, 
+	0x5AD3, 0x5AE5, 0x5AEF, 0x5AFB, 0x5AFD, 0x5B01, 0x5B0F, 0x5B19, 
+	0x5B1F, 0x5B25, 0x5B2B, 0x5B3D, 0x5B49, 0x5B4B, 0x5B67, 0x5B79, 
+	0x5B87, 0x5B97, 0x5BA3, 0x5BB1, 0x5BC9, 0x5BD5, 0x5BEB, 0x5BF1, 
+	0x5BF3, 0x5BFD, 0x5C05, 0x5C09, 0x5C0B, 0x5C0F, 0x5C1D, 0x5C29, 
+	0x5C2F, 0x5C33, 0x5C39, 0x5C47, 0x5C4B, 0x5C4D, 0x5C51, 0x5C6F, 
+	0x5C75, 0x5C77, 0x5C7D, 0x5C87, 0x5C89, 0x5CA7, 0x5CBD, 0x5CBF, 
+	0x5CC3, 0x5CC9, 0x5CD1, 0x5CD7, 0x5CDD, 0x5CED, 0x5CF9, 0x5D05, 
+	0x5D0B, 0x5D13, 0x5D17, 0x5D19, 0x5D31, 0x5D3D, 0x5D41, 0x5D47, 
+	0x5D4F, 0x5D55, 0x5D5B, 0x5D65, 0x5D67, 0x5D6D, 0x5D79, 0x5D95, 
+	0x5DA3, 0x5DA9, 0x5DAD, 0x5DB9, 0x5DC1, 0x5DC7, 0x5DD3, 0x5DD7, 
+	0x5DDD, 0x5DEB, 0x5DF1, 0x5DFD, 0x5E07, 0x5E0D, 0x5E13, 0x5E1B, 
+	0x5E21, 0x5E27, 0x5E2B, 0x5E2D, 0x5E31, 0x5E39, 0x5E45, 0x5E49, 
+	0x5E57, 0x5E69, 0x5E73, 0x5E75, 0x5E85, 0x5E8B, 0x5E9F, 0x5EA5, 
+	0x5EAF, 0x5EB7, 0x5EBB, 0x5ED9, 0x5EFD, 0x5F09, 0x5F11, 0x5F27, 
+	0x5F33, 0x5F35, 0x5F3B, 0x5F47, 0x5F57, 0x5F5D, 0x5F63, 0x5F65, 
+	0x5F77, 0x5F7B, 0x5F95, 0x5F99, 0x5FA1, 0x5FB3, 0x5FBD, 0x5FC5, 
+	0x5FCF, 0x5FD5, 0x5FE3, 0x5FE7, 0x5FFB, 0x6011, 0x6023, 0x602F, 
+	0x6037, 0x6053, 0x605F, 0x6065, 0x606B, 0x6073, 0x6079, 0x6085, 
+	0x609D, 0x60AD, 0x60BB, 0x60BF, 0x60CD, 0x60D9, 0x60DF, 0x60E9, 
+	0x60F5, 0x6109, 0x610F, 0x6113, 0x611B, 0x612D, 0x6139, 0x614B, 
+	0x6155, 0x6157, 0x615B, 0x616F, 0x6179, 0x6187, 0x618B, 0x6191, 
+	0x6193, 0x619D, 0x61B5, 0x61C7, 0x61C9, 0x61CD, 0x61E1, 0x61F1, 
+	0x61FF, 0x6209, 0x6217, 0x621D, 0x6221, 0x6227, 0x623B, 0x6241, 
+	0x624B, 0x6251, 0x6253, 0x625F, 0x6265, 0x6283, 0x628D, 0x6295, 
+	0x629B, 0x629F, 0x62A5, 0x62AD, 0x62D5, 0x62D7, 0x62DB, 0x62DD, 
+	0x62E9, 0x62FB, 0x62FF, 0x6305, 0x630D, 0x6317, 0x631D, 0x632F, 
+	0x6341, 0x6343, 0x634F, 0x635F, 0x6367, 0x636D, 0x6371, 0x6377, 
+	0x637D, 0x637F, 0x63B3, 0x63C1, 0x63C5, 0x63D9, 0x63E9, 0x63EB, 
+	0x63EF, 0x63F5, 0x6401, 0x6403, 0x6409, 0x6415, 0x6421, 0x6427, 
+	0x642B, 0x6439, 0x6443, 0x6449, 0x644F, 0x645D, 0x6467, 0x6475, 
+	0x6485, 0x648D, 0x6493, 0x649F, 0x64A3, 0x64AB, 0x64C1, 0x64C7, 
+	0x64C9, 0x64DB, 0x64F1, 0x64F7, 0x64F9, 0x650B, 0x6511, 0x6521, 
+	0x652F, 0x6539, 0x653F, 0x654B, 0x654D, 0x6553, 0x6557, 0x655F, 
+	0x6571, 0x657D, 0x658D, 0x658F, 0x6593, 0x65A1, 0x65A5, 0x65AD, 
+	0x65B9, 0x65C5, 0x65E3, 0x65F3, 0x65FB, 0x65FF, 0x6601, 0x6607, 
+	0x661D, 0x6629, 0x6631, 0x663B, 0x6641, 0x6647, 0x664D, 0x665B, 
+	0x6661, 0x6673, 0x667D, 0x6689, 0x668B, 0x6695, 0x6697, 0x669B, 
+	0x66B5, 0x66B9, 0x66C5, 0x66CD, 0x66D1, 0x66E3, 0x66EB, 0x66F5, 
+	0x6703, 0x6713, 0x6719, 0x671F, 0x6727, 0x6731, 0x6737, 0x673F, 
+	0x6745, 0x6751, 0x675B, 0x676F, 0x6779, 0x6781, 0x6785, 0x6791, 
+	0x67AB, 0x67BD, 0x67C1, 0x67CD, 0x67DF, 0x67E5, 0x6803, 0x6809, 
+	0x6811, 0x6817, 0x682D, 0x6839, 0x683B, 0x683F, 0x6845, 0x684B, 
+	0x684D, 0x6857, 0x6859, 0x685D, 0x6863, 0x6869, 0x686B, 0x6871, 
+	0x6887, 0x6899, 0x689F, 0x68B1, 0x68BD, 0x68C5, 0x68D1, 0x68D7, 
+	0x68E1, 0x68ED, 0x68EF, 0x68FF, 0x6901, 0x690B, 0x690D, 0x6917, 
+	0x6929, 0x692F, 0x6943, 0x6947, 0x6949, 0x694F, 0x6965, 0x696B, 
+	0x6971, 0x6983, 0x6989, 0x6997, 0x69A3, 0x69B3, 0x69B5, 0x69BB, 
+	0x69C1, 0x69C5, 0x69D3, 0x69DF, 0x69E3, 0x69E5, 0x69F7, 0x6A07, 
+	0x6A2B, 0x6A37, 0x6A3D, 0x6A4B, 0x6A67, 0x6A69, 0x6A75, 0x6A7B, 
+	0x6A87, 0x6A8D, 0x6A91, 0x6A93, 0x6AA3, 0x6AC1, 0x6AC9, 0x6AE1, 
+	0x6AE7, 0x6B05, 0x6B0F, 0x6B11, 0x6B23, 0x6B27, 0x6B2D, 0x6B39, 
+	0x6B41, 0x6B57, 0x6B59, 0x6B5F, 0x6B75, 0x6B87, 0x6B89, 0x6B93, 
+	0x6B95, 0x6B9F, 0x6BBD, 0x6BBF, 0x6BDB, 0x6BE1, 0x6BEF, 0x6BFF, 
+	0x6C05, 0x6C19, 0x6C29, 0x6C2B, 0x6C31, 0x6C35, 0x6C55, 0x6C59, 
+	0x6C5B, 0x6C5F, 0x6C65, 0x6C67, 0x6C73, 0x6C77, 0x6C7D, 0x6C83, 
+	0x6C8F, 0x6C91, 0x6C97, 0x6C9B, 0x6CA1, 0x6CA9, 0x6CAF, 0x6CB3, 
+	0x6CC7, 0x6CCB, 0x6CEB, 0x6CF5, 0x6CFD, 0x6D0D, 0x6D0F, 0x6D25, 
+	0x6D27, 0x6D2B, 0x6D31, 0x6D39, 0x6D3F, 0x6D4F, 0x6D5D, 0x6D61, 
+	0x6D73, 0x6D7B, 0x6D7F, 0x6D93, 0x6D99, 0x6DA5, 0x6DB1, 0x6DB7, 
+	0x6DC1, 0x6DC3, 0x6DCD, 0x6DCF, 0x6DDB, 0x6DF7, 0x6E03, 0x6E15, 
+	0x6E17, 0x6E29, 0x6E33, 0x6E3B, 0x6E45, 0x6E75, 0x6E77, 0x6E7B, 
+	0x6E81, 0x6E89, 0x6E93, 0x6E95, 0x6E9F, 0x6EBD, 0x6EBF, 0x6EE3, 
+	0x6EE9, 0x6EF3, 0x6EF9, 0x6EFB, 0x6F0D, 0x6F11, 0x6F17, 0x6F1F, 
+	0x6F2F, 0x6F3D, 0x6F4D, 0x6F53, 0x6F61, 0x6F65, 0x6F79, 0x6F7D, 
+	0x6F83, 0x6F85, 0x6F8F, 0x6F9B, 0x6F9D, 0x6FA3, 0x6FAF, 0x6FB5, 
+	0x6FBB, 0x6FBF, 0x6FCB, 0x6FCD, 0x6FD3, 0x6FD7, 0x6FE3, 0x6FE9, 
+	0x6FF1, 0x6FF5, 0x6FF7, 0x6FFD, 0x700F, 0x7019, 0x701F, 0x7027, 
+	0x7033, 0x7039, 0x704F, 0x7051, 0x7057, 0x7063, 0x7075, 0x7079, 
+	0x7087, 0x708D, 0x7091, 0x70A5, 0x70AB, 0x70BB, 0x70C3, 0x70C7, 
+	0x70CF, 0x70E5, 0x70ED, 0x70F9, 0x70FF, 0x7105, 0x7115, 0x7121, 
+	0x7133, 0x7151, 0x7159, 0x715D, 0x715F, 0x7163, 0x7169, 0x7183, 
+	0x7187, 0x7195, 0x71AD, 0x71C3, 0x71C9, 0x71CB, 0x71D1, 0x71DB, 
+	0x71E1, 0x71EF, 0x71F5, 0x71FB, 0x7207, 0x7211, 0x7217, 0x7219, 
+	0x7225, 0x722F, 0x723B, 0x7243, 0x7255, 0x7267, 0x7271, 0x7277, 
+	0x727F, 0x728F, 0x7295, 0x729B, 0x72A3, 0x72B3, 0x72C7, 0x72CB, 
+	0x72CD, 0x72D7, 0x72D9, 0x72E3, 0x72EF, 0x72F5, 0x72FD, 0x7303, 
+	0x730D, 0x7321, 0x732B, 0x733D, 0x7357, 0x735B, 0x7361, 0x737F, 
+	0x7381, 0x7385, 0x738D, 0x7393, 0x739F, 0x73AB, 0x73BD, 0x73C1, 
+	0x73C9, 0x73DF, 0x73E5, 0x73E7, 0x73F3, 0x7415, 0x741B, 0x742D, 
+	0x7439, 0x743F, 0x7441, 0x745D, 0x746B, 0x747B, 0x7489, 0x748D, 
+	0x749B, 0x74A7, 0x74AB, 0x74B1, 0x74B7, 0x74B9, 0x74DD, 0x74E1, 
+	0x74E7, 0x74FB, 0x7507, 0x751F, 0x7525, 0x753B, 0x753D, 0x754D, 
+	0x755F, 0x756B, 0x7577, 0x7589, 0x758B, 0x7591, 0x7597, 0x759D, 
+	0x75A1, 0x75A7, 0x75B5, 0x75B9, 0x75BB, 0x75D1, 0x75D9, 0x75E5, 
+	0x75EB, 0x75F5, 0x75FB, 0x7603, 0x760F, 0x7621, 0x762D, 0x7633, 
+	0x763D, 0x763F, 0x7655, 0x7663, 0x7669, 0x766F, 0x7673, 0x7685, 
+	0x768B, 0x769F, 0x76B5, 0x76B7, 0x76C3, 0x76DB, 0x76DF, 0x76F1, 
+	0x7703, 0x7705, 0x771B, 0x771D, 0x7721, 0x772D, 0x7735, 0x7741, 
+	0x774B, 0x7759, 0x775D, 0x775F, 0x7771, 0x7781, 0x77A7, 0x77AD, 
+	0x77B3, 0x77B9, 0x77C5, 0x77CF, 0x77D5, 0x77E1, 0x77E9, 0x77EF, 
+	0x77F3, 0x77F9, 0x7807, 0x7825, 0x782B, 0x7835, 0x783D, 0x7853, 
+	0x7859, 0x7861, 0x786D, 0x7877, 0x7879, 0x7883, 0x7885, 0x788B, 
+	0x7895, 0x7897, 0x78A1, 0x78AD, 0x78BF, 0x78D3, 0x78D9, 0x78DD, 
+	0x78E5, 0x78FB, 0x7901, 0x7907, 0x7925, 0x792B, 0x7939, 0x793F, 
+	0x794B, 0x7957, 0x795D, 0x7967, 0x7969, 0x7973, 0x7991, 0x7993, 
+	0x79A3, 0x79AB, 0x79AF, 0x79B1, 0x79B7, 0x79C9, 0x79CD, 0x79CF, 
+	0x79D5, 0x79D9, 0x79F3, 0x79F7, 0x79FF, 0x7A05, 0x7A0F, 0x7A11, 
+	0x7A15, 0x7A1B, 0x7A23, 0x7A27, 0x7A2D, 0x7A4B, 0x7A57, 0x7A59, 
+	0x7A5F, 0x7A65, 0x7A69, 0x7A7D, 0x7A93, 0x7A9B, 0x7A9F, 0x7AA1, 
+	0x7AA5, 0x7AED, 0x7AF5, 0x7AF9, 0x7B01, 0x7B17, 0x7B19, 0x7B1D, 
+	0x7B2B, 0x7B35, 0x7B37, 0x7B3B, 0x7B4F, 0x7B55, 0x7B5F, 0x7B71, 
+	0x7B77, 0x7B8B, 0x7B9B, 0x7BA1, 0x7BA9, 0x7BAF, 0x7BB3, 0x7BC7, 
+	0x7BD3, 0x7BE9, 0x7BEB, 0x7BEF, 0x7BF1, 0x7BFD, 0x7C07, 0x7C19, 
+	0x7C1B, 0x7C31, 0x7C37, 0x7C49, 0x7C67, 0x7C69, 0x7C73, 0x7C81, 
+	0x7C8B, 0x7C93, 0x7CA3, 0x7CD5, 0x7CDB, 0x7CE5, 0x7CED, 0x7CF7, 
+	0x7D03, 0x7D09, 0x7D1B, 0x7D1D, 0x7D33, 0x7D39, 0x7D3B, 0x7D3F, 
+	0x7D45, 0x7D4D, 0x7D53, 0x7D59, 0x7D63, 0x7D75, 0x7D77, 0x7D8D, 
+	0x7D8F, 0x7D9F, 0x7DAD, 0x7DB7, 0x7DBD, 0x7DBF, 0x7DCB, 0x7DD5, 
+	0x7DE9, 0x7DED, 0x7DFB, 0x7E01, 0x7E05, 0x7E29, 0x7E2B, 0x7E2F, 
+	0x7E35, 0x7E41, 0x7E43, 0x7E47, 0x7E55, 0x7E61, 0x7E67, 0x7E6B, 
+	0x7E71, 0x7E73, 0x7E79, 0x7E7D, 0x7E91, 0x7E9B, 0x7E9D, 0x7EA7, 
+	0x7EAD, 0x7EB9, 0x7EBB, 0x7ED3, 0x7EDF, 0x7EEB, 0x7EF1, 0x7EF7, 
+	0x7EFB, 0x7F13, 0x7F15, 0x7F19, 0x7F31, 0x7F33, 0x7F39, 0x7F3D, 
+	0x7F43, 0x7F4B, 0x7F5B, 0x7F61, 0x7F63, 0x7F6D, 0x7F79, 0x7F87, 
+	0x7F8D, 0x7FAF, 0x7FB5, 0x7FC3, 0x7FC9, 0x7FCD, 0x7FCF, 0x7FED, 
+	0x8003, 0x800B, 0x800F, 0x8015, 0x801D, 0x8021, 0x8023, 0x803F, 
+	0x8041, 0x8047, 0x804B, 0x8065, 0x8077, 0x808D, 0x808F, 0x8095, 
+	0x80A5, 0x80AB, 0x80AD, 0x80BD, 0x80C9, 0x80CB, 0x80D7, 0x80DB, 
+	0x80E1, 0x80E7, 0x80F5, 0x80FF, 0x8105, 0x810D, 0x8119, 0x811D, 
+	0x812F, 0x8131, 0x813B, 0x8143, 0x8153, 0x8159, 0x815F, 0x817D, 
+	0x817F, 0x8189, 0x819B, 0x819D, 0x81A7, 0x81AF, 0x81B3, 0x81BB, 
+	0x81C7, 0x81DF, 0x8207, 0x8209, 0x8215, 0x821F, 0x8225, 0x8231, 
+	0x8233, 0x823F, 0x8243, 0x8245, 0x8249, 0x824F, 0x8261, 0x826F, 
+	0x827B, 0x8281, 0x8285, 0x8293, 0x82B1, 0x82B5, 0x82BD, 0x82C7, 
+	0x82CF, 0x82D5, 0x82DF, 0x82F1, 0x82F9, 0x82FD, 0x830B, 0x831B, 
+	0x8321, 0x8329, 0x832D, 0x8333, 0x8335, 0x833F, 0x8341, 0x834D, 
+	0x8351, 0x8353, 0x8357, 0x835D, 0x8365, 0x8369, 0x836F, 0x838F, 
+	0x83A7, 0x83B1, 0x83B9, 0x83CB, 0x83D5, 0x83D7, 0x83DD, 0x83E7, 
+	0x83E9, 0x83ED, 0x83FF, 0x8405, 0x8411, 0x8413, 0x8423, 0x8425, 
+	0x843B, 0x8441, 0x8447, 0x844F, 0x8461, 0x8465, 0x8477, 0x8483, 
+	0x848B, 0x8491, 0x8495, 0x84A9, 0x84AF, 0x84CD, 0x84E3, 0x84EF, 
+	0x84F1, 0x84F7, 0x8509, 0x850D, 0x854B, 0x854F, 0x8551, 0x855D, 
+	0x8563, 0x856D, 0x856F, 0x857B, 0x8587, 0x85A3, 0x85A5, 0x85A9, 
+	0x85B7, 0x85CD, 0x85D3, 0x85D5, 0x85DB, 0x85E1, 0x85EB, 0x85F9, 
+	0x85FD, 0x85FF, 0x8609, 0x860F, 0x8617, 0x8621, 0x862F, 0x8639, 
+	0x863F, 0x8641, 0x864D, 0x8663, 0x8675, 0x867D, 0x8687, 0x8699, 
+	0x86A5, 0x86A7, 0x86B3, 0x86B7, 0x86C3, 0x86C5, 0x86CF, 0x86D1, 
+	0x86D7, 0x86E9, 0x86EF, 0x86F5, 0x8717, 0x871D, 0x871F, 0x872B, 
+	0x872F, 0x8735, 0x8747, 0x8759, 0x875B, 0x876B, 0x8771, 0x8777, 
+	0x877F, 0x8785, 0x878F, 0x87A1, 0x87A9, 0x87B3, 0x87BB, 0x87C5, 
+	0x87C7, 0x87CB, 0x87DD, 0x87F7, 0x8803, 0x8819, 0x881B, 0x881F, 
+	0x8821, 0x8837, 0x883D, 0x8843, 0x8851, 0x8861, 0x8867, 0x887B, 
+	0x8885, 0x8891, 0x8893, 0x88A5, 0x88CF, 0x88D3, 0x88EB, 0x88ED, 
+	0x88F3, 0x88FD, 0x8909, 0x890B, 0x8911, 0x891B, 0x8923, 0x8927, 
+	0x892D, 0x8939, 0x8945, 0x894D, 0x8951, 0x8957, 0x8963, 0x8981, 
+	0x8995, 0x899B, 0x89B3, 0x89B9, 0x89C3, 0x89CF, 0x89D1, 0x89DB, 
+	0x89EF, 0x89F5, 0x89FB, 0x89FF, 0x8A0B, 0x8A19, 0x8A23, 0x8A35, 
+	0x8A41, 0x8A49, 0x8A4F, 0x8A5B, 0x8A5F, 0x8A6D, 0x8A77, 0x8A79, 
+	0x8A85, 0x8AA3, 0x8AB3, 0x8AB5, 0x8AC1, 0x8AC7, 0x8ACB, 0x8ACD, 
+	0x8AD1, 0x8AD7, 0x8AF1, 0x8AF5, 0x8B07, 0x8B09, 0x8B0D, 0x8B13, 
+	0x8B21, 0x8B57, 0x8B5D, 0x8B91, 0x8B93, 0x8BA3, 0x8BA9, 0x8BAF, 
+	0x8BBB, 0x8BD5, 0x8BD9, 0x8BDB, 0x8BE1, 0x8BF7, 0x8BFD, 0x8BFF, 
+	0x8C0B, 0x8C17, 0x8C1D, 0x8C27, 0x8C39, 0x8C3B, 0x8C47, 0x8C53, 
+	0x8C5D, 0x8C6F, 0x8C7B, 0x8C81, 0x8C89, 0x8C8F, 0x8C99, 0x8C9F, 
+	0x8CA7, 0x8CAB, 0x8CAD, 0x8CB1, 0x8CC5, 0x8CDD, 0x8CE3, 0x8CE9, 
+	0x8CF3, 0x8D01, 0x8D0B, 0x8D0D, 0x8D23, 0x8D29, 0x8D37, 0x8D41, 
+	0x8D5B, 0x8D5F, 0x8D71, 0x8D79, 0x8D85, 0x8D91, 0x8D9B, 0x8DA7, 
+	0x8DAD, 0x8DB5, 0x8DC5, 0x8DCB, 0x8DD3, 0x8DD9, 0x8DDF, 0x8DF5, 
+	0x8DF7, 0x8E01, 0x8E15, 0x8E1F, 0x8E25, 0x8E51, 0x8E63, 0x8E69, 
+	0x8E73, 0x8E75, 0x8E79, 0x8E7F, 0x8E8D, 0x8E91, 0x8EAB, 0x8EAF, 
+	0x8EB1, 0x8EBD, 0x8EC7, 0x8ECF, 0x8ED3, 0x8EDB, 0x8EE7, 0x8EEB, 
+	0x8EF7, 0x8EFF, 0x8F15, 0x8F1D, 0x8F23, 0x8F2D, 0x8F3F, 0x8F45, 
+	0x8F4B, 0x8F53, 0x8F59, 0x8F65, 0x8F69, 0x8F71, 0x8F83, 0x8F8D, 
+	0x8F99, 0x8F9F, 0x8FAB, 0x8FAD, 0x8FB3, 0x8FB7, 0x8FB9, 0x8FC9, 
+	0x8FD5, 0x8FE1, 0x8FEF, 0x8FF9, 0x9007, 0x900D, 0x9017, 0x9023, 
+	0x9025, 0x9031, 0x9037, 0x903B, 0x9041, 0x9043, 0x904F, 0x9053, 
+	0x906D, 0x9073, 0x9085, 0x908B, 0x9095, 0x909B, 0x909D, 0x90AF, 
+	0x90B9, 0x90C1, 0x90C5, 0x90DF, 0x90E9, 0x90FD, 0x9103, 0x9113, 
+	0x9127, 0x9133, 0x913D, 0x9145, 0x914F, 0x9151, 0x9161, 0x9167, 
+	0x917B, 0x9185, 0x9199, 0x919D, 0x91BB, 0x91BD, 0x91C1, 0x91C9, 
+	0x91D9, 0x91DB, 0x91ED, 0x91F1, 0x91F3, 0x91F9, 0x9203, 0x9215, 
+	0x9221, 0x922F, 0x9241, 0x9247, 0x9257, 0x926B, 0x9271, 0x9275, 
+	0x927D, 0x9283, 0x9287, 0x928D, 0x9299, 0x92A1, 0x92AB, 0x92AD, 
+	0x92B9, 0x92BF, 0x92C3, 0x92C5, 0x92CB, 0x92D5, 0x92D7, 0x92E7, 
+	0x92F3, 0x9301, 0x930B, 0x9311, 0x9319, 0x931F, 0x933B, 0x933D, 
+	0x9343, 0x9355, 0x9373, 0x9395, 0x9397, 0x93A7, 0x93B3, 0x93B5, 
+	0x93C7, 0x93D7, 0x93DD, 0x93E5, 0x93EF, 0x93F7, 0x9401, 0x9409, 
+	0x9413, 0x943F, 0x9445, 0x944B, 0x944F, 0x9463, 0x9467, 0x9469, 
+	0x946D, 0x947B, 0x9497, 0x949F, 0x94A5, 0x94B5, 0x94C3, 0x94E1, 
+	0x94E7, 0x9505, 0x9509, 0x9517, 0x9521, 0x9527, 0x952D, 0x9535, 
+	0x9539, 0x954B, 0x9557, 0x955D, 0x955F, 0x9575, 0x9581, 0x9589, 
+	0x958F, 0x959B, 0x959F, 0x95AD, 0x95B1, 0x95B7, 0x95B9, 0x95BD, 
+	0x95CF, 0x95E3, 0x95E9, 0x95F9, 0x961F, 0x962F, 0x9631, 0x9635, 
+	0x963B, 0x963D, 0x9665, 0x968F, 0x969D, 0x96A1, 0x96A7, 0x96A9, 
+	0x96C1, 0x96CB, 0x96D1, 0x96D3, 0x96E5, 0x96EF, 0x96FB, 0x96FD, 
+	0x970D, 0x970F, 0x9715, 0x9725, 0x972B, 0x9733, 0x9737, 0x9739, 
+	0x9743, 0x9749, 0x9751, 0x975B, 0x975D, 0x976F, 0x977F, 0x9787, 
+	0x9793, 0x97A5, 0x97B1, 0x97B7, 0x97C3, 0x97CD, 0x97D3, 0x97D9, 
+	0x97EB, 0x97F7, 0x9805, 0x9809, 0x980B, 0x9815, 0x9829, 0x982F, 
+	0x983B, 0x9841, 0x9851, 0x986B, 0x986F, 0x9881, 0x9883, 0x9887, 
+	0x98A7, 0x98B1, 0x98B9, 0x98BF, 0x98C3, 0x98C9, 0x98CF, 0x98DD, 
+	0x98E3, 0x98F5, 0x98F9, 0x98FB, 0x990D, 0x9917, 0x991F, 0x9929, 
+	0x9931, 0x993B, 0x993D, 0x9941, 0x9947, 0x9949, 0x9953, 0x997D, 
+	0x9985, 0x9991, 0x9995, 0x999B, 0x99AD, 0x99AF, 0x99BF, 0x99C7, 
+	0x99CB, 0x99CD, 0x99D7, 0x99E5, 0x99F1, 0x99FB, 0x9A0F, 0x9A13, 
+	0x9A1B, 0x9A25, 0x9A4B, 0x9A4F, 0x9A55, 0x9A57, 0x9A61, 0x9A75, 
+	0x9A7F, 0x9A8B, 0x9A91, 0x9A9D, 0x9AB7, 0x9AC3, 0x9AC7, 0x9ACF, 
+	0x9AEB, 0x9AF3, 0x9AF7, 0x9AFF, 0x9B17, 0x9B1D, 0x9B27, 0x9B2F, 
+	0x9B35, 0x9B45, 0x9B51, 0x9B59, 0x9B63, 0x9B6F, 0x9B77, 0x9B8D, 
+	0x9B93, 0x9B95, 0x9B9F, 0x9BA1, 0x9BA7, 0x9BB1, 0x9BB7, 0x9BBD, 
+	0x9BC5, 0x9BCB, 0x9BCF, 0x9BDD, 0x9BF9, 0x9C01, 0x9C11, 0x9C23, 
+	0x9C2B, 0x9C2F, 0x9C35, 0x9C49, 0x9C4D, 0x9C5F, 0x9C65, 0x9C67, 
+	0x9C7F, 0x9C97, 0x9C9D, 0x9CA3, 0x9CAF, 0x9CBB, 0x9CBF, 0x9CC1, 
+	0x9CD7, 0x9CD9, 0x9CE3, 0x9CE9, 0x9CF1, 0x9CFD, 0x9D01, 0x9D15, 
+	0x9D27, 0x9D2D, 0x9D31, 0x9D3D, 0x9D55, 0x9D5B, 0x9D61, 0x9D97, 
+	0x9D9F, 0x9DA5, 0x9DA9, 0x9DC3, 0x9DE7, 0x9DEB, 0x9DED, 0x9DF1, 
+	0x9E0B, 0x9E17, 0x9E23, 0x9E27, 0x9E2D, 0x9E33, 0x9E3B, 0x9E47, 
+	0x9E51, 0x9E53, 0x9E5F, 0x9E6F, 0x9E81, 0x9E87, 0x9E8F, 0x9E95, 
+	0x9EA1, 0x9EB3, 0x9EBD, 0x9EBF, 0x9EF5, 0x9EF9, 0x9EFB, 0x9F05, 
+	0x9F23, 0x9F2F, 0x9F37, 0x9F3B, 0x9F43, 0x9F53, 0x9F61, 0x9F6D, 
+	0x9F73, 0x9F77, 0x9F7D, 0x9F89, 0x9F8F, 0x9F91, 0x9F95, 0x9FA3, 
+	0x9FAF, 0x9FB3, 0x9FC1, 0x9FC7, 0x9FDF, 0x9FE5, 0x9FEB, 0x9FF5, 
+	0xA001, 0xA00D, 0xA021, 0xA033, 0xA039, 0xA03F, 0xA04F, 0xA057, 
+	0xA05B, 0xA061, 0xA075, 0xA079, 0xA099, 0xA09D, 0xA0AB, 0xA0B5, 
+	0xA0B7, 0xA0BD, 0xA0C9, 0xA0D9, 0xA0DB, 0xA0DF, 0xA0E5, 0xA0F1, 
+	0xA0F3, 0xA0FD, 0xA105, 0xA10B, 0xA10F, 0xA111, 0xA11B, 0xA129, 
+	0xA12F, 0xA135, 0xA141, 0xA153, 0xA175, 0xA17D, 0xA187, 0xA18D, 
+	0xA1A5, 0xA1AB, 0xA1AD, 0xA1B7, 0xA1C3, 0xA1C5, 0xA1E3, 0xA1ED, 
+	0xA1FB, 0xA207, 0xA213, 0xA223, 0xA229, 0xA22F, 0xA231, 0xA243, 
+	0xA247, 0xA24D, 0xA26B, 0xA279, 0xA27D, 0xA283, 0xA289, 0xA28B, 
+	0xA291, 0xA295, 0xA29B, 0xA2A9, 0xA2AF, 0xA2B3, 0xA2BB, 0xA2C5, 
+	0xA2D1, 0xA2D7, 0xA2F7, 0xA301, 0xA309, 0xA31F, 0xA321, 0xA32B, 
+	0xA331, 0xA349, 0xA351, 0xA355, 0xA373, 0xA379, 0xA37B, 0xA387, 
+	0xA397, 0xA39F, 0xA3A5, 0xA3A9, 0xA3AF, 0xA3B7, 0xA3C7, 0xA3D5, 
+	0xA3DB, 0xA3E1, 0xA3E5, 0xA3E7, 0xA3F1, 0xA3FD, 0xA3FF, 0xA40F, 
+	0xA41D, 0xA421, 0xA423, 0xA427, 0xA43B, 0xA44D, 0xA457, 0xA459, 
+	0xA463, 0xA469, 0xA475, 0xA493, 0xA49B, 0xA4AD, 0xA4B9, 0xA4C3, 
+	0xA4C5, 0xA4CB, 0xA4D1, 0xA4D5, 0xA4E1, 0xA4ED, 0xA4EF, 0xA4F3, 
+	0xA4FF, 0xA511, 0xA529, 0xA52B, 0xA535, 0xA53B, 0xA543, 0xA553, 
+	0xA55B, 0xA561, 0xA56D, 0xA577, 0xA585, 0xA58B, 0xA597, 0xA59D, 
+	0xA5A3, 0xA5A7, 0xA5A9, 0xA5C1, 0xA5C5, 0xA5CB, 0xA5D3, 0xA5D9, 
+	0xA5DD, 0xA5DF, 0xA5E3, 0xA5E9, 0xA5F7, 0xA5FB, 0xA603, 0xA60D, 
+	0xA625, 0xA63D, 0xA649, 0xA64B, 0xA651, 0xA65D, 0xA673, 0xA691, 
+	0xA693, 0xA699, 0xA6AB, 0xA6B5, 0xA6BB, 0xA6C1, 0xA6C9, 0xA6CD, 
+	0xA6CF, 0xA6D5, 0xA6DF, 0xA6E7, 0xA6F1, 0xA6F7, 0xA6FF, 0xA70F, 
+	0xA715, 0xA723, 0xA729, 0xA72D, 0xA745, 0xA74D, 0xA757, 0xA759, 
+	0xA765, 0xA76B, 0xA76F, 0xA793, 0xA795, 0xA7AB, 0xA7B1, 0xA7B9, 
+	0xA7BF, 0xA7C9, 0xA7D1, 0xA7D7, 0xA7E3, 0xA7ED, 0xA7FB, 0xA805, 
+	0xA80B, 0xA81D, 0xA829, 0xA82B, 0xA837, 0xA83B, 0xA855, 0xA85F, 
+	0xA86D, 0xA87D, 0xA88F, 0xA897, 0xA8A9, 0xA8B5, 0xA8C1, 0xA8C7, 
+	0xA8D7, 0xA8E5, 0xA8FD, 0xA907, 0xA913, 0xA91B, 0xA931, 0xA937, 
+	0xA939, 0xA943, 0xA97F, 0xA985, 0xA987, 0xA98B, 0xA993, 0xA9A3, 
+	0xA9B1, 0xA9BB, 0xA9C1, 0xA9D9, 0xA9DF, 0xA9EB, 0xA9FD, 0xAA15, 
+	0xAA17, 0xAA35, 0xAA39, 0xAA3B, 0xAA47, 0xAA4D, 0xAA57, 0xAA59, 
+	0xAA5D, 0xAA6B, 0xAA71, 0xAA81, 0xAA83, 0xAA8D, 0xAA95, 0xAAAB, 
+	0xAABF, 0xAAC5, 0xAAC9, 0xAAE9, 0xAAEF, 0xAB01, 0xAB05, 0xAB07, 
+	0xAB0B, 0xAB0D, 0xAB11, 0xAB19, 0xAB4D, 0xAB5B, 0xAB71, 0xAB73, 
+	0xAB89, 0xAB9D, 0xABA7, 0xABAF, 0xABB9, 0xABBB, 0xABC1, 0xABC5, 
+	0xABD3, 0xABD7, 0xABDD, 0xABF1, 0xABF5, 0xABFB, 0xABFD, 0xAC09, 
+	0xAC15, 0xAC1B, 0xAC27, 0xAC37, 0xAC39, 0xAC45, 0xAC4F, 0xAC57, 
+	0xAC5B, 0xAC61, 0xAC63, 0xAC7F, 0xAC8B, 0xAC93, 0xAC9D, 0xACA9, 
+	0xACAB, 0xACAF, 0xACBD, 0xACD9, 0xACE1, 0xACE7, 0xACEB, 0xACED, 
+	0xACF1, 0xACF7, 0xACF9, 0xAD05, 0xAD3F, 0xAD45, 0xAD53, 0xAD5D, 
+	0xAD5F, 0xAD65, 0xAD81, 0xADA1, 0xADA5, 0xADC3, 0xADCB, 0xADD1, 
+	0xADD5, 0xADDB, 0xADE7, 0xADF3, 0xADF5, 0xADF9, 0xADFF, 0xAE05, 
+	0xAE13, 0xAE23, 0xAE2B, 0xAE49, 0xAE4D, 0xAE4F, 0xAE59, 0xAE61, 
+	0xAE67, 0xAE6B, 0xAE71, 0xAE8B, 0xAE8F, 0xAE9B, 0xAE9D, 0xAEA7, 
+	0xAEB9, 0xAEC5, 0xAED1, 0xAEE3, 0xAEE5, 0xAEE9, 0xAEF5, 0xAEFD, 
+	0xAF09, 0xAF13, 0xAF27, 0xAF2B, 0xAF33, 0xAF43, 0xAF4F, 0xAF57, 
+	0xAF5D, 0xAF6D, 0xAF75, 0xAF7F, 0xAF8B, 0xAF99, 0xAF9F, 0xAFA3, 
+	0xAFAB, 0xAFB7, 0xAFBB, 0xAFCF, 0xAFD5, 0xAFFD, 0xB005, 0xB015, 
+	0xB01B, 0xB03F, 0xB041, 0xB047, 0xB04B, 0xB051, 0xB053, 0xB069, 
+	0xB07B, 0xB07D, 0xB087, 0xB08D, 0xB0B1, 0xB0BF, 0xB0CB, 0xB0CF, 
+	0xB0E1, 0xB0E9, 0xB0ED, 0xB0FB, 0xB105, 0xB107, 0xB111, 0xB119, 
+	0xB11D, 0xB11F, 0xB131, 0xB141, 0xB14D, 0xB15B, 0xB165, 0xB173, 
+	0xB179, 0xB17F, 0xB1A9, 0xB1B3, 0xB1B9, 0xB1BF, 0xB1D3, 0xB1DD, 
+	0xB1E5, 0xB1F1, 0xB1F5, 0xB201, 0xB213, 0xB215, 0xB21F, 0xB22D, 
+	0xB23F, 0xB249, 0xB25B, 0xB263, 0xB269, 0xB26D, 0xB27B, 0xB281, 
+	0xB28B, 0xB2A9, 0xB2B7, 0xB2BD, 0xB2C3, 0xB2C7, 0xB2D3, 0xB2F9, 
+	0xB2FD, 0xB2FF, 0xB303, 0xB309, 0xB311, 0xB31D, 0xB327, 0xB32D, 
+	0xB33F, 0xB345, 0xB377, 0xB37D, 0xB381, 0xB387, 0xB393, 0xB39B, 
+	0xB3A5, 0xB3C5, 0xB3CB, 0xB3E1, 0xB3E3, 0xB3ED, 0xB3F9, 0xB40B, 
+	0xB40D, 0xB413, 0xB417, 0xB435, 0xB43D, 0xB443, 0xB449, 0xB45B, 
+	0xB465, 0xB467, 0xB46B, 0xB477, 0xB48B, 0xB495, 0xB49D, 0xB4B5, 
+	0xB4BF, 0xB4C1, 0xB4C7, 0xB4DD, 0xB4E3, 0xB4E5, 0xB4F7, 0xB501, 
+	0xB50D, 0xB50F, 0xB52D, 0xB53F, 0xB54B, 0xB567, 0xB569, 0xB56F, 
+	0xB573, 0xB579, 0xB587, 0xB58D, 0xB599, 0xB5A3, 0xB5AB, 0xB5AF, 
+	0xB5BB, 0xB5D5, 0xB5DF, 0xB5E7, 0xB5ED, 0xB5FD, 0xB5FF, 0xB609, 
+	0xB61B, 0xB629, 0xB62F, 0xB633, 0xB639, 0xB647, 0xB657, 0xB659, 
+	0xB65F, 0xB663, 0xB66F, 0xB683, 0xB687, 0xB69B, 0xB69F, 0xB6A5, 
+	0xB6B1, 0xB6B3, 0xB6D7, 0xB6DB, 0xB6E1, 0xB6E3, 0xB6ED, 0xB6EF, 
+	0xB705, 0xB70D, 0xB713, 0xB71D, 0xB729, 0xB735, 0xB747, 0xB755, 
+	0xB76D, 0xB791, 0xB795, 0xB7A9, 0xB7C1, 0xB7CB, 0xB7D1, 0xB7D3, 
+	0xB7EF, 0xB7F5, 0xB807, 0xB80F, 0xB813, 0xB819, 0xB821, 0xB827, 
+	0xB82B, 0xB82D, 0xB839, 0xB855, 0xB867, 0xB875, 0xB885, 0xB893, 
+	0xB8A5, 0xB8AF, 0xB8B7, 0xB8BD, 0xB8C1, 0xB8C7, 0xB8CD, 0xB8D5, 
+	0xB8EB, 0xB8F7, 0xB8F9, 0xB903, 0xB915, 0xB91B, 0xB91D, 0xB92F, 
+	0xB939, 0xB93B, 0xB947, 0xB951, 0xB963, 0xB983, 0xB989, 0xB98D, 
+	0xB993, 0xB999, 0xB9A1, 0xB9A7, 0xB9AD, 0xB9B7, 0xB9CB, 0xB9D1, 
+	0xB9DD, 0xB9E7, 0xB9EF, 0xB9F9, 0xBA07, 0xBA0D, 0xBA17, 0xBA25, 
+	0xBA29, 0xBA2B, 0xBA41, 0xBA53, 0xBA55, 0xBA5F, 0xBA61, 0xBA65, 
+	0xBA79, 0xBA7D, 0xBA7F, 0xBAA1, 0xBAA3, 0xBAAF, 0xBAB5, 0xBABF, 
+	0xBAC1, 0xBACB, 0xBADD, 0xBAE3, 0xBAF1, 0xBAFD, 0xBB09, 0xBB1F, 
+	0xBB27, 0xBB2D, 0xBB3D, 0xBB43, 0xBB4B, 0xBB4F, 0xBB5B, 0xBB61, 
+	0xBB69, 0xBB6D, 0xBB91, 0xBB97, 0xBB9D, 0xBBB1, 0xBBC9, 0xBBCF, 
+	0xBBDB, 0xBBED, 0xBBF7, 0xBBF9, 0xBC03, 0xBC1D, 0xBC23, 0xBC33, 
+	0xBC3B, 0xBC41, 0xBC45, 0xBC5D, 0xBC6F, 0xBC77, 0xBC83, 0xBC8F, 
+	0xBC99, 0xBCAB, 0xBCB7, 0xBCB9, 0xBCD1, 0xBCD5, 0xBCE1, 0xBCF3, 
+	0xBCFF, 0xBD0D, 0xBD17, 0xBD19, 0xBD1D, 0xBD35, 0xBD41, 0xBD4F, 
+	0xBD59, 0xBD5F, 0xBD61, 0xBD67, 0xBD6B, 0xBD71, 0xBD8B, 0xBD8F, 
+	0xBD95, 0xBD9B, 0xBD9D, 0xBDB3, 0xBDBB, 0xBDCD, 0xBDD1, 0xBDE3, 
+	0xBDEB, 0xBDEF, 0xBE07, 0xBE09, 0xBE15, 0xBE21, 0xBE25, 0xBE27, 
+	0xBE5B, 0xBE5D, 0xBE6F, 0xBE75, 0xBE79, 0xBE7F, 0xBE8B, 0xBE8D, 
+	0xBE93, 0xBE9F, 0xBEA9, 0xBEB1, 0xBEB5, 0xBEB7, 0xBECF, 0xBED9, 
+	0xBEDB, 0xBEE5, 0xBEE7, 0xBEF3, 0xBEF9, 0xBF0B, 0xBF33, 0xBF39, 
+	0xBF4D, 0xBF5D, 0xBF5F, 0xBF6B, 0xBF71, 0xBF7B, 0xBF87, 0xBF89, 
+	0xBF8D, 0xBF93, 0xBFA1, 0xBFAD, 0xBFB9, 0xBFCF, 0xBFD5, 0xBFDD, 
+	0xBFE1, 0xBFE3, 0xBFF3, 0xC005, 0xC011, 0xC013, 0xC019, 0xC029, 
+	0xC02F, 0xC031, 0xC037, 0xC03B, 0xC047, 0xC065, 0xC06D, 0xC07D, 
+	0xC07F, 0xC091, 0xC09B, 0xC0B3, 0xC0B5, 0xC0BB, 0xC0D3, 0xC0D7, 
+	0xC0D9, 0xC0EF, 0xC0F1, 0xC101, 0xC103, 0xC109, 0xC115, 0xC119, 
+	0xC12B, 0xC133, 0xC137, 0xC145, 0xC149, 0xC15B, 0xC173, 0xC179, 
+	0xC17B, 0xC181, 0xC18B, 0xC18D, 0xC197, 0xC1BD, 0xC1C3, 0xC1CD, 
+	0xC1DB, 0xC1E1, 0xC1E7, 0xC1FF, 0xC203, 0xC205, 0xC211, 0xC221, 
+	0xC22F, 0xC23F, 0xC24B, 0xC24D, 0xC253, 0xC25D, 0xC277, 0xC27B, 
+	0xC27D, 0xC289, 0xC28F, 0xC293, 0xC29F, 0xC2A7, 0xC2B3, 0xC2BD, 
+	0xC2CF, 0xC2D5, 0xC2E3, 0xC2FF, 0xC301, 0xC307, 0xC311, 0xC313, 
+	0xC317, 0xC325, 0xC347, 0xC349, 0xC34F, 0xC365, 0xC367, 0xC371, 
+	0xC37F, 0xC383, 0xC385, 0xC395, 0xC39D, 0xC3A7, 0xC3AD, 0xC3B5, 
+	0xC3BF, 0xC3C7, 0xC3CB, 0xC3D1, 0xC3D3, 0xC3E3, 0xC3E9, 0xC3EF, 
+	0xC401, 0xC41F, 0xC42D, 0xC433, 0xC437, 0xC455, 0xC457, 0xC461, 
+	0xC46F, 0xC473, 0xC487, 0xC491, 0xC499, 0xC49D, 0xC4A5, 0xC4B7, 
+	0xC4BB, 0xC4C9, 0xC4CF, 0xC4D3, 0xC4EB, 0xC4F1, 0xC4F7, 0xC509, 
+	0xC51B, 0xC51D, 0xC541, 0xC547, 0xC551, 0xC55F, 0xC56B, 0xC56F, 
+	0xC575, 0xC577, 0xC595, 0xC59B, 0xC59F, 0xC5A1, 0xC5A7, 0xC5C3, 
+	0xC5D7, 0xC5DB, 0xC5EF, 0xC5FB, 0xC613, 0xC623, 0xC635, 0xC641, 
+	0xC64F, 0xC655, 0xC659, 0xC665, 0xC685, 0xC691, 0xC697, 0xC6A1, 
+	0xC6A9, 0xC6B3, 0xC6B9, 0xC6CB, 0xC6CD, 0xC6DD, 0xC6EB, 0xC6F1, 
+	0xC707, 0xC70D, 0xC719, 0xC71B, 0xC72D, 0xC731, 0xC739, 0xC757, 
+	0xC763, 0xC767, 0xC773, 0xC775, 0xC77F, 0xC7A5, 0xC7BB, 0xC7BD, 
+	0xC7C1, 0xC7CF, 0xC7D5, 0xC7E1, 0xC7F9, 0xC7FD, 0xC7FF, 0xC803, 
+	0xC811, 0xC81D, 0xC827, 0xC829, 0xC839, 0xC83F, 0xC853, 0xC857, 
+	0xC86B, 0xC881, 0xC88D, 0xC88F, 0xC893, 0xC895, 0xC8A1, 0xC8B7, 
+	0xC8CF, 0xC8D5, 0xC8DB, 0xC8DD, 0xC8E3, 0xC8E7, 0xC8ED, 0xC8EF, 
+	0xC8F9, 0xC905, 0xC911, 0xC917, 0xC919, 0xC91F, 0xC92F, 0xC937, 
+	0xC93D, 0xC941, 0xC953, 0xC95F, 0xC96B, 0xC979, 0xC97D, 0xC989, 
+	0xC98F, 0xC997, 0xC99D, 0xC9AF, 0xC9B5, 0xC9BF, 0xC9CB, 0xC9D9, 
+	0xC9DF, 0xC9E3, 0xC9EB, 0xCA01, 0xCA07, 0xCA09, 0xCA25, 0xCA37, 
+	0xCA39, 0xCA4B, 0xCA55, 0xCA5B, 0xCA69, 0xCA73, 0xCA75, 0xCA7F, 
+	0xCA8D, 0xCA93, 0xCA9D, 0xCA9F, 0xCAB5, 0xCABB, 0xCAC3, 0xCAC9, 
+	0xCAD9, 0xCAE5, 0xCAED, 0xCB03, 0xCB05, 0xCB09, 0xCB17, 0xCB29, 
+	0xCB35, 0xCB3B, 0xCB53, 0xCB59, 0xCB63, 0xCB65, 0xCB71, 0xCB87, 
+	0xCB99, 0xCB9F, 0xCBB3, 0xCBB9, 0xCBC3, 0xCBD1, 0xCBD5, 0xCBD7, 
+	0xCBDD, 0xCBE9, 0xCBFF, 0xCC0D, 0xCC19, 0xCC1D, 0xCC23, 0xCC2B, 
+	0xCC41, 0xCC43, 0xCC4D, 0xCC59, 0xCC61, 0xCC89, 0xCC8B, 0xCC91, 
+	0xCC9B, 0xCCA3, 0xCCA7, 0xCCD1, 0xCCE5, 0xCCE9, 0xCD09, 0xCD15, 
+	0xCD1F, 0xCD25, 0xCD31, 0xCD3D, 0xCD3F, 0xCD49, 0xCD51, 0xCD57, 
+	0xCD5B, 0xCD63, 0xCD67, 0xCD81, 0xCD93, 0xCD97, 0xCD9F, 0xCDBB, 
+	0xCDC1, 0xCDD3, 0xCDD9, 0xCDE5, 0xCDE7, 0xCDF1, 0xCDF7, 0xCDFD, 
+	0xCE0B, 0xCE15, 0xCE21, 0xCE2F, 0xCE47, 0xCE4D, 0xCE51, 0xCE65, 
+	0xCE7B, 0xCE7D, 0xCE8F, 0xCE93, 0xCE99, 0xCEA5, 0xCEA7, 0xCEB7, 
+	0xCEC9, 0xCED7, 0xCEDD, 0xCEE3, 0xCEE7, 0xCEED, 0xCEF5, 0xCF07, 
+	0xCF0B, 0xCF19, 0xCF37, 0xCF3B, 0xCF4D, 0xCF55, 0xCF5F, 0xCF61, 
+	0xCF65, 0xCF6D, 0xCF79, 0xCF7D, 0xCF89, 0xCF9B, 0xCF9D, 0xCFA9, 
+	0xCFB3, 0xCFB5, 0xCFC5, 0xCFCD, 0xCFD1, 0xCFEF, 0xCFF1, 0xCFF7, 
+	0xD013, 0xD015, 0xD01F, 0xD021, 0xD033, 0xD03D, 0xD04B, 0xD04F, 
+	0xD069, 0xD06F, 0xD081, 0xD085, 0xD099, 0xD09F, 0xD0A3, 0xD0AB, 
+	0xD0BD, 0xD0C1, 0xD0CD, 0xD0E7, 0xD0FF, 0xD103, 0xD117, 0xD12D, 
+	0xD12F, 0xD141, 0xD157, 0xD159, 0xD15D, 0xD169, 0xD16B, 0xD171, 
+	0xD177, 0xD17D, 0xD181, 0xD187, 0xD195, 0xD199, 0xD1B1, 0xD1BD, 
+	0xD1C3, 0xD1D5, 0xD1D7, 0xD1E3, 0xD1FF, 0xD20D, 0xD211, 0xD217, 
+	0xD21F, 0xD235, 0xD23B, 0xD247, 0xD259, 0xD261, 0xD265, 0xD279, 
+	0xD27F, 0xD283, 0xD289, 0xD28B, 0xD29D, 0xD2A3, 0xD2A7, 0xD2B3, 
+	0xD2BF, 0xD2C7, 0xD2E3, 0xD2E9, 0xD2F1, 0xD2FB, 0xD2FD, 0xD315, 
+	0xD321, 0xD32B, 0xD343, 0xD34B, 0xD355, 0xD369, 0xD375, 0xD37B, 
+	0xD387, 0xD393, 0xD397, 0xD3A5, 0xD3B1, 0xD3C9, 0xD3EB, 0xD3FD, 
+	0xD405, 0xD40F, 0xD415, 0xD427, 0xD42F, 0xD433, 0xD43B, 0xD44B, 
+	0xD459, 0xD45F, 0xD463, 0xD469, 0xD481, 0xD483, 0xD489, 0xD48D, 
+	0xD493, 0xD495, 0xD4A5, 0xD4AB, 0xD4B1, 0xD4C5, 0xD4DD, 0xD4E1, 
+	0xD4E3, 0xD4E7, 0xD4F5, 0xD4F9, 0xD50B, 0xD50D, 0xD513, 0xD51F, 
+	0xD523, 0xD531, 0xD535, 0xD537, 0xD549, 0xD559, 0xD55F, 0xD565, 
+	0xD567, 0xD577, 0xD58B, 0xD591, 0xD597, 0xD5B5, 0xD5B9, 0xD5C1, 
+	0xD5C7, 0xD5DF, 0xD5EF, 0xD5F5, 0xD5FB, 0xD603, 0xD60F, 0xD62D, 
+	0xD631, 0xD643, 0xD655, 0xD65D, 0xD661, 0xD67B, 0xD685, 0xD687, 
+	0xD69D, 0xD6A5, 0xD6AF, 0xD6BD, 0xD6C3, 0xD6C7, 0xD6D9, 0xD6E1, 
+	0xD6ED, 0xD709, 0xD70B, 0xD711, 0xD715, 0xD721, 0xD727, 0xD73F, 
+	0xD745, 0xD74D, 0xD757, 0xD76B, 0xD77B, 0xD783, 0xD7A1, 0xD7A7, 
+	0xD7AD, 0xD7B1, 0xD7B3, 0xD7BD, 0xD7CB, 0xD7D1, 0xD7DB, 0xD7FB, 
+	0xD811, 0xD823, 0xD825, 0xD829, 0xD82B, 0xD82F, 0xD837, 0xD84D, 
+	0xD855, 0xD867, 0xD873, 0xD88F, 0xD891, 0xD8A1, 0xD8AD, 0xD8BF, 
+	0xD8CD, 0xD8D7, 0xD8E9, 0xD8F5, 0xD8FB, 0xD91B, 0xD925, 0xD933, 
+	0xD939, 0xD943, 0xD945, 0xD94F, 0xD951, 0xD957, 0xD96D, 0xD96F, 
+	0xD973, 0xD979, 0xD981, 0xD98B, 0xD991, 0xD99F, 0xD9A5, 0xD9A9, 
+	0xD9B5, 0xD9D3, 0xD9EB, 0xD9F1, 0xD9F7, 0xD9FF, 0xDA05, 0xDA09, 
+	0xDA0B, 0xDA0F, 0xDA15, 0xDA1D, 0xDA23, 0xDA29, 0xDA3F, 0xDA51, 
+	0xDA59, 0xDA5D, 0xDA5F, 0xDA71, 0xDA77, 0xDA7B, 0xDA7D, 0xDA8D, 
+	0xDA9F, 0xDAB3, 0xDABD, 0xDAC3, 0xDAC9, 0xDAE7, 0xDAE9, 0xDAF5, 
+	0xDB11, 0xDB17, 0xDB1D, 0xDB23, 0xDB25, 0xDB31, 0xDB3B, 0xDB43, 
+	0xDB55, 0xDB67, 0xDB6B, 0xDB73, 0xDB85, 0xDB8F, 0xDB91, 0xDBAD, 
+	0xDBAF, 0xDBB9, 0xDBC7, 0xDBCB, 0xDBCD, 0xDBEB, 0xDBF7, 0xDC0D, 
+	0xDC27, 0xDC31, 0xDC39, 0xDC3F, 0xDC49, 0xDC51, 0xDC61, 0xDC6F, 
+	0xDC75, 0xDC7B, 0xDC85, 0xDC93, 0xDC99, 0xDC9D, 0xDC9F, 0xDCA9, 
+	0xDCB5, 0xDCB7, 0xDCBD, 0xDCC7, 0xDCCF, 0xDCD3, 0xDCD5, 0xDCDF, 
+	0xDCF9, 0xDD0F, 0xDD15, 0xDD17, 0xDD23, 0xDD35, 0xDD39, 0xDD53, 
+	0xDD57, 0xDD5F, 0xDD69, 0xDD6F, 0xDD7D, 0xDD87, 0xDD89, 0xDD9B, 
+	0xDDA1, 0xDDAB, 0xDDBF, 0xDDC5, 0xDDCB, 0xDDCF, 0xDDE7, 0xDDE9, 
+	0xDDED, 0xDDF5, 0xDDFB, 0xDE0B, 0xDE19, 0xDE29, 0xDE3B, 0xDE3D, 
+	0xDE41, 0xDE4D, 0xDE4F, 0xDE59, 0xDE5B, 0xDE61, 0xDE6D, 0xDE77, 
+	0xDE7D, 0xDE83, 0xDE97, 0xDE9D, 0xDEA1, 0xDEA7, 0xDECD, 0xDED1, 
+	0xDED7, 0xDEE3, 0xDEF1, 0xDEF5, 0xDF01, 0xDF09, 0xDF13, 0xDF1F, 
+	0xDF2B, 0xDF33, 0xDF37, 0xDF3D, 0xDF4B, 0xDF55, 0xDF5B, 0xDF67, 
+	0xDF69, 0xDF73, 0xDF85, 0xDF87, 0xDF99, 0xDFA3, 0xDFAB, 0xDFB5, 
+	0xDFB7, 0xDFC3, 0xDFC7, 0xDFD5, 0xDFF1, 0xDFF3, 0xE003, 0xE005, 
+	0xE017, 0xE01D, 0xE027, 0xE02D, 0xE035, 0xE045, 0xE053, 0xE071, 
+	0xE07B, 0xE08F, 0xE095, 0xE09F, 0xE0B7, 0xE0B9, 0xE0D5, 0xE0D7, 
+	0xE0E3, 0xE0F3, 0xE0F9, 0xE101, 0xE125, 0xE129, 0xE131, 0xE135, 
+	0xE143, 0xE14F, 0xE159, 0xE161, 0xE16D, 0xE171, 0xE177, 0xE17F, 
+	0xE183, 0xE189, 0xE197, 0xE1AD, 0xE1B5, 0xE1BB, 0xE1BF, 0xE1C1, 
+	0xE1CB, 0xE1D1, 0xE1E5, 0xE1EF, 0xE1F7, 0xE1FD, 0xE203, 0xE219, 
+	0xE22B, 0xE22D, 0xE23D, 0xE243, 0xE257, 0xE25B, 0xE275, 0xE279, 
+	0xE287, 0xE29D, 0xE2AB, 0xE2AF, 0xE2BB, 0xE2C1, 0xE2C9, 0xE2CD, 
+	0xE2D3, 0xE2D9, 0xE2F3, 0xE2FD, 0xE2FF, 0xE311, 0xE323, 0xE327, 
+	0xE329, 0xE339, 0xE33B, 0xE34D, 0xE351, 0xE357, 0xE35F, 0xE363, 
+	0xE369, 0xE375, 0xE377, 0xE37D, 0xE383, 0xE39F, 0xE3C5, 0xE3C9, 
+	0xE3D1, 0xE3E1, 0xE3FB, 0xE3FF, 0xE401, 0xE40B, 0xE417, 0xE419, 
+	0xE423, 0xE42B, 0xE431, 0xE43B, 0xE447, 0xE449, 0xE453, 0xE455, 
+	0xE46D, 0xE471, 0xE48F, 0xE4A9, 0xE4AF, 0xE4B5, 0xE4C7, 0xE4CD, 
+	0xE4D3, 0xE4E9, 0xE4EB, 0xE4F5, 0xE507, 0xE521, 0xE525, 0xE537, 
+	0xE53F, 0xE545, 0xE54B, 0xE557, 0xE567, 0xE56D, 0xE575, 0xE585, 
+	0xE58B, 0xE593, 0xE5A3, 0xE5A5, 0xE5CF, 0xE609, 0xE611, 0xE615, 
+	0xE61B, 0xE61D, 0xE621, 0xE629, 0xE639, 0xE63F, 0xE653, 0xE657, 
+	0xE663, 0xE66F, 0xE675, 0xE681, 0xE683, 0xE68D, 0xE68F, 0xE695, 
+	0xE6AB, 0xE6AD, 0xE6B7, 0xE6BD, 0xE6C5, 0xE6CB, 0xE6D5, 0xE6E3, 
+	0xE6E9, 0xE6EF, 0xE6F3, 0xE705, 0xE70D, 0xE717, 0xE71F, 0xE72F, 
+	0xE73D, 0xE747, 0xE749, 0xE753, 0xE755, 0xE761, 0xE767, 0xE76B, 
+	0xE77F, 0xE789, 0xE791, 0xE7C5, 0xE7CD, 0xE7D7, 0xE7DD, 0xE7DF, 
+	0xE7E9, 0xE7F1, 0xE7FB, 0xE801, 0xE807, 0xE80F, 0xE819, 0xE81B, 
+	0xE831, 0xE833, 0xE837, 0xE83D, 0xE84B, 0xE84F, 0xE851, 0xE869, 
+	0xE875, 0xE879, 0xE893, 0xE8A5, 0xE8A9, 0xE8AF, 0xE8BD, 0xE8DB, 
+	0xE8E1, 0xE8E5, 0xE8EB, 0xE8ED, 0xE903, 0xE90B, 0xE90F, 0xE915, 
+	0xE917, 0xE92D, 0xE933, 0xE93B, 0xE94B, 0xE951, 0xE95F, 0xE963, 
+	0xE969, 0xE97B, 0xE983, 0xE98F, 0xE995, 0xE9A1, 0xE9B9, 0xE9D7, 
+	0xE9E7, 0xE9EF, 0xEA11, 0xEA19, 0xEA2F, 0xEA35, 0xEA43, 0xEA4D, 
+	0xEA5F, 0xEA6D, 0xEA71, 0xEA7D, 0xEA85, 0xEA89, 0xEAAD, 0xEAB3, 
+	0xEAB9, 0xEABB, 0xEAC5, 0xEAC7, 0xEACB, 0xEADF, 0xEAE5, 0xEAEB, 
+	0xEAF5, 0xEB01, 0xEB07, 0xEB09, 0xEB31, 0xEB39, 0xEB3F, 0xEB5B, 
+	0xEB61, 0xEB63, 0xEB6F, 0xEB81, 0xEB85, 0xEB9D, 0xEBAB, 0xEBB1, 
+	0xEBB7, 0xEBC1, 0xEBD5, 0xEBDF, 0xEBED, 0xEBFD, 0xEC0B, 0xEC1B, 
+	0xEC21, 0xEC29, 0xEC4D, 0xEC51, 0xEC5D, 0xEC69, 0xEC6F, 0xEC7B, 
+	0xECAD, 0xECB9, 0xECBF, 0xECC3, 0xECC9, 0xECCF, 0xECD7, 0xECDD, 
+	0xECE7, 0xECE9, 0xECF3, 0xECF5, 0xED07, 0xED11, 0xED1F, 0xED2F, 
+	0xED37, 0xED3D, 0xED41, 0xED55, 0xED59, 0xED5B, 0xED65, 0xED6B, 
+	0xED79, 0xED8B, 0xED95, 0xEDBB, 0xEDC5, 0xEDD7, 0xEDD9, 0xEDE3, 
+	0xEDE5, 0xEDF1, 0xEDF5, 0xEDF7, 0xEDFB, 0xEE09, 0xEE0F, 0xEE19, 
+	0xEE21, 0xEE49, 0xEE4F, 0xEE63, 0xEE67, 0xEE73, 0xEE7B, 0xEE81, 
+	0xEEA3, 0xEEAB, 0xEEC1, 0xEEC9, 0xEED5, 0xEEDF, 0xEEE1, 0xEEF1, 
+	0xEF1B, 0xEF27, 0xEF2F, 0xEF45, 0xEF4D, 0xEF63, 0xEF6B, 0xEF71, 
+	0xEF93, 0xEF95, 0xEF9B, 0xEF9F, 0xEFAD, 0xEFB3, 0xEFC3, 0xEFC5, 
+	0xEFDB, 0xEFE1, 0xEFE9, 0xF001, 0xF017, 0xF01D, 0xF01F, 0xF02B, 
+	0xF02F, 0xF035, 0xF043, 0xF047, 0xF04F, 0xF067, 0xF06B, 0xF071, 
+	0xF077, 0xF079, 0xF08F, 0xF0A3, 0xF0A9, 0xF0AD, 0xF0BB, 0xF0BF, 
+	0xF0C5, 0xF0CB, 0xF0D3, 0xF0D9, 0xF0E3, 0xF0E9, 0xF0F1, 0xF0F7, 
+	0xF107, 0xF115, 0xF11B, 0xF121, 0xF137, 0xF13D, 0xF155, 0xF175, 
+	0xF17B, 0xF18D, 0xF193, 0xF1A5, 0xF1AF, 0xF1B7, 0xF1D5, 0xF1E7, 
+	0xF1ED, 0xF1FD, 0xF209, 0xF20F, 0xF21B, 0xF21D, 0xF223, 0xF227, 
+	0xF233, 0xF23B, 0xF241, 0xF257, 0xF25F, 0xF265, 0xF269, 0xF277, 
+	0xF281, 0xF293, 0xF2A7, 0xF2B1, 0xF2B3, 0xF2B9, 0xF2BD, 0xF2BF, 
+	0xF2DB, 0xF2ED, 0xF2EF, 0xF2F9, 0xF2FF, 0xF305, 0xF30B, 0xF319, 
+	0xF341, 0xF359, 0xF35B, 0xF35F, 0xF367, 0xF373, 0xF377, 0xF38B, 
+	0xF38F, 0xF3AF, 0xF3C1, 0xF3D1, 0xF3D7, 0xF3FB, 0xF403, 0xF409, 
+	0xF40D, 0xF413, 0xF421, 0xF425, 0xF42B, 0xF445, 0xF44B, 0xF455, 
+	0xF463, 0xF475, 0xF47F, 0xF485, 0xF48B, 0xF499, 0xF4A3, 0xF4A9, 
+	0xF4AF, 0xF4BD, 0xF4C3, 0xF4DB, 0xF4DF, 0xF4ED, 0xF503, 0xF50B, 
+	0xF517, 0xF521, 0xF529, 0xF535, 0xF547, 0xF551, 0xF563, 0xF56B, 
+	0xF583, 0xF58D, 0xF595, 0xF599, 0xF5B1, 0xF5B7, 0xF5C9, 0xF5CF, 
+	0xF5D1, 0xF5DB, 0xF5F9, 0xF5FB, 0xF605, 0xF607, 0xF60B, 0xF60D, 
+	0xF635, 0xF637, 0xF653, 0xF65B, 0xF661, 0xF667, 0xF679, 0xF67F, 
+	0xF689, 0xF697, 0xF69B, 0xF6AD, 0xF6CB, 0xF6DD, 0xF6DF, 0xF6EB, 
+	0xF709, 0xF70F, 0xF72D, 0xF731, 0xF743, 0xF74F, 0xF751, 0xF755, 
+	0xF763, 0xF769, 0xF773, 0xF779, 0xF781, 0xF787, 0xF791, 0xF79D, 
+	0xF79F, 0xF7A5, 0xF7B1, 0xF7BB, 0xF7BD, 0xF7CF, 0xF7D3, 0xF7E7, 
+	0xF7EB, 0xF7F1, 0xF7FF, 0xF805, 0xF80B, 0xF821, 0xF827, 0xF82D, 
+	0xF835, 0xF847, 0xF859, 0xF863, 0xF865, 0xF86F, 0xF871, 0xF877, 
+	0xF87B, 0xF881, 0xF88D, 0xF89F, 0xF8A1, 0xF8AB, 0xF8B3, 0xF8B7, 
+	0xF8C9, 0xF8CB, 0xF8D1, 0xF8D7, 0xF8DD, 0xF8E7, 0xF8EF, 0xF8F9, 
+	0xF8FF, 0xF911, 0xF91D, 0xF925, 0xF931, 0xF937, 0xF93B, 0xF941, 
+	0xF94F, 0xF95F, 0xF961, 0xF96D, 0xF971, 0xF977, 0xF99D, 0xF9A3, 
+	0xF9A9, 0xF9B9, 0xF9CD, 0xF9E9, 0xF9FD, 0xFA07, 0xFA0D, 0xFA13, 
+	0xFA21, 0xFA25, 0xFA3F, 0xFA43, 0xFA51, 0xFA5B, 0xFA6D, 0xFA7B, 
+	0xFA97, 0xFA99, 0xFA9D, 0xFAAB, 0xFABB, 0xFABD, 0xFAD9, 0xFADF, 
+	0xFAE7, 0xFAED, 0xFB0F, 0xFB17, 0xFB1B, 0xFB2D, 0xFB2F, 0xFB3F, 
+	0xFB47, 0xFB4D, 0xFB75, 0xFB7D, 0xFB8F, 0xFB93, 0xFBB1, 0xFBB7, 
+	0xFBC3, 0xFBC5, 0xFBE3, 0xFBE9, 0xFBF3, 0xFC01, 0xFC29, 0xFC37, 
+	0xFC41, 0xFC43, 0xFC4F, 0xFC59, 0xFC61, 0xFC65, 0xFC6D, 0xFC73, 
+	0xFC79, 0xFC95, 0xFC97, 0xFC9B, 0xFCA7, 0xFCB5, 0xFCC5, 0xFCCD, 
+	0xFCEB, 0xFCFB, 0xFD0D, 0xFD0F, 0xFD19, 0xFD2B, 0xFD31, 0xFD51, 
+	0xFD55, 0xFD67, 0xFD6D, 0xFD6F, 0xFD7B, 0xFD85, 0xFD97, 0xFD99, 
+	0xFD9F, 0xFDA9, 0xFDB7, 0xFDC9, 0xFDE5, 0xFDEB, 0xFDF3, 0xFE03, 
+	0xFE05, 0xFE09, 0xFE1D, 0xFE27, 0xFE2F, 0xFE41, 0xFE4B, 0xFE4D, 
+	0xFE57, 0xFE5F, 0xFE63, 0xFE69, 0xFE75, 0xFE7B, 0xFE8F, 0xFE93, 
+	0xFE95, 0xFE9B, 0xFE9F, 0xFEB3, 0xFEBD, 0xFED7, 0xFEE9, 0xFEF3, 
+	0xFEF5, 0xFF07, 0xFF0D, 0xFF1D, 0xFF2B, 0xFF2F, 0xFF49, 0xFF4D, 
+	0xFF5B, 0xFF65, 0xFF71, 0xFF7F, 0xFF85, 0xFF8B, 0xFF8F, 0xFF9D, 
+	0xFFA7, 0xFFA9, 0xFFC7, 0xFFD9, 0xFFEF, 0xFFF1, 
+#endif
+};
+
diff --git a/mozilla/security/nss/lib/freebl/pqg.c b/mozilla/security/nss/lib/freebl/pqg.c
new file mode 100644
index 0000000..daedd8b
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/pqg.c
@@ -0,0 +1,717 @@
+/* ***** 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 ***** */
+
+/*
+ * PQG parameter generation/verification.  Based on FIPS 186-1.
+ *
+ * $Id: pqg.c,v 1.17 2009/03/26 23:16:37 glen.beasley%sun.com Exp $
+ */
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prerr.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+#include "blapi.h"
+#include "secitem.h"
+#include "mpi.h"
+#include "mpprime.h"
+#include "mplogic.h"
+#include "secmpi.h"
+
+#define MAX_ITERATIONS 1000  /* Maximum number of iterations of primegen */
+#define PQG_Q_PRIMALITY_TESTS 18 /* from HAC table 4.4 */
+#define PQG_P_PRIMALITY_TESTS 5  /* from HAC table 4.4 */
+
+ /* XXX to be replaced by define in blapit.h */
+#define BITS_IN_Q 160
+
+/* For FIPS-compliance testing.
+** The following array holds the seed defined in FIPS 186-1 appendix 5.
+** This seed is used to generate P and Q according to appendix 2; use of
+** this seed will exactly generate the PQG specified in appendix 2.
+*/
+#ifdef FIPS_186_1_A5_TEST
+static const unsigned char fips_186_1_a5_pqseed[] = {
+    0xd5, 0x01, 0x4e, 0x4b, 0x60, 0xef, 0x2b, 0xa8,
+    0xb6, 0x21, 0x1b, 0x40, 0x62, 0xba, 0x32, 0x24,
+    0xe0, 0x42, 0x7d, 0xd3
+};
+#endif
+
+/* Get a seed for generating P and Q.  If in testing mode, copy in the
+** seed from FIPS 186-1 appendix 5.  Otherwise, obtain bytes from the
+** global random number generator.
+*/
+static SECStatus
+getPQseed(SECItem *seed, PRArenaPool* arena)
+{
+    SECStatus rv;
+
+    if (!seed->data) {
+        seed->data = (unsigned char*)PORT_ArenaZAlloc(arena, seed->len);
+    }
+    if (!seed->data) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+#ifdef FIPS_186_1_A5_TEST
+    memcpy(seed->data, fips_186_1_a5_pqseed, seed->len);
+    return SECSuccess;
+#else
+    rv = RNG_GenerateGlobalRandomBytes(seed->data, seed->len);
+    /*
+     * NIST CMVP disallows a sequence of 20 bytes with the most
+     * significant byte equal to 0.  Perhaps they interpret
+     * "a sequence of at least 160 bits" as "a number >= 2^159".
+     * So we always set the most significant bit to 1. (bug 334533)
+     */
+    seed->data[0] |= 0x80;
+    return rv;
+#endif
+}
+
+/* Generate a candidate h value.  If in testing mode, use the h value
+** specified in FIPS 186-1 appendix 5, h = 2.  Otherwise, obtain bytes
+** from the global random number generator.
+*/
+static SECStatus
+generate_h_candidate(SECItem *hit, mp_int *H)
+{
+    SECStatus rv = SECSuccess;
+    mp_err   err = MP_OKAY;
+#ifdef FIPS_186_1_A5_TEST
+    memset(hit->data, 0, hit->len);
+    hit->data[hit->len-1] = 0x02;
+#else
+    rv = RNG_GenerateGlobalRandomBytes(hit->data, hit->len);
+#endif
+    if (rv)
+	return SECFailure;
+    err = mp_read_unsigned_octets(H, hit->data, hit->len);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/* Compute SHA[(SEED + addend) mod 2**g]
+** Result is placed in shaOutBuf.
+** This computation is used in steps 2 and 7 of FIPS 186 Appendix 2.2 .
+*/
+static SECStatus
+addToSeedThenSHA(const SECItem * seed,
+                 unsigned long   addend,
+                 int             g,
+                 unsigned char * shaOutBuf)
+{
+    SECItem str = { 0, 0, 0 };
+    mp_int s, sum, modulus, tmp;
+    mp_err    err = MP_OKAY;
+    SECStatus rv  = SECSuccess;
+    MP_DIGITS(&s)       = 0;
+    MP_DIGITS(&sum)     = 0;
+    MP_DIGITS(&modulus) = 0;
+    MP_DIGITS(&tmp)     = 0;
+    CHECK_MPI_OK( mp_init(&s) );
+    CHECK_MPI_OK( mp_init(&sum) );
+    CHECK_MPI_OK( mp_init(&modulus) );
+    SECITEM_TO_MPINT(*seed, &s); /* s = seed */
+    /* seed += addend */
+    if (addend < MP_DIGIT_MAX) {
+	CHECK_MPI_OK( mp_add_d(&s, (mp_digit)addend, &s) );
+    } else {
+	CHECK_MPI_OK( mp_init(&tmp) );
+	CHECK_MPI_OK( mp_set_ulong(&tmp, addend) );
+	CHECK_MPI_OK( mp_add(&s, &tmp, &s) );
+    }
+    CHECK_MPI_OK( mp_div_2d(&s, (mp_digit)g, NULL, &sum) );/*sum = s mod 2**g */
+    MPINT_TO_SECITEM(&sum, &str, NULL);
+    rv = SHA1_HashBuf(shaOutBuf, str.data, str.len); /* SHA1 hash result */
+cleanup:
+    mp_clear(&s);
+    mp_clear(&sum);
+    mp_clear(&modulus);
+    mp_clear(&tmp);
+    if (str.data)
+	SECITEM_ZfreeItem(&str, PR_FALSE);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	return SECFailure;
+    }
+    return rv;
+}
+
+/*
+**  Perform steps 2 and 3 of FIPS 186, appendix 2.2.
+**  Generate Q from seed.
+*/
+static SECStatus
+makeQfromSeed(
+      unsigned int  g,          /* input.  Length of seed in bits. */
+const SECItem   *   seed,       /* input.  */
+      mp_int    *   Q)          /* output. */
+{
+    unsigned char sha1[SHA1_LENGTH];
+    unsigned char sha2[SHA1_LENGTH];
+    unsigned char U[SHA1_LENGTH];
+    SECStatus rv  = SECSuccess;
+    mp_err    err = MP_OKAY;
+    int i;
+    /* ******************************************************************
+    ** Step 2.
+    ** "Compute U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]."
+    **/
+    CHECK_SEC_OK( SHA1_HashBuf(sha1, seed->data, seed->len) );
+    CHECK_SEC_OK( addToSeedThenSHA(seed, 1, g, sha2) );
+    for (i=0; i<SHA1_LENGTH; ++i) 
+	U[i] = sha1[i] ^ sha2[i];
+    /* ******************************************************************
+    ** Step 3.
+    ** "Form Q from U by setting the most signficant bit (the 2**159 bit)
+    **  and the least signficant bit to 1.  In terms of boolean operations,
+    **  Q = U OR 2**159 OR 1.  Note that 2**159 < Q < 2**160."
+    */
+    U[0]             |= 0x80;  /* U is MSB first */
+    U[SHA1_LENGTH-1] |= 0x01;
+    err = mp_read_unsigned_octets(Q, U, SHA1_LENGTH);
+cleanup:
+     memset(U, 0, SHA1_LENGTH);
+     memset(sha1, 0, SHA1_LENGTH);
+     memset(sha2, 0, SHA1_LENGTH);
+     if (err) {
+	MP_TO_SEC_ERROR(err);
+	return SECFailure;
+     }
+     return rv;
+}
+
+/*  Perform steps 7, 8 and 9 of FIPS 186, appendix 2.2.
+**  Generate P from Q, seed, L, and offset.
+*/
+static SECStatus
+makePfromQandSeed(
+      unsigned int  L,          /* Length of P in bits.  Per FIPS 186. */
+      unsigned int  offset,     /* Per FIPS 186, appendix 2.2. */
+      unsigned int  g,          /* input.  Length of seed in bits. */
+const SECItem   *   seed,       /* input.  */
+const mp_int    *   Q,          /* input.  */
+      mp_int    *   P)          /* output. */
+{
+    unsigned int  k;            /* Per FIPS 186, appendix 2.2. */
+    unsigned int  n;            /* Per FIPS 186, appendix 2.2. */
+    mp_digit      b;            /* Per FIPS 186, appendix 2.2. */
+    unsigned char V_k[SHA1_LENGTH];
+    mp_int        W, X, c, twoQ, V_n, tmp;
+    mp_err    err = MP_OKAY;
+    SECStatus rv  = SECSuccess;
+    /* Initialize bignums */
+    MP_DIGITS(&W)     = 0;
+    MP_DIGITS(&X)     = 0;
+    MP_DIGITS(&c)     = 0;
+    MP_DIGITS(&twoQ)  = 0;
+    MP_DIGITS(&V_n)   = 0;
+    MP_DIGITS(&tmp)   = 0;
+    CHECK_MPI_OK( mp_init(&W)    );
+    CHECK_MPI_OK( mp_init(&X)    );
+    CHECK_MPI_OK( mp_init(&c)    );
+    CHECK_MPI_OK( mp_init(&twoQ) );
+    CHECK_MPI_OK( mp_init(&tmp)  );
+    CHECK_MPI_OK( mp_init(&V_n)  );
+    /* L - 1 = n*160 + b */
+    n = (L - 1) / BITS_IN_Q;
+    b = (L - 1) % BITS_IN_Q;
+    /* ******************************************************************
+    ** Step 7.
+    **  "for k = 0 ... n let
+    **           V_k = SHA[(SEED + offset + k) mod 2**g]."
+    **
+    ** Step 8.
+    **  "Let W be the integer 
+    **    W = V_0 + (V_1 * 2**160) + ... + (V_n-1 * 2**((n-1)*160)) 
+    **         + ((V_n mod 2**b) * 2**(n*160))
+    */
+    for (k=0; k<n; ++k) { /* Do the first n terms of V_k */
+	/* Do step 7 for iteration k.
+	** V_k = SHA[(seed + offset + k) mod 2**g]
+	*/
+	CHECK_SEC_OK( addToSeedThenSHA(seed, offset + k, g, V_k) );
+	/* Do step 8 for iteration k.
+	** W += V_k * 2**(k*160)
+	*/
+	OCTETS_TO_MPINT(V_k, &tmp, SHA1_LENGTH);      /* get bignum V_k     */
+	CHECK_MPI_OK( mpl_lsh(&tmp, &tmp, k*160) );   /* tmp = V_k << k*160 */
+	CHECK_MPI_OK( mp_add(&W, &tmp, &W) );         /* W += tmp           */
+    }
+    /* Step 8, continued.
+    **   [W += ((V_n mod 2**b) * 2**(n*160))] 
+    */
+    CHECK_SEC_OK( addToSeedThenSHA(seed, offset + n, g, V_k) );
+    OCTETS_TO_MPINT(V_k, &V_n, SHA1_LENGTH);          /* get bignum V_n     */
+    CHECK_MPI_OK( mp_div_2d(&V_n, b, NULL, &tmp) );   /* tmp = V_n mod 2**b */
+    CHECK_MPI_OK( mpl_lsh(&tmp, &tmp, n*160) );       /* tmp = tmp << n*160 */
+    CHECK_MPI_OK( mp_add(&W, &tmp, &W) );             /* W += tmp           */
+    /* Step 8, continued.
+    ** "and let X = W + 2**(L-1).
+    **  Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L."
+    */
+    CHECK_MPI_OK( mpl_set_bit(&X, (mp_size)(L-1), 1) );    /* X = 2**(L-1) */
+    CHECK_MPI_OK( mp_add(&X, &W, &X) );                    /* X += W       */
+    /*************************************************************
+    ** Step 9.
+    ** "Let c = X mod 2q  and set p = X - (c - 1).
+    **  Note that p is congruent to 1 mod 2q."
+    */
+    CHECK_MPI_OK( mp_mul_2(Q, &twoQ) );                    /* 2q           */
+    CHECK_MPI_OK( mp_mod(&X, &twoQ, &c) );                 /* c = X mod 2q */
+    CHECK_MPI_OK( mp_sub_d(&c, 1, &c) );                   /* c -= 1       */
+    CHECK_MPI_OK( mp_sub(&X, &c, P) );                     /* P = X - c    */
+cleanup:
+    mp_clear(&W);
+    mp_clear(&X);
+    mp_clear(&c);
+    mp_clear(&twoQ);
+    mp_clear(&V_n);
+    mp_clear(&tmp);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	return SECFailure;
+    }
+    return rv;
+}
+
+/*
+** Generate G from h, P, and Q.
+*/
+static SECStatus
+makeGfromH(const mp_int *P,     /* input.  */
+           const mp_int *Q,     /* input.  */
+                 mp_int *H,     /* input and output. */
+                 mp_int *G,     /* output. */
+                 PRBool *passed)
+{
+    mp_int exp, pm1;
+    mp_err err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    *passed = PR_FALSE;
+    MP_DIGITS(&exp) = 0;
+    MP_DIGITS(&pm1) = 0;
+    CHECK_MPI_OK( mp_init(&exp) );
+    CHECK_MPI_OK( mp_init(&pm1) );
+    CHECK_MPI_OK( mp_sub_d(P, 1, &pm1) );        /* P - 1            */
+    if ( mp_cmp(H, &pm1) >= 0)                   /* H >= P-1         */
+	CHECK_MPI_OK( mp_sub(H, &pm1, H) );      /* H = H mod (P-1)  */
+    /* Let b = 2**n (smallest power of 2 greater than P).
+    ** Since P-1 >= b/2, and H < b, quotient(H/(P-1)) = 0 or 1
+    ** so the above operation safely computes H mod (P-1)
+    */
+    /* Check for H = to 0 or 1.  Regen H if so.  (Regen means return error). */
+    if (mp_cmp_d(H, 1) <= 0) {
+	rv = SECFailure;
+	goto cleanup;
+    }
+    /* Compute G, according to the equation  G = (H ** ((P-1)/Q)) mod P */
+    CHECK_MPI_OK( mp_div(&pm1, Q, &exp, NULL) );  /* exp = (P-1)/Q      */
+    CHECK_MPI_OK( mp_exptmod(H, &exp, P, G) );    /* G = H ** exp mod P */
+    /* Check for G == 0 or G == 1, return error if so. */
+    if (mp_cmp_d(G, 1) <= 0) {
+	rv = SECFailure;
+	goto cleanup;
+    }
+    *passed = PR_TRUE;
+cleanup:
+    mp_clear(&exp);
+    mp_clear(&pm1);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+SECStatus
+PQG_ParamGen(unsigned int j, PQGParams **pParams, PQGVerify **pVfy)
+{
+    unsigned int L;            /* Length of P in bits.  Per FIPS 186. */
+    unsigned int seedBytes;
+
+    if (j > 8 || !pParams || !pVfy) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    L = 512 + (j * 64);         /* bits in P */
+    seedBytes = L/8;
+    return PQG_ParamGenSeedLen(j, seedBytes, pParams, pVfy);
+}
+
+/* This code uses labels and gotos, so that it can follow the numbered
+** steps in the algorithms from FIPS 186 appendix 2.2 very closely,
+** and so that the correctness of this code can be easily verified.
+** So, please forgive the ugly c code.
+**/
+SECStatus
+PQG_ParamGenSeedLen(unsigned int j, unsigned int seedBytes,
+                    PQGParams **pParams, PQGVerify **pVfy)
+{
+    unsigned int  L;        /* Length of P in bits.  Per FIPS 186. */
+    unsigned int  n;        /* Per FIPS 186, appendix 2.2. */
+    unsigned int  b;        /* Per FIPS 186, appendix 2.2. */
+    unsigned int  g;        /* Per FIPS 186, appendix 2.2. */
+    unsigned int  counter;  /* Per FIPS 186, appendix 2.2. */
+    unsigned int  offset;   /* Per FIPS 186, appendix 2.2. */
+    SECItem      *seed;     /* Per FIPS 186, appendix 2.2. */
+    PRArenaPool  *arena  = NULL;
+    PQGParams    *params = NULL;
+    PQGVerify    *verify = NULL;
+    PRBool passed;
+    SECItem hit = { 0, 0, 0 };
+    mp_int P, Q, G, H, l;
+    mp_err    err = MP_OKAY;
+    SECStatus rv  = SECFailure;
+    int iterations = 0;
+    if (j > 8 || seedBytes < 20 || !pParams || !pVfy) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* Initialize an arena for the params. */
+    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    params = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams));
+    if (!params) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	PORT_FreeArena(arena, PR_TRUE);
+	return SECFailure;
+    }
+    params->arena = arena;
+    /* Initialize an arena for the verify. */
+    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	PORT_FreeArena(params->arena, PR_TRUE);
+	return SECFailure;
+    }
+    verify = (PQGVerify *)PORT_ArenaZAlloc(arena, sizeof(PQGVerify));
+    if (!verify) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	PORT_FreeArena(arena, PR_TRUE);
+	PORT_FreeArena(params->arena, PR_TRUE);
+	return SECFailure;
+    }
+    verify->arena = arena;
+    seed = &verify->seed;
+    arena = NULL;
+    /* Initialize bignums */
+    MP_DIGITS(&P) = 0;
+    MP_DIGITS(&Q) = 0;
+    MP_DIGITS(&G) = 0;
+    MP_DIGITS(&H) = 0;
+    MP_DIGITS(&l) = 0;
+    CHECK_MPI_OK( mp_init(&P) );
+    CHECK_MPI_OK( mp_init(&Q) );
+    CHECK_MPI_OK( mp_init(&G) );
+    CHECK_MPI_OK( mp_init(&H) );
+    CHECK_MPI_OK( mp_init(&l) );
+    /* Compute lengths. */
+    L = 512 + (j * 64);               /* bits in P */
+    n = (L - 1) / BITS_IN_Q;          /* BITS_IN_Q is 160 */  
+    b = (L - 1) % BITS_IN_Q;
+    g = seedBytes * BITS_PER_BYTE;    /* bits in seed, NOT G of PQG. */
+step_1:
+    /* ******************************************************************
+    ** Step 1.
+    ** "Choose an abitrary sequence of at least 160 bits and call it SEED.
+    **  Let g be the length of SEED in bits."
+    */
+    if (++iterations > MAX_ITERATIONS) {        /* give up after a while */
+        PORT_SetError(SEC_ERROR_NEED_RANDOM);
+        goto cleanup;
+    }
+    seed->len = seedBytes;
+    CHECK_SEC_OK( getPQseed(seed, verify->arena) );
+    /* ******************************************************************
+    ** Step 2.
+    ** "Compute U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]."
+    **
+    ** Step 3.
+    ** "Form Q from U by setting the most signficant bit (the 2**159 bit) 
+    **  and the least signficant bit to 1.  In terms of boolean operations,
+    **  Q = U OR 2**159 OR 1.  Note that 2**159 < Q < 2**160."
+    */
+    CHECK_SEC_OK( makeQfromSeed(g, seed, &Q) );
+    /* ******************************************************************
+    ** Step 4.
+    ** "Use a robust primality testing algorithm to test whether q is prime."
+    **
+    ** Appendix 2.1 states that a Rabin test with at least 50 iterations
+    ** "will give an acceptable probability of error."
+    */
+    /*CHECK_SEC_OK( prm_RabinTest(&Q, &passed) );*/
+    err = mpp_pprime(&Q, PQG_Q_PRIMALITY_TESTS);
+    passed = (err == MP_YES) ? SECSuccess : SECFailure;
+    /* ******************************************************************
+    ** Step 5. "If q is not prime, goto step 1."
+    */
+    if (passed != SECSuccess)
+        goto step_1;
+    /* ******************************************************************
+    ** Step 6. "Let counter = 0 and offset = 2."
+    */
+    counter = 0;
+    offset  = 2;
+step_7:
+    /* ******************************************************************
+    ** Step 7.
+    ** "for k = 0 ... n let
+    **          V_k = SHA[(SEED + offset + k) mod 2**g]."
+    **
+    ** Step 8.
+    ** "Let W be the sum of  (V_k * 2**(k*160)) for k = 0 ... n
+    **  and let X = W + 2**(L-1).
+    **  Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L."
+    **
+    ** Step 9.
+    ** "Let c = X mod 2q  and set p = X - (c - 1).
+    **  Note that p is congruent to 1 mod 2q."
+    */
+    CHECK_SEC_OK( makePfromQandSeed(L, offset, g, seed, &Q, &P) );
+    /*************************************************************
+    ** Step 10.
+    ** "if p < 2**(L-1), then goto step 13."
+    */
+    CHECK_MPI_OK( mpl_set_bit(&l, (mp_size)(L-1), 1) ); /* l = 2**(L-1) */
+    if (mp_cmp(&P, &l) < 0)
+        goto step_13;
+    /************************************************************
+    ** Step 11.
+    ** "Perform a robust primality test on p."
+    */
+    /*CHECK_SEC_OK( prm_RabinTest(&P, &passed) );*/
+    err = mpp_pprime(&P, PQG_P_PRIMALITY_TESTS);
+    passed = (err == MP_YES) ? SECSuccess : SECFailure;
+    /* ******************************************************************
+    ** Step 12. "If p passes the test performed in step 11, go to step 15."
+    */
+    if (passed == SECSuccess)
+        goto step_15;
+step_13:
+    /* ******************************************************************
+    ** Step 13.  "Let counter = counter + 1 and offset = offset + n + 1."
+    */
+    counter++;
+    offset += n + 1;
+    /* ******************************************************************
+    ** Step 14.  "If counter >= 4096 goto step 1, otherwise go to step 7."
+    */
+    if (counter >= 4096)
+        goto step_1;
+    goto step_7;
+step_15:
+    /* ******************************************************************
+    ** Step 15.  
+    ** "Save the value of SEED and the value of counter for use
+    **  in certifying the proper generation of p and q."
+    */
+    /* Generate h. */
+    SECITEM_AllocItem(NULL, &hit, L/8); /* h is no longer than p */
+    if (!hit.data) goto cleanup;
+    do {
+	/* loop generate h until 1<h<p-1 and (h**[(p-1)/q])mod p > 1 */
+	CHECK_SEC_OK( generate_h_candidate(&hit, &H) );
+        CHECK_SEC_OK( makeGfromH(&P, &Q, &H, &G, &passed) );
+    } while (passed != PR_TRUE);
+    /* All generation is done.  Now, save the PQG params.  */
+    MPINT_TO_SECITEM(&P, &params->prime,    params->arena);
+    MPINT_TO_SECITEM(&Q, &params->subPrime, params->arena);
+    MPINT_TO_SECITEM(&G, &params->base,     params->arena);
+    MPINT_TO_SECITEM(&H, &verify->h,        verify->arena);
+    verify->counter = counter;
+    *pParams = params;
+    *pVfy = verify;
+cleanup:
+    mp_clear(&P);
+    mp_clear(&Q);
+    mp_clear(&G);
+    mp_clear(&H);
+    mp_clear(&l);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    if (rv) {
+	PORT_FreeArena(params->arena, PR_TRUE);
+	PORT_FreeArena(verify->arena, PR_TRUE);
+    }
+    if (hit.data) {
+        SECITEM_FreeItem(&hit, PR_FALSE);
+    }
+    return rv;
+}
+
+SECStatus   
+PQG_VerifyParams(const PQGParams *params, 
+                 const PQGVerify *vfy, SECStatus *result)
+{
+    SECStatus rv = SECSuccess;
+    int passed;
+    unsigned int g, n, L, offset;
+    mp_int P, Q, G, P_, Q_, G_, r, h;
+    mp_err err = MP_OKAY;
+    int j;
+#define CHECKPARAM(cond)      \
+    if (!(cond)) {            \
+	*result = SECFailure; \
+	goto cleanup;         \
+    }
+    if (!params || !vfy || !result) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    MP_DIGITS(&P) = 0;
+    MP_DIGITS(&Q) = 0;
+    MP_DIGITS(&G) = 0;
+    MP_DIGITS(&P_) = 0;
+    MP_DIGITS(&Q_) = 0;
+    MP_DIGITS(&G_) = 0;
+    MP_DIGITS(&r) = 0;
+    MP_DIGITS(&h) = 0;
+    CHECK_MPI_OK( mp_init(&P) );
+    CHECK_MPI_OK( mp_init(&Q) );
+    CHECK_MPI_OK( mp_init(&G) );
+    CHECK_MPI_OK( mp_init(&P_) );
+    CHECK_MPI_OK( mp_init(&Q_) );
+    CHECK_MPI_OK( mp_init(&G_) );
+    CHECK_MPI_OK( mp_init(&r) );
+    CHECK_MPI_OK( mp_init(&h) );
+    *result = SECSuccess;
+    SECITEM_TO_MPINT(params->prime,    &P);
+    SECITEM_TO_MPINT(params->subPrime, &Q);
+    SECITEM_TO_MPINT(params->base,     &G);
+    /* 1.  Q is 160 bits long. */
+    CHECKPARAM( mpl_significant_bits(&Q) == 160 );
+    /* 2.  P is one of the 9 valid lengths. */
+    L = mpl_significant_bits(&P);
+    j = PQG_PBITS_TO_INDEX(L);
+    CHECKPARAM( j >= 0 && j <= 8 );
+    /* 3.  G < P */
+    CHECKPARAM( mp_cmp(&G, &P) < 0 );
+    /* 4.  P % Q == 1 */
+    CHECK_MPI_OK( mp_mod(&P, &Q, &r) );
+    CHECKPARAM( mp_cmp_d(&r, 1) == 0 );
+    /* 5.  Q is prime */
+    CHECKPARAM( mpp_pprime(&Q, PQG_Q_PRIMALITY_TESTS) == MP_YES );
+    /* 6.  P is prime */
+    CHECKPARAM( mpp_pprime(&P, PQG_P_PRIMALITY_TESTS) == MP_YES );
+    /* Steps 7-12 are done only if the optional PQGVerify is supplied. */
+    /* 7.  counter < 4096 */
+    CHECKPARAM( vfy->counter < 4096 );
+    /* 8.  g >= 160 and g < 2048   (g is length of seed in bits) */
+    g = vfy->seed.len * 8;
+    CHECKPARAM( g >= 160 && g < 2048 );
+    /* 9.  Q generated from SEED matches Q in PQGParams. */
+    CHECK_SEC_OK( makeQfromSeed(g, &vfy->seed, &Q_) );
+    CHECKPARAM( mp_cmp(&Q, &Q_) == 0 );
+    /* 10. P generated from (L, counter, g, SEED, Q) matches P in PQGParams. */
+    n = (L - 1) / BITS_IN_Q;
+    offset = vfy->counter * (n + 1) + 2;
+    CHECK_SEC_OK( makePfromQandSeed(L, offset, g, &vfy->seed, &Q, &P_) );
+    CHECKPARAM( mp_cmp(&P, &P_) == 0 );
+    /* Next two are optional: if h == 0 ignore */
+    if (vfy->h.len == 0) goto cleanup;
+    /* 11. 1 < h < P-1 */
+    SECITEM_TO_MPINT(vfy->h, &h);
+    CHECK_MPI_OK( mpl_set_bit(&P, 0, 0) ); /* P is prime, p-1 == zero 1st bit */
+    CHECKPARAM( mp_cmp_d(&h, 1) > 0 && mp_cmp(&h, &P) );
+    CHECK_MPI_OK( mpl_set_bit(&P, 0, 1) ); /* set it back */
+    /* 12. G generated from h matches G in PQGParams. */
+    CHECK_SEC_OK( makeGfromH(&P, &Q, &h, &G_, &passed) );
+    CHECKPARAM( passed && mp_cmp(&G, &G_) == 0 );
+cleanup:
+    mp_clear(&P);
+    mp_clear(&Q);
+    mp_clear(&G);
+    mp_clear(&P_);
+    mp_clear(&Q_);
+    mp_clear(&G_);
+    mp_clear(&r);
+    mp_clear(&h);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+/**************************************************************************
+ *  Free the PQGParams struct and the things it points to.                *
+ **************************************************************************/
+void
+PQG_DestroyParams(PQGParams *params)
+{
+    if (params == NULL) 
+    	return;
+    if (params->arena != NULL) {
+	PORT_FreeArena(params->arena, PR_FALSE);	/* don't zero it */
+    } else {
+	SECITEM_FreeItem(&params->prime,    PR_FALSE); /* don't free prime */
+	SECITEM_FreeItem(&params->subPrime, PR_FALSE); /* don't free subPrime */
+	SECITEM_FreeItem(&params->base,     PR_FALSE); /* don't free base */
+	PORT_Free(params);
+    }
+}
+
+/**************************************************************************
+ *  Free the PQGVerify struct and the things it points to.                *
+ **************************************************************************/
+
+void
+PQG_DestroyVerify(PQGVerify *vfy)
+{
+    if (vfy == NULL) 
+    	return;
+    if (vfy->arena != NULL) {
+	PORT_FreeArena(vfy->arena, PR_FALSE);	/* don't zero it */
+    } else {
+	SECITEM_FreeItem(&vfy->seed,   PR_FALSE); /* don't free seed */
+	SECITEM_FreeItem(&vfy->h,      PR_FALSE); /* don't free h */
+	PORT_Free(vfy);
+    }
+}
diff --git a/mozilla/security/nss/lib/freebl/rawhash.c b/mozilla/security/nss/lib/freebl/rawhash.c
new file mode 100644
index 0000000..811be1a
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/rawhash.c
@@ -0,0 +1,168 @@
+/* ***** 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "nspr.h"
+#include "sechash.h"
+#include "blapi.h"	/* below the line */
+#include "secerr.h"
+
+static void *
+null_hash_new_context(void)
+{
+    return NULL;
+}
+
+static void *
+null_hash_clone_context(void *v)
+{
+    PORT_Assert(v == NULL);
+    return NULL;
+}
+
+static void
+null_hash_begin(void *v)
+{
+}
+
+static void
+null_hash_update(void *v, const unsigned char *input, unsigned int length)
+{
+}
+
+static void
+null_hash_end(void *v, unsigned char *output, unsigned int *outLen,
+	      unsigned int maxOut)
+{
+    *outLen = 0;
+}
+
+static void
+null_hash_destroy_context(void *v, PRBool b)
+{
+    PORT_Assert(v == NULL);
+}
+
+
+const SECHashObject SECRawHashObjects[] = {
+  { 0,
+    (void * (*)(void)) null_hash_new_context,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) null_hash_destroy_context,
+    (void (*)(void *)) null_hash_begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) null_hash_update,
+    (void (*)(void *, unsigned char *, unsigned int *,
+	      unsigned int)) null_hash_end,
+    0,
+    HASH_AlgNULL
+  },
+  { MD2_LENGTH,
+    (void * (*)(void)) MD2_NewContext,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) MD2_DestroyContext,
+    (void (*)(void *)) MD2_Begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) MD2_Update,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) MD2_End,
+    MD2_BLOCK_LENGTH,
+    HASH_AlgMD2
+  },
+  { MD5_LENGTH,
+    (void * (*)(void)) MD5_NewContext,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) MD5_DestroyContext,
+    (void (*)(void *)) MD5_Begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) MD5_Update,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) MD5_End,
+    MD5_BLOCK_LENGTH,
+    HASH_AlgMD5
+  },
+  { SHA1_LENGTH,
+    (void * (*)(void)) SHA1_NewContext,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) SHA1_DestroyContext,
+    (void (*)(void *)) SHA1_Begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) SHA1_Update,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) SHA1_End,
+    SHA1_BLOCK_LENGTH,
+    HASH_AlgSHA1
+  },
+  { SHA256_LENGTH,
+    (void * (*)(void)) SHA256_NewContext,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) SHA256_DestroyContext,
+    (void (*)(void *)) SHA256_Begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) SHA256_Update,
+    (void (*)(void *, unsigned char *, unsigned int *,
+	      unsigned int)) SHA256_End,
+    SHA256_BLOCK_LENGTH,
+    HASH_AlgSHA256
+  },
+  { SHA384_LENGTH,
+    (void * (*)(void)) SHA384_NewContext,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) SHA384_DestroyContext,
+    (void (*)(void *)) SHA384_Begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) SHA384_Update,
+    (void (*)(void *, unsigned char *, unsigned int *,
+	      unsigned int)) SHA384_End,
+    SHA384_BLOCK_LENGTH,
+    HASH_AlgSHA384
+  },
+  { SHA512_LENGTH,
+    (void * (*)(void)) SHA512_NewContext,
+    (void * (*)(void *)) null_hash_clone_context,
+    (void (*)(void *, PRBool)) SHA512_DestroyContext,
+    (void (*)(void *)) SHA512_Begin,
+    (void (*)(void *, const unsigned char *, unsigned int)) SHA512_Update,
+    (void (*)(void *, unsigned char *, unsigned int *,
+	      unsigned int)) SHA512_End,
+    SHA512_BLOCK_LENGTH,
+    HASH_AlgSHA512
+  },
+};
+
+const SECHashObject *
+HASH_GetRawHashObject(HASH_HashType hashType)
+{
+    if (hashType < HASH_AlgNULL || hashType >= HASH_AlgTOTAL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    return &SECRawHashObjects[hashType];
+}
diff --git a/mozilla/security/nss/lib/freebl/rijndael.c b/mozilla/security/nss/lib/freebl/rijndael.c
new file mode 100644
index 0000000..79deebd
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/rijndael.c
@@ -0,0 +1,1193 @@
+/* ***** 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 ***** */
+/* $Id: rijndael.c,v 1.25 2009/04/09 22:11:07 julien.pierre.boogz%sun.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prinit.h"
+#include "prerr.h"
+#include "secerr.h"
+
+#include "prtypes.h"
+#include "blapi.h"
+#include "rijndael.h"
+
+#if USE_HW_AES
+#include "intel-aes.h"
+#include "mpi.h"
+#endif
+
+/*
+ * There are currently five ways to build this code, varying in performance
+ * and code size.
+ *
+ * RIJNDAEL_INCLUDE_TABLES         Include all tables from rijndael32.tab
+ * RIJNDAEL_GENERATE_TABLES        Generate tables on first 
+ *                                 encryption/decryption, then store them;
+ *                                 use the function gfm
+ * RIJNDAEL_GENERATE_TABLES_MACRO  Same as above, but use macros to do
+ *                                 the generation
+ * RIJNDAEL_GENERATE_VALUES        Do not store tables, generate the table
+ *                                 values "on-the-fly", using gfm
+ * RIJNDAEL_GENERATE_VALUES_MACRO  Same as above, but use macros
+ *
+ * The default is RIJNDAEL_INCLUDE_TABLES.
+ */
+
+/*
+ * When building RIJNDAEL_INCLUDE_TABLES, includes S**-1, Rcon, T[0..4], 
+ *                                                 T**-1[0..4], IMXC[0..4]
+ * When building anything else, includes S, S**-1, Rcon
+ */
+#include "rijndael32.tab"
+
+#if defined(RIJNDAEL_INCLUDE_TABLES)
+/*
+ * RIJNDAEL_INCLUDE_TABLES
+ */
+#define T0(i)    _T0[i]
+#define T1(i)    _T1[i]
+#define T2(i)    _T2[i]
+#define T3(i)    _T3[i]
+#define TInv0(i) _TInv0[i]
+#define TInv1(i) _TInv1[i]
+#define TInv2(i) _TInv2[i]
+#define TInv3(i) _TInv3[i]
+#define IMXC0(b) _IMXC0[b]
+#define IMXC1(b) _IMXC1[b]
+#define IMXC2(b) _IMXC2[b]
+#define IMXC3(b) _IMXC3[b]
+/* The S-box can be recovered from the T-tables */
+#ifdef IS_LITTLE_ENDIAN
+#define SBOX(b)    ((PRUint8)_T3[b])
+#else
+#define SBOX(b)    ((PRUint8)_T1[b])
+#endif
+#define SINV(b) (_SInv[b])
+
+#else /* not RIJNDAEL_INCLUDE_TABLES */
+
+/*
+ * Code for generating T-table values.
+ */
+
+#ifdef IS_LITTLE_ENDIAN
+#define WORD4(b0, b1, b2, b3) \
+    (((b3) << 24) | ((b2) << 16) | ((b1) << 8) | (b0))
+#else
+#define WORD4(b0, b1, b2, b3) \
+    (((b0) << 24) | ((b1) << 16) | ((b2) << 8) | (b3))
+#endif
+
+/*
+ * Define the S and S**-1 tables (both have been stored)
+ */
+#define SBOX(b)    (_S[b])
+#define SINV(b) (_SInv[b])
+
+/*
+ * The function xtime, used for Galois field multiplication
+ */
+#define XTIME(a) \
+    ((a & 0x80) ? ((a << 1) ^ 0x1b) : (a << 1))
+
+/* Choose GFM method (macros or function) */
+#if defined(RIJNDAEL_GENERATE_TABLES_MACRO) ||  \
+    defined(RIJNDAEL_GENERATE_VALUES_MACRO)
+
+/*
+ * Galois field GF(2**8) multipliers, in macro form
+ */
+#define GFM01(a) \
+    (a)                                 /* a * 01 = a, the identity */
+#define GFM02(a) \
+    (XTIME(a) & 0xff)                   /* a * 02 = xtime(a) */
+#define GFM04(a) \
+    (GFM02(GFM02(a)))                   /* a * 04 = xtime**2(a) */
+#define GFM08(a) \
+    (GFM02(GFM04(a)))                   /* a * 08 = xtime**3(a) */
+#define GFM03(a) \
+    (GFM01(a) ^ GFM02(a))               /* a * 03 = a * (01 + 02) */
+#define GFM09(a) \
+    (GFM01(a) ^ GFM08(a))               /* a * 09 = a * (01 + 08) */
+#define GFM0B(a) \
+    (GFM01(a) ^ GFM02(a) ^ GFM08(a))    /* a * 0B = a * (01 + 02 + 08) */
+#define GFM0D(a) \
+    (GFM01(a) ^ GFM04(a) ^ GFM08(a))    /* a * 0D = a * (01 + 04 + 08) */
+#define GFM0E(a) \
+    (GFM02(a) ^ GFM04(a) ^ GFM08(a))    /* a * 0E = a * (02 + 04 + 08) */
+
+#else  /* RIJNDAEL_GENERATE_TABLES or RIJNDAEL_GENERATE_VALUES */
+
+/* GF_MULTIPLY
+ *
+ * multiply two bytes represented in GF(2**8), mod (x**4 + 1)
+ */
+PRUint8 gfm(PRUint8 a, PRUint8 b)
+{
+    PRUint8 res = 0;
+    while (b > 0) {
+	res = (b & 0x01) ? res ^ a : res;
+	a = XTIME(a);
+	b >>= 1;
+    }
+    return res;
+}
+
+#define GFM01(a) \
+    (a)                                 /* a * 01 = a, the identity */
+#define GFM02(a) \
+    (XTIME(a) & 0xff)                   /* a * 02 = xtime(a) */
+#define GFM03(a) \
+    (gfm(a, 0x03))                      /* a * 03 */
+#define GFM09(a) \
+    (gfm(a, 0x09))                      /* a * 09 */
+#define GFM0B(a) \
+    (gfm(a, 0x0B))                      /* a * 0B */
+#define GFM0D(a) \
+    (gfm(a, 0x0D))                      /* a * 0D */
+#define GFM0E(a) \
+    (gfm(a, 0x0E))                      /* a * 0E */
+
+#endif /* choosing GFM function */
+
+/*
+ * The T-tables
+ */
+#define G_T0(i) \
+    ( WORD4( GFM02(SBOX(i)), GFM01(SBOX(i)), GFM01(SBOX(i)), GFM03(SBOX(i)) ) )
+#define G_T1(i) \
+    ( WORD4( GFM03(SBOX(i)), GFM02(SBOX(i)), GFM01(SBOX(i)), GFM01(SBOX(i)) ) )
+#define G_T2(i) \
+    ( WORD4( GFM01(SBOX(i)), GFM03(SBOX(i)), GFM02(SBOX(i)), GFM01(SBOX(i)) ) )
+#define G_T3(i) \
+    ( WORD4( GFM01(SBOX(i)), GFM01(SBOX(i)), GFM03(SBOX(i)), GFM02(SBOX(i)) ) )
+
+/*
+ * The inverse T-tables
+ */
+#define G_TInv0(i) \
+    ( WORD4( GFM0E(SINV(i)), GFM09(SINV(i)), GFM0D(SINV(i)), GFM0B(SINV(i)) ) )
+#define G_TInv1(i) \
+    ( WORD4( GFM0B(SINV(i)), GFM0E(SINV(i)), GFM09(SINV(i)), GFM0D(SINV(i)) ) )
+#define G_TInv2(i) \
+    ( WORD4( GFM0D(SINV(i)), GFM0B(SINV(i)), GFM0E(SINV(i)), GFM09(SINV(i)) ) )
+#define G_TInv3(i) \
+    ( WORD4( GFM09(SINV(i)), GFM0D(SINV(i)), GFM0B(SINV(i)), GFM0E(SINV(i)) ) )
+
+/*
+ * The inverse mix column tables
+ */
+#define G_IMXC0(i) \
+    ( WORD4( GFM0E(i), GFM09(i), GFM0D(i), GFM0B(i) ) )
+#define G_IMXC1(i) \
+    ( WORD4( GFM0B(i), GFM0E(i), GFM09(i), GFM0D(i) ) )
+#define G_IMXC2(i) \
+    ( WORD4( GFM0D(i), GFM0B(i), GFM0E(i), GFM09(i) ) )
+#define G_IMXC3(i) \
+    ( WORD4( GFM09(i), GFM0D(i), GFM0B(i), GFM0E(i) ) )
+
+/* Now choose the T-table indexing method */
+#if defined(RIJNDAEL_GENERATE_VALUES)
+/* generate values for the tables with a function*/
+static PRUint32 gen_TInvXi(PRUint8 tx, PRUint8 i)
+{
+    PRUint8 si01, si02, si03, si04, si08, si09, si0B, si0D, si0E;
+    si01 = SINV(i);
+    si02 = XTIME(si01);
+    si04 = XTIME(si02);
+    si08 = XTIME(si04);
+    si03 = si02 ^ si01;
+    si09 = si08 ^ si01;
+    si0B = si08 ^ si03;
+    si0D = si09 ^ si04;
+    si0E = si08 ^ si04 ^ si02;
+    switch (tx) {
+    case 0:
+	return WORD4(si0E, si09, si0D, si0B);
+    case 1:
+	return WORD4(si0B, si0E, si09, si0D);
+    case 2:
+	return WORD4(si0D, si0B, si0E, si09);
+    case 3:
+	return WORD4(si09, si0D, si0B, si0E);
+    }
+    return -1;
+}
+#define T0(i)    G_T0(i)
+#define T1(i)    G_T1(i)
+#define T2(i)    G_T2(i)
+#define T3(i)    G_T3(i)
+#define TInv0(i) gen_TInvXi(0, i)
+#define TInv1(i) gen_TInvXi(1, i)
+#define TInv2(i) gen_TInvXi(2, i)
+#define TInv3(i) gen_TInvXi(3, i)
+#define IMXC0(b) G_IMXC0(b)
+#define IMXC1(b) G_IMXC1(b)
+#define IMXC2(b) G_IMXC2(b)
+#define IMXC3(b) G_IMXC3(b)
+#elif defined(RIJNDAEL_GENERATE_VALUES_MACRO)
+/* generate values for the tables with macros */
+#define T0(i)    G_T0(i)
+#define T1(i)    G_T1(i)
+#define T2(i)    G_T2(i)
+#define T3(i)    G_T3(i)
+#define TInv0(i) G_TInv0(i)
+#define TInv1(i) G_TInv1(i)
+#define TInv2(i) G_TInv2(i)
+#define TInv3(i) G_TInv3(i)
+#define IMXC0(b) G_IMXC0(b)
+#define IMXC1(b) G_IMXC1(b)
+#define IMXC2(b) G_IMXC2(b)
+#define IMXC3(b) G_IMXC3(b)
+#else  /* RIJNDAEL_GENERATE_TABLES or RIJNDAEL_GENERATE_TABLES_MACRO */
+/* Generate T and T**-1 table values and store, then index */
+/* The inverse mix column tables are still generated */
+#define T0(i)    rijndaelTables->T0[i]
+#define T1(i)    rijndaelTables->T1[i]
+#define T2(i)    rijndaelTables->T2[i]
+#define T3(i)    rijndaelTables->T3[i]
+#define TInv0(i) rijndaelTables->TInv0[i]
+#define TInv1(i) rijndaelTables->TInv1[i]
+#define TInv2(i) rijndaelTables->TInv2[i]
+#define TInv3(i) rijndaelTables->TInv3[i]
+#define IMXC0(b) G_IMXC0(b)
+#define IMXC1(b) G_IMXC1(b)
+#define IMXC2(b) G_IMXC2(b)
+#define IMXC3(b) G_IMXC3(b)
+#endif /* choose T-table indexing method */
+
+#endif /* not RIJNDAEL_INCLUDE_TABLES */
+
+#if defined(RIJNDAEL_GENERATE_TABLES) ||  \
+    defined(RIJNDAEL_GENERATE_TABLES_MACRO)
+
+/* Code to generate and store the tables */
+
+struct rijndael_tables_str {
+    PRUint32 T0[256];
+    PRUint32 T1[256];
+    PRUint32 T2[256];
+    PRUint32 T3[256];
+    PRUint32 TInv0[256];
+    PRUint32 TInv1[256];
+    PRUint32 TInv2[256];
+    PRUint32 TInv3[256];
+};
+
+static struct rijndael_tables_str *rijndaelTables = NULL;
+static PRCallOnceType coRTInit = { 0, 0, 0 };
+static PRStatus 
+init_rijndael_tables(void)
+{
+    PRUint32 i;
+    PRUint8 si01, si02, si03, si04, si08, si09, si0B, si0D, si0E;
+    struct rijndael_tables_str *rts;
+    rts = (struct rijndael_tables_str *)
+                   PORT_Alloc(sizeof(struct rijndael_tables_str));
+    if (!rts) return PR_FAILURE;
+    for (i=0; i<256; i++) {
+	/* The forward values */
+	si01 = SBOX(i);
+	si02 = XTIME(si01);
+	si03 = si02 ^ si01;
+	rts->T0[i] = WORD4(si02, si01, si01, si03);
+	rts->T1[i] = WORD4(si03, si02, si01, si01);
+	rts->T2[i] = WORD4(si01, si03, si02, si01);
+	rts->T3[i] = WORD4(si01, si01, si03, si02);
+	/* The inverse values */
+	si01 = SINV(i);
+	si02 = XTIME(si01);
+	si04 = XTIME(si02);
+	si08 = XTIME(si04);
+	si03 = si02 ^ si01;
+	si09 = si08 ^ si01;
+	si0B = si08 ^ si03;
+	si0D = si09 ^ si04;
+	si0E = si08 ^ si04 ^ si02;
+	rts->TInv0[i] = WORD4(si0E, si09, si0D, si0B);
+	rts->TInv1[i] = WORD4(si0B, si0E, si09, si0D);
+	rts->TInv2[i] = WORD4(si0D, si0B, si0E, si09);
+	rts->TInv3[i] = WORD4(si09, si0D, si0B, si0E);
+    }
+    /* wait until all the values are in to set */
+    rijndaelTables = rts;
+    return PR_SUCCESS;
+}
+
+#endif /* code to generate tables */
+
+/**************************************************************************
+ *
+ * Stuff related to the Rijndael key schedule
+ *
+ *************************************************************************/
+
+#define SUBBYTE(w) \
+    ((SBOX((w >> 24) & 0xff) << 24) | \
+     (SBOX((w >> 16) & 0xff) << 16) | \
+     (SBOX((w >>  8) & 0xff) <<  8) | \
+     (SBOX((w      ) & 0xff)         ))
+
+#ifdef IS_LITTLE_ENDIAN
+#define ROTBYTE(b) \
+    ((b >> 8) | (b << 24))
+#else
+#define ROTBYTE(b) \
+    ((b << 8) | (b >> 24))
+#endif
+
+/* rijndael_key_expansion7
+ *
+ * Generate the expanded key from the key input by the user.
+ * XXX
+ * Nk == 7 (224 key bits) is a weird case.  Since Nk > 6, an added SubByte
+ * transformation is done periodically.  The period is every 4 bytes, and
+ * since 7%4 != 0 this happens at different times for each key word (unlike
+ * Nk == 8 where it happens twice in every key word, in the same positions).
+ * For now, I'm implementing this case "dumbly", w/o any unrolling.
+ */
+static SECStatus
+rijndael_key_expansion7(AESContext *cx, const unsigned char *key, unsigned int Nk)
+{
+    unsigned int i;
+    PRUint32 *W;
+    PRUint32 *pW;
+    PRUint32 tmp;
+    W = cx->expandedKey;
+    /* 1.  the first Nk words contain the cipher key */
+    memcpy(W, key, Nk * 4);
+    i = Nk;
+    /* 2.  loop until full expanded key is obtained */
+    pW = W + i - 1;
+    for (; i < cx->Nb * (cx->Nr + 1); ++i) {
+	tmp = *pW++;
+	if (i % Nk == 0)
+	    tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
+	else if (i % Nk == 4)
+	    tmp = SUBBYTE(tmp);
+	*pW = W[i - Nk] ^ tmp;
+    }
+    return SECSuccess;
+}
+
+/* rijndael_key_expansion
+ *
+ * Generate the expanded key from the key input by the user.
+ */
+static SECStatus
+rijndael_key_expansion(AESContext *cx, const unsigned char *key, unsigned int Nk)
+{
+    unsigned int i;
+    PRUint32 *W;
+    PRUint32 *pW;
+    PRUint32 tmp;
+    unsigned int round_key_words = cx->Nb * (cx->Nr + 1);
+    if (Nk == 7)
+	return rijndael_key_expansion7(cx, key, Nk);
+    W = cx->expandedKey;
+    /* The first Nk words contain the input cipher key */
+    memcpy(W, key, Nk * 4);
+    i = Nk;
+    pW = W + i - 1;
+    /* Loop over all sets of Nk words, except the last */
+    while (i < round_key_words - Nk) {
+	tmp = *pW++;
+	tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
+	*pW = W[i++ - Nk] ^ tmp;
+	tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
+	tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
+	tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
+	if (Nk == 4)
+	    continue;
+	switch (Nk) {
+	case 8: tmp = *pW++; tmp = SUBBYTE(tmp); *pW = W[i++ - Nk] ^ tmp;
+	case 7: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
+	case 6: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
+	case 5: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
+	}
+    }
+    /* Generate the last word */
+    tmp = *pW++;
+    tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
+    *pW = W[i++ - Nk] ^ tmp;
+    /* There may be overflow here, if Nk % (Nb * (Nr + 1)) > 0.  However,
+     * since the above loop generated all but the last Nk key words, there
+     * is no more need for the SubByte transformation.
+     */
+    if (Nk < 8) {
+	for (; i < round_key_words; ++i) {
+	    tmp = *pW++; 
+	    *pW = W[i - Nk] ^ tmp;
+	}
+    } else {
+	/* except in the case when Nk == 8.  Then one more SubByte may have
+	 * to be performed, at i % Nk == 4.
+	 */
+	for (; i < round_key_words; ++i) {
+	    tmp = *pW++;
+	    if (i % Nk == 4)
+		tmp = SUBBYTE(tmp);
+	    *pW = W[i - Nk] ^ tmp;
+	}
+    }
+    return SECSuccess;
+}
+
+/* rijndael_invkey_expansion
+ *
+ * Generate the expanded key for the inverse cipher from the key input by 
+ * the user.
+ */
+static SECStatus
+rijndael_invkey_expansion(AESContext *cx, const unsigned char *key, unsigned int Nk)
+{
+    unsigned int r;
+    PRUint32 *roundkeyw;
+    PRUint8 *b;
+    int Nb = cx->Nb;
+    /* begins like usual key expansion ... */
+    if (rijndael_key_expansion(cx, key, Nk) != SECSuccess)
+	return SECFailure;
+    /* ... but has the additional step of InvMixColumn,
+     * excepting the first and last round keys.
+     */
+    roundkeyw = cx->expandedKey + cx->Nb;
+    for (r=1; r<cx->Nr; ++r) {
+	/* each key word, roundkeyw, represents a column in the key
+	 * matrix.  Each column is multiplied by the InvMixColumn matrix.
+	 *   [ 0E 0B 0D 09 ]   [ b0 ]
+	 *   [ 09 0E 0B 0D ] * [ b1 ]
+	 *   [ 0D 09 0E 0B ]   [ b2 ]
+	 *   [ 0B 0D 09 0E ]   [ b3 ]
+	 */
+	b = (PRUint8 *)roundkeyw;
+	*roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
+	b = (PRUint8 *)roundkeyw;
+	*roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
+	b = (PRUint8 *)roundkeyw;
+	*roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
+	b = (PRUint8 *)roundkeyw;
+	*roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
+	if (Nb <= 4)
+	    continue;
+	switch (Nb) {
+	case 8: b = (PRUint8 *)roundkeyw;
+	        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
+	                       IMXC2(b[2]) ^ IMXC3(b[3]);
+	case 7: b = (PRUint8 *)roundkeyw;
+	        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
+	                       IMXC2(b[2]) ^ IMXC3(b[3]);
+	case 6: b = (PRUint8 *)roundkeyw;
+	        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
+	                       IMXC2(b[2]) ^ IMXC3(b[3]);
+	case 5: b = (PRUint8 *)roundkeyw;
+	        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
+	                       IMXC2(b[2]) ^ IMXC3(b[3]);
+	}
+    }
+    return SECSuccess;
+}
+/**************************************************************************
+ *
+ * Stuff related to Rijndael encryption/decryption, optimized for
+ * a 128-bit blocksize.
+ *
+ *************************************************************************/
+
+#ifdef IS_LITTLE_ENDIAN
+#define BYTE0WORD(w) ((w) & 0x000000ff)
+#define BYTE1WORD(w) ((w) & 0x0000ff00)
+#define BYTE2WORD(w) ((w) & 0x00ff0000)
+#define BYTE3WORD(w) ((w) & 0xff000000)
+#else
+#define BYTE0WORD(w) ((w) & 0xff000000)
+#define BYTE1WORD(w) ((w) & 0x00ff0000)
+#define BYTE2WORD(w) ((w) & 0x0000ff00)
+#define BYTE3WORD(w) ((w) & 0x000000ff)
+#endif
+
+typedef union {
+    PRUint32 w[4];
+    PRUint8  b[16];
+} rijndael_state;
+
+#define COLUMN_0(state) state.w[0]
+#define COLUMN_1(state) state.w[1]
+#define COLUMN_2(state) state.w[2]
+#define COLUMN_3(state) state.w[3]
+
+#define STATE_BYTE(i) state.b[i]
+
+static SECStatus 
+rijndael_encryptBlock128(AESContext *cx, 
+                         unsigned char *output,
+                         const unsigned char *input)
+{
+    unsigned int r;
+    PRUint32 *roundkeyw;
+    rijndael_state state;
+    PRUint32 C0, C1, C2, C3;
+#if defined(NSS_X86_OR_X64)
+#define pIn input
+#define pOut output
+#else
+    unsigned char *pIn, *pOut;
+    PRUint32 inBuf[4], outBuf[4];
+
+    if ((ptrdiff_t)input & 0x3) {
+	memcpy(inBuf, input, sizeof inBuf);
+	pIn = (unsigned char *)inBuf;
+    } else {
+	pIn = (unsigned char *)input;
+    }
+    if ((ptrdiff_t)output & 0x3) {
+	pOut = (unsigned char *)outBuf;
+    } else {
+	pOut = (unsigned char *)output;
+    }
+#endif
+    roundkeyw = cx->expandedKey;
+    /* Step 1: Add Round Key 0 to initial state */
+    COLUMN_0(state) = *((PRUint32 *)(pIn     )) ^ *roundkeyw++;
+    COLUMN_1(state) = *((PRUint32 *)(pIn + 4 )) ^ *roundkeyw++;
+    COLUMN_2(state) = *((PRUint32 *)(pIn + 8 )) ^ *roundkeyw++;
+    COLUMN_3(state) = *((PRUint32 *)(pIn + 12)) ^ *roundkeyw++;
+    /* Step 2: Loop over rounds [1..NR-1] */
+    for (r=1; r<cx->Nr; ++r) {
+        /* Do ShiftRow, ByteSub, and MixColumn all at once */
+	C0 = T0(STATE_BYTE(0))  ^
+	     T1(STATE_BYTE(5))  ^
+	     T2(STATE_BYTE(10)) ^
+	     T3(STATE_BYTE(15));
+	C1 = T0(STATE_BYTE(4))  ^
+	     T1(STATE_BYTE(9))  ^
+	     T2(STATE_BYTE(14)) ^
+	     T3(STATE_BYTE(3));
+	C2 = T0(STATE_BYTE(8))  ^
+	     T1(STATE_BYTE(13)) ^
+	     T2(STATE_BYTE(2))  ^
+	     T3(STATE_BYTE(7));
+	C3 = T0(STATE_BYTE(12)) ^
+	     T1(STATE_BYTE(1))  ^
+	     T2(STATE_BYTE(6))  ^
+	     T3(STATE_BYTE(11));
+	/* Round key addition */
+	COLUMN_0(state) = C0 ^ *roundkeyw++;
+	COLUMN_1(state) = C1 ^ *roundkeyw++;
+	COLUMN_2(state) = C2 ^ *roundkeyw++;
+	COLUMN_3(state) = C3 ^ *roundkeyw++;
+    }
+    /* Step 3: Do the last round */
+    /* Final round does not employ MixColumn */
+    C0 = ((BYTE0WORD(T2(STATE_BYTE(0))))   |
+          (BYTE1WORD(T3(STATE_BYTE(5))))   |
+          (BYTE2WORD(T0(STATE_BYTE(10))))  |
+          (BYTE3WORD(T1(STATE_BYTE(15)))))  ^
+          *roundkeyw++;
+    C1 = ((BYTE0WORD(T2(STATE_BYTE(4))))   |
+          (BYTE1WORD(T3(STATE_BYTE(9))))   |
+          (BYTE2WORD(T0(STATE_BYTE(14))))  |
+          (BYTE3WORD(T1(STATE_BYTE(3)))))   ^
+          *roundkeyw++;
+    C2 = ((BYTE0WORD(T2(STATE_BYTE(8))))   |
+          (BYTE1WORD(T3(STATE_BYTE(13))))  |
+          (BYTE2WORD(T0(STATE_BYTE(2))))   |
+          (BYTE3WORD(T1(STATE_BYTE(7)))))   ^
+          *roundkeyw++;
+    C3 = ((BYTE0WORD(T2(STATE_BYTE(12))))  |
+          (BYTE1WORD(T3(STATE_BYTE(1))))   |
+          (BYTE2WORD(T0(STATE_BYTE(6))))   |
+          (BYTE3WORD(T1(STATE_BYTE(11)))))  ^
+          *roundkeyw++;
+    *((PRUint32 *) pOut     )  = C0;
+    *((PRUint32 *)(pOut + 4))  = C1;
+    *((PRUint32 *)(pOut + 8))  = C2;
+    *((PRUint32 *)(pOut + 12)) = C3;
+#if defined(NSS_X86_OR_X64)
+#undef pIn
+#undef pOut
+#else
+    if ((ptrdiff_t)output & 0x3) {
+	memcpy(output, outBuf, sizeof outBuf);
+    }
+#endif
+    return SECSuccess;
+}
+
+static SECStatus 
+rijndael_decryptBlock128(AESContext *cx, 
+                         unsigned char *output,
+                         const unsigned char *input)
+{
+    int r;
+    PRUint32 *roundkeyw;
+    rijndael_state state;
+    PRUint32 C0, C1, C2, C3;
+#if defined(NSS_X86_OR_X64)
+#define pIn input
+#define pOut output
+#else
+    unsigned char *pIn, *pOut;
+    PRUint32 inBuf[4], outBuf[4];
+
+    if ((ptrdiff_t)input & 0x3) {
+	memcpy(inBuf, input, sizeof inBuf);
+	pIn = (unsigned char *)inBuf;
+    } else {
+	pIn = (unsigned char *)input;
+    }
+    if ((ptrdiff_t)output & 0x3) {
+	pOut = (unsigned char *)outBuf;
+    } else {
+	pOut = (unsigned char *)output;
+    }
+#endif
+    roundkeyw = cx->expandedKey + cx->Nb * cx->Nr + 3;
+    /* reverse the final key addition */
+    COLUMN_3(state) = *((PRUint32 *)(pIn + 12)) ^ *roundkeyw--;
+    COLUMN_2(state) = *((PRUint32 *)(pIn +  8)) ^ *roundkeyw--;
+    COLUMN_1(state) = *((PRUint32 *)(pIn +  4)) ^ *roundkeyw--;
+    COLUMN_0(state) = *((PRUint32 *)(pIn     )) ^ *roundkeyw--;
+    /* Loop over rounds in reverse [NR..1] */
+    for (r=cx->Nr; r>1; --r) {
+	/* Invert the (InvByteSub*InvMixColumn)(InvShiftRow(state)) */
+	C0 = TInv0(STATE_BYTE(0))  ^
+	     TInv1(STATE_BYTE(13)) ^
+	     TInv2(STATE_BYTE(10)) ^
+	     TInv3(STATE_BYTE(7));
+	C1 = TInv0(STATE_BYTE(4))  ^
+	     TInv1(STATE_BYTE(1))  ^
+	     TInv2(STATE_BYTE(14)) ^
+	     TInv3(STATE_BYTE(11));
+	C2 = TInv0(STATE_BYTE(8))  ^
+	     TInv1(STATE_BYTE(5))  ^
+	     TInv2(STATE_BYTE(2))  ^
+	     TInv3(STATE_BYTE(15));
+	C3 = TInv0(STATE_BYTE(12)) ^
+	     TInv1(STATE_BYTE(9))  ^
+	     TInv2(STATE_BYTE(6))  ^
+	     TInv3(STATE_BYTE(3));
+	/* Invert the key addition step */
+	COLUMN_3(state) = C3 ^ *roundkeyw--;
+	COLUMN_2(state) = C2 ^ *roundkeyw--;
+	COLUMN_1(state) = C1 ^ *roundkeyw--;
+	COLUMN_0(state) = C0 ^ *roundkeyw--;
+    }
+    /* inverse sub */
+    pOut[ 0] = SINV(STATE_BYTE( 0));
+    pOut[ 1] = SINV(STATE_BYTE(13));
+    pOut[ 2] = SINV(STATE_BYTE(10));
+    pOut[ 3] = SINV(STATE_BYTE( 7));
+    pOut[ 4] = SINV(STATE_BYTE( 4));
+    pOut[ 5] = SINV(STATE_BYTE( 1));
+    pOut[ 6] = SINV(STATE_BYTE(14));
+    pOut[ 7] = SINV(STATE_BYTE(11));
+    pOut[ 8] = SINV(STATE_BYTE( 8));
+    pOut[ 9] = SINV(STATE_BYTE( 5));
+    pOut[10] = SINV(STATE_BYTE( 2));
+    pOut[11] = SINV(STATE_BYTE(15));
+    pOut[12] = SINV(STATE_BYTE(12));
+    pOut[13] = SINV(STATE_BYTE( 9));
+    pOut[14] = SINV(STATE_BYTE( 6));
+    pOut[15] = SINV(STATE_BYTE( 3));
+    /* final key addition */
+    *((PRUint32 *)(pOut + 12)) ^= *roundkeyw--;
+    *((PRUint32 *)(pOut +  8)) ^= *roundkeyw--;
+    *((PRUint32 *)(pOut +  4)) ^= *roundkeyw--;
+    *((PRUint32 *) pOut      ) ^= *roundkeyw--;
+#if defined(NSS_X86_OR_X64)
+#undef pIn
+#undef pOut
+#else
+    if ((ptrdiff_t)output & 0x3) {
+	memcpy(output, outBuf, sizeof outBuf);
+    }
+#endif
+    return SECSuccess;
+}
+
+/**************************************************************************
+ *
+ * Stuff related to general Rijndael encryption/decryption, for blocksizes
+ * greater than 128 bits.
+ *
+ * XXX This code is currently untested!  So far, AES specs have only been
+ *     released for 128 bit blocksizes.  This will be tested, but for now
+ *     only the code above has been tested using known values.
+ *
+ *************************************************************************/
+
+#define COLUMN(array, j) *((PRUint32 *)(array + j))
+
+SECStatus 
+rijndael_encryptBlock(AESContext *cx, 
+                      unsigned char *output,
+                      const unsigned char *input)
+{
+    return SECFailure;
+#ifdef rijndael_large_blocks_fixed
+    unsigned int j, r, Nb;
+    unsigned int c2=0, c3=0;
+    PRUint32 *roundkeyw;
+    PRUint8 clone[RIJNDAEL_MAX_STATE_SIZE];
+    Nb = cx->Nb;
+    roundkeyw = cx->expandedKey;
+    /* Step 1: Add Round Key 0 to initial state */
+    for (j=0; j<4*Nb; j+=4) {
+	COLUMN(clone, j) = COLUMN(input, j) ^ *roundkeyw++;
+    }
+    /* Step 2: Loop over rounds [1..NR-1] */
+    for (r=1; r<cx->Nr; ++r) {
+	for (j=0; j<Nb; ++j) {
+	    COLUMN(output, j) = T0(STATE_BYTE(4*  j          )) ^
+	                        T1(STATE_BYTE(4*((j+ 1)%Nb)+1)) ^
+	                        T2(STATE_BYTE(4*((j+c2)%Nb)+2)) ^
+	                        T3(STATE_BYTE(4*((j+c3)%Nb)+3));
+	}
+	for (j=0; j<4*Nb; j+=4) {
+	    COLUMN(clone, j) = COLUMN(output, j) ^ *roundkeyw++;
+	}
+    }
+    /* Step 3: Do the last round */
+    /* Final round does not employ MixColumn */
+    for (j=0; j<Nb; ++j) {
+	COLUMN(output, j) = ((BYTE0WORD(T2(STATE_BYTE(4* j         ))))  |
+                             (BYTE1WORD(T3(STATE_BYTE(4*(j+ 1)%Nb)+1)))  |
+                             (BYTE2WORD(T0(STATE_BYTE(4*(j+c2)%Nb)+2)))  |
+                             (BYTE3WORD(T1(STATE_BYTE(4*(j+c3)%Nb)+3)))) ^
+	                     *roundkeyw++;
+    }
+    return SECSuccess;
+#endif
+}
+
+SECStatus 
+rijndael_decryptBlock(AESContext *cx, 
+                      unsigned char *output,
+                      const unsigned char *input)
+{
+    return SECFailure;
+#ifdef rijndael_large_blocks_fixed
+    int j, r, Nb;
+    int c2=0, c3=0;
+    PRUint32 *roundkeyw;
+    PRUint8 clone[RIJNDAEL_MAX_STATE_SIZE];
+    Nb = cx->Nb;
+    roundkeyw = cx->expandedKey + cx->Nb * cx->Nr + 3;
+    /* reverse key addition */
+    for (j=4*Nb; j>=0; j-=4) {
+	COLUMN(clone, j) = COLUMN(input, j) ^ *roundkeyw--;
+    }
+    /* Loop over rounds in reverse [NR..1] */
+    for (r=cx->Nr; r>1; --r) {
+	/* Invert the (InvByteSub*InvMixColumn)(InvShiftRow(state)) */
+	for (j=0; j<Nb; ++j) {
+	    COLUMN(output, 4*j) = TInv0(STATE_BYTE(4* j            )) ^
+	                          TInv1(STATE_BYTE(4*(j+Nb- 1)%Nb)+1) ^
+	                          TInv2(STATE_BYTE(4*(j+Nb-c2)%Nb)+2) ^
+	                          TInv3(STATE_BYTE(4*(j+Nb-c3)%Nb)+3);
+	}
+	/* Invert the key addition step */
+	for (j=4*Nb; j>=0; j-=4) {
+	    COLUMN(clone, j) = COLUMN(output, j) ^ *roundkeyw--;
+	}
+    }
+    /* inverse sub */
+    for (j=0; j<4*Nb; ++j) {
+	output[j] = SINV(clone[j]);
+    }
+    /* final key addition */
+    for (j=4*Nb; j>=0; j-=4) {
+	COLUMN(output, j) ^= *roundkeyw--;
+    }
+    return SECSuccess;
+#endif
+}
+
+/**************************************************************************
+ *
+ *  Rijndael modes of operation (ECB and CBC)
+ *
+ *************************************************************************/
+
+static SECStatus 
+rijndael_encryptECB(AESContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen, 
+                    unsigned int blocksize)
+{
+    SECStatus rv;
+    AESBlockFunc *encryptor;
+
+
+    encryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
+				  ? &rijndael_encryptBlock128 
+				  : &rijndael_encryptBlock;
+    while (inputLen > 0) {
+        rv = (*encryptor)(cx, output, input);
+	if (rv != SECSuccess)
+	    return rv;
+	output += blocksize;
+	input += blocksize;
+	inputLen -= blocksize;
+    }
+    return SECSuccess;
+}
+
+static SECStatus 
+rijndael_encryptCBC(AESContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen, 
+                    unsigned int blocksize)
+{
+    unsigned int j;
+    SECStatus rv;
+    AESBlockFunc *encryptor;
+    unsigned char *lastblock;
+    unsigned char inblock[RIJNDAEL_MAX_STATE_SIZE * 8];
+
+    if (!inputLen)
+	return SECSuccess;
+    lastblock = cx->iv;
+    encryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
+				  ? &rijndael_encryptBlock128 
+				  : &rijndael_encryptBlock;
+    while (inputLen > 0) {
+	/* XOR with the last block (IV if first block) */
+	for (j=0; j<blocksize; ++j)
+	    inblock[j] = input[j] ^ lastblock[j];
+	/* encrypt */
+        rv = (*encryptor)(cx, output, inblock);
+	if (rv != SECSuccess)
+	    return rv;
+	/* move to the next block */
+	lastblock = output;
+	output += blocksize;
+	input += blocksize;
+	inputLen -= blocksize;
+    }
+    memcpy(cx->iv, lastblock, blocksize);
+    return SECSuccess;
+}
+
+static SECStatus 
+rijndael_decryptECB(AESContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen, 
+                    unsigned int blocksize)
+{
+    SECStatus rv;
+    AESBlockFunc *decryptor;
+
+    decryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
+				  ? &rijndael_decryptBlock128 
+				  : &rijndael_decryptBlock;
+    while (inputLen > 0) {
+        rv = (*decryptor)(cx, output, input);
+	if (rv != SECSuccess)
+	    return rv;
+	output += blocksize;
+	input += blocksize;
+	inputLen -= blocksize;
+    }
+    return SECSuccess;
+}
+
+static SECStatus 
+rijndael_decryptCBC(AESContext *cx, unsigned char *output,
+                    unsigned int *outputLen, unsigned int maxOutputLen,
+                    const unsigned char *input, unsigned int inputLen, 
+                    unsigned int blocksize)
+{
+    SECStatus rv;
+    AESBlockFunc *decryptor;
+    const unsigned char *in;
+    unsigned char *out;
+    unsigned int j;
+    unsigned char newIV[RIJNDAEL_MAX_BLOCKSIZE];
+
+
+    if (!inputLen) 
+	return SECSuccess;
+    PORT_Assert(output - input >= 0 || input - output >= (int)inputLen );
+    decryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
+                                  ? &rijndael_decryptBlock128 
+				  : &rijndael_decryptBlock;
+    in  = input  + (inputLen - blocksize);
+    memcpy(newIV, in, blocksize);
+    out = output + (inputLen - blocksize);
+    while (inputLen > blocksize) {
+        rv = (*decryptor)(cx, out, in);
+	if (rv != SECSuccess)
+	    return rv;
+	for (j=0; j<blocksize; ++j)
+	    out[j] ^= in[(int)(j - blocksize)];
+	out -= blocksize;
+	in -= blocksize;
+	inputLen -= blocksize;
+    }
+    if (in == input) {
+        rv = (*decryptor)(cx, out, in);
+	if (rv != SECSuccess)
+	    return rv;
+	for (j=0; j<blocksize; ++j)
+	    out[j] ^= cx->iv[j];
+    }
+    memcpy(cx->iv, newIV, blocksize);
+    return SECSuccess;
+}
+
+/************************************************************************
+ *
+ * BLAPI Interface functions
+ *
+ * The following functions implement the encryption routines defined in
+ * BLAPI for the AES cipher, Rijndael.
+ *
+ ***********************************************************************/
+
+AESContext * AES_AllocateContext(void)
+{
+    return PORT_ZNew(AESContext);
+}
+
+
+SECStatus   
+AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, 
+	        const unsigned char *iv, int mode, unsigned int encrypt,
+	        unsigned int blocksize)
+{
+#if USE_HW_AES
+    static int has_intel_aes;
+    PRBool use_hw_aes = PR_FALSE;
+#endif
+    unsigned int Nk;
+    /* According to Rijndael AES Proposal, section 12.1, block and key
+     * lengths between 128 and 256 bits are supported, as long as the
+     * length in bytes is divisible by 4.
+     */
+    if (key == NULL || 
+        keysize < RIJNDAEL_MIN_BLOCKSIZE   || 
+	keysize > RIJNDAEL_MAX_BLOCKSIZE   || 
+	keysize % 4 != 0 ||
+        blocksize < RIJNDAEL_MIN_BLOCKSIZE || 
+	blocksize > RIJNDAEL_MAX_BLOCKSIZE || 
+	blocksize % 4 != 0) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (mode != NSS_AES && mode != NSS_AES_CBC) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (mode == NSS_AES_CBC && iv == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (!cx) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    	return SECFailure;
+    }
+#if USE_HW_AES
+    if (has_intel_aes == 0) {
+	unsigned long eax, ebx, ecx, edx;
+
+	freebl_cpuid(1, &eax, &ebx, &ecx, &edx);
+	has_intel_aes = (ecx & (1 << 25)) != 0 ? 1 : -1;
+    }
+    use_hw_aes = (PRBool)
+		(has_intel_aes > 0 && (keysize % 8) == 0 && blocksize == 16);
+#endif
+    /* Nb = (block size in bits) / 32 */
+    cx->Nb = blocksize / 4;
+    /* Nk = (key size in bits) / 32 */
+    Nk = keysize / 4;
+    /* Obtain number of rounds from "table" */
+    cx->Nr = RIJNDAEL_NUM_ROUNDS(Nk, cx->Nb);
+    /* copy in the iv, if neccessary */
+    if (mode == NSS_AES_CBC) {
+	memcpy(cx->iv, iv, blocksize);
+#if USE_HW_AES
+	if (use_hw_aes) {
+	    cx->worker = intel_aes_cbc_worker(encrypt, keysize);
+	} else
+#endif
+	    cx->worker = (encrypt
+			  ? &rijndael_encryptCBC : &rijndael_decryptCBC);
+    } else {
+#if  USE_HW_AES
+	if (use_hw_aes) {
+	    cx->worker = intel_aes_ecb_worker(encrypt, keysize);
+	} else
+#endif
+	    cx->worker = (encrypt
+			  ? &rijndael_encryptECB : &rijndael_decryptECB);
+    }
+    PORT_Assert((cx->Nb * (cx->Nr + 1)) <= RIJNDAEL_MAX_EXP_KEY_SIZE);
+    if ((cx->Nb * (cx->Nr + 1)) > RIJNDAEL_MAX_EXP_KEY_SIZE) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	goto cleanup;
+    }
+#ifdef USE_HW_AES
+    if (use_hw_aes) {
+	intel_aes_init(encrypt, keysize);
+    } else
+#endif
+    {
+
+#if defined(RIJNDAEL_GENERATE_TABLES) ||  \
+	defined(RIJNDAEL_GENERATE_TABLES_MACRO)
+	if (rijndaelTables == NULL) {
+	    if (PR_CallOnce(&coRTInit, init_rijndael_tables)
+	      != PR_SUCCESS) {
+		return SecFailure;
+	    }
+	}
+#endif
+	/* Generate expanded key */
+	if (encrypt) {
+	    if (rijndael_key_expansion(cx, key, Nk) != SECSuccess)
+		goto cleanup;
+	} else {
+	    if (rijndael_invkey_expansion(cx, key, Nk) != SECSuccess)
+		goto cleanup;
+	}
+    }
+    return SECSuccess;
+cleanup:
+    return SECFailure;
+}
+
+
+/* AES_CreateContext
+ *
+ * create a new context for Rijndael operations
+ */
+AESContext *
+AES_CreateContext(const unsigned char *key, const unsigned char *iv, 
+                  int mode, int encrypt,
+                  unsigned int keysize, unsigned int blocksize)
+{
+    AESContext *cx = AES_AllocateContext();
+    if (cx) {
+	SECStatus rv = AES_InitContext(cx, key, keysize, iv, mode, encrypt,
+				       blocksize);
+	if (rv != SECSuccess) {
+	    AES_DestroyContext(cx, PR_TRUE);
+	    cx = NULL;
+	}
+    }
+    return cx;
+}
+
+/*
+ * AES_DestroyContext
+ * 
+ * Zero an AES cipher context.  If freeit is true, also free the pointer
+ * to the context.
+ */
+void 
+AES_DestroyContext(AESContext *cx, PRBool freeit)
+{
+/*  memset(cx, 0, sizeof *cx); */
+    if (freeit)
+	PORT_Free(cx);
+}
+
+/*
+ * AES_Encrypt
+ *
+ * Encrypt an arbitrary-length buffer.  The output buffer must already be
+ * allocated to at least inputLen.
+ */
+SECStatus 
+AES_Encrypt(AESContext *cx, unsigned char *output,
+            unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen)
+{
+    int blocksize;
+    /* Check args */
+    if (cx == NULL || output == NULL || input == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    blocksize = 4 * cx->Nb;
+    if (inputLen % blocksize != 0) {
+	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	return SECFailure;
+    }
+    if (maxOutputLen < inputLen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return SECFailure;
+    }
+    *outputLen = inputLen;
+    return (*cx->worker)(cx, output, outputLen, maxOutputLen,	
+                             input, inputLen, blocksize);
+}
+
+/*
+ * AES_Decrypt
+ *
+ * Decrypt and arbitrary-length buffer.  The output buffer must already be
+ * allocated to at least inputLen.
+ */
+SECStatus 
+AES_Decrypt(AESContext *cx, unsigned char *output,
+            unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen)
+{
+    int blocksize;
+    /* Check args */
+    if (cx == NULL || output == NULL || input == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    blocksize = 4 * cx->Nb;
+    if (inputLen % blocksize != 0) {
+	PORT_SetError(SEC_ERROR_INPUT_LEN);
+	return SECFailure;
+    }
+    if (maxOutputLen < inputLen) {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return SECFailure;
+    }
+    *outputLen = inputLen;
+    return (*cx->worker)(cx, output, outputLen, maxOutputLen,	
+                             input, inputLen, blocksize);
+}
diff --git a/mozilla/security/nss/lib/freebl/rijndael.h b/mozilla/security/nss/lib/freebl/rijndael.h
new file mode 100644
index 0000000..3677576
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/rijndael.h
@@ -0,0 +1,95 @@
+/* ***** 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 ***** */
+/* $Id: rijndael.h,v 1.11 2005/08/06 07:24:21 nelsonb%netscape.com Exp $ */
+
+#ifndef _RIJNDAEL_H_
+#define _RIJNDAEL_H_ 1
+
+#define RIJNDAEL_MIN_BLOCKSIZE 16 /* bytes */
+#define RIJNDAEL_MAX_BLOCKSIZE 32 /* bytes */
+
+typedef SECStatus AESFunc(AESContext *cx, unsigned char *output,
+                          unsigned int *outputLen, unsigned int maxOutputLen,
+                          const unsigned char *input, unsigned int inputLen, 
+                          unsigned int blocksize);
+
+typedef SECStatus AESBlockFunc(AESContext *cx, 
+                               unsigned char *output,
+                               const unsigned char *input);
+
+/* RIJNDAEL_NUM_ROUNDS
+ *
+ * Number of rounds per execution
+ * Nk - number of key bytes
+ * Nb - blocksize (in bytes)
+ */
+#define RIJNDAEL_NUM_ROUNDS(Nk, Nb) \
+    (PR_MAX(Nk, Nb) + 6)
+
+/* RIJNDAEL_MAX_STATE_SIZE 
+ *
+ * Maximum number of bytes in the state (spec includes up to 256-bit block
+ * size)
+ */
+#define RIJNDAEL_MAX_STATE_SIZE 32
+
+/*
+ * This magic number is (Nb_max * (Nr_max + 1))
+ * where Nb_max is the maximum block size in 32-bit words,
+ *       Nr_max is the maximum number of rounds, which is Nb_max + 6
+ */
+#define RIJNDAEL_MAX_EXP_KEY_SIZE (8 * 15)
+
+/* AESContextStr
+ *
+ * Values which maintain the state for Rijndael encryption/decryption.
+ *
+ * iv          - initialization vector for CBC mode
+ * Nb          - the number of bytes in a block, specified by user
+ * Nr          - the number of rounds, specified by a table
+ * expandedKey - the round keys in 4-byte words, the length is Nr * Nb
+ * worker      - the encryption/decryption function to use with this context
+ */
+struct AESContextStr
+{
+    unsigned int   Nb;
+    unsigned int   Nr;
+    AESFunc       *worker;
+    unsigned char iv[RIJNDAEL_MAX_BLOCKSIZE];
+    PRUint32      expandedKey[RIJNDAEL_MAX_EXP_KEY_SIZE];
+};
+
+#endif /* _RIJNDAEL_H_ */
diff --git a/mozilla/security/nss/lib/freebl/rijndael32.tab b/mozilla/security/nss/lib/freebl/rijndael32.tab
new file mode 100644
index 0000000..6b78e2e
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/rijndael32.tab
@@ -0,0 +1,1215 @@
+#ifndef RIJNDAEL_INCLUDE_TABLES
+static const PRUint8 _S[256] = 
+{
+ 99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 118,
+202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
+183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 216,  49,  21,
+  4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 235,  39, 178, 117,
+  9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 179,  41, 227,  47, 132,
+ 83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 190,  57,  74,  76,  88, 207,
+208, 239, 170, 251,  67,  77,  51, 133,  69, 249,   2, 127,  80,  60, 159, 168,
+ 81, 163,  64, 143, 146, 157,  56, 245, 188, 182, 218,  33,  16, 255, 243, 210,
+205,  12,  19, 236,  95, 151,  68,  23, 196, 167, 126,  61, 100,  93,  25, 115,
+ 96, 129,  79, 220,  34,  42, 144, 136,  70, 238, 184,  20, 222,  94,  11, 219,
+224,  50,  58,  10,  73,   6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121,
+231, 200,  55, 109, 141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8,
+186, 120,  37,  46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138,
+112,  62, 181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158,
+225, 248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
+140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  22 
+};
+#endif /* not RIJNDAEL_INCLUDE_TABLES */
+
+static const PRUint8 _SInv[256] = 
+{
+ 82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 251,
+124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 233, 203,
+ 84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 250, 195,  78,
+  8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 109, 139, 209,  37,
+114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 204,  93, 101, 182, 146,
+108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  70,  87, 167, 141, 157, 132,
+144, 216, 171,   0, 140, 188, 211,  10, 247, 228,  88,   5, 184, 179,  69,   6,
+208,  44,  30, 143, 202,  63,  15,   2, 193, 175, 189,   3,   1,  19, 138, 107,
+ 58, 145,  17,  65,  79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115,
+150, 172, 116,  34, 231, 173,  53, 133, 226, 249,  55, 232,  28, 117, 223, 110,
+ 71, 241,  26, 113,  29,  41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27,
+252,  86,  62,  75, 198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,
+ 31, 221, 168,  51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,
+ 96,  81, 127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239,
+160, 224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97,
+ 23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12, 125 
+};
+
+#ifdef RIJNDAEL_INCLUDE_TABLES
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _T0[256] = 
+{
+0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6,
+0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
+0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f,
+0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
+0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
+0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551,
+0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
+0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637,
+0x0f05050a, 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d,
+0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
+0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd,
+0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
+0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
+0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a,
+0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
+0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d,
+0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5,
+0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
+0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755,
+0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
+0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
+0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264,
+0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
+0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531,
+0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac,
+0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
+0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657,
+0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
+0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
+0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199,
+0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
+0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c,
+0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7,
+0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
+0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c  
+};
+#else
+static const PRUint32 _T0[256] = 
+{
+0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd,
+0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
+0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d,
+0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
+0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7,
+0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
+0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4,
+0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
+0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1,
+0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
+0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e,
+0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
+0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e,
+0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
+0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46,
+0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
+0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7,
+0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
+0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe,
+0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
+0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a,
+0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
+0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2,
+0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
+0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e,
+0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
+0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256,
+0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
+0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4,
+0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
+0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa,
+0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
+0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1,
+0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
+0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42,
+0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
+0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158,
+0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
+0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22,
+0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
+0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631,
+0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
+0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _T1[256] = 
+{
+0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd,
+0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d,
+0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d,
+0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
+0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7,
+0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a,
+0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4,
+0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
+0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1,
+0x05050a0f, 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
+0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, 0x83831d9e,
+0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
+0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e,
+0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c,
+0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46,
+0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
+0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7,
+0x33336655, 0x85851194, 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81,
+0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe,
+0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
+0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a,
+0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,
+0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2,
+0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
+0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e,
+0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c,
+0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, 0xe0e0db3b, 0x32326456,
+0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
+0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4,
+0xe4e4d337, 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
+0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa,
+0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
+0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1,
+0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,
+0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42,
+0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
+0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958,
+0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233,
+0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22,
+0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
+0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731,
+0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11,
+0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a  
+};
+#else
+static const PRUint32 _T1[256] = 
+{
+0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b,
+0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b,
+0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282,
+0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
+0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4,
+0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626,
+0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5,
+0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
+0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696,
+0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2,
+0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383,
+0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
+0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3,
+0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded,
+0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb,
+0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
+0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d,
+0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f,
+0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3,
+0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
+0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff,
+0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec,
+0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7,
+0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
+0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a,
+0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414,
+0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232,
+0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
+0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595,
+0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d,
+0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656,
+0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
+0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6,
+0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f,
+0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e,
+0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
+0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1,
+0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111,
+0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e,
+0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
+0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6,
+0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f,
+0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _T2[256] = 
+{
+0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b,
+0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b,
+0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82,
+0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
+0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4,
+0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26,
+0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5,
+0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
+0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196,
+0x050a0f05, 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
+0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, 0x831d9e83,
+0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
+0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3,
+0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced,
+0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb,
+0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
+0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d,
+0x33665533, 0x85119485, 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f,
+0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3,
+0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
+0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff,
+0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,
+0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7,
+0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
+0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a,
+0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14,
+0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, 0xe0db3be0, 0x32645632,
+0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
+0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495,
+0xe4d337e4, 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
+0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56,
+0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
+0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6,
+0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,
+0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e,
+0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
+0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1,
+0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311,
+0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e,
+0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
+0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6,
+0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f,
+0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16  
+};
+#else
+static const PRUint32 _T2[256] = 
+{
+0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b,
+0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b,
+0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82,
+0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
+0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4,
+0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26,
+0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5,
+0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
+0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796,
+0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2,
+0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83,
+0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
+0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3,
+0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed,
+0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb,
+0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
+0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d,
+0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f,
+0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3,
+0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
+0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff,
+0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec,
+0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7,
+0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
+0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a,
+0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814,
+0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432,
+0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
+0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195,
+0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d,
+0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56,
+0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
+0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6,
+0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f,
+0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e,
+0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
+0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1,
+0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211,
+0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e,
+0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
+0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6,
+0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f,
+0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _T3[256] = 
+{
+0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b,
+0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b,
+0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282,
+0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
+0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4,
+0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626,
+0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5,
+0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
+0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696,
+0x0a0f0505, 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
+0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383,
+0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
+0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3,
+0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded,
+0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb,
+0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
+0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d,
+0x66553333, 0x11948585, 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f,
+0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3,
+0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
+0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff,
+0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,
+0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7,
+0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
+0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a,
+0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414,
+0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 0xdb3be0e0, 0x64563232,
+0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
+0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595,
+0xd337e4e4, 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
+0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656,
+0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
+0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6,
+0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,
+0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e,
+0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
+0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1,
+0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111,
+0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e,
+0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
+0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6,
+0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f,
+0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616  
+};
+#else
+static const PRUint32 _T3[256] = 
+{
+0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6,
+0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56,
+0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f,
+0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
+0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753,
+0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c,
+0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451,
+0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
+0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137,
+0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf,
+0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d,
+0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
+0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd,
+0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1,
+0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d,
+0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
+0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a,
+0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe,
+0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d,
+0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
+0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5,
+0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3,
+0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255,
+0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
+0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54,
+0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28,
+0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664,
+0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
+0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431,
+0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da,
+0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac,
+0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
+0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157,
+0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e,
+0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c,
+0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
+0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899,
+0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322,
+0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c,
+0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
+0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7,
+0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e,
+0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _TInv0[256] = 
+{
+0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f,
+0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5,
+0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 0x495ab1de, 0x671bba25,
+0x980eea45, 0xe1c0fe5d, 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b,
+0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927,
+0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5,
+0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9,
+0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72,
+0x578f1fe3, 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7,
+0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4,
+0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040,
+0x069f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d,
+0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879,
+0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 0x83868009, 0x48ed2b32,
+0xac70111e, 0x4e725a6c, 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36,
+0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793,
+0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 0xadc78bf2,
+0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3,
+0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb,
+0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684,
+0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947,
+0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 0xc74e4987, 0xc1d138d9,
+0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f,
+0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890,
+0x5ef7392e, 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 0xf418596e,
+0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef,
+0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a,
+0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733,
+0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546,
+0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92,
+0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb,
+0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255,
+0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0x0c25e2bc,
+0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664,
+0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0  
+};
+#else
+static const PRUint32 _TInv0[256] = 
+{
+0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1,
+0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25,
+0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67,
+0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
+0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3,
+0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd,
+0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182,
+0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
+0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2,
+0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5,
+0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492,
+0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
+0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa,
+0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46,
+0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997,
+0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
+0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48,
+0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927,
+0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f,
+0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
+0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad,
+0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd,
+0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc,
+0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
+0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3,
+0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422,
+0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1,
+0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
+0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8,
+0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3,
+0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4,
+0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
+0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331,
+0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815,
+0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d,
+0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
+0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252,
+0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89,
+0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f,
+0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
+0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c,
+0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
+0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _TInv1[256] = 
+{
+0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1,
+0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525,
+0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, 0x5ab1de49, 0x1bba2567,
+0x0eea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6,
+0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3,
+0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd,
+0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582,
+0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994,
+0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2,
+0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5,
+0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792,
+0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a,
+0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa,
+0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46,
+0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697,
+0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db,
+0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, 0x86800983, 0xed2b3248,
+0x70111eac, 0x725a6c4e, 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627,
+0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f,
+0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16,
+0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, 0xc78bf2ad,
+0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd,
+0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc,
+0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420,
+0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3,
+0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722,
+0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 0x4e4987c7, 0xd138d9c1,
+0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4,
+0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8,
+0xf7392e5e, 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3,
+0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4,
+0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6,
+0x9be7bad9, 0x366f4ace, 0x099fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31,
+0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315,
+0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d,
+0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f,
+0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252,
+0x5610e933, 0x47d66d13, 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89,
+0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f,
+0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886,
+0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c,
+0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490,
+0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042  
+};
+#else
+static const PRUint32 _TInv1[256] = 
+{
+0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45,
+0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c,
+0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b,
+0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
+0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421,
+0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971,
+0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31,
+0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
+0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02,
+0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708,
+0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4,
+0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
+0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef,
+0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd,
+0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9,
+0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
+0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed,
+0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39,
+0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7,
+0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
+0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7,
+0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60,
+0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6,
+0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
+0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230,
+0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964,
+0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1,
+0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
+0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8,
+0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512,
+0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918,
+0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
+0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23,
+0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8,
+0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0,
+0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
+0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2,
+0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c,
+0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273,
+0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
+0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225,
+0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1,
+0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _TInv2[256] = 
+{
+0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145,
+0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c,
+0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, 0xb1de495a, 0xba25671b,
+0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9,
+0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321,
+0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71,
+0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231,
+0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b,
+0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202,
+0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508,
+0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4,
+0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, 0x34d11f62, 0xa6c48afe,
+0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef,
+0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd,
+0x5491b58d, 0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9,
+0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee,
+0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, 0x80098386, 0x2b3248ed,
+0x111eac70, 0x5a6c4e72, 0x0efdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739,
+0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7,
+0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a,
+0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, 0x8bf2adc7,
+0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60,
+0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6,
+0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011,
+0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330,
+0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264,
+0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 0x4987c74e, 0x38d9c1d1,
+0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf,
+0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8,
+0x392e5ef7, 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312,
+0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418,
+0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8,
+0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123,
+0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8,
+0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0,
+0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51,
+0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, 0x67b35a1d, 0xdb9252d2,
+0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c,
+0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73,
+0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db,
+0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25,
+0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1,
+0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257  
+};
+#else
+static const PRUint32 _TInv2[256] = 
+{
+0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d,
+0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502,
+0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba,
+0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
+0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874,
+0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9,
+0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a,
+0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
+0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b,
+0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337,
+0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779,
+0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
+0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060,
+0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6,
+0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd,
+0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
+0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b,
+0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d,
+0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357,
+0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
+0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b,
+0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f,
+0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23,
+0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
+0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2,
+0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9,
+0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938,
+0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
+0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8,
+0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25,
+0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59,
+0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
+0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f,
+0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7,
+0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef,
+0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
+0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db,
+0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13,
+0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2,
+0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
+0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2,
+0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456,
+0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _TInv3[256] = 
+{
+0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d,
+0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02,
+0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, 0xde495ab1, 0x25671bba,
+0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3,
+0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174,
+0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9,
+0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a,
+0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08,
+0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b,
+0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837,
+0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479,
+0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, 0xd11f6234, 0xc48afea6,
+0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, 0x0b39ec83, 0x40aaef60,
+0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6,
+0x91b58d54, 0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd,
+0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8,
+0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, 0x09838680, 0x3248ed2b,
+0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 0x0f563885, 0x3d1ed5ae, 0x3627392d,
+0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757,
+0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12,
+0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, 0xf2adc78b,
+0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f,
+0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623,
+0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6,
+0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2,
+0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9,
+0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 0x87c74e49, 0xd9c1d138,
+0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad,
+0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8,
+0x2e5ef739, 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225,
+0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859,
+0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815,
+0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f,
+0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7,
+0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef,
+0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165,
+0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db,
+0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13,
+0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2,
+0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44,
+0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2,
+0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c, 0xd89ce4b4, 0x6490c156,
+0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8  
+};
+#else
+static const PRUint32 _TInv3[256] = 
+{
+0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f,
+0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5,
+0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725,
+0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
+0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358,
+0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27,
+0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5,
+0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
+0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272,
+0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3,
+0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7,
+0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
+0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40,
+0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d,
+0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6,
+0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
+0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832,
+0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736,
+0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93,
+0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
+0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2,
+0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3,
+0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb,
+0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
+0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc,
+0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247,
+0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9,
+0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
+0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890,
+0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf,
+0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e,
+0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
+0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a,
+0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533,
+0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43,
+0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
+0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292,
+0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb,
+0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55,
+0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
+0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc,
+0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064,
+0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _IMXC0[256] = 
+{
+0x00000000, 0x0b0d090e, 0x161a121c, 0x1d171b12, 0x2c342438, 0x27392d36,
+0x3a2e3624, 0x31233f2a, 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362,
+0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a, 0xb0d090e0, 0xbbdd99ee,
+0xa6ca82fc, 0xadc78bf2, 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca,
+0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382, 0xc48cfca8, 0xcf81f5a6,
+0xd296eeb4, 0xd99be7ba, 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9,
+0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1, 0x23d373ab, 0x28de7aa5,
+0x35c961b7, 0x3ec468b9, 0x0fe75793, 0x04ea5e9d, 0x19fd458f, 0x12f04c81,
+0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029, 0xe75f8f03, 0xec52860d,
+0xf1459d1f, 0xfa489411, 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859,
+0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61, 0xf66d76ad, 0xfd607fa3,
+0xe07764b1, 0xeb7a6dbf, 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987,
+0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf, 0x82311ae5, 0x893c13eb,
+0x942b08f9, 0x9f2601f7, 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f,
+0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967, 0x1ed5ae3d, 0x15d8a733,
+0x08cfbc21, 0x03c2b52f, 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117,
+0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664, 0xa1e2694e, 0xaaef6040,
+0xb7f87b52, 0xbcf5725c, 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14,
+0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c, 0x3d06dd96, 0x360bd498,
+0x2b1ccf8a, 0x2011c684, 0x1132f9ae, 0x1a3ff0a0, 0x0728ebb2, 0x0c25e2bc,
+0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4, 0x495ab1de, 0x4257b8d0,
+0x5f40a3c2, 0x544daacc, 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753,
+0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b, 0xafb2a431, 0xa4bfad3f,
+0xb9a8b62d, 0xb2a5bf23, 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b,
+0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3, 0x6b3e5899, 0x60335197,
+0x7d244a85, 0x7629438b, 0x1f6234d1, 0x146f3ddf, 0x097826cd, 0x02752fc3,
+0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb, 0x8c61d79a, 0x876cde94,
+0x9a7bc586, 0x9176cc88, 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0,
+0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8, 0xf83dbbd2, 0xf330b2dc,
+0xee27a9ce, 0xe52aa0c0, 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68,
+0x10856342, 0x1b886a4c, 0x069f715e, 0x0d927850, 0x64d90f0a, 0x6fd40604,
+0x72c31d16, 0x79ce1418, 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020,
+0x01b79aec, 0x0aba93e2, 0x17ad88f0, 0x1ca081fe, 0x2d83bed4, 0x268eb7da,
+0x3b99acc8, 0x3094a5c6, 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e,
+0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6, 0xb1670a0c, 0xba6a0302,
+0xa77d1810, 0xac70111e, 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526,
+0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e, 0xc53b6644, 0xce366f4a,
+0xd3217458, 0xd82c7d56, 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25,
+0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d, 0x2264e947, 0x2969e049,
+0x347efb5b, 0x3f73f255, 0x0e50cd7f, 0x055dc471, 0x184adf63, 0x1347d66d,
+0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5, 0xe6e815ef, 0xede51ce1,
+0xf0f207f3, 0xfbff0efd, 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5,
+0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d  
+};
+#else
+static const PRUint32 _IMXC0[256] = 
+{
+0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
+0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
+0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
+0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
+0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
+0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
+0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
+0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
+0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
+0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
+0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
+0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
+0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
+0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
+0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
+0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
+0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
+0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
+0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
+0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
+0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
+0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
+0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
+0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
+0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
+0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
+0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
+0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
+0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
+0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
+0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
+0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
+0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
+0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
+0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
+0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
+0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
+0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
+0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
+0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
+0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
+0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
+0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _IMXC1[256] = 
+{
+0x00000000, 0x0d090e0b, 0x1a121c16, 0x171b121d, 0x3424382c, 0x392d3627,
+0x2e36243a, 0x233f2a31, 0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245,
+0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69, 0xd090e0b0, 0xdd99eebb,
+0xca82fca6, 0xc78bf2ad, 0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81,
+0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5, 0x8cfca8c4, 0x81f5a6cf,
+0x96eeb4d2, 0x9be7bad9, 0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966,
+0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a, 0xd373ab23, 0xde7aa528,
+0xc961b735, 0xc468b93e, 0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112,
+0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6, 0x5f8f03e7, 0x52860dec,
+0x459d1ff1, 0x489411fa, 0x03e34b93, 0x0eea4598, 0x19f15785, 0x14f8598e,
+0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2, 0x6d76adf6, 0x607fa3fd,
+0x7764b1e0, 0x7a6dbfeb, 0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7,
+0x053eddae, 0x0837d3a5, 0x1f2cc1b8, 0x1225cfb3, 0x311ae582, 0x3c13eb89,
+0x2b08f994, 0x2601f79f, 0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b,
+0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777, 0xd5ae3d1e, 0xd8a73315,
+0xcfbc2108, 0xc2b52f03, 0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f,
+0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490, 0xe2694ea1, 0xef6040aa,
+0xf87b52b7, 0xf5725cbc, 0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8,
+0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4, 0x06dd963d, 0x0bd49836,
+0x1ccf8a2b, 0x11c68420, 0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c,
+0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478, 0x5ab1de49, 0x57b8d042,
+0x40a3c25f, 0x4daacc54, 0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea,
+0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6, 0xb2a431af, 0xbfad3fa4,
+0xa8b62db9, 0xa5bf23b2, 0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e,
+0x0a7ca147, 0x0775af4c, 0x106ebd51, 0x1d67b35a, 0x3e58996b, 0x33519760,
+0x244a857d, 0x29438b76, 0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302,
+0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e, 0x61d79a8c, 0x6cde9487,
+0x7bc5869a, 0x76cc8891, 0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd,
+0x099fead4, 0x0496e4df, 0x138df6c2, 0x1e84f8c9, 0x3dbbd2f8, 0x30b2dcf3,
+0x27a9ceee, 0x2aa0c0e5, 0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821,
+0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d, 0xd90f0a64, 0xd406046f,
+0xc31d1672, 0xce141879, 0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055,
+0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c, 0x83bed42d, 0x8eb7da26,
+0x99acc83b, 0x94a5c630, 0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44,
+0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668, 0x670a0cb1, 0x6a0302ba,
+0x7d1810a7, 0x70111eac, 0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680,
+0x0f427ce9, 0x024b72e2, 0x155060ff, 0x18596ef4, 0x3b6644c5, 0x366f4ace,
+0x217458d3, 0x2c7d56d8, 0x0ca1377a, 0x01a83971, 0x16b32b6c, 0x1bba2567,
+0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b, 0x64e94722, 0x69e04929,
+0x7efb5b34, 0x73f2553f, 0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13,
+0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7, 0xe815efe6, 0xe51ce1ed,
+0xf207f3f0, 0xff0efdfb, 0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f,
+0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3  
+};
+#else
+static const PRUint32 _IMXC1[256] = 
+{
+0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39,
+0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f,
+0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd,
+0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3,
+0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581,
+0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac,
+0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade,
+0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0,
+0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652,
+0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814,
+0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60,
+0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e,
+0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c,
+0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa,
+0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8,
+0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6,
+0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef,
+0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9,
+0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b,
+0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225,
+0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857,
+0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd,
+0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf,
+0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91,
+0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133,
+0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75,
+0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c,
+0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842,
+0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230,
+0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6,
+0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4,
+0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa,
+0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e,
+0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8,
+0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a,
+0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544,
+0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36,
+0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b,
+0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069,
+0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647,
+0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5,
+0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3,
+0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _IMXC2[256] = 
+{
+0x00000000, 0x090e0b0d, 0x121c161a, 0x1b121d17, 0x24382c34, 0x2d362739,
+0x36243a2e, 0x3f2a3123, 0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f,
+0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b, 0x90e0b0d0, 0x99eebbdd,
+0x82fca6ca, 0x8bf2adc7, 0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3,
+0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af, 0xfca8c48c, 0xf5a6cf81,
+0xeeb4d296, 0xe7bad99b, 0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac,
+0x1fe3578f, 0x16ed5c82, 0x0dff4195, 0x04f14a98, 0x73ab23d3, 0x7aa528de,
+0x61b735c9, 0x68b93ec4, 0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0,
+0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c, 0x8f03e75f, 0x860dec52,
+0x9d1ff145, 0x9411fa48, 0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14,
+0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220, 0x76adf66d, 0x7fa3fd60,
+0x64b1e077, 0x6dbfeb7a, 0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e,
+0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312, 0x1ae58231, 0x13eb893c,
+0x08f9942b, 0x01f79f26, 0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa,
+0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e, 0xae3d1ed5, 0xa73315d8,
+0xbc2108cf, 0xb52f03c2, 0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6,
+0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1, 0x694ea1e2, 0x6040aaef,
+0x7b52b7f8, 0x725cbcf5, 0x0506d5be, 0x0c08deb3, 0x171ac3a4, 0x1e14c8a9,
+0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d, 0xdd963d06, 0xd498360b,
+0xcf8a2b1c, 0xc6842011, 0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25,
+0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879, 0xb1de495a, 0xb8d04257,
+0xa3c25f40, 0xaacc544d, 0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd,
+0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9, 0xa431afb2, 0xad3fa4bf,
+0xb62db9a8, 0xbf23b2a5, 0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91,
+0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d, 0x58996b3e, 0x51976033,
+0x4a857d24, 0x438b7629, 0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275,
+0x10e93356, 0x19e7385b, 0x02f5254c, 0x0bfb2e41, 0xd79a8c61, 0xde94876c,
+0xc5869a7b, 0xcc889176, 0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42,
+0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e, 0xbbd2f83d, 0xb2dcf330,
+0xa9ceee27, 0xa0c0e52a, 0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6,
+0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92, 0x0f0a64d9, 0x06046fd4,
+0x1d1672c3, 0x141879ce, 0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa,
+0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0, 0xbed42d83, 0xb7da268e,
+0xacc83b99, 0xa5c63094, 0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8,
+0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc, 0x0a0cb167, 0x0302ba6a,
+0x1810a77d, 0x111eac70, 0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044,
+0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418, 0x6644c53b, 0x6f4ace36,
+0x7458d321, 0x7d56d82c, 0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b,
+0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f, 0xe9472264, 0xe0492969,
+0xfb5b347e, 0xf2553f73, 0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347,
+0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb, 0x15efe6e8, 0x1ce1ede5,
+0x07f3f0f2, 0x0efdfbff, 0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3,
+0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397  
+};
+#else
+static const PRUint32 _IMXC2[256] = 
+{
+0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d,
+0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253,
+0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99,
+0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf,
+0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5,
+0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920,
+0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a,
+0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c,
+0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86,
+0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8,
+0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f,
+0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749,
+0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13,
+0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd,
+0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7,
+0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791,
+0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060,
+0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e,
+0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4,
+0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2,
+0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8,
+0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7,
+0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad,
+0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b,
+0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751,
+0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f,
+0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de,
+0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8,
+0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2,
+0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c,
+0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406,
+0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030,
+0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7,
+0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9,
+0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203,
+0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635,
+0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f,
+0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba,
+0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0,
+0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6,
+0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c,
+0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562,
+0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46  
+};
+#endif
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 _IMXC3[256] = 
+{
+0x00000000, 0x0e0b0d09, 0x1c161a12, 0x121d171b, 0x382c3424, 0x3627392d,
+0x243a2e36, 0x2a31233f, 0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53,
+0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77, 0xe0b0d090, 0xeebbdd99,
+0xfca6ca82, 0xf2adc78b, 0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af,
+0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3, 0xa8c48cfc, 0xa6cf81f5,
+0xb4d296ee, 0xbad99be7, 0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20,
+0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804, 0xab23d373, 0xa528de7a,
+0xb735c961, 0xb93ec468, 0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c,
+0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0, 0x03e75f8f, 0x0dec5286,
+0x1ff1459d, 0x11fa4894, 0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8,
+0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc, 0xadf66d76, 0xa3fd607f,
+0xb1e07764, 0xbfeb7a6d, 0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49,
+0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225, 0xe582311a, 0xeb893c13,
+0xf9942b08, 0xf79f2601, 0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd,
+0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9, 0x3d1ed5ae, 0x3315d8a7,
+0x2108cfbc, 0x2f03c2b5, 0x0532e18a, 0x0b39ec83, 0x1924fb98, 0x172ff691,
+0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156, 0x4ea1e269, 0x40aaef60,
+0x52b7f87b, 0x5cbcf572, 0x06d5be05, 0x08deb30c, 0x1ac3a417, 0x14c8a91e,
+0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a, 0x963d06dd, 0x98360bd4,
+0x8a2b1ccf, 0x842011c6, 0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2,
+0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e, 0xde495ab1, 0xd04257b8,
+0xc25f40a3, 0xcc544daa, 0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7,
+0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3, 0x31afb2a4, 0x3fa4bfad,
+0x2db9a8b6, 0x23b2a5bf, 0x09838680, 0x07888b89, 0x15959c92, 0x1b9e919b,
+0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67, 0x996b3e58, 0x97603351,
+0x857d244a, 0x8b762943, 0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f,
+0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b, 0x9a8c61d7, 0x94876cde,
+0x869a7bc5, 0x889176cc, 0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8,
+0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84, 0xd2f83dbb, 0xdcf330b2,
+0xceee27a9, 0xc0e52aa0, 0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c,
+0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278, 0x0a64d90f, 0x046fd406,
+0x1672c31d, 0x1879ce14, 0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30,
+0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081, 0xd42d83be, 0xda268eb7,
+0xc83b99ac, 0xc63094a5, 0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9,
+0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced, 0x0cb1670a, 0x02ba6a03,
+0x10a77d18, 0x1eac7011, 0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435,
+0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859, 0x44c53b66, 0x4ace366f,
+0x58d32174, 0x56d82c7d, 0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba,
+0x0f563885, 0x015d358c, 0x13402297, 0x1d4b2f9e, 0x472264e9, 0x492969e0,
+0x5b347efb, 0x553f73f2, 0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6,
+0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a, 0xefe6e815, 0xe1ede51c,
+0xf3f0f207, 0xfdfbff0e, 0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362,
+0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746  
+};
+#else
+static const PRUint32 _IMXC3[256] = 
+{
+0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736,
+0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562,
+0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee,
+0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca,
+0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6,
+0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9,
+0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5,
+0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281,
+0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d,
+0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59,
+0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3,
+0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787,
+0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb,
+0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f,
+0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533,
+0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17,
+0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40,
+0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814,
+0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698,
+0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc,
+0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0,
+0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53,
+0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f,
+0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b,
+0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097,
+0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3,
+0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794,
+0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0,
+0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc,
+0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168,
+0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04,
+0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520,
+0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da,
+0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e,
+0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02,
+0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026,
+0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a,
+0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725,
+0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949,
+0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d,
+0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1,
+0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5,
+0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d  
+};
+#endif
+
+#endif /* RIJNDAEL_INCLUDE_TABLES */
+
+#ifdef IS_LITTLE_ENDIAN
+static const PRUint32 Rcon[30] = {
+0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
+0x00000040, 0x00000080, 0x0000001b, 0x00000036, 0x0000006c, 0x000000d8,
+0x000000ab, 0x0000004d, 0x0000009a, 0x0000002f, 0x0000005e, 0x000000bc,
+0x00000063, 0x000000c6, 0x00000097, 0x00000035, 0x0000006a, 0x000000d4,
+0x000000b3, 0x0000007d, 0x000000fa, 0x000000ef, 0x000000c5, 0x00000091 
+};
+#else
+static const PRUint32 Rcon[30] = {
+0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
+0x40000000, 0x80000000, 0x1b000000, 0x36000000, 0x6c000000, 0xd8000000,
+0xab000000, 0x4d000000, 0x9a000000, 0x2f000000, 0x5e000000, 0xbc000000,
+0x63000000, 0xc6000000, 0x97000000, 0x35000000, 0x6a000000, 0xd4000000,
+0xb3000000, 0x7d000000, 0xfa000000, 0xef000000, 0xc5000000, 0x91000000 
+};
+#endif
+
diff --git a/mozilla/security/nss/lib/freebl/rsa.c b/mozilla/security/nss/lib/freebl/rsa.c
new file mode 100644
index 0000000..293b5ef
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/rsa.c
@@ -0,0 +1,991 @@
+/* ***** 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 ***** */
+
+/*
+ * RSA key generation, public key op, private key op.
+ *
+ * $Id: rsa.c,v 1.39 2009/02/03 05:34:41 julien.pierre.boogz%sun.com Exp $
+ */
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "secerr.h"
+
+#include "prclist.h"
+#include "nssilock.h"
+#include "prinit.h"
+#include "blapi.h"
+#include "mpi.h"
+#include "mpprime.h"
+#include "mplogic.h"
+#include "secmpi.h"
+#include "secitem.h"
+#include "blapii.h"
+
+/*
+** Number of times to attempt to generate a prime (p or q) from a random
+** seed (the seed changes for each iteration).
+*/
+#define MAX_PRIME_GEN_ATTEMPTS 10
+/*
+** Number of times to attempt to generate a key.  The primes p and q change
+** for each attempt.
+*/
+#define MAX_KEY_GEN_ATTEMPTS 10
+
+/* exponent should not be greater than modulus */
+#define BAD_RSA_KEY_SIZE(modLen, expLen) \
+    ((expLen) > (modLen) || (modLen) > RSA_MAX_MODULUS_BITS/8 || \
+    (expLen) > RSA_MAX_EXPONENT_BITS/8)
+
+/*
+** RSABlindingParamsStr
+**
+** For discussion of Paul Kocher's timing attack against an RSA private key
+** operation, see http://www.cryptography.com/timingattack/paper.html.  The 
+** countermeasure to this attack, known as blinding, is also discussed in 
+** the Handbook of Applied Cryptography, 11.118-11.119.
+*/
+struct RSABlindingParamsStr
+{
+    /* Blinding-specific parameters */
+    PRCList   link;                  /* link to list of structs            */
+    SECItem   modulus;               /* list element "key"                 */
+    mp_int    f, g;                  /* Blinding parameters                */
+    int       counter;               /* number of remaining uses of (f, g) */
+};
+
+/*
+** RSABlindingParamsListStr
+**
+** List of key-specific blinding params.  The arena holds the volatile pool
+** of memory for each entry and the list itself.  The lock is for list
+** operations, in this case insertions and iterations, as well as control
+** of the counter for each set of blinding parameters.
+*/
+struct RSABlindingParamsListStr
+{
+    PZLock  *lock;   /* Lock for the list   */
+    PRCList  head;   /* Pointer to the list */
+};
+
+/*
+** The master blinding params list.
+*/
+static struct RSABlindingParamsListStr blindingParamsList = { 0 };
+
+/* Number of times to reuse (f, g).  Suggested by Paul Kocher */
+#define RSA_BLINDING_PARAMS_MAX_REUSE 50
+
+/* Global, allows optional use of blinding.  On by default. */
+/* Cannot be changed at the moment, due to thread-safety issues. */
+static PRBool nssRSAUseBlinding = PR_TRUE;
+
+static SECStatus
+rsa_keygen_from_primes(mp_int *p, mp_int *q, mp_int *e, RSAPrivateKey *key,
+                       unsigned int keySizeInBits)
+{
+    mp_int n, d, phi;
+    mp_int psub1, qsub1, tmp;
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    MP_DIGITS(&n)     = 0;
+    MP_DIGITS(&d)     = 0;
+    MP_DIGITS(&phi)   = 0;
+    MP_DIGITS(&psub1) = 0;
+    MP_DIGITS(&qsub1) = 0;
+    MP_DIGITS(&tmp)   = 0;
+    CHECK_MPI_OK( mp_init(&n)     );
+    CHECK_MPI_OK( mp_init(&d)     );
+    CHECK_MPI_OK( mp_init(&phi)   );
+    CHECK_MPI_OK( mp_init(&psub1) );
+    CHECK_MPI_OK( mp_init(&qsub1) );
+    CHECK_MPI_OK( mp_init(&tmp)   );
+    /* 1.  Compute n = p*q */
+    CHECK_MPI_OK( mp_mul(p, q, &n) );
+    /*     verify that the modulus has the desired number of bits */
+    if ((unsigned)mpl_significant_bits(&n) != keySizeInBits) {
+	PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	rv = SECFailure;
+	goto cleanup;
+    }
+    /* 2.  Compute phi = (p-1)*(q-1) */
+    CHECK_MPI_OK( mp_sub_d(p, 1, &psub1) );
+    CHECK_MPI_OK( mp_sub_d(q, 1, &qsub1) );
+    CHECK_MPI_OK( mp_mul(&psub1, &qsub1, &phi) );
+    /* 3.  Compute d = e**-1 mod(phi) */
+    err = mp_invmod(e, &phi, &d);
+    /*     Verify that phi(n) and e have no common divisors */
+    if (err != MP_OKAY) {
+	if (err == MP_UNDEF) {
+	    PORT_SetError(SEC_ERROR_NEED_RANDOM);
+	    err = MP_OKAY; /* to keep PORT_SetError from being called again */
+	    rv = SECFailure;
+	}
+	goto cleanup;
+    }
+    MPINT_TO_SECITEM(&n, &key->modulus, key->arena);
+    MPINT_TO_SECITEM(&d, &key->privateExponent, key->arena);
+    /* 4.  Compute exponent1 = d mod (p-1) */
+    CHECK_MPI_OK( mp_mod(&d, &psub1, &tmp) );
+    MPINT_TO_SECITEM(&tmp, &key->exponent1, key->arena);
+    /* 5.  Compute exponent2 = d mod (q-1) */
+    CHECK_MPI_OK( mp_mod(&d, &qsub1, &tmp) );
+    MPINT_TO_SECITEM(&tmp, &key->exponent2, key->arena);
+    /* 6.  Compute coefficient = q**-1 mod p */
+    CHECK_MPI_OK( mp_invmod(q, p, &tmp) );
+    MPINT_TO_SECITEM(&tmp, &key->coefficient, key->arena);
+cleanup:
+    mp_clear(&n);
+    mp_clear(&d);
+    mp_clear(&phi);
+    mp_clear(&psub1);
+    mp_clear(&qsub1);
+    mp_clear(&tmp);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+static SECStatus
+generate_prime(mp_int *prime, int primeLen)
+{
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    unsigned long counter = 0;
+    int piter;
+    unsigned char *pb = NULL;
+    pb = PORT_Alloc(primeLen);
+    if (!pb) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	goto cleanup;
+    }
+    for (piter = 0; piter < MAX_PRIME_GEN_ATTEMPTS; piter++) {
+	CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) );
+	pb[0]          |= 0xC0; /* set two high-order bits */
+	pb[primeLen-1] |= 0x01; /* set low-order bit       */
+	CHECK_MPI_OK( mp_read_unsigned_octets(prime, pb, primeLen) );
+	err = mpp_make_prime(prime, primeLen * 8, PR_FALSE, &counter);
+	if (err != MP_NO)
+	    goto cleanup;
+	/* keep going while err == MP_NO */
+    }
+cleanup:
+    if (pb)
+	PORT_ZFree(pb, primeLen);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+/*
+** Generate and return a new RSA public and private key.
+**	Both keys are encoded in a single RSAPrivateKey structure.
+**	"cx" is the random number generator context
+**	"keySizeInBits" is the size of the key to be generated, in bits.
+**	   512, 1024, etc.
+**	"publicExponent" when not NULL is a pointer to some data that
+**	   represents the public exponent to use. The data is a byte
+**	   encoded integer, in "big endian" order.
+*/
+RSAPrivateKey *
+RSA_NewKey(int keySizeInBits, SECItem *publicExponent)
+{
+    unsigned int primeLen;
+    mp_int p, q, e;
+    int kiter;
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    int prerr = 0;
+    RSAPrivateKey *key = NULL;
+    PRArenaPool *arena = NULL;
+    /* Require key size to be a multiple of 16 bits. */
+    if (!publicExponent || keySizeInBits % 16 != 0 ||
+	    BAD_RSA_KEY_SIZE(keySizeInBits/8, publicExponent->len)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    /* 1. Allocate arena & key */
+    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+    key = (RSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(RSAPrivateKey));
+    if (!key) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	PORT_FreeArena(arena, PR_TRUE);
+	return NULL;
+    }
+    key->arena = arena;
+    /* length of primes p and q (in bytes) */
+    primeLen = keySizeInBits / (2 * BITS_PER_BYTE);
+    MP_DIGITS(&p) = 0;
+    MP_DIGITS(&q) = 0;
+    MP_DIGITS(&e) = 0;
+    CHECK_MPI_OK( mp_init(&p) );
+    CHECK_MPI_OK( mp_init(&q) );
+    CHECK_MPI_OK( mp_init(&e) );
+    /* 2.  Set the version number (PKCS1 v1.5 says it should be zero) */
+    SECITEM_AllocItem(arena, &key->version, 1);
+    key->version.data[0] = 0;
+    /* 3.  Set the public exponent */
+    SECITEM_CopyItem(arena, &key->publicExponent, publicExponent);
+    SECITEM_TO_MPINT(*publicExponent, &e);
+    kiter = 0;
+    do {
+	prerr = 0;
+	PORT_SetError(0);
+	CHECK_SEC_OK( generate_prime(&p, primeLen) );
+	CHECK_SEC_OK( generate_prime(&q, primeLen) );
+	/* Assure q < p */
+	if (mp_cmp(&p, &q) < 0)
+	    mp_exch(&p, &q);
+	/* Attempt to use these primes to generate a key */
+	rv = rsa_keygen_from_primes(&p, &q, &e, key, keySizeInBits);
+	if (rv == SECSuccess)
+	    break; /* generated two good primes */
+	prerr = PORT_GetError();
+	kiter++;
+	/* loop until have primes */
+    } while (prerr == SEC_ERROR_NEED_RANDOM && kiter < MAX_KEY_GEN_ATTEMPTS);
+    if (prerr)
+	goto cleanup;
+    MPINT_TO_SECITEM(&p, &key->prime1, arena);
+    MPINT_TO_SECITEM(&q, &key->prime2, arena);
+cleanup:
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&e);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    if (rv && arena) {
+	PORT_FreeArena(arena, PR_TRUE);
+	key = NULL;
+    }
+    return key;
+}
+
+static unsigned int
+rsa_modulusLen(SECItem *modulus)
+{
+    unsigned char byteZero = modulus->data[0];
+    unsigned int modLen = modulus->len - !byteZero;
+    return modLen;
+}
+
+/*
+** Perform a raw public-key operation 
+**	Length of input and output buffers are equal to key's modulus len.
+*/
+SECStatus 
+RSA_PublicKeyOp(RSAPublicKey  *key, 
+                unsigned char *output, 
+                const unsigned char *input)
+{
+    unsigned int modLen, expLen, offset;
+    mp_int n, e, m, c;
+    mp_err err   = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    if (!key || !output || !input) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    MP_DIGITS(&n) = 0;
+    MP_DIGITS(&e) = 0;
+    MP_DIGITS(&m) = 0;
+    MP_DIGITS(&c) = 0;
+    CHECK_MPI_OK( mp_init(&n) );
+    CHECK_MPI_OK( mp_init(&e) );
+    CHECK_MPI_OK( mp_init(&m) );
+    CHECK_MPI_OK( mp_init(&c) );
+    modLen = rsa_modulusLen(&key->modulus);
+    expLen = rsa_modulusLen(&key->publicExponent);
+    /* 1.  Obtain public key (n, e) */
+    if (BAD_RSA_KEY_SIZE(modLen, expLen)) {
+    	PORT_SetError(SEC_ERROR_INVALID_KEY);
+	rv = SECFailure;
+	goto cleanup;
+    }
+    SECITEM_TO_MPINT(key->modulus, &n);
+    SECITEM_TO_MPINT(key->publicExponent, &e);
+    if (e.used > n.used) {
+	/* exponent should not be greater than modulus */
+    	PORT_SetError(SEC_ERROR_INVALID_KEY);
+	rv = SECFailure;
+	goto cleanup;
+    }
+    /* 2. check input out of range (needs to be in range [0..n-1]) */
+    offset = (key->modulus.data[0] == 0) ? 1 : 0; /* may be leading 0 */
+    if (memcmp(input, key->modulus.data + offset, modLen) >= 0) {
+        PORT_SetError(SEC_ERROR_INPUT_LEN);
+        rv = SECFailure;
+        goto cleanup;
+    }
+    /* 2 bis.  Represent message as integer in range [0..n-1] */
+    CHECK_MPI_OK( mp_read_unsigned_octets(&m, input, modLen) );
+    /* 3.  Compute c = m**e mod n */
+#ifdef USE_MPI_EXPT_D
+    /* XXX see which is faster */
+    if (MP_USED(&e) == 1) {
+	CHECK_MPI_OK( mp_exptmod_d(&m, MP_DIGIT(&e, 0), &n, &c) );
+    } else
+#endif
+    CHECK_MPI_OK( mp_exptmod(&m, &e, &n, &c) );
+    /* 4.  result c is ciphertext */
+    err = mp_to_fixlen_octets(&c, output, modLen);
+    if (err >= 0) err = MP_OKAY;
+cleanup:
+    mp_clear(&n);
+    mp_clear(&e);
+    mp_clear(&m);
+    mp_clear(&c);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+/*
+**  RSA Private key operation (no CRT).
+*/
+static SECStatus 
+rsa_PrivateKeyOpNoCRT(RSAPrivateKey *key, mp_int *m, mp_int *c, mp_int *n,
+                      unsigned int modLen)
+{
+    mp_int d;
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    MP_DIGITS(&d) = 0;
+    CHECK_MPI_OK( mp_init(&d) );
+    SECITEM_TO_MPINT(key->privateExponent, &d);
+    /* 1. m = c**d mod n */
+    CHECK_MPI_OK( mp_exptmod(c, &d, n, m) );
+cleanup:
+    mp_clear(&d);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+/*
+**  RSA Private key operation using CRT.
+*/
+static SECStatus 
+rsa_PrivateKeyOpCRTNoCheck(RSAPrivateKey *key, mp_int *m, mp_int *c)
+{
+    mp_int p, q, d_p, d_q, qInv;
+    mp_int m1, m2, h, ctmp;
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    MP_DIGITS(&p)    = 0;
+    MP_DIGITS(&q)    = 0;
+    MP_DIGITS(&d_p)  = 0;
+    MP_DIGITS(&d_q)  = 0;
+    MP_DIGITS(&qInv) = 0;
+    MP_DIGITS(&m1)   = 0;
+    MP_DIGITS(&m2)   = 0;
+    MP_DIGITS(&h)    = 0;
+    MP_DIGITS(&ctmp) = 0;
+    CHECK_MPI_OK( mp_init(&p)    );
+    CHECK_MPI_OK( mp_init(&q)    );
+    CHECK_MPI_OK( mp_init(&d_p)  );
+    CHECK_MPI_OK( mp_init(&d_q)  );
+    CHECK_MPI_OK( mp_init(&qInv) );
+    CHECK_MPI_OK( mp_init(&m1)   );
+    CHECK_MPI_OK( mp_init(&m2)   );
+    CHECK_MPI_OK( mp_init(&h)    );
+    CHECK_MPI_OK( mp_init(&ctmp) );
+    /* copy private key parameters into mp integers */
+    SECITEM_TO_MPINT(key->prime1,      &p);    /* p */
+    SECITEM_TO_MPINT(key->prime2,      &q);    /* q */
+    SECITEM_TO_MPINT(key->exponent1,   &d_p);  /* d_p  = d mod (p-1) */
+    SECITEM_TO_MPINT(key->exponent2,   &d_q);  /* d_q  = d mod (q-1) */
+    SECITEM_TO_MPINT(key->coefficient, &qInv); /* qInv = q**-1 mod p */
+    /* 1. m1 = c**d_p mod p */
+    CHECK_MPI_OK( mp_mod(c, &p, &ctmp) );
+    CHECK_MPI_OK( mp_exptmod(&ctmp, &d_p, &p, &m1) );
+    /* 2. m2 = c**d_q mod q */
+    CHECK_MPI_OK( mp_mod(c, &q, &ctmp) );
+    CHECK_MPI_OK( mp_exptmod(&ctmp, &d_q, &q, &m2) );
+    /* 3.  h = (m1 - m2) * qInv mod p */
+    CHECK_MPI_OK( mp_submod(&m1, &m2, &p, &h) );
+    CHECK_MPI_OK( mp_mulmod(&h, &qInv, &p, &h)  );
+    /* 4.  m = m2 + h * q */
+    CHECK_MPI_OK( mp_mul(&h, &q, m) );
+    CHECK_MPI_OK( mp_add(m, &m2, m) );
+cleanup:
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&d_p);
+    mp_clear(&d_q);
+    mp_clear(&qInv);
+    mp_clear(&m1);
+    mp_clear(&m2);
+    mp_clear(&h);
+    mp_clear(&ctmp);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+/*
+** An attack against RSA CRT was described by Boneh, DeMillo, and Lipton in:
+** "On the Importance of Eliminating Errors in Cryptographic Computations",
+** http://theory.stanford.edu/~dabo/papers/faults.ps.gz
+**
+** As a defense against the attack, carry out the private key operation, 
+** followed up with a public key operation to invert the result.  
+** Verify that result against the input.
+*/
+static SECStatus 
+rsa_PrivateKeyOpCRTCheckedPubKey(RSAPrivateKey *key, mp_int *m, mp_int *c)
+{
+    mp_int n, e, v;
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    MP_DIGITS(&n) = 0;
+    MP_DIGITS(&e) = 0;
+    MP_DIGITS(&v) = 0;
+    CHECK_MPI_OK( mp_init(&n) );
+    CHECK_MPI_OK( mp_init(&e) );
+    CHECK_MPI_OK( mp_init(&v) );
+    CHECK_SEC_OK( rsa_PrivateKeyOpCRTNoCheck(key, m, c) );
+    SECITEM_TO_MPINT(key->modulus,        &n);
+    SECITEM_TO_MPINT(key->publicExponent, &e);
+    /* Perform a public key operation v = m ** e mod n */
+    CHECK_MPI_OK( mp_exptmod(m, &e, &n, &v) );
+    if (mp_cmp(&v, c) != 0) {
+	rv = SECFailure;
+    }
+cleanup:
+    mp_clear(&n);
+    mp_clear(&e);
+    mp_clear(&v);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+static PRCallOnceType coBPInit = { 0, 0, 0 };
+static PRStatus 
+init_blinding_params_list(void)
+{
+    blindingParamsList.lock = PZ_NewLock(nssILockOther);
+    if (!blindingParamsList.lock) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return PR_FAILURE;
+    }
+    PR_INIT_CLIST(&blindingParamsList.head);
+    return PR_SUCCESS;
+}
+
+static SECStatus
+generate_blinding_params(struct RSABlindingParamsStr *rsabp, 
+                         RSAPrivateKey *key, mp_int *n, unsigned int modLen)
+{
+    SECStatus rv = SECSuccess;
+    mp_int e, k;
+    mp_err err = MP_OKAY;
+    unsigned char *kb = NULL;
+    MP_DIGITS(&e) = 0;
+    MP_DIGITS(&k) = 0;
+    CHECK_MPI_OK( mp_init(&e) );
+    CHECK_MPI_OK( mp_init(&k) );
+    SECITEM_TO_MPINT(key->publicExponent, &e);
+    /* generate random k < n */
+    kb = PORT_Alloc(modLen);
+    if (!kb) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	goto cleanup;
+    }
+    CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(kb, modLen) );
+    CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, modLen) );
+    /* k < n */
+    CHECK_MPI_OK( mp_mod(&k, n, &k) );
+    /* f = k**e mod n */
+    CHECK_MPI_OK( mp_exptmod(&k, &e, n, &rsabp->f) );
+    /* g = k**-1 mod n */
+    CHECK_MPI_OK( mp_invmod(&k, n, &rsabp->g) );
+    /* Initialize the counter for this (f, g) */
+    rsabp->counter = RSA_BLINDING_PARAMS_MAX_REUSE;
+cleanup:
+    if (kb)
+	PORT_ZFree(kb, modLen);
+    mp_clear(&k);
+    mp_clear(&e);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+static SECStatus
+init_blinding_params(struct RSABlindingParamsStr *rsabp, RSAPrivateKey *key,
+                     mp_int *n, unsigned int modLen)
+{
+    SECStatus rv = SECSuccess;
+    mp_err err = MP_OKAY;
+    MP_DIGITS(&rsabp->f) = 0;
+    MP_DIGITS(&rsabp->g) = 0;
+    /* initialize blinding parameters */
+    CHECK_MPI_OK( mp_init(&rsabp->f) );
+    CHECK_MPI_OK( mp_init(&rsabp->g) );
+    /* List elements are keyed using the modulus */
+    SECITEM_CopyItem(NULL, &rsabp->modulus, &key->modulus);
+    CHECK_SEC_OK( generate_blinding_params(rsabp, key, n, modLen) );
+    return SECSuccess;
+cleanup:
+    mp_clear(&rsabp->f);
+    mp_clear(&rsabp->g);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+static SECStatus
+get_blinding_params(RSAPrivateKey *key, mp_int *n, unsigned int modLen,
+                    mp_int *f, mp_int *g)
+{
+    SECStatus rv = SECSuccess;
+    mp_err err = MP_OKAY;
+    int cmp;
+    PRCList *el;
+    struct RSABlindingParamsStr *rsabp = NULL;
+    /* Init the list if neccessary (the init function is only called once!) */
+    if (blindingParamsList.lock == NULL) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    /* Acquire the list lock */
+    PZ_Lock(blindingParamsList.lock);
+    /* Walk the list looking for the private key */
+    for (el = PR_NEXT_LINK(&blindingParamsList.head);
+         el != &blindingParamsList.head;
+         el = PR_NEXT_LINK(el)) {
+	rsabp = (struct RSABlindingParamsStr *)el;
+	cmp = SECITEM_CompareItem(&rsabp->modulus, &key->modulus);
+	if (cmp == 0) {
+	    /* Check the usage counter for the parameters */
+	    if (--rsabp->counter <= 0) {
+		/* Regenerate the blinding parameters */
+		CHECK_SEC_OK( generate_blinding_params(rsabp, key, n, modLen) );
+	    }
+	    /* Return the parameters */
+	    CHECK_MPI_OK( mp_copy(&rsabp->f, f) );
+	    CHECK_MPI_OK( mp_copy(&rsabp->g, g) );
+	    /* Now that the params are located, release the list lock. */
+	    PZ_Unlock(blindingParamsList.lock); /* XXX when fails? */
+	    return SECSuccess;
+	} else if (cmp > 0) {
+	    /* The key is not in the list.  Break to param creation. */
+	    break;
+	}
+    }
+    /* At this point, the key is not in the list.  el should point to the
+    ** list element that this key should be inserted before.  NOTE: the list
+    ** lock is still held, so there cannot be a race condition here.
+    */
+    rsabp = (struct RSABlindingParamsStr *)
+              PORT_ZAlloc(sizeof(struct RSABlindingParamsStr));
+    if (!rsabp) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	goto cleanup;
+    }
+    /* Initialize the list pointer for the element */
+    PR_INIT_CLIST(&rsabp->link);
+    /* Initialize the blinding parameters 
+    ** This ties up the list lock while doing some heavy, element-specific
+    ** operations, but we don't want to insert the element until it is valid,
+    ** which requires computing the blinding params.  If this proves costly,
+    ** it could be done after the list lock is released, and then if it fails
+    ** the lock would have to be reobtained and the invalid element removed.
+    */
+    rv = init_blinding_params(rsabp, key, n, modLen);
+    if (rv != SECSuccess) {
+	PORT_ZFree(rsabp, sizeof(struct RSABlindingParamsStr));
+	goto cleanup;
+    }
+    /* Insert the new element into the list
+    ** If inserting in the middle of the list, el points to the link
+    ** to insert before.  Otherwise, the link needs to be appended to
+    ** the end of the list, which is the same as inserting before the
+    ** head (since el would have looped back to the head).
+    */
+    PR_INSERT_BEFORE(&rsabp->link, el);
+    /* Return the parameters */
+    CHECK_MPI_OK( mp_copy(&rsabp->f, f) );
+    CHECK_MPI_OK( mp_copy(&rsabp->g, g) );
+    /* Release the list lock */
+    PZ_Unlock(blindingParamsList.lock); /* XXX when fails? */
+    return SECSuccess;
+cleanup:
+    /* It is possible to reach this after the lock is already released.
+    ** Ignore the error in that case.
+    */
+    PZ_Unlock(blindingParamsList.lock);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return SECFailure;
+}
+
+/*
+** Perform a raw private-key operation 
+**	Length of input and output buffers are equal to key's modulus len.
+*/
+static SECStatus 
+rsa_PrivateKeyOp(RSAPrivateKey *key, 
+                 unsigned char *output, 
+                 const unsigned char *input,
+                 PRBool check)
+{
+    unsigned int modLen;
+    unsigned int offset;
+    SECStatus rv = SECSuccess;
+    mp_err err;
+    mp_int n, c, m;
+    mp_int f, g;
+    if (!key || !output || !input) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    /* check input out of range (needs to be in range [0..n-1]) */
+    modLen = rsa_modulusLen(&key->modulus);
+    offset = (key->modulus.data[0] == 0) ? 1 : 0; /* may be leading 0 */
+    if (memcmp(input, key->modulus.data + offset, modLen) >= 0) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    MP_DIGITS(&n) = 0;
+    MP_DIGITS(&c) = 0;
+    MP_DIGITS(&m) = 0;
+    MP_DIGITS(&f) = 0;
+    MP_DIGITS(&g) = 0;
+    CHECK_MPI_OK( mp_init(&n) );
+    CHECK_MPI_OK( mp_init(&c) );
+    CHECK_MPI_OK( mp_init(&m) );
+    CHECK_MPI_OK( mp_init(&f) );
+    CHECK_MPI_OK( mp_init(&g) );
+    SECITEM_TO_MPINT(key->modulus, &n);
+    OCTETS_TO_MPINT(input, &c, modLen);
+    /* If blinding, compute pre-image of ciphertext by multiplying by
+    ** blinding factor
+    */
+    if (nssRSAUseBlinding) {
+	CHECK_SEC_OK( get_blinding_params(key, &n, modLen, &f, &g) );
+	/* c' = c*f mod n */
+	CHECK_MPI_OK( mp_mulmod(&c, &f, &n, &c) );
+    }
+    /* Do the private key operation m = c**d mod n */
+    if ( key->prime1.len      == 0 ||
+         key->prime2.len      == 0 ||
+         key->exponent1.len   == 0 ||
+         key->exponent2.len   == 0 ||
+         key->coefficient.len == 0) {
+	CHECK_SEC_OK( rsa_PrivateKeyOpNoCRT(key, &m, &c, &n, modLen) );
+    } else if (check) {
+	CHECK_SEC_OK( rsa_PrivateKeyOpCRTCheckedPubKey(key, &m, &c) );
+    } else {
+	CHECK_SEC_OK( rsa_PrivateKeyOpCRTNoCheck(key, &m, &c) );
+    }
+    /* If blinding, compute post-image of plaintext by multiplying by
+    ** blinding factor
+    */
+    if (nssRSAUseBlinding) {
+	/* m = m'*g mod n */
+	CHECK_MPI_OK( mp_mulmod(&m, &g, &n, &m) );
+    }
+    err = mp_to_fixlen_octets(&m, output, modLen);
+    if (err >= 0) err = MP_OKAY;
+cleanup:
+    mp_clear(&n);
+    mp_clear(&c);
+    mp_clear(&m);
+    mp_clear(&f);
+    mp_clear(&g);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+SECStatus 
+RSA_PrivateKeyOp(RSAPrivateKey *key, 
+                 unsigned char *output, 
+                 const unsigned char *input)
+{
+    return rsa_PrivateKeyOp(key, output, input, PR_FALSE);
+}
+
+SECStatus 
+RSA_PrivateKeyOpDoubleChecked(RSAPrivateKey *key, 
+                              unsigned char *output, 
+                              const unsigned char *input)
+{
+    return rsa_PrivateKeyOp(key, output, input, PR_TRUE);
+}
+
+static SECStatus
+swap_in_key_value(PRArenaPool *arena, mp_int *mpval, SECItem *buffer)
+{
+    int len;
+    mp_err err = MP_OKAY;
+    memset(buffer->data, 0, buffer->len);
+    len = mp_unsigned_octet_size(mpval);
+    if (len <= 0) return SECFailure;
+    if ((unsigned int)len <= buffer->len) {
+	/* The new value is no longer than the old buffer, so use it */
+	err = mp_to_unsigned_octets(mpval, buffer->data, len);
+	if (err >= 0) err = MP_OKAY;
+	buffer->len = len;
+    } else if (arena) {
+	/* The new value is longer, but working within an arena */
+	(void)SECITEM_AllocItem(arena, buffer, len);
+	err = mp_to_unsigned_octets(mpval, buffer->data, len);
+	if (err >= 0) err = MP_OKAY;
+    } else {
+	/* The new value is longer, no arena, can't handle this key */
+	return SECFailure;
+    }
+    return (err == MP_OKAY) ? SECSuccess : SECFailure;
+}
+
+SECStatus
+RSA_PrivateKeyCheck(RSAPrivateKey *key)
+{
+    mp_int p, q, n, psub1, qsub1, e, d, d_p, d_q, qInv, res;
+    mp_err   err = MP_OKAY;
+    SECStatus rv = SECSuccess;
+    MP_DIGITS(&n)    = 0;
+    MP_DIGITS(&psub1)= 0;
+    MP_DIGITS(&qsub1)= 0;
+    MP_DIGITS(&e)    = 0;
+    MP_DIGITS(&d)    = 0;
+    MP_DIGITS(&d_p)  = 0;
+    MP_DIGITS(&d_q)  = 0;
+    MP_DIGITS(&qInv) = 0;
+    MP_DIGITS(&res)  = 0;
+    CHECK_MPI_OK( mp_init(&n)    );
+    CHECK_MPI_OK( mp_init(&p)    );
+    CHECK_MPI_OK( mp_init(&q)    );
+    CHECK_MPI_OK( mp_init(&psub1));
+    CHECK_MPI_OK( mp_init(&qsub1));
+    CHECK_MPI_OK( mp_init(&e)    );
+    CHECK_MPI_OK( mp_init(&d)    );
+    CHECK_MPI_OK( mp_init(&d_p)  );
+    CHECK_MPI_OK( mp_init(&d_q)  );
+    CHECK_MPI_OK( mp_init(&qInv) );
+    CHECK_MPI_OK( mp_init(&res)  );
+    SECITEM_TO_MPINT(key->modulus,         &n);
+    SECITEM_TO_MPINT(key->prime1,          &p);
+    SECITEM_TO_MPINT(key->prime2,          &q);
+    SECITEM_TO_MPINT(key->publicExponent,  &e);
+    SECITEM_TO_MPINT(key->privateExponent, &d);
+    SECITEM_TO_MPINT(key->exponent1,       &d_p);
+    SECITEM_TO_MPINT(key->exponent2,       &d_q);
+    SECITEM_TO_MPINT(key->coefficient,     &qInv);
+    /* p > q  */
+    if (mp_cmp(&p, &q) <= 0) {
+	/* mind the p's and q's (and d_p's and d_q's) */
+	SECItem tmp;
+	mp_exch(&p, &q);
+	mp_exch(&d_p,&d_q);
+	tmp = key->prime1;
+	key->prime1 = key->prime2;
+	key->prime2 = tmp;
+	tmp = key->exponent1;
+	key->exponent1 = key->exponent2;
+	key->exponent2 = tmp;
+    }
+#define VERIFY_MPI_EQUAL(m1, m2) \
+    if (mp_cmp(m1, m2) != 0) {   \
+	rv = SECFailure;         \
+	goto cleanup;            \
+    }
+#define VERIFY_MPI_EQUAL_1(m)    \
+    if (mp_cmp_d(m, 1) != 0) {   \
+	rv = SECFailure;         \
+	goto cleanup;            \
+    }
+    /*
+     * The following errors cannot be recovered from.
+     */
+    /* n == p * q */
+    CHECK_MPI_OK( mp_mul(&p, &q, &res) );
+    VERIFY_MPI_EQUAL(&res, &n);
+    /* gcd(e, p-1) == 1 */
+    CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) );
+    CHECK_MPI_OK( mp_gcd(&e, &psub1, &res) );
+    VERIFY_MPI_EQUAL_1(&res);
+    /* gcd(e, q-1) == 1 */
+    CHECK_MPI_OK( mp_sub_d(&q, 1, &qsub1) );
+    CHECK_MPI_OK( mp_gcd(&e, &qsub1, &res) );
+    VERIFY_MPI_EQUAL_1(&res);
+    /* d*e == 1 mod p-1 */
+    CHECK_MPI_OK( mp_mulmod(&d, &e, &psub1, &res) );
+    VERIFY_MPI_EQUAL_1(&res);
+    /* d*e == 1 mod q-1 */
+    CHECK_MPI_OK( mp_mulmod(&d, &e, &qsub1, &res) );
+    VERIFY_MPI_EQUAL_1(&res);
+    /*
+     * The following errors can be recovered from.
+     */
+    /* d_p == d mod p-1 */
+    CHECK_MPI_OK( mp_mod(&d, &psub1, &res) );
+    if (mp_cmp(&d_p, &res) != 0) {
+	/* swap in the correct value */
+	CHECK_SEC_OK( swap_in_key_value(key->arena, &res, &key->exponent1) );
+    }
+    /* d_q == d mod q-1 */
+    CHECK_MPI_OK( mp_mod(&d, &qsub1, &res) );
+    if (mp_cmp(&d_q, &res) != 0) {
+	/* swap in the correct value */
+	CHECK_SEC_OK( swap_in_key_value(key->arena, &res, &key->exponent2) );
+    }
+    /* q * q**-1 == 1 mod p */
+    CHECK_MPI_OK( mp_mulmod(&q, &qInv, &p, &res) );
+    if (mp_cmp_d(&res, 1) != 0) {
+	/* compute the correct value */
+	CHECK_MPI_OK( mp_invmod(&q, &p, &qInv) );
+	CHECK_SEC_OK( swap_in_key_value(key->arena, &qInv, &key->coefficient) );
+    }
+cleanup:
+    mp_clear(&n);
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&psub1);
+    mp_clear(&qsub1);
+    mp_clear(&e);
+    mp_clear(&d);
+    mp_clear(&d_p);
+    mp_clear(&d_q);
+    mp_clear(&qInv);
+    mp_clear(&res);
+    if (err) {
+	MP_TO_SEC_ERROR(err);
+	rv = SECFailure;
+    }
+    return rv;
+}
+
+static SECStatus RSA_Init(void)
+{
+    if (PR_CallOnce(&coBPInit, init_blinding_params_list) != PR_SUCCESS) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    return SECSuccess;
+}
+
+SECStatus BL_Init(void)
+{
+    return RSA_Init();
+}
+
+/* cleanup at shutdown */
+void RSA_Cleanup(void)
+{
+    if (!coBPInit.initialized)
+	return;
+
+    while (!PR_CLIST_IS_EMPTY(&blindingParamsList.head))
+    {
+	struct RSABlindingParamsStr * rsabp = (struct RSABlindingParamsStr *)
+	    PR_LIST_HEAD(&blindingParamsList.head);
+	PR_REMOVE_LINK(&rsabp->link);
+	mp_clear(&rsabp->f);
+	mp_clear(&rsabp->g);
+	SECITEM_FreeItem(&rsabp->modulus,PR_FALSE);
+	PORT_Free(rsabp);
+    }
+
+    if (blindingParamsList.lock)
+    {
+	SKIP_AFTER_FORK(PZ_DestroyLock(blindingParamsList.lock));
+	blindingParamsList.lock = NULL;
+    }
+
+    coBPInit.initialized = 0;
+    coBPInit.inProgress = 0;
+    coBPInit.status = 0;
+}
+
+/*
+ * need a central place for this function to free up all the memory that
+ * free_bl may have allocated along the way. Currently only RSA does this,
+ * so I've put it here for now.
+ */
+void BL_Cleanup(void)
+{
+    RSA_Cleanup();
+}
+
+#if 1  /* STATIC LIBRARIES */
+void
+BL_Unload(void)
+{
+}
+#endif
+
+PRBool bl_parentForkedAfterC_Initialize;
+
+/*
+ * Set fork flag so it can be tested in SKIP_AFTER_FORK on relevant platforms.
+ */
+void BL_SetForkState(PRBool forked)
+{
+    bl_parentForkedAfterC_Initialize = forked;
+}
+
diff --git a/mozilla/security/nss/lib/freebl/sechash.h b/mozilla/security/nss/lib/freebl/sechash.h
new file mode 100644
index 0000000..6f53f36
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/sechash.h
@@ -0,0 +1,90 @@
+#ifndef _HASH_H_
+#define _HASH_H_
+/* ***** 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 ***** */
+/* $Id: sechash.h,v 1.8 2008/12/10 22:48:04 nelson%bolyard.com Exp $ */
+
+#include "seccomon.h"
+#include "hasht.h"
+#include "secoidt.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Generic hash api.  
+*/
+
+extern unsigned int  HASH_ResultLen(HASH_HashType type);
+
+extern unsigned int  HASH_ResultLenContext(HASHContext *context);
+
+extern unsigned int  HASH_ResultLenByOidTag(SECOidTag hashOid);
+
+extern SECStatus     HASH_HashBuf(HASH_HashType type,
+				 unsigned char *dest,
+				 unsigned char *src,
+				 PRUint32 src_len);
+
+extern HASHContext * HASH_Create(HASH_HashType type);
+
+extern HASHContext * HASH_Clone(HASHContext *context);
+
+extern void          HASH_Destroy(HASHContext *context);
+
+extern void          HASH_Begin(HASHContext *context);
+
+extern void          HASH_Update(HASHContext *context,
+				const unsigned char *src,
+				unsigned int len);
+
+extern void          HASH_End(HASHContext *context,
+			     unsigned char *result,
+			     unsigned int *result_len,
+			     unsigned int max_result_len);
+			     
+extern HASH_HashType HASH_GetType(HASHContext *context);
+
+extern const SECHashObject * HASH_GetHashObject(HASH_HashType type);
+
+extern const SECHashObject * HASH_GetHashObjectByOidTag(SECOidTag hashOid);
+
+extern HASH_HashType HASH_GetHashTypeByOidTag(SECOidTag hashOid);
+extern SECOidTag HASH_GetHashOidTagByHMACOidTag(SECOidTag hmacOid);
+extern SECOidTag HASH_GetHMACOidTagByHashOidTag(SECOidTag hashOid);
+
+SEC_END_PROTOS
+
+#endif /* _HASH_H_ */
diff --git a/mozilla/security/nss/lib/freebl/secmpi.h b/mozilla/security/nss/lib/freebl/secmpi.h
new file mode 100644
index 0000000..e343fb8
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/secmpi.h
@@ -0,0 +1,61 @@
+/* ***** 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 "mpi.h"
+
+#define CHECK_SEC_OK(func) if (SECSuccess != (rv = func)) goto cleanup
+
+#define CHECK_MPI_OK(func) if (MP_OKAY > (err = func)) goto cleanup
+
+#define OCTETS_TO_MPINT(oc, mp, len) \
+    CHECK_MPI_OK(mp_read_unsigned_octets((mp), oc, len))
+
+#define SECITEM_TO_MPINT(it, mp) \
+    CHECK_MPI_OK(mp_read_unsigned_octets((mp), (it).data, (it).len))
+
+#define MPINT_TO_SECITEM(mp, it, arena)                         \
+    SECITEM_AllocItem(arena, (it), mp_unsigned_octet_size(mp)); \
+    if ((it)->data == NULL) {err = MP_MEM; goto cleanup;}       \
+    err = mp_to_unsigned_octets(mp, (it)->data, (it)->len);     \
+    if (err < 0) goto cleanup; else err = MP_OKAY;
+
+#define MP_TO_SEC_ERROR(err)                                          \
+    switch (err) {                                                    \
+    case MP_MEM:    PORT_SetError(SEC_ERROR_NO_MEMORY);       break;  \
+    case MP_RANGE:  PORT_SetError(SEC_ERROR_BAD_DATA);        break;  \
+    case MP_BADARG: PORT_SetError(SEC_ERROR_INVALID_ARGS);    break;  \
+    default:        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); break;  \
+    }
diff --git a/mozilla/security/nss/lib/freebl/secrng.h b/mozilla/security/nss/lib/freebl/secrng.h
new file mode 100644
index 0000000..5cff943
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/secrng.h
@@ -0,0 +1,99 @@
+/* ***** 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 ***** */
+
+#ifndef _SECRNG_H_
+#define _SECRNG_H_
+/*
+ * secrng.h - public data structures and prototypes for the secure random
+ *	      number generator
+ *
+ * $Id: secrng.h,v 1.6 2006/10/12 02:23:49 wtchang%redhat.com Exp $
+ */
+
+/******************************************/
+/*
+** Random number generation. A cryptographically strong random number
+** generator.
+*/
+
+#include "blapi.h"
+
+/* the number of bytes to read from the system random number generator */
+#define SYSTEM_RNG_SEED_COUNT 1024
+
+SEC_BEGIN_PROTOS
+
+/*
+** The following functions are provided by the security library
+** but are differently implemented for the UNIX, Win, and OS/2
+** versions
+*/
+
+/*
+** Get the "noisiest" information available on the system.
+** The amount of data returned depends on the system implementation.
+** It will not exceed maxbytes, but may be (much) less.
+** Returns number of noise bytes copied into buf, or zero if error.
+*/
+extern size_t RNG_GetNoise(void *buf, size_t maxbytes);
+
+/*
+** RNG_SystemInfoForRNG should be called before any use of SSL. It
+** gathers up the system specific information to help seed the
+** state of the global random number generator.
+*/
+extern void RNG_SystemInfoForRNG(void);
+
+/* 
+** Use the contents (and stat) of a file to help seed the
+** global random number generator.
+*/
+extern void RNG_FileForRNG(const char *filename);
+
+/*
+** Get maxbytes bytes of random data from the system random number
+** generator.
+** Returns the number of bytes copied into buf -- maxbytes if success
+** or zero if error.
+** Errors:
+**   PR_NOT_IMPLEMENTED_ERROR   There is no system RNG on the platform.
+**   SEC_ERROR_NEED_RANDOM      The system RNG failed.
+*/
+extern size_t RNG_SystemRNG(void *buf, size_t maxbytes);
+
+SEC_END_PROTOS
+
+#endif /* _SECRNG_H_ */
diff --git a/mozilla/security/nss/lib/freebl/seed.c b/mozilla/security/nss/lib/freebl/seed.c
new file mode 100644
index 0000000..fa3e1ae
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/seed.c
@@ -0,0 +1,678 @@
+/* ***** 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 SEED code.
+ *
+ * The Initial Developer of the Original Code is
+ * KISA(Korea Information Security Agency).
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer.
+ * 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#ifdef WIN32
+#include <memory.h>
+#endif
+
+#include "seed.h"
+#include "secerr.h"
+
+static const seed_word SS[4][256] = {	
+    {
+        0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 
+        0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
+        0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 
+        0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
+        0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 
+        0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
+        0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 
+        0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec,
+        0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 
+        0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074,
+        0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 
+        0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
+        0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 
+        0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8,
+        0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 
+        0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8,
+        0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 
+        0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
+        0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 
+        0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4,
+        0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 
+        0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008,
+        0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 
+        0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
+        0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 
+        0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8,
+        0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 
+        0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208,
+        0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 
+        0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
+        0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 
+        0x06060204, 0x21012120, 0x2b4b6368, 0x26466264,
+        0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 
+        0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0,
+        0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 
+        0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
+        0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 
+        0x36063234, 0x15051114, 0x22022220, 0x38083038,
+        0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 
+        0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394,
+        0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 
+        0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
+        0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 
+        0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4,
+        0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 
+        0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8,
+        0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 
+        0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
+        0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 
+        0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040,
+        0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 
+        0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154,
+        0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 
+        0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
+        0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 
+        0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8,
+        0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 
+        0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0,
+        0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 
+        0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
+        0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 
+        0x22426260, 0x29092128, 0x07070304, 0x33033330,
+        0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 
+        0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298
+    },    
+    {
+        0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 
+        0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0,
+        0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 
+        0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53,
+        0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 
+        0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
+        0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 
+        0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43,
+        0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 
+        0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0,
+        0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 
+        0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
+        0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 
+        0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3,
+        0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 
+        0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272,
+        0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 
+        0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
+        0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 
+        0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430,
+        0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 
+        0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0,
+        0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 
+        0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
+        0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 
+        0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1,
+        0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 
+        0x20220222, 0x04040400, 0x68284860, 0x70314171,
+        0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 
+        0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
+        0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 
+        0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0,
+        0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 
+        0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3,
+        0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 
+        0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
+        0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 
+        0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62,
+        0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 
+        0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0,
+        0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 
+        0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
+        0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 
+        0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901,
+        0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 
+        0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501,
+        0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 
+        0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
+        0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 
+        0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971,
+        0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 
+        0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53,
+        0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 
+        0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
+        0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 
+        0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1,
+        0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 
+        0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70,
+        0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 
+        0x30320232, 0x84048480, 0x68294961, 0x90138393,
+        0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 
+        0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783,
+        0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 
+        0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3
+    },    
+    {
+        0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 
+        0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505,
+        0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 
+        0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343,
+        0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 
+        0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
+        0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 
+        0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece,
+        0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 
+        0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444,
+        0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 
+        0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
+        0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 
+        0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9,
+        0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 
+        0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9,
+        0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 
+        0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
+        0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 
+        0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5,
+        0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 
+        0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808,
+        0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 
+        0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
+        0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 
+        0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b,
+        0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 
+        0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a,
+        0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 
+        0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
+        0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 
+        0x02040606, 0x21202101, 0x63682b4b, 0x62642646,
+        0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 
+        0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0,
+        0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 
+        0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
+        0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 
+        0x32343606, 0x11141505, 0x22202202, 0x30383808,
+        0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 
+        0x81800181, 0xe1e829c9, 0x80840484, 0x93941787,
+        0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 
+        0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
+        0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 
+        0x90941484, 0x51581949, 0x82800282, 0xc0c404c4,
+        0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 
+        0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888,
+        0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 
+        0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
+        0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 
+        0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040,
+        0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 
+        0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545,
+        0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 
+        0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
+        0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 
+        0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca,
+        0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 
+        0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282,
+        0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 
+        0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
+        0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 
+        0x62602242, 0x21282909, 0x03040707, 0x33303303,
+        0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 
+        0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a
+    },    
+    {
+        0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 
+        0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838,
+        0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 
+        0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b,
+        0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 
+        0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
+        0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 
+        0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b,
+        0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 
+        0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434,
+        0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 
+        0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
+        0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 
+        0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f,
+        0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 
+        0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032,
+        0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 
+        0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
+        0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 
+        0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434,
+        0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 
+        0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838,
+        0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 
+        0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
+        0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 
+        0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031,
+        0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 
+        0x02222022, 0x04000404, 0x48606828, 0x41717031,
+        0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 
+        0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
+        0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 
+        0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010,
+        0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 
+        0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f,
+        0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 
+        0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
+        0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 
+        0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e,
+        0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 
+        0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c,
+        0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 
+        0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
+        0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 
+        0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809,
+        0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 
+        0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405,
+        0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 
+        0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
+        0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 
+        0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839,
+        0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 
+        0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f,
+        0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 
+        0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
+        0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 
+        0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d,
+        0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 
+        0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c,
+        0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 
+        0x02323032, 0x84808404, 0x49616829, 0x83939013,
+        0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 
+        0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407,
+        0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 
+        0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437
+    }    
+};
+
+/* key schedule constants - golden ratio */
+#define KC0     0x9e3779b9
+#define KC1     0x3c6ef373
+#define KC2     0x78dde6e6
+#define KC3     0xf1bbcdcc
+#define KC4     0xe3779b99
+#define KC5     0xc6ef3733
+#define KC6     0x8dde6e67
+#define KC7     0x1bbcdccf
+#define KC8     0x3779b99e
+#define KC9     0x6ef3733c
+#define KC10    0xdde6e678
+#define KC11    0xbbcdccf1
+#define KC12    0x779b99e3
+#define KC13    0xef3733c6
+#define KC14    0xde6e678d
+#define KC15    0xbcdccf1b
+
+
+void SEED_set_key(const unsigned char rawkey[SEED_KEY_LENGTH], 
+                  SEED_KEY_SCHEDULE *ks)
+{
+    seed_word K0, K1, K2, K3;
+    seed_word t0, t1;
+
+    char2word(rawkey   , K0);
+    char2word(rawkey+4 , K1);
+    char2word(rawkey+8 , K2);
+    char2word(rawkey+12, K3);
+
+    t0 = (K0 + K2 - KC0);
+    t1 = (K1 - K3 + KC0);                     
+    KEYUPDATE_TEMP(t0, t1, &ks->data[0]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC1);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[2]);
+    KEYSCHEDULE_UPDATE0(t0, t1, K0, K1, K2, K3, KC2);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[4]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC3);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[6]);
+    KEYSCHEDULE_UPDATE0(t0, t1, K0, K1, K2, K3, KC4);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[8]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC5);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[10]);
+    KEYSCHEDULE_UPDATE0(t0, t1, K0, K1, K2, K3, KC6);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[12]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC7);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[14]);
+    KEYSCHEDULE_UPDATE0(t0, t1, K0, K1, K2, K3, KC8);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[16]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC9);      
+    KEYUPDATE_TEMP(t0, t1, &ks->data[18]);
+    KEYSCHEDULE_UPDATE0(t0, t1, K0, K1, K2, K3, KC10);     
+    KEYUPDATE_TEMP(t0, t1, &ks->data[20]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC11);     
+    KEYUPDATE_TEMP(t0, t1, &ks->data[22]);
+    KEYSCHEDULE_UPDATE0(t0, t1, K0, K1, K2, K3, KC12);     
+    KEYUPDATE_TEMP(t0, t1, &ks->data[24]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC13);     
+    KEYUPDATE_TEMP(t0, t1, &ks->data[26]);
+    KEYSCHEDULE_UPDATE0(t0, t1, K0, K1, K2, K3, KC14);     
+    KEYUPDATE_TEMP(t0, t1, &ks->data[28]);
+    KEYSCHEDULE_UPDATE1(t0, t1, K0, K1, K2, K3, KC15);     
+    KEYUPDATE_TEMP(t0, t1, &ks->data[30]);
+}
+
+void SEED_encrypt(const unsigned char s[SEED_BLOCK_SIZE], 
+                  unsigned char d[SEED_BLOCK_SIZE], 
+                  const SEED_KEY_SCHEDULE *ks)
+{
+    seed_word L0, L1, R0, R1;
+    seed_word t0, t1;
+
+    char2word(s,    L0);
+    char2word(s+4,  L1);
+    char2word(s+8,  R0);
+    char2word(s+12, R1);
+    
+    E_SEED(t0, t1, L0, L1, R0, R1, 0);
+    E_SEED(t0, t1, R0, R1, L0, L1, 2);
+    E_SEED(t0, t1, L0, L1, R0, R1, 4);
+    E_SEED(t0, t1, R0, R1, L0, L1, 6);
+    E_SEED(t0, t1, L0, L1, R0, R1, 8);
+    E_SEED(t0, t1, R0, R1, L0, L1, 10);
+    E_SEED(t0, t1, L0, L1, R0, R1, 12);
+    E_SEED(t0, t1, R0, R1, L0, L1, 14);
+    E_SEED(t0, t1, L0, L1, R0, R1, 16);
+    E_SEED(t0, t1, R0, R1, L0, L1, 18);
+    E_SEED(t0, t1, L0, L1, R0, R1, 20);
+    E_SEED(t0, t1, R0, R1, L0, L1, 22);
+    E_SEED(t0, t1, L0, L1, R0, R1, 24);
+    E_SEED(t0, t1, R0, R1, L0, L1, 26);
+    E_SEED(t0, t1, L0, L1, R0, R1, 28);
+    E_SEED(t0, t1, R0, R1, L0, L1, 30);
+
+    word2char(R0, d);
+    word2char(R1, d+4);
+    word2char(L0, d+8);
+    word2char(L1, d+12);
+}
+
+void SEED_decrypt(const unsigned char s[SEED_BLOCK_SIZE], 
+                  unsigned char d[SEED_BLOCK_SIZE], 
+                  const SEED_KEY_SCHEDULE *ks)
+{
+    seed_word L0, L1, R0, R1;
+    seed_word t0, t1;
+
+    char2word(s,    L0);
+    char2word(s+4,  L1);
+    char2word(s+8,  R0);
+    char2word(s+12, R1);
+    
+    E_SEED(t0, t1, L0, L1, R0, R1, 30);
+    E_SEED(t0, t1, R0, R1, L0, L1, 28);
+    E_SEED(t0, t1, L0, L1, R0, R1, 26);
+    E_SEED(t0, t1, R0, R1, L0, L1, 24);
+    E_SEED(t0, t1, L0, L1, R0, R1, 22);
+    E_SEED(t0, t1, R0, R1, L0, L1, 20);
+    E_SEED(t0, t1, L0, L1, R0, R1, 18);
+    E_SEED(t0, t1, R0, R1, L0, L1, 16);
+    E_SEED(t0, t1, L0, L1, R0, R1, 14);
+    E_SEED(t0, t1, R0, R1, L0, L1, 12);
+    E_SEED(t0, t1, L0, L1, R0, R1, 10);
+    E_SEED(t0, t1, R0, R1, L0, L1, 8);
+    E_SEED(t0, t1, L0, L1, R0, R1, 6);
+    E_SEED(t0, t1, R0, R1, L0, L1, 4);
+    E_SEED(t0, t1, L0, L1, R0, R1, 2);
+    E_SEED(t0, t1, R0, R1, L0, L1, 0);
+
+    word2char(R0, d);
+    word2char(R1, d+4);
+    word2char(L0, d+8);
+    word2char(L1, d+12);
+}
+
+void SEED_ecb_encrypt(const unsigned char *in, 
+                      unsigned char *out, 
+                      const SEED_KEY_SCHEDULE *ks, int enc) 
+{
+    if (enc) {
+        SEED_encrypt(in, out, ks);
+    } else {
+        SEED_decrypt(in, out, ks);
+    }
+}
+
+
+void SEED_cbc_encrypt(const unsigned char *in, unsigned char *out,
+                      size_t len, const SEED_KEY_SCHEDULE *ks,
+                      unsigned char ivec[SEED_BLOCK_SIZE], int enc)
+{
+    size_t n;
+    unsigned char tmp[SEED_BLOCK_SIZE];
+    const unsigned char *iv = ivec;
+
+    if (enc) {
+        while (len >= SEED_BLOCK_SIZE) {
+            for (n = 0; n < SEED_BLOCK_SIZE; ++n)
+                out[n] = in[n] ^ iv[n];
+
+            SEED_encrypt(out, out, ks);
+            iv = out;
+            len -= SEED_BLOCK_SIZE;
+            in  += SEED_BLOCK_SIZE;
+            out += SEED_BLOCK_SIZE;
+        }
+
+        if (len) {
+            for (n = 0; n < len; ++n)
+                out[n] = in[n] ^ iv[n];
+
+            for (n = len; n < SEED_BLOCK_SIZE; ++n)
+                out[n] = iv[n];
+
+            SEED_encrypt(out, out, ks);
+            iv = out;
+        }
+        
+        memcpy(ivec, iv, SEED_BLOCK_SIZE);
+    } else if (in != out) {
+        while (len >= SEED_BLOCK_SIZE) {
+            SEED_decrypt(in, out, ks);
+
+            for (n = 0; n < SEED_BLOCK_SIZE; ++n)
+                out[n] ^= iv[n];
+
+            iv = in;
+            len -= SEED_BLOCK_SIZE;
+            in  += SEED_BLOCK_SIZE;
+            out += SEED_BLOCK_SIZE;
+        }
+        
+        if (len) {
+            SEED_decrypt(in, tmp, ks);
+
+            for (n = 0; n < len; ++n)
+                out[n] = tmp[n] ^ iv[n];
+
+            iv = in;
+        }
+        
+        memcpy(ivec, iv, SEED_BLOCK_SIZE);
+    } else {
+        while (len >= SEED_BLOCK_SIZE) {
+            memcpy(tmp, in, SEED_BLOCK_SIZE);
+            SEED_decrypt(in, out, ks);
+
+            for (n = 0; n < SEED_BLOCK_SIZE; ++n)
+                out[n] ^= ivec[n];
+
+            memcpy(ivec, tmp, SEED_BLOCK_SIZE);
+            len -= SEED_BLOCK_SIZE;
+            in  += SEED_BLOCK_SIZE;
+            out += SEED_BLOCK_SIZE;
+        }
+
+        if (len) {
+            memcpy(tmp, in, SEED_BLOCK_SIZE);
+            SEED_decrypt(tmp, tmp, ks);
+
+            for (n = 0; n < len; ++n)
+                out[n] = tmp[n] ^ ivec[n];
+
+            memcpy(ivec, tmp, SEED_BLOCK_SIZE);
+        }
+    }
+}
+
+SEEDContext *
+SEED_AllocateContext(void)
+{
+    return PORT_ZNew(SEEDContext);
+}
+
+SECStatus   
+SEED_InitContext(SEEDContext *cx, const unsigned char *key, 
+                 unsigned int keylen, const unsigned char *iv, 
+                 int mode, unsigned int encrypt,unsigned int unused)
+{
+    if (!cx) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    switch (mode) {
+    case NSS_SEED:    
+        SEED_set_key(key, &cx->ks);
+        cx->mode = NSS_SEED;
+        cx->encrypt = encrypt;
+        break;
+
+    case NSS_SEED_CBC:
+        memcpy(cx->iv, iv, 16);
+        SEED_set_key(key, &cx->ks);
+        cx->mode = NSS_SEED_CBC;
+        cx->encrypt = encrypt;
+        break;
+
+    default:
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+SEEDContext *
+SEED_CreateContext(const unsigned char * key, const unsigned char *iv,
+                   int mode, PRBool encrypt)
+{
+    SEEDContext *cx = PORT_ZNew(SEEDContext);
+    SECStatus rv   = SEED_InitContext(cx, key, SEED_KEY_LENGTH, iv, mode, 
+                                      encrypt, 0);
+
+    if (rv != SECSuccess) {
+        PORT_ZFree(cx, sizeof *cx);
+        cx = NULL;
+    }
+
+    return cx;
+}
+
+void
+SEED_DestroyContext(SEEDContext *cx, PRBool freeit)
+{
+    if (cx) {
+        memset(cx, 0, sizeof *cx);
+
+        if (freeit)
+            PORT_Free(cx);
+    }
+}
+
+SECStatus
+SEED_Encrypt(SEEDContext *cx, unsigned char *out, unsigned int *outLen,
+             unsigned int maxOutLen, const unsigned char *in, 
+             unsigned int inLen)
+{
+    if (!cx) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (!cx->encrypt) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    switch (cx->mode) {
+    case NSS_SEED:
+        SEED_ecb_encrypt(in, out, &cx->ks, 1);
+        *outLen = inLen;
+        break;
+
+    case NSS_SEED_CBC:
+        SEED_cbc_encrypt(in, out, inLen, &cx->ks, cx->iv, 1);
+        *outLen = inLen;
+        break;
+
+    default:
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+SECStatus
+SEED_Decrypt(SEEDContext *cx, unsigned char *out, unsigned int *outLen,
+             unsigned int maxOutLen, const unsigned char *in, 
+             unsigned int inLen)
+{
+    if (!cx) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (cx->encrypt) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    switch (cx->mode) {
+    case NSS_SEED:
+        SEED_ecb_encrypt(in, out, &cx->ks, 0);
+        *outLen = inLen;
+        break;
+        
+    case NSS_SEED_CBC:
+        SEED_cbc_encrypt(in, out, inLen, &cx->ks, cx->iv, 0);
+        *outLen = inLen;
+        break;
+    
+    default:
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    
+    return SECSuccess;
+}
diff --git a/mozilla/security/nss/lib/freebl/seed.h b/mozilla/security/nss/lib/freebl/seed.h
new file mode 100644
index 0000000..b5642e1
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/seed.h
@@ -0,0 +1,160 @@
+/* ***** 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 SEED code.
+ *
+ * The Initial Developer of the Original Code is
+ * KISA(Korea Information Security Agency).
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer.
+ * 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 ***** */
+
+#ifndef HEADER_SEED_H
+#define HEADER_SEED_H
+
+#include <string.h>
+#include "blapi.h"
+
+#if !defined(NO_SYS_TYPES_H)
+# include <sys/types.h>
+#endif
+
+typedef PRUint32 seed_word;
+
+#define G_FUNC(v) \
+    SS[0][((v)     & 0xff)] ^ \
+    SS[1][((v)>> 8 & 0xff)] ^ \
+    SS[2][((v)>>16 & 0xff)] ^ \
+    SS[3][((v)>>24 & 0xff)]
+
+#define char2word(c, i)  \
+    (i) = ((((seed_word)((c)[0])) << 24) | \
+           (((seed_word)((c)[1])) << 16) | \
+           (((seed_word)((c)[2])) <<  8) | \
+            ((seed_word)((c)[3])))
+
+#define word2char(l, c)  \
+    *((c)+0) = (unsigned char)((l)>>24); \
+    *((c)+1) = (unsigned char)((l)>>16); \
+    *((c)+2) = (unsigned char)((l)>> 8); \
+    *((c)+3) = (unsigned char)((l)    )
+
+#define KEYSCHEDULE_UPDATE0(T0, T1, K0, K1, K2, K3, KC)  \
+    (T0) = (K2);                                          \
+    (K2) = (((K2)<<8) ^ ((K3)>>24));                     \
+    (K3) = (((K3)<<8) ^ ((T0)>>24));                     \
+    (T0) = ((K0) + (K2) - (KC));                         \
+    (T1) = ((K1) + (KC) - (K3))
+
+#define KEYSCHEDULE_UPDATE1(T0, T1, K0, K1, K2, K3, KC) \
+    (T0) = (K0);                                         \
+    (K0) = (((K0)>>8) ^ ((K1)<<24));                    \
+    (K1) = (((K1)>>8) ^ ((T0)<<24));                    \
+    (T0) = ((K0) + (K2) - (KC));                         \
+    (T1) = ((K1) + (KC) - (K3))
+
+#define KEYUPDATE_TEMP(T0, T1, K)   \
+    (K)[0] = G_FUNC((T0));          \
+    (K)[1] = G_FUNC((T1))
+
+#define XOR_SEEDBLOCK(DST, SRC)  \
+    (DST)[0] ^= (SRC)[0];    \
+    (DST)[1] ^= (SRC)[1];    \
+    (DST)[2] ^= (SRC)[2];    \
+    (DST)[3] ^= (SRC)[3]
+
+#define MOV_SEEDBLOCK(DST, SRC)  \
+    (DST)[0] = (SRC)[0];     \
+    (DST)[1] = (SRC)[1];     \
+    (DST)[2] = (SRC)[2];     \
+    (DST)[3] = (SRC)[3]
+
+# define CHAR2WORD(C, I)          \
+    char2word((C),    (I)[0]);    \
+    char2word((C)+4,  (I)[1]);    \
+    char2word((C)+8,  (I)[2]);    \
+    char2word((C)+12, (I)[3])
+
+# define WORD2CHAR(I, C)          \
+    word2char((I)[0], (C));       \
+    word2char((I)[1], (C+4));     \
+    word2char((I)[2], (C+8));     \
+    word2char((I)[3], (C+12))
+
+# define E_SEED(T0, T1, X1, X2, X3, X4, rbase)  \
+    (T0)  = (X3) ^ (ks->data)[(rbase)];         \
+    (T1)  = (X4) ^ (ks->data)[(rbase)+1];       \
+    (T1) ^= (T0);       \
+    (T1)  = G_FUNC(T1); \
+    (T0) += (T1);       \
+    (T0)  = G_FUNC(T0); \
+    (T1) += (T0);       \
+    (T1)  = G_FUNC(T1); \
+    (T0) += (T1);       \
+    (X1) ^= (T0);       \
+    (X2) ^= (T1)
+
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct seed_key_st {
+    PRUint32 data[32];
+} SEED_KEY_SCHEDULE;
+
+
+
+struct SEEDContextStr {
+    unsigned char iv[SEED_BLOCK_SIZE];
+    SEED_KEY_SCHEDULE ks;
+    int mode;
+    unsigned int encrypt;
+};
+
+void SEED_set_key(const unsigned char rawkey[SEED_KEY_LENGTH], 
+                  SEED_KEY_SCHEDULE *ks);
+
+void SEED_encrypt(const unsigned char s[SEED_BLOCK_SIZE], 
+                  unsigned char d[SEED_BLOCK_SIZE], 
+                  const SEED_KEY_SCHEDULE *ks);
+void SEED_decrypt(const unsigned char s[SEED_BLOCK_SIZE], 
+                  unsigned char d[SEED_BLOCK_SIZE], 
+                  const SEED_KEY_SCHEDULE *ks);
+
+void SEED_ecb_encrypt(const unsigned char *in, unsigned char *out, 
+                      const SEED_KEY_SCHEDULE *ks, int enc);
+void SEED_cbc_encrypt(const unsigned char *in, unsigned char *out, 
+                      size_t len, const SEED_KEY_SCHEDULE *ks, 
+                      unsigned char ivec[SEED_BLOCK_SIZE], int enc);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* HEADER_SEED_H */
diff --git a/mozilla/security/nss/lib/freebl/sha256.h b/mozilla/security/nss/lib/freebl/sha256.h
new file mode 100644
index 0000000..f598132
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/sha256.h
@@ -0,0 +1,51 @@
+/* ***** 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) 2002
+ * 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 ***** */
+
+#ifndef _SHA_256_H_
+#define _SHA_256_H_
+
+#include "prtypes.h"
+
+struct SHA256ContextStr {
+    union {
+	PRUint32 w[64];	    /* message schedule, input buffer, plus 48 words */
+	PRUint8  b[256];
+    } u;
+    PRUint32 h[8];		/* 8 state variables */
+    PRUint32 sizeHi,sizeLo;	/* 64-bit count of hashed bytes. */
+};
+
+#endif /* _SHA_256_H_ */
diff --git a/mozilla/security/nss/lib/freebl/sha512.c b/mozilla/security/nss/lib/freebl/sha512.c
new file mode 100644
index 0000000..4449985
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/sha512.c
@@ -0,0 +1,1411 @@
+/*
+ * sha512.c - implementation of SHA256, SHA384 and SHA512
+ *
+ * ***** 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) 2002
+ * 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 ***** */
+/* $Id: sha512.c,v 1.14 2009/04/09 22:11:07 julien.pierre.boogz%sun.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "prcpucfg.h"
+#if defined(NSS_X86) || defined(SHA_NO_LONG_LONG)
+#define NOUNROLL512 1
+#undef HAVE_LONG_LONG
+#endif
+#include "prtypes.h"	/* for PRUintXX */
+#include "secport.h"	/* for PORT_XXX */
+#include "blapi.h"
+#include "sha256.h"	/* for struct SHA256ContextStr */
+
+/* ============= Common constants and defines ======================= */
+
+#define W ctx->u.w
+#define B ctx->u.b
+#define H ctx->h
+
+#define SHR(x,n) (x >> n)
+#define SHL(x,n) (x << n)
+#define Ch(x,y,z)  ((x & y) ^ (~x & z))
+#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
+
+/* Padding used with all flavors of SHA */
+static const PRUint8 pad[240] = { 
+0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+   /* compiler will fill the rest in with zeros */
+};
+
+/* ============= SHA256 implemenmtation ================================== */
+
+/* SHA-256 constants, K256. */
+static const PRUint32 K256[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 
+    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 
+    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 
+    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 
+    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 
+    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/* SHA-256 initial hash values */
+static const PRUint32 H256[8] = {
+    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 
+    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+};
+
+#if (_MSC_VER >= 1300)
+#include <stdlib.h>
+#pragma intrinsic(_byteswap_ulong)
+#define SHA_HTONL(x) _byteswap_ulong(x)
+#define BYTESWAP4(x)  x = SHA_HTONL(x)
+#elif defined(_MSC_VER) && defined(NSS_X86_OR_X64)
+#ifndef FORCEINLINE
+#if (_MSC_VER >= 1200)
+#define FORCEINLINE __forceinline
+#else
+#define FORCEINLINE __inline
+#endif
+#endif
+#define FASTCALL __fastcall
+
+static FORCEINLINE PRUint32 FASTCALL 
+swap4b(PRUint32 dwd) 
+{
+    __asm {
+    	mov   eax,dwd
+	bswap eax
+    }
+}
+
+#define SHA_HTONL(x) swap4b(x)
+#define BYTESWAP4(x)  x = SHA_HTONL(x)
+
+#elif defined(__GNUC__) && defined(NSS_X86_OR_X64)
+static __inline__ PRUint32 swap4b(PRUint32 value)
+{
+    __asm__("bswap %0" : "+r" (value));
+    return (value);
+}
+#define SHA_HTONL(x) swap4b(x)
+#define BYTESWAP4(x)  x = SHA_HTONL(x)
+
+#else /* neither windows nor Linux PC */
+#define SWAP4MASK  0x00FF00FF
+#define SHA_HTONL(x) (t1 = (x), t1 = (t1 << 16) | (t1 >> 16), \
+                      ((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK))
+#define BYTESWAP4(x)  x = SHA_HTONL(x)
+#endif
+
+#if defined(_MSC_VER)
+#pragma intrinsic (_lrotr, _lrotl) 
+#define ROTR32(x,n) _lrotr(x,n)
+#define ROTL32(x,n) _lrotl(x,n)
+#else
+#define ROTR32(x,n) ((x >> n) | (x << ((8 * sizeof x) - n)))
+#define ROTL32(x,n) ((x << n) | (x >> ((8 * sizeof x) - n)))
+#endif
+
+/* Capitol Sigma and lower case sigma functions */
+#define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22))
+#define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25))
+#define s0(x) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3))
+#define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10))
+
+SHA256Context *
+SHA256_NewContext(void)
+{
+    SHA256Context *ctx = PORT_New(SHA256Context);
+    return ctx;
+}
+
+void 
+SHA256_DestroyContext(SHA256Context *ctx, PRBool freeit)
+{
+    if (freeit) {
+        PORT_ZFree(ctx, sizeof *ctx);
+    }
+}
+
+void 
+SHA256_Begin(SHA256Context *ctx)
+{
+    memset(ctx, 0, sizeof *ctx);
+    memcpy(H, H256, sizeof H256);
+}
+
+static void
+SHA256_Compress(SHA256Context *ctx)
+{
+  {
+    register PRUint32 t1, t2;
+
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP4(W[0]);
+    BYTESWAP4(W[1]);
+    BYTESWAP4(W[2]);
+    BYTESWAP4(W[3]);
+    BYTESWAP4(W[4]);
+    BYTESWAP4(W[5]);
+    BYTESWAP4(W[6]);
+    BYTESWAP4(W[7]);
+    BYTESWAP4(W[8]);
+    BYTESWAP4(W[9]);
+    BYTESWAP4(W[10]);
+    BYTESWAP4(W[11]);
+    BYTESWAP4(W[12]);
+    BYTESWAP4(W[13]);
+    BYTESWAP4(W[14]);
+    BYTESWAP4(W[15]);
+#endif
+
+#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
+
+    /* prepare the "message schedule"   */
+#ifdef NOUNROLL256
+    {
+	int t;
+	for (t = 16; t < 64; ++t) {
+	    INITW(t);
+	}
+    }
+#else
+    INITW(16);
+    INITW(17);
+    INITW(18);
+    INITW(19);
+
+    INITW(20);
+    INITW(21);
+    INITW(22);
+    INITW(23);
+    INITW(24);
+    INITW(25);
+    INITW(26);
+    INITW(27);
+    INITW(28);
+    INITW(29);
+
+    INITW(30);
+    INITW(31);
+    INITW(32);
+    INITW(33);
+    INITW(34);
+    INITW(35);
+    INITW(36);
+    INITW(37);
+    INITW(38);
+    INITW(39);
+
+    INITW(40);
+    INITW(41);
+    INITW(42);
+    INITW(43);
+    INITW(44);
+    INITW(45);
+    INITW(46);
+    INITW(47);
+    INITW(48);
+    INITW(49);
+
+    INITW(50);
+    INITW(51);
+    INITW(52);
+    INITW(53);
+    INITW(54);
+    INITW(55);
+    INITW(56);
+    INITW(57);
+    INITW(58);
+    INITW(59);
+
+    INITW(60);
+    INITW(61);
+    INITW(62);
+    INITW(63);
+
+#endif
+#undef INITW
+  }
+  {
+    PRUint32 a, b, c, d, e, f, g, h;
+
+    a = H[0];
+    b = H[1];
+    c = H[2];
+    d = H[3];
+    e = H[4];
+    f = H[5];
+    g = H[6];
+    h = H[7];
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+    h += S1(e) + Ch(e,f,g) + K256[n] + W[n]; \
+    d += h; \
+    h += S0(a) + Maj(a,b,c); 
+
+#ifdef NOUNROLL256
+    {
+	int t;
+	for (t = 0; t < 64; t+= 8) {
+	    ROUND(t+0,a,b,c,d,e,f,g,h)
+	    ROUND(t+1,h,a,b,c,d,e,f,g)
+	    ROUND(t+2,g,h,a,b,c,d,e,f)
+	    ROUND(t+3,f,g,h,a,b,c,d,e)
+	    ROUND(t+4,e,f,g,h,a,b,c,d)
+	    ROUND(t+5,d,e,f,g,h,a,b,c)
+	    ROUND(t+6,c,d,e,f,g,h,a,b)
+	    ROUND(t+7,b,c,d,e,f,g,h,a)
+	}
+    }
+#else
+    ROUND( 0,a,b,c,d,e,f,g,h)
+    ROUND( 1,h,a,b,c,d,e,f,g)
+    ROUND( 2,g,h,a,b,c,d,e,f)
+    ROUND( 3,f,g,h,a,b,c,d,e)
+    ROUND( 4,e,f,g,h,a,b,c,d)
+    ROUND( 5,d,e,f,g,h,a,b,c)
+    ROUND( 6,c,d,e,f,g,h,a,b)
+    ROUND( 7,b,c,d,e,f,g,h,a)
+
+    ROUND( 8,a,b,c,d,e,f,g,h)
+    ROUND( 9,h,a,b,c,d,e,f,g)
+    ROUND(10,g,h,a,b,c,d,e,f)
+    ROUND(11,f,g,h,a,b,c,d,e)
+    ROUND(12,e,f,g,h,a,b,c,d)
+    ROUND(13,d,e,f,g,h,a,b,c)
+    ROUND(14,c,d,e,f,g,h,a,b)
+    ROUND(15,b,c,d,e,f,g,h,a)
+
+    ROUND(16,a,b,c,d,e,f,g,h)
+    ROUND(17,h,a,b,c,d,e,f,g)
+    ROUND(18,g,h,a,b,c,d,e,f)
+    ROUND(19,f,g,h,a,b,c,d,e)
+    ROUND(20,e,f,g,h,a,b,c,d)
+    ROUND(21,d,e,f,g,h,a,b,c)
+    ROUND(22,c,d,e,f,g,h,a,b)
+    ROUND(23,b,c,d,e,f,g,h,a)
+
+    ROUND(24,a,b,c,d,e,f,g,h)
+    ROUND(25,h,a,b,c,d,e,f,g)
+    ROUND(26,g,h,a,b,c,d,e,f)
+    ROUND(27,f,g,h,a,b,c,d,e)
+    ROUND(28,e,f,g,h,a,b,c,d)
+    ROUND(29,d,e,f,g,h,a,b,c)
+    ROUND(30,c,d,e,f,g,h,a,b)
+    ROUND(31,b,c,d,e,f,g,h,a)
+
+    ROUND(32,a,b,c,d,e,f,g,h)
+    ROUND(33,h,a,b,c,d,e,f,g)
+    ROUND(34,g,h,a,b,c,d,e,f)
+    ROUND(35,f,g,h,a,b,c,d,e)
+    ROUND(36,e,f,g,h,a,b,c,d)
+    ROUND(37,d,e,f,g,h,a,b,c)
+    ROUND(38,c,d,e,f,g,h,a,b)
+    ROUND(39,b,c,d,e,f,g,h,a)
+
+    ROUND(40,a,b,c,d,e,f,g,h)
+    ROUND(41,h,a,b,c,d,e,f,g)
+    ROUND(42,g,h,a,b,c,d,e,f)
+    ROUND(43,f,g,h,a,b,c,d,e)
+    ROUND(44,e,f,g,h,a,b,c,d)
+    ROUND(45,d,e,f,g,h,a,b,c)
+    ROUND(46,c,d,e,f,g,h,a,b)
+    ROUND(47,b,c,d,e,f,g,h,a)
+
+    ROUND(48,a,b,c,d,e,f,g,h)
+    ROUND(49,h,a,b,c,d,e,f,g)
+    ROUND(50,g,h,a,b,c,d,e,f)
+    ROUND(51,f,g,h,a,b,c,d,e)
+    ROUND(52,e,f,g,h,a,b,c,d)
+    ROUND(53,d,e,f,g,h,a,b,c)
+    ROUND(54,c,d,e,f,g,h,a,b)
+    ROUND(55,b,c,d,e,f,g,h,a)
+
+    ROUND(56,a,b,c,d,e,f,g,h)
+    ROUND(57,h,a,b,c,d,e,f,g)
+    ROUND(58,g,h,a,b,c,d,e,f)
+    ROUND(59,f,g,h,a,b,c,d,e)
+    ROUND(60,e,f,g,h,a,b,c,d)
+    ROUND(61,d,e,f,g,h,a,b,c)
+    ROUND(62,c,d,e,f,g,h,a,b)
+    ROUND(63,b,c,d,e,f,g,h,a)
+#endif
+
+    H[0] += a;
+    H[1] += b;
+    H[2] += c;
+    H[3] += d;
+    H[4] += e;
+    H[5] += f;
+    H[6] += g;
+    H[7] += h;
+  }
+#undef ROUND
+}
+
+#undef s0
+#undef s1
+#undef S0
+#undef S1
+
+void 
+SHA256_Update(SHA256Context *ctx, const unsigned char *input,
+		    unsigned int inputLen)
+{
+    unsigned int inBuf = ctx->sizeLo & 0x3f;
+    if (!inputLen)
+    	return;
+
+    /* Add inputLen into the count of bytes processed, before processing */
+    if ((ctx->sizeLo += inputLen) < inputLen)
+    	ctx->sizeHi++;
+
+    /* if data already in buffer, attemp to fill rest of buffer */
+    if (inBuf) {
+    	unsigned int todo = SHA256_BLOCK_LENGTH - inBuf;
+	if (inputLen < todo)
+	    todo = inputLen;
+	memcpy(B + inBuf, input, todo);
+	input    += todo;
+	inputLen -= todo;
+	if (inBuf + todo == SHA256_BLOCK_LENGTH)
+	    SHA256_Compress(ctx);
+    }
+
+    /* if enough data to fill one or more whole buffers, process them. */
+    while (inputLen >= SHA256_BLOCK_LENGTH) {
+    	memcpy(B, input, SHA256_BLOCK_LENGTH);
+	input    += SHA256_BLOCK_LENGTH;
+	inputLen -= SHA256_BLOCK_LENGTH;
+	SHA256_Compress(ctx);
+    }
+    /* if data left over, fill it into buffer */
+    if (inputLen) 
+    	memcpy(B, input, inputLen);
+}
+
+void 
+SHA256_End(SHA256Context *ctx, unsigned char *digest,
+           unsigned int *digestLen, unsigned int maxDigestLen)
+{
+    unsigned int inBuf = ctx->sizeLo & 0x3f;
+    unsigned int padLen = (inBuf < 56) ? (56 - inBuf) : (56 + 64 - inBuf);
+    PRUint32 hi, lo;
+#ifdef SWAP4MASK
+    PRUint32 t1;
+#endif
+
+    hi = (ctx->sizeHi << 3) | (ctx->sizeLo >> 29);
+    lo = (ctx->sizeLo << 3);
+
+    SHA256_Update(ctx, pad, padLen);
+
+#if defined(IS_LITTLE_ENDIAN)
+    W[14] = SHA_HTONL(hi);
+    W[15] = SHA_HTONL(lo);
+#else
+    W[14] = hi;
+    W[15] = lo;
+#endif
+    SHA256_Compress(ctx);
+
+    /* now output the answer */
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP4(H[0]);
+    BYTESWAP4(H[1]);
+    BYTESWAP4(H[2]);
+    BYTESWAP4(H[3]);
+    BYTESWAP4(H[4]);
+    BYTESWAP4(H[5]);
+    BYTESWAP4(H[6]);
+    BYTESWAP4(H[7]);
+#endif
+    padLen = PR_MIN(SHA256_LENGTH, maxDigestLen);
+    memcpy(digest, H, padLen);
+    if (digestLen)
+	*digestLen = padLen;
+}
+
+SECStatus 
+SHA256_HashBuf(unsigned char *dest, const unsigned char *src, 
+               uint32 src_length)
+{
+    SHA256Context ctx;
+    unsigned int outLen;
+
+    SHA256_Begin(&ctx);
+    SHA256_Update(&ctx, src, src_length);
+    SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH);
+
+    return SECSuccess;
+}
+
+
+SECStatus 
+SHA256_Hash(unsigned char *dest, const char *src)
+{
+    return SHA256_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+
+void SHA256_TraceState(SHA256Context *ctx) { }
+
+unsigned int 
+SHA256_FlattenSize(SHA256Context *ctx)
+{
+    return sizeof *ctx;
+}
+
+SECStatus 
+SHA256_Flatten(SHA256Context *ctx,unsigned char *space)
+{
+    PORT_Memcpy(space, ctx, sizeof *ctx);
+    return SECSuccess;
+}
+
+SHA256Context * 
+SHA256_Resurrect(unsigned char *space, void *arg)
+{
+    SHA256Context *ctx = SHA256_NewContext();
+    if (ctx) 
+	PORT_Memcpy(ctx, space, sizeof *ctx);
+    return ctx;
+}
+
+void SHA256_Clone(SHA256Context *dest, SHA256Context *src) 
+{
+    memcpy(dest, src, sizeof *dest);
+}
+
+
+/* ======= SHA512 and SHA384 common constants and defines ================= */
+
+/* common #defines for SHA512 and SHA384 */
+#if defined(HAVE_LONG_LONG)
+#if defined(_MSC_VER)
+#pragma intrinsic(_rotr64,_rotl64)
+#define ROTR64(x,n) _rotr64(x,n)
+#define ROTL64(x,n) _rotl64(x,n)
+#else
+#define ROTR64(x,n) ((x >> n) | (x << (64 - n)))
+#define ROTL64(x,n) ((x << n) | (x >> (64 - n)))
+#endif
+
+#define S0(x) (ROTR64(x,28) ^ ROTR64(x,34) ^ ROTR64(x,39))
+#define S1(x) (ROTR64(x,14) ^ ROTR64(x,18) ^ ROTR64(x,41))
+#define s0(x) (t1 = x, ROTR64(t1, 1) ^ ROTR64(t1, 8) ^ SHR(t1,7))
+#define s1(x) (t2 = x, ROTR64(t2,19) ^ ROTR64(t2,61) ^ SHR(t2,6))
+
+#if PR_BYTES_PER_LONG == 8
+#define ULLC(hi,lo) 0x ## hi ## lo ## UL
+#elif defined(_MSC_VER)
+#define ULLC(hi,lo) 0x ## hi ## lo ## ui64
+#else
+#define ULLC(hi,lo) 0x ## hi ## lo ## ULL
+#endif
+
+#if defined(_MSC_VER)
+#pragma intrinsic(_byteswap_uint64)
+#define SHA_HTONLL(x) _byteswap_uint64(x)
+
+#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__x86_64))
+static __inline__ PRUint64 swap8b(PRUint64 value)
+{
+    __asm__("bswapq %0" : "+r" (value));
+    return (value);
+}
+#define SHA_HTONLL(x) swap8b(x)
+
+#else
+#define SHA_MASK16 ULLC(0000FFFF,0000FFFF)
+#define SHA_MASK8  ULLC(00FF00FF,00FF00FF)
+#define SHA_HTONLL(x) (t1 = x, \
+  t1 = ((t1 & SHA_MASK8 ) <<  8) | ((t1 >>  8) & SHA_MASK8 ), \
+  t1 = ((t1 & SHA_MASK16) << 16) | ((t1 >> 16) & SHA_MASK16), \
+  (t1 >> 32) | (t1 << 32))
+#endif
+#define BYTESWAP8(x)  x = SHA_HTONLL(x)
+
+#else /* no long long */
+
+#if defined(IS_LITTLE_ENDIAN)
+#define ULLC(hi,lo) { 0x ## lo ## U, 0x ## hi ## U }
+#else
+#define ULLC(hi,lo) { 0x ## hi ## U, 0x ## lo ## U }
+#endif
+
+#define SHA_HTONLL(x) ( BYTESWAP4(x.lo), BYTESWAP4(x.hi), \
+   x.hi ^= x.lo ^= x.hi ^= x.lo, x)
+#define BYTESWAP8(x)  do { PRUint32 tmp; BYTESWAP4(x.lo); BYTESWAP4(x.hi); \
+   tmp = x.lo; x.lo = x.hi; x.hi = tmp; } while (0)
+#endif
+
+/* SHA-384 and SHA-512 constants, K512. */
+static const PRUint64 K512[80] = {
+#if PR_BYTES_PER_LONG == 8
+     0x428a2f98d728ae22UL ,  0x7137449123ef65cdUL , 
+     0xb5c0fbcfec4d3b2fUL ,  0xe9b5dba58189dbbcUL ,
+     0x3956c25bf348b538UL ,  0x59f111f1b605d019UL , 
+     0x923f82a4af194f9bUL ,  0xab1c5ed5da6d8118UL ,
+     0xd807aa98a3030242UL ,  0x12835b0145706fbeUL , 
+     0x243185be4ee4b28cUL ,  0x550c7dc3d5ffb4e2UL ,
+     0x72be5d74f27b896fUL ,  0x80deb1fe3b1696b1UL , 
+     0x9bdc06a725c71235UL ,  0xc19bf174cf692694UL ,
+     0xe49b69c19ef14ad2UL ,  0xefbe4786384f25e3UL , 
+     0x0fc19dc68b8cd5b5UL ,  0x240ca1cc77ac9c65UL ,
+     0x2de92c6f592b0275UL ,  0x4a7484aa6ea6e483UL , 
+     0x5cb0a9dcbd41fbd4UL ,  0x76f988da831153b5UL ,
+     0x983e5152ee66dfabUL ,  0xa831c66d2db43210UL , 
+     0xb00327c898fb213fUL ,  0xbf597fc7beef0ee4UL ,
+     0xc6e00bf33da88fc2UL ,  0xd5a79147930aa725UL , 
+     0x06ca6351e003826fUL ,  0x142929670a0e6e70UL ,
+     0x27b70a8546d22ffcUL ,  0x2e1b21385c26c926UL , 
+     0x4d2c6dfc5ac42aedUL ,  0x53380d139d95b3dfUL ,
+     0x650a73548baf63deUL ,  0x766a0abb3c77b2a8UL , 
+     0x81c2c92e47edaee6UL ,  0x92722c851482353bUL ,
+     0xa2bfe8a14cf10364UL ,  0xa81a664bbc423001UL , 
+     0xc24b8b70d0f89791UL ,  0xc76c51a30654be30UL ,
+     0xd192e819d6ef5218UL ,  0xd69906245565a910UL , 
+     0xf40e35855771202aUL ,  0x106aa07032bbd1b8UL ,
+     0x19a4c116b8d2d0c8UL ,  0x1e376c085141ab53UL , 
+     0x2748774cdf8eeb99UL ,  0x34b0bcb5e19b48a8UL ,
+     0x391c0cb3c5c95a63UL ,  0x4ed8aa4ae3418acbUL , 
+     0x5b9cca4f7763e373UL ,  0x682e6ff3d6b2b8a3UL ,
+     0x748f82ee5defb2fcUL ,  0x78a5636f43172f60UL , 
+     0x84c87814a1f0ab72UL ,  0x8cc702081a6439ecUL ,
+     0x90befffa23631e28UL ,  0xa4506cebde82bde9UL , 
+     0xbef9a3f7b2c67915UL ,  0xc67178f2e372532bUL ,
+     0xca273eceea26619cUL ,  0xd186b8c721c0c207UL , 
+     0xeada7dd6cde0eb1eUL ,  0xf57d4f7fee6ed178UL ,
+     0x06f067aa72176fbaUL ,  0x0a637dc5a2c898a6UL , 
+     0x113f9804bef90daeUL ,  0x1b710b35131c471bUL ,
+     0x28db77f523047d84UL ,  0x32caab7b40c72493UL , 
+     0x3c9ebe0a15c9bebcUL ,  0x431d67c49c100d4cUL ,
+     0x4cc5d4becb3e42b6UL ,  0x597f299cfc657e2aUL , 
+     0x5fcb6fab3ad6faecUL ,  0x6c44198c4a475817UL 
+#else
+    ULLC(428a2f98,d728ae22), ULLC(71374491,23ef65cd), 
+    ULLC(b5c0fbcf,ec4d3b2f), ULLC(e9b5dba5,8189dbbc),
+    ULLC(3956c25b,f348b538), ULLC(59f111f1,b605d019), 
+    ULLC(923f82a4,af194f9b), ULLC(ab1c5ed5,da6d8118),
+    ULLC(d807aa98,a3030242), ULLC(12835b01,45706fbe), 
+    ULLC(243185be,4ee4b28c), ULLC(550c7dc3,d5ffb4e2),
+    ULLC(72be5d74,f27b896f), ULLC(80deb1fe,3b1696b1), 
+    ULLC(9bdc06a7,25c71235), ULLC(c19bf174,cf692694),
+    ULLC(e49b69c1,9ef14ad2), ULLC(efbe4786,384f25e3), 
+    ULLC(0fc19dc6,8b8cd5b5), ULLC(240ca1cc,77ac9c65),
+    ULLC(2de92c6f,592b0275), ULLC(4a7484aa,6ea6e483), 
+    ULLC(5cb0a9dc,bd41fbd4), ULLC(76f988da,831153b5),
+    ULLC(983e5152,ee66dfab), ULLC(a831c66d,2db43210), 
+    ULLC(b00327c8,98fb213f), ULLC(bf597fc7,beef0ee4),
+    ULLC(c6e00bf3,3da88fc2), ULLC(d5a79147,930aa725), 
+    ULLC(06ca6351,e003826f), ULLC(14292967,0a0e6e70),
+    ULLC(27b70a85,46d22ffc), ULLC(2e1b2138,5c26c926), 
+    ULLC(4d2c6dfc,5ac42aed), ULLC(53380d13,9d95b3df),
+    ULLC(650a7354,8baf63de), ULLC(766a0abb,3c77b2a8), 
+    ULLC(81c2c92e,47edaee6), ULLC(92722c85,1482353b),
+    ULLC(a2bfe8a1,4cf10364), ULLC(a81a664b,bc423001), 
+    ULLC(c24b8b70,d0f89791), ULLC(c76c51a3,0654be30),
+    ULLC(d192e819,d6ef5218), ULLC(d6990624,5565a910), 
+    ULLC(f40e3585,5771202a), ULLC(106aa070,32bbd1b8),
+    ULLC(19a4c116,b8d2d0c8), ULLC(1e376c08,5141ab53), 
+    ULLC(2748774c,df8eeb99), ULLC(34b0bcb5,e19b48a8),
+    ULLC(391c0cb3,c5c95a63), ULLC(4ed8aa4a,e3418acb), 
+    ULLC(5b9cca4f,7763e373), ULLC(682e6ff3,d6b2b8a3),
+    ULLC(748f82ee,5defb2fc), ULLC(78a5636f,43172f60), 
+    ULLC(84c87814,a1f0ab72), ULLC(8cc70208,1a6439ec),
+    ULLC(90befffa,23631e28), ULLC(a4506ceb,de82bde9), 
+    ULLC(bef9a3f7,b2c67915), ULLC(c67178f2,e372532b),
+    ULLC(ca273ece,ea26619c), ULLC(d186b8c7,21c0c207), 
+    ULLC(eada7dd6,cde0eb1e), ULLC(f57d4f7f,ee6ed178),
+    ULLC(06f067aa,72176fba), ULLC(0a637dc5,a2c898a6), 
+    ULLC(113f9804,bef90dae), ULLC(1b710b35,131c471b),
+    ULLC(28db77f5,23047d84), ULLC(32caab7b,40c72493), 
+    ULLC(3c9ebe0a,15c9bebc), ULLC(431d67c4,9c100d4c),
+    ULLC(4cc5d4be,cb3e42b6), ULLC(597f299c,fc657e2a), 
+    ULLC(5fcb6fab,3ad6faec), ULLC(6c44198c,4a475817)
+#endif
+};
+
+struct SHA512ContextStr {
+    union {
+	PRUint64 w[80];	    /* message schedule, input buffer, plus 64 words */
+	PRUint32 l[160];
+	PRUint8  b[640];
+    } u;
+    PRUint64 h[8];	    /* 8 state variables */
+    PRUint64 sizeLo;	    /* 64-bit count of hashed bytes. */
+};
+
+/* =========== SHA512 implementation ===================================== */
+
+/* SHA-512 initial hash values */
+static const PRUint64 H512[8] = {
+#if PR_BYTES_PER_LONG == 8
+     0x6a09e667f3bcc908UL ,  0xbb67ae8584caa73bUL , 
+     0x3c6ef372fe94f82bUL ,  0xa54ff53a5f1d36f1UL , 
+     0x510e527fade682d1UL ,  0x9b05688c2b3e6c1fUL , 
+     0x1f83d9abfb41bd6bUL ,  0x5be0cd19137e2179UL 
+#else
+    ULLC(6a09e667,f3bcc908), ULLC(bb67ae85,84caa73b), 
+    ULLC(3c6ef372,fe94f82b), ULLC(a54ff53a,5f1d36f1), 
+    ULLC(510e527f,ade682d1), ULLC(9b05688c,2b3e6c1f), 
+    ULLC(1f83d9ab,fb41bd6b), ULLC(5be0cd19,137e2179)
+#endif
+};
+
+
+SHA512Context *
+SHA512_NewContext(void)
+{
+    SHA512Context *ctx = PORT_New(SHA512Context);
+    return ctx;
+}
+
+void 
+SHA512_DestroyContext(SHA512Context *ctx, PRBool freeit)
+{
+    if (freeit) {
+        PORT_ZFree(ctx, sizeof *ctx);
+    }
+}
+
+void 
+SHA512_Begin(SHA512Context *ctx)
+{
+    memset(ctx, 0, sizeof *ctx);
+    memcpy(H, H512, sizeof H512);
+}
+
+#if defined(SHA512_TRACE)
+#if defined(HAVE_LONG_LONG)
+#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %016lx, %s = %016lx\n", \
+			       n, #e, d, #a, h);
+#else
+#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %08x%08x, %s = %08x%08x\n", \
+			       n, #e, d.hi, d.lo, #a, h.hi, h.lo);
+#endif
+#else
+#define DUMP(n,a,d,e,h)
+#endif
+
+#if defined(HAVE_LONG_LONG)
+
+#define ADDTO(x,y) y += x
+
+#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+    h += S1(e) + Ch(e,f,g) + K512[n] + W[n]; \
+    d += h; \
+    h += S0(a) + Maj(a,b,c); \
+    DUMP(n,a,d,e,h)
+
+#else /* use only 32-bit variables, and don't unroll loops */
+
+#undef  NOUNROLL512
+#define NOUNROLL512 1
+
+#define ADDTO(x,y) y.lo += x.lo; y.hi += x.hi + (x.lo > y.lo)
+
+#define ROTR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
+#define ROTR64A(x,n,lo,hi) (x.lo << (64-n) | x.hi >> (n-32))
+#define  SHR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
+
+/* Capitol Sigma and lower case sigma functions */
+#define s0lo(x) (ROTR64a(x,1,lo,hi) ^ ROTR64a(x,8,lo,hi) ^ SHR64a(x,7,lo,hi))
+#define s0hi(x) (ROTR64a(x,1,hi,lo) ^ ROTR64a(x,8,hi,lo) ^ (x.hi >> 7))
+
+#define s1lo(x) (ROTR64a(x,19,lo,hi) ^ ROTR64A(x,61,lo,hi) ^ SHR64a(x,6,lo,hi))
+#define s1hi(x) (ROTR64a(x,19,hi,lo) ^ ROTR64A(x,61,hi,lo) ^ (x.hi >> 6))
+
+#define S0lo(x)(ROTR64a(x,28,lo,hi) ^ ROTR64A(x,34,lo,hi) ^ ROTR64A(x,39,lo,hi))
+#define S0hi(x)(ROTR64a(x,28,hi,lo) ^ ROTR64A(x,34,hi,lo) ^ ROTR64A(x,39,hi,lo))
+
+#define S1lo(x)(ROTR64a(x,14,lo,hi) ^ ROTR64a(x,18,lo,hi) ^ ROTR64A(x,41,lo,hi))
+#define S1hi(x)(ROTR64a(x,14,hi,lo) ^ ROTR64a(x,18,hi,lo) ^ ROTR64A(x,41,hi,lo))
+
+/* 32-bit versions of Ch and Maj */
+#define Chxx(x,y,z,lo) ((x.lo & y.lo) ^ (~x.lo & z.lo))
+#define Majx(x,y,z,lo) ((x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo))
+
+#define INITW(t) \
+    do { \
+	PRUint32 lo, tm; \
+	PRUint32 cy = 0; \
+	lo = s1lo(W[t-2]); \
+	lo += (tm = W[t-7].lo);     if (lo < tm) cy++; \
+	lo += (tm = s0lo(W[t-15])); if (lo < tm) cy++; \
+	lo += (tm = W[t-16].lo);    if (lo < tm) cy++; \
+	W[t].lo = lo; \
+	W[t].hi = cy + s1hi(W[t-2]) + W[t-7].hi + s0hi(W[t-15]) + W[t-16].hi; \
+    } while (0)
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+    { \
+	PRUint32 lo, tm, cy; \
+	lo  = S1lo(e); \
+	lo += (tm = Chxx(e,f,g,lo));    cy = (lo < tm); \
+	lo += (tm = K512[n].lo);	if (lo < tm) cy++; \
+	lo += (tm =    W[n].lo);	if (lo < tm) cy++; \
+	h.lo += lo;			if (h.lo < lo) cy++; \
+	h.hi += cy + S1hi(e) + Chxx(e,f,g,hi) + K512[n].hi + W[n].hi; \
+	d.lo += h.lo; \
+	d.hi += h.hi + (d.lo < h.lo); \
+	lo  = S0lo(a);  \
+	lo += (tm = Majx(a,b,c,lo));	cy = (lo < tm); \
+	h.lo += lo;			if (h.lo < lo) cy++; \
+	h.hi += cy + S0hi(a) + Majx(a,b,c,hi); \
+	DUMP(n,a,d,e,h) \
+    }
+#endif
+
+static void
+SHA512_Compress(SHA512Context *ctx)
+{
+#if defined(IS_LITTLE_ENDIAN)
+  {
+#if defined(HAVE_LONG_LONG)
+    PRUint64 t1;
+#else
+    PRUint32 t1;
+#endif
+    BYTESWAP8(W[0]);
+    BYTESWAP8(W[1]);
+    BYTESWAP8(W[2]);
+    BYTESWAP8(W[3]);
+    BYTESWAP8(W[4]);
+    BYTESWAP8(W[5]);
+    BYTESWAP8(W[6]);
+    BYTESWAP8(W[7]);
+    BYTESWAP8(W[8]);
+    BYTESWAP8(W[9]);
+    BYTESWAP8(W[10]);
+    BYTESWAP8(W[11]);
+    BYTESWAP8(W[12]);
+    BYTESWAP8(W[13]);
+    BYTESWAP8(W[14]);
+    BYTESWAP8(W[15]);
+  }
+#endif
+
+  {
+    PRUint64 t1, t2;
+#ifdef NOUNROLL512
+    {
+	/* prepare the "message schedule"   */
+	int t;
+	for (t = 16; t < 80; ++t) {
+	    INITW(t);
+	}
+    }
+#else
+    INITW(16);
+    INITW(17);
+    INITW(18);
+    INITW(19);
+
+    INITW(20);
+    INITW(21);
+    INITW(22);
+    INITW(23);
+    INITW(24);
+    INITW(25);
+    INITW(26);
+    INITW(27);
+    INITW(28);
+    INITW(29);
+
+    INITW(30);
+    INITW(31);
+    INITW(32);
+    INITW(33);
+    INITW(34);
+    INITW(35);
+    INITW(36);
+    INITW(37);
+    INITW(38);
+    INITW(39);
+
+    INITW(40);
+    INITW(41);
+    INITW(42);
+    INITW(43);
+    INITW(44);
+    INITW(45);
+    INITW(46);
+    INITW(47);
+    INITW(48);
+    INITW(49);
+
+    INITW(50);
+    INITW(51);
+    INITW(52);
+    INITW(53);
+    INITW(54);
+    INITW(55);
+    INITW(56);
+    INITW(57);
+    INITW(58);
+    INITW(59);
+
+    INITW(60);
+    INITW(61);
+    INITW(62);
+    INITW(63);
+    INITW(64);
+    INITW(65);
+    INITW(66);
+    INITW(67);
+    INITW(68);
+    INITW(69);
+
+    INITW(70);
+    INITW(71);
+    INITW(72);
+    INITW(73);
+    INITW(74);
+    INITW(75);
+    INITW(76);
+    INITW(77);
+    INITW(78);
+    INITW(79);
+#endif
+  }
+#ifdef SHA512_TRACE
+  {
+    int i;
+    for (i = 0; i < 80; ++i) {
+#ifdef HAVE_LONG_LONG
+	printf("W[%2d] = %016lx\n", i, W[i]);
+#else
+	printf("W[%2d] = %08x%08x\n", i, W[i].hi, W[i].lo);
+#endif
+    }
+  }
+#endif
+  {
+    PRUint64 a, b, c, d, e, f, g, h;
+
+    a = H[0];
+    b = H[1];
+    c = H[2];
+    d = H[3];
+    e = H[4];
+    f = H[5];
+    g = H[6];
+    h = H[7];
+
+#ifdef NOUNROLL512
+    {
+	int t;
+	for (t = 0; t < 80; t+= 8) {
+	    ROUND(t+0,a,b,c,d,e,f,g,h)
+	    ROUND(t+1,h,a,b,c,d,e,f,g)
+	    ROUND(t+2,g,h,a,b,c,d,e,f)
+	    ROUND(t+3,f,g,h,a,b,c,d,e)
+	    ROUND(t+4,e,f,g,h,a,b,c,d)
+	    ROUND(t+5,d,e,f,g,h,a,b,c)
+	    ROUND(t+6,c,d,e,f,g,h,a,b)
+	    ROUND(t+7,b,c,d,e,f,g,h,a)
+	}
+    }
+#else
+    ROUND( 0,a,b,c,d,e,f,g,h)
+    ROUND( 1,h,a,b,c,d,e,f,g)
+    ROUND( 2,g,h,a,b,c,d,e,f)
+    ROUND( 3,f,g,h,a,b,c,d,e)
+    ROUND( 4,e,f,g,h,a,b,c,d)
+    ROUND( 5,d,e,f,g,h,a,b,c)
+    ROUND( 6,c,d,e,f,g,h,a,b)
+    ROUND( 7,b,c,d,e,f,g,h,a)
+
+    ROUND( 8,a,b,c,d,e,f,g,h)
+    ROUND( 9,h,a,b,c,d,e,f,g)
+    ROUND(10,g,h,a,b,c,d,e,f)
+    ROUND(11,f,g,h,a,b,c,d,e)
+    ROUND(12,e,f,g,h,a,b,c,d)
+    ROUND(13,d,e,f,g,h,a,b,c)
+    ROUND(14,c,d,e,f,g,h,a,b)
+    ROUND(15,b,c,d,e,f,g,h,a)
+
+    ROUND(16,a,b,c,d,e,f,g,h)
+    ROUND(17,h,a,b,c,d,e,f,g)
+    ROUND(18,g,h,a,b,c,d,e,f)
+    ROUND(19,f,g,h,a,b,c,d,e)
+    ROUND(20,e,f,g,h,a,b,c,d)
+    ROUND(21,d,e,f,g,h,a,b,c)
+    ROUND(22,c,d,e,f,g,h,a,b)
+    ROUND(23,b,c,d,e,f,g,h,a)
+
+    ROUND(24,a,b,c,d,e,f,g,h)
+    ROUND(25,h,a,b,c,d,e,f,g)
+    ROUND(26,g,h,a,b,c,d,e,f)
+    ROUND(27,f,g,h,a,b,c,d,e)
+    ROUND(28,e,f,g,h,a,b,c,d)
+    ROUND(29,d,e,f,g,h,a,b,c)
+    ROUND(30,c,d,e,f,g,h,a,b)
+    ROUND(31,b,c,d,e,f,g,h,a)
+
+    ROUND(32,a,b,c,d,e,f,g,h)
+    ROUND(33,h,a,b,c,d,e,f,g)
+    ROUND(34,g,h,a,b,c,d,e,f)
+    ROUND(35,f,g,h,a,b,c,d,e)
+    ROUND(36,e,f,g,h,a,b,c,d)
+    ROUND(37,d,e,f,g,h,a,b,c)
+    ROUND(38,c,d,e,f,g,h,a,b)
+    ROUND(39,b,c,d,e,f,g,h,a)
+
+    ROUND(40,a,b,c,d,e,f,g,h)
+    ROUND(41,h,a,b,c,d,e,f,g)
+    ROUND(42,g,h,a,b,c,d,e,f)
+    ROUND(43,f,g,h,a,b,c,d,e)
+    ROUND(44,e,f,g,h,a,b,c,d)
+    ROUND(45,d,e,f,g,h,a,b,c)
+    ROUND(46,c,d,e,f,g,h,a,b)
+    ROUND(47,b,c,d,e,f,g,h,a)
+
+    ROUND(48,a,b,c,d,e,f,g,h)
+    ROUND(49,h,a,b,c,d,e,f,g)
+    ROUND(50,g,h,a,b,c,d,e,f)
+    ROUND(51,f,g,h,a,b,c,d,e)
+    ROUND(52,e,f,g,h,a,b,c,d)
+    ROUND(53,d,e,f,g,h,a,b,c)
+    ROUND(54,c,d,e,f,g,h,a,b)
+    ROUND(55,b,c,d,e,f,g,h,a)
+
+    ROUND(56,a,b,c,d,e,f,g,h)
+    ROUND(57,h,a,b,c,d,e,f,g)
+    ROUND(58,g,h,a,b,c,d,e,f)
+    ROUND(59,f,g,h,a,b,c,d,e)
+    ROUND(60,e,f,g,h,a,b,c,d)
+    ROUND(61,d,e,f,g,h,a,b,c)
+    ROUND(62,c,d,e,f,g,h,a,b)
+    ROUND(63,b,c,d,e,f,g,h,a)
+
+    ROUND(64,a,b,c,d,e,f,g,h)
+    ROUND(65,h,a,b,c,d,e,f,g)
+    ROUND(66,g,h,a,b,c,d,e,f)
+    ROUND(67,f,g,h,a,b,c,d,e)
+    ROUND(68,e,f,g,h,a,b,c,d)
+    ROUND(69,d,e,f,g,h,a,b,c)
+    ROUND(70,c,d,e,f,g,h,a,b)
+    ROUND(71,b,c,d,e,f,g,h,a)
+
+    ROUND(72,a,b,c,d,e,f,g,h)
+    ROUND(73,h,a,b,c,d,e,f,g)
+    ROUND(74,g,h,a,b,c,d,e,f)
+    ROUND(75,f,g,h,a,b,c,d,e)
+    ROUND(76,e,f,g,h,a,b,c,d)
+    ROUND(77,d,e,f,g,h,a,b,c)
+    ROUND(78,c,d,e,f,g,h,a,b)
+    ROUND(79,b,c,d,e,f,g,h,a)
+#endif
+
+    ADDTO(a,H[0]);
+    ADDTO(b,H[1]);
+    ADDTO(c,H[2]);
+    ADDTO(d,H[3]);
+    ADDTO(e,H[4]);
+    ADDTO(f,H[5]);
+    ADDTO(g,H[6]);
+    ADDTO(h,H[7]);
+  }
+}
+
+void 
+SHA512_Update(SHA512Context *ctx, const unsigned char *input,
+              unsigned int inputLen)
+{
+    unsigned int inBuf;
+    if (!inputLen)
+    	return;
+
+#if defined(HAVE_LONG_LONG)
+    inBuf = (unsigned int)ctx->sizeLo & 0x7f;
+    /* Add inputLen into the count of bytes processed, before processing */
+    ctx->sizeLo += inputLen;
+#else
+    inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f;
+    ctx->sizeLo.lo += inputLen;
+    if (ctx->sizeLo.lo < inputLen) ctx->sizeLo.hi++;
+#endif
+
+    /* if data already in buffer, attemp to fill rest of buffer */
+    if (inBuf) {
+    	unsigned int todo = SHA512_BLOCK_LENGTH - inBuf;
+	if (inputLen < todo)
+	    todo = inputLen;
+	memcpy(B + inBuf, input, todo);
+	input    += todo;
+	inputLen -= todo;
+	if (inBuf + todo == SHA512_BLOCK_LENGTH)
+	    SHA512_Compress(ctx);
+    }
+
+    /* if enough data to fill one or more whole buffers, process them. */
+    while (inputLen >= SHA512_BLOCK_LENGTH) {
+    	memcpy(B, input, SHA512_BLOCK_LENGTH);
+	input    += SHA512_BLOCK_LENGTH;
+	inputLen -= SHA512_BLOCK_LENGTH;
+	SHA512_Compress(ctx);
+    }
+    /* if data left over, fill it into buffer */
+    if (inputLen) 
+    	memcpy(B, input, inputLen);
+}
+
+void 
+SHA512_End(SHA512Context *ctx, unsigned char *digest,
+           unsigned int *digestLen, unsigned int maxDigestLen)
+{
+#if defined(HAVE_LONG_LONG)
+    unsigned int inBuf  = (unsigned int)ctx->sizeLo & 0x7f;
+    unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf);
+    PRUint64 lo, t1;
+    lo = (ctx->sizeLo << 3);
+#else
+    unsigned int inBuf  = (unsigned int)ctx->sizeLo.lo & 0x7f;
+    unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf);
+    PRUint64 lo = ctx->sizeLo;
+    PRUint32 t1;
+    lo.lo <<= 3;
+#endif
+
+    SHA512_Update(ctx, pad, padLen);
+
+#if defined(HAVE_LONG_LONG)
+    W[14] = 0;
+#else
+    W[14].lo = 0;
+    W[14].hi = 0;
+#endif
+
+    W[15] = lo;
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP8(W[15]);
+#endif
+    SHA512_Compress(ctx);
+
+    /* now output the answer */
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP8(H[0]);
+    BYTESWAP8(H[1]);
+    BYTESWAP8(H[2]);
+    BYTESWAP8(H[3]);
+    BYTESWAP8(H[4]);
+    BYTESWAP8(H[5]);
+    BYTESWAP8(H[6]);
+    BYTESWAP8(H[7]);
+#endif
+    padLen = PR_MIN(SHA512_LENGTH, maxDigestLen);
+    memcpy(digest, H, padLen);
+    if (digestLen)
+	*digestLen = padLen;
+}
+
+SECStatus 
+SHA512_HashBuf(unsigned char *dest, const unsigned char *src, 
+               uint32 src_length)
+{
+    SHA512Context ctx;
+    unsigned int outLen;
+
+    SHA512_Begin(&ctx);
+    SHA512_Update(&ctx, src, src_length);
+    SHA512_End(&ctx, dest, &outLen, SHA512_LENGTH);
+
+    return SECSuccess;
+}
+
+
+SECStatus 
+SHA512_Hash(unsigned char *dest, const char *src)
+{
+    return SHA512_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+
+void SHA512_TraceState(SHA512Context *ctx) { }
+
+unsigned int 
+SHA512_FlattenSize(SHA512Context *ctx)
+{
+    return sizeof *ctx;
+}
+
+SECStatus 
+SHA512_Flatten(SHA512Context *ctx,unsigned char *space)
+{
+    PORT_Memcpy(space, ctx, sizeof *ctx);
+    return SECSuccess;
+}
+
+SHA512Context * 
+SHA512_Resurrect(unsigned char *space, void *arg)
+{
+    SHA512Context *ctx = SHA512_NewContext();
+    if (ctx) 
+	PORT_Memcpy(ctx, space, sizeof *ctx);
+    return ctx;
+}
+
+void SHA512_Clone(SHA512Context *dest, SHA512Context *src) 
+{
+    memcpy(dest, src, sizeof *dest);
+}
+
+/* ======================================================================= */
+/* SHA384 uses a SHA512Context as the real context. 
+** The only differences between SHA384 an SHA512 are:
+** a) the intialization values for the context, and
+** b) the number of bytes of data produced as output.
+*/
+
+/* SHA-384 initial hash values */
+static const PRUint64 H384[8] = {
+#if PR_BYTES_PER_LONG == 8
+     0xcbbb9d5dc1059ed8UL ,  0x629a292a367cd507UL , 
+     0x9159015a3070dd17UL ,  0x152fecd8f70e5939UL , 
+     0x67332667ffc00b31UL ,  0x8eb44a8768581511UL , 
+     0xdb0c2e0d64f98fa7UL ,  0x47b5481dbefa4fa4UL 
+#else
+    ULLC(cbbb9d5d,c1059ed8), ULLC(629a292a,367cd507), 
+    ULLC(9159015a,3070dd17), ULLC(152fecd8,f70e5939), 
+    ULLC(67332667,ffc00b31), ULLC(8eb44a87,68581511), 
+    ULLC(db0c2e0d,64f98fa7), ULLC(47b5481d,befa4fa4)
+#endif
+};
+
+SHA384Context *
+SHA384_NewContext(void)
+{
+    return SHA512_NewContext();
+}
+
+void 
+SHA384_DestroyContext(SHA384Context *ctx, PRBool freeit)
+{
+    SHA512_DestroyContext(ctx, freeit);
+}
+
+void 
+SHA384_Begin(SHA384Context *ctx)
+{
+    memset(ctx, 0, sizeof *ctx);
+    memcpy(H, H384, sizeof H384);
+}
+
+void 
+SHA384_Update(SHA384Context *ctx, const unsigned char *input,
+		    unsigned int inputLen)
+{
+    SHA512_Update(ctx, input, inputLen);
+}
+
+void 
+SHA384_End(SHA384Context *ctx, unsigned char *digest,
+		 unsigned int *digestLen, unsigned int maxDigestLen)
+{
+#define SHA_MIN(a,b) (a < b ? a : b)
+    unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH);
+    SHA512_End(ctx, digest, digestLen, maxLen);
+}
+
+SECStatus 
+SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
+			  uint32 src_length)
+{
+    SHA512Context ctx;
+    unsigned int outLen;
+
+    SHA384_Begin(&ctx);
+    SHA512_Update(&ctx, src, src_length);
+    SHA512_End(&ctx, dest, &outLen, SHA384_LENGTH);
+
+    return SECSuccess;
+}
+
+SECStatus 
+SHA384_Hash(unsigned char *dest, const char *src)
+{
+    return SHA384_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+void SHA384_TraceState(SHA384Context *ctx) { }
+
+unsigned int 
+SHA384_FlattenSize(SHA384Context *ctx)
+{
+    return sizeof(SHA384Context);
+}
+
+SECStatus 
+SHA384_Flatten(SHA384Context *ctx,unsigned char *space)
+{
+    return SHA512_Flatten(ctx, space);
+}
+
+SHA384Context * 
+SHA384_Resurrect(unsigned char *space, void *arg)
+{
+    return SHA512_Resurrect(space, arg);
+}
+
+void SHA384_Clone(SHA384Context *dest, SHA384Context *src) 
+{
+    memcpy(dest, src, sizeof *dest);
+}
+
+/* ======================================================================= */
+#ifdef SELFTEST
+#include <stdio.h>
+
+static const char abc[] = { "abc" };
+static const char abcdbc[] = { 
+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+};
+static const char abcdef[] = { 
+    "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+    "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" 
+};
+
+void
+dumpHash32(const unsigned char *buf, unsigned int bufLen)
+{
+    unsigned int i;
+    for (i = 0; i < bufLen; i += 4) {
+	printf(" %02x%02x%02x%02x", buf[i], buf[i+1], buf[i+2], buf[i+3]);
+    }
+    printf("\n");
+}
+
+void test256(void)
+{
+    unsigned char outBuf[SHA256_LENGTH];
+
+    printf("SHA256, input = %s\n", abc);
+    SHA256_Hash(outBuf, abc);
+    dumpHash32(outBuf, sizeof outBuf);
+
+    printf("SHA256, input = %s\n", abcdbc);
+    SHA256_Hash(outBuf, abcdbc);
+    dumpHash32(outBuf, sizeof outBuf);
+}
+
+void
+dumpHash64(const unsigned char *buf, unsigned int bufLen)
+{
+    unsigned int i;
+    for (i = 0; i < bufLen; i += 8) {
+    	if (i % 32 == 0)
+	    printf("\n");
+	printf(" %02x%02x%02x%02x%02x%02x%02x%02x", 
+	       buf[i  ], buf[i+1], buf[i+2], buf[i+3],
+	       buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
+    }
+    printf("\n");
+}
+
+void test512(void)
+{
+    unsigned char outBuf[SHA512_LENGTH];
+
+    printf("SHA512, input = %s\n", abc);
+    SHA512_Hash(outBuf, abc);
+    dumpHash64(outBuf, sizeof outBuf);
+
+    printf("SHA512, input = %s\n", abcdef);
+    SHA512_Hash(outBuf, abcdef);
+    dumpHash64(outBuf, sizeof outBuf);
+}
+
+void time512(void)
+{
+    unsigned char outBuf[SHA512_LENGTH];
+
+    SHA512_Hash(outBuf, abc);
+    SHA512_Hash(outBuf, abcdef);
+}
+
+void test384(void)
+{
+    unsigned char outBuf[SHA384_LENGTH];
+
+    printf("SHA384, input = %s\n", abc);
+    SHA384_Hash(outBuf, abc);
+    dumpHash64(outBuf, sizeof outBuf);
+
+    printf("SHA384, input = %s\n", abcdef);
+    SHA384_Hash(outBuf, abcdef);
+    dumpHash64(outBuf, sizeof outBuf);
+}
+
+int main (int argc, char *argv[], char *envp[])
+{
+    int i = 1;
+    if (argc > 1) {
+    	i = atoi(argv[1]);
+    }
+    if (i < 2) {
+	test256();
+	test512();
+	test384();
+    } else {
+    	while (i-- > 0) {
+	    time512();
+	}
+	printf("done\n");
+    }
+    return 0;
+}
+
+void *PORT_Alloc(size_t len) 		{ return malloc(len); }
+void PORT_Free(void *ptr)		{ free(ptr); }
+void PORT_ZFree(void *ptr, size_t len)  { memset(ptr, 0, len); free(ptr); }
+#endif
diff --git a/mozilla/security/nss/lib/freebl/sha_fast.c b/mozilla/security/nss/lib/freebl/sha_fast.c
new file mode 100644
index 0000000..f855285
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/sha_fast.c
@@ -0,0 +1,477 @@
+/* ***** 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 SHA 180-1 Reference Implementation (Optimized).
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Kocher of Cryptography Research.
+ * Portions created by the Initial Developer are Copyright (C) 1995-9
+ * 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include <memory.h>
+#include "blapi.h"
+#include "sha_fast.h"
+#include "prerror.h"
+
+#ifdef TRACING_SSL
+#include "ssl.h"
+#include "ssltrace.h"
+#endif
+
+static void shaCompress(volatile SHA_HW_t *X, const PRUint32 * datain);
+
+#define W u.w
+#define B u.b
+
+
+#define SHA_F1(X,Y,Z) ((((Y)^(Z))&(X))^(Z))
+#define SHA_F2(X,Y,Z) ((X)^(Y)^(Z))
+#define SHA_F3(X,Y,Z) (((X)&(Y))|((Z)&((X)|(Y))))
+#define SHA_F4(X,Y,Z) ((X)^(Y)^(Z))
+
+#define SHA_MIX(n,a,b,c)    XW(n) = SHA_ROTL(XW(a)^XW(b)^XW(c)^XW(n), 1)
+
+/*
+ *  SHA: initialize context
+ */
+void 
+SHA1_Begin(SHA1Context *ctx)
+{
+  ctx->size = 0;
+  /*
+   *  Initialize H with constants from FIPS180-1.
+   */
+  ctx->H[0] = 0x67452301L;
+  ctx->H[1] = 0xefcdab89L;
+  ctx->H[2] = 0x98badcfeL;
+  ctx->H[3] = 0x10325476L;
+  ctx->H[4] = 0xc3d2e1f0L;
+}
+
+/* Explanation of H array and index values:
+ * The context's H array is actually the concatenation of two arrays 
+ * defined by SHA1, the H array of state variables (5 elements),
+ * and the W array of intermediate values, of which there are 16 elements.
+ * The W array starts at H[5], that is W[0] is H[5].
+ * Although these values are defined as 32-bit values, we use 64-bit
+ * variables to hold them because the AMD64 stores 64 bit values in
+ * memory MUCH faster than it stores any smaller values.
+ *
+ * Rather than passing the context structure to shaCompress, we pass
+ * this combined array of H and W values.  We do not pass the address
+ * of the first element of this array, but rather pass the address of an
+ * element in the middle of the array, element X.  Presently X[0] is H[11].
+ * So we pass the address of H[11] as the address of array X to shaCompress.
+ * Then shaCompress accesses the members of the array using positive AND 
+ * negative indexes.  
+ *
+ * Pictorially: (each element is 8 bytes)
+ * H | H0 H1 H2 H3 H4 W0 W1 W2 W3 W4 W5 W6 W7 W8 W9 Wa Wb Wc Wd We Wf |
+ * X |-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 |
+ * 
+ * The byte offset from X[0] to any member of H and W is always 
+ * representable in a signed 8-bit value, which will be encoded 
+ * as a single byte offset in the X86-64 instruction set.  
+ * If we didn't pass the address of H[11], and instead passed the 
+ * address of H[0], the offsets to elements H[16] and above would be
+ * greater than 127, not representable in a signed 8-bit value, and the 
+ * x86-64 instruction set would encode every such offset as a 32-bit 
+ * signed number in each instruction that accessed element H[16] or 
+ * higher.  This results in much bigger and slower code. 
+ */
+#if !defined(SHA_PUT_W_IN_STACK)
+#define H2X 11 /* X[0] is H[11], and H[0] is X[-11] */
+#define W2X  6 /* X[0] is W[6],  and W[0] is X[-6]  */
+#else
+#define H2X 0
+#endif
+
+/*
+ *  SHA: Add data to context.
+ */
+void 
+SHA1_Update(SHA1Context *ctx, const unsigned char *dataIn, unsigned int len) 
+{
+  register unsigned int lenB;
+  register unsigned int togo;
+
+  if (!len)
+    return;
+
+  /* accumulate the byte count. */
+  lenB = (unsigned int)(ctx->size) & 63U;
+
+  ctx->size += len;
+
+  /*
+   *  Read the data into W and process blocks as they get full
+   */
+  if (lenB > 0) {
+    togo = 64U - lenB;
+    if (len < togo)
+      togo = len;
+    memcpy(ctx->B + lenB, dataIn, togo);
+    len    -= togo;
+    dataIn += togo;
+    lenB    = (lenB + togo) & 63U;
+    if (!lenB) {
+      shaCompress(&ctx->H[H2X], ctx->W);
+    }
+  }
+#if !defined(SHA_ALLOW_UNALIGNED_ACCESS)
+  if ((ptrdiff_t)dataIn % sizeof(PRUint32)) {
+    while (len >= 64U) {
+      memcpy(ctx->B, dataIn, 64);
+      len    -= 64U;
+      shaCompress(&ctx->H[H2X], ctx->W);
+      dataIn += 64U;
+    }
+  } else 
+#endif
+  {
+    while (len >= 64U) {
+      len    -= 64U;
+      shaCompress(&ctx->H[H2X], (PRUint32 *)dataIn);
+      dataIn += 64U;
+    }
+  }
+  if (len) {
+    memcpy(ctx->B, dataIn, len);
+  }
+}
+
+
+/*
+ *  SHA: Generate hash value from context
+ */
+void 
+SHA1_End(SHA1Context *ctx, unsigned char *hashout,
+         unsigned int *pDigestLen, unsigned int maxDigestLen)
+{
+  register PRUint64 size;
+  register PRUint32 lenB;
+
+  static const unsigned char bulk_pad[64] = { 0x80,0,0,0,0,0,0,0,0,0,
+          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  };
+#define tmp lenB
+
+  PORT_Assert (maxDigestLen >= SHA1_LENGTH);
+
+  /*
+   *  Pad with a binary 1 (e.g. 0x80), then zeroes, then length in bits
+   */
+  size = ctx->size;
+
+  lenB = (PRUint32)size & 63;
+  SHA1_Update(ctx, bulk_pad, (((55+64) - lenB) & 63) + 1);
+  PORT_Assert(((PRUint32)ctx->size & 63) == 56);
+  /* Convert size from bytes to bits. */
+  size <<= 3;
+  ctx->W[14] = SHA_HTONL((PRUint32)(size >> 32));
+  ctx->W[15] = SHA_HTONL((PRUint32)size);
+  shaCompress(&ctx->H[H2X], ctx->W);
+
+  /*
+   *  Output hash
+   */
+  SHA_STORE_RESULT;
+  *pDigestLen = SHA1_LENGTH;
+
+}
+
+#undef B
+#undef tmp
+/*
+ *  SHA: Compression function, unrolled.
+ *
+ * Some operations in shaCompress are done as 5 groups of 16 operations.
+ * Others are done as 4 groups of 20 operations.
+ * The code below shows that structure.
+ *
+ * The functions that compute the new values of the 5 state variables
+ * A-E are done in 4 groups of 20 operations (or you may also think
+ * of them as being done in 16 groups of 5 operations).  They are
+ * done by the SHA_RNDx macros below, in the right column.
+ *
+ * The functions that set the 16 values of the W array are done in 
+ * 5 groups of 16 operations.  The first group is done by the 
+ * LOAD macros below, the latter 4 groups are done by SHA_MIX below,
+ * in the left column.
+ *
+ * gcc's optimizer observes that each member of the W array is assigned
+ * a value 5 times in this code.  It reduces the number of store 
+ * operations done to the W array in the context (that is, in the X array)
+ * by creating a W array on the stack, and storing the W values there for 
+ * the first 4 groups of operations on W, and storing the values in the 
+ * context's W array only in the fifth group.  This is undesirable.
+ * It is MUCH bigger code than simply using the context's W array, because 
+ * all the offsets to the W array in the stack are 32-bit signed offsets, 
+ * and it is no faster than storing the values in the context's W array. 
+ *
+ * The original code for sha_fast.c prevented this creation of a separate 
+ * W array in the stack by creating a W array of 80 members, each of
+ * whose elements is assigned only once. It also separated the computations
+ * of the W array values and the computations of the values for the 5
+ * state variables into two separate passes, W's, then A-E's so that the 
+ * second pass could be done all in registers (except for accessing the W
+ * array) on machines with fewer registers.  The method is suboptimal
+ * for machines with enough registers to do it all in one pass, and it
+ * necessitates using many instructions with 32-bit offsets.
+ *
+ * This code eliminates the separate W array on the stack by a completely
+ * different means: by declaring the X array volatile.  This prevents
+ * the optimizer from trying to reduce the use of the X array by the
+ * creation of a MORE expensive W array on the stack. The result is
+ * that all instructions use signed 8-bit offsets and not 32-bit offsets.
+ *
+ * The combination of this code and the -O3 optimizer flag on GCC 3.4.3
+ * results in code that is 3 times faster than the previous NSS sha_fast
+ * code on AMD64.
+ */
+static void 
+shaCompress(volatile SHA_HW_t *X, const PRUint32 *inbuf) 
+{
+  register SHA_HW_t A, B, C, D, E;
+
+#if defined(SHA_NEED_TMP_VARIABLE)
+  register PRUint32 tmp;
+#endif
+
+#if !defined(SHA_PUT_W_IN_STACK)
+#define XH(n) X[n-H2X]
+#define XW(n) X[n-W2X]
+#else
+  SHA_HW_t w_0, w_1, w_2, w_3, w_4, w_5, w_6, w_7,
+           w_8, w_9, w_10, w_11, w_12, w_13, w_14, w_15;
+#define XW(n) w_ ## n
+#define XH(n) X[n]
+#endif
+
+#define K0 0x5a827999L
+#define K1 0x6ed9eba1L
+#define K2 0x8f1bbcdcL
+#define K3 0xca62c1d6L
+
+#define SHA_RND1(a,b,c,d,e,n) \
+  a = SHA_ROTL(b,5)+SHA_F1(c,d,e)+a+XW(n)+K0; c=SHA_ROTL(c,30) 
+#define SHA_RND2(a,b,c,d,e,n) \
+  a = SHA_ROTL(b,5)+SHA_F2(c,d,e)+a+XW(n)+K1; c=SHA_ROTL(c,30) 
+#define SHA_RND3(a,b,c,d,e,n) \
+  a = SHA_ROTL(b,5)+SHA_F3(c,d,e)+a+XW(n)+K2; c=SHA_ROTL(c,30) 
+#define SHA_RND4(a,b,c,d,e,n) \
+  a = SHA_ROTL(b,5)+SHA_F4(c,d,e)+a+XW(n)+K3; c=SHA_ROTL(c,30) 
+
+#define LOAD(n) XW(n) = SHA_HTONL(inbuf[n])
+
+  A = XH(0);
+  B = XH(1);
+  C = XH(2);
+  D = XH(3);
+  E = XH(4);
+
+  LOAD(0);		   SHA_RND1(E,A,B,C,D, 0);
+  LOAD(1);		   SHA_RND1(D,E,A,B,C, 1);
+  LOAD(2);		   SHA_RND1(C,D,E,A,B, 2);
+  LOAD(3);		   SHA_RND1(B,C,D,E,A, 3);
+  LOAD(4);		   SHA_RND1(A,B,C,D,E, 4);
+  LOAD(5);		   SHA_RND1(E,A,B,C,D, 5);
+  LOAD(6);		   SHA_RND1(D,E,A,B,C, 6);
+  LOAD(7);		   SHA_RND1(C,D,E,A,B, 7);
+  LOAD(8);		   SHA_RND1(B,C,D,E,A, 8);
+  LOAD(9);		   SHA_RND1(A,B,C,D,E, 9);
+  LOAD(10);		   SHA_RND1(E,A,B,C,D,10);
+  LOAD(11);		   SHA_RND1(D,E,A,B,C,11);
+  LOAD(12);		   SHA_RND1(C,D,E,A,B,12);
+  LOAD(13);		   SHA_RND1(B,C,D,E,A,13);
+  LOAD(14);		   SHA_RND1(A,B,C,D,E,14);
+  LOAD(15);		   SHA_RND1(E,A,B,C,D,15);
+
+  SHA_MIX( 0, 13,  8,  2); SHA_RND1(D,E,A,B,C, 0);
+  SHA_MIX( 1, 14,  9,  3); SHA_RND1(C,D,E,A,B, 1);
+  SHA_MIX( 2, 15, 10,  4); SHA_RND1(B,C,D,E,A, 2);
+  SHA_MIX( 3,  0, 11,  5); SHA_RND1(A,B,C,D,E, 3);
+
+  SHA_MIX( 4,  1, 12,  6); SHA_RND2(E,A,B,C,D, 4);
+  SHA_MIX( 5,  2, 13,  7); SHA_RND2(D,E,A,B,C, 5);
+  SHA_MIX( 6,  3, 14,  8); SHA_RND2(C,D,E,A,B, 6);
+  SHA_MIX( 7,  4, 15,  9); SHA_RND2(B,C,D,E,A, 7);
+  SHA_MIX( 8,  5,  0, 10); SHA_RND2(A,B,C,D,E, 8);
+  SHA_MIX( 9,  6,  1, 11); SHA_RND2(E,A,B,C,D, 9);
+  SHA_MIX(10,  7,  2, 12); SHA_RND2(D,E,A,B,C,10);
+  SHA_MIX(11,  8,  3, 13); SHA_RND2(C,D,E,A,B,11);
+  SHA_MIX(12,  9,  4, 14); SHA_RND2(B,C,D,E,A,12);
+  SHA_MIX(13, 10,  5, 15); SHA_RND2(A,B,C,D,E,13);
+  SHA_MIX(14, 11,  6,  0); SHA_RND2(E,A,B,C,D,14);
+  SHA_MIX(15, 12,  7,  1); SHA_RND2(D,E,A,B,C,15);
+
+  SHA_MIX( 0, 13,  8,  2); SHA_RND2(C,D,E,A,B, 0);
+  SHA_MIX( 1, 14,  9,  3); SHA_RND2(B,C,D,E,A, 1);
+  SHA_MIX( 2, 15, 10,  4); SHA_RND2(A,B,C,D,E, 2);
+  SHA_MIX( 3,  0, 11,  5); SHA_RND2(E,A,B,C,D, 3);
+  SHA_MIX( 4,  1, 12,  6); SHA_RND2(D,E,A,B,C, 4);
+  SHA_MIX( 5,  2, 13,  7); SHA_RND2(C,D,E,A,B, 5);
+  SHA_MIX( 6,  3, 14,  8); SHA_RND2(B,C,D,E,A, 6);
+  SHA_MIX( 7,  4, 15,  9); SHA_RND2(A,B,C,D,E, 7);
+
+  SHA_MIX( 8,  5,  0, 10); SHA_RND3(E,A,B,C,D, 8);
+  SHA_MIX( 9,  6,  1, 11); SHA_RND3(D,E,A,B,C, 9);
+  SHA_MIX(10,  7,  2, 12); SHA_RND3(C,D,E,A,B,10);
+  SHA_MIX(11,  8,  3, 13); SHA_RND3(B,C,D,E,A,11);
+  SHA_MIX(12,  9,  4, 14); SHA_RND3(A,B,C,D,E,12);
+  SHA_MIX(13, 10,  5, 15); SHA_RND3(E,A,B,C,D,13);
+  SHA_MIX(14, 11,  6,  0); SHA_RND3(D,E,A,B,C,14);
+  SHA_MIX(15, 12,  7,  1); SHA_RND3(C,D,E,A,B,15);
+
+  SHA_MIX( 0, 13,  8,  2); SHA_RND3(B,C,D,E,A, 0);
+  SHA_MIX( 1, 14,  9,  3); SHA_RND3(A,B,C,D,E, 1);
+  SHA_MIX( 2, 15, 10,  4); SHA_RND3(E,A,B,C,D, 2);
+  SHA_MIX( 3,  0, 11,  5); SHA_RND3(D,E,A,B,C, 3);
+  SHA_MIX( 4,  1, 12,  6); SHA_RND3(C,D,E,A,B, 4);
+  SHA_MIX( 5,  2, 13,  7); SHA_RND3(B,C,D,E,A, 5);
+  SHA_MIX( 6,  3, 14,  8); SHA_RND3(A,B,C,D,E, 6);
+  SHA_MIX( 7,  4, 15,  9); SHA_RND3(E,A,B,C,D, 7);
+  SHA_MIX( 8,  5,  0, 10); SHA_RND3(D,E,A,B,C, 8);
+  SHA_MIX( 9,  6,  1, 11); SHA_RND3(C,D,E,A,B, 9);
+  SHA_MIX(10,  7,  2, 12); SHA_RND3(B,C,D,E,A,10);
+  SHA_MIX(11,  8,  3, 13); SHA_RND3(A,B,C,D,E,11);
+
+  SHA_MIX(12,  9,  4, 14); SHA_RND4(E,A,B,C,D,12);
+  SHA_MIX(13, 10,  5, 15); SHA_RND4(D,E,A,B,C,13);
+  SHA_MIX(14, 11,  6,  0); SHA_RND4(C,D,E,A,B,14);
+  SHA_MIX(15, 12,  7,  1); SHA_RND4(B,C,D,E,A,15);
+
+  SHA_MIX( 0, 13,  8,  2); SHA_RND4(A,B,C,D,E, 0);
+  SHA_MIX( 1, 14,  9,  3); SHA_RND4(E,A,B,C,D, 1);
+  SHA_MIX( 2, 15, 10,  4); SHA_RND4(D,E,A,B,C, 2);
+  SHA_MIX( 3,  0, 11,  5); SHA_RND4(C,D,E,A,B, 3);
+  SHA_MIX( 4,  1, 12,  6); SHA_RND4(B,C,D,E,A, 4);
+  SHA_MIX( 5,  2, 13,  7); SHA_RND4(A,B,C,D,E, 5);
+  SHA_MIX( 6,  3, 14,  8); SHA_RND4(E,A,B,C,D, 6);
+  SHA_MIX( 7,  4, 15,  9); SHA_RND4(D,E,A,B,C, 7);
+  SHA_MIX( 8,  5,  0, 10); SHA_RND4(C,D,E,A,B, 8);
+  SHA_MIX( 9,  6,  1, 11); SHA_RND4(B,C,D,E,A, 9);
+  SHA_MIX(10,  7,  2, 12); SHA_RND4(A,B,C,D,E,10);
+  SHA_MIX(11,  8,  3, 13); SHA_RND4(E,A,B,C,D,11);
+  SHA_MIX(12,  9,  4, 14); SHA_RND4(D,E,A,B,C,12);
+  SHA_MIX(13, 10,  5, 15); SHA_RND4(C,D,E,A,B,13);
+  SHA_MIX(14, 11,  6,  0); SHA_RND4(B,C,D,E,A,14);
+  SHA_MIX(15, 12,  7,  1); SHA_RND4(A,B,C,D,E,15);
+
+  XH(0) += A;
+  XH(1) += B;
+  XH(2) += C;
+  XH(3) += D;
+  XH(4) += E;
+}
+
+/*************************************************************************
+** Code below this line added to make SHA code support BLAPI interface
+*/
+
+SHA1Context *
+SHA1_NewContext(void)
+{
+    SHA1Context *cx;
+
+    /* no need to ZNew, SHA1_Begin will init the context */
+    cx = PORT_New(SHA1Context);
+    return cx;
+}
+
+/* Zero and free the context */
+void
+SHA1_DestroyContext(SHA1Context *cx, PRBool freeit)
+{
+    memset(cx, 0, sizeof *cx);
+    if (freeit) {
+        PORT_Free(cx);
+    }
+}
+
+SECStatus
+SHA1_HashBuf(unsigned char *dest, const unsigned char *src, uint32 src_length)
+{
+    SHA1Context ctx;
+    unsigned int outLen;
+
+    SHA1_Begin(&ctx);
+    SHA1_Update(&ctx, src, src_length);
+    SHA1_End(&ctx, dest, &outLen, SHA1_LENGTH);
+    return SECSuccess;
+}
+
+/* Hash a null-terminated character string. */
+SECStatus
+SHA1_Hash(unsigned char *dest, const char *src)
+{
+    return SHA1_HashBuf(dest, (const unsigned char *)src, PORT_Strlen (src));
+}
+
+/*
+ * need to support save/restore state in pkcs11. Stores all the info necessary
+ * for a structure into just a stream of bytes.
+ */
+unsigned int
+SHA1_FlattenSize(SHA1Context *cx)
+{
+    return sizeof(SHA1Context);
+}
+
+SECStatus
+SHA1_Flatten(SHA1Context *cx,unsigned char *space)
+{
+    PORT_Memcpy(space,cx, sizeof(SHA1Context));
+    return SECSuccess;
+}
+
+SHA1Context *
+SHA1_Resurrect(unsigned char *space,void *arg)
+{
+    SHA1Context *cx = SHA1_NewContext();
+    if (cx == NULL) return NULL;
+
+    PORT_Memcpy(cx,space, sizeof(SHA1Context));
+    return cx;
+}
+
+void SHA1_Clone(SHA1Context *dest, SHA1Context *src) 
+{
+    memcpy(dest, src, sizeof *dest);
+}
+
+void
+SHA1_TraceState(SHA1Context *ctx)
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+}
diff --git a/mozilla/security/nss/lib/freebl/sha_fast.h b/mozilla/security/nss/lib/freebl/sha_fast.h
new file mode 100644
index 0000000..952d2cf
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/sha_fast.h
@@ -0,0 +1,184 @@
+/* ***** 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 SHA 180-1 Reference Implementation (Optimized).
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Kocher of Cryptography Research.
+ * Portions created by the Initial Developer are Copyright (C) 1995-9
+ * 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 ***** */
+
+#ifndef _SHA_FAST_H_
+#define _SHA_FAST_H_
+
+#include "prlong.h"
+
+#define SHA1_INPUT_LEN 64
+
+#if defined(IS_64) && !defined(__sparc) 
+typedef PRUint64 SHA_HW_t;
+#define SHA1_USING_64_BIT 1
+#else
+typedef PRUint32 SHA_HW_t;
+#endif
+
+struct SHA1ContextStr {
+  union {
+    PRUint32 w[16];		/* input buffer */
+    PRUint8  b[64];
+  } u;
+  PRUint64 size;          	/* count of hashed bytes. */
+  SHA_HW_t H[22];		/* 5 state variables, 16 tmp values, 1 extra */
+};
+
+#if defined(_MSC_VER)
+#include <stdlib.h>
+#if defined(IS_LITTLE_ENDIAN) 
+#if (_MSC_VER >= 1300)
+#pragma intrinsic(_byteswap_ulong)
+#define SHA_HTONL(x) _byteswap_ulong(x)
+#elif defined(NSS_X86_OR_X64)
+#ifndef FORCEINLINE
+#if (_MSC_VER >= 1200)
+#define FORCEINLINE __forceinline
+#else
+#define FORCEINLINE __inline
+#endif /* _MSC_VER */
+#endif /* !defined FORCEINLINE */
+#define FASTCALL __fastcall
+
+static FORCEINLINE PRUint32 FASTCALL 
+swap4b(PRUint32 dwd) 
+{
+    __asm {
+    	mov   eax,dwd
+	bswap eax
+    }
+}
+
+#define SHA_HTONL(x) swap4b(x)
+#endif /* NSS_X86_OR_X64 */
+#endif /* IS_LITTLE_ENDIAN */
+
+#pragma intrinsic (_lrotr, _lrotl) 
+#define SHA_ROTL(x,n) _lrotl(x,n)
+#define SHA_ROTL_IS_DEFINED 1
+#endif /* _MSC_VER */
+
+#if defined(__GNUC__) 
+/* __x86_64__  and __x86_64 are defined by GCC on x86_64 CPUs */
+
+#if defined( SHA1_USING_64_BIT )
+static __inline__ PRUint64 SHA_ROTL(PRUint64 x, PRUint32 n)
+{
+    PRUint32 t = (PRUint32)x;
+    return ((t << n) | (t >> (32 - n)));
+}
+#else 
+static __inline__ PRUint32 SHA_ROTL(PRUint32 t, PRUint32 n)
+{
+    return ((t << n) | (t >> (32 - n)));
+}
+#endif
+#define SHA_ROTL_IS_DEFINED 1
+
+#if defined(NSS_X86_OR_X64)
+static __inline__ PRUint32 swap4b(PRUint32 value)
+{
+    __asm__("bswap %0" : "+r" (value));
+    return (value);
+}
+#define SHA_HTONL(x) swap4b(x)
+#endif /* x86 family */
+
+#endif /* __GNUC__ */
+
+#if !defined(SHA_ROTL_IS_DEFINED)
+#define SHA_NEED_TMP_VARIABLE 1
+#define SHA_ROTL(X,n) (tmp = (X), ((tmp) << (n)) | ((tmp) >> (32-(n))))
+#endif
+
+#if defined(NSS_X86_OR_X64)
+#define SHA_ALLOW_UNALIGNED_ACCESS 1
+#endif
+
+#if !defined(SHA_HTONL)
+#define SHA_MASK      0x00FF00FF
+#if defined(IS_LITTLE_ENDIAN)
+#undef  SHA_NEED_TMP_VARIABLE 
+#define SHA_NEED_TMP_VARIABLE 1
+#define SHA_HTONL(x)  (tmp = (x), tmp = (tmp << 16) | (tmp >> 16), \
+                       ((tmp & SHA_MASK) << 8) | ((tmp >> 8) & SHA_MASK))
+#else
+#define SHA_HTONL(x)  (x)
+#endif
+#endif
+
+#define SHA_BYTESWAP(x) x = SHA_HTONL(x)
+
+#define SHA_STORE(n) ((PRUint32*)hashout)[n] = SHA_HTONL(ctx->H[n])
+#if defined(SHA_ALLOW_UNALIGNED_ACCESS)
+#define SHA_STORE_RESULT \
+  SHA_STORE(0); \
+  SHA_STORE(1); \
+  SHA_STORE(2); \
+  SHA_STORE(3); \
+  SHA_STORE(4);
+
+#elif defined(IS_LITTLE_ENDIAN) || defined( SHA1_USING_64_BIT )
+#define SHA_STORE_RESULT \
+  if (!((ptrdiff_t)hashout % sizeof(PRUint32))) { \
+    SHA_STORE(0); \
+    SHA_STORE(1); \
+    SHA_STORE(2); \
+    SHA_STORE(3); \
+    SHA_STORE(4); \
+  } else { \
+    ctx->u.w[0] = SHA_HTONL(ctx->H[0]); \
+    ctx->u.w[1] = SHA_HTONL(ctx->H[1]); \
+    ctx->u.w[2] = SHA_HTONL(ctx->H[2]); \
+    ctx->u.w[3] = SHA_HTONL(ctx->H[3]); \
+    ctx->u.w[4] = SHA_HTONL(ctx->H[4]); \
+    memcpy(hashout, ctx->u.w, SHA1_LENGTH); \
+  }
+
+#else
+#define SHA_STORE_RESULT \
+  if (!((ptrdiff_t)hashout % sizeof(PRUint32))) { \
+    SHA_STORE(0); \
+    SHA_STORE(1); \
+    SHA_STORE(2); \
+    SHA_STORE(3); \
+    SHA_STORE(4); \
+  } else { \
+    memcpy(hashout, ctx->H, SHA1_LENGTH); \
+  }
+#endif 
+
+#endif /* _SHA_FAST_H_ */
diff --git a/mozilla/security/nss/lib/freebl/shsign.h b/mozilla/security/nss/lib/freebl/shsign.h
new file mode 100644
index 0000000..82d40e8
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/shsign.h
@@ -0,0 +1,47 @@
+/* ***** 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) 2003
+ * 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 ***** */
+/* $Id: shsign.h,v 1.3 2004/04/27 23:04:36 gerv%gerv.net Exp $ */
+
+#ifndef _SHSIGN_H_
+#define _SHSIGN_H_
+
+#define SGN_SUFFIX ".chk"
+#define  NSS_SIGN_CHK_MAGIC1 0xf1
+#define  NSS_SIGN_CHK_MAGIC2 0xc5
+#define  NSS_SIGN_CHK_MAJOR_VERSION 0x01
+#define  NSS_SIGN_CHK_MINOR_VERSION 0x02
+
+#endif /* _SHSIGN_H_ */
diff --git a/mozilla/security/nss/lib/freebl/shvfy.c b/mozilla/security/nss/lib/freebl/shvfy.c
new file mode 100644
index 0000000..8fc5ef4
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/shvfy.c
@@ -0,0 +1,314 @@
+
+/* ***** 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) 2003
+ * 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 ***** */
+/* $Id: shvfy.c,v 1.11 2008/11/18 19:48:24 rrelyea%redhat.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "shsign.h"
+#include "prlink.h"
+#include "prio.h"
+#include "blapi.h"
+#include "seccomon.h"
+#include "stdio.h"
+#include "prmem.h"
+
+
+/* #define DEBUG_SHVERIFY 1 */
+
+static char *
+mkCheckFileName(const char *libName)
+{
+    int ln_len = PORT_Strlen(libName);
+    char *output = PORT_Alloc(ln_len+sizeof(SGN_SUFFIX));
+    int index = ln_len + 1 - sizeof("."SHLIB_SUFFIX);
+
+    if ((index > 0) &&
+        (PORT_Strncmp(&libName[index],
+                        "."SHLIB_SUFFIX,sizeof("."SHLIB_SUFFIX)) == 0)) {
+        ln_len = index;
+    }
+    PORT_Memcpy(output,libName,ln_len);
+    PORT_Memcpy(&output[ln_len],SGN_SUFFIX,sizeof(SGN_SUFFIX));
+    return output;
+}
+
+static int
+decodeInt(unsigned char *buf)
+{
+    return (buf[3]) | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24);
+}
+
+static SECStatus
+readItem(PRFileDesc *fd, SECItem *item)
+{
+    unsigned char buf[4];
+    int bytesRead;
+
+
+    bytesRead = PR_Read(fd, buf, 4);
+    if (bytesRead != 4) {
+	return SECFailure;
+    }
+    item->len = decodeInt(buf);
+
+    item->data = PORT_Alloc(item->len);
+    if (item->data == NULL) {
+	item->len = 0;
+	return SECFailure;
+    }
+    bytesRead = PR_Read(fd, item->data, item->len);
+    if (bytesRead != item->len) {
+	PORT_Free(item->data);
+	item->data = NULL;
+	item->len = 0;
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * Define PSEUDO_FIPS if you can't do FIPS software integrity test (e.g.,
+ * if you're using NSS as static libraries), but want to confirm to the
+ * rest of the FIPS requirements.
+ */
+#define PSEUDO_FIPS
+
+PRBool
+BLAPI_SHVerify(const char *name, PRFuncPtr addr)
+{
+#ifdef PSEUDO_FIPS
+    return PR_TRUE;  /* a lie, hence *pseudo* FIPS */
+#else
+    /* find our shared library name */
+    char *shName = PR_GetLibraryFilePathname(name, addr);
+    char *checkName = NULL;
+    PRFileDesc *checkFD = NULL;
+    PRFileDesc *shFD = NULL;
+    SHA1Context *hashcx = NULL;
+    SECItem signature = { 0, NULL, 0 };
+    SECItem hash;
+    int bytesRead, offset;
+    SECStatus rv;
+    DSAPublicKey key;
+    int count;
+
+    PRBool result = PR_FALSE; /* if anything goes wrong,
+			       * the signature does not verify */
+    unsigned char buf[512];
+    unsigned char hashBuf[SHA1_LENGTH];
+
+    PORT_Memset(&key,0,sizeof(key));
+    hash.data = hashBuf;
+    hash.len = sizeof(hashBuf);
+
+    if (!shName) {
+	goto loser;
+    }
+
+    /* figure out the name of our check file */
+    checkName = mkCheckFileName(shName);
+    if (!checkName) {
+	goto loser;
+    }
+
+    /* open the check File */
+    checkFD = PR_Open(checkName, PR_RDONLY, 0);
+    if (checkFD == NULL) {
+#ifdef DEBUG_SHVERIFY
+        fprintf(stderr, "Failed to open the check file %s: (%d, %d)\n",
+                checkName, (int)PR_GetError(), (int)PR_GetOSError());
+#endif /* DEBUG_SHVERIFY */
+	goto loser;
+    }
+
+    /* read and Verify the headerthe header */
+    bytesRead = PR_Read(checkFD, buf, 12);
+    if (bytesRead != 12) {
+	goto loser;
+    }
+    if ((buf[0] != NSS_SIGN_CHK_MAGIC1) || (buf[1] != NSS_SIGN_CHK_MAGIC2)) {
+	goto loser;
+    }
+    if ((buf[2] != NSS_SIGN_CHK_MAJOR_VERSION) || 
+				(buf[3] < NSS_SIGN_CHK_MINOR_VERSION)) {
+	goto loser;
+    }
+#ifdef notdef
+    if (decodeInt(&buf[8]) != CKK_DSA) {
+	goto loser;
+    }
+#endif
+
+    /* seek past any future header extensions */
+    offset = decodeInt(&buf[4]);
+    PR_Seek(checkFD, offset, PR_SEEK_SET);
+
+    /* read the key */
+    rv = readItem(checkFD,&key.params.prime);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    rv = readItem(checkFD,&key.params.subPrime);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    rv = readItem(checkFD,&key.params.base);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    rv = readItem(checkFD,&key.publicValue);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    /* read the siganture */
+    rv = readItem(checkFD,&signature);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    /* done with the check file */
+    PR_Close(checkFD);
+    checkFD = NULL;
+
+    /* open our library file */
+    shFD = PR_Open(shName, PR_RDONLY, 0);
+    if (shFD == NULL) {
+#ifdef DEBUG_SHVERIFY
+        fprintf(stderr, "Failed to open the library file %s: (%d, %d)\n",
+                shName, (int)PR_GetError(), (int)PR_GetOSError());
+#endif /* DEBUG_SHVERIFY */
+	goto loser;
+    }
+
+    /* hash our library file with SHA1 */
+    hashcx = SHA1_NewContext();
+    if (hashcx == NULL) {
+	goto loser;
+    }
+    SHA1_Begin(hashcx);
+
+    count = 0;
+    while ((bytesRead = PR_Read(shFD, buf, sizeof(buf))) > 0) {
+	SHA1_Update(hashcx, buf, bytesRead);
+	count += bytesRead;
+    }
+    PR_Close(shFD);
+    shFD = NULL;
+
+    SHA1_End(hashcx, hash.data, &hash.len, hash.len);
+
+
+    /* verify the hash against the check file */
+    if (DSA_VerifyDigest(&key, &signature, &hash) == SECSuccess) {
+	result = PR_TRUE;
+    }
+#ifdef DEBUG_SHVERIFY
+  {
+        int i,j;
+        fprintf(stderr,"File %s: %d bytes\n",shName, count);
+        fprintf(stderr,"  hash: %d bytes\n", hash.len);
+#define STEP 10
+        for (i=0; i < hash.len; i += STEP) {
+           fprintf(stderr,"   ");
+           for (j=0; j < STEP && (i+j) < hash.len; j++) {
+                fprintf(stderr," %02x", hash.data[i+j]);
+           }
+           fprintf(stderr,"\n");
+        }
+        fprintf(stderr,"  signature: %d bytes\n", signature.len);
+        for (i=0; i < signature.len; i += STEP) {
+           fprintf(stderr,"   ");
+           for (j=0; j < STEP && (i+j) < signature.len; j++) {
+                fprintf(stderr," %02x", signature.data[i+j]);
+           }
+           fprintf(stderr,"\n");
+        }
+	fprintf(stderr,"Verified : %s\n",result?"TRUE": "FALSE");
+    }
+#endif /* DEBUG_SHVERIFY */
+
+
+loser:
+    if (shName != NULL) {
+	PR_Free(shName);
+    }
+    if (checkName != NULL) {
+	PORT_Free(checkName);
+    }
+    if (checkFD != NULL) {
+	PR_Close(checkFD);
+    }
+    if (shFD != NULL) {
+	PR_Close(shFD);
+    }
+    if (hashcx != NULL) {
+	SHA1_DestroyContext(hashcx,PR_TRUE);
+    }
+    if (signature.data != NULL) {
+	PORT_Free(signature.data);
+    }
+    if (key.params.prime.data != NULL) {
+	PORT_Free(key.params.prime.data);
+    }
+    if (key.params.subPrime.data != NULL) {
+	PORT_Free(key.params.subPrime.data);
+    }
+    if (key.params.base.data != NULL) {
+	PORT_Free(key.params.base.data);
+    }
+    if (key.publicValue.data != NULL) {
+	PORT_Free(key.publicValue.data);
+    }
+
+    return result;
+#endif  /* PSEUDO_FIPS */
+}
+
+PRBool
+BLAPI_VerifySelf(const char *name)
+{
+    if (name == NULL) {
+	/*
+	 * If name is NULL, freebl is statically linked into softoken.
+	 * softoken will call BLAPI_SHVerify next to verify itself.
+	 */
+	return PR_TRUE;
+    }
+    return BLAPI_SHVerify(name, (PRFuncPtr) decodeInt);
+}
diff --git a/mozilla/security/nss/lib/freebl/sysrand.c b/mozilla/security/nss/lib/freebl/sysrand.c
new file mode 100644
index 0000000..8494eaf
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/sysrand.c
@@ -0,0 +1,78 @@
+/* ***** 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 ***** */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "seccomon.h"
+
+static size_t rng_systemFromNoise(unsigned char *dest, size_t maxLen);
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+#include "unix_rand.c"
+#endif
+#ifdef XP_WIN
+#include "win_rand.c"
+#endif
+#ifdef XP_OS2
+#include "os2_rand.c"
+#endif
+
+/*
+ * Normal RNG_SystemRNG() isn't available, use the system noise to collect
+ * the required amount of entropy.
+ */
+static size_t 
+rng_systemFromNoise(unsigned char *dest, size_t maxLen) 
+{
+   size_t retBytes = maxLen;
+
+   while (maxLen) {
+	size_t nbytes = RNG_GetNoise(dest, maxLen);
+
+	PORT_Assert(nbytes != 0);
+
+	dest += nbytes;
+	maxLen -= nbytes;
+
+	/* some hw op to try to introduce more entropy into the next
+	 * RNG_GetNoise call */
+	rng_systemJitter();
+   }
+   return retBytes;
+}
+
diff --git a/mozilla/security/nss/lib/freebl/tlsprfalg.c b/mozilla/security/nss/lib/freebl/tlsprfalg.c
new file mode 100644
index 0000000..4208ebc
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/tlsprfalg.c
@@ -0,0 +1,169 @@
+/* tlsprfalg.c - TLS Pseudo Random Function (PRF) implementation
+ *
+ * ***** 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 ***** */
+/* $Id: tlsprfalg.c,v 1.6 2008/11/18 19:48:24 rrelyea%redhat.com Exp $ */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "sechash.h"
+#include "alghmac.h"
+#include "blapi.h"
+
+
+#define PHASH_STATE_MAX_LEN SHA1_LENGTH
+
+/* TLS P_hash function */
+static SECStatus
+sftk_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, 
+	SECItem *seed, SECItem *result, PRBool isFIPS)
+{
+    unsigned char state[PHASH_STATE_MAX_LEN];
+    unsigned char outbuf[PHASH_STATE_MAX_LEN];
+    unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size;
+    unsigned int remaining;
+    unsigned char *res;
+    SECStatus status;
+    HMACContext *cx;
+    SECStatus rv = SECFailure;
+    const SECHashObject *hashObj = HASH_GetRawHashObject(hashType);
+
+    PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
+    PORT_Assert((seed != NULL) && (seed->data != NULL));
+    PORT_Assert((result != NULL) && (result->data != NULL));
+
+    remaining = result->len;
+    res = result->data;
+
+    if (label != NULL)
+	label_len = PORT_Strlen(label);
+
+    cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS);
+    if (cx == NULL)
+	goto loser;
+
+    /* initialize the state = A(1) = HMAC_hash(secret, seed) */
+    HMAC_Begin(cx);
+    HMAC_Update(cx, (unsigned char *)label, label_len);
+    HMAC_Update(cx, seed->data, seed->len);
+    status = HMAC_Finish(cx, state, &state_len, sizeof(state));
+    if (status != SECSuccess)
+	goto loser;
+
+    /* generate a block at a time until we're done */
+    while (remaining > 0) {
+
+	HMAC_Begin(cx);
+	HMAC_Update(cx, state, state_len);
+	if (label_len)
+	    HMAC_Update(cx, (unsigned char *)label, label_len);
+	HMAC_Update(cx, seed->data, seed->len);
+	status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf));
+	if (status != SECSuccess)
+	    goto loser;
+
+        /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */
+	HMAC_Begin(cx); 
+	HMAC_Update(cx, state, state_len); 
+	status = HMAC_Finish(cx, state, &state_len, sizeof(state));
+	if (status != SECSuccess)
+	    goto loser;
+
+	chunk_size = PR_MIN(outbuf_len, remaining);
+	PORT_Memcpy(res, &outbuf, chunk_size);
+	res += chunk_size;
+	remaining -= chunk_size;
+    }
+
+    rv = SECSuccess;
+
+loser:
+    /* clear out state so it's not left on the stack */
+    if (cx) 
+    	HMAC_Destroy(cx, PR_TRUE);
+    PORT_Memset(state, 0, sizeof(state));
+    PORT_Memset(outbuf, 0, sizeof(outbuf));
+    return rv;
+}
+
+SECStatus
+TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, 
+         SECItem *result, PRBool isFIPS)
+{
+    SECStatus rv = SECFailure, status;
+    unsigned int i;
+    SECItem tmp = { siBuffer, NULL, 0};
+    SECItem S1;
+    SECItem S2;
+
+    PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
+    PORT_Assert((seed != NULL) && (seed->data != NULL));
+    PORT_Assert((result != NULL) && (result->data != NULL));
+
+    S1.type = siBuffer;
+    S1.len  = (secret->len / 2) + (secret->len & 1);
+    S1.data = secret->data;
+
+    S2.type = siBuffer;
+    S2.len  = S1.len;
+    S2.data = secret->data + (secret->len - S2.len);
+
+    tmp.data = (unsigned char*)PORT_Alloc(result->len);
+    if (tmp.data == NULL)
+	goto loser;
+    tmp.len = result->len;
+
+    status = sftk_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS);
+    if (status != SECSuccess)
+	goto loser;
+
+    status = sftk_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS);
+    if (status != SECSuccess)
+	goto loser;
+
+    for (i = 0; i < result->len; i++)
+	result->data[i] ^= tmp.data[i];
+
+    rv = SECSuccess;
+
+loser:
+    if (tmp.data != NULL)
+	PORT_ZFree(tmp.data, tmp.len);
+    return rv;
+}
+
diff --git a/mozilla/security/nss/lib/freebl/unix_rand.c b/mozilla/security/nss/lib/freebl/unix_rand.c
new file mode 100644
index 0000000..c8344b9
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/unix_rand.c
@@ -0,0 +1,1180 @@
+/* ***** 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 <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include "secrng.h"
+#include "secerr.h"
+#include "prerror.h"
+#include "prthread.h"
+#include "prprf.h"
+
+size_t RNG_FileUpdate(const char *fileName, size_t limit);
+
+/*
+ * When copying data to the buffer we want the least signicant bytes
+ * from the input since those bits are changing the fastest. The address
+ * of least significant byte depends upon whether we are running on
+ * a big-endian or little-endian machine.
+ *
+ * Does this mean the least signicant bytes are the most significant
+ * to us? :-)
+ */
+    
+static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
+{
+    union endianness {
+	int32 i;
+	char c[4];
+    } u;
+
+    if (srclen <= dstlen) {
+	memcpy(dst, src, srclen);
+	return srclen;
+    }
+    u.i = 0x01020304;
+    if (u.c[0] == 0x01) {
+	/* big-endian case */
+	memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
+    } else {
+	/* little-endian case */
+	memcpy(dst, src, dstlen);
+    }
+    return dstlen;
+}
+
+#ifdef SOLARIS
+
+#include <kstat.h>
+
+static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
+
+/* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
+ * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
+ * by the number of bytes successfully buffered.
+ */
+static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen,
+                                char* entropy_buf, PRUint32* entropy_buffered,
+                                PRUint32* total_fed)
+{
+    PRUint32 tocopy = 0;
+    PRUint32 avail = 0;
+    SECStatus rv = SECSuccess;
+
+    while (inlen) {
+        avail = entropy_buf_len - *entropy_buffered;
+        if (!avail) {
+            /* Buffer is full, time to feed it to the RNG. */
+            rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
+            if (SECSuccess != rv) {
+                break;
+            }
+            *entropy_buffered = 0;
+            avail = entropy_buf_len;
+        }
+        tocopy = PR_MIN(avail, inlen);
+        memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
+        *entropy_buffered += tocopy;
+        inlen -= tocopy;
+        inbuf += tocopy;
+        *total_fed += tocopy;
+    }
+    return rv;
+}
+
+/* Feed kernel statistics structures and ks_data field to the RNG.
+ * Returns status as well as the number of bytes successfully fed to the RNG.
+ */
+static SECStatus RNG_kstat(PRUint32* fed)
+{
+    kstat_ctl_t*    kc = NULL;
+    kstat_t*        ksp = NULL;
+    PRUint32        entropy_buffered = 0;
+    char*           entropy_buf = NULL;
+    SECStatus       rv = SECSuccess;
+
+    PORT_Assert(fed);
+    if (!fed) {
+        return SECFailure;
+    }
+    *fed = 0;
+
+    kc = kstat_open();
+    PORT_Assert(kc);
+    if (!kc) {
+        return SECFailure;
+    }
+    entropy_buf = (char*) PORT_Alloc(entropy_buf_len);
+    PORT_Assert(entropy_buf);
+    if (entropy_buf) {
+        for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
+            if (-1 == kstat_read(kc, ksp, NULL)) {
+                /* missing data from a single kstat shouldn't be fatal */
+                continue;
+            }
+            rv = BufferEntropy((char*)ksp, sizeof(kstat_t),
+                                    entropy_buf, &entropy_buffered,
+                                    fed);
+            if (SECSuccess != rv) {
+                break;
+            }
+
+            if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) {
+                rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size,
+                                        entropy_buf, &entropy_buffered,
+                                        fed);
+                if (SECSuccess != rv) {
+                    break;
+                }
+            }
+        }
+        if (SECSuccess == rv && entropy_buffered) {
+            /* Buffer is not empty, time to feed it to the RNG */
+            rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
+        }
+        PORT_Free(entropy_buf);
+    } else {
+        rv = SECFailure;
+    }
+    if (kstat_close(kc)) {
+        PORT_Assert(0);
+        rv = SECFailure;
+    }
+    return rv;
+}
+
+#endif
+
+#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
+    || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \
+    || defined(NTO) || defined(__riscos__)
+#include <sys/times.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    int ticks;
+    struct tms buffer;
+
+    ticks=times(&buffer);
+    return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
+}
+
+static void
+GiveSystemInfo(void)
+{
+    long si;
+
+    /* 
+     * Is this really necessary?  Why not use rand48 or something?
+     */
+    si = sysconf(_SC_CHILD_MAX);
+    RNG_RandomUpdate(&si, sizeof(si));
+
+    si = sysconf(_SC_STREAM_MAX);
+    RNG_RandomUpdate(&si, sizeof(si));
+
+    si = sysconf(_SC_OPEN_MAX);
+    RNG_RandomUpdate(&si, sizeof(si));
+}
+#endif
+
+#if defined(__sun)
+#if defined(__svr4) || defined(SVR4)
+#include <sys/systeminfo.h>
+#include <sys/times.h>
+#include <wait.h>
+
+int gettimeofday(struct timeval *);
+int gethostname(char *, int);
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static void
+GiveSystemInfo(void)
+{
+    int rv;
+    char buf[2000];
+
+    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+}
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    hrtime_t t;
+    t = gethrtime();
+    if (t) {
+	return CopyLowBits(buf, maxbytes, &t, sizeof(t));
+    }
+    return 0;
+}
+#else /* SunOS (Sun, but not SVR4) */
+
+extern long sysconf(int name);
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+    long si;
+
+    /* This is not very good */
+    si = sysconf(_SC_CHILD_MAX);
+    RNG_RandomUpdate(&si, sizeof(si));
+}
+#endif
+#endif /* Sun */
+
+#if defined(__hpux)
+#include <sys/unistd.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+#if defined(__ia64)
+#include <ia64/sys/inline.h>
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    PRUint64 t;
+
+    t = _Asm_mov_from_ar(_AREG44);
+    return CopyLowBits(buf, maxbytes, &t, sizeof(t));
+}
+#else
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    extern int ret_cr16();
+    int cr16val;
+
+    cr16val = ret_cr16();
+    return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
+}
+#endif
+
+static void
+GiveSystemInfo(void)
+{
+    long si;
+
+    /* This is not very good */
+    si = sysconf(_AES_OS_VERSION);
+    RNG_RandomUpdate(&si, sizeof(si));
+    si = sysconf(_SC_CPU_VERSION);
+    RNG_RandomUpdate(&si, sizeof(si));
+}
+#endif /* HPUX */
+
+#if defined(OSF1)
+#include <sys/types.h>
+#include <sys/sysinfo.h>
+#include <sys/systeminfo.h>
+#include <c_asm.h>
+
+static void
+GiveSystemInfo(void)
+{
+    char buf[BUFSIZ];
+    int rv;
+    int off = 0;
+
+    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+}
+
+/*
+ * Use the "get the cycle counter" instruction on the alpha.
+ * The low 32 bits completely turn over in less than a minute.
+ * The high 32 bits are some non-counter gunk that changes sometimes.
+ */
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    unsigned long t;
+
+    t = asm("rpcc %v0");
+    return CopyLowBits(buf, maxbytes, &t, sizeof(t));
+}
+
+#endif /* Alpha */
+
+#if defined(_IBMR2)
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+    /* XXX haven't found any yet! */
+}
+#endif /* IBM R2 */
+
+#if defined(LINUX)
+#include <sys/sysinfo.h>
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+    struct sysinfo si;
+    if (sysinfo(&si) == 0) {
+	RNG_RandomUpdate(&si, sizeof(si));
+    }
+}
+#endif /* LINUX */
+
+#if defined(NCR)
+
+#include <sys/utsname.h>
+#include <sys/systeminfo.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+    int rv;
+    char buf[2000];
+
+    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+}
+
+#endif /* NCR */
+
+#if defined(sgi)
+#include <fcntl.h>
+#undef PRIVATE
+#include <sys/mman.h>
+#include <sys/syssgi.h>
+#include <sys/immu.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <wait.h>
+
+static void
+GiveSystemInfo(void)
+{
+    int rv;
+    char buf[4096];
+
+    rv = syssgi(SGI_SYSID, &buf[0]);
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, MAXSYSIDSIZE);
+    }
+#ifdef SGI_RDUBLK
+    rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, sizeof(buf));
+    }
+#endif /* SGI_RDUBLK */
+    rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, sizeof(buf));
+    }
+    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+}
+
+static size_t GetHighResClock(void *buf, size_t maxbuf)
+{
+    unsigned phys_addr, raddr, cycleval;
+    static volatile unsigned *iotimer_addr = NULL;
+    static int tries = 0;
+    static int cntr_size;
+    int mfd;
+    long s0[2];
+    struct timeval tv;
+
+#ifndef SGI_CYCLECNTR_SIZE
+#define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
+#endif
+
+    if (iotimer_addr == NULL) {
+	if (tries++ > 1) {
+	    /* Don't keep trying if it didn't work */
+	    return 0;
+	}
+
+	/*
+	** For SGI machines we can use the cycle counter, if it has one,
+	** to generate some truly random numbers
+	*/
+	phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
+	if (phys_addr) {
+	    int pgsz = getpagesize();
+	    int pgoffmask = pgsz - 1;
+
+	    raddr = phys_addr & ~pgoffmask;
+	    mfd = open("/dev/mmem", O_RDONLY);
+	    if (mfd < 0) {
+		return 0;
+	    }
+	    iotimer_addr = (unsigned *)
+		mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
+	    if (iotimer_addr == (void*)-1) {
+		close(mfd);
+		iotimer_addr = NULL;
+		return 0;
+	    }
+	    iotimer_addr = (unsigned*)
+		((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
+	    /*
+	     * The file 'mfd' is purposefully not closed.
+	     */
+	    cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
+	    if (cntr_size < 0) {
+		struct utsname utsinfo;
+
+		/* 
+		 * We must be executing on a 6.0 or earlier system, since the
+		 * SGI_CYCLECNTR_SIZE call is not supported.
+		 * 
+		 * The only pre-6.1 platforms with 64-bit counters are
+		 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
+		 */
+		uname(&utsinfo);
+		if (!strncmp(utsinfo.machine, "IP19", 4) ||
+		    !strncmp(utsinfo.machine, "IP21", 4))
+			cntr_size = 64;
+		else
+			cntr_size = 32;
+	    }
+	    cntr_size /= 8;	/* Convert from bits to bytes */
+	}
+    }
+
+    s0[0] = *iotimer_addr;
+    if (cntr_size > 4)
+	s0[1] = *(iotimer_addr + 1);
+    memcpy(buf, (char *)&s0[0], cntr_size);
+    return CopyLowBits(buf, maxbuf, &s0, cntr_size);
+}
+#endif
+
+#if defined(sony)
+#include <sys/systeminfo.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+    int rv;
+    char buf[2000];
+
+    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+}
+#endif /* sony */
+
+#if defined(sinix)
+#include <sys/systeminfo.h>
+#include <sys/times.h>
+
+int gettimeofday(struct timeval *, struct timezone *);
+int gethostname(char *, int);
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    int ticks;
+    struct tms buffer;
+
+    ticks=times(&buffer);
+    return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
+}
+
+static void
+GiveSystemInfo(void)
+{
+    int rv;
+    char buf[2000];
+
+    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+}
+#endif /* sinix */
+
+
+#ifdef BEOS
+#include <be/kernel/OS.h>
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    bigtime_t bigtime; /* Actually an int64 */
+
+    bigtime = real_time_clock_usecs();
+    return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime));
+}
+
+static void
+GiveSystemInfo(void)
+{
+    system_info *info = NULL;
+    int32 val;                     
+    get_system_info(info);
+    if (info) {
+        val = info->boot_time;
+        RNG_RandomUpdate(&val, sizeof(val));
+        val = info->used_pages;
+        RNG_RandomUpdate(&val, sizeof(val));
+        val = info->used_ports;
+        RNG_RandomUpdate(&val, sizeof(val));
+        val = info->used_threads;
+        RNG_RandomUpdate(&val, sizeof(val));
+        val = info->used_teams;
+        RNG_RandomUpdate(&val, sizeof(val));
+    }
+}
+#endif /* BEOS */
+
+#if defined(nec_ews)
+#include <sys/systeminfo.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+    return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+    int rv;
+    char buf[2000];
+
+    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+    if (rv > 0) {
+	RNG_RandomUpdate(buf, rv);
+    }
+}
+#endif /* nec_ews */
+
+size_t RNG_GetNoise(void *buf, size_t maxbytes)
+{
+    struct timeval tv;
+    int n = 0;
+    int c;
+
+    n = GetHighResClock(buf, maxbytes);
+    maxbytes -= n;
+
+#if defined(__sun) && (defined(_svr4) || defined(SVR4)) || defined(sony)
+    (void)gettimeofday(&tv);
+#else
+    (void)gettimeofday(&tv, 0);
+#endif
+    c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
+    n += c;
+    maxbytes -= c;
+    c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
+    n += c;
+    return n;
+}
+
+#define SAFE_POPEN_MAXARGS	10	/* must be at least 2 */
+
+/*
+ * safe_popen is static to this module and we know what arguments it is
+ * called with. Note that this version only supports a single open child
+ * process at any time.
+ */
+static pid_t safe_popen_pid;
+static struct sigaction oldact;
+
+static FILE *
+safe_popen(char *cmd)
+{
+    int p[2], fd, argc;
+    pid_t pid;
+    char *argv[SAFE_POPEN_MAXARGS + 1];
+    FILE *fp;
+    static char blank[] = " \t";
+    static struct sigaction newact;
+
+    if (pipe(p) < 0)
+	return 0;
+
+    fp = fdopen(p[0], "r");
+    if (fp == 0) {
+	close(p[0]);
+	close(p[1]);
+	return 0;
+    }
+
+    /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
+    newact.sa_handler = SIG_DFL;
+    newact.sa_flags = 0;
+    sigfillset(&newact.sa_mask);
+    sigaction (SIGCHLD, &newact, &oldact);
+
+    pid = fork();
+    switch (pid) {
+      int ndesc;
+
+      case -1:
+	fclose(fp); /* this closes p[0], the fd associated with fp */
+	close(p[1]);
+	sigaction (SIGCHLD, &oldact, NULL);
+	return 0;
+
+      case 0:
+	/* dup write-side of pipe to stderr and stdout */
+	if (p[1] != 1) dup2(p[1], 1);
+	if (p[1] != 2) dup2(p[1], 2);
+
+	/* 
+	 * close the other file descriptors, except stdin which we
+	 * try reassociating with /dev/null, first (bug 174993)
+	 */
+	if (!freopen("/dev/null", "r", stdin))
+	    close(0);
+	ndesc = getdtablesize();
+	for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd));
+
+	/* clean up environment in the child process */
+	putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
+	putenv("SHELL=/bin/sh");
+	putenv("IFS= \t");
+
+	/*
+	 * The caller may have passed us a string that is in text
+	 * space. It may be illegal to modify the string
+	 */
+	cmd = strdup(cmd);
+	/* format argv */
+	argv[0] = strtok(cmd, blank);
+	argc = 1;
+	while ((argv[argc] = strtok(0, blank)) != 0) {
+	    if (++argc == SAFE_POPEN_MAXARGS) {
+		argv[argc] = 0;
+		break;
+	    }
+	}
+
+	/* and away we go */
+	execvp(argv[0], argv);
+	exit(127);
+	break;
+
+      default:
+	close(p[1]);
+	break;
+    }
+
+    /* non-zero means there's a cmd running */
+    safe_popen_pid = pid;
+    return fp;
+}
+
+static int
+safe_pclose(FILE *fp)
+{
+    pid_t pid;
+    int status = -1, rv;
+
+    if ((pid = safe_popen_pid) == 0)
+	return -1;
+    safe_popen_pid = 0;
+
+    fclose(fp);
+
+    /* yield the processor so the child gets some time to exit normally */
+    PR_Sleep(PR_INTERVAL_NO_WAIT);
+
+    /* if the child hasn't exited, kill it -- we're done with its output */
+    while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR)
+	;
+    if (rv == 0) {
+	kill(pid, SIGKILL);
+	while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
+	    ;
+    }
+
+    /* Reset SIGCHLD signal hander before returning */
+    sigaction(SIGCHLD, &oldact, NULL);
+
+    return status;
+}
+
+#ifdef DARWIN
+#include <crt_externs.h>
+#endif
+
+/* Fork netstat to collect its output by default. Do not unset this unless
+ * another source of entropy is available
+ */
+#define DO_NETSTAT 1
+
+void RNG_SystemInfoForRNG(void)
+{
+    FILE *fp;
+    char buf[BUFSIZ];
+    size_t bytes;
+    const char * const *cp;
+    char *randfile;
+#ifdef DARWIN
+    char **environ = *_NSGetEnviron();
+#else
+    extern char **environ;
+#endif
+#ifdef BEOS
+    static const char * const files[] = {
+	"/boot/var/swap",
+	"/boot/var/log/syslog",
+	"/boot/var/tmp",
+	"/boot/home/config/settings",
+	"/boot/home",
+	0
+    };
+#else
+    static const char * const files[] = {
+	"/etc/passwd",
+	"/etc/utmp",
+	"/tmp",
+	"/var/tmp",
+	"/usr/tmp",
+	0
+    };
+#endif
+
+#if defined(BSDI)
+    static char netstat_ni_cmd[] = "netstat -nis";
+#else
+    static char netstat_ni_cmd[] = "netstat -ni";
+#endif
+
+    GiveSystemInfo();
+
+    bytes = RNG_GetNoise(buf, sizeof(buf));
+    RNG_RandomUpdate(buf, bytes);
+
+    /*
+     * Pass the C environment and the addresses of the pointers to the
+     * hash function. This makes the random number function depend on the
+     * execution environment of the user and on the platform the program
+     * is running on.
+     */
+    if (environ != NULL) {
+        cp = (const char * const *) environ;
+        while (*cp) {
+	    RNG_RandomUpdate(*cp, strlen(*cp));
+	    cp++;
+        }
+        RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
+    }
+
+    /* Give in system information */
+    if (gethostname(buf, sizeof(buf)) == 0) {
+	RNG_RandomUpdate(buf, strlen(buf));
+    }
+    GiveSystemInfo();
+
+    /* grab some data from system's PRNG before any other files. */
+    bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
+
+    /* If the user points us to a random file, pass it through the rng */
+    randfile = getenv("NSRANDFILE");
+    if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
+	char *randCountString = getenv("NSRANDCOUNT");
+	int randCount = randCountString ? atoi(randCountString) : 0;
+	if (randCount != 0) {
+	    RNG_FileUpdate(randfile, randCount);
+	} else {
+	    RNG_FileForRNG(randfile);
+	}
+    }
+
+    /* pass other files through */
+    for (cp = files; *cp; cp++)
+	RNG_FileForRNG(*cp);
+
+/*
+ * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
+ * in a pthreads environment.  Therefore, we call safe_popen last and on
+ * BSD/OS we do not call safe_popen when we succeeded in getting data
+ * from /dev/urandom.
+ *
+ * Bug 174993: LINUX provides /dev/urandom, don't fork netstat
+ * if data has been gathered successfully
+ */
+
+#if defined(BSDI) || defined(LINUX)
+    if (bytes)
+        return;
+#endif
+
+#ifdef SOLARIS
+
+/*
+ * On Solaris, NSS may be initialized automatically from libldap in
+ * applications that are unaware of the use of NSS. safe_popen forks, and
+ * sometimes creates issues with some applications' pthread_atfork handlers.
+ * We always have /dev/urandom on Solaris 9 and above as an entropy source,
+ * and for Solaris 8 we have the libkstat interface, so we don't need to
+ * fork netstat.
+ */
+
+#undef DO_NETSTAT
+    if (!bytes) {
+        /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
+        PRUint32 kstat_bytes = 0;
+        if (SECSuccess != RNG_kstat(&kstat_bytes)) {
+            PORT_Assert(0);
+        }
+        bytes += kstat_bytes;
+        PORT_Assert(bytes);
+    }
+#endif
+
+#ifdef DO_NETSTAT
+    fp = safe_popen(netstat_ni_cmd);
+    if (fp != NULL) {
+	while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
+	    RNG_RandomUpdate(buf, bytes);
+	safe_pclose(fp);
+    }
+#endif
+
+}
+
+#define TOTAL_FILE_LIMIT 1000000	/* one million */
+
+size_t RNG_FileUpdate(const char *fileName, size_t limit)
+{
+    FILE *        file;
+    size_t        bytes;
+    size_t        fileBytes = 0;
+    struct stat   stat_buf;
+    unsigned char buffer[BUFSIZ];
+    static size_t totalFileBytes = 0;
+    
+    /* suppress valgrind warnings due to holes in struct stat */
+    memset(&stat_buf, 0, sizeof(stat_buf));
+
+    if (stat((char *)fileName, &stat_buf) < 0)
+	return fileBytes;
+    RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
+    
+    file = fopen((char *)fileName, "r");
+    if (file != NULL) {
+	while (limit > fileBytes) {
+	    bytes = PR_MIN(sizeof buffer, limit - fileBytes);
+	    bytes = fread(buffer, 1, bytes, file);
+	    if (bytes == 0) 
+		break;
+	    RNG_RandomUpdate(buffer, bytes);
+	    fileBytes      += bytes;
+	    totalFileBytes += bytes;
+	    /* after TOTAL_FILE_LIMIT has been reached, only read in first
+	    ** buffer of data from each subsequent file.
+	    */
+	    if (totalFileBytes > TOTAL_FILE_LIMIT) 
+		break;
+	}
+	fclose(file);
+    }
+    /*
+     * Pass yet another snapshot of our highest resolution clock into
+     * the hash function.
+     */
+    bytes = RNG_GetNoise(buffer, sizeof(buffer));
+    RNG_RandomUpdate(buffer, bytes);
+    return fileBytes;
+}
+
+void RNG_FileForRNG(const char *fileName)
+{
+    RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
+}
+
+void ReadSingleFile(const char *fileName)
+{
+    FILE *        file;
+    unsigned char buffer[BUFSIZ];
+    
+    file = fopen((char *)fileName, "rb");
+    if (file != NULL) {
+	while (fread(buffer, 1, sizeof(buffer), file) > 0)
+	    ;
+	fclose(file);
+    } 
+}
+
+#define _POSIX_PTHREAD_SEMANTICS
+#include <dirent.h>
+
+PRBool
+ReadFileOK(char *dir, char *file)
+{
+    struct stat   stat_buf;
+    char filename[PATH_MAX];
+    int count = snprintf(filename, sizeof filename, "%s/%s",dir, file);
+
+    if (count <= 0) {
+	return PR_FALSE; /* name too long, can't read it anyway */
+    }
+    
+    if (stat(filename, &stat_buf) < 0)
+	return PR_FALSE; /* can't stat, probably can't read it then as well */
+    return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
+}
+
+/*
+ * read one file out of either /etc or the user's home directory.
+ * fileToRead tells which file to read.
+ *
+ * return 1 if it's time to reset the fileToRead (no more files to read).
+ */
+int ReadOneFile(int fileToRead)
+{
+    char *dir = "/etc";
+    DIR *fd = opendir(dir);
+    int resetCount = 0;
+#ifdef SOLARIS
+     /* grumble, Solaris does not define struct dirent to be the full length */
+    typedef union {
+	unsigned char space[sizeof(struct dirent) + MAXNAMELEN];
+	struct dirent dir;
+    } dirent_hack;
+    dirent_hack entry, firstEntry;
+
+#define entry_dir entry.dir
+#else
+    struct dirent entry, firstEntry;
+#define entry_dir entry
+#endif
+
+    int i, error = -1;
+
+    if (fd == NULL) {
+	dir = getenv("HOME");
+	if (dir) {
+	    fd = opendir(dir);
+	}
+    }
+    if (fd == NULL) {
+	return 1;
+    }
+
+    for (i=0; i <= fileToRead; i++) {
+	struct dirent *result = NULL;
+	do {
+	    error = readdir_r(fd, &entry_dir, &result);
+	} while (error == 0 && result != NULL  &&
+					!ReadFileOK(dir,&result->d_name[0]));
+	if (error != 0 || result == NULL)  {
+	    resetCount = 1; /* read to the end, start again at the beginning */
+	    if (i != 0) {
+		/* ran out of entries in the directory, use the first one */
+	 	entry = firstEntry;
+	 	error = 0;
+	 	break;
+	    }
+	    /* if i== 0, there were no readable entries in the directory */
+	    break;
+	}
+	if (i==0) {
+	    /* save the first entry in case we run out of entries */
+	    firstEntry = entry;
+	}
+    }
+
+    if (error == 0) {
+	char filename[PATH_MAX];
+	int count = snprintf(filename, sizeof filename, 
+				"%s/%s",dir, &entry_dir.d_name[0]);
+	if (count >= 1) {
+	    ReadSingleFile(filename);
+	}
+    } 
+
+    closedir(fd);
+    return resetCount;
+}
+
+/*
+ * do something to try to introduce more noise into the 'GetNoise' call
+ */
+static void rng_systemJitter(void)
+{
+   static int fileToRead = 1;
+
+   if (ReadOneFile(fileToRead)) {
+	fileToRead = 1;
+   } else {
+	fileToRead++;
+   }
+}
+
+size_t RNG_SystemRNG(void *dest, size_t maxLen)
+{
+    FILE *file;
+    size_t bytes;
+    size_t fileBytes = 0;
+    unsigned char *buffer = dest;
+
+    file = fopen("/dev/urandom", "r");
+    if (file == NULL) {
+	return rng_systemFromNoise(dest, maxLen);
+    }
+    while (maxLen > fileBytes) {
+	bytes = maxLen - fileBytes;
+	bytes = fread(buffer, 1, bytes, file);
+	if (bytes == 0) 
+	    break;
+	fileBytes += bytes;
+	buffer += bytes;
+    }
+    fclose(file);
+    if (fileBytes != maxLen) {
+	PORT_SetError(SEC_ERROR_NEED_RANDOM);  /* system RNG failed */
+	fileBytes = 0;
+    }
+    return fileBytes;
+}
diff --git a/mozilla/security/nss/lib/freebl/win_rand.c b/mozilla/security/nss/lib/freebl/win_rand.c
new file mode 100644
index 0000000..1847988
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/win_rand.c
@@ -0,0 +1,577 @@
+/* ***** 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 "secrng.h"
+#include "secerr.h"
+
+#ifdef XP_WIN
+#include <windows.h>
+#include <shlobj.h>     /* for CSIDL constants */
+
+#if defined(_WIN32_WCE)
+#include <stdlib.h>	/* Win CE puts lots of stuff here. */
+#include "prprf.h"	/* for PR_snprintf */
+#else
+#include <time.h>
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+#include <stdio.h>
+#include "prio.h"
+#include "prerror.h"
+
+static PRInt32  filesToRead;
+static DWORD    totalFileBytes;
+static DWORD    maxFileBytes	= 250000;	/* 250 thousand */
+static DWORD    dwNumFiles, dwReadEvery, dwFileToRead;
+static PRBool   usedWindowsPRNG;
+
+static BOOL
+CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow)
+{
+    LARGE_INTEGER   liCount;
+
+    if (!QueryPerformanceCounter(&liCount))
+        return FALSE;
+
+    *lpdwHigh = liCount.u.HighPart;
+    *lpdwLow = liCount.u.LowPart;
+    return TRUE;
+}
+
+size_t RNG_GetNoise(void *buf, size_t maxbuf)
+{
+    DWORD   dwHigh, dwLow, dwVal;
+    int     n = 0;
+    int     nBytes;
+
+    if (maxbuf <= 0)
+        return 0;
+
+    CurrentClockTickTime(&dwHigh, &dwLow);
+
+    // get the maximally changing bits first
+    nBytes = sizeof(dwLow) > maxbuf ? maxbuf : sizeof(dwLow);
+    memcpy((char *)buf, &dwLow, nBytes);
+    n += nBytes;
+    maxbuf -= nBytes;
+
+    if (maxbuf <= 0)
+        return n;
+
+    nBytes = sizeof(dwHigh) > maxbuf ? maxbuf : sizeof(dwHigh);
+    memcpy(((char *)buf) + n, &dwHigh, nBytes);
+    n += nBytes;
+    maxbuf -= nBytes;
+
+    if (maxbuf <= 0)
+        return n;
+
+    // get the number of milliseconds that have elapsed since Windows started
+    dwVal = GetTickCount();
+
+    nBytes = sizeof(dwVal) > maxbuf ? maxbuf : sizeof(dwVal);
+    memcpy(((char *)buf) + n, &dwVal, nBytes);
+    n += nBytes;
+    maxbuf -= nBytes;
+
+    if (maxbuf <= 0)
+        return n;
+
+    {
+#if defined(_WIN32_WCE)
+    // get the number of milliseconds elapsed since Windows CE was started. 
+    FILETIME sTime;
+    SYSTEMTIME st;
+    GetSystemTime(&st);
+    SystemTimeToFileTime(&st,&sTime);
+#else
+    time_t  sTime;
+    // get the time in seconds since midnight Jan 1, 1970
+    time(&sTime);
+#endif
+    nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime);
+    memcpy(((char *)buf) + n, &sTime, nBytes);
+    n += nBytes;
+    }
+
+    return n;
+}
+
+typedef PRInt32 (* Handler)(const PRUnichar *);
+#define MAX_DEPTH 2
+#define MAX_FOLDERS 4
+#define MAX_FILES 1024
+
+static void
+EnumSystemFilesInFolder(Handler func, PRUnichar* szSysDir, int maxDepth) 
+{
+    int                 iContinue;
+    unsigned int        uFolders  = 0;
+    unsigned int        uFiles    = 0;
+    HANDLE              lFindHandle;
+    WIN32_FIND_DATAW    fdData;
+    PRUnichar           szFileName[_MAX_PATH];
+
+    if (maxDepth < 0)
+    	return;
+    // append *.* so we actually look for files.
+    _snwprintf(szFileName, _MAX_PATH, L"%s\\*.*", szSysDir);
+
+    lFindHandle = FindFirstFileW(szFileName, &fdData);
+    if (lFindHandle == INVALID_HANDLE_VALUE)
+        return;
+    do {
+	iContinue = 1;
+	if (wcscmp(fdData.cFileName, L".") == 0 ||
+            wcscmp(fdData.cFileName, L"..") == 0) {
+	    // skip "." and ".."
+	} else {
+	    // pass the full pathname to the callback
+	    _snwprintf(szFileName, _MAX_PATH, L"%s\\%s", szSysDir, 
+		       fdData.cFileName);
+	    if (fdData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+		if (++uFolders <= MAX_FOLDERS)
+		    EnumSystemFilesInFolder(func, szFileName, maxDepth - 1);
+	    } else {
+		iContinue = (++uFiles <= MAX_FILES) && !(*func)(szFileName);
+	    }
+	}
+	if (iContinue)
+	    iContinue = FindNextFileW(lFindHandle, &fdData);
+    } while (iContinue);
+    FindClose(lFindHandle);
+}
+
+static BOOL
+EnumSystemFiles(Handler func)
+{
+    PRUnichar szSysDir[_MAX_PATH];
+    static const int folders[] = {
+    	CSIDL_BITBUCKET,  
+	CSIDL_RECENT,
+#ifndef WINCE		     
+	CSIDL_INTERNET_CACHE, 
+	CSIDL_HISTORY,
+#endif
+	0
+    };
+    int i = 0;
+    if (_MAX_PATH > (i = GetTempPathW(_MAX_PATH, szSysDir))) {
+        if (i > 0 && szSysDir[i-1] == L'\\')
+	    szSysDir[i-1] = L'\0'; // we need to lop off the trailing slash
+        EnumSystemFilesInFolder(func, szSysDir, MAX_DEPTH);
+    }
+    for(i = 0; folders[i]; i++) {
+        DWORD rv = SHGetSpecialFolderPathW(NULL, szSysDir, folders[i], 0);
+        if (szSysDir[0])
+            EnumSystemFilesInFolder(func, szSysDir, MAX_DEPTH);
+        szSysDir[0] =  L'\0';
+    }
+    return PR_TRUE;
+}
+
+static PRInt32
+CountFiles(const PRUnichar *file)
+{
+    dwNumFiles++;
+    return 0;
+}
+
+static int
+ReadSingleFile(const char *filename)
+{
+    PRFileDesc *    file;
+    unsigned char   buffer[1024];
+
+    file = PR_Open(filename, PR_RDONLY, 0);
+    if (file != NULL) {
+	while (PR_Read(file, buffer, sizeof buffer) > 0)
+	    ;
+        PR_Close(file);
+    }
+    return (file != NULL);
+}
+
+static PRInt32
+ReadOneFile(const PRUnichar *szFileName)
+{
+    char narrowFileName[_MAX_PATH];
+
+    if (dwNumFiles == dwFileToRead) {
+	int success = WideCharToMultiByte(CP_ACP, 0, szFileName, -1, 
+					  narrowFileName, _MAX_PATH, 
+					  NULL, NULL);
+	if (success)
+	    success = ReadSingleFile(narrowFileName);
+    	if (!success)
+	    dwFileToRead++; /* couldn't read this one, read the next one. */
+    }
+    dwNumFiles++;
+    return dwNumFiles > dwFileToRead;
+}
+
+static PRInt32
+ReadFiles(const PRUnichar *szFileName)
+{
+    char narrowFileName[_MAX_PATH];
+
+    if ((dwNumFiles % dwReadEvery) == 0) {
+	++filesToRead;
+    }
+    if (filesToRead) {
+	DWORD prevFileBytes = totalFileBytes;
+	int   iContinue     = WideCharToMultiByte(CP_ACP, 0, szFileName, -1, 
+						  narrowFileName, _MAX_PATH, 
+						  NULL, NULL);
+	if (iContinue) {
+	    RNG_FileForRNG(narrowFileName);
+	}
+	if (prevFileBytes < totalFileBytes) {
+	    --filesToRead;
+	}
+    }
+    dwNumFiles++;
+    return (totalFileBytes >= maxFileBytes);
+}
+
+static void
+ReadSystemFiles(void)
+{
+    // first count the number of files
+    dwNumFiles = 0;
+    if (!EnumSystemFiles(CountFiles))
+        return;
+
+    RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles));
+
+    // now read the first 10 readable files, then 10 or 11 files
+    // spread throughout the system directory
+    filesToRead = 10;
+    if (dwNumFiles == 0)
+        return;
+
+    dwReadEvery = dwNumFiles / 10;
+    if (dwReadEvery == 0)
+        dwReadEvery = 1;  // less than 10 files
+
+    dwNumFiles = 0;
+    totalFileBytes = 0;
+    EnumSystemFiles(ReadFiles);
+}
+
+void RNG_SystemInfoForRNG(void)
+{
+    DWORD           dwVal;
+    char            buffer[256];
+    int             nBytes;
+    MEMORYSTATUS    sMem;
+    HANDLE          hVal;
+#if !defined(_WIN32_WCE)
+    DWORD           dwSerialNum;
+    DWORD           dwComponentLen;
+    DWORD           dwSysFlags;
+    char            volName[128];
+    DWORD           dwSectors, dwBytes, dwFreeClusters, dwNumClusters;
+#endif
+
+    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
+    RNG_RandomUpdate(buffer, nBytes);
+
+    sMem.dwLength = sizeof(sMem);
+    GlobalMemoryStatus(&sMem);                // assorted memory stats
+    RNG_RandomUpdate(&sMem, sizeof(sMem));
+#if !defined(_WIN32_WCE)
+    dwVal = GetLogicalDrives();
+    RNG_RandomUpdate(&dwVal, sizeof(dwVal));  // bitfields in bits 0-25
+#endif
+
+#if !defined(_WIN32_WCE)
+    dwVal = sizeof(buffer);
+    if (GetComputerName(buffer, &dwVal))
+        RNG_RandomUpdate(buffer, dwVal);
+#endif
+
+    hVal = GetCurrentProcess();               // 4 or 8 byte pseudo handle (a
+                                              // constant!) of current process
+    RNG_RandomUpdate(&hVal, sizeof(hVal));
+
+    dwVal = GetCurrentProcessId();            // process ID (4 bytes)
+    RNG_RandomUpdate(&dwVal, sizeof(dwVal));
+
+    dwVal = GetCurrentThreadId();             // thread ID (4 bytes)
+    RNG_RandomUpdate(&dwVal, sizeof(dwVal));
+
+#if !defined(_WIN32_WCE)
+    volName[0] = '\0';
+    buffer[0] = '\0';
+    GetVolumeInformation(NULL,
+                         volName,
+                         sizeof(volName),
+                         &dwSerialNum,
+                         &dwComponentLen,
+                         &dwSysFlags,
+                         buffer,
+                         sizeof(buffer));
+
+    RNG_RandomUpdate(volName,         strlen(volName));
+    RNG_RandomUpdate(&dwSerialNum,    sizeof(dwSerialNum));
+    RNG_RandomUpdate(&dwComponentLen, sizeof(dwComponentLen));
+    RNG_RandomUpdate(&dwSysFlags,     sizeof(dwSysFlags));
+    RNG_RandomUpdate(buffer,          strlen(buffer));
+
+    if (GetDiskFreeSpace(NULL, &dwSectors, &dwBytes, &dwFreeClusters, 
+                         &dwNumClusters)) {
+        RNG_RandomUpdate(&dwSectors,      sizeof(dwSectors));
+        RNG_RandomUpdate(&dwBytes,        sizeof(dwBytes));
+        RNG_RandomUpdate(&dwFreeClusters, sizeof(dwFreeClusters));
+        RNG_RandomUpdate(&dwNumClusters,  sizeof(dwNumClusters));
+    }
+#endif
+
+    // Skip the potentially slow file scanning if the OS's PRNG worked.
+    if (!usedWindowsPRNG)
+	ReadSystemFiles();
+
+    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
+    RNG_RandomUpdate(buffer, nBytes);
+}
+
+static void rng_systemJitter(void)
+{   
+    dwNumFiles = 0;
+    EnumSystemFiles(ReadOneFile);
+    dwFileToRead++;
+    if (dwFileToRead >= dwNumFiles) {
+	dwFileToRead = 0;
+    }
+}
+
+
+#if defined(_WIN32_WCE)
+void RNG_FileForRNG(const char *filename)
+{
+    PRFileDesc *    file;
+    int             nBytes;
+    PRFileInfo      infoBuf;
+    unsigned char   buffer[1024];
+
+    if (PR_GetFileInfo(filename, &infoBuf) != PR_SUCCESS)
+        return;
+
+    RNG_RandomUpdate((unsigned char*)&infoBuf, sizeof(infoBuf));
+
+    file = PR_Open(filename, PR_RDONLY, 0);
+    if (file != NULL) {
+        for (;;) {
+            PRInt32 bytes = PR_Read(file, buffer, sizeof buffer);
+
+            if (bytes <= 0)
+                break;
+
+            RNG_RandomUpdate(buffer, bytes);
+            totalFileBytes += bytes;
+            if (totalFileBytes > maxFileBytes)
+                break;
+        }
+
+        PR_Close(file);
+    }
+
+    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
+    RNG_RandomUpdate(buffer, nBytes);
+}
+
+/*
+ * The Windows CE and Windows Mobile FIPS Security Policy, page 13,
+ * (http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp825.pdf)
+ * says CeGenRandom is the right function to call for creating a seed
+ * for a random number generator.
+ */
+size_t RNG_SystemRNG(void *dest, size_t maxLen)
+{
+    size_t bytes = 0;
+    usedWindowsPRNG = PR_FALSE;
+    if (CeGenRandom(maxLen, dest)) {
+	bytes = maxLen;
+	usedWindowsPRNG = PR_TRUE;
+    }
+    if (bytes == 0) {
+	bytes = rng_systemFromNoise(dest,maxLen);
+    }
+    return bytes;
+}
+
+
+#else /* not WinCE */
+
+void RNG_FileForRNG(const char *filename)
+{
+    FILE*           file;
+    int             nBytes;
+    struct stat     stat_buf;
+    unsigned char   buffer[1024];
+
+    /* windows doesn't initialize all the bytes in the stat buf,
+     * so initialize them all here to avoid UMRs.
+     */
+    memset(&stat_buf, 0, sizeof stat_buf);
+
+    if (stat((char *)filename, &stat_buf) < 0)
+        return;
+
+    RNG_RandomUpdate((unsigned char*)&stat_buf, sizeof(stat_buf));
+
+    file = fopen((char *)filename, "r");
+    if (file != NULL) {
+        for (;;) {
+            size_t  bytes = fread(buffer, 1, sizeof(buffer), file);
+
+            if (bytes == 0)
+                break;
+
+            RNG_RandomUpdate(buffer, bytes);
+            totalFileBytes += bytes;
+            if (totalFileBytes > maxFileBytes)
+                break;
+        }
+
+        fclose(file);
+    }
+
+    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
+    RNG_RandomUpdate(buffer, nBytes);
+}
+
+
+/*
+ * CryptoAPI requires Windows NT 4.0 or Windows 95 OSR2 and later.
+ * Until we drop support for Windows 95, we need to emulate some
+ * definitions and declarations in <wincrypt.h> and look up the
+ * functions in advapi32.dll at run time.
+ */
+
+#ifndef WIN64
+typedef unsigned long HCRYPTPROV;
+#endif
+
+#define CRYPT_VERIFYCONTEXT 0xF0000000
+
+#define PROV_RSA_FULL 1
+
+typedef BOOL
+(WINAPI *CryptAcquireContextAFn)(
+    HCRYPTPROV *phProv,
+    LPCSTR pszContainer,
+    LPCSTR pszProvider,
+    DWORD dwProvType,
+    DWORD dwFlags);
+
+typedef BOOL
+(WINAPI *CryptReleaseContextFn)(
+    HCRYPTPROV hProv,
+    DWORD dwFlags);
+
+typedef BOOL
+(WINAPI *CryptGenRandomFn)(
+    HCRYPTPROV hProv,
+    DWORD dwLen,
+    BYTE *pbBuffer);
+
+/*
+ * Windows XP and Windows Server 2003 and later have RtlGenRandom,
+ * which must be looked up by the name SystemFunction036.
+ */
+typedef BOOLEAN
+(APIENTRY *RtlGenRandomFn)(
+    PVOID RandomBuffer,
+    ULONG RandomBufferLength);
+
+size_t RNG_SystemRNG(void *dest, size_t maxLen)
+{
+    HMODULE hModule;
+    RtlGenRandomFn pRtlGenRandom;
+    CryptAcquireContextAFn pCryptAcquireContextA;
+    CryptReleaseContextFn pCryptReleaseContext;
+    CryptGenRandomFn pCryptGenRandom;
+    HCRYPTPROV hCryptProv;
+    size_t bytes = 0;
+
+    usedWindowsPRNG = PR_FALSE;
+    hModule = LoadLibrary("advapi32.dll");
+    if (hModule == NULL) {
+	return rng_systemFromNoise(dest,maxLen);
+    }
+    pRtlGenRandom = (RtlGenRandomFn)
+	GetProcAddress(hModule, "SystemFunction036");
+    if (pRtlGenRandom) {
+	if (pRtlGenRandom(dest, maxLen)) {
+	    bytes = maxLen;
+	    usedWindowsPRNG = PR_TRUE;
+	} else {
+	    bytes = rng_systemFromNoise(dest,maxLen);
+	}
+	goto done;
+    }
+    pCryptAcquireContextA = (CryptAcquireContextAFn)
+	GetProcAddress(hModule, "CryptAcquireContextA");
+    pCryptReleaseContext = (CryptReleaseContextFn)
+	GetProcAddress(hModule, "CryptReleaseContext");
+    pCryptGenRandom = (CryptGenRandomFn)
+	GetProcAddress(hModule, "CryptGenRandom");
+    if (!pCryptAcquireContextA || !pCryptReleaseContext || !pCryptGenRandom) {
+	bytes = rng_systemFromNoise(dest,maxLen);
+	goto done;
+    }
+    if (pCryptAcquireContextA(&hCryptProv, NULL, NULL,
+	PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+	if (pCryptGenRandom(hCryptProv, maxLen, dest)) {
+	    bytes = maxLen;
+	    usedWindowsPRNG = PR_TRUE;
+	}
+	pCryptReleaseContext(hCryptProv, 0);
+    }
+    if (bytes == 0) {
+	bytes = rng_systemFromNoise(dest,maxLen);
+    }
+done:
+    FreeLibrary(hModule);
+    return bytes;
+}
+#endif  /* not WinCE */
+
+#endif  /* is XP_WIN */
diff --git a/mozilla/security/nss/lib/nss/nss.h b/mozilla/security/nss/lib/nss/nss.h
new file mode 100644
index 0000000..7de97ed
--- /dev/null
+++ b/mozilla/security/nss/lib/nss/nss.h
@@ -0,0 +1,352 @@
+/*
+ * NSS utility functions
+ *
+ * ***** 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 ***** */
+/* $Id: nss.h,v 1.74 2009/11/20 20:15:05 christophe.ravel.bugs%sun.com Exp $ */
+
+#ifndef __nss_h_
+#define __nss_h_
+
+/* The private macro _NSS_ECC_STRING is for NSS internal use only. */
+#ifdef NSS_ENABLE_ECC
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+#define _NSS_ECC_STRING " Extended ECC"
+#else
+#define _NSS_ECC_STRING " Basic ECC"
+#endif
+#else
+#define _NSS_ECC_STRING ""
+#endif
+
+/* The private macro _NSS_CUSTOMIZED is for NSS internal use only. */
+#if defined(NSS_ALLOW_UNSUPPORTED_CRITICAL)
+#define _NSS_CUSTOMIZED " (Customized build)"
+#else
+#define _NSS_CUSTOMIZED 
+#endif
+
+/*
+ * NSS's major version, minor version, patch level, build number, and whether
+ * this is a beta release.
+ *
+ * The format of the version string should be
+ *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
+ */
+#define NSS_VERSION  "3.12.6.0" _NSS_ECC_STRING _NSS_CUSTOMIZED " Beta"
+#define NSS_VMAJOR   3
+#define NSS_VMINOR   12
+#define NSS_VPATCH   6
+#define NSS_VBUILD   0
+#define NSS_BETA     PR_TRUE
+
+#ifndef RC_INVOKED
+
+#include "seccomon.h"
+
+typedef struct NSSInitParametersStr NSSInitParameters;
+
+/*
+ * parameters used to initialize softoken. Mostly strings used to 
+ * internationalize softoken. Memory for the strings are owned by the caller,
+ * who is free to free them once NSS_ContextInit returns. If the string 
+ * parameter is NULL (as opposed to empty, zero length), then the softoken
+ * default is used. These are equivalent to the parameters for 
+ * PK11_ConfigurePKCS11().
+ *
+ * field names match their equivalent parameter names for softoken strings 
+ * documented at https://developer.mozilla.org/en/PKCS11_Module_Specs.
+ * 
+ * minPWLen 
+ *     Minimum password length in bytes. 
+ * manufacturerID 
+ *     Override the default manufactureID value for the module returned in 
+ *     the CK_INFO, CK_SLOT_INFO, and CK_TOKEN_INFO structures with an 
+ *     internationalize string (UTF8). This value will be truncated at 32 
+ *     bytes (not including the trailing NULL, partial UTF8 characters will be
+ *     dropped). 
+ * libraryDescription 
+ *     Override the default libraryDescription value for the module returned in
+ *     the CK_INFO structure with an internationalize string (UTF8). This value
+ *     will be truncated at 32 bytes(not including the trailing NULL, partial 
+ *     UTF8 characters will be dropped). 
+ * cryptoTokenDescription 
+ *     Override the default label value for the internal crypto token returned
+ *     in the CK_TOKEN_INFO structure with an internationalize string (UTF8).
+ *     This value will be truncated at 32 bytes (not including the trailing
+ *     NULL, partial UTF8 characters will be dropped). 
+ * dbTokenDescription 
+ *     Override the default label value for the internal DB token returned in 
+ *     the CK_TOKEN_INFO structure with an internationalize string (UTF8). This
+ *     value will be truncated at 32 bytes (not including the trailing NULL,
+ *     partial UTF8 characters will be dropped). 
+ * FIPSTokenDescription 
+ *     Override the default label value for the internal FIPS token returned in
+ *     the CK_TOKEN_INFO structure with an internationalize string (UTF8). This
+ *     value will be truncated at 32 bytes (not including the trailing NULL,
+ *     partial UTF8 characters will be dropped). 
+ * cryptoSlotDescription 
+ *     Override the default slotDescription value for the internal crypto token
+ *     returned in the CK_SLOT_INFO structure with an internationalize string
+ *     (UTF8). This value will be truncated at 64 bytes (not including the
+ *     trailing NULL, partial UTF8 characters will be dropped). 
+ * dbSlotDescription 
+ *     Override the default slotDescription value for the internal DB token 
+ *     returned in the CK_SLOT_INFO structure with an internationalize string 
+ *     (UTF8). This value will be truncated at 64 bytes (not including the
+ *     trailing NULL, partial UTF8 characters will be dropped). 
+ * FIPSSlotDescription 
+ *     Override the default slotDecription value for the internal FIPS token
+ *     returned in the CK_SLOT_INFO structure with an internationalize string
+ *     (UTF8). This value will be truncated at 64 bytes (not including the
+ *     trailing NULL, partial UTF8 characters will be dropped). 
+ *
+ */
+struct NSSInitParametersStr {
+   unsigned int	  length;      /* allow this structure to grow in the future,
+				* must be set */
+   PRBool passwordRequired;
+   int    minPWLen;
+   char * manufactureID;           /* variable names for strings match the */
+   char * libraryDescription;      /*   parameter name in softoken */
+   char * cryptoTokenDescription;
+   char * dbTokenDescription;
+   char * FIPSTokenDescription;
+   char * cryptoSlotDescription;
+   char * dbSlotDescription;
+   char * FIPSSlotDescription;
+};
+   
+
+SEC_BEGIN_PROTOS
+
+/*
+ * Return a boolean that indicates whether the underlying library
+ * will perform as the caller expects.
+ *
+ * The only argument is a string, which should be the verson
+ * identifier of the NSS library. That string will be compared
+ * against a string that represents the actual build version of
+ * the NSS library.  It also invokes the version checking functions
+ * of the dependent libraries such as NSPR.
+ */
+extern PRBool NSS_VersionCheck(const char *importedVersion);
+
+/*
+ * Open the Cert, Key, and Security Module databases, read only.
+ * Initialize the Random Number Generator.
+ * Does not initialize the cipher policies or enables.
+ * Default policy settings disallow all ciphers.
+ */
+extern SECStatus NSS_Init(const char *configdir);
+
+/*
+ * Returns whether NSS has already been initialized or not.
+ */
+extern PRBool NSS_IsInitialized(void);
+
+/*
+ * Open the Cert, Key, and Security Module databases, read/write.
+ * Initialize the Random Number Generator.
+ * Does not initialize the cipher policies or enables.
+ * Default policy settings disallow all ciphers.
+ */
+extern SECStatus NSS_InitReadWrite(const char *configdir);
+
+/*
+ * Open the Cert, Key, and Security Module databases, read/write.
+ * Initialize the Random Number Generator.
+ * Does not initialize the cipher policies or enables.
+ * Default policy settings disallow all ciphers.
+ *
+ * This allows using application defined prefixes for the cert and key db's
+ * and an alternate name for the secmod database. NOTE: In future releases,
+ * the database prefixes my not necessarily map to database names.
+ *
+ * configdir - base directory where all the cert, key, and module datbases live.
+ * certPrefix - prefix added to the beginning of the cert database example: "
+ * 			"https-server1-"
+ * keyPrefix - prefix added to the beginning of the key database example: "
+ * 			"https-server1-"
+ * secmodName - name of the security module database (usually "secmod.db").
+ * flags - change the open options of NSS_Initialize as follows:
+ * 	NSS_INIT_READONLY - Open the databases read only.
+ * 	NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just 
+ * 			initialize the volatile certdb.
+ * 	NSS_INIT_NOMODDB  - Don't open the security module DB, just 
+ *			initialize the 	PKCS #11 module.
+ *      NSS_INIT_FORCEOPEN - Continue to force initializations even if the 
+ * 			databases cannot be opened.
+ *      NSS_INIT_NOROOTINIT - Don't try to look for the root certs module
+ *			automatically.
+ *      NSS_INIT_OPTIMIZESPACE - Use smaller tables and caches.
+ *      NSS_INIT_PK11THREADSAFE - only load PKCS#11 modules that are
+ *                      thread-safe, ie. that support locking - either OS
+ *                      locking or NSS-provided locks . If a PKCS#11
+ *                      module isn't thread-safe, don't serialize its
+ *                      calls; just don't load it instead. This is necessary
+ *                      if another piece of code is using the same PKCS#11
+ *                      modules that NSS is accessing without going through
+ *                      NSS, for example the Java SunPKCS11 provider.
+ *      NSS_INIT_PK11RELOAD - ignore the CKR_CRYPTOKI_ALREADY_INITIALIZED
+ *                      error when loading PKCS#11 modules. This is necessary
+ *                      if another piece of code is using the same PKCS#11
+ *                      modules that NSS is accessing without going through
+ *                      NSS, for example Java SunPKCS11 provider.
+ *      NSS_INIT_NOPK11FINALIZE - never call C_Finalize on any
+ *                      PKCS#11 module. This may be necessary in order to
+ *                      ensure continuous operation and proper shutdown
+ *                      sequence if another piece of code is using the same
+ *                      PKCS#11 modules that NSS is accessing without going
+ *                      through NSS, for example Java SunPKCS11 provider.
+ *                      The following limitation applies when this is set :
+ *                      SECMOD_WaitForAnyTokenEvent will not use
+ *                      C_WaitForSlotEvent, in order to prevent the need for
+ *                      C_Finalize. This call will be emulated instead.
+ *      NSS_INIT_RESERVED - Currently has no effect, but may be used in the
+ *                      future to trigger better cooperation between PKCS#11
+ *                      modules used by both NSS and the Java SunPKCS11
+ *                      provider. This should occur after a new flag is defined
+ *                      for C_Initialize by the PKCS#11 working group.
+ *      NSS_INIT_COOPERATE - Sets 4 recommended options for applications that
+ *                      use both NSS and the Java SunPKCS11 provider.
+ *
+ * Also NOTE: This is not the recommended method for initializing NSS. 
+ * The prefered method is NSS_init().
+ */
+#define NSS_INIT_READONLY	0x1
+#define NSS_INIT_NOCERTDB	0x2
+#define NSS_INIT_NOMODDB	0x4
+#define NSS_INIT_FORCEOPEN	0x8
+#define NSS_INIT_NOROOTINIT     0x10
+#define NSS_INIT_OPTIMIZESPACE  0x20
+#define NSS_INIT_PK11THREADSAFE   0x40
+#define NSS_INIT_PK11RELOAD       0x80
+#define NSS_INIT_NOPK11FINALIZE   0x100
+#define NSS_INIT_RESERVED         0x200
+
+#define NSS_INIT_COOPERATE NSS_INIT_PK11THREADSAFE | \
+        NSS_INIT_PK11RELOAD | \
+        NSS_INIT_NOPK11FINALIZE | \
+        NSS_INIT_RESERVED
+
+#ifdef macintosh
+#define SECMOD_DB "Security Modules"
+#else
+#define SECMOD_DB "secmod.db"
+#endif
+
+typedef struct NSSInitContextStr NSSInitContext;
+
+
+extern SECStatus NSS_Initialize(const char *configdir, 
+	const char *certPrefix, const char *keyPrefix, 
+	const char *secmodName, PRUint32 flags);
+
+extern NSSInitContext *NSS_InitContext(const char *configdir, 
+	const char *certPrefix, const char *keyPrefix, 
+	const char *secmodName, NSSInitParameters *initParams, PRUint32 flags);
+
+extern SECStatus NSS_ShutdownContext(NSSInitContext *);
+
+/*
+ * same as NSS_Init, but checks to see if we need to merge an
+ * old database in.
+ *   updatedir is the directory where the old database lives.
+ *   updCertPrefix is the certPrefix for the old database.
+ *   updKeyPrefix is the keyPrefix for the old database.
+ *   updateID is a unique identifier chosen by the application for
+ *      the specific database.
+ *   updatName is the name the user will be prompted for when
+ *      asking to authenticate to the old database  */
+extern SECStatus NSS_InitWithMerge(const char *configdir, 
+	const char *certPrefix, const char *keyPrefix, const char *secmodName,
+	const char *updatedir,  const char *updCertPrefix, 
+	const char *updKeyPrefix, const char *updateID, 
+	const char *updateName, PRUint32 flags);
+/*
+ * initialize NSS without a creating cert db's, key db's, or secmod db's.
+ */
+SECStatus NSS_NoDB_Init(const char *configdir);
+
+/*
+ * Allow applications and libraries to register with NSS so that they are called
+ * when NSS shuts down.
+ *
+ * void *appData application specific data passed in by the application at 
+ * NSS_RegisterShutdown() time.
+ * void *nssData is NULL in this release, but is reserved for future versions of 
+ * NSS to pass some future status information * back to the shutdown function. 
+ *
+ * If the shutdown function returns SECFailure,
+ * Shutdown will still complete, but NSS_Shutdown() will return SECFailure.
+ */
+typedef SECStatus (*NSS_ShutdownFunc)(void *appData, void *nssData);
+
+/*
+ * Register a shutdown function.
+ */
+SECStatus NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData);
+
+/*
+ * Remove an existing shutdown function (you may do this if your library is
+ * complete and going away, but NSS is still running).
+ */
+SECStatus NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData);
+
+/* 
+ * Close the Cert, Key databases.
+ */
+extern SECStatus NSS_Shutdown(void);
+
+/*
+ * set the PKCS #11 strings for the internal token.
+ */
+void PK11_ConfigurePKCS11(const char *man, const char *libdesc, 
+	const char *tokdesc, const char *ptokdesc, const char *slotdesc, 
+	const char *pslotdesc, const char *fslotdesc, const char *fpslotdesc,
+        int minPwd, int pwRequired);
+
+/*
+ * Dump the contents of the certificate cache and the temporary cert store.
+ * Use to detect leaked references of certs at shutdown time.
+ */
+void nss_DumpCertificateCacheInfo(void);
+
+SEC_END_PROTOS
+
+#endif /* RC_INVOKED */
+#endif /* __nss_h_ */
diff --git a/mozilla/security/nss/lib/nss/nssinit.c b/mozilla/security/nss/lib/nss/nssinit.c
new file mode 100644
index 0000000..28f860e
--- /dev/null
+++ b/mozilla/security/nss/lib/nss/nssinit.c
@@ -0,0 +1,1215 @@
+/*
+ * NSS utility functions
+ *
+ * ***** 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 ***** */
+/* $Id: nssinit.c,v 1.104 2010/01/09 01:01:32 rrelyea%redhat.com Exp $ */
+
+#include <ctype.h>
+#include <string.h>
+#include "seccomon.h"
+#include "prinit.h"
+#include "prprf.h"
+#include "prmem.h"
+#include "cert.h"
+#include "key.h"
+#include "secmod.h"
+#include "secoid.h"
+#include "nss.h"
+#include "pk11func.h"
+#include "secerr.h"
+#include "nssbase.h"
+#define NO_LIBPKIX
+#ifndef NO_LIBPKIX
+#include "pkixt.h"
+#include "pkix.h"
+#include "pkix_tools.h"
+#endif  /* NO_LIBPKIX */
+
+#include "pki3hack.h"
+#include "certi.h"
+#include "secmodi.h"
+#include "ocspti.h"
+#include "ocspi.h"
+
+/*
+ * On Windows nss3.dll needs to export the symbol 'mktemp' to be
+ * fully backward compatible with the nss3.dll in NSS 3.2.x and
+ * 3.3.x.  This symbol was unintentionally exported and its
+ * definition (in DBM) was moved from nss3.dll to softokn3.dll
+ * in NSS 3.4.  See bug 142575.
+ */
+#ifdef WIN32_NSS3_DLL_COMPAT
+#include <io.h>
+
+/* exported as 'mktemp' */
+char *
+nss_mktemp(char *path)
+{
+    return _mktemp(path);
+}
+#endif
+
+#define NSS_MAX_FLAG_SIZE  sizeof("readOnly")+sizeof("noCertDB")+ \
+	sizeof("noModDB")+sizeof("forceOpen")+sizeof("passwordRequired")+ \
+	sizeof ("optimizeSpace")
+#define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
+
+static char *
+nss_makeFlags(PRBool readOnly, PRBool noCertDB, 
+				PRBool noModDB, PRBool forceOpen, 
+				PRBool passwordRequired, PRBool optimizeSpace) 
+{
+    char *flags = (char *)PORT_Alloc(NSS_MAX_FLAG_SIZE);
+    PRBool first = PR_TRUE;
+
+    PORT_Memset(flags,0,NSS_MAX_FLAG_SIZE);
+    if (readOnly) {
+        PORT_Strcat(flags,"readOnly");
+        first = PR_FALSE;
+    }
+    if (noCertDB) {
+        if (!first) PORT_Strcat(flags,",");
+        PORT_Strcat(flags,"noCertDB");
+        first = PR_FALSE;
+    }
+    if (noModDB) {
+        if (!first) PORT_Strcat(flags,",");
+        PORT_Strcat(flags,"noModDB");
+        first = PR_FALSE;
+    }
+    if (forceOpen) {
+        if (!first) PORT_Strcat(flags,",");
+        PORT_Strcat(flags,"forceOpen");
+        first = PR_FALSE;
+    }
+    if (passwordRequired) {
+        if (!first) PORT_Strcat(flags,",");
+        PORT_Strcat(flags,"passwordRequired");
+        first = PR_FALSE;
+    }
+    if (optimizeSpace) {
+        if (!first) PORT_Strcat(flags,",");
+        PORT_Strcat(flags,"optimizeSpace");
+        first = PR_FALSE;
+    }
+    return flags;
+}
+
+
+/*
+ * build config string from individual internationalized strings
+ */
+char *
+nss_MkConfigString(const char *man, const char *libdesc, const char *tokdesc,
+	const char *ptokdesc, const char *slotdesc, const char *pslotdesc, 
+	const char *fslotdesc, const char *fpslotdesc, int minPwd)
+{
+    char *strings = NULL;
+    char *newStrings;
+
+    /* make sure the internationalization was done correctly... */
+    strings = PR_smprintf("");
+    if (strings == NULL) return NULL;
+
+    if (man) {
+        newStrings = PR_smprintf("%s manufacturerID='%s'",strings,man);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    if (libdesc) {
+        newStrings = PR_smprintf("%s libraryDescription='%s'",strings,libdesc);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    if (tokdesc) {
+        newStrings = PR_smprintf("%s cryptoTokenDescription='%s'",strings,
+								tokdesc);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    if (ptokdesc) {
+        newStrings = PR_smprintf("%s dbTokenDescription='%s'",strings,ptokdesc);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    if (slotdesc) {
+        newStrings = PR_smprintf("%s cryptoSlotDescription='%s'",strings,
+								slotdesc);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    if (pslotdesc) {
+        newStrings = PR_smprintf("%s dbSlotDescription='%s'",strings,pslotdesc);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    if (fslotdesc) {
+        newStrings = PR_smprintf("%s FIPSSlotDescription='%s'",
+							strings,fslotdesc);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    if (fpslotdesc) {
+        newStrings = PR_smprintf("%s FIPSTokenDescription='%s'",
+							strings,fpslotdesc);
+	PR_smprintf_free(strings);
+	strings = newStrings;
+    }
+    if (strings == NULL) return NULL;
+
+    newStrings = PR_smprintf("%s minPS=%d", strings, minPwd);
+    PR_smprintf_free(strings);
+    strings = newStrings;
+
+    return(strings);
+}
+
+/*
+ * statics to remember the PK11_ConfigurePKCS11()
+ * info.
+ */
+static char * pk11_config_strings = NULL;
+static char * pk11_config_name = NULL;
+static PRBool pk11_password_required = PR_FALSE;
+
+/*
+ * this is a legacy configuration function which used to be part of
+ * the PKCS #11 internal token.
+ */
+void
+PK11_ConfigurePKCS11(const char *man, const char *libdesc, const char *tokdesc,
+	const char *ptokdesc, const char *slotdesc, const char *pslotdesc, 
+	const char *fslotdesc, const char *fpslotdesc, int minPwd, 
+	int pwRequired)
+{
+    char * strings;
+
+    strings = nss_MkConfigString(man,libdesc,tokdesc,ptokdesc,slotdesc,
+	pslotdesc,fslotdesc,fpslotdesc,minPwd);
+    if (strings == NULL) {
+	return;
+    }
+
+    if (libdesc) {
+	if (pk11_config_name != NULL) {
+	    PORT_Free(pk11_config_name);
+	}
+	pk11_config_name = PORT_Strdup(libdesc);
+    }
+
+    if (pk11_config_strings != NULL) {
+	PR_smprintf_free(pk11_config_strings);
+    }
+    pk11_config_strings = strings;
+    pk11_password_required = pwRequired;
+
+    return;
+}
+
+void PK11_UnconfigurePKCS11(void)
+{
+    if (pk11_config_strings != NULL) {
+	PR_smprintf_free(pk11_config_strings);
+        pk11_config_strings = NULL;
+    }
+    if (pk11_config_name) {
+        PORT_Free(pk11_config_name);
+        pk11_config_name = NULL;
+    }
+}
+
+/*
+ * The following code is an attempt to automagically find the external root
+ * module.
+ * Note: Keep the #if-defined chunks in order. HPUX must select before UNIX.
+ */
+
+static const char *dllname =
+#if defined(XP_WIN32) || defined(XP_OS2)
+	"nssckbi.dll";
+#elif defined(HPUX) && !defined(__ia64)  /* HP-UX PA-RISC */
+	"libnssckbi.sl";
+#elif defined(DARWIN)
+	"libnssckbi.dylib";
+#elif defined(XP_UNIX) || defined(XP_BEOS)
+	"libnssckbi.so";
+#else
+	#error "Uh! Oh! I don't know about this platform."
+#endif
+
+/* Should we have platform ifdefs here??? */
+#define FILE_SEP '/'
+
+static void nss_FindExternalRootPaths(const char *dbpath, 
+                                      const char* secmodprefix,
+                              char** retoldpath, char** retnewpath)
+{
+    char *path, *oldpath = NULL, *lastsep;
+    int len, path_len, secmod_len, dll_len;
+
+    path_len = PORT_Strlen(dbpath);
+    secmod_len = secmodprefix ? PORT_Strlen(secmodprefix) : 0;
+    dll_len = PORT_Strlen(dllname);
+    len = path_len + secmod_len + dll_len + 2; /* FILE_SEP + NULL */
+
+    path = PORT_Alloc(len);
+    if (path == NULL) return;
+
+    /* back up to the top of the directory */
+    PORT_Memcpy(path,dbpath,path_len);
+    if (path[path_len-1] != FILE_SEP) {
+        path[path_len++] = FILE_SEP;
+    }
+    PORT_Strcpy(&path[path_len],dllname);
+    if (secmod_len > 0) {
+        lastsep = PORT_Strrchr(secmodprefix, FILE_SEP);
+        if (lastsep) {
+            int secmoddir_len = lastsep-secmodprefix+1; /* FILE_SEP */
+            oldpath = PORT_Alloc(len);
+            if (oldpath == NULL) {
+                PORT_Free(path);
+                return;
+            }
+            PORT_Memcpy(oldpath,path,path_len);
+            PORT_Memcpy(&oldpath[path_len],secmodprefix,secmoddir_len);
+            PORT_Strcpy(&oldpath[path_len+secmoddir_len],dllname);
+        }
+    }
+    *retoldpath = oldpath;
+    *retnewpath = path;
+    return;
+}
+
+static void nss_FreeExternalRootPaths(char* oldpath, char* path)
+{
+    if (path) {
+        PORT_Free(path);
+    }
+    if (oldpath) {
+        PORT_Free(oldpath);
+    }
+}
+
+static void
+nss_FindExternalRoot(const char *dbpath, const char* secmodprefix)
+{
+	char *path = NULL;
+        char *oldpath = NULL;
+        PRBool hasrootcerts = PR_FALSE;
+
+        /*
+         * 'oldpath' is the external root path in NSS 3.3.x or older.
+         * For backward compatibility we try to load the root certs
+         * module with the old path first.
+         */
+        nss_FindExternalRootPaths(dbpath, secmodprefix, &oldpath, &path);
+        if (oldpath) {
+            (void) SECMOD_AddNewModule("Root Certs",oldpath, 0, 0);
+            hasrootcerts = SECMOD_HasRootCerts();
+        }
+        if (path && !hasrootcerts) {
+	    (void) SECMOD_AddNewModule("Root Certs",path, 0, 0);
+        }
+        nss_FreeExternalRootPaths(oldpath, path);
+	return;
+}
+
+/*
+ * see nss_Init for definitions of the various options.
+ *
+ * this function builds a moduleSpec string from the options and previously
+ * set statics (from PKCS11_Configure, for instance), and uses it to kick off
+ * the loading of the various PKCS #11 modules.
+ */
+static SECStatus
+nss_InitModules(const char *configdir, const char *certPrefix, 
+		const char *keyPrefix, const char *secmodName, 
+		const char *updateDir, const char *updCertPrefix, 
+		const char *updKeyPrefix, const char *updateID, 
+		const char *updateName, char *configName, char *configStrings,
+		PRBool pwRequired, PRBool readOnly, PRBool noCertDB,
+		PRBool noModDB, PRBool forceOpen, PRBool optimizeSpace,
+		PRBool isContextInit)
+{
+    SECStatus rv = SECFailure;
+    char *moduleSpec = NULL;
+    char *flags = NULL;
+    char *lconfigdir = NULL;
+    char *lcertPrefix = NULL;
+    char *lkeyPrefix = NULL;
+    char *lsecmodName = NULL;
+    char *lupdateDir = NULL;
+    char *lupdCertPrefix = NULL;
+    char *lupdKeyPrefix = NULL;
+    char *lupdateID = NULL;
+    char *lupdateName = NULL;
+
+    flags = nss_makeFlags(readOnly,noCertDB,noModDB,forceOpen,
+					pwRequired, optimizeSpace);
+    if (flags == NULL) return rv;
+
+    /*
+     * configdir is double nested, and Windows uses the same character
+     * for file seps as we use for escapes! (sigh).
+     */
+    lconfigdir = secmod_DoubleEscape(configdir, '\'', '\"');
+    if (lconfigdir == NULL) {
+	goto loser;
+    }
+    lcertPrefix = secmod_DoubleEscape(certPrefix, '\'', '\"');
+    if (lcertPrefix == NULL) {
+	goto loser;
+    }
+    lkeyPrefix = secmod_DoubleEscape(keyPrefix, '\'', '\"');
+    if (lkeyPrefix == NULL) {
+	goto loser;
+    }
+    lsecmodName = secmod_DoubleEscape(secmodName, '\'', '\"');
+    if (lsecmodName == NULL) {
+	goto loser;
+    }
+    lupdateDir = secmod_DoubleEscape(updateDir, '\'', '\"');
+    if (lupdateDir == NULL) {
+	goto loser;
+    }
+    lupdCertPrefix = secmod_DoubleEscape(updCertPrefix, '\'', '\"');
+    if (lupdCertPrefix == NULL) {
+	goto loser;
+    }
+    lupdKeyPrefix = secmod_DoubleEscape(updKeyPrefix, '\'', '\"');
+    if (lupdKeyPrefix == NULL) {
+	goto loser;
+    }
+    lupdateID = secmod_DoubleEscape(updateID, '\'', '\"');
+    if (lupdateID == NULL) {
+	goto loser;
+    }
+    lupdateName = secmod_DoubleEscape(updateName, '\'', '\"');
+    if (lupdateName == NULL) {
+	goto loser;
+    }
+
+    moduleSpec = PR_smprintf(
+     "name=\"%s\" parameters=\"configdir='%s' certPrefix='%s' keyPrefix='%s' "
+     "secmod='%s' flags=%s updatedir='%s' updateCertPrefix='%s' "
+     "updateKeyPrefix='%s' updateid='%s' updateTokenDescription='%s' %s\" "
+     "NSS=\"flags=internal,moduleDB,moduleDBOnly,critical%s\"",
+		configName ? configName : NSS_DEFAULT_MOD_NAME,
+		lconfigdir,lcertPrefix,lkeyPrefix,lsecmodName,flags,
+		lupdateDir, lupdCertPrefix, lupdKeyPrefix, lupdateID, 
+		lupdateName, configStrings ? configStrings : "",
+		isContextInit ? "" : ",defaultModDB,internalKeySlot");
+
+loser:
+    PORT_Free(flags);
+    if (lconfigdir) PORT_Free(lconfigdir);
+    if (lcertPrefix) PORT_Free(lcertPrefix);
+    if (lkeyPrefix) PORT_Free(lkeyPrefix);
+    if (lsecmodName) PORT_Free(lsecmodName);
+    if (lupdateDir) PORT_Free(lupdateDir);
+    if (lupdCertPrefix) PORT_Free(lupdCertPrefix);
+    if (lupdKeyPrefix) PORT_Free(lupdKeyPrefix);
+    if (lupdateID) PORT_Free(lupdateID);
+    if (lupdateName) PORT_Free(lupdateName);
+
+    if (moduleSpec) {
+	SECMODModule *module = SECMOD_LoadModule(moduleSpec,NULL,PR_TRUE);
+	PR_smprintf_free(moduleSpec);
+	if (module) {
+	    if (module->loaded) rv=SECSuccess;
+	    SECMOD_DestroyModule(module);
+	}
+    }
+    return rv;
+}
+
+/*
+ * OK there are now lots of options here, lets go through them all:
+ *
+ * configdir - base directory where all the cert, key, and module datbases live.
+ * certPrefix - prefix added to the beginning of the cert database example: "
+ * 			"https-server1-"
+ * keyPrefix - prefix added to the beginning of the key database example: "
+ * 			"https-server1-"
+ * secmodName - name of the security module database (usually "secmod.db").
+ * updateDir - used in initMerge, old directory to update from.
+ * updateID - used in initMerge, unique ID to represent the updated directory.
+ * updateName - used in initMerge, token name when updating.
+ * initContextPtr -  used in initContext, pointer to return a unique context
+ *            value.
+ * readOnly - Boolean: true if the databases are to be opened read only.
+ * nocertdb - Don't open the cert DB and key DB's, just initialize the 
+ *			Volatile certdb.
+ * nomoddb - Don't open the security module DB, just initialize the 
+ *			PKCS #11 module.
+ * forceOpen - Continue to force initializations even if the databases cannot
+ * 			be opened.
+ * noRootInit - don't try to automatically load the root cert store if one is
+ *           not found.
+ * optimizeSpace - tell NSS to use fewer hash table buckets.
+ *
+ * The next three options are used in an attempt to share PKCS #11 modules
+ * with other loaded, running libraries. PKCS #11 was not designed with this
+ * sort of sharing in mind, so use of these options may lead to questionable
+ * results. These options are may be incompatible with NSS_LoadContext() calls.
+ *
+ * noSingleThreadedModules - don't load modules that are not thread safe (many
+ *           smart card tokens will not work).
+ * allowAlreadyInitializedModules - if a module has already been loaded and
+ *           initialize try to use it.
+ * don'tFinalizeModules -  dont shutdown modules we may have loaded.
+ */
+
+static PRBool          nssIsInitted = PR_FALSE;
+static NSSInitContext *nssInitContextList = NULL;
+static void*           plContext = NULL;
+
+struct NSSInitContextStr {
+    NSSInitContext *next;
+    PRUint32 magic;
+};
+
+#define NSS_INIT_MAGIC 0x1413A91C
+static SECStatus nss_InitShutdownList(void);
+
+#ifdef DEBUG
+static CERTCertificate dummyCert;
+#endif
+
+static SECStatus
+nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
+		 const char *secmodName, const char *updateDir, 
+		 const char *updCertPrefix, const char *updKeyPrefix,
+		 const char *updateID, const char *updateName,
+		 NSSInitContext ** initContextPtr,
+		 NSSInitParameters *initParams,
+		 PRBool readOnly, PRBool noCertDB, 
+		 PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
+		 PRBool optimizeSpace, PRBool noSingleThreadedModules,
+		 PRBool allowAlreadyInitializedModules,
+		 PRBool dontFinalizeModules)
+{
+    SECStatus rv = SECFailure;
+#ifndef NO_LIBPKIX
+    PKIX_UInt32 actualMinorVersion = 0;
+    PKIX_Error *pkixError = NULL;
+#endif
+    PRBool isReallyInitted;
+    char *configStrings = NULL;
+    char *configName = NULL;
+    PRBool passwordRequired = PR_FALSE;
+
+    /* if we are trying to init with a traditional NSS_Init call, maintain
+     * the traditional idempotent behavior. */
+    if (!initContextPtr && nssIsInitted) {
+	return SECSuccess;
+    }
+
+    /* this tells us whether or not some library has already initialized us.
+     * if so, we don't want to double call some of the basic initialization
+     * functions */
+    isReallyInitted = NSS_IsInitialized();
+
+    if (!isReallyInitted) {
+	/* New option bits must not change the size of CERTCertificate. */
+	PORT_Assert(sizeof(dummyCert.options) == sizeof(void *));
+
+	if (SECSuccess != cert_InitLocks()) {
+            return SECFailure;
+	}
+
+	if (SECSuccess != InitCRLCache()) {
+            return SECFailure;
+	}
+    
+	if (SECSuccess != OCSP_InitGlobal()) {
+            return SECFailure;
+	}
+    }
+
+    if (noSingleThreadedModules || allowAlreadyInitializedModules ||
+        dontFinalizeModules) {
+        pk11_setGlobalOptions(noSingleThreadedModules,
+                              allowAlreadyInitializedModules,
+                              dontFinalizeModules);
+    }
+
+    if (initContextPtr) {
+	*initContextPtr = PORT_ZNew(NSSInitContext);
+	if (*initContextPtr == NULL) {
+	    return SECFailure;
+	}
+	/*
+	 * For traditional NSS_Init, we used the PK11_Configure() call to set
+	 * globals. with InitContext, we pass those strings in as parameters.
+	 *
+	 * This allows old NSS_Init calls to work as before, while at the same
+	 * time new calls and old calls will not interfere with each other.
+	 */
+        if (initParams) {
+	    if (initParams->length < sizeof(NSSInitParameters)) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		return SECFailure;
+	    }
+	    configStrings = nss_MkConfigString(initParams->manufactureID,
+		initParams->libraryDescription,
+		initParams->cryptoTokenDescription,
+		initParams->dbTokenDescription,
+		initParams->cryptoSlotDescription,
+		initParams->dbSlotDescription,
+		initParams->FIPSSlotDescription,
+		initParams->FIPSTokenDescription,
+		initParams->minPWLen);
+	    if (configStrings == NULL) {
+		PORT_SetError(SEC_ERROR_NO_MEMORY);
+		return SECFailure;
+	    }
+	    configName = initParams->libraryDescription;
+	    passwordRequired = initParams->passwordRequired;
+	}
+    } else {
+	configStrings = pk11_config_strings;
+	configName = pk11_config_name;
+	passwordRequired = pk11_password_required;
+    }
+
+    /* we always try to initialize the modules */
+    rv = nss_InitModules(configdir, certPrefix, keyPrefix, secmodName, 
+		updateDir, updCertPrefix, updKeyPrefix, updateID, 
+		updateName, configName, configStrings, passwordRequired,
+		readOnly, noCertDB, noModDB, forceOpen, optimizeSpace, 
+		(initContextPtr != NULL));
+
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+
+    /* finish up initialization */
+    if (!isReallyInitted) {
+	if (SECOID_Init() != SECSuccess) {
+	    goto loser;
+	}
+	if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) {
+	    goto loser;
+	}
+	if (nss_InitShutdownList() != SECSuccess) {
+	    goto loser;
+	}
+	CERT_SetDefaultCertDB((CERTCertDBHandle *)
+				STAN_GetDefaultTrustDomain());
+	if ((!noModDB) && (!noCertDB) && (!noRootInit)) {
+	    if (!SECMOD_HasRootCerts()) {
+		const char *dbpath = configdir;
+		/* handle supported database modifiers */
+		if (strncmp(dbpath, "sql:", 4) == 0) {
+		    dbpath += 4;
+		} else if(strncmp(dbpath, "dbm:", 4) == 0) {
+		    dbpath += 4;
+		} else if(strncmp(dbpath, "extern:", 7) == 0) {
+		    dbpath += 7;
+		} else if(strncmp(dbpath, "rdb:", 4) == 0) {
+		    /* if rdb: is specified, the configdir isn't really a 
+		     * path. Skip it */
+		    dbpath = NULL;
+		}
+		if (dbpath) {
+		    nss_FindExternalRoot(dbpath, secmodName);
+		}
+	    }
+	}
+
+	pk11sdr_Init();
+	cert_CreateSubjectKeyIDHashTable();
+
+#ifndef NO_LIBPKIX
+	pkixError = PKIX_Initialize
+	    (PKIX_FALSE, PKIX_MAJOR_VERSION, PKIX_MINOR_VERSION,
+	    PKIX_MINOR_VERSION, &actualMinorVersion, &plContext);
+
+	if (pkixError != NULL) {
+	    goto loser;
+	} else {
+            char *ev = getenv("NSS_ENABLE_PKIX_VERIFY");
+            if (ev && ev[0]) {
+                CERT_SetUsePKIXForValidation(PR_TRUE);
+            }
+        }
+#endif  /* NO_LIBPKIX */
+
+
+    }
+
+    /*
+     * Now mark the appropriate init state. If initContextPtr was passed
+     * in, then return the new context pointer and add it to the
+     * nssInitContextList. Otherwise set the global nss_isInitted flag
+     */
+    if (!initContextPtr) {
+	nssIsInitted = PR_TRUE;
+    } else {
+	(*initContextPtr)->magic = NSS_INIT_MAGIC;
+	(*initContextPtr)->next = nssInitContextList;
+	nssInitContextList = (*initContextPtr);
+    }
+
+    return SECSuccess;
+
+loser:
+    if (initContextPtr && *initContextPtr) {
+	PORT_Free(*initContextPtr);
+	*initContextPtr = NULL;
+	if (configStrings) {
+	   PR_smprintf_free(configStrings);
+	}
+    }
+    return SECFailure;
+}
+
+
+SECStatus
+NSS_Init(const char *configdir)
+{
+    return nss_Init(configdir, "", "", SECMOD_DB, "", "", "", "", "", NULL,
+		NULL, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, 
+		PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
+}
+
+SECStatus
+NSS_InitReadWrite(const char *configdir)
+{
+    return nss_Init(configdir, "", "", SECMOD_DB, "", "", "", "", "", NULL,
+		NULL, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, 
+		PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
+}
+
+/*
+ * OK there are now lots of options here, lets go through them all:
+ *
+ * configdir - base directory where all the cert, key, and module datbases live.
+ * certPrefix - prefix added to the beginning of the cert database example: "
+ * 			"https-server1-"
+ * keyPrefix - prefix added to the beginning of the key database example: "
+ * 			"https-server1-"
+ * secmodName - name of the security module database (usually "secmod.db").
+ * flags - change the open options of NSS_Initialize as follows:
+ * 	NSS_INIT_READONLY - Open the databases read only.
+ * 	NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just 
+ * 			initialize the volatile certdb.
+ * 	NSS_INIT_NOMODDB  - Don't open the security module DB, just 
+ *			initialize the 	PKCS #11 module.
+ *      NSS_INIT_FORCEOPEN - Continue to force initializations even if the 
+ * 			databases cannot be opened.
+ *      NSS_INIT_PK11THREADSAFE - only load PKCS#11 modules that are
+ *                      thread-safe, ie. that support locking - either OS
+ *                      locking or NSS-provided locks . If a PKCS#11
+ *                      module isn't thread-safe, don't serialize its
+ *                      calls; just don't load it instead. This is necessary
+ *                      if another piece of code is using the same PKCS#11
+ *                      modules that NSS is accessing without going through
+ *                      NSS, for example the Java SunPKCS11 provider.
+ *      NSS_INIT_PK11RELOAD - ignore the CKR_CRYPTOKI_ALREADY_INITIALIZED
+ *                      error when loading PKCS#11 modules. This is necessary
+ *                      if another piece of code is using the same PKCS#11
+ *                      modules that NSS is accessing without going through
+ *                      NSS, for example Java SunPKCS11 provider.
+ *      NSS_INIT_NOPK11FINALIZE - never call C_Finalize on any
+ *                      PKCS#11 module. This may be necessary in order to
+ *                      ensure continuous operation and proper shutdown
+ *                      sequence if another piece of code is using the same
+ *                      PKCS#11 modules that NSS is accessing without going
+ *                      through NSS, for example Java SunPKCS11 provider.
+ *                      The following limitation applies when this is set :
+ *                      SECMOD_WaitForAnyTokenEvent will not use
+ *                      C_WaitForSlotEvent, in order to prevent the need for
+ *                      C_Finalize. This call will be emulated instead.
+ *      NSS_INIT_RESERVED - Currently has no effect, but may be used in the
+ *                      future to trigger better cooperation between PKCS#11
+ *                      modules used by both NSS and the Java SunPKCS11
+ *                      provider. This should occur after a new flag is defined
+ *                      for C_Initialize by the PKCS#11 working group.
+ *      NSS_INIT_COOPERATE - Sets 4 recommended options for applications that
+ *                      use both NSS and the Java SunPKCS11 provider. 
+ */
+SECStatus
+NSS_Initialize(const char *configdir, const char *certPrefix, 
+	const char *keyPrefix, const char *secmodName, PRUint32 flags)
+{
+    return nss_Init(configdir, certPrefix, keyPrefix, secmodName,
+	"", "", "", "", "", NULL, NULL,
+	((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
+	((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
+	((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
+	((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
+	((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
+	((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
+        ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
+        ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
+        ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
+}
+
+NSSInitContext *
+NSS_InitContext(const char *configdir, const char *certPrefix, 
+	const char *keyPrefix, const char *secmodName, 
+	NSSInitParameters *initParams, PRUint32 flags)
+{
+    SECStatus rv;
+    NSSInitContext *context;
+
+    rv = nss_Init(configdir, certPrefix, keyPrefix, secmodName,
+	"", "", "", "", "", &context, initParams,
+	((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
+	((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
+	((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
+	((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN), PR_TRUE,
+	((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
+        ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
+        ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
+        ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
+    return (rv == SECSuccess) ? context : NULL;
+}
+
+SECStatus
+NSS_InitWithMerge(const char *configdir, const char *certPrefix, 
+	const char *keyPrefix, const char *secmodName, 
+	const char *updateDir, const char *updCertPrefix,
+	const char *updKeyPrefix, const char *updateID, 
+	const char *updateName, PRUint32 flags)
+{
+    return nss_Init(configdir, certPrefix, keyPrefix, secmodName,
+	updateDir, updCertPrefix, updKeyPrefix, updateID, updateName, 
+	NULL, NULL,
+	((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
+	((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
+	((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
+	((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
+	((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
+	((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
+        ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
+        ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
+        ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
+}
+
+/*
+ * initialize NSS without a creating cert db's, key db's, or secmod db's.
+ */
+SECStatus
+NSS_NoDB_Init(const char * configdir)
+{
+      return nss_Init("","","","", "", "", "", "", "", NULL, NULL,
+			PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,
+			PR_FALSE,PR_FALSE,PR_FALSE);
+}
+
+
+#define NSS_SHUTDOWN_STEP 10
+
+struct NSSShutdownFuncPair {
+    NSS_ShutdownFunc	func;
+    void		*appData;
+};
+
+static struct NSSShutdownListStr {
+    PZLock		*lock;
+    int			allocatedFuncs;
+    int			peakFuncs;
+    struct NSSShutdownFuncPair	*funcs;
+} nssShutdownList = { 0 };
+
+/*
+ * find and existing shutdown function
+ */
+static int 
+nss_GetShutdownEntry(NSS_ShutdownFunc sFunc, void *appData)
+{
+    int count, i;
+    count = nssShutdownList.peakFuncs;
+
+    for (i=0; i < count; i++) {
+	if ((nssShutdownList.funcs[i].func == sFunc) &&
+	    (nssShutdownList.funcs[i].appData == appData)){
+	    return i;
+	}
+    }
+    return -1;
+}
+    
+/*
+ * register a callback to be called when NSS shuts down
+ */
+SECStatus
+NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
+{
+    int i;
+
+    if (!NSS_IsInitialized()) {
+	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return SECFailure;
+    }
+    if (sFunc == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    PORT_Assert(nssShutdownList.lock);
+    PZ_Lock(nssShutdownList.lock);
+
+    /* make sure we don't have a duplicate */
+    i = nss_GetShutdownEntry(sFunc, appData);
+    if (i >= 0) {
+	PZ_Unlock(nssShutdownList.lock);
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    /* find an empty slot */
+    i = nss_GetShutdownEntry(NULL, NULL);
+    if (i >= 0) {
+	nssShutdownList.funcs[i].func = sFunc;
+	nssShutdownList.funcs[i].appData = appData;
+	PZ_Unlock(nssShutdownList.lock);
+	return SECSuccess;
+    }
+    if (nssShutdownList.allocatedFuncs == nssShutdownList.peakFuncs) {
+	struct NSSShutdownFuncPair *funcs = 
+		(struct NSSShutdownFuncPair *)PORT_Realloc
+		(nssShutdownList.funcs, 
+		(nssShutdownList.allocatedFuncs + NSS_SHUTDOWN_STEP) 
+		*sizeof(struct NSSShutdownFuncPair));
+	if (!funcs) {
+	    PZ_Unlock(nssShutdownList.lock);
+	    return SECFailure;
+	}
+	nssShutdownList.funcs = funcs;
+	nssShutdownList.allocatedFuncs += NSS_SHUTDOWN_STEP;
+    }
+    nssShutdownList.funcs[nssShutdownList.peakFuncs].func = sFunc;
+    nssShutdownList.funcs[nssShutdownList.peakFuncs].appData = appData;
+    nssShutdownList.peakFuncs++;
+    PZ_Unlock(nssShutdownList.lock);
+    return SECSuccess;
+}
+
+/*
+ * unregister a callback so it won't get called on shutdown.
+ */
+SECStatus
+NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
+{
+    int i;
+    if (!NSS_IsInitialized()) {
+	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return SECFailure;
+    }
+
+    PORT_Assert(nssShutdownList.lock);
+    PZ_Lock(nssShutdownList.lock);
+    i = nss_GetShutdownEntry(sFunc, appData);
+    if (i >= 0) {
+	nssShutdownList.funcs[i].func = NULL;
+	nssShutdownList.funcs[i].appData = NULL;
+    }
+    PZ_Unlock(nssShutdownList.lock);
+
+    if (i < 0) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * bring up and shutdown the shutdown list
+ */
+static SECStatus
+nss_InitShutdownList(void)
+{
+    if (nssShutdownList.lock != NULL) {
+	return SECSuccess;
+    }
+    nssShutdownList.lock = PZ_NewLock(nssILockOther);
+    if (nssShutdownList.lock == NULL) {
+	return SECFailure;
+    }
+    nssShutdownList.funcs = PORT_ZNewArray(struct NSSShutdownFuncPair, 
+				           NSS_SHUTDOWN_STEP);
+    if (nssShutdownList.funcs == NULL) {
+	PZ_DestroyLock(nssShutdownList.lock);
+    	nssShutdownList.lock = NULL;
+	return SECFailure;
+    }
+    nssShutdownList.allocatedFuncs = NSS_SHUTDOWN_STEP;
+    nssShutdownList.peakFuncs = 0;
+
+    return SECSuccess;
+}
+
+static SECStatus
+nss_ShutdownShutdownList(void)
+{
+    SECStatus rv = SECSuccess;
+    int i;
+
+    /* call all the registerd functions first */
+    for (i=0; i < nssShutdownList.peakFuncs; i++) {
+	struct NSSShutdownFuncPair *funcPair = &nssShutdownList.funcs[i];
+	if (funcPair->func) {
+	    if ((*funcPair->func)(funcPair->appData,NULL) != SECSuccess) {
+		rv = SECFailure;
+	    }
+	}
+    }
+
+    nssShutdownList.peakFuncs = 0;
+    nssShutdownList.allocatedFuncs = 0;
+    PORT_Free(nssShutdownList.funcs);
+    nssShutdownList.funcs = NULL;
+    if (nssShutdownList.lock) {
+	PZ_DestroyLock(nssShutdownList.lock);
+    }
+    nssShutdownList.lock = NULL;
+    return rv;
+}
+
+
+extern const NSSError NSS_ERROR_BUSY;
+
+SECStatus
+nss_Shutdown(void)
+{
+    SECStatus shutdownRV = SECSuccess;
+    SECStatus rv;
+    PRStatus status;
+    NSSInitContext *temp;
+
+    rv = nss_ShutdownShutdownList();
+    if (rv != SECSuccess) {
+	shutdownRV = SECFailure;
+    }
+    cert_DestroyLocks();
+    ShutdownCRLCache();
+    OCSP_ShutdownGlobal();
+#ifndef NO_LIBPKIX
+    PKIX_Shutdown(plContext);
+#endif
+    SECOID_Shutdown();
+    status = STAN_Shutdown();
+    cert_DestroySubjectKeyIDHashTable();
+    pk11_SetInternalKeySlot(NULL);
+    rv = SECMOD_Shutdown();
+    if (rv != SECSuccess) {
+	shutdownRV = SECFailure;
+    }
+    pk11sdr_Shutdown();
+    /*
+     * A thread's error stack is automatically destroyed when the thread
+     * terminates, except for the primordial thread, whose error stack is
+     * destroyed by PR_Cleanup.  Since NSS is usually shut down by the
+     * primordial thread and many NSS-based apps don't call PR_Cleanup,
+     * we destroy the calling thread's error stack here.
+     */
+    nss_DestroyErrorStack();
+    nssArena_Shutdown();
+    if (status == PR_FAILURE) {
+	if (NSS_GetError() == NSS_ERROR_BUSY) {
+	    PORT_SetError(SEC_ERROR_BUSY);
+	}
+	shutdownRV = SECFailure;
+    }
+    nssIsInitted = PR_FALSE;
+    temp = nssInitContextList;
+    nssInitContextList = NULL;
+    /* free the old list. This is necessary when we are called from
+     * NSS_Shutdown(). */
+    while (temp) {
+	NSSInitContext *next = temp->next;
+	temp->magic = 0;
+	PORT_Free(temp);
+	temp = next;
+    }
+    return shutdownRV;
+}
+
+SECStatus
+NSS_Shutdown(void)
+{
+    if (!nssIsInitted) {
+	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return SECFailure;
+    }
+
+    return nss_Shutdown();
+}
+
+/*
+ * remove the context from a list. return true if found, false if not
+ */
+PRBool
+nss_RemoveList(NSSInitContext *context) {
+    NSSInitContext *this = nssInitContextList;
+    NSSInitContext **last = &nssInitContextList;
+
+    while (this) {
+	if (this == context) {
+	    *last = this->next;
+	    this->magic = 0;
+	    PORT_Free(this);
+	    return PR_TRUE;
+	}
+	last = &this->next;
+	this=this->next;
+    }
+    return PR_FALSE;
+}
+
+/*
+ * This form of shutdown is safe in the case where we may have multiple 
+ * entities using NSS in a single process. Each entity calls shutdown with
+ * it's own context. The application (which doesn't get a context), calls
+ * shutdown with NULL. Once all users have 'checked in' NSS will shutdown.
+ * This is different than NSS_Shutdown, where calling it will shutdown NSS
+ * irreguardless of who else may have NSS open.
+ */
+SECStatus
+NSS_ShutdownContext(NSSInitContext *context)
+{
+   if (!context) {
+	if (!nssIsInitted) {
+	    PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	    return SECFailure;
+	}
+	nssIsInitted = 0;
+    } else if (! nss_RemoveList(context)) {
+	/* context was already freed or wasn't valid */
+	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return SECFailure;
+    }
+    if ((nssIsInitted == 0) && (nssInitContextList == NULL)) {
+	return nss_Shutdown();
+    }
+    return SECSuccess;
+}
+	
+	
+
+
+PRBool
+NSS_IsInitialized(void)
+{
+    return (nssIsInitted) || (nssInitContextList != NULL);
+}
+
+
+extern const char __nss_base_rcsid[];
+extern const char __nss_base_sccsid[];
+
+PRBool
+NSS_VersionCheck(const char *importedVersion)
+{
+    /*
+     * This is the secret handshake algorithm.
+     *
+     * This release has a simple version compatibility
+     * check algorithm.  This release is not backward
+     * compatible with previous major releases.  It is
+     * not compatible with future major, minor, or
+     * patch releases or builds.
+     */
+    int vmajor = 0, vminor = 0, vpatch = 0, vbuild = 0;
+    const char *ptr = importedVersion;
+    volatile char c; /* force a reference that won't get optimized away */
+
+    c = __nss_base_rcsid[0] + __nss_base_sccsid[0]; 
+
+    while (isdigit(*ptr)) {
+        vmajor = 10 * vmajor + *ptr - '0';
+        ptr++;
+    }
+    if (*ptr == '.') {
+        ptr++;
+        while (isdigit(*ptr)) {
+            vminor = 10 * vminor + *ptr - '0';
+            ptr++;
+        }
+        if (*ptr == '.') {
+            ptr++;
+            while (isdigit(*ptr)) {
+                vpatch = 10 * vpatch + *ptr - '0';
+                ptr++;
+            }
+            if (*ptr == '.') {
+                ptr++;
+                while (isdigit(*ptr)) {
+                    vbuild = 10 * vbuild + *ptr - '0';
+                    ptr++;
+                }
+            }
+        }
+    }
+
+    if (vmajor != NSS_VMAJOR) {
+        return PR_FALSE;
+    }
+    if (vmajor == NSS_VMAJOR && vminor > NSS_VMINOR) {
+        return PR_FALSE;
+    }
+    if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR && vpatch > NSS_VPATCH) {
+        return PR_FALSE;
+    }
+    if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR &&
+        vpatch == NSS_VPATCH && vbuild > NSS_VBUILD) {
+        return PR_FALSE;
+    }
+    /* Check dependent libraries */
+    if (PR_VersionCheck(PR_VERSION) == PR_FALSE) {
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
diff --git a/mozilla/security/nss/lib/nss/nssrenam.h b/mozilla/security/nss/lib/nss/nssrenam.h
new file mode 100644
index 0000000..156646c
--- /dev/null
+++ b/mozilla/security/nss/lib/nss/nssrenam.h
@@ -0,0 +1,47 @@
+/* ***** 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) 2001
+ * 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 ***** */
+
+#ifndef __nssrenam_h_
+#define __nssrenam_h_
+
+#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
+#define PK11_CreateContextByRawKey __PK11_CreateContextByRawKey
+#define CERT_ClosePermCertDB __CERT_ClosePermCertDB
+#define CERT_DecodeDERCertificate __CERT_DecodeDERCertificate
+#define CERT_TraversePermCertsForNickname __CERT_TraversePermCertsForNickname
+#define CERT_TraversePermCertsForSubject __CERT_TraversePermCertsForSubject
+
+#endif /* __nssrenam_h_ */
diff --git a/mozilla/security/nss/lib/nss/nssver.c b/mozilla/security/nss/lib/nss/nssver.c
new file mode 100644
index 0000000..9d7f813
--- /dev/null
+++ b/mozilla/security/nss/lib/nss/nssver.c
@@ -0,0 +1,56 @@
+/* ***** 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) 2001
+ * 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 ***** */
+
+/* Library identity and versioning */
+
+#include "nss.h"
+
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
+
+/*
+ * Version information for the 'ident' and 'what commands
+ *
+ * NOTE: the first component of the concatenated rcsid string
+ * must not end in a '$' to prevent rcs keyword substitution.
+ */
+const char __nss_base_rcsid[] = "$Header: NSS " NSS_VERSION _DEBUG_STRING
+        "  " __DATE__ " " __TIME__ " $";
+const char __nss_base_sccsid[] = "@(#)NSS " NSS_VERSION _DEBUG_STRING
+        "  " __DATE__ " " __TIME__;
diff --git a/mozilla/security/nss/lib/nss/utilwrap.c b/mozilla/security/nss/lib/nss/utilwrap.c
new file mode 100644
index 0000000..900ab32
--- /dev/null
+++ b/mozilla/security/nss/lib/nss/utilwrap.c
@@ -0,0 +1,826 @@
+/*
+ * NSS utility functions
+ *
+ * ***** 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 Network Security Services libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 "secport.h"
+#include "secoid.h"
+#include "secitem.h"
+#include "secdig.h"
+#include "secder.h"
+#include "secasn1.h"
+#include "base64.h"
+#include "nssb64.h"
+#include "nssrwlk.h"
+#include "cert.h"
+#include "prerror.h"
+
+/* wrappers for implementation in libnssutil3 */
+#undef ATOB_AsciiToData
+#undef ATOB_ConvertAsciiToItem
+#undef BTOA_ConvertItemToAscii
+#undef BTOA_DataToAscii
+#undef CERT_GenTime2FormattedAscii
+#undef DER_AsciiToTime
+#undef DER_DecodeTimeChoice
+#undef DER_Encode
+#undef DER_EncodeTimeChoice
+#undef DER_GeneralizedDayToAscii
+#undef DER_GeneralizedTimeToTime
+#undef DER_GetInteger
+#undef DER_Lengths
+#undef DER_TimeChoiceDayToAscii
+#undef DER_TimeToGeneralizedTime
+#undef DER_TimeToGeneralizedTimeArena
+#undef DER_TimeToUTCTime
+#undef DER_UTCDayToAscii
+#undef DER_UTCTimeToAscii
+#undef DER_UTCTimeToTime
+#undef NSS_PutEnv
+#undef NSSBase64_DecodeBuffer
+#undef NSSBase64_EncodeItem
+#undef NSSBase64Decoder_Create
+#undef NSSBase64Decoder_Destroy
+#undef NSSBase64Decoder_Update
+#undef NSSBase64Encoder_Create
+#undef NSSBase64Encoder_Destroy
+#undef NSSBase64Encoder_Update
+#undef NSSRWLock_Destroy
+#undef NSSRWLock_HaveWriteLock
+#undef NSSRWLock_LockRead
+#undef NSSRWLock_LockWrite
+#undef NSSRWLock_New
+#undef NSSRWLock_UnlockRead
+#undef NSSRWLock_UnlockWrite
+#undef PORT_Alloc
+#undef PORT_ArenaAlloc
+#undef PORT_ArenaGrow
+#undef PORT_ArenaMark
+#undef PORT_ArenaRelease
+#undef PORT_ArenaStrdup
+#undef PORT_ArenaUnmark
+#undef PORT_ArenaZAlloc
+#undef PORT_Free
+#undef PORT_FreeArena
+#undef PORT_GetError
+#undef PORT_NewArena
+#undef PORT_Realloc
+#undef PORT_SetError
+#undef PORT_SetUCS2_ASCIIConversionFunction
+#undef PORT_SetUCS2_UTF8ConversionFunction
+#undef PORT_SetUCS4_UTF8ConversionFunction
+#undef PORT_Strdup
+#undef PORT_UCS2_ASCIIConversion
+#undef PORT_UCS2_UTF8Conversion
+#undef PORT_ZAlloc
+#undef PORT_ZFree
+#undef SEC_ASN1Decode
+#undef SEC_ASN1DecodeInteger
+#undef SEC_ASN1DecodeItem
+#undef SEC_ASN1DecoderAbort
+#undef SEC_ASN1DecoderClearFilterProc
+#undef SEC_ASN1DecoderClearNotifyProc
+#undef SEC_ASN1DecoderFinish
+#undef SEC_ASN1DecoderSetFilterProc
+#undef SEC_ASN1DecoderSetNotifyProc
+#undef SEC_ASN1DecoderStart
+#undef SEC_ASN1DecoderUpdate
+#undef SEC_ASN1Encode
+#undef SEC_ASN1EncodeInteger
+#undef SEC_ASN1EncodeItem
+#undef SEC_ASN1EncoderAbort
+#undef SEC_ASN1EncoderClearNotifyProc
+#undef SEC_ASN1EncoderClearStreaming
+#undef SEC_ASN1EncoderClearTakeFromBuf
+#undef SEC_ASN1EncoderFinish
+#undef SEC_ASN1EncoderSetNotifyProc
+#undef SEC_ASN1EncoderSetStreaming
+#undef SEC_ASN1EncoderSetTakeFromBuf
+#undef SEC_ASN1EncoderStart
+#undef SEC_ASN1EncoderUpdate
+#undef SEC_ASN1EncodeUnsignedInteger
+#undef SEC_ASN1LengthLength
+#undef SEC_QuickDERDecodeItem
+#undef SECITEM_AllocItem
+#undef SECITEM_ArenaDupItem
+#undef SECITEM_CompareItem
+#undef SECITEM_CopyItem
+#undef SECITEM_DupItem
+#undef SECITEM_FreeItem
+#undef SECITEM_ItemsAreEqual
+#undef SECITEM_ZfreeItem
+#undef SECOID_AddEntry
+#undef SECOID_CompareAlgorithmID
+#undef SECOID_CopyAlgorithmID
+#undef SECOID_DestroyAlgorithmID
+#undef SECOID_FindOID
+#undef SECOID_FindOIDByTag
+#undef SECOID_FindOIDTag
+#undef SECOID_FindOIDTagDescription
+#undef SECOID_GetAlgorithmTag
+#undef SECOID_SetAlgorithmID
+#undef SGN_CompareDigestInfo
+#undef SGN_CopyDigestInfo
+#undef SGN_CreateDigestInfo
+#undef SGN_DestroyDigestInfo
+
+void *
+PORT_Alloc(size_t bytes)
+{
+    return PORT_Alloc_Util(bytes);
+}
+
+void *
+PORT_Realloc(void *oldptr, size_t bytes)
+{
+    return PORT_Realloc_Util(oldptr, bytes);
+}
+
+void *
+PORT_ZAlloc(size_t bytes)
+{
+    return PORT_ZAlloc_Util(bytes);
+}
+
+void
+PORT_Free(void *ptr)
+{
+    PORT_Free_Util(ptr);
+}
+
+void
+PORT_ZFree(void *ptr, size_t len)
+{
+    PORT_ZFree_Util(ptr, len);
+}
+
+char *
+PORT_Strdup(const char *str)
+{
+    return PORT_Strdup_Util(str);
+}
+
+void
+PORT_SetError(int value)
+{
+    PORT_SetError_Util(value);
+}
+
+int
+PORT_GetError(void)
+{
+    return PORT_GetError_Util();
+}
+
+PLArenaPool *
+PORT_NewArena(unsigned long chunksize)
+{
+    return PORT_NewArena_Util(chunksize);
+}
+
+void *
+PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
+{
+    return PORT_ArenaAlloc_Util(arena, size);
+}
+
+void *
+PORT_ArenaZAlloc(PLArenaPool *arena, size_t size)
+{
+    return PORT_ArenaZAlloc_Util(arena, size);
+}
+
+void
+PORT_FreeArena(PLArenaPool *arena, PRBool zero)
+{
+    PORT_FreeArena_Util(arena, zero);
+}
+
+void *
+PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
+{
+    return PORT_ArenaGrow_Util(arena, ptr, oldsize, newsize);
+}
+
+void *
+PORT_ArenaMark(PLArenaPool *arena)
+{
+    return PORT_ArenaMark_Util(arena);
+}
+
+void
+PORT_ArenaRelease(PLArenaPool *arena, void *mark)
+{
+    PORT_ArenaRelease_Util(arena, mark);
+}
+
+void
+PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
+{
+    PORT_ArenaUnmark_Util(arena, mark);
+}
+
+char *
+PORT_ArenaStrdup(PLArenaPool *arena, const char *str)
+{
+    return PORT_ArenaStrdup_Util(arena, str);
+}
+
+void
+PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{
+    PORT_SetUCS4_UTF8ConversionFunction_Util(convFunc);
+}
+
+void
+PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc)
+{ 
+    PORT_SetUCS2_ASCIIConversionFunction_Util(convFunc);
+}
+
+void
+PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{ 
+    PORT_SetUCS2_UTF8ConversionFunction_Util(convFunc);
+}
+
+PRBool 
+PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+			 unsigned int inBufLen, unsigned char *outBuf,
+			 unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+    return PORT_UCS2_UTF8Conversion_Util(toUnicode, inBuf, inBufLen, outBuf,
+                                          maxOutBufLen, outBufLen);
+} 
+
+PRBool 
+PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
+			  unsigned int inBufLen, unsigned char *outBuf,
+			  unsigned int maxOutBufLen, unsigned int *outBufLen,
+			  PRBool swapBytes)
+{
+    return PORT_UCS2_ASCIIConversion_Util(toUnicode, inBuf, inBufLen, outBuf,
+			  maxOutBufLen, outBufLen, swapBytes);
+}
+
+int
+NSS_PutEnv(const char * envVarName, const char * envValue)
+{
+    return NSS_PutEnv_Util(envVarName, envValue);
+}
+
+SECOidData *SECOID_FindOID( const SECItem *oid)
+{
+    return SECOID_FindOID_Util(oid);
+}
+
+SECOidTag SECOID_FindOIDTag(const SECItem *oid)
+{
+    return SECOID_FindOIDTag_Util(oid);
+}
+
+SECOidData *SECOID_FindOIDByTag(SECOidTag tagnum)
+{
+    return SECOID_FindOIDByTag_Util(tagnum);
+}
+
+SECStatus SECOID_SetAlgorithmID(PRArenaPool *arena, SECAlgorithmID *aid,
+				   SECOidTag tag, SECItem *params)
+{
+    return SECOID_SetAlgorithmID_Util(arena, aid, tag, params);
+}
+
+SECStatus SECOID_CopyAlgorithmID(PRArenaPool *arena, SECAlgorithmID *dest,
+				    SECAlgorithmID *src)
+{
+    return SECOID_CopyAlgorithmID_Util(arena, dest, src);
+}
+
+SECOidTag SECOID_GetAlgorithmTag(SECAlgorithmID *aid)
+{
+    return SECOID_GetAlgorithmTag_Util(aid);
+}
+
+void SECOID_DestroyAlgorithmID(SECAlgorithmID *aid, PRBool freeit)
+{
+    SECOID_DestroyAlgorithmID_Util(aid, freeit);
+}
+
+SECComparison SECOID_CompareAlgorithmID(SECAlgorithmID *a,
+					   SECAlgorithmID *b)
+{
+    return SECOID_CompareAlgorithmID_Util(a, b);
+}
+
+const char *SECOID_FindOIDTagDescription(SECOidTag tagnum)
+{
+    return SECOID_FindOIDTagDescription_Util(tagnum);
+}
+
+SECOidTag SECOID_AddEntry(const SECOidData * src)
+{
+    return SECOID_AddEntry_Util(src);
+}
+
+SECItem *SECITEM_AllocItem(PRArenaPool *arena, SECItem *item,
+				  unsigned int len)
+{
+    return SECITEM_AllocItem_Util(arena, item, len);
+}
+
+SECComparison SECITEM_CompareItem(const SECItem *a, const SECItem *b)
+{
+    return SECITEM_CompareItem_Util(a, b);
+}
+
+PRBool SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
+{
+    return SECITEM_ItemsAreEqual_Util(a, b);
+}
+
+SECStatus SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, 
+                                  const SECItem *from)
+{
+    return SECITEM_CopyItem_Util(arena, to, from);
+}
+
+SECItem *SECITEM_DupItem(const SECItem *from)
+{
+    return SECITEM_DupItem_Util(from);
+}
+
+SECItem *SECITEM_ArenaDupItem(PRArenaPool *arena, const SECItem *from)
+{
+    return SECITEM_ArenaDupItem_Util(arena, from);
+}
+
+void SECITEM_FreeItem(SECItem *zap, PRBool freeit)
+{
+    SECITEM_FreeItem_Util(zap, freeit);
+}
+
+void SECITEM_ZfreeItem(SECItem *zap, PRBool freeit)
+{
+    SECITEM_ZfreeItem_Util(zap, freeit);
+}
+
+SGNDigestInfo *SGN_CreateDigestInfo(SECOidTag algorithm,
+					   unsigned char *sig,
+					   unsigned int sigLen)
+{
+    return SGN_CreateDigestInfo_Util(algorithm, sig, sigLen);
+}
+
+void SGN_DestroyDigestInfo(SGNDigestInfo *info)
+{
+    SGN_DestroyDigestInfo_Util(info);
+}
+
+SECStatus  SGN_CopyDigestInfo(PRArenaPool *poolp,
+					SGNDigestInfo *a, 
+					SGNDigestInfo *b)
+{
+    return SGN_CopyDigestInfo_Util(poolp, a, b);
+}
+
+SECComparison SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b)
+{
+    return SGN_CompareDigestInfo_Util(a, b);
+}
+
+SECStatus DER_Encode(PRArenaPool *arena, SECItem *dest, DERTemplate *t,
+			   void *src)
+{
+    return DER_Encode_Util(arena, dest, t, src);
+}
+
+SECStatus DER_Lengths(SECItem *item, int *header_len_p,
+                             PRUint32 *contents_len_p)
+{
+    return DER_Lengths_Util(item, header_len_p, contents_len_p);
+}
+
+long DER_GetInteger(SECItem *src)
+{
+    return DER_GetInteger_Util(src);
+}
+
+SECStatus DER_TimeToUTCTime(SECItem *result, int64 time)
+{
+    return DER_TimeToUTCTime_Util(result, time);
+}
+
+SECStatus DER_AsciiToTime(int64 *result, const char *string)
+{
+    return DER_AsciiToTime_Util(result, string);
+}
+
+SECStatus DER_UTCTimeToTime(int64 *result, const SECItem *time)
+{
+    return DER_UTCTimeToTime_Util(result, time);
+}
+
+char *DER_UTCTimeToAscii(SECItem *utcTime)
+{
+    return DER_UTCTimeToAscii_Util(utcTime);
+}
+
+char *DER_UTCDayToAscii(SECItem *utctime)
+{
+    return DER_UTCDayToAscii_Util(utctime);
+}
+
+char *DER_GeneralizedDayToAscii(SECItem *gentime)
+{
+    return DER_GeneralizedDayToAscii_Util(gentime);
+}
+
+char *DER_TimeChoiceDayToAscii(SECItem *timechoice)
+{
+    return DER_TimeChoiceDayToAscii_Util(timechoice);
+}
+
+SECStatus DER_TimeToGeneralizedTime(SECItem *dst, int64 gmttime)
+{
+    return DER_TimeToGeneralizedTime_Util(dst, gmttime);
+}
+
+SECStatus DER_TimeToGeneralizedTimeArena(PRArenaPool* arenaOpt,
+                                                SECItem *dst, int64 gmttime)
+{
+    return DER_TimeToGeneralizedTimeArena_Util(arenaOpt, dst, gmttime);
+}
+
+SECStatus DER_GeneralizedTimeToTime(int64 *dst, const SECItem *time)
+{
+    return DER_GeneralizedTimeToTime_Util(dst, time);
+}
+
+char *CERT_GenTime2FormattedAscii (int64 genTime, char *format)
+{
+    return CERT_GenTime2FormattedAscii_Util(genTime, format);
+}
+
+SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input)
+{
+    return DER_DecodeTimeChoice_Util(output, input);
+}
+
+SECStatus DER_EncodeTimeChoice(PRArenaPool* arena, SECItem* output,
+                                       PRTime input)
+{
+    return DER_EncodeTimeChoice_Util(arena, output, input);
+}
+
+SEC_ASN1DecoderContext *SEC_ASN1DecoderStart(PRArenaPool *pool,
+						    void *dest,
+						    const SEC_ASN1Template *t)
+{
+    return SEC_ASN1DecoderStart_Util(pool, dest, t);
+}
+
+SECStatus SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
+				       const char *buf,
+				       unsigned long len)
+{
+    return SEC_ASN1DecoderUpdate_Util(cx, buf, len);
+}
+
+SECStatus SEC_ASN1DecoderFinish(SEC_ASN1DecoderContext *cx)
+{
+    return SEC_ASN1DecoderFinish_Util(cx);
+}
+
+void SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error)
+{
+    SEC_ASN1DecoderAbort_Util(cx, error);
+}
+
+void SEC_ASN1DecoderSetFilterProc(SEC_ASN1DecoderContext *cx,
+					 SEC_ASN1WriteProc fn,
+					 void *arg, PRBool no_store)
+{
+    SEC_ASN1DecoderSetFilterProc_Util(cx, fn, arg, no_store);
+}
+
+void SEC_ASN1DecoderClearFilterProc(SEC_ASN1DecoderContext *cx)
+{
+    SEC_ASN1DecoderClearFilterProc_Util(cx);
+}
+
+void SEC_ASN1DecoderSetNotifyProc(SEC_ASN1DecoderContext *cx,
+					 SEC_ASN1NotifyProc fn,
+					 void *arg)
+{
+    SEC_ASN1DecoderSetNotifyProc_Util(cx, fn, arg);
+}
+
+void SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx)
+{
+    SEC_ASN1DecoderClearNotifyProc_Util(cx);
+}
+
+SECStatus SEC_ASN1Decode(PRArenaPool *pool, void *dest,
+				const SEC_ASN1Template *t,
+				const char *buf, long len)
+{
+    return SEC_ASN1Decode_Util(pool, dest, t, buf, len);
+}
+
+SECStatus SEC_ASN1DecodeItem(PRArenaPool *pool, void *dest,
+				    const SEC_ASN1Template *t,
+				    const SECItem *src)
+{
+    return SEC_ASN1DecodeItem_Util(pool, dest, t, src);
+}
+
+SECStatus SEC_QuickDERDecodeItem(PRArenaPool* arena, void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     const SECItem* src)
+{
+    return SEC_QuickDERDecodeItem_Util(arena, dest, templateEntry, src);
+}
+
+SEC_ASN1EncoderContext *SEC_ASN1EncoderStart(const void *src,
+						    const SEC_ASN1Template *t,
+						    SEC_ASN1WriteProc fn,
+						    void *output_arg)
+{
+    return SEC_ASN1EncoderStart_Util(src, t, fn, output_arg);
+}
+
+SECStatus SEC_ASN1EncoderUpdate(SEC_ASN1EncoderContext *cx,
+				       const char *buf,
+				       unsigned long len)
+{
+    return SEC_ASN1EncoderUpdate_Util(cx, buf, len);
+}
+
+void SEC_ASN1EncoderFinish(SEC_ASN1EncoderContext *cx)
+{
+    SEC_ASN1EncoderFinish_Util(cx);
+}
+
+void SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
+{
+    SEC_ASN1EncoderAbort_Util(cx, error);
+}
+
+void SEC_ASN1EncoderSetNotifyProc(SEC_ASN1EncoderContext *cx,
+					 SEC_ASN1NotifyProc fn,
+					 void *arg)
+{
+    SEC_ASN1EncoderSetNotifyProc_Util(cx, fn, arg);
+}
+
+void SEC_ASN1EncoderClearNotifyProc(SEC_ASN1EncoderContext *cx)
+{
+    SEC_ASN1EncoderClearNotifyProc_Util(cx);
+}
+
+void SEC_ASN1EncoderSetStreaming(SEC_ASN1EncoderContext *cx)
+{
+    SEC_ASN1EncoderSetStreaming_Util(cx);
+}
+
+void SEC_ASN1EncoderClearStreaming(SEC_ASN1EncoderContext *cx)
+{
+    SEC_ASN1EncoderClearStreaming_Util(cx);
+}
+
+void SEC_ASN1EncoderSetTakeFromBuf(SEC_ASN1EncoderContext *cx)
+{
+    SEC_ASN1EncoderSetTakeFromBuf_Util(cx);
+}
+
+void SEC_ASN1EncoderClearTakeFromBuf(SEC_ASN1EncoderContext *cx)
+{
+    SEC_ASN1EncoderClearTakeFromBuf_Util(cx);
+}
+
+SECStatus SEC_ASN1Encode(const void *src, const SEC_ASN1Template *t,
+				SEC_ASN1WriteProc output_proc,
+				void *output_arg)
+{
+    return SEC_ASN1Encode_Util(src, t, output_proc, output_arg);
+}
+
+SECItem * SEC_ASN1EncodeItem(PRArenaPool *pool, SECItem *dest,
+				    const void *src, const SEC_ASN1Template *t)
+{
+    return SEC_ASN1EncodeItem_Util(pool, dest, src, t);
+}
+
+SECItem * SEC_ASN1EncodeInteger(PRArenaPool *pool,
+				       SECItem *dest, long value)
+{
+    return SEC_ASN1EncodeInteger_Util(pool, dest, value);
+}
+
+SECItem * SEC_ASN1EncodeUnsignedInteger(PRArenaPool *pool,
+					       SECItem *dest,
+					       unsigned long value)
+{
+    return SEC_ASN1EncodeUnsignedInteger_Util(pool, dest, value);
+}
+
+SECStatus SEC_ASN1DecodeInteger(SECItem *src,
+				       unsigned long *value)
+{
+    return SEC_ASN1DecodeInteger_Util(src, value);
+}
+
+int SEC_ASN1LengthLength (unsigned long len)
+{
+    return SEC_ASN1LengthLength_Util(len);
+}
+
+char *BTOA_DataToAscii(const unsigned char *data, unsigned int len)
+{
+    return BTOA_DataToAscii_Util(data, len);
+}
+
+unsigned char *ATOB_AsciiToData(const char *string, unsigned int *lenp)
+{
+    return ATOB_AsciiToData_Util(string, lenp);
+}
+ 
+SECStatus ATOB_ConvertAsciiToItem(SECItem *binary_item, char *ascii)
+{
+    return ATOB_ConvertAsciiToItem_Util(binary_item, ascii);
+}
+
+char *BTOA_ConvertItemToAscii(SECItem *binary_item)
+{
+    return BTOA_ConvertItemToAscii_Util(binary_item);
+}
+
+NSSBase64Decoder *
+NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
+					       PRInt32),
+			 void *output_arg)
+{
+    return NSSBase64Decoder_Create_Util(output_fn, output_arg);
+}
+
+NSSBase64Encoder *
+NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+			 void *output_arg)
+{
+    return NSSBase64Encoder_Create_Util(output_fn, output_arg);
+}
+
+SECStatus
+NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
+			 PRUint32 size)
+{
+    return NSSBase64Decoder_Update_Util(data, buffer, size);
+}
+
+SECStatus
+NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
+			 PRUint32 size)
+{
+    return NSSBase64Encoder_Update_Util(data, buffer, size);
+}
+
+SECStatus
+NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p)
+{
+    return NSSBase64Decoder_Destroy_Util(data, abort_p);
+}
+
+SECStatus
+NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p)
+{
+    return NSSBase64Encoder_Destroy_Util(data, abort_p);
+}
+
+SECItem *
+NSSBase64_DecodeBuffer (PRArenaPool *arenaOpt, SECItem *outItemOpt,
+			const char *inStr, unsigned int inLen)
+{
+    return NSSBase64_DecodeBuffer_Util(arenaOpt, outItemOpt, inStr, inLen);
+}
+
+char *
+NSSBase64_EncodeItem (PRArenaPool *arenaOpt, char *outStrOpt,
+		      unsigned int maxOutLen, SECItem *inItem)
+{
+    return NSSBase64_EncodeItem_Util(arenaOpt, outStrOpt, maxOutLen, inItem);
+}
+
+NSSRWLock* NSSRWLock_New(PRUint32 lock_rank, const char *lock_name)
+{
+    return NSSRWLock_New_Util(lock_rank, lock_name);
+}
+
+void NSSRWLock_Destroy(NSSRWLock *lock)
+{
+    NSSRWLock_Destroy_Util(lock);
+}
+
+void NSSRWLock_LockRead(NSSRWLock *lock)
+{
+    NSSRWLock_LockRead_Util(lock);
+}
+
+void NSSRWLock_LockWrite(NSSRWLock *lock)
+{
+    NSSRWLock_LockWrite_Util(lock);
+}
+
+void NSSRWLock_UnlockRead(NSSRWLock *lock)
+{
+    NSSRWLock_UnlockRead_Util(lock);
+}
+
+void NSSRWLock_UnlockWrite(NSSRWLock *lock)
+{
+    NSSRWLock_UnlockWrite_Util(lock);
+}
+
+PRBool NSSRWLock_HaveWriteLock(NSSRWLock *rwlock)
+{
+    return NSSRWLock_HaveWriteLock_Util(rwlock);
+}
+
+SECStatus __nss_InitLock(   PZLock    **ppLock, nssILockType ltype )
+{
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+}
+
+/* templates duplicated in libnss3 and libnssutil3 */
+
+#undef NSS_Get_SEC_AnyTemplate
+#undef NSS_Get_SEC_BitStringTemplate
+#undef NSS_Get_SEC_BMPStringTemplate
+#undef NSS_Get_SEC_BooleanTemplate
+#undef NSS_Get_SEC_GeneralizedTimeTemplate
+#undef NSS_Get_SEC_IA5StringTemplate
+#undef NSS_Get_SEC_IntegerTemplate
+#undef NSS_Get_SEC_NullTemplate
+#undef NSS_Get_SEC_ObjectIDTemplate
+#undef NSS_Get_SEC_OctetStringTemplate
+#undef NSS_Get_SEC_PointerToAnyTemplate
+#undef NSS_Get_SEC_PointerToOctetStringTemplate
+#undef NSS_Get_SEC_SetOfAnyTemplate
+#undef NSS_Get_SEC_UTCTimeTemplate
+#undef NSS_Get_SEC_UTF8StringTemplate
+#undef NSS_Get_SECOID_AlgorithmIDTemplate
+#undef NSS_Get_sgn_DigestInfoTemplate
+#undef SEC_AnyTemplate
+#undef SEC_BitStringTemplate
+#undef SEC_BMPStringTemplate
+#undef SEC_BooleanTemplate
+#undef SEC_GeneralizedTimeTemplate
+#undef SEC_IA5StringTemplate
+#undef SEC_IntegerTemplate
+#undef SEC_NullTemplate
+#undef SEC_ObjectIDTemplate
+#undef SEC_OctetStringTemplate
+#undef SEC_PointerToAnyTemplate
+#undef SEC_PointerToOctetStringTemplate
+#undef SEC_SetOfAnyTemplate
+#undef SEC_UTCTimeTemplate
+#undef SEC_UTF8StringTemplate
+#undef SECOID_AlgorithmIDTemplate
+#undef sgn_DigestInfoTemplate
+
+#include "templates.c"
+
diff --git a/mozilla/security/nss/lib/pk11wrap/debug_module.c b/mozilla/security/nss/lib/pk11wrap/debug_module.c
new file mode 100644
index 0000000..5197d96
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/debug_module.c
@@ -0,0 +1,2743 @@
+/* ***** 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 "prlog.h"
+#include <stdio.h>
+#include "cert.h"  /* for CERT_DerNameToAscii & CERT_Hexify */
+
+static PRLogModuleInfo *modlog = NULL;
+
+static CK_FUNCTION_LIST_PTR module_functions;
+
+static CK_FUNCTION_LIST debug_functions;
+
+static void print_final_statistics(void);
+
+#define STRING static const char 
+
+STRING fmt_flags[]                = "  flags = 0x%x";
+STRING fmt_hKey[]                 = "  hKey = 0x%x";
+STRING fmt_hObject[]              = "  hObject = 0x%x";
+STRING fmt_hSession[]             = "  hSession = 0x%x";
+STRING fmt_manufacturerID[]       = "  manufacturerID = \"%.32s\"";
+STRING fmt_pData[]                = "  pData = 0x%p";
+STRING fmt_pDigest[]              = "  pDigest = 0x%p";
+STRING fmt_pEncryptedData[]       = "  pEncryptedData = 0x%p";
+STRING fmt_pEncryptedPart[]       = "  pEncryptedPart = 0x%p";
+STRING fmt_pInfo[]                = "  pInfo = 0x%p";
+STRING fmt_pMechanism[]           = "  pMechanism = 0x%p";
+STRING fmt_pOperationState[]      = "  pOperationState = 0x%p";
+STRING fmt_pPart[]                = "  pPart = 0x%p";
+STRING fmt_pPin[]                 = "  pPin = 0x%p";
+STRING fmt_pSignature[]           = "  pSignature = 0x%p";
+STRING fmt_pTemplate[]            = "  pTemplate = 0x%p";
+STRING fmt_pWrappedKey[]          = "  pWrappedKey = 0x%p";
+STRING fmt_phKey[]                = "  phKey = 0x%p";
+STRING fmt_phObject[]             = "  phObject = 0x%p";
+STRING fmt_pulCount[]             = "  pulCount = 0x%p";
+STRING fmt_pulDataLen[]           = "  pulDataLen = 0x%p";
+STRING fmt_pulDigestLen[]         = "  pulDigestLen = 0x%p";
+STRING fmt_pulEncryptedPartLen[]  = "  pulEncryptedPartLen = 0x%p";
+STRING fmt_pulPartLen[]           = "  pulPartLen = 0x%p";
+STRING fmt_pulSignatureLen[]      = "  pulSignatureLen = 0x%p";
+STRING fmt_slotID[]               = "  slotID = 0x%x";
+STRING fmt_sphKey[]               = "  *phKey = 0x%x";
+STRING fmt_spulCount[]            = "  *pulCount = 0x%x";
+STRING fmt_spulDataLen[]          = "  *pulDataLen = 0x%x";
+STRING fmt_spulDigestLen[]        = "  *pulDigestLen = 0x%x";
+STRING fmt_spulEncryptedPartLen[] = "  *pulEncryptedPartLen = 0x%x";
+STRING fmt_spulPartLen[]          = "  *pulPartLen = 0x%x";
+STRING fmt_spulSignatureLen[]     = "  *pulSignatureLen = 0x%x";
+STRING fmt_ulAttributeCount[]     = "  ulAttributeCount = %d";
+STRING fmt_ulCount[]              = "  ulCount = %d";
+STRING fmt_ulDataLen[]            = "  ulDataLen = %d";
+STRING fmt_ulEncryptedPartLen[]   = "  ulEncryptedPartLen = %d";
+STRING fmt_ulPartLen[]            = "  ulPartLen = %d";
+STRING fmt_ulPinLen[]             = "  ulPinLen = %d";
+STRING fmt_ulSignatureLen[]       = "  ulSignatureLen = %d";
+
+STRING fmt_fwVersion[]            = "  firmware version: %d.%d";
+STRING fmt_hwVersion[]            = "  hardware version: %d.%d";
+STRING fmt_s_qsq_d[]              = "    %s = \"%s\" [%d]";
+STRING fmt_s_s_d[]                = "    %s = %s [%d]";
+STRING fmt_invalid_handle[]       = " (CK_INVALID_HANDLE)";
+
+
+static void get_attr_type_str(CK_ATTRIBUTE_TYPE atype, char *str, int len)
+{
+#define CASE(attr) case attr: a = #attr ; break
+
+    const char * a = NULL;
+
+    switch (atype) {
+    CASE(CKA_CLASS);
+    CASE(CKA_TOKEN);
+    CASE(CKA_PRIVATE);
+    CASE(CKA_LABEL);
+    CASE(CKA_APPLICATION);
+    CASE(CKA_VALUE);
+    CASE(CKA_OBJECT_ID);
+    CASE(CKA_CERTIFICATE_TYPE);
+    CASE(CKA_ISSUER);
+    CASE(CKA_SERIAL_NUMBER);
+    CASE(CKA_AC_ISSUER);
+    CASE(CKA_OWNER);
+    CASE(CKA_ATTR_TYPES);
+    CASE(CKA_TRUSTED);
+    CASE(CKA_KEY_TYPE);
+    CASE(CKA_SUBJECT);
+    CASE(CKA_ID);
+    CASE(CKA_SENSITIVE);
+    CASE(CKA_ENCRYPT);
+    CASE(CKA_DECRYPT);
+    CASE(CKA_WRAP);
+    CASE(CKA_UNWRAP);
+    CASE(CKA_SIGN);
+    CASE(CKA_SIGN_RECOVER);
+    CASE(CKA_VERIFY);
+    CASE(CKA_VERIFY_RECOVER);
+    CASE(CKA_DERIVE);
+    CASE(CKA_START_DATE);
+    CASE(CKA_END_DATE);
+    CASE(CKA_MODULUS);
+    CASE(CKA_MODULUS_BITS);
+    CASE(CKA_PUBLIC_EXPONENT);
+    CASE(CKA_PRIVATE_EXPONENT);
+    CASE(CKA_PRIME_1);
+    CASE(CKA_PRIME_2);
+    CASE(CKA_EXPONENT_1);
+    CASE(CKA_EXPONENT_2);
+    CASE(CKA_COEFFICIENT);
+    CASE(CKA_PRIME);
+    CASE(CKA_SUBPRIME);
+    CASE(CKA_BASE);
+    CASE(CKA_PRIME_BITS);
+    CASE(CKA_SUB_PRIME_BITS);
+    CASE(CKA_VALUE_BITS);
+    CASE(CKA_VALUE_LEN);
+    CASE(CKA_EXTRACTABLE);
+    CASE(CKA_LOCAL);
+    CASE(CKA_NEVER_EXTRACTABLE);
+    CASE(CKA_ALWAYS_SENSITIVE);
+    CASE(CKA_KEY_GEN_MECHANISM);
+    CASE(CKA_MODIFIABLE);
+    CASE(CKA_ECDSA_PARAMS);
+    CASE(CKA_EC_POINT);
+    CASE(CKA_SECONDARY_AUTH);
+    CASE(CKA_AUTH_PIN_FLAGS);
+    CASE(CKA_HW_FEATURE_TYPE);
+    CASE(CKA_RESET_ON_INIT);
+    CASE(CKA_HAS_RESET);
+    CASE(CKA_VENDOR_DEFINED);
+    CASE(CKA_NETSCAPE_URL);
+    CASE(CKA_NETSCAPE_EMAIL);
+    CASE(CKA_NETSCAPE_SMIME_INFO);
+    CASE(CKA_NETSCAPE_SMIME_TIMESTAMP);
+    CASE(CKA_NETSCAPE_PKCS8_SALT);
+    CASE(CKA_NETSCAPE_PASSWORD_CHECK);
+    CASE(CKA_NETSCAPE_EXPIRES);
+    CASE(CKA_NETSCAPE_KRL);
+    CASE(CKA_NETSCAPE_PQG_COUNTER);
+    CASE(CKA_NETSCAPE_PQG_SEED);
+    CASE(CKA_NETSCAPE_PQG_H);
+    CASE(CKA_NETSCAPE_PQG_SEED_BITS);
+    CASE(CKA_TRUST);
+    CASE(CKA_TRUST_DIGITAL_SIGNATURE);
+    CASE(CKA_TRUST_NON_REPUDIATION);
+    CASE(CKA_TRUST_KEY_ENCIPHERMENT);
+    CASE(CKA_TRUST_DATA_ENCIPHERMENT);
+    CASE(CKA_TRUST_KEY_AGREEMENT);
+    CASE(CKA_TRUST_KEY_CERT_SIGN);
+    CASE(CKA_TRUST_CRL_SIGN);
+    CASE(CKA_TRUST_SERVER_AUTH);
+    CASE(CKA_TRUST_CLIENT_AUTH);
+    CASE(CKA_TRUST_CODE_SIGNING);
+    CASE(CKA_TRUST_EMAIL_PROTECTION);
+    CASE(CKA_TRUST_IPSEC_END_SYSTEM);
+    CASE(CKA_TRUST_IPSEC_TUNNEL);
+    CASE(CKA_TRUST_IPSEC_USER);
+    CASE(CKA_TRUST_TIME_STAMPING);
+    CASE(CKA_CERT_SHA1_HASH);
+    CASE(CKA_CERT_MD5_HASH);
+    CASE(CKA_NETSCAPE_DB);
+    CASE(CKA_NETSCAPE_TRUST);
+    default: break;
+    }
+    if (a)
+	PR_snprintf(str, len, "%s", a);
+    else
+	PR_snprintf(str, len, "0x%p", atype);
+}
+
+static void get_obj_class(CK_OBJECT_CLASS objClass, char *str, int len)
+{
+
+    const char * a = NULL;
+
+    switch (objClass) {
+    CASE(CKO_DATA);
+    CASE(CKO_CERTIFICATE);
+    CASE(CKO_PUBLIC_KEY);
+    CASE(CKO_PRIVATE_KEY);
+    CASE(CKO_SECRET_KEY);
+    CASE(CKO_HW_FEATURE);
+    CASE(CKO_DOMAIN_PARAMETERS);
+    CASE(CKO_NETSCAPE_CRL);
+    CASE(CKO_NETSCAPE_SMIME);
+    CASE(CKO_NETSCAPE_TRUST);
+    CASE(CKO_NETSCAPE_BUILTIN_ROOT_LIST);
+    default: break;
+    }
+    if (a)
+	PR_snprintf(str, len, "%s", a);
+    else
+	PR_snprintf(str, len, "0x%p", objClass);
+}
+
+static void get_trust_val(CK_TRUST trust, char *str, int len)
+{
+    const char * a = NULL;
+
+    switch (trust) {
+    CASE(CKT_NETSCAPE_TRUSTED);
+    CASE(CKT_NETSCAPE_TRUSTED_DELEGATOR);
+    CASE(CKT_NETSCAPE_UNTRUSTED);
+    CASE(CKT_NETSCAPE_MUST_VERIFY);
+    CASE(CKT_NETSCAPE_TRUST_UNKNOWN);
+    CASE(CKT_NETSCAPE_VALID);
+    CASE(CKT_NETSCAPE_VALID_DELEGATOR);
+    default: break;
+    }
+    if (a)
+	PR_snprintf(str, len, "%s", a);
+    else
+	PR_snprintf(str, len, "0x%p", trust);
+}
+
+static void log_rv(CK_RV rv)
+{
+    const char * a = NULL;
+
+    switch (rv) {
+    CASE(CKR_OK);
+    CASE(CKR_CANCEL);
+    CASE(CKR_HOST_MEMORY);
+    CASE(CKR_SLOT_ID_INVALID);
+    CASE(CKR_GENERAL_ERROR);
+    CASE(CKR_FUNCTION_FAILED);
+    CASE(CKR_ARGUMENTS_BAD);
+    CASE(CKR_NO_EVENT);
+    CASE(CKR_NEED_TO_CREATE_THREADS);
+    CASE(CKR_CANT_LOCK);
+    CASE(CKR_ATTRIBUTE_READ_ONLY);
+    CASE(CKR_ATTRIBUTE_SENSITIVE);
+    CASE(CKR_ATTRIBUTE_TYPE_INVALID);
+    CASE(CKR_ATTRIBUTE_VALUE_INVALID);
+    CASE(CKR_DATA_INVALID);
+    CASE(CKR_DATA_LEN_RANGE);
+    CASE(CKR_DEVICE_ERROR);
+    CASE(CKR_DEVICE_MEMORY);
+    CASE(CKR_DEVICE_REMOVED);
+    CASE(CKR_ENCRYPTED_DATA_INVALID);
+    CASE(CKR_ENCRYPTED_DATA_LEN_RANGE);
+    CASE(CKR_FUNCTION_CANCELED);
+    CASE(CKR_FUNCTION_NOT_PARALLEL);
+    CASE(CKR_FUNCTION_NOT_SUPPORTED);
+    CASE(CKR_KEY_HANDLE_INVALID);
+    CASE(CKR_KEY_SIZE_RANGE);
+    CASE(CKR_KEY_TYPE_INCONSISTENT);
+    CASE(CKR_KEY_NOT_NEEDED);
+    CASE(CKR_KEY_CHANGED);
+    CASE(CKR_KEY_NEEDED);
+    CASE(CKR_KEY_INDIGESTIBLE);
+    CASE(CKR_KEY_FUNCTION_NOT_PERMITTED);
+    CASE(CKR_KEY_NOT_WRAPPABLE);
+    CASE(CKR_KEY_UNEXTRACTABLE);
+    CASE(CKR_MECHANISM_INVALID);
+    CASE(CKR_MECHANISM_PARAM_INVALID);
+    CASE(CKR_OBJECT_HANDLE_INVALID);
+    CASE(CKR_OPERATION_ACTIVE);
+    CASE(CKR_OPERATION_NOT_INITIALIZED);
+    CASE(CKR_PIN_INCORRECT);
+    CASE(CKR_PIN_INVALID);
+    CASE(CKR_PIN_LEN_RANGE);
+    CASE(CKR_PIN_EXPIRED);
+    CASE(CKR_PIN_LOCKED);
+    CASE(CKR_SESSION_CLOSED);
+    CASE(CKR_SESSION_COUNT);
+    CASE(CKR_SESSION_HANDLE_INVALID);
+    CASE(CKR_SESSION_PARALLEL_NOT_SUPPORTED);
+    CASE(CKR_SESSION_READ_ONLY);
+    CASE(CKR_SESSION_EXISTS);
+    CASE(CKR_SESSION_READ_ONLY_EXISTS);
+    CASE(CKR_SESSION_READ_WRITE_SO_EXISTS);
+    CASE(CKR_SIGNATURE_INVALID);
+    CASE(CKR_SIGNATURE_LEN_RANGE);
+    CASE(CKR_TEMPLATE_INCOMPLETE);
+    CASE(CKR_TEMPLATE_INCONSISTENT);
+    CASE(CKR_TOKEN_NOT_PRESENT);
+    CASE(CKR_TOKEN_NOT_RECOGNIZED);
+    CASE(CKR_TOKEN_WRITE_PROTECTED);
+    CASE(CKR_UNWRAPPING_KEY_HANDLE_INVALID);
+    CASE(CKR_UNWRAPPING_KEY_SIZE_RANGE);
+    CASE(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT);
+    CASE(CKR_USER_ALREADY_LOGGED_IN);
+    CASE(CKR_USER_NOT_LOGGED_IN);
+    CASE(CKR_USER_PIN_NOT_INITIALIZED);
+    CASE(CKR_USER_TYPE_INVALID);
+    CASE(CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
+    CASE(CKR_USER_TOO_MANY_TYPES);
+    CASE(CKR_WRAPPED_KEY_INVALID);
+    CASE(CKR_WRAPPED_KEY_LEN_RANGE);
+    CASE(CKR_WRAPPING_KEY_HANDLE_INVALID);
+    CASE(CKR_WRAPPING_KEY_SIZE_RANGE);
+    CASE(CKR_WRAPPING_KEY_TYPE_INCONSISTENT);
+    CASE(CKR_RANDOM_SEED_NOT_SUPPORTED);
+    CASE(CKR_RANDOM_NO_RNG);
+    CASE(CKR_DOMAIN_PARAMS_INVALID);
+    CASE(CKR_BUFFER_TOO_SMALL);
+    CASE(CKR_SAVED_STATE_INVALID);
+    CASE(CKR_INFORMATION_SENSITIVE);
+    CASE(CKR_STATE_UNSAVEABLE);
+    CASE(CKR_CRYPTOKI_NOT_INITIALIZED);
+    CASE(CKR_CRYPTOKI_ALREADY_INITIALIZED);
+    CASE(CKR_MUTEX_BAD);
+    CASE(CKR_MUTEX_NOT_LOCKED);
+    CASE(CKR_FUNCTION_REJECTED);
+    CASE(CKR_KEY_PARAMS_INVALID);
+    default: break;
+    }
+    if (a)
+	PR_LOG(modlog, 1, ("  rv = %s\n", a));
+    else
+	PR_LOG(modlog, 1, ("  rv = 0x%x\n", rv));
+}
+
+static void log_state(CK_STATE state)
+{
+    const char * a = NULL;
+
+    switch (state) {
+    CASE(CKS_RO_PUBLIC_SESSION);
+    CASE(CKS_RO_USER_FUNCTIONS);
+    CASE(CKS_RW_PUBLIC_SESSION);
+    CASE(CKS_RW_USER_FUNCTIONS);
+    CASE(CKS_RW_SO_FUNCTIONS);
+    default: break;
+    }
+    if (a)
+	PR_LOG(modlog, 1, ("  state = %s\n", a));
+    else
+	PR_LOG(modlog, 1, ("  state = 0x%x\n", state));
+}
+
+static void log_handle(int level, const char * format, CK_ULONG handle)
+{
+    char fmtBuf[80];
+    if (handle)
+	PR_LOG(modlog, level, (format, handle));
+    else {
+	PL_strncpyz(fmtBuf, format, sizeof fmtBuf);
+	PL_strcatn(fmtBuf, sizeof fmtBuf, fmt_invalid_handle);
+	PR_LOG(modlog, level, (fmtBuf, handle));
+    }
+}
+
+static void print_mechanism(CK_MECHANISM_PTR m)
+{
+
+    const char * a = NULL;
+
+    switch (m->mechanism) {
+    CASE(CKM_AES_CBC);
+    CASE(CKM_AES_CBC_ENCRYPT_DATA);
+    CASE(CKM_AES_CBC_PAD);
+    CASE(CKM_AES_ECB);
+    CASE(CKM_AES_ECB_ENCRYPT_DATA);
+    CASE(CKM_AES_KEY_GEN);
+    CASE(CKM_AES_MAC);
+    CASE(CKM_AES_MAC_GENERAL);
+    CASE(CKM_CAMELLIA_CBC);
+    CASE(CKM_CAMELLIA_CBC_ENCRYPT_DATA);
+    CASE(CKM_CAMELLIA_CBC_PAD);
+    CASE(CKM_CAMELLIA_ECB);
+    CASE(CKM_CAMELLIA_ECB_ENCRYPT_DATA);
+    CASE(CKM_CAMELLIA_KEY_GEN);
+    CASE(CKM_CAMELLIA_MAC);
+    CASE(CKM_CAMELLIA_MAC_GENERAL);
+    CASE(CKM_CDMF_CBC);
+    CASE(CKM_CDMF_CBC_PAD);
+    CASE(CKM_CDMF_ECB);
+    CASE(CKM_CDMF_KEY_GEN);
+    CASE(CKM_CDMF_MAC);
+    CASE(CKM_CDMF_MAC_GENERAL);
+    CASE(CKM_CMS_SIG);
+    CASE(CKM_CONCATENATE_BASE_AND_DATA);
+    CASE(CKM_CONCATENATE_BASE_AND_KEY);
+    CASE(CKM_CONCATENATE_DATA_AND_BASE);
+    CASE(CKM_DES2_KEY_GEN);
+    CASE(CKM_DES3_CBC);
+    CASE(CKM_DES3_CBC_ENCRYPT_DATA);
+    CASE(CKM_DES3_CBC_PAD);
+    CASE(CKM_DES3_ECB);
+    CASE(CKM_DES3_ECB_ENCRYPT_DATA);
+    CASE(CKM_DES3_KEY_GEN);
+    CASE(CKM_DES3_MAC);
+    CASE(CKM_DES3_MAC_GENERAL);
+    CASE(CKM_DES_CBC);
+    CASE(CKM_DES_CBC_ENCRYPT_DATA);
+    CASE(CKM_DES_CBC_PAD);
+    CASE(CKM_DES_CFB64);
+    CASE(CKM_DES_CFB8);
+    CASE(CKM_DES_ECB);
+    CASE(CKM_DES_ECB_ENCRYPT_DATA);
+    CASE(CKM_DES_KEY_GEN);
+    CASE(CKM_DES_MAC);
+    CASE(CKM_DES_MAC_GENERAL);
+    CASE(CKM_DES_OFB64);
+    CASE(CKM_DES_OFB8);
+    CASE(CKM_DH_PKCS_DERIVE);
+    CASE(CKM_DH_PKCS_KEY_PAIR_GEN);
+    CASE(CKM_DH_PKCS_PARAMETER_GEN);
+    CASE(CKM_DSA);
+    CASE(CKM_DSA_KEY_PAIR_GEN);
+    CASE(CKM_DSA_PARAMETER_GEN);
+    CASE(CKM_DSA_SHA1);
+    CASE(CKM_ECDH1_COFACTOR_DERIVE);
+    CASE(CKM_ECDH1_DERIVE);
+    CASE(CKM_ECDSA);
+    CASE(CKM_ECDSA_SHA1);
+    CASE(CKM_ECMQV_DERIVE);
+    CASE(CKM_EC_KEY_PAIR_GEN);	     /* also CASE(CKM_ECDSA_KEY_PAIR_GEN); */
+    CASE(CKM_EXTRACT_KEY_FROM_KEY);
+    CASE(CKM_FASTHASH);
+    CASE(CKM_FORTEZZA_TIMESTAMP);
+    CASE(CKM_GENERIC_SECRET_KEY_GEN);
+    CASE(CKM_IDEA_CBC);
+    CASE(CKM_IDEA_CBC_PAD);
+    CASE(CKM_IDEA_ECB);
+    CASE(CKM_IDEA_KEY_GEN);
+    CASE(CKM_IDEA_MAC);
+    CASE(CKM_IDEA_MAC_GENERAL);
+    CASE(CKM_KEA_KEY_DERIVE);
+    CASE(CKM_KEA_KEY_PAIR_GEN);
+    CASE(CKM_KEY_WRAP_LYNKS);
+    CASE(CKM_KEY_WRAP_SET_OAEP);
+    CASE(CKM_MD2);
+    CASE(CKM_MD2_HMAC);
+    CASE(CKM_MD2_HMAC_GENERAL);
+    CASE(CKM_MD2_KEY_DERIVATION);
+    CASE(CKM_MD2_RSA_PKCS);
+    CASE(CKM_MD5);
+    CASE(CKM_MD5_HMAC);
+    CASE(CKM_MD5_HMAC_GENERAL);
+    CASE(CKM_MD5_KEY_DERIVATION);
+    CASE(CKM_MD5_RSA_PKCS);
+    CASE(CKM_PBA_SHA1_WITH_SHA1_HMAC);
+    CASE(CKM_PBE_MD2_DES_CBC);
+    CASE(CKM_PBE_MD5_DES_CBC);
+    CASE(CKM_PBE_SHA1_DES2_EDE_CBC);
+    CASE(CKM_PBE_SHA1_DES3_EDE_CBC);
+    CASE(CKM_PBE_SHA1_RC2_128_CBC);
+    CASE(CKM_PBE_SHA1_RC2_40_CBC);
+    CASE(CKM_PBE_SHA1_RC4_128);
+    CASE(CKM_PBE_SHA1_RC4_40);
+    CASE(CKM_PKCS5_PBKD2);
+    CASE(CKM_RC2_CBC);
+    CASE(CKM_RC2_CBC_PAD);
+    CASE(CKM_RC2_ECB);
+    CASE(CKM_RC2_KEY_GEN);
+    CASE(CKM_RC2_MAC);
+    CASE(CKM_RC2_MAC_GENERAL);
+    CASE(CKM_RC4);
+    CASE(CKM_RC4_KEY_GEN);
+    CASE(CKM_RC5_CBC);
+    CASE(CKM_RC5_CBC_PAD);
+    CASE(CKM_RC5_ECB);
+    CASE(CKM_RC5_KEY_GEN);
+    CASE(CKM_RC5_MAC);
+    CASE(CKM_RC5_MAC_GENERAL);
+    CASE(CKM_RIPEMD128);
+    CASE(CKM_RIPEMD128_HMAC);
+    CASE(CKM_RIPEMD128_HMAC_GENERAL);
+    CASE(CKM_RIPEMD128_RSA_PKCS);
+    CASE(CKM_RIPEMD160);
+    CASE(CKM_RIPEMD160_HMAC);
+    CASE(CKM_RIPEMD160_HMAC_GENERAL);
+    CASE(CKM_RIPEMD160_RSA_PKCS);
+    CASE(CKM_RSA_9796);
+    CASE(CKM_RSA_PKCS);
+    CASE(CKM_RSA_PKCS_KEY_PAIR_GEN);
+    CASE(CKM_RSA_PKCS_OAEP);
+    CASE(CKM_RSA_PKCS_PSS);
+    CASE(CKM_RSA_X9_31);
+    CASE(CKM_RSA_X9_31_KEY_PAIR_GEN);
+    CASE(CKM_RSA_X_509);
+    CASE(CKM_SHA1_KEY_DERIVATION);
+    CASE(CKM_SHA1_RSA_PKCS);
+    CASE(CKM_SHA1_RSA_PKCS_PSS);
+    CASE(CKM_SHA1_RSA_X9_31);
+    CASE(CKM_SHA224);
+    CASE(CKM_SHA224_HMAC);
+    CASE(CKM_SHA224_HMAC_GENERAL);
+    CASE(CKM_SHA224_KEY_DERIVATION);
+    CASE(CKM_SHA224_RSA_PKCS);
+    CASE(CKM_SHA224_RSA_PKCS_PSS);
+    CASE(CKM_SHA256);
+    CASE(CKM_SHA256_HMAC);
+    CASE(CKM_SHA256_HMAC_GENERAL);
+    CASE(CKM_SHA256_KEY_DERIVATION);
+    CASE(CKM_SHA256_RSA_PKCS);
+    CASE(CKM_SHA256_RSA_PKCS_PSS);
+    CASE(CKM_SHA384);
+    CASE(CKM_SHA384_HMAC);
+    CASE(CKM_SHA384_HMAC_GENERAL);
+    CASE(CKM_SHA384_KEY_DERIVATION);
+    CASE(CKM_SHA384_RSA_PKCS);
+    CASE(CKM_SHA384_RSA_PKCS_PSS);
+    CASE(CKM_SHA512);
+    CASE(CKM_SHA512_HMAC);
+    CASE(CKM_SHA512_HMAC_GENERAL);
+    CASE(CKM_SHA512_KEY_DERIVATION);
+    CASE(CKM_SHA512_RSA_PKCS);
+    CASE(CKM_SHA512_RSA_PKCS_PSS);
+    CASE(CKM_SHA_1);
+    CASE(CKM_SHA_1_HMAC);
+    CASE(CKM_SHA_1_HMAC_GENERAL);
+    CASE(CKM_SKIPJACK_CBC64);
+    CASE(CKM_SKIPJACK_CFB16);
+    CASE(CKM_SKIPJACK_CFB32);
+    CASE(CKM_SKIPJACK_CFB64);
+    CASE(CKM_SKIPJACK_CFB8);
+    CASE(CKM_SKIPJACK_ECB64);
+    CASE(CKM_SKIPJACK_KEY_GEN);
+    CASE(CKM_SKIPJACK_OFB64);
+    CASE(CKM_SKIPJACK_PRIVATE_WRAP);
+    CASE(CKM_SKIPJACK_RELAYX);
+    CASE(CKM_SKIPJACK_WRAP);
+    CASE(CKM_SSL3_KEY_AND_MAC_DERIVE);
+    CASE(CKM_SSL3_MASTER_KEY_DERIVE);
+    CASE(CKM_SSL3_MASTER_KEY_DERIVE_DH);
+    CASE(CKM_SSL3_MD5_MAC);
+    CASE(CKM_SSL3_PRE_MASTER_KEY_GEN);
+    CASE(CKM_SSL3_SHA1_MAC);
+    CASE(CKM_TLS_KEY_AND_MAC_DERIVE);
+    CASE(CKM_TLS_MASTER_KEY_DERIVE);
+    CASE(CKM_TLS_MASTER_KEY_DERIVE_DH);
+    CASE(CKM_TLS_PRE_MASTER_KEY_GEN);
+    CASE(CKM_TLS_PRF);
+    CASE(CKM_TWOFISH_CBC);
+    CASE(CKM_TWOFISH_KEY_GEN);
+    CASE(CKM_X9_42_DH_DERIVE);
+    CASE(CKM_X9_42_DH_HYBRID_DERIVE);
+    CASE(CKM_X9_42_DH_KEY_PAIR_GEN);
+    CASE(CKM_X9_42_DH_PARAMETER_GEN);
+    CASE(CKM_X9_42_MQV_DERIVE);
+    CASE(CKM_XOR_BASE_AND_DATA);
+    default: break;
+    }
+    if (a)
+	PR_LOG(modlog, 4, ("      mechanism = %s", a));
+    else
+	PR_LOG(modlog, 4, ("      mechanism = 0x%p", m->mechanism));
+}
+
+static void get_key_type(CK_KEY_TYPE keyType, char *str, int len)
+{
+
+    const char * a = NULL;
+
+    switch (keyType) {
+    CASE(CKK_AES);
+    CASE(CKK_CAMELLIA);
+    CASE(CKK_CDMF);
+    CASE(CKK_DES);
+    CASE(CKK_DES2);
+    CASE(CKK_DES3);
+    CASE(CKK_DH);
+    CASE(CKK_DSA);
+    CASE(CKK_EC);		/* also CASE(CKK_ECDSA); */
+    CASE(CKK_GENERIC_SECRET);
+    CASE(CKK_IDEA);
+    CASE(CKK_INVALID_KEY_TYPE);
+    CASE(CKK_KEA);
+    CASE(CKK_RC2);
+    CASE(CKK_RC4);
+    CASE(CKK_RC5);
+    CASE(CKK_RSA);
+    CASE(CKK_SKIPJACK);
+    CASE(CKK_TWOFISH);
+    CASE(CKK_X9_42_DH);
+    default: break;
+    }
+    if (a)
+	PR_snprintf(str, len, "%s", a);
+    else
+	PR_snprintf(str, len, "0x%p", keyType);
+}
+
+static void print_attr_value(CK_ATTRIBUTE_PTR attr)
+{
+    char atype[48];
+    char valstr[49];
+    int len;
+
+    get_attr_type_str(attr->type, atype, sizeof atype);
+    switch (attr->type) {
+    case CKA_ALWAYS_SENSITIVE:
+    case CKA_DECRYPT:
+    case CKA_DERIVE:
+    case CKA_ENCRYPT:
+    case CKA_EXTRACTABLE:
+    case CKA_LOCAL:
+    case CKA_MODIFIABLE:
+    case CKA_NEVER_EXTRACTABLE:
+    case CKA_PRIVATE:
+    case CKA_SENSITIVE:
+    case CKA_SIGN:
+    case CKA_SIGN_RECOVER:
+    case CKA_TOKEN:
+    case CKA_UNWRAP:
+    case CKA_VERIFY:
+    case CKA_VERIFY_RECOVER:
+    case CKA_WRAP:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    CK_BBOOL tf = *((CK_BBOOL *)attr->pValue);
+	    PR_LOG(modlog, 4, (fmt_s_s_d, 
+	           atype, tf ? "CK_TRUE" : "CK_FALSE", attr->ulValueLen));
+	    break;
+	}
+    case CKA_CLASS:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    CK_OBJECT_CLASS objClass = *((CK_OBJECT_CLASS *)attr->pValue);
+	    get_obj_class(objClass, valstr, sizeof valstr);
+	    PR_LOG(modlog, 4, (fmt_s_s_d, 
+	           atype, valstr, attr->ulValueLen));
+	    break;
+	}
+    case CKA_TRUST_CLIENT_AUTH:
+    case CKA_TRUST_CODE_SIGNING:
+    case CKA_TRUST_EMAIL_PROTECTION:
+    case CKA_TRUST_SERVER_AUTH:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    CK_TRUST trust = *((CK_TRUST *)attr->pValue);
+	    get_trust_val(trust, valstr, sizeof valstr);
+	    PR_LOG(modlog, 4, (fmt_s_s_d, 
+	           atype, valstr, attr->ulValueLen));
+	    break;
+	}
+    case CKA_KEY_TYPE:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    CK_KEY_TYPE keyType = *((CK_KEY_TYPE *)attr->pValue);
+	    get_obj_class(keyType, valstr, sizeof valstr);
+	    PR_LOG(modlog, 4, (fmt_s_s_d, 
+	           atype, valstr, attr->ulValueLen));
+	    break;
+	}
+    case CKA_LABEL:
+    case CKA_NETSCAPE_EMAIL:
+    case CKA_NETSCAPE_URL:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    len = PR_MIN(attr->ulValueLen + 1, sizeof valstr);
+	    PR_snprintf(valstr, len, "%s", attr->pValue);
+	    PR_LOG(modlog, 4, (fmt_s_qsq_d, 
+	           atype, valstr, attr->ulValueLen));
+	    break;
+	}
+    case CKA_ISSUER:
+    case CKA_SUBJECT:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    char * asciiName;
+	    SECItem derName;
+	    derName.type = siDERNameBuffer;
+	    derName.data = attr->pValue;
+	    derName.len  = attr->ulValueLen;
+	    asciiName = CERT_DerNameToAscii(&derName);
+	    if (asciiName) {
+		PR_LOG(modlog, 4, (fmt_s_s_d, 
+		       atype, asciiName, attr->ulValueLen));
+	    	PORT_Free(asciiName);
+		break;
+	    }
+	    /* else fall through and treat like a binary buffer */
+	}
+    case CKA_ID:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    unsigned char * pV = attr->pValue;
+	    for (len = (int)attr->ulValueLen; len > 0; --len) {
+		unsigned int ch = *pV++;
+		if (ch >= 0x20 && ch < 0x7f) 
+		    continue;
+		if (!ch && len == 1)  /* will ignore NUL if last character */
+		    continue;
+		break;
+	    }
+	    if (!len) {	/* entire string is printable */
+		len = PR_MIN(attr->ulValueLen + 1, sizeof valstr);
+		PR_snprintf(valstr, len, "%s", attr->pValue);
+		PR_LOG(modlog, 4, (fmt_s_qsq_d, 
+		       atype, valstr, attr->ulValueLen));
+		break;
+	    }
+	    /* else fall through and treat like a binary buffer */
+	}
+    case CKA_SERIAL_NUMBER:
+    default:
+	if (attr->ulValueLen > 0 && attr->pValue) {
+	    char * hexBuf;
+	    SECItem attrBuf;
+	    attrBuf.type = siDERNameBuffer;
+	    attrBuf.data = attr->pValue;
+	    attrBuf.len  = PR_MIN(attr->ulValueLen, (sizeof valstr)/2);
+
+	    hexBuf = CERT_Hexify(&attrBuf, PR_FALSE);
+	    if (hexBuf) {
+		PR_LOG(modlog, 4, (fmt_s_s_d, 
+		       atype, hexBuf, attr->ulValueLen));
+	    	PORT_Free(hexBuf);
+		break;
+	    }
+	    /* else fall through and show only the address. :( */
+	}
+	PR_LOG(modlog, 4, ("    %s = [0x%p] [%d]", 
+	       atype, attr->pValue, attr->ulValueLen));
+	break;
+    }
+}
+
+static void print_template(CK_ATTRIBUTE_PTR templ, CK_ULONG tlen)
+{
+    CK_ULONG i;
+    for (i=0; i<tlen; i++) {
+	print_attr_value(&templ[i]);
+    }
+}
+
+struct nssdbg_prof_str {
+    PRUint32 time;
+    PRUint32 calls;
+    char *function;
+};
+
+#define NSSDBG_DEFINE(func) { 0, 0, #func }
+
+struct nssdbg_prof_str nssdbg_prof_data[] = {
+#define FUNC_C_INITIALIZE 0
+    NSSDBG_DEFINE(C_Initialize),
+#define FUNC_C_FINALIZE 1
+    NSSDBG_DEFINE(C_Finalize),
+#define FUNC_C_GETINFO 2
+    NSSDBG_DEFINE(C_GetInfo),
+#define FUNC_C_GETFUNCITONLIST 3
+    NSSDBG_DEFINE(C_GetFunctionList),
+#define FUNC_C_GETSLOTLIST 4
+    NSSDBG_DEFINE(C_GetSlotList),
+#define FUNC_C_GETSLOTINFO 5
+    NSSDBG_DEFINE(C_GetSlotInfo),
+#define FUNC_C_GETTOKENINFO 6
+    NSSDBG_DEFINE(C_GetTokenInfo),
+#define FUNC_C_GETMECHANISMLIST 7
+    NSSDBG_DEFINE(C_GetMechanismList),
+#define FUNC_C_GETMECHANISMINFO 8
+    NSSDBG_DEFINE(C_GetMechanismInfo),
+#define FUNC_C_INITTOKEN 9
+    NSSDBG_DEFINE(C_InitToken),
+#define FUNC_C_INITPIN 10
+    NSSDBG_DEFINE(C_InitPIN),
+#define FUNC_C_SETPIN 11
+    NSSDBG_DEFINE(C_SetPIN),
+#define FUNC_C_OPENSESSION 12
+    NSSDBG_DEFINE(C_OpenSession),
+#define FUNC_C_CLOSESESSION 13
+    NSSDBG_DEFINE(C_CloseSession),
+#define FUNC_C_CLOSEALLSESSIONS 14
+    NSSDBG_DEFINE(C_CloseAllSessions),
+#define FUNC_C_GETSESSIONINFO 15
+    NSSDBG_DEFINE(C_GetSessionInfo),
+#define FUNC_C_GETOPERATIONSTATE 16
+    NSSDBG_DEFINE(C_GetOperationState),
+#define FUNC_C_SETOPERATIONSTATE 17
+    NSSDBG_DEFINE(C_SetOperationState),
+#define FUNC_C_LOGIN 18
+    NSSDBG_DEFINE(C_Login),
+#define FUNC_C_LOGOUT 19
+    NSSDBG_DEFINE(C_Logout),
+#define FUNC_C_CREATEOBJECT 20
+    NSSDBG_DEFINE(C_CreateObject),
+#define FUNC_C_COPYOBJECT 21
+    NSSDBG_DEFINE(C_CopyObject),
+#define FUNC_C_DESTROYOBJECT 22
+    NSSDBG_DEFINE(C_DestroyObject),
+#define FUNC_C_GETOBJECTSIZE  23
+    NSSDBG_DEFINE(C_GetObjectSize),
+#define FUNC_C_GETATTRIBUTEVALUE 24
+    NSSDBG_DEFINE(C_GetAttributeValue),
+#define FUNC_C_SETATTRIBUTEVALUE 25
+    NSSDBG_DEFINE(C_SetAttributeValue),
+#define FUNC_C_FINDOBJECTSINIT 26
+    NSSDBG_DEFINE(C_FindObjectsInit),
+#define FUNC_C_FINDOBJECTS 27
+    NSSDBG_DEFINE(C_FindObjects),
+#define FUNC_C_FINDOBJECTSFINAL 28
+    NSSDBG_DEFINE(C_FindObjectsFinal),
+#define FUNC_C_ENCRYPTINIT 29
+    NSSDBG_DEFINE(C_EncryptInit),
+#define FUNC_C_ENCRYPT 30
+    NSSDBG_DEFINE(C_Encrypt),
+#define FUNC_C_ENCRYPTUPDATE 31
+    NSSDBG_DEFINE(C_EncryptUpdate),
+#define FUNC_C_ENCRYPTFINAL 32
+    NSSDBG_DEFINE(C_EncryptFinal),
+#define FUNC_C_DECRYPTINIT 33
+    NSSDBG_DEFINE(C_DecryptInit),
+#define FUNC_C_DECRYPT 34
+    NSSDBG_DEFINE(C_Decrypt),
+#define FUNC_C_DECRYPTUPDATE 35
+    NSSDBG_DEFINE(C_DecryptUpdate),
+#define FUNC_C_DECRYPTFINAL 36
+    NSSDBG_DEFINE(C_DecryptFinal),
+#define FUNC_C_DIGESTINIT 37
+    NSSDBG_DEFINE(C_DigestInit),
+#define FUNC_C_DIGEST 38
+    NSSDBG_DEFINE(C_Digest),
+#define FUNC_C_DIGESTUPDATE 39
+    NSSDBG_DEFINE(C_DigestUpdate),
+#define FUNC_C_DIGESTKEY 40
+    NSSDBG_DEFINE(C_DigestKey),
+#define FUNC_C_DIGESTFINAL 41
+    NSSDBG_DEFINE(C_DigestFinal),
+#define FUNC_C_SIGNINIT 42
+    NSSDBG_DEFINE(C_SignInit),
+#define FUNC_C_SIGN 43
+    NSSDBG_DEFINE(C_Sign),
+#define FUNC_C_SIGNUPDATE 44
+    NSSDBG_DEFINE(C_SignUpdate),
+#define FUNC_C_SIGNFINAL 45
+    NSSDBG_DEFINE(C_SignFinal),
+#define FUNC_C_SIGNRECOVERINIT 46
+    NSSDBG_DEFINE(C_SignRecoverInit),
+#define FUNC_C_SIGNRECOVER 47
+    NSSDBG_DEFINE(C_SignRecover),
+#define FUNC_C_VERIFYINIT 48
+    NSSDBG_DEFINE(C_VerifyInit),
+#define FUNC_C_VERIFY 49
+    NSSDBG_DEFINE(C_Verify),
+#define FUNC_C_VERIFYUPDATE 50
+    NSSDBG_DEFINE(C_VerifyUpdate),
+#define FUNC_C_VERIFYFINAL 51
+    NSSDBG_DEFINE(C_VerifyFinal),
+#define FUNC_C_VERIFYRECOVERINIT 52
+    NSSDBG_DEFINE(C_VerifyRecoverInit),
+#define FUNC_C_VERIFYRECOVER 53
+    NSSDBG_DEFINE(C_VerifyRecover),
+#define FUNC_C_DIGESTENCRYPTUPDATE 54
+    NSSDBG_DEFINE(C_DigestEncryptUpdate),
+#define FUNC_C_DECRYPTDIGESTUPDATE 55
+    NSSDBG_DEFINE(C_DecryptDigestUpdate),
+#define FUNC_C_SIGNENCRYPTUPDATE 56
+    NSSDBG_DEFINE(C_SignEncryptUpdate),
+#define FUNC_C_DECRYPTVERIFYUPDATE 57
+    NSSDBG_DEFINE(C_DecryptVerifyUpdate),
+#define FUNC_C_GENERATEKEY 58
+    NSSDBG_DEFINE(C_GenerateKey),
+#define FUNC_C_GENERATEKEYPAIR 59
+    NSSDBG_DEFINE(C_GenerateKeyPair),
+#define FUNC_C_WRAPKEY 60
+    NSSDBG_DEFINE(C_WrapKey),
+#define FUNC_C_UNWRAPKEY 61
+    NSSDBG_DEFINE(C_UnWrapKey),
+#define FUNC_C_DERIVEKEY 62 
+    NSSDBG_DEFINE(C_DeriveKey),
+#define FUNC_C_SEEDRANDOM 63
+    NSSDBG_DEFINE(C_SeedRandom),
+#define FUNC_C_GENERATERANDOM 64
+    NSSDBG_DEFINE(C_GenerateRandom),
+#define FUNC_C_GETFUNCTIONSTATUS 65
+    NSSDBG_DEFINE(C_GetFunctionStatus),
+#define FUNC_C_CANCELFUNCTION 66
+    NSSDBG_DEFINE(C_CancelFunction),
+#define FUNC_C_WAITFORSLOTEVENT 67
+    NSSDBG_DEFINE(C_WaitForSlotEvent)
+};
+
+int nssdbg_prof_size = sizeof(nssdbg_prof_data)/sizeof(nssdbg_prof_data[0]);
+    
+
+static void nssdbg_finish_time(PRInt32 fun_number, PRIntervalTime start)
+{
+    PRIntervalTime ival;
+    PRIntervalTime end = PR_IntervalNow();
+
+    ival = end-start;
+    /* sigh, lie to PRAtomic add and say we are using signed values */
+    PR_AtomicAdd((PRInt32 *)&nssdbg_prof_data[fun_number].time, (PRInt32)ival);
+}
+
+static void nssdbg_start_time(PRInt32 fun_number, PRIntervalTime *start)
+{
+    PR_AtomicIncrement((PRInt32 *)&nssdbg_prof_data[fun_number].calls);
+    *start = PR_IntervalNow();
+}
+
+#define COMMON_DEFINITIONS \
+    CK_RV rv; \
+    PRIntervalTime start
+
+CK_RV NSSDBGC_Initialize(
+  CK_VOID_PTR pInitArgs
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Initialize"));
+    PR_LOG(modlog, 3, ("  pInitArgs = 0x%p", pInitArgs));
+    nssdbg_start_time(FUNC_C_INITIALIZE,&start);
+    rv = module_functions->C_Initialize(pInitArgs);
+    nssdbg_finish_time(FUNC_C_INITIALIZE,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Finalize(
+  CK_VOID_PTR pReserved
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Finalize"));
+    PR_LOG(modlog, 3, ("  pReserved = 0x%p", pReserved));
+    nssdbg_start_time(FUNC_C_FINALIZE,&start);
+    rv = module_functions->C_Finalize(pReserved);
+    nssdbg_finish_time(FUNC_C_FINALIZE,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetInfo(
+  CK_INFO_PTR pInfo
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetInfo"));
+    PR_LOG(modlog, 3, (fmt_pInfo, pInfo));
+    nssdbg_start_time(FUNC_C_GETINFO,&start);
+    rv = module_functions->C_GetInfo(pInfo);
+    nssdbg_finish_time(FUNC_C_GETINFO,start);
+    if (rv == CKR_OK) {
+	PR_LOG(modlog, 4, ("  cryptoki version: %d.%d", 
+			   pInfo->cryptokiVersion.major,
+			   pInfo->cryptokiVersion.minor));
+	PR_LOG(modlog, 4, (fmt_manufacturerID, pInfo->manufacturerID));
+	PR_LOG(modlog, 4, ("  library description = \"%.32s\"", 
+	                   pInfo->libraryDescription));
+	PR_LOG(modlog, 4, ("  library version: %d.%d", 
+			   pInfo->libraryVersion.major,
+			   pInfo->libraryVersion.minor));
+    }
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetFunctionList(
+  CK_FUNCTION_LIST_PTR_PTR ppFunctionList
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetFunctionList"));
+    PR_LOG(modlog, 3, ("  ppFunctionList = 0x%p", ppFunctionList));
+    nssdbg_start_time(FUNC_C_GETFUNCITONLIST,&start);
+    rv = module_functions->C_GetFunctionList(ppFunctionList);
+    nssdbg_finish_time(FUNC_C_GETFUNCITONLIST,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetSlotList(
+  CK_BBOOL       tokenPresent,
+  CK_SLOT_ID_PTR pSlotList,
+  CK_ULONG_PTR   pulCount
+)
+{
+    COMMON_DEFINITIONS;
+
+    CK_ULONG i;
+    PR_LOG(modlog, 1, ("C_GetSlotList"));
+    PR_LOG(modlog, 3, ("  tokenPresent = 0x%x", tokenPresent));
+    PR_LOG(modlog, 3, ("  pSlotList = 0x%p", pSlotList));
+    PR_LOG(modlog, 3, (fmt_pulCount, pulCount));
+    nssdbg_start_time(FUNC_C_GETSLOTLIST,&start);
+    rv = module_functions->C_GetSlotList(tokenPresent, pSlotList, pulCount);
+    nssdbg_finish_time(FUNC_C_GETSLOTLIST,start);
+    PR_LOG(modlog, 4, (fmt_spulCount, *pulCount));
+    if (pSlotList) {
+	for (i=0; i<*pulCount; i++) {
+	    PR_LOG(modlog, 4, ("  slotID[%d] = %x", i, pSlotList[i]));
+	}
+    }
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetSlotInfo(
+  CK_SLOT_ID       slotID,
+  CK_SLOT_INFO_PTR pInfo
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetSlotInfo"));
+    PR_LOG(modlog, 3, (fmt_slotID, slotID));
+    PR_LOG(modlog, 3, (fmt_pInfo, pInfo));
+    nssdbg_start_time(FUNC_C_GETSLOTINFO,&start);
+    rv = module_functions->C_GetSlotInfo(slotID, pInfo);
+    nssdbg_finish_time(FUNC_C_GETSLOTINFO,start);
+    if (rv == CKR_OK) {
+	PR_LOG(modlog, 4, ("  slotDescription = \"%.64s\"", 
+	                   pInfo->slotDescription));
+	PR_LOG(modlog, 4, (fmt_manufacturerID, pInfo->manufacturerID));
+	PR_LOG(modlog, 4, ("  flags = %s %s %s",
+	    pInfo->flags & CKF_HW_SLOT          ? "CKF_HW_SLOT" : "",
+	    pInfo->flags & CKF_REMOVABLE_DEVICE ? "CKF_REMOVABLE_DEVICE" : "",
+	    pInfo->flags & CKF_TOKEN_PRESENT    ? "CKF_TOKEN_PRESENT" : ""));
+	PR_LOG(modlog, 4, (fmt_hwVersion, 
+			    pInfo->hardwareVersion.major,
+			    pInfo->hardwareVersion.minor));
+	PR_LOG(modlog, 4, (fmt_fwVersion, 
+			    pInfo->firmwareVersion.major,
+			    pInfo->firmwareVersion.minor));
+    }
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetTokenInfo(
+  CK_SLOT_ID        slotID,
+  CK_TOKEN_INFO_PTR pInfo
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetTokenInfo"));
+    PR_LOG(modlog, 3, (fmt_slotID, slotID));
+    PR_LOG(modlog, 3, (fmt_pInfo, pInfo));
+    nssdbg_start_time(FUNC_C_GETTOKENINFO,&start);
+    rv = module_functions->C_GetTokenInfo(slotID, pInfo);
+    nssdbg_finish_time(FUNC_C_GETTOKENINFO,start);
+    if (rv == CKR_OK) {
+    	PR_LOG(modlog, 4, ("  label = \"%.32s\"", pInfo->label));
+	PR_LOG(modlog, 4, (fmt_manufacturerID, pInfo->manufacturerID));
+    	PR_LOG(modlog, 4, ("  model = \"%.16s\"", pInfo->model));
+    	PR_LOG(modlog, 4, ("  serial = \"%.16s\"", pInfo->serialNumber));
+	PR_LOG(modlog, 4, ("  flags = %s %s %s %s",
+	    pInfo->flags & CKF_RNG             ? "CKF_RNG" : "",
+	    pInfo->flags & CKF_WRITE_PROTECTED ? "CKF_WRITE_PROTECTED" : "",
+	    pInfo->flags & CKF_LOGIN_REQUIRED  ? "CKF_LOGIN_REQUIRED" : "",
+	    pInfo->flags & CKF_USER_PIN_INITIALIZED ? "CKF_USER_PIN_INIT" : ""));
+	PR_LOG(modlog, 4, ("  maxSessions = %u, Sessions = %u", 
+	                   pInfo->ulMaxSessionCount, pInfo->ulSessionCount));
+	PR_LOG(modlog, 4, ("  maxRwSessions = %u, RwSessions = %u", 
+	                   pInfo->ulMaxRwSessionCount, 
+			   pInfo->ulRwSessionCount));
+	/* ignore Max & Min Pin Len, Public and Private Memory */
+	PR_LOG(modlog, 4, (fmt_hwVersion, 
+			    pInfo->hardwareVersion.major,
+			    pInfo->hardwareVersion.minor));
+	PR_LOG(modlog, 4, (fmt_fwVersion, 
+			    pInfo->firmwareVersion.major,
+			    pInfo->firmwareVersion.minor));
+    }
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetMechanismList(
+  CK_SLOT_ID            slotID,
+  CK_MECHANISM_TYPE_PTR pMechanismList,
+  CK_ULONG_PTR          pulCount
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetMechanismList"));
+    PR_LOG(modlog, 3, (fmt_slotID, slotID));
+    PR_LOG(modlog, 3, ("  pMechanismList = 0x%p", pMechanismList));
+    PR_LOG(modlog, 3, (fmt_pulCount, pulCount));
+    nssdbg_start_time(FUNC_C_GETMECHANISMLIST,&start);
+    rv = module_functions->C_GetMechanismList(slotID,
+                                 pMechanismList,
+                                 pulCount);
+    nssdbg_finish_time(FUNC_C_GETMECHANISMLIST,start);
+    PR_LOG(modlog, 4, (fmt_spulCount, *pulCount));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetMechanismInfo(
+  CK_SLOT_ID            slotID,
+  CK_MECHANISM_TYPE     type,
+  CK_MECHANISM_INFO_PTR pInfo
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetMechanismInfo"));
+    PR_LOG(modlog, 3, (fmt_slotID, slotID));
+    PR_LOG(modlog, 3, ("  type = 0x%x", type));
+    PR_LOG(modlog, 3, (fmt_pInfo, pInfo));
+    nssdbg_start_time(FUNC_C_GETMECHANISMINFO,&start);
+    rv = module_functions->C_GetMechanismInfo(slotID,
+                                 type,
+                                 pInfo);
+    nssdbg_finish_time(FUNC_C_GETMECHANISMINFO,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_InitToken(
+  CK_SLOT_ID  slotID,
+  CK_CHAR_PTR pPin,
+  CK_ULONG    ulPinLen,
+  CK_CHAR_PTR pLabel
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_InitToken"));
+    PR_LOG(modlog, 3, (fmt_slotID, slotID));
+    PR_LOG(modlog, 3, (fmt_pPin, pPin));
+    PR_LOG(modlog, 3, (fmt_ulPinLen, ulPinLen));
+    PR_LOG(modlog, 3, ("  pLabel = 0x%p", pLabel));
+    nssdbg_start_time(FUNC_C_INITTOKEN,&start);
+    rv = module_functions->C_InitToken(slotID,
+                                 pPin,
+                                 ulPinLen,
+                                 pLabel);
+    nssdbg_finish_time(FUNC_C_INITTOKEN,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_InitPIN(
+  CK_SESSION_HANDLE hSession,
+  CK_CHAR_PTR       pPin,
+  CK_ULONG          ulPinLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_InitPIN"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pPin, pPin));
+    PR_LOG(modlog, 3, (fmt_ulPinLen, ulPinLen));
+    nssdbg_start_time(FUNC_C_INITPIN,&start);
+    rv = module_functions->C_InitPIN(hSession,
+                                 pPin,
+                                 ulPinLen);
+    nssdbg_finish_time(FUNC_C_INITPIN,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SetPIN(
+  CK_SESSION_HANDLE hSession,
+  CK_CHAR_PTR       pOldPin,
+  CK_ULONG          ulOldLen,
+  CK_CHAR_PTR       pNewPin,
+  CK_ULONG          ulNewLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SetPIN"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, ("  pOldPin = 0x%p", pOldPin));
+    PR_LOG(modlog, 3, ("  ulOldLen = %d", ulOldLen));
+    PR_LOG(modlog, 3, ("  pNewPin = 0x%p", pNewPin));
+    PR_LOG(modlog, 3, ("  ulNewLen = %d", ulNewLen));
+    nssdbg_start_time(FUNC_C_SETPIN,&start);
+    rv = module_functions->C_SetPIN(hSession,
+                                 pOldPin,
+                                 ulOldLen,
+                                 pNewPin,
+                                 ulNewLen);
+    nssdbg_finish_time(FUNC_C_SETPIN,start);
+    log_rv(rv);
+    return rv;
+}
+
+static PRUint32 numOpenSessions = 0;
+static PRUint32 maxOpenSessions = 0;
+
+CK_RV NSSDBGC_OpenSession(
+  CK_SLOT_ID            slotID,
+  CK_FLAGS              flags,
+  CK_VOID_PTR           pApplication,
+  CK_NOTIFY             Notify,
+  CK_SESSION_HANDLE_PTR phSession
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_AtomicIncrement((PRInt32 *)&numOpenSessions);
+    maxOpenSessions = PR_MAX(numOpenSessions, maxOpenSessions);
+    PR_LOG(modlog, 1, ("C_OpenSession"));
+    PR_LOG(modlog, 3, (fmt_slotID, slotID));
+    PR_LOG(modlog, 3, (fmt_flags, flags));
+    PR_LOG(modlog, 3, ("  pApplication = 0x%p", pApplication));
+    PR_LOG(modlog, 3, ("  Notify = 0x%x", Notify));
+    PR_LOG(modlog, 3, ("  phSession = 0x%p", phSession));
+    nssdbg_start_time(FUNC_C_OPENSESSION,&start);
+    rv = module_functions->C_OpenSession(slotID,
+                                 flags,
+                                 pApplication,
+                                 Notify,
+                                 phSession);
+    nssdbg_finish_time(FUNC_C_OPENSESSION,start);
+    log_handle(4, "  *phSession = 0x%x", *phSession);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_CloseSession(
+  CK_SESSION_HANDLE hSession
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_AtomicDecrement((PRInt32 *)&numOpenSessions);
+    PR_LOG(modlog, 1, ("C_CloseSession"));
+    log_handle(3, fmt_hSession, hSession);
+    nssdbg_start_time(FUNC_C_CLOSESESSION,&start);
+    rv = module_functions->C_CloseSession(hSession);
+    nssdbg_finish_time(FUNC_C_CLOSESESSION,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_CloseAllSessions(
+  CK_SLOT_ID slotID
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_CloseAllSessions"));
+    PR_LOG(modlog, 3, (fmt_slotID, slotID));
+    nssdbg_start_time(FUNC_C_CLOSEALLSESSIONS,&start);
+    rv = module_functions->C_CloseAllSessions(slotID);
+    nssdbg_finish_time(FUNC_C_CLOSEALLSESSIONS,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetSessionInfo(
+  CK_SESSION_HANDLE   hSession,
+  CK_SESSION_INFO_PTR pInfo
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetSessionInfo"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pInfo, pInfo));
+    nssdbg_start_time(FUNC_C_GETSESSIONINFO,&start);
+    rv = module_functions->C_GetSessionInfo(hSession,
+                                 pInfo);
+    nssdbg_finish_time(FUNC_C_GETSESSIONINFO,start);
+    if (rv == CKR_OK) {
+	PR_LOG(modlog, 4, (fmt_slotID, pInfo->slotID));
+	log_state(pInfo->state);
+	PR_LOG(modlog, 4, ("  flags = %s %s",
+	    pInfo->flags & CKF_RW_SESSION     ? "CKF_RW_SESSION" : "",
+	    pInfo->flags & CKF_SERIAL_SESSION ? "CKF_SERIAL_SESSION" : ""));
+	PR_LOG(modlog, 4, ("  deviceError = 0x%x", pInfo->ulDeviceError));
+    }
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetOperationState(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pOperationState,
+  CK_ULONG_PTR      pulOperationStateLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetOperationState"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pOperationState, pOperationState));
+    PR_LOG(modlog, 3, ("  pulOperationStateLen = 0x%p", pulOperationStateLen));
+    nssdbg_start_time(FUNC_C_GETOPERATIONSTATE,&start);
+    rv = module_functions->C_GetOperationState(hSession,
+                                 pOperationState,
+                                 pulOperationStateLen);
+    nssdbg_finish_time(FUNC_C_GETOPERATIONSTATE,start);
+    PR_LOG(modlog, 4, ("  *pulOperationStateLen = 0x%x", *pulOperationStateLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SetOperationState(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR      pOperationState,
+  CK_ULONG         ulOperationStateLen,
+  CK_OBJECT_HANDLE hEncryptionKey,
+  CK_OBJECT_HANDLE hAuthenticationKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SetOperationState"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pOperationState, pOperationState));
+    PR_LOG(modlog, 3, ("  ulOperationStateLen = %d", ulOperationStateLen));
+    log_handle(3, "  hEncryptionKey = 0x%x", hEncryptionKey);
+    log_handle(3, "  hAuthenticationKey = 0x%x", hAuthenticationKey);
+    nssdbg_start_time(FUNC_C_SETOPERATIONSTATE,&start);
+    rv = module_functions->C_SetOperationState(hSession,
+                                 pOperationState,
+                                 ulOperationStateLen,
+                                 hEncryptionKey,
+                                 hAuthenticationKey);
+    nssdbg_finish_time(FUNC_C_SETOPERATIONSTATE,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Login(
+  CK_SESSION_HANDLE hSession,
+  CK_USER_TYPE      userType,
+  CK_CHAR_PTR       pPin,
+  CK_ULONG          ulPinLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Login"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, ("  userType = 0x%x", userType));
+    PR_LOG(modlog, 3, (fmt_pPin, pPin));
+    PR_LOG(modlog, 3, (fmt_ulPinLen, ulPinLen));
+    nssdbg_start_time(FUNC_C_LOGIN,&start);
+    rv = module_functions->C_Login(hSession,
+                                 userType,
+                                 pPin,
+                                 ulPinLen);
+    nssdbg_finish_time(FUNC_C_LOGIN,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Logout(
+  CK_SESSION_HANDLE hSession
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Logout"));
+    log_handle(3, fmt_hSession, hSession);
+    nssdbg_start_time(FUNC_C_LOGOUT,&start);
+    rv = module_functions->C_Logout(hSession);
+    nssdbg_finish_time(FUNC_C_LOGOUT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_CreateObject(
+  CK_SESSION_HANDLE    hSession,
+  CK_ATTRIBUTE_PTR     pTemplate,
+  CK_ULONG             ulCount,
+  CK_OBJECT_HANDLE_PTR phObject
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_CreateObject"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulCount, ulCount));
+    PR_LOG(modlog, 3, (fmt_phObject, phObject));
+    print_template(pTemplate, ulCount);
+    nssdbg_start_time(FUNC_C_CREATEOBJECT,&start);
+    rv = module_functions->C_CreateObject(hSession,
+                                 pTemplate,
+                                 ulCount,
+                                 phObject);
+    nssdbg_finish_time(FUNC_C_CREATEOBJECT,start);
+    log_handle(4, "  *phObject = 0x%x", *phObject);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_CopyObject(
+  CK_SESSION_HANDLE    hSession,
+  CK_OBJECT_HANDLE     hObject,
+  CK_ATTRIBUTE_PTR     pTemplate,
+  CK_ULONG             ulCount,
+  CK_OBJECT_HANDLE_PTR phNewObject
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_CopyObject"));
+    log_handle(3, fmt_hSession, hSession);
+    log_handle(3, fmt_hObject, hObject);
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulCount, ulCount));
+    PR_LOG(modlog, 3, ("  phNewObject = 0x%p", phNewObject));
+    print_template(pTemplate, ulCount);
+    nssdbg_start_time(FUNC_C_COPYOBJECT,&start);
+    rv = module_functions->C_CopyObject(hSession,
+                                 hObject,
+                                 pTemplate,
+                                 ulCount,
+                                 phNewObject);
+    nssdbg_finish_time(FUNC_C_COPYOBJECT,start);
+    log_handle(4, "  *phNewObject = 0x%x", *phNewObject);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DestroyObject(
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE  hObject
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DestroyObject"));
+    log_handle(3, fmt_hSession, hSession);
+    log_handle(3, fmt_hObject, hObject);
+    nssdbg_start_time(FUNC_C_DESTROYOBJECT,&start);
+    rv = module_functions->C_DestroyObject(hSession,
+                                 hObject);
+    nssdbg_finish_time(FUNC_C_DESTROYOBJECT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetObjectSize(
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE  hObject,
+  CK_ULONG_PTR      pulSize
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetObjectSize"));
+    log_handle(3, fmt_hSession, hSession);
+    log_handle(3, fmt_hObject, hObject);
+    PR_LOG(modlog, 3, ("  pulSize = 0x%p", pulSize));
+    nssdbg_start_time(FUNC_C_GETOBJECTSIZE,&start);
+    rv = module_functions->C_GetObjectSize(hSession,
+                                 hObject,
+                                 pulSize);
+    nssdbg_finish_time(FUNC_C_GETOBJECTSIZE,start);
+    PR_LOG(modlog, 4, ("  *pulSize = 0x%x", *pulSize));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetAttributeValue(
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE  hObject,
+  CK_ATTRIBUTE_PTR  pTemplate,
+  CK_ULONG          ulCount
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetAttributeValue"));
+    log_handle(3, fmt_hSession, hSession);
+    log_handle(3, fmt_hObject, hObject);
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulCount, ulCount));
+    nssdbg_start_time(FUNC_C_GETATTRIBUTEVALUE,&start);
+    rv = module_functions->C_GetAttributeValue(hSession,
+                                 hObject,
+                                 pTemplate,
+                                 ulCount);
+    nssdbg_finish_time(FUNC_C_GETATTRIBUTEVALUE,start);
+    print_template(pTemplate, ulCount);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SetAttributeValue(
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE  hObject,
+  CK_ATTRIBUTE_PTR  pTemplate,
+  CK_ULONG          ulCount
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SetAttributeValue"));
+    log_handle(3, fmt_hSession, hSession);
+    log_handle(3, fmt_hObject, hObject);
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulCount, ulCount));
+    print_template(pTemplate, ulCount);
+    nssdbg_start_time(FUNC_C_SETATTRIBUTEVALUE,&start);
+    rv = module_functions->C_SetAttributeValue(hSession,
+                                 hObject,
+                                 pTemplate,
+                                 ulCount);
+    nssdbg_finish_time(FUNC_C_SETATTRIBUTEVALUE,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_FindObjectsInit(
+  CK_SESSION_HANDLE hSession,
+  CK_ATTRIBUTE_PTR  pTemplate,
+  CK_ULONG          ulCount
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_FindObjectsInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulCount, ulCount));
+    print_template(pTemplate, ulCount);
+    nssdbg_start_time(FUNC_C_FINDOBJECTSINIT,&start);
+    rv = module_functions->C_FindObjectsInit(hSession,
+                                 pTemplate,
+                                 ulCount);
+    nssdbg_finish_time(FUNC_C_FINDOBJECTSINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_FindObjects(
+  CK_SESSION_HANDLE    hSession,
+  CK_OBJECT_HANDLE_PTR phObject,
+  CK_ULONG             ulMaxObjectCount,
+  CK_ULONG_PTR         pulObjectCount
+)
+{
+    COMMON_DEFINITIONS;
+    CK_ULONG i;
+
+    PR_LOG(modlog, 1, ("C_FindObjects"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_phObject, phObject));
+    PR_LOG(modlog, 3, ("  ulMaxObjectCount = %d", ulMaxObjectCount));
+    PR_LOG(modlog, 3, ("  pulObjectCount = 0x%p", pulObjectCount));
+    nssdbg_start_time(FUNC_C_FINDOBJECTS,&start);
+    rv = module_functions->C_FindObjects(hSession,
+                                 phObject,
+                                 ulMaxObjectCount,
+                                 pulObjectCount);
+    nssdbg_finish_time(FUNC_C_FINDOBJECTS,start);
+    PR_LOG(modlog, 4, ("  *pulObjectCount = 0x%x", *pulObjectCount));
+    for (i=0; i<*pulObjectCount; i++) {
+	PR_LOG(modlog, 4, ("  phObject[%d] = 0x%x%s", i, phObject[i],
+	       phObject[i] ? "" : fmt_invalid_handle));
+    }
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_FindObjectsFinal(
+  CK_SESSION_HANDLE hSession
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_FindObjectsFinal"));
+    log_handle(3, fmt_hSession, hSession);
+    nssdbg_start_time(FUNC_C_FINDOBJECTSFINAL,&start);
+    rv = module_functions->C_FindObjectsFinal(hSession);
+    nssdbg_finish_time(FUNC_C_FINDOBJECTSFINAL,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_EncryptInit(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism,
+  CK_OBJECT_HANDLE  hKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_EncryptInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, fmt_hKey, hKey);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_ENCRYPTINIT,&start);
+    rv = module_functions->C_EncryptInit(hSession,
+                                 pMechanism,
+                                 hKey);
+    nssdbg_finish_time(FUNC_C_ENCRYPTINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Encrypt(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pData,
+  CK_ULONG          ulDataLen,
+  CK_BYTE_PTR       pEncryptedData,
+  CK_ULONG_PTR      pulEncryptedDataLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Encrypt"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pData, pData));
+    PR_LOG(modlog, 3, (fmt_ulDataLen, ulDataLen));
+    PR_LOG(modlog, 3, (fmt_pEncryptedData, pEncryptedData));
+    PR_LOG(modlog, 3, ("  pulEncryptedDataLen = 0x%p", pulEncryptedDataLen));
+    nssdbg_start_time(FUNC_C_ENCRYPT,&start);
+    rv = module_functions->C_Encrypt(hSession,
+                                 pData,
+                                 ulDataLen,
+                                 pEncryptedData,
+                                 pulEncryptedDataLen);
+    nssdbg_finish_time(FUNC_C_ENCRYPT,start);
+    PR_LOG(modlog, 4, ("  *pulEncryptedDataLen = 0x%x", *pulEncryptedDataLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_EncryptUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG          ulPartLen,
+  CK_BYTE_PTR       pEncryptedPart,
+  CK_ULONG_PTR      pulEncryptedPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_EncryptUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_ulPartLen, ulPartLen));
+    PR_LOG(modlog, 3, (fmt_pEncryptedPart, pEncryptedPart));
+    PR_LOG(modlog, 3, (fmt_pulEncryptedPartLen, pulEncryptedPartLen));
+    nssdbg_start_time(FUNC_C_ENCRYPTUPDATE,&start);
+    rv = module_functions->C_EncryptUpdate(hSession,
+                                 pPart,
+                                 ulPartLen,
+                                 pEncryptedPart,
+                                 pulEncryptedPartLen);
+    nssdbg_finish_time(FUNC_C_ENCRYPTUPDATE,start);
+    PR_LOG(modlog, 4, (fmt_spulEncryptedPartLen, *pulEncryptedPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_EncryptFinal(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pLastEncryptedPart,
+  CK_ULONG_PTR      pulLastEncryptedPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_EncryptFinal"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, ("  pLastEncryptedPart = 0x%p", pLastEncryptedPart));
+    PR_LOG(modlog, 3, ("  pulLastEncryptedPartLen = 0x%p", pulLastEncryptedPartLen));
+    nssdbg_start_time(FUNC_C_ENCRYPTFINAL,&start);
+    rv = module_functions->C_EncryptFinal(hSession,
+                                 pLastEncryptedPart,
+                                 pulLastEncryptedPartLen);
+    nssdbg_finish_time(FUNC_C_ENCRYPTFINAL,start);
+    PR_LOG(modlog, 4, ("  *pulLastEncryptedPartLen = 0x%x", *pulLastEncryptedPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DecryptInit(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism,
+  CK_OBJECT_HANDLE  hKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DecryptInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, fmt_hKey, hKey);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_DECRYPTINIT,&start);
+    rv = module_functions->C_DecryptInit(hSession,
+                                 pMechanism,
+                                 hKey);
+    nssdbg_finish_time(FUNC_C_DECRYPTINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Decrypt(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pEncryptedData,
+  CK_ULONG          ulEncryptedDataLen,
+  CK_BYTE_PTR       pData,
+  CK_ULONG_PTR      pulDataLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Decrypt"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pEncryptedData, pEncryptedData));
+    PR_LOG(modlog, 3, ("  ulEncryptedDataLen = %d", ulEncryptedDataLen));
+    PR_LOG(modlog, 3, (fmt_pData, pData));
+    PR_LOG(modlog, 3, (fmt_pulDataLen, pulDataLen));
+    nssdbg_start_time(FUNC_C_DECRYPT,&start);
+    rv = module_functions->C_Decrypt(hSession,
+                                 pEncryptedData,
+                                 ulEncryptedDataLen,
+                                 pData,
+                                 pulDataLen);
+    nssdbg_finish_time(FUNC_C_DECRYPT,start);
+    PR_LOG(modlog, 4, (fmt_spulDataLen, *pulDataLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DecryptUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pEncryptedPart,
+  CK_ULONG          ulEncryptedPartLen,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG_PTR      pulPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DecryptUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pEncryptedPart, pEncryptedPart));
+    PR_LOG(modlog, 3, (fmt_ulEncryptedPartLen, ulEncryptedPartLen));
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_pulPartLen, pulPartLen));
+    nssdbg_start_time(FUNC_C_DECRYPTUPDATE,&start);
+    rv = module_functions->C_DecryptUpdate(hSession,
+                                 pEncryptedPart,
+                                 ulEncryptedPartLen,
+                                 pPart,
+                                 pulPartLen);
+    nssdbg_finish_time(FUNC_C_DECRYPTUPDATE,start);
+    PR_LOG(modlog, 4, (fmt_spulPartLen, *pulPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DecryptFinal(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pLastPart,
+  CK_ULONG_PTR      pulLastPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DecryptFinal"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, ("  pLastPart = 0x%p", pLastPart));
+    PR_LOG(modlog, 3, ("  pulLastPartLen = 0x%p", pulLastPartLen));
+    nssdbg_start_time(FUNC_C_DECRYPTFINAL,&start);
+    rv = module_functions->C_DecryptFinal(hSession,
+                                 pLastPart,
+                                 pulLastPartLen);
+    nssdbg_finish_time(FUNC_C_DECRYPTFINAL,start);
+    PR_LOG(modlog, 4, ("  *pulLastPartLen = 0x%x", *pulLastPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DigestInit(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DigestInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_DIGESTINIT,&start);
+    rv = module_functions->C_DigestInit(hSession,
+                                 pMechanism);
+    nssdbg_finish_time(FUNC_C_DIGESTINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Digest(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pData,
+  CK_ULONG          ulDataLen,
+  CK_BYTE_PTR       pDigest,
+  CK_ULONG_PTR      pulDigestLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Digest"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pData, pData));
+    PR_LOG(modlog, 3, (fmt_ulDataLen, ulDataLen));
+    PR_LOG(modlog, 3, (fmt_pDigest, pDigest));
+    PR_LOG(modlog, 3, (fmt_pulDigestLen, pulDigestLen));
+    nssdbg_start_time(FUNC_C_DIGEST,&start);
+    rv = module_functions->C_Digest(hSession,
+                                 pData,
+                                 ulDataLen,
+                                 pDigest,
+                                 pulDigestLen);
+    nssdbg_finish_time(FUNC_C_DIGEST,start);
+    PR_LOG(modlog, 4, (fmt_spulDigestLen, *pulDigestLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DigestUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG          ulPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DigestUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_ulPartLen, ulPartLen));
+    nssdbg_start_time(FUNC_C_DIGESTUPDATE,&start);
+    rv = module_functions->C_DigestUpdate(hSession,
+                                 pPart,
+                                 ulPartLen);
+    nssdbg_finish_time(FUNC_C_DIGESTUPDATE,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DigestKey(
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE  hKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DigestKey"));
+    log_handle(3, fmt_hSession, hSession);
+    nssdbg_start_time(FUNC_C_DIGESTKEY,&start);
+    rv = module_functions->C_DigestKey(hSession,
+                                 hKey);
+    nssdbg_finish_time(FUNC_C_DIGESTKEY,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DigestFinal(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pDigest,
+  CK_ULONG_PTR      pulDigestLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DigestFinal"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pDigest, pDigest));
+    PR_LOG(modlog, 3, (fmt_pulDigestLen, pulDigestLen));
+    nssdbg_start_time(FUNC_C_DIGESTFINAL,&start);
+    rv = module_functions->C_DigestFinal(hSession,
+                                 pDigest,
+                                 pulDigestLen);
+    nssdbg_finish_time(FUNC_C_DIGESTFINAL,start);
+    PR_LOG(modlog, 4, (fmt_spulDigestLen, *pulDigestLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SignInit(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism,
+  CK_OBJECT_HANDLE  hKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SignInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, fmt_hKey, hKey);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_SIGNINIT,&start);
+    rv = module_functions->C_SignInit(hSession,
+                                 pMechanism,
+                                 hKey);
+    nssdbg_finish_time(FUNC_C_SIGNINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Sign(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pData,
+  CK_ULONG          ulDataLen,
+  CK_BYTE_PTR       pSignature,
+  CK_ULONG_PTR      pulSignatureLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Sign"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pData, pData));
+    PR_LOG(modlog, 3, (fmt_ulDataLen, ulDataLen));
+    PR_LOG(modlog, 3, (fmt_pSignature, pSignature));
+    PR_LOG(modlog, 3, (fmt_pulSignatureLen, pulSignatureLen));
+    nssdbg_start_time(FUNC_C_SIGN,&start);
+    rv = module_functions->C_Sign(hSession,
+                                 pData,
+                                 ulDataLen,
+                                 pSignature,
+                                 pulSignatureLen);
+    nssdbg_finish_time(FUNC_C_SIGN,start);
+    PR_LOG(modlog, 4, (fmt_spulSignatureLen, *pulSignatureLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SignUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG          ulPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SignUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_ulPartLen, ulPartLen));
+    nssdbg_start_time(FUNC_C_SIGNUPDATE,&start);
+    rv = module_functions->C_SignUpdate(hSession,
+                                 pPart,
+                                 ulPartLen);
+    nssdbg_finish_time(FUNC_C_SIGNUPDATE,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SignFinal(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pSignature,
+  CK_ULONG_PTR      pulSignatureLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SignFinal"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pSignature, pSignature));
+    PR_LOG(modlog, 3, (fmt_pulSignatureLen, pulSignatureLen));
+    nssdbg_start_time(FUNC_C_SIGNFINAL,&start);
+    rv = module_functions->C_SignFinal(hSession,
+                                 pSignature,
+                                 pulSignatureLen);
+    nssdbg_finish_time(FUNC_C_SIGNFINAL,start);
+    PR_LOG(modlog, 4, (fmt_spulSignatureLen, *pulSignatureLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SignRecoverInit(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism,
+  CK_OBJECT_HANDLE  hKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SignRecoverInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, fmt_hKey, hKey);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_SIGNRECOVERINIT,&start);
+    rv = module_functions->C_SignRecoverInit(hSession,
+                                 pMechanism,
+                                 hKey);
+    nssdbg_finish_time(FUNC_C_SIGNRECOVERINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SignRecover(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pData,
+  CK_ULONG          ulDataLen,
+  CK_BYTE_PTR       pSignature,
+  CK_ULONG_PTR      pulSignatureLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SignRecover"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pData, pData));
+    PR_LOG(modlog, 3, (fmt_ulDataLen, ulDataLen));
+    PR_LOG(modlog, 3, (fmt_pSignature, pSignature));
+    PR_LOG(modlog, 3, (fmt_pulSignatureLen, pulSignatureLen));
+    nssdbg_start_time(FUNC_C_SIGNRECOVER,&start);
+    rv = module_functions->C_SignRecover(hSession,
+                                 pData,
+                                 ulDataLen,
+                                 pSignature,
+                                 pulSignatureLen);
+    nssdbg_finish_time(FUNC_C_SIGNRECOVER,start);
+    PR_LOG(modlog, 4, (fmt_spulSignatureLen, *pulSignatureLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_VerifyInit(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism,
+  CK_OBJECT_HANDLE  hKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_VerifyInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, fmt_hKey, hKey);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_VERIFYINIT,&start);
+    rv = module_functions->C_VerifyInit(hSession,
+                                 pMechanism,
+                                 hKey);
+    nssdbg_finish_time(FUNC_C_VERIFYINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_Verify(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pData,
+  CK_ULONG          ulDataLen,
+  CK_BYTE_PTR       pSignature,
+  CK_ULONG          ulSignatureLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_Verify"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pData, pData));
+    PR_LOG(modlog, 3, (fmt_ulDataLen, ulDataLen));
+    PR_LOG(modlog, 3, (fmt_pSignature, pSignature));
+    PR_LOG(modlog, 3, (fmt_ulSignatureLen, ulSignatureLen));
+    nssdbg_start_time(FUNC_C_VERIFY,&start);
+    rv = module_functions->C_Verify(hSession,
+                                 pData,
+                                 ulDataLen,
+                                 pSignature,
+                                 ulSignatureLen);
+    nssdbg_finish_time(FUNC_C_VERIFY,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_VerifyUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG          ulPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_VerifyUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_ulPartLen, ulPartLen));
+    nssdbg_start_time(FUNC_C_VERIFYUPDATE,&start);
+    rv = module_functions->C_VerifyUpdate(hSession,
+                                 pPart,
+                                 ulPartLen);
+    nssdbg_finish_time(FUNC_C_VERIFYUPDATE,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_VerifyFinal(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pSignature,
+  CK_ULONG          ulSignatureLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_VerifyFinal"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pSignature, pSignature));
+    PR_LOG(modlog, 3, (fmt_ulSignatureLen, ulSignatureLen));
+    nssdbg_start_time(FUNC_C_VERIFYFINAL,&start);
+    rv = module_functions->C_VerifyFinal(hSession,
+                                 pSignature,
+                                 ulSignatureLen);
+    nssdbg_finish_time(FUNC_C_VERIFYFINAL,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_VerifyRecoverInit(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism,
+  CK_OBJECT_HANDLE  hKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_VerifyRecoverInit"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, fmt_hKey, hKey);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_VERIFYRECOVERINIT,&start);
+    rv = module_functions->C_VerifyRecoverInit(hSession,
+                                 pMechanism,
+                                 hKey);
+    nssdbg_finish_time(FUNC_C_VERIFYRECOVERINIT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_VerifyRecover(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pSignature,
+  CK_ULONG          ulSignatureLen,
+  CK_BYTE_PTR       pData,
+  CK_ULONG_PTR      pulDataLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_VerifyRecover"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pSignature, pSignature));
+    PR_LOG(modlog, 3, (fmt_ulSignatureLen, ulSignatureLen));
+    PR_LOG(modlog, 3, (fmt_pData, pData));
+    PR_LOG(modlog, 3, (fmt_pulDataLen, pulDataLen));
+    nssdbg_start_time(FUNC_C_VERIFYRECOVER,&start);
+    rv = module_functions->C_VerifyRecover(hSession,
+                                 pSignature,
+                                 ulSignatureLen,
+                                 pData,
+                                 pulDataLen);
+    nssdbg_finish_time(FUNC_C_VERIFYRECOVER,start);
+    PR_LOG(modlog, 4, (fmt_spulDataLen, *pulDataLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DigestEncryptUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG          ulPartLen,
+  CK_BYTE_PTR       pEncryptedPart,
+  CK_ULONG_PTR      pulEncryptedPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DigestEncryptUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_ulPartLen, ulPartLen));
+    PR_LOG(modlog, 3, (fmt_pEncryptedPart, pEncryptedPart));
+    PR_LOG(modlog, 3, (fmt_pulEncryptedPartLen, pulEncryptedPartLen));
+    nssdbg_start_time(FUNC_C_DIGESTENCRYPTUPDATE,&start);
+    rv = module_functions->C_DigestEncryptUpdate(hSession,
+                                 pPart,
+                                 ulPartLen,
+                                 pEncryptedPart,
+                                 pulEncryptedPartLen);
+    nssdbg_finish_time(FUNC_C_DIGESTENCRYPTUPDATE,start);
+    PR_LOG(modlog, 4, (fmt_spulEncryptedPartLen, *pulEncryptedPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DecryptDigestUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pEncryptedPart,
+  CK_ULONG          ulEncryptedPartLen,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG_PTR      pulPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DecryptDigestUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pEncryptedPart, pEncryptedPart));
+    PR_LOG(modlog, 3, (fmt_ulEncryptedPartLen, ulEncryptedPartLen));
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_pulPartLen, pulPartLen));
+    nssdbg_start_time(FUNC_C_DECRYPTDIGESTUPDATE,&start);
+    rv = module_functions->C_DecryptDigestUpdate(hSession,
+                                 pEncryptedPart,
+                                 ulEncryptedPartLen,
+                                 pPart,
+                                 pulPartLen);
+    nssdbg_finish_time(FUNC_C_DECRYPTDIGESTUPDATE,start);
+    PR_LOG(modlog, 4, (fmt_spulPartLen, *pulPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SignEncryptUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG          ulPartLen,
+  CK_BYTE_PTR       pEncryptedPart,
+  CK_ULONG_PTR      pulEncryptedPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SignEncryptUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_ulPartLen, ulPartLen));
+    PR_LOG(modlog, 3, (fmt_pEncryptedPart, pEncryptedPart));
+    PR_LOG(modlog, 3, (fmt_pulEncryptedPartLen, pulEncryptedPartLen));
+    nssdbg_start_time(FUNC_C_SIGNENCRYPTUPDATE,&start);
+    rv = module_functions->C_SignEncryptUpdate(hSession,
+                                 pPart,
+                                 ulPartLen,
+                                 pEncryptedPart,
+                                 pulEncryptedPartLen);
+    nssdbg_finish_time(FUNC_C_SIGNENCRYPTUPDATE,start);
+    PR_LOG(modlog, 4, (fmt_spulEncryptedPartLen, *pulEncryptedPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DecryptVerifyUpdate(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pEncryptedPart,
+  CK_ULONG          ulEncryptedPartLen,
+  CK_BYTE_PTR       pPart,
+  CK_ULONG_PTR      pulPartLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DecryptVerifyUpdate"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pEncryptedPart, pEncryptedPart));
+    PR_LOG(modlog, 3, (fmt_ulEncryptedPartLen, ulEncryptedPartLen));
+    PR_LOG(modlog, 3, (fmt_pPart, pPart));
+    PR_LOG(modlog, 3, (fmt_pulPartLen, pulPartLen));
+    nssdbg_start_time(FUNC_C_DECRYPTVERIFYUPDATE,&start);
+    rv = module_functions->C_DecryptVerifyUpdate(hSession,
+                                 pEncryptedPart,
+                                 ulEncryptedPartLen,
+                                 pPart,
+                                 pulPartLen);
+    nssdbg_finish_time(FUNC_C_DECRYPTVERIFYUPDATE,start);
+    PR_LOG(modlog, 4, (fmt_spulPartLen, *pulPartLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GenerateKey(
+  CK_SESSION_HANDLE    hSession,
+  CK_MECHANISM_PTR     pMechanism,
+  CK_ATTRIBUTE_PTR     pTemplate,
+  CK_ULONG             ulCount,
+  CK_OBJECT_HANDLE_PTR phKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GenerateKey"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulCount, ulCount));
+    PR_LOG(modlog, 3, (fmt_phKey, phKey));
+    print_template(pTemplate, ulCount);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_GENERATEKEY,&start);
+    rv = module_functions->C_GenerateKey(hSession,
+                                 pMechanism,
+                                 pTemplate,
+                                 ulCount,
+                                 phKey);
+    nssdbg_finish_time(FUNC_C_GENERATEKEY,start);
+    log_handle(4, fmt_sphKey, *phKey);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GenerateKeyPair(
+  CK_SESSION_HANDLE    hSession,
+  CK_MECHANISM_PTR     pMechanism,
+  CK_ATTRIBUTE_PTR     pPublicKeyTemplate,
+  CK_ULONG             ulPublicKeyAttributeCount,
+  CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,
+  CK_ULONG             ulPrivateKeyAttributeCount,
+  CK_OBJECT_HANDLE_PTR phPublicKey,
+  CK_OBJECT_HANDLE_PTR phPrivateKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GenerateKeyPair"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    PR_LOG(modlog, 3, ("  pPublicKeyTemplate = 0x%p", pPublicKeyTemplate));
+    PR_LOG(modlog, 3, ("  ulPublicKeyAttributeCount = %d", ulPublicKeyAttributeCount));
+    PR_LOG(modlog, 3, ("  pPrivateKeyTemplate = 0x%p", pPrivateKeyTemplate));
+    PR_LOG(modlog, 3, ("  ulPrivateKeyAttributeCount = %d", ulPrivateKeyAttributeCount));
+    PR_LOG(modlog, 3, ("  phPublicKey = 0x%p", phPublicKey));
+    print_template(pPublicKeyTemplate, ulPublicKeyAttributeCount);
+    PR_LOG(modlog, 3, ("  phPrivateKey = 0x%p", phPrivateKey));
+    print_template(pPrivateKeyTemplate, ulPrivateKeyAttributeCount);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_GENERATEKEYPAIR,&start);
+    rv = module_functions->C_GenerateKeyPair(hSession,
+                                 pMechanism,
+                                 pPublicKeyTemplate,
+                                 ulPublicKeyAttributeCount,
+                                 pPrivateKeyTemplate,
+                                 ulPrivateKeyAttributeCount,
+                                 phPublicKey,
+                                 phPrivateKey);
+    nssdbg_finish_time(FUNC_C_GENERATEKEYPAIR,start);
+    log_handle(4, "  *phPublicKey = 0x%x", *phPublicKey);
+    log_handle(4, "  *phPrivateKey = 0x%x", *phPrivateKey);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_WrapKey(
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR  pMechanism,
+  CK_OBJECT_HANDLE  hWrappingKey,
+  CK_OBJECT_HANDLE  hKey,
+  CK_BYTE_PTR       pWrappedKey,
+  CK_ULONG_PTR      pulWrappedKeyLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_WrapKey"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, "  hWrappingKey = 0x%x", hWrappingKey);
+    log_handle(3, fmt_hKey, hKey);
+    PR_LOG(modlog, 3, (fmt_pWrappedKey, pWrappedKey));
+    PR_LOG(modlog, 3, ("  pulWrappedKeyLen = 0x%p", pulWrappedKeyLen));
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_WRAPKEY,&start);
+    rv = module_functions->C_WrapKey(hSession,
+                                 pMechanism,
+                                 hWrappingKey,
+                                 hKey,
+                                 pWrappedKey,
+                                 pulWrappedKeyLen);
+    nssdbg_finish_time(FUNC_C_WRAPKEY,start);
+    PR_LOG(modlog, 4, ("  *pulWrappedKeyLen = 0x%x", *pulWrappedKeyLen));
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_UnwrapKey(
+  CK_SESSION_HANDLE    hSession,
+  CK_MECHANISM_PTR     pMechanism,
+  CK_OBJECT_HANDLE     hUnwrappingKey,
+  CK_BYTE_PTR          pWrappedKey,
+  CK_ULONG             ulWrappedKeyLen,
+  CK_ATTRIBUTE_PTR     pTemplate,
+  CK_ULONG             ulAttributeCount,
+  CK_OBJECT_HANDLE_PTR phKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_UnwrapKey"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, "  hUnwrappingKey = 0x%x", hUnwrappingKey);
+    PR_LOG(modlog, 3, (fmt_pWrappedKey, pWrappedKey));
+    PR_LOG(modlog, 3, ("  ulWrappedKeyLen = %d", ulWrappedKeyLen));
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulAttributeCount, ulAttributeCount));
+    PR_LOG(modlog, 3, (fmt_phKey, phKey));
+    print_template(pTemplate, ulAttributeCount);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_UNWRAPKEY,&start);
+    rv = module_functions->C_UnwrapKey(hSession,
+                                 pMechanism,
+                                 hUnwrappingKey,
+                                 pWrappedKey,
+                                 ulWrappedKeyLen,
+                                 pTemplate,
+                                 ulAttributeCount,
+                                 phKey);
+    nssdbg_finish_time(FUNC_C_UNWRAPKEY,start);
+    log_handle(4, fmt_sphKey, *phKey);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_DeriveKey(
+  CK_SESSION_HANDLE    hSession,
+  CK_MECHANISM_PTR     pMechanism,
+  CK_OBJECT_HANDLE     hBaseKey,
+  CK_ATTRIBUTE_PTR     pTemplate,
+  CK_ULONG             ulAttributeCount,
+  CK_OBJECT_HANDLE_PTR phKey
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_DeriveKey"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, (fmt_pMechanism, pMechanism));
+    log_handle(3, "  hBaseKey = 0x%x", hBaseKey);
+    PR_LOG(modlog, 3, (fmt_pTemplate, pTemplate));
+    PR_LOG(modlog, 3, (fmt_ulAttributeCount, ulAttributeCount));
+    PR_LOG(modlog, 3, (fmt_phKey, phKey));
+    print_template(pTemplate, ulAttributeCount);
+    print_mechanism(pMechanism);
+    nssdbg_start_time(FUNC_C_DERIVEKEY,&start);
+    rv = module_functions->C_DeriveKey(hSession,
+                                 pMechanism,
+                                 hBaseKey,
+                                 pTemplate,
+                                 ulAttributeCount,
+                                 phKey);
+    nssdbg_finish_time(FUNC_C_DERIVEKEY,start);
+    log_handle(4, fmt_sphKey, *phKey);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_SeedRandom(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       pSeed,
+  CK_ULONG          ulSeedLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_SeedRandom"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, ("  pSeed = 0x%p", pSeed));
+    PR_LOG(modlog, 3, ("  ulSeedLen = %d", ulSeedLen));
+    nssdbg_start_time(FUNC_C_SEEDRANDOM,&start);
+    rv = module_functions->C_SeedRandom(hSession,
+                                 pSeed,
+                                 ulSeedLen);
+    nssdbg_finish_time(FUNC_C_SEEDRANDOM,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GenerateRandom(
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR       RandomData,
+  CK_ULONG          ulRandomLen
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GenerateRandom"));
+    log_handle(3, fmt_hSession, hSession);
+    PR_LOG(modlog, 3, ("  RandomData = 0x%p", RandomData));
+    PR_LOG(modlog, 3, ("  ulRandomLen = %d", ulRandomLen));
+    nssdbg_start_time(FUNC_C_GENERATERANDOM,&start);
+    rv = module_functions->C_GenerateRandom(hSession,
+                                 RandomData,
+                                 ulRandomLen);
+    nssdbg_finish_time(FUNC_C_GENERATERANDOM,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_GetFunctionStatus(
+  CK_SESSION_HANDLE hSession
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_GetFunctionStatus"));
+    log_handle(3, fmt_hSession, hSession);
+    nssdbg_start_time(FUNC_C_GETFUNCTIONSTATUS,&start);
+    rv = module_functions->C_GetFunctionStatus(hSession);
+    nssdbg_finish_time(FUNC_C_GETFUNCTIONSTATUS,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_CancelFunction(
+  CK_SESSION_HANDLE hSession
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_CancelFunction"));
+    log_handle(3, fmt_hSession, hSession);
+    nssdbg_start_time(FUNC_C_CANCELFUNCTION,&start);
+    rv = module_functions->C_CancelFunction(hSession);
+    nssdbg_finish_time(FUNC_C_CANCELFUNCTION,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_RV NSSDBGC_WaitForSlotEvent(
+  CK_FLAGS       flags,
+  CK_SLOT_ID_PTR pSlot,
+  CK_VOID_PTR    pRserved
+)
+{
+    COMMON_DEFINITIONS;
+
+    PR_LOG(modlog, 1, ("C_WaitForSlotEvent"));
+    PR_LOG(modlog, 3, (fmt_flags, flags));
+    PR_LOG(modlog, 3, ("  pSlot = 0x%p", pSlot));
+    PR_LOG(modlog, 3, ("  pRserved = 0x%p", pRserved));
+    nssdbg_start_time(FUNC_C_WAITFORSLOTEVENT,&start);
+    rv = module_functions->C_WaitForSlotEvent(flags,
+                                 pSlot,
+                                 pRserved);
+    nssdbg_finish_time(FUNC_C_WAITFORSLOTEVENT,start);
+    log_rv(rv);
+    return rv;
+}
+
+CK_FUNCTION_LIST_PTR nss_InsertDeviceLog(
+  CK_FUNCTION_LIST_PTR devEPV
+)
+{
+    module_functions = devEPV;
+    modlog = PR_NewLogModule("nss_mod_log");
+    debug_functions.C_Initialize = NSSDBGC_Initialize;
+    debug_functions.C_Finalize = NSSDBGC_Finalize;
+    debug_functions.C_GetInfo = NSSDBGC_GetInfo;
+    debug_functions.C_GetFunctionList = NSSDBGC_GetFunctionList;
+    debug_functions.C_GetSlotList = NSSDBGC_GetSlotList;
+    debug_functions.C_GetSlotInfo = NSSDBGC_GetSlotInfo;
+    debug_functions.C_GetTokenInfo = NSSDBGC_GetTokenInfo;
+    debug_functions.C_GetMechanismList = NSSDBGC_GetMechanismList;
+    debug_functions.C_GetMechanismInfo = NSSDBGC_GetMechanismInfo;
+    debug_functions.C_InitToken = NSSDBGC_InitToken;
+    debug_functions.C_InitPIN = NSSDBGC_InitPIN;
+    debug_functions.C_SetPIN = NSSDBGC_SetPIN;
+    debug_functions.C_OpenSession = NSSDBGC_OpenSession;
+    debug_functions.C_CloseSession = NSSDBGC_CloseSession;
+    debug_functions.C_CloseAllSessions = NSSDBGC_CloseAllSessions;
+    debug_functions.C_GetSessionInfo = NSSDBGC_GetSessionInfo;
+    debug_functions.C_GetOperationState = NSSDBGC_GetOperationState;
+    debug_functions.C_SetOperationState = NSSDBGC_SetOperationState;
+    debug_functions.C_Login = NSSDBGC_Login;
+    debug_functions.C_Logout = NSSDBGC_Logout;
+    debug_functions.C_CreateObject = NSSDBGC_CreateObject;
+    debug_functions.C_CopyObject = NSSDBGC_CopyObject;
+    debug_functions.C_DestroyObject = NSSDBGC_DestroyObject;
+    debug_functions.C_GetObjectSize = NSSDBGC_GetObjectSize;
+    debug_functions.C_GetAttributeValue = NSSDBGC_GetAttributeValue;
+    debug_functions.C_SetAttributeValue = NSSDBGC_SetAttributeValue;
+    debug_functions.C_FindObjectsInit = NSSDBGC_FindObjectsInit;
+    debug_functions.C_FindObjects = NSSDBGC_FindObjects;
+    debug_functions.C_FindObjectsFinal = NSSDBGC_FindObjectsFinal;
+    debug_functions.C_EncryptInit = NSSDBGC_EncryptInit;
+    debug_functions.C_Encrypt = NSSDBGC_Encrypt;
+    debug_functions.C_EncryptUpdate = NSSDBGC_EncryptUpdate;
+    debug_functions.C_EncryptFinal = NSSDBGC_EncryptFinal;
+    debug_functions.C_DecryptInit = NSSDBGC_DecryptInit;
+    debug_functions.C_Decrypt = NSSDBGC_Decrypt;
+    debug_functions.C_DecryptUpdate = NSSDBGC_DecryptUpdate;
+    debug_functions.C_DecryptFinal = NSSDBGC_DecryptFinal;
+    debug_functions.C_DigestInit = NSSDBGC_DigestInit;
+    debug_functions.C_Digest = NSSDBGC_Digest;
+    debug_functions.C_DigestUpdate = NSSDBGC_DigestUpdate;
+    debug_functions.C_DigestKey = NSSDBGC_DigestKey;
+    debug_functions.C_DigestFinal = NSSDBGC_DigestFinal;
+    debug_functions.C_SignInit = NSSDBGC_SignInit;
+    debug_functions.C_Sign = NSSDBGC_Sign;
+    debug_functions.C_SignUpdate = NSSDBGC_SignUpdate;
+    debug_functions.C_SignFinal = NSSDBGC_SignFinal;
+    debug_functions.C_SignRecoverInit = NSSDBGC_SignRecoverInit;
+    debug_functions.C_SignRecover = NSSDBGC_SignRecover;
+    debug_functions.C_VerifyInit = NSSDBGC_VerifyInit;
+    debug_functions.C_Verify = NSSDBGC_Verify;
+    debug_functions.C_VerifyUpdate = NSSDBGC_VerifyUpdate;
+    debug_functions.C_VerifyFinal = NSSDBGC_VerifyFinal;
+    debug_functions.C_VerifyRecoverInit = NSSDBGC_VerifyRecoverInit;
+    debug_functions.C_VerifyRecover = NSSDBGC_VerifyRecover;
+    debug_functions.C_DigestEncryptUpdate = NSSDBGC_DigestEncryptUpdate;
+    debug_functions.C_DecryptDigestUpdate = NSSDBGC_DecryptDigestUpdate;
+    debug_functions.C_SignEncryptUpdate = NSSDBGC_SignEncryptUpdate;
+    debug_functions.C_DecryptVerifyUpdate = NSSDBGC_DecryptVerifyUpdate;
+    debug_functions.C_GenerateKey = NSSDBGC_GenerateKey;
+    debug_functions.C_GenerateKeyPair = NSSDBGC_GenerateKeyPair;
+    debug_functions.C_WrapKey = NSSDBGC_WrapKey;
+    debug_functions.C_UnwrapKey = NSSDBGC_UnwrapKey;
+    debug_functions.C_DeriveKey = NSSDBGC_DeriveKey;
+    debug_functions.C_SeedRandom = NSSDBGC_SeedRandom;
+    debug_functions.C_GenerateRandom = NSSDBGC_GenerateRandom;
+    debug_functions.C_GetFunctionStatus = NSSDBGC_GetFunctionStatus;
+    debug_functions.C_CancelFunction = NSSDBGC_CancelFunction;
+    debug_functions.C_WaitForSlotEvent = NSSDBGC_WaitForSlotEvent;
+    return &debug_functions;
+}
+
+/*
+ * scale the time factor up accordingly.
+ * This routine tries to keep at least 2 significant figures on output.
+ *    If the time is 0, then indicate that with a 'z' for units.
+ *    If the time is greater than 10 minutes, output the time in minutes.
+ *    If the time is less than 10 minutes but greater than 10 seconds output 
+ * the time in second.
+ *    If the time is less than 10 seconds but greater than 10 milliseconds 
+ * output * the time in millisecond.
+ *    If the time is less than 10 milliseconds but greater than 0 ticks output 
+ * the time in microsecond.
+ *
+ */
+static PRUint32 getPrintTime(PRIntervalTime time ,char **type)
+{
+	PRUint32 prTime;
+
+        /* detect a programming error by outputting 'bu' to the output stream
+	 * rather than crashing */
+ 	*type = "bug";
+	if (time == 0) {
+	    *type = "z";
+	    return 0;
+	}
+
+	prTime = PR_IntervalToSeconds(time);
+
+	if (prTime >= 600) {
+	    *type="m";
+	    return prTime/60;
+	}
+        if (prTime >= 10) {
+	    *type="s";
+	    return prTime;
+	} 
+	prTime = PR_IntervalToMilliseconds(time);
+        if (prTime >= 10) {
+	    *type="ms";
+	    return prTime;
+	} 
+ 	*type = "us";
+	return PR_IntervalToMicroseconds(time);
+}
+
+static void print_final_statistics(void)
+{
+    int total_calls = 0;
+    PRIntervalTime total_time = 0;
+    PRUint32 pr_total_time;
+    char *type;
+    char *fname;
+    FILE *outfile = NULL;
+    int i;
+
+    fname = PR_GetEnv("NSS_OUTPUT_FILE");
+    if (fname) {
+	/* need to add an optional process id to the filename */
+	outfile = fopen(fname,"w+");
+    }
+    if (!outfile) {
+	outfile = stdout;
+    }
+	
+
+    fprintf(outfile,"%-25s %10s %12s %12s %10s\n", "Function", "# Calls", 
+				"Time", "Avg.", "% Time");
+    fprintf(outfile,"\n");
+    for (i=0; i < nssdbg_prof_size; i++) {
+	total_calls += nssdbg_prof_data[i].calls;
+	total_time += nssdbg_prof_data[i].time;
+    }
+    for (i=0; i < nssdbg_prof_size; i++) {
+	PRIntervalTime time = nssdbg_prof_data[i].time;
+	PRUint32 usTime = PR_IntervalToMicroseconds(time);
+	PRUint32 prTime = 0;
+	PRUint32 calls = nssdbg_prof_data[i].calls;
+	/* don't print out functions that weren't even called */
+	if (calls == 0) {
+	    continue;
+	}
+
+	prTime = getPrintTime(time,&type);
+
+	fprintf(outfile,"%-25s %10d %10d%2s ", nssdbg_prof_data[i].function, 
+						calls, prTime, type);
+	/* for now always output the average in microseconds */
+	fprintf(outfile,"%10.2f%2s", (float)usTime / (float)calls, "us" );
+	fprintf(outfile,"%10.2f%%", ((float)time / (float)total_time) * 100);
+	fprintf(outfile,"\n");
+    }
+    fprintf(outfile,"\n");
+
+    pr_total_time = getPrintTime(total_time,&type);
+
+    fprintf(outfile,"%25s %10d %10d%2s\n", "Totals", total_calls, 
+							pr_total_time, type);
+    fprintf(outfile,"\n\nMaximum number of concurrent open sessions: %d\n\n",
+							 maxOpenSessions);
+    fflush (outfile);
+    if (outfile != stdout) {
+	fclose(outfile);
+    }
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/dev3hack.c b/mozilla/security/nss/lib/pk11wrap/dev3hack.c
new file mode 100644
index 0000000..af50b17
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/dev3hack.c
@@ -0,0 +1,339 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: dev3hack.c,v $ $Revision: 1.25 $ $Date: 2008/09/30 04:09:04 $";
+#endif /* DEBUG */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+#ifndef DEVM_H
+#include "devm.h"
+#endif /* DEVM_H */
+
+#include "pki3hack.h"
+#include "dev3hack.h"
+#include "pkim.h"
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#include "pk11func.h"
+#include "secmodti.h"
+#include "secerr.h"
+
+NSS_IMPLEMENT nssSession *
+nssSession_ImportNSS3Session(NSSArena *arenaOpt,
+                             CK_SESSION_HANDLE session, 
+                             PZLock *lock, PRBool rw)
+{
+    nssSession *rvSession = NULL;
+    if (session != CK_INVALID_SESSION) {
+	rvSession = nss_ZNEW(arenaOpt, nssSession);
+	if (rvSession) {
+	    rvSession->handle = session;
+	    rvSession->lock = lock;
+	    rvSession->ownLock = PR_FALSE;
+	    rvSession->isRW = rw;
+	}
+    }
+    return rvSession;
+}
+
+NSS_IMPLEMENT nssSession *
+nssSlot_CreateSession
+(
+  NSSSlot *slot,
+  NSSArena *arenaOpt,
+  PRBool readWrite
+)
+{
+    nssSession *rvSession;
+    rvSession = nss_ZNEW(arenaOpt, nssSession);
+    if (!rvSession) {
+	return (nssSession *)NULL;
+    }
+    if (readWrite) {
+	rvSession->handle = PK11_GetRWSession(slot->pk11slot);
+	if (rvSession->handle == CK_INVALID_HANDLE) {
+	    nss_ZFreeIf(rvSession);
+	    return NULL;
+	}
+	rvSession->isRW = PR_TRUE;
+	rvSession->slot = slot;
+        /*
+         * The session doesn't need its own lock.  Here's why.
+         * 1. If we are reusing the default RW session of the slot,
+         *    the slot lock is already locked to protect the session.
+         * 2. If the module is not thread safe, the slot (or rather
+         *    module) lock is already locked.
+         * 3. If the module is thread safe and we are using a new
+         *    session, no higher-level lock has been locked and we
+         *    would need a lock for the new session.  However, the
+         *    current usage of the session is that it is always
+         *    used and destroyed within the same function and never
+         *    shared with another thread.
+         * So the session is either already protected by another
+         * lock or only used by one thread.
+         */
+        rvSession->lock = NULL;
+        rvSession->ownLock = PR_FALSE;
+	return rvSession;
+    } else {
+	return NULL;
+    }
+}
+
+NSS_IMPLEMENT PRStatus
+nssSession_Destroy
+(
+  nssSession *s
+)
+{
+    CK_RV ckrv = CKR_OK;
+    if (s) {
+	if (s->isRW) {
+	    PK11_RestoreROSession(s->slot->pk11slot, s->handle);
+	}
+	nss_ZFreeIf(s);
+    }
+    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
+}
+
+static NSSSlot *
+nssSlot_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot)
+{
+    NSSSlot *rvSlot;
+    NSSArena *arena;
+    arena = nssArena_Create();
+    if (!arena) {
+	return NULL;
+    }
+    rvSlot = nss_ZNEW(arena, NSSSlot);
+    if (!rvSlot) {
+	nssArena_Destroy(arena);
+	return NULL;
+    }
+    rvSlot->base.refCount = 1;
+    rvSlot->base.lock = PZ_NewLock(nssILockOther);
+    rvSlot->base.arena = arena;
+    rvSlot->pk11slot = nss3slot;
+    rvSlot->epv = nss3slot->functionList;
+    rvSlot->slotID = nss3slot->slotID;
+    /* Grab the slot name from the PKCS#11 fixed-length buffer */
+    rvSlot->base.name = nssUTF8_Duplicate(nss3slot->slot_name,td->arena);
+    rvSlot->lock = (nss3slot->isThreadSafe) ? NULL : nss3slot->sessionLock;
+    return rvSlot;
+}
+
+NSSToken *
+nssToken_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot)
+{
+    NSSToken *rvToken;
+    NSSArena *arena;
+
+    /* Don't create a token object for a disabled slot */
+    if (nss3slot->disabled) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+    arena = nssArena_Create();
+    if (!arena) {
+	return NULL;
+    }
+    rvToken = nss_ZNEW(arena, NSSToken);
+    if (!rvToken) {
+	nssArena_Destroy(arena);
+	return NULL;
+    }
+    rvToken->base.refCount = 1;
+    rvToken->base.lock = PZ_NewLock(nssILockOther);
+    if (!rvToken->base.lock) {
+	nssArena_Destroy(arena);
+	return NULL;
+    }
+    rvToken->base.arena = arena;
+    rvToken->pk11slot = nss3slot;
+    rvToken->epv = nss3slot->functionList;
+    rvToken->defaultSession = nssSession_ImportNSS3Session(td->arena,
+                                                       nss3slot->session,
+                                                       nss3slot->sessionLock,
+                                                       nss3slot->defRWSession);
+#if 0 /* we should do this instead of blindly continuing. */
+    if (!rvToken->defaultSession) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+    	goto loser;
+    }
+#endif
+    if (!PK11_IsInternal(nss3slot) && PK11_IsHW(nss3slot)) {
+	rvToken->cache = nssTokenObjectCache_Create(rvToken, 
+	                                            PR_TRUE, PR_TRUE, PR_TRUE);
+	if (!rvToken->cache)
+	    goto loser;
+    }
+    rvToken->trustDomain = td;
+    /* Grab the token name from the PKCS#11 fixed-length buffer */
+    rvToken->base.name = nssUTF8_Duplicate(nss3slot->token_name,td->arena);
+    rvToken->slot = nssSlot_CreateFromPK11SlotInfo(td, nss3slot);
+    if (!rvToken->slot) {
+        goto loser;
+    }
+    rvToken->slot->token = rvToken;
+    if (rvToken->defaultSession)
+	rvToken->defaultSession->slot = rvToken->slot;
+    return rvToken;
+loser:
+    PZ_DestroyLock(rvToken->base.lock);
+    nssArena_Destroy(arena);
+    return NULL;
+}
+
+NSS_IMPLEMENT void
+nssToken_UpdateName(NSSToken *token)
+{
+    if (!token) {
+	return;
+    }
+    token->base.name = nssUTF8_Duplicate(token->pk11slot->token_name,token->base.arena);
+}
+
+NSS_IMPLEMENT PRBool
+nssSlot_IsPermanent
+(
+  NSSSlot *slot
+)
+{
+    return slot->pk11slot->isPerm;
+}
+
+NSS_IMPLEMENT PRBool
+nssSlot_IsFriendly
+(
+  NSSSlot *slot
+)
+{
+    return PK11_IsFriendly(slot->pk11slot);
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_Refresh(NSSToken *token)
+{
+    PK11SlotInfo *nss3slot;
+
+    if (!token) {
+	return PR_SUCCESS;
+    }
+    nss3slot = token->pk11slot;
+    token->defaultSession = 
+    	nssSession_ImportNSS3Session(token->slot->base.arena,
+				     nss3slot->session,
+				     nss3slot->sessionLock,
+				     nss3slot->defRWSession);
+    return token->defaultSession ? PR_SUCCESS : PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssSlot_Refresh
+(
+  NSSSlot *slot
+)
+{
+    PK11SlotInfo *nss3slot = slot->pk11slot;
+    PRBool doit = PR_FALSE;
+    if (slot->token && slot->token->base.name[0] == 0) {
+	doit = PR_TRUE;
+    }
+    if (PK11_InitToken(nss3slot, PR_FALSE) != SECSuccess) {
+	return PR_FAILURE;
+    }
+    if (doit) {
+	nssTrustDomain_UpdateCachedTokenCerts(slot->token->trustDomain, 
+	                                      slot->token);
+    }
+    return nssToken_Refresh(slot->token);
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_GetTrustOrder
+(
+  NSSToken *tok
+)
+{
+    PK11SlotInfo *slot;
+    SECMODModule *module;
+    slot = tok->pk11slot;
+    module = PK11_GetModule(slot);
+    return module->trustOrder;
+}
+
+NSS_IMPLEMENT PRBool
+nssSlot_IsLoggedIn
+(
+  NSSSlot *slot
+)
+{
+    if (!slot->pk11slot->needLogin) {
+	return PR_TRUE;
+    }
+    return PK11_IsLoggedIn(slot->pk11slot, NULL);
+}
+
+
+NSSTrustDomain *
+nssToken_GetTrustDomain(NSSToken *token)
+{
+    return token->trustDomain;
+}
+
+NSS_EXTERN PRStatus
+nssTrustDomain_RemoveTokenCertsFromCache
+(
+  NSSTrustDomain *td,
+  NSSToken *token
+);
+
+NSS_IMPLEMENT PRStatus
+nssToken_NotifyCertsNotVisible
+(
+  NSSToken *tok
+)
+{
+    return nssTrustDomain_RemoveTokenCertsFromCache(tok->trustDomain, tok);
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/dev3hack.h b/mozilla/security/nss/lib/pk11wrap/dev3hack.h
new file mode 100644
index 0000000..4a91895
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/dev3hack.h
@@ -0,0 +1,66 @@
+/* ***** 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 ***** */
+
+#ifndef DEVNSS3HACK_H
+#define DEVNSS3HACK_H
+
+#ifdef DEBUG
+static const char DEVNSS3HACK_CVS_ID[] = "@(#) $RCSfile: dev3hack.h,v $ $Revision: 1.9 $ $Date: 2005/01/20 02:25:48 $";
+#endif /* DEBUG */
+
+#include "cert.h"
+
+PR_BEGIN_EXTERN_C
+
+NSS_EXTERN NSSToken *
+nssToken_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot);
+
+NSS_EXTERN void
+nssToken_UpdateName(NSSToken *);
+
+NSS_EXTERN PRStatus
+nssToken_Refresh(NSSToken *);
+
+NSSTrustDomain *
+nssToken_GetTrustDomain(NSSToken *token);
+
+void PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst);
+
+NSSToken * PK11Slot_GetNSSToken(PK11SlotInfo *sl);
+
+PR_END_EXTERN_C
+
+#endif /* DEVNSS3HACK_H */
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11akey.c b/mozilla/security/nss/lib/pk11wrap/pk11akey.c
new file mode 100644
index 0000000..822fa6b
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11akey.c
@@ -0,0 +1,2387 @@
+/* ***** 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):
+ *   Dr Stephen Henson <stephen.henson@gemplus.com>
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * This file contains functions to manage asymetric keys, (public and
+ * private keys).
+ */
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pkcs11t.h"
+#include "pk11func.h"
+#include "cert.h"
+#include "key.h"
+#include "secitem.h"
+#include "secasn1.h" 
+#include "secoid.h" 
+#include "secerr.h"
+#include "sslerr.h"
+#include "sechash.h"
+
+#include "secpkcs5.h"  
+#include "ec.h"
+
+static SECItem *
+pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey)
+{
+    /* set the ID to the public key so we can find it again */
+    SECItem *pubKeyIndex =  NULL;
+    switch (pubKey->keyType) {
+    case rsaKey:
+      pubKeyIndex = &pubKey->u.rsa.modulus;
+      break;
+    case dsaKey:
+      pubKeyIndex = &pubKey->u.dsa.publicValue;
+      break;
+    case dhKey:
+      pubKeyIndex = &pubKey->u.dh.publicValue;
+      break;      
+    case ecKey:
+      pubKeyIndex = &pubKey->u.ec.publicValue;
+      break;      
+    default:
+      return NULL;
+    }
+    PORT_Assert(pubKeyIndex != NULL);
+
+    return PK11_MakeIDFromPubKey(pubKeyIndex);
+} 
+
+/*
+ * import a public key into the desired slot
+ *
+ * This function takes a public key structure and creates a public key in a 
+ * given slot. If isToken is set, then a persistant public key is created.
+ *
+ * Note: it is possible for this function to return a handle for a key which
+ * is persistant, even if isToken is not set.
+ */
+CK_OBJECT_HANDLE
+PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey, 
+								PRBool isToken)
+{
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
+    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+    CK_OBJECT_HANDLE objectID;
+    CK_ATTRIBUTE theTemplate[11];
+    CK_ATTRIBUTE *signedattr = NULL;
+    CK_ATTRIBUTE *attrs = theTemplate;
+    SECItem *ckaId = NULL;
+    SECItem *pubValue = NULL;
+    int signedcount = 0;
+    int templateCount = 0;
+    SECStatus rv;
+
+    /* if we already have an object in the desired slot, use it */
+    if (!isToken && pubKey->pkcs11Slot == slot) {
+	return pubKey->pkcs11ID;
+    }
+
+    /* free the existing key */
+    if (pubKey->pkcs11Slot != NULL) {
+	PK11SlotInfo *oSlot = pubKey->pkcs11Slot;
+	if (!PK11_IsPermObject(pubKey->pkcs11Slot,pubKey->pkcs11ID)) {
+	    PK11_EnterSlotMonitor(oSlot);
+	    (void) PK11_GETTAB(oSlot)->C_DestroyObject(oSlot->session,
+							pubKey->pkcs11ID);
+	    PK11_ExitSlotMonitor(oSlot);
+	}
+	PK11_FreeSlot(oSlot);
+	pubKey->pkcs11Slot = NULL;
+    }
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, isToken ? &cktrue : &ckfalse,
+						 sizeof(CK_BBOOL) ); attrs++;
+    if (isToken) {
+	ckaId = pk11_MakeIDFromPublicKey(pubKey);
+	if (ckaId == NULL) {
+	    PORT_SetError( SEC_ERROR_BAD_KEY );
+	    return CK_INVALID_HANDLE;
+	}
+	PK11_SETATTRS(attrs, CKA_ID, ckaId->data, ckaId->len); attrs++;
+    }
+
+    /* now import the key */
+    {
+        switch (pubKey->keyType) {
+        case rsaKey:
+	    keyType = CKK_RSA;
+	    PK11_SETATTRS(attrs, CKA_WRAP, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+	    PK11_SETATTRS(attrs, CKA_ENCRYPT, &cktrue, 
+						sizeof(CK_BBOOL) ); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); attrs++;
+ 	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_MODULUS, pubKey->u.rsa.modulus.data,
+					 pubKey->u.rsa.modulus.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, 
+	     	pubKey->u.rsa.publicExponent.data,
+				 pubKey->u.rsa.publicExponent.len); attrs++;
+	    break;
+        case dsaKey:
+	    keyType = CKK_DSA;
+	    PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++;
+ 	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_PRIME,    pubKey->u.dsa.params.prime.data,
+				pubKey->u.dsa.params.prime.len); attrs++;
+	    PK11_SETATTRS(attrs,CKA_SUBPRIME,pubKey->u.dsa.params.subPrime.data,
+				pubKey->u.dsa.params.subPrime.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_BASE,  pubKey->u.dsa.params.base.data,
+					pubKey->u.dsa.params.base.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VALUE,    pubKey->u.dsa.publicValue.data, 
+					pubKey->u.dsa.publicValue.len); attrs++;
+	    break;
+	case fortezzaKey:
+	    keyType = CKK_DSA;
+	    PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++;
+ 	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_PRIME,pubKey->u.fortezza.params.prime.data,
+				pubKey->u.fortezza.params.prime.len); attrs++;
+	    PK11_SETATTRS(attrs,CKA_SUBPRIME,
+				pubKey->u.fortezza.params.subPrime.data,
+				pubKey->u.fortezza.params.subPrime.len);attrs++;
+	    PK11_SETATTRS(attrs, CKA_BASE,  pubKey->u.fortezza.params.base.data,
+				pubKey->u.fortezza.params.base.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.fortezza.DSSKey.data, 
+				pubKey->u.fortezza.DSSKey.len); attrs++;
+            break;
+        case dhKey:
+	    keyType = CKK_DH;
+	    PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++;
+ 	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_PRIME,    pubKey->u.dh.prime.data,
+				pubKey->u.dh.prime.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_BASE,  pubKey->u.dh.base.data,
+					pubKey->u.dh.base.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VALUE,    pubKey->u.dh.publicValue.data, 
+					pubKey->u.dh.publicValue.len); attrs++;
+	    break;
+        case ecKey:
+	    keyType = CKK_EC;
+	    PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++;
+	    PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++;
+ 	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_EC_PARAMS, 
+		          pubKey->u.ec.DEREncodedParams.data,
+		          pubKey->u.ec.DEREncodedParams.len); attrs++;
+	    if (PR_GetEnv("NSS_USE_DECODED_CKA_EC_POINT")) {
+	    	PK11_SETATTRS(attrs, CKA_EC_POINT, 
+			  pubKey->u.ec.publicValue.data,
+			  pubKey->u.ec.publicValue.len); attrs++;
+	    } else {
+		pubValue = SEC_ASN1EncodeItem(NULL, NULL,
+			&pubKey->u.ec.publicValue,
+			SEC_ASN1_GET(SEC_OctetStringTemplate));
+		if (pubValue == NULL) {
+		    if (ckaId) {
+			SECITEM_FreeItem(ckaId,PR_TRUE);
+		    }
+		    return CK_INVALID_HANDLE;
+		}
+	    	PK11_SETATTRS(attrs, CKA_EC_POINT, 
+			  pubValue->data, pubValue->len); attrs++;
+	    }
+	    break;
+	default:
+	    PORT_SetError( SEC_ERROR_BAD_KEY );
+	    return CK_INVALID_HANDLE;
+	}
+
+	templateCount = attrs - theTemplate;
+	signedcount = attrs - signedattr;
+	PORT_Assert(templateCount <= (sizeof(theTemplate)/sizeof(CK_ATTRIBUTE)));
+	for (attrs=signedattr; signedcount; attrs++, signedcount--) {
+		pk11_SignedToUnsigned(attrs);
+	} 
+        rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate,
+				 	templateCount, isToken, &objectID);
+	if (ckaId) {
+	    SECITEM_FreeItem(ckaId,PR_TRUE);
+	}
+	if (pubValue) {
+	    SECITEM_FreeItem(pubValue,PR_TRUE);
+	}
+	if ( rv != SECSuccess) {
+	    return CK_INVALID_HANDLE;
+	}
+    }
+
+    pubKey->pkcs11ID = objectID;
+    pubKey->pkcs11Slot = PK11_ReferenceSlot(slot);
+
+    return objectID;
+}
+
+/*
+ * take an attribute and copy it into a secitem
+ */
+static CK_RV
+pk11_Attr2SecItem(PRArenaPool *arena, const CK_ATTRIBUTE *attr, SECItem *item) 
+{
+    item->data = NULL;
+
+    (void)SECITEM_AllocItem(arena, item, attr->ulValueLen);
+    if (item->data == NULL) {
+	return CKR_HOST_MEMORY;
+    } 
+    PORT_Memcpy(item->data, attr->pValue, item->len);
+    return CKR_OK;
+}
+
+
+/*
+ * get a curve length from a set of ecParams.
+ * 
+ * We need this so we can reliably determine if a the ecPoint passed to us
+ * was encoded or not. With out this, for many curves, we would incorrectly
+ * identify an unencoded curve as an encoded curve 1 in 65536 times, and for
+ * a few we would make that same mistake 1 in 32768 times. These are bad 
+ * numbers since they are rare enough to pass tests, but common enough to
+ * be tripped over in the field. 
+ *
+ * This function will only work for curves we recognized as of March 2009.
+ * The assumption is curves in use after March of 2009 would be supplied by
+ * PKCS #11 modules that already pass the correct encoding to us.
+ *
+ * Point length = (Roundup(curveLenInBits/8)*2+1)
+ */
+static int
+pk11_get_EC_PointLenInBytes(PRArenaPool *arena, const SECItem *ecParams)
+{
+   SECItem oid;
+   SECOidTag tag;
+   SECStatus rv;
+
+   /* decode the OID tag */
+   rv = SEC_QuickDERDecodeItem(arena, &oid,
+		SEC_ASN1_GET(SEC_ObjectIDTemplate), ecParams);
+   if (rv != SECSuccess) {
+	/* could be explict curves, allow them to work if the 
+	 * PKCS #11 module support them. If we try to parse the
+	 * explicit curve value in the future, we may return -1 here
+	 * to indicate an invalid parameter if the explicit curve
+	 * decode fails. */
+	return 0;
+   }
+
+   tag = SECOID_FindOIDTag(&oid);
+   switch (tag) {
+    case SEC_OID_SECG_EC_SECP112R1:
+    case SEC_OID_SECG_EC_SECP112R2:
+	return 29; /* curve len in bytes = 14 bytes */
+    case SEC_OID_SECG_EC_SECT113R1:
+    case SEC_OID_SECG_EC_SECT113R2:
+	return 31; /* curve len in bytes = 15 bytes */
+    case SEC_OID_SECG_EC_SECP128R1:
+    case SEC_OID_SECG_EC_SECP128R2:
+	return 33; /* curve len in bytes = 16 bytes */
+    case SEC_OID_SECG_EC_SECT131R1:
+    case SEC_OID_SECG_EC_SECT131R2:
+	return 35; /* curve len in bytes = 17 bytes */
+    case SEC_OID_SECG_EC_SECP160K1:
+    case SEC_OID_SECG_EC_SECP160R1:
+    case SEC_OID_SECG_EC_SECP160R2:
+	return 41; /* curve len in bytes = 20 bytes */
+    case SEC_OID_SECG_EC_SECT163K1:
+    case SEC_OID_SECG_EC_SECT163R1:
+    case SEC_OID_SECG_EC_SECT163R2:
+    case SEC_OID_ANSIX962_EC_C2PNB163V1:
+    case SEC_OID_ANSIX962_EC_C2PNB163V2:
+    case SEC_OID_ANSIX962_EC_C2PNB163V3:
+	return 43; /* curve len in bytes = 21 bytes */
+    case SEC_OID_ANSIX962_EC_C2PNB176V1:
+	return 45; /* curve len in bytes = 22 bytes */
+    case SEC_OID_ANSIX962_EC_C2TNB191V1:
+    case SEC_OID_ANSIX962_EC_C2TNB191V2:
+    case SEC_OID_ANSIX962_EC_C2TNB191V3:
+    case SEC_OID_SECG_EC_SECP192K1:
+    case SEC_OID_ANSIX962_EC_PRIME192V1:
+    case SEC_OID_ANSIX962_EC_PRIME192V2:
+    case SEC_OID_ANSIX962_EC_PRIME192V3:
+	return 49; /*curve len in bytes = 24 bytes */
+    case SEC_OID_SECG_EC_SECT193R1:
+    case SEC_OID_SECG_EC_SECT193R2:
+	return 51; /*curve len in bytes = 25 bytes */
+    case SEC_OID_ANSIX962_EC_C2PNB208W1:
+	return 53; /*curve len in bytes = 26 bytes */
+    case SEC_OID_SECG_EC_SECP224K1:
+    case SEC_OID_SECG_EC_SECP224R1:
+	return 57; /*curve len in bytes = 28 bytes */
+    case SEC_OID_SECG_EC_SECT233K1:
+    case SEC_OID_SECG_EC_SECT233R1:
+    case SEC_OID_SECG_EC_SECT239K1:
+    case SEC_OID_ANSIX962_EC_PRIME239V1:
+    case SEC_OID_ANSIX962_EC_PRIME239V2:
+    case SEC_OID_ANSIX962_EC_PRIME239V3:
+    case SEC_OID_ANSIX962_EC_C2TNB239V1:
+    case SEC_OID_ANSIX962_EC_C2TNB239V2:
+    case SEC_OID_ANSIX962_EC_C2TNB239V3:
+	return 61; /*curve len in bytes = 30 bytes */
+    case SEC_OID_ANSIX962_EC_PRIME256V1:
+    case SEC_OID_SECG_EC_SECP256K1:
+	return 65; /*curve len in bytes = 32 bytes */
+    case SEC_OID_ANSIX962_EC_C2PNB272W1:
+	return 69; /*curve len in bytes = 34 bytes */
+    case SEC_OID_SECG_EC_SECT283K1:
+    case SEC_OID_SECG_EC_SECT283R1:
+	return 73; /*curve len in bytes = 36 bytes */
+    case SEC_OID_ANSIX962_EC_C2PNB304W1:
+	return 77; /*curve len in bytes = 38 bytes */
+    case SEC_OID_ANSIX962_EC_C2TNB359V1:
+	return 91; /*curve len in bytes = 45 bytes */
+    case SEC_OID_ANSIX962_EC_C2PNB368W1:
+	return 93; /*curve len in bytes = 46 bytes */
+    case SEC_OID_SECG_EC_SECP384R1:
+	return 97; /*curve len in bytes = 48 bytes */
+    case SEC_OID_SECG_EC_SECT409K1:
+    case SEC_OID_SECG_EC_SECT409R1:
+	return 105; /*curve len in bytes = 52 bytes */
+    case SEC_OID_ANSIX962_EC_C2TNB431R1:
+	return 109; /*curve len in bytes = 54 bytes */
+    case SEC_OID_SECG_EC_SECP521R1:
+	return 133; /*curve len in bytes = 66 bytes */
+    case SEC_OID_SECG_EC_SECT571K1:
+    case SEC_OID_SECG_EC_SECT571R1:
+	return 145; /*curve len in bytes = 72 bytes */
+    /* unknown or unrecognized OIDs. return unknown length */
+    default:
+	break;
+   }
+   return 0;
+}
+
+/*
+ * returns the decoded point. In some cases the point may already be decoded.
+ * this function tries to detect those cases and return the point in 
+ * publicKeyValue. In other cases it's DER encoded. In those cases the point
+ * is first decoded and returned. Space for the point is allocated out of 
+ * the passed in arena.
+ */
+static CK_RV
+pk11_get_Decoded_ECPoint(PRArenaPool *arena, const SECItem *ecParams, 
+	const CK_ATTRIBUTE *ecPoint, SECItem *publicKeyValue)
+{
+    SECItem encodedPublicValue;
+    SECStatus rv;
+    int keyLen;
+
+    if (ecPoint->ulValueLen == 0) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    /*
+     * The PKCS #11 spec requires ecPoints to be encoded as a DER OCTET String.
+     * NSS has mistakenly passed unencoded values, and some PKCS #11 vendors
+     * followed that mistake. Now we need to detect which encoding we were
+     * passed in. The task is made more complicated by the fact the the
+     * DER encoding byte (SEC_ASN_OCTET_STRING) is the same as the 
+     * EC_POINT_FORM_UNCOMPRESSED byte (0x04), so we can't use that to
+     * determine which curve we are using.
+     */
+
+    /* get the expected key length for the passed in curve.
+     * pk11_get_EC_PointLenInBytes only returns valid values for curves
+     * NSS has traditionally recognized. If the curve is not recognized,
+     * it will return '0', and we have to figure out if the key was
+     * encoded or not heuristically. If the ecParams are invalid, it
+     * will return -1 for the keyLen.
+     */
+    keyLen = pk11_get_EC_PointLenInBytes(arena, ecParams);
+    if (keyLen < 0) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+
+    /* If the point is uncompressed and the lengths match, it
+     * must be an unencoded point */
+    if ((*((char *)ecPoint->pValue) == EC_POINT_FORM_UNCOMPRESSED) 
+	&& (ecPoint->ulValueLen == keyLen)) {
+	    return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue);
+    }
+
+    /* now assume the key passed to us was encoded and decode it */
+    if (*((char *)ecPoint->pValue) == SEC_ASN1_OCTET_STRING) {
+	/* OK, now let's try to decode it and see if it's valid */
+	encodedPublicValue.data = ecPoint->pValue;
+	encodedPublicValue.len = ecPoint->ulValueLen;
+	rv = SEC_QuickDERDecodeItem(arena, publicKeyValue,
+		SEC_ASN1_GET(SEC_OctetStringTemplate), &encodedPublicValue);
+
+	/* it coded correctly & we know the key length (and they match)
+	 * then we are done, return the results. */
+        if (keyLen && rv == SECSuccess && publicKeyValue->len == keyLen) {
+	    return CKR_OK;
+	}
+
+	/* if we know the key length, one of the above tests should have
+	 * succeded. If it doesn't the module gave us bad data */
+	if (keyLen) {
+	    return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+		
+
+	/* We don't know the key length, so we don't know deterministically
+	 * which encoding was used. We now will try to pick the most likely 
+	 * form that's correct, with a preference for the encoded form if we
+	 * can't determine for sure. We do this by checking the key we got
+	 * back from SEC_QuickDERDecodeItem for defects. If no defects are
+	 * found, we assume the encoded paramter was was passed to us.
+	 * our defect tests include:
+	 *   1) it didn't decode.
+	 *   2) The decode key had an invalid length (must be odd).
+	 *   3) The decoded key wasn't an UNCOMPRESSED key.
+	 *   4) The decoded key didn't include the entire encoded block
+	 *   except the DER encoding values. (fixing DER length to one
+	 *   particular value).
+	 */
+	if ((rv != SECSuccess)
+	    || ((publicKeyValue->len & 1) != 1)
+	    || (publicKeyValue->data[0] != EC_POINT_FORM_UNCOMPRESSED)
+	    || (PORT_Memcmp(&encodedPublicValue.data[encodedPublicValue.len -
+		 	    publicKeyValue->len], publicKeyValue->data, 
+			    publicKeyValue->len) != 0)) {
+	    /* The decoded public key was flawed, the original key must have
+	     * already been in decoded form. Do a quick sanity check then 
+	     * return the original key value.
+	     */
+	    if ((encodedPublicValue.len & 1) == 0) {
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+	    }
+	    return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue);
+	}
+
+	/* as best we can figure, the passed in key was encoded, and we've
+	 * now decoded it. Note: there is a chance this could be wrong if the 
+	 * following conditions hold:
+	 *  1) The first byte or bytes of the X point looks like a valid length
+	 * of precisely the right size (2*curveSize -1). this means for curves
+	 * less than 512 bits (64 bytes), this will happen 1 in 256 times*.
+	 * for curves between 512 and 1024, this will happen 1 in 65,536 times*
+	 * for curves between 1024 and 256K this will happen 1 in 16 million*
+	 *  2) The length of the 'DER length field' is odd 
+	 * (making both the encoded and decode
+	 * values an odd length. this is true of all curves less than 512,
+	 * as well as curves between 1024 and 256K).
+	 *  3) The X[length of the 'DER length field'] == 0x04, 1 in 256.
+	 *
+	 *  (* assuming all values are equally likely in the first byte, 
+	 * This isn't true if the curve length is not a multiple of 8. In these
+	 * cases, if the DER length is possible, it's more likely, 
+	 * if it's not possible, then we have no false decodes).
+	 * 
+	 * For reference here are the odds for the various curves we currently
+	 * have support for (and the only curves SSL will negotiate at this
+	 * time). NOTE: None of the supported curves will show up here 
+	 * because we return a valid length for all of these curves. 
+	 * The only way to get here is to have some application (not SSL) 
+	 * which supports some unknown curve and have some vendor supplied 
+	 * PKCS #11 module support that curve. NOTE: in this case, one 
+	 * presumes that that pkcs #11 module is likely to be using the 
+	 * correct encodings.
+	 *
+	 * Prime Curves (GFp):
+	 *   Bit	False	    Odds of 
+	 *  Size	DER Len	 False Decode Positive
+	 *  112 	27	   1 in 65536 
+	 *  128 	31	   1 in 65536 
+	 *  160 	39	   1 in 65536 
+	 *  192 	47	   1 in 65536 
+	 *  224 	55	   1 in 65536 
+	 *  239 	59	   1 in 32768 (top byte can only be 0-127)
+	 *  256 	63	   1 in 65536 
+	 *  521 	129,131	     0        (decoded value would be even)
+	 *
+	 * Binary curves (GF2m).
+	 *   Bit	False	    Odds of 
+	 *  Size	DER Len	 False Decode Positive
+	 *  131 	33	     0        (top byte can only be 0-7)
+	 *  163 	41	     0        (top byte can only be 0-7)
+	 *  176 	43	   1 in 65536 
+	 *  191 	47	   1 in 32768 (top byte can only be 0-127)
+	 *  193 	49	     0        (top byte can only be 0-1)
+	 *  208 	51	   1 in 65536 
+	 *  233 	59	     0        (top byte can only be 0-1)
+	 *  239 	59	   1 in 32768 (top byte can only be 0-127)
+	 *  272 	67	   1 in 65536 
+	 *  283 	71	     0        (top byte can only be 0-7)
+	 *  304 	75	   1 in 65536 
+	 *  359 	89	   1 in 32768 (top byte can only be 0-127)
+	 *  368 	91	   1 in 65536 
+	 *  409 	103	     0        (top byte can only be 0-1)
+	 *  431 	107	   1 in 32768 (top byte can only be 0-127)
+	 *  571 	129,143	     0        (decoded value would be even)
+	 *
+	 */
+
+	return CKR_OK;
+    }
+
+    /* In theory, we should handle the case where the curve == 0 and
+     * the first byte is EC_POINT_FORM_UNCOMPRESSED, (which would be
+     * handled by doing a santity check on the key length and returning
+     * pk11_Attr2SecItem() to copy the ecPoint to the publicKeyValue).
+     *
+     * This test is unnecessary, however, due to the fact that 
+     * EC_POINT_FORM_UNCOMPRESSED == SEC_ASIN1_OCTET_STRING, that case is
+     * handled in the above if. That means if we get here, the initial
+     * byte of our ecPoint value was invalid, so we can safely return.
+     * invalid attribute.
+     */
+	
+    return CKR_ATTRIBUTE_VALUE_INVALID;
+}
+
+/*
+ * extract a public key from a slot and id
+ */
+SECKEYPublicKey *
+PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id)
+{
+    CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
+    PRArenaPool *arena;
+    PRArenaPool *tmp_arena;
+    SECKEYPublicKey *pubKey;
+    int templateCount = 0;
+    CK_KEY_TYPE pk11KeyType;
+    CK_RV crv;
+    CK_ATTRIBUTE template[8];
+    CK_ATTRIBUTE *attrs= template;
+    CK_ATTRIBUTE *modulus,*exponent,*base,*prime,*subprime,*value;
+    CK_ATTRIBUTE *ecparams;
+
+    /* if we didn't know the key type, get it */
+    if (keyType== nullKey) {
+
+        pk11KeyType = PK11_ReadULongAttribute(slot,id,CKA_KEY_TYPE);
+	if (pk11KeyType ==  CK_UNAVAILABLE_INFORMATION) {
+	    return NULL;
+	}
+	switch (pk11KeyType) {
+	case CKK_RSA:
+	    keyType = rsaKey;
+	    break;
+	case CKK_DSA:
+	    keyType = dsaKey;
+	    break;
+	case CKK_DH:
+	    keyType = dhKey;
+	    break;
+	case CKK_EC:
+	    keyType = ecKey;
+	    break;
+	default:
+	    PORT_SetError( SEC_ERROR_BAD_KEY );
+	    return NULL;
+	}
+    }
+
+
+    /* now we need to create space for the public key */
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) return NULL;
+    tmp_arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (tmp_arena == NULL) {
+	PORT_FreeArena (arena, PR_FALSE);
+	return NULL;
+    }
+
+
+    pubKey = (SECKEYPublicKey *) 
+			PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
+    if (pubKey == NULL) {
+	PORT_FreeArena (arena, PR_FALSE);
+	PORT_FreeArena (tmp_arena, PR_FALSE);
+	return NULL;
+    }
+
+    pubKey->arena = arena;
+    pubKey->keyType = keyType;
+    pubKey->pkcs11Slot = PK11_ReferenceSlot(slot);
+    pubKey->pkcs11ID = id;
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, 
+						sizeof(keyClass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &pk11KeyType, 
+						sizeof(pk11KeyType) ); attrs++;
+    switch (pubKey->keyType) {
+    case rsaKey:
+	modulus = attrs;
+	PK11_SETATTRS(attrs, CKA_MODULUS, NULL, 0); attrs++; 
+	exponent = attrs;
+	PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, NULL, 0); attrs++; 
+
+	templateCount = attrs - template;
+	PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
+	crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount);
+	if (crv != CKR_OK) break;
+
+	if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_RSA)) {
+	    crv = CKR_OBJECT_HANDLE_INVALID;
+	    break;
+	} 
+	crv = pk11_Attr2SecItem(arena,modulus,&pubKey->u.rsa.modulus);
+	if (crv != CKR_OK) break;
+	crv = pk11_Attr2SecItem(arena,exponent,&pubKey->u.rsa.publicExponent);
+	if (crv != CKR_OK) break;
+	break;
+    case dsaKey:
+	prime = attrs;
+	PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; 
+	subprime = attrs;
+	PK11_SETATTRS(attrs, CKA_SUBPRIME, NULL, 0); attrs++; 
+	base = attrs;
+	PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; 
+	value = attrs;
+	PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; 
+	templateCount = attrs - template;
+	PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
+	crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount);
+	if (crv != CKR_OK) break;
+
+	if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DSA)) {
+	    crv = CKR_OBJECT_HANDLE_INVALID;
+	    break;
+	} 
+	crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dsa.params.prime);
+	if (crv != CKR_OK) break;
+	crv = pk11_Attr2SecItem(arena,subprime,&pubKey->u.dsa.params.subPrime);
+	if (crv != CKR_OK) break;
+	crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dsa.params.base);
+	if (crv != CKR_OK) break;
+	crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dsa.publicValue);
+	if (crv != CKR_OK) break;
+	break;
+    case dhKey:
+	prime = attrs;
+	PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; 
+	base = attrs;
+	PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; 
+	value =attrs;
+	PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; 
+	templateCount = attrs - template;
+	PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
+	crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount);
+	if (crv != CKR_OK) break;
+
+	if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DH)) {
+	    crv = CKR_OBJECT_HANDLE_INVALID;
+	    break;
+	} 
+	crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dh.prime);
+	if (crv != CKR_OK) break;
+	crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dh.base);
+	if (crv != CKR_OK) break;
+	crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dh.publicValue);
+	if (crv != CKR_OK) break;
+	break;
+    case ecKey:
+	pubKey->u.ec.size = 0;
+	ecparams = attrs;
+	PK11_SETATTRS(attrs, CKA_EC_PARAMS, NULL, 0); attrs++; 
+	value =attrs;
+	PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++; 
+	templateCount = attrs - template;
+	PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
+	crv = PK11_GetAttributes(arena,slot,id,template,templateCount);
+	if (crv != CKR_OK) break;
+
+	if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) {
+	    crv = CKR_OBJECT_HANDLE_INVALID;
+	    break;
+	} 
+
+	crv = pk11_Attr2SecItem(arena,ecparams,
+	                        &pubKey->u.ec.DEREncodedParams);
+	if (crv != CKR_OK) break;
+	crv = pk11_get_Decoded_ECPoint(arena,
+		 &pubKey->u.ec.DEREncodedParams, value, 
+		 &pubKey->u.ec.publicValue);
+	break;
+    case fortezzaKey:
+    case nullKey:
+    default:
+	crv = CKR_OBJECT_HANDLE_INVALID;
+	break;
+    }
+
+    PORT_FreeArena(tmp_arena,PR_FALSE);
+
+    if (crv != CKR_OK) {
+	PORT_FreeArena(arena,PR_FALSE);
+	PK11_FreeSlot(slot);
+	PORT_SetError( PK11_MapError(crv) );
+	return NULL;
+    }
+
+    return pubKey;
+}
+
+/*
+ * Build a Private Key structure from raw PKCS #11 information.
+ */
+SECKEYPrivateKey *
+PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, 
+			PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx)
+{
+    PRArenaPool *arena;
+    SECKEYPrivateKey *privKey;
+    PRBool isPrivate;
+    SECStatus rv;
+
+    /* don't know? look it up */
+    if (keyType == nullKey) {
+	CK_KEY_TYPE pk11Type = CKK_RSA;
+
+	pk11Type = PK11_ReadULongAttribute(slot,privID,CKA_KEY_TYPE);
+	isTemp = (PRBool)!PK11_HasAttributeSet(slot,privID,CKA_TOKEN);
+	switch (pk11Type) {
+	case CKK_RSA: keyType = rsaKey; break;
+	case CKK_DSA: keyType = dsaKey; break;
+	case CKK_DH: keyType = dhKey; break;
+	case CKK_KEA: keyType = fortezzaKey; break;
+	case CKK_EC: keyType = ecKey; break;
+	default:
+		break;
+	}
+    }
+
+    /* if the key is private, make sure we are authenticated to the
+     * token before we try to use it */
+    isPrivate = (PRBool)PK11_HasAttributeSet(slot,privID,CKA_PRIVATE);
+    if (isPrivate) {
+	rv = PK11_Authenticate(slot, PR_TRUE, wincx);
+ 	if (rv != SECSuccess) {
+ 	    return NULL;
+ 	}
+    }
+
+    /* now we need to create space for the private key */
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) return NULL;
+
+    privKey = (SECKEYPrivateKey *) 
+			PORT_ArenaZAlloc(arena, sizeof(SECKEYPrivateKey));
+    if (privKey == NULL) {
+	PORT_FreeArena(arena, PR_FALSE);
+	return NULL;
+    }
+
+    privKey->arena = arena;
+    privKey->keyType = keyType;
+    privKey->pkcs11Slot = PK11_ReferenceSlot(slot);
+    privKey->pkcs11ID = privID;
+    privKey->pkcs11IsTemp = isTemp;
+    privKey->wincx = wincx;
+
+    return privKey;
+}
+
+
+PK11SlotInfo *
+PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key)
+{
+    PK11SlotInfo *slot = key->pkcs11Slot;
+    slot = PK11_ReferenceSlot(slot);
+    return slot;
+}
+
+/*
+ * Get the modulus length for raw parsing
+ */
+int
+PK11_GetPrivateModulusLen(SECKEYPrivateKey *key)
+{
+    CK_ATTRIBUTE theTemplate = { CKA_MODULUS, NULL, 0 };
+    PK11SlotInfo *slot = key->pkcs11Slot;
+    CK_RV crv;
+    int length;
+
+    switch (key->keyType) {
+    case rsaKey:
+	crv = PK11_GetAttributes(NULL, slot, key->pkcs11ID, &theTemplate, 1);
+	if (crv != CKR_OK) {
+	    PORT_SetError( PK11_MapError(crv) );
+	    return -1;
+	}
+	length = theTemplate.ulValueLen;
+	if ( *(unsigned char *)theTemplate.pValue == 0) {
+	    length--;
+	}
+	if (theTemplate.pValue != NULL)
+	    PORT_Free(theTemplate.pValue);
+	return (int) length;
+	
+    case fortezzaKey:
+    case dsaKey:
+    case dhKey:
+    default:
+	break;
+    }
+    if (theTemplate.pValue != NULL)
+	PORT_Free(theTemplate.pValue);
+    PORT_SetError( SEC_ERROR_INVALID_KEY );
+    return -1;
+}
+
+
+
+/*
+ * take a private key in one pkcs11 module and load it into another:
+ *  NOTE: the source private key is a rare animal... it can't be sensitive.
+ *  This is used to do a key gen using one pkcs11 module and storing the
+ *  result into another.
+ */
+static SECKEYPrivateKey *
+pk11_loadPrivKeyWithFlags(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, 
+		SECKEYPublicKey *pubKey, PK11AttrFlags attrFlags) 
+{
+    CK_ATTRIBUTE privTemplate[] = {
+        /* class must be first */
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_KEY_TYPE, NULL, 0 },
+	{ CKA_ID, NULL, 0 },
+	/* RSA - the attributes below will be replaced for other 
+	 *       key types.
+	 */
+	{ CKA_MODULUS, NULL, 0 },
+	{ CKA_PRIVATE_EXPONENT, NULL, 0 },
+	{ CKA_PUBLIC_EXPONENT, NULL, 0 },
+	{ CKA_PRIME_1, NULL, 0 },
+	{ CKA_PRIME_2, NULL, 0 },
+	{ CKA_EXPONENT_1, NULL, 0 },
+	{ CKA_EXPONENT_2, NULL, 0 },
+	{ CKA_COEFFICIENT, NULL, 0 },
+	{ CKA_DECRYPT, NULL, 0 },
+	{ CKA_DERIVE, NULL, 0 },
+	{ CKA_SIGN, NULL, 0 },
+	{ CKA_SIGN_RECOVER, NULL, 0 },
+	{ CKA_UNWRAP, NULL, 0 },
+	/* reserve space for the attributes that may be
+	 * specified in attrFlags */
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_PRIVATE, NULL, 0 },
+	{ CKA_MODIFIABLE, NULL, 0 },
+	{ CKA_SENSITIVE, NULL, 0 },
+	{ CKA_EXTRACTABLE, NULL, 0 },
+#define NUM_RESERVED_ATTRS 5    /* number of reserved attributes above */
+    };
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_ATTRIBUTE *attrs = NULL, *ap;
+    const int templateSize = sizeof(privTemplate)/sizeof(privTemplate[0]);
+    PRArenaPool *arena;
+    CK_OBJECT_HANDLE objectID;
+    int i, count = 0;
+    int extra_count = 0;
+    CK_RV crv;
+    SECStatus rv;
+    PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0);
+
+    if (pk11_BadAttrFlags(attrFlags)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    for (i=0; i < templateSize; i++) {
+	if (privTemplate[i].type == CKA_MODULUS) {
+	    attrs= &privTemplate[i];
+	    count = i;
+	    break;
+	}
+    }
+    PORT_Assert(attrs != NULL);
+    if (attrs == NULL) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return NULL;
+    }
+
+    ap = attrs;
+
+    switch (privKey->keyType) {
+    case rsaKey:
+	count = templateSize - NUM_RESERVED_ATTRS;
+	extra_count = count - (attrs - privTemplate);
+	break;
+    case dsaKey:
+	ap->type = CKA_PRIME; ap++; count++; extra_count++;
+	ap->type = CKA_SUBPRIME; ap++; count++; extra_count++;
+	ap->type = CKA_BASE; ap++; count++; extra_count++;
+	ap->type = CKA_VALUE; ap++; count++; extra_count++;
+	ap->type = CKA_SIGN; ap++; count++; extra_count++;
+	break;
+    case dhKey:
+	ap->type = CKA_PRIME; ap++; count++; extra_count++;
+	ap->type = CKA_BASE; ap++; count++; extra_count++;
+	ap->type = CKA_VALUE; ap++; count++; extra_count++;
+	ap->type = CKA_DERIVE; ap++; count++; extra_count++;
+	break;
+    case ecKey:
+	ap->type = CKA_EC_PARAMS; ap++; count++; extra_count++;
+	ap->type = CKA_VALUE; ap++; count++; extra_count++;
+	ap->type = CKA_DERIVE; ap++; count++; extra_count++;
+	ap->type = CKA_SIGN; ap++; count++; extra_count++;
+	break;
+     default:
+	count = 0;
+	extra_count = 0;
+	break;
+     }
+
+     if (count == 0) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return NULL;
+     }
+
+     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+     if (arena == NULL) return NULL;
+     /*
+      * read out the old attributes.
+      */
+     crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID,
+		privTemplate,count);
+     if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	PORT_FreeArena(arena, PR_TRUE);
+	return NULL;
+     }
+
+     /* Set token, private, modifiable, sensitive, and extractable */
+     count += pk11_AttrFlagsToAttributes(attrFlags, &privTemplate[count],
+					&cktrue, &ckfalse);
+
+     /* Not everyone can handle zero padded key values, give
+      * them the raw data as unsigned */
+     for (ap=attrs; extra_count; ap++, extra_count--) {
+	pk11_SignedToUnsigned(ap);
+     }
+
+     /* now Store the puppies */
+     rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, privTemplate, 
+						count, token, &objectID);
+     PORT_FreeArena(arena, PR_TRUE);
+     if (rv != SECSuccess) {
+	return NULL;
+     }
+
+     /* try loading the public key */
+     if (pubKey) {
+	PK11_ImportPublicKey(slot, pubKey, token);
+	if (pubKey->pkcs11Slot) {
+	    PK11_FreeSlot(pubKey->pkcs11Slot);
+	    pubKey->pkcs11Slot = NULL;
+	    pubKey->pkcs11ID = CK_INVALID_HANDLE;
+	}
+     }
+
+     /* build new key structure */
+     return PK11_MakePrivKey(slot, privKey->keyType, !token, 
+						objectID, privKey->wincx);
+}
+
+static SECKEYPrivateKey *
+pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, 
+		SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) 
+{
+    PK11AttrFlags attrFlags = 0;
+    if (token) {
+	attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
+    } else {
+	attrFlags |= (PK11_ATTR_SESSION | PK11_ATTR_PUBLIC);
+    }
+    if (sensitive) {
+	attrFlags |= PK11_ATTR_SENSITIVE;
+    } else {
+	attrFlags |= PK11_ATTR_INSENSITIVE;
+    }
+    return pk11_loadPrivKeyWithFlags(slot, privKey, pubKey, attrFlags);
+}
+
+/*
+ * export this for PSM
+ */
+SECKEYPrivateKey *
+PK11_LoadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, 
+		SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) 
+{
+    return pk11_loadPrivKey(slot,privKey,pubKey,token,sensitive);
+}
+
+
+/*
+ * Use the token to generate a key pair.
+ */
+SECKEYPrivateKey *
+PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 
+   void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, 
+   CK_FLAGS opFlags, CK_FLAGS opFlagsMask, void *wincx)
+{
+    /* we have to use these native types because when we call PKCS 11 modules
+     * we have to make sure that we are using the correct sizes for all the
+     * parameters. */
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_ULONG modulusBits;
+    CK_BYTE publicExponent[4];
+    CK_ATTRIBUTE privTemplate[] = {
+	{ CKA_SENSITIVE, NULL, 0},
+	{ CKA_TOKEN,  NULL, 0},
+	{ CKA_PRIVATE,  NULL, 0},
+	{ CKA_DERIVE,  NULL, 0},
+	{ CKA_UNWRAP,  NULL, 0},
+	{ CKA_SIGN,  NULL, 0},
+	{ CKA_DECRYPT,  NULL, 0},
+	{ CKA_EXTRACTABLE, NULL, 0},
+	{ CKA_MODIFIABLE,  NULL, 0},
+    };
+    CK_ATTRIBUTE rsaPubTemplate[] = {
+	{ CKA_MODULUS_BITS, NULL, 0},
+	{ CKA_PUBLIC_EXPONENT, NULL, 0},
+	{ CKA_TOKEN,  NULL, 0},
+	{ CKA_DERIVE,  NULL, 0},
+	{ CKA_WRAP,  NULL, 0},
+	{ CKA_VERIFY,  NULL, 0},
+	{ CKA_VERIFY_RECOVER,  NULL, 0},
+	{ CKA_ENCRYPT,  NULL, 0},
+	{ CKA_MODIFIABLE,  NULL, 0},
+    };
+    CK_ATTRIBUTE dsaPubTemplate[] = {
+	{ CKA_PRIME, NULL, 0 },
+	{ CKA_SUBPRIME, NULL, 0 },
+	{ CKA_BASE, NULL, 0 },
+	{ CKA_TOKEN,  NULL, 0},
+	{ CKA_DERIVE,  NULL, 0},
+	{ CKA_WRAP,  NULL, 0},
+	{ CKA_VERIFY,  NULL, 0},
+	{ CKA_VERIFY_RECOVER,  NULL, 0},
+	{ CKA_ENCRYPT,  NULL, 0},
+	{ CKA_MODIFIABLE,  NULL, 0},
+    };
+    CK_ATTRIBUTE dhPubTemplate[] = {
+      { CKA_PRIME, NULL, 0 }, 
+      { CKA_BASE, NULL, 0 }, 
+      { CKA_TOKEN,  NULL, 0},
+      { CKA_DERIVE,  NULL, 0},
+      { CKA_WRAP,  NULL, 0},
+      { CKA_VERIFY,  NULL, 0},
+      { CKA_VERIFY_RECOVER,  NULL, 0},
+      { CKA_ENCRYPT,  NULL, 0},
+      { CKA_MODIFIABLE,  NULL, 0},
+    };
+    CK_ATTRIBUTE ecPubTemplate[] = {
+      { CKA_EC_PARAMS, NULL, 0 }, 
+      { CKA_TOKEN,  NULL, 0},
+      { CKA_DERIVE,  NULL, 0},
+      { CKA_WRAP,  NULL, 0},
+      { CKA_VERIFY,  NULL, 0},
+      { CKA_VERIFY_RECOVER,  NULL, 0},
+      { CKA_ENCRYPT,  NULL, 0},
+      { CKA_MODIFIABLE,  NULL, 0},
+    };
+    SECKEYECParams * ecParams;
+
+    /*CK_ULONG key_size = 0;*/
+    CK_ATTRIBUTE *pubTemplate;
+    int privCount = 0;
+    int pubCount = 0;
+    PK11RSAGenParams *rsaParams;
+    SECKEYPQGParams *dsaParams;
+    SECKEYDHParams * dhParams;
+    CK_MECHANISM mechanism;
+    CK_MECHANISM test_mech;
+    CK_MECHANISM test_mech2;
+    CK_SESSION_HANDLE session_handle;
+    CK_RV crv;
+    CK_OBJECT_HANDLE privID,pubID;
+    SECKEYPrivateKey *privKey;
+    KeyType keyType;
+    PRBool restore;
+    int peCount,i;
+    CK_ATTRIBUTE *attrs;
+    CK_ATTRIBUTE *privattrs;
+    CK_ATTRIBUTE setTemplate;
+    CK_MECHANISM_INFO mechanism_info;
+    CK_OBJECT_CLASS keyClass;
+    SECItem *cka_id;
+    PRBool haslock = PR_FALSE;
+    PRBool pubIsToken = PR_FALSE;
+    PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0);
+    /* subset of attrFlags applicable to the public key */
+    PK11AttrFlags pubKeyAttrFlags = attrFlags &
+	(PK11_ATTR_TOKEN | PK11_ATTR_SESSION
+	| PK11_ATTR_MODIFIABLE | PK11_ATTR_UNMODIFIABLE);
+
+    if (pk11_BadAttrFlags(attrFlags)) {
+	PORT_SetError( SEC_ERROR_INVALID_ARGS );
+	return NULL;
+    }
+
+    /*
+     * The opFlags and opFlagMask parameters allow us to control the
+     * settings of the key usage attributes (CKA_ENCRYPT and friends).
+     * opFlagMask is set to one if the flag is specified in opFlags and 
+     *  zero if it is to take on a default value calculated by 
+     *  PK11_GenerateKeyPairWithOpFlags.
+     * opFlags specifies the actual value of the flag 1 or 0. 
+     *   Bits not corresponding to one bits in opFlagMask should be zero.
+     */
+
+    /* if we are trying to turn on a flag, it better be in the mask */
+    PORT_Assert ((opFlags & ~opFlagsMask) == 0);
+    opFlags &= opFlagsMask;
+
+    PORT_Assert(slot != NULL);
+    if (slot == NULL) {
+	PORT_SetError( SEC_ERROR_NO_MODULE);
+	return NULL;
+    }
+
+    /* if our slot really doesn't do this mechanism, Generate the key
+     * in our internal token and write it out */
+    if (!PK11_DoesMechanism(slot,type)) {
+	PK11SlotInfo *int_slot = PK11_GetInternalSlot();
+
+	/* don't loop forever looking for a slot */
+	if (slot == int_slot) {
+	    PK11_FreeSlot(int_slot);
+	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	    return NULL;
+	}
+
+	/* if there isn't a suitable slot, then we can't do the keygen */
+	if (int_slot == NULL) {
+	    PORT_SetError( SEC_ERROR_NO_MODULE );
+	    return NULL;
+	}
+
+	/* generate the temporary key to load */
+	privKey = PK11_GenerateKeyPair(int_slot,type, param, pubKey, PR_FALSE, 
+							PR_FALSE, wincx);
+	PK11_FreeSlot(int_slot);
+
+	/* if successful, load the temp key into the new token */
+	if (privKey != NULL) {
+	    SECKEYPrivateKey *newPrivKey = pk11_loadPrivKeyWithFlags(slot,
+						privKey,*pubKey,attrFlags);
+	    SECKEY_DestroyPrivateKey(privKey);
+	    if (newPrivKey == NULL) {
+		SECKEY_DestroyPublicKey(*pubKey);
+		*pubKey = NULL;
+	    }
+	    return newPrivKey;
+	}
+	return NULL;
+   }
+
+
+    mechanism.mechanism = type;
+    mechanism.pParameter = NULL;
+    mechanism.ulParameterLen = 0;
+    test_mech.pParameter = NULL;
+    test_mech.ulParameterLen = 0;
+    test_mech2.mechanism = CKM_INVALID_MECHANISM;
+    test_mech2.pParameter = NULL;
+    test_mech2.ulParameterLen = 0;
+
+    /* set up the private key template */
+    privattrs = privTemplate;
+    privattrs += pk11_AttrFlagsToAttributes(attrFlags, privattrs,
+						&cktrue, &ckfalse);
+
+    /* set up the mechanism specific info */
+    switch (type) {
+    case CKM_RSA_PKCS_KEY_PAIR_GEN:
+    case CKM_RSA_X9_31_KEY_PAIR_GEN:
+	rsaParams = (PK11RSAGenParams *)param;
+	if (rsaParams->pe == 0) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return NULL;
+	}
+	modulusBits = rsaParams->keySizeInBits;
+	peCount = 0;
+
+	/* convert pe to a PKCS #11 string */
+	for (i=0; i < 4; i++) {
+	    if (peCount || (rsaParams->pe & 
+				((unsigned long)0xff000000L >> (i*8)))) {
+		publicExponent[peCount] = 
+				(CK_BYTE)((rsaParams->pe >> (3-i)*8) & 0xff);
+		peCount++;
+	    }
+	}
+	PORT_Assert(peCount != 0);
+	attrs = rsaPubTemplate;
+	PK11_SETATTRS(attrs, CKA_MODULUS_BITS, 
+				&modulusBits, sizeof(modulusBits)); attrs++;
+	PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, 
+				publicExponent, peCount);attrs++;
+	pubTemplate = rsaPubTemplate;
+	keyType = rsaKey;
+	test_mech.mechanism = CKM_RSA_PKCS;
+	break;
+    case CKM_DSA_KEY_PAIR_GEN:
+	dsaParams = (SECKEYPQGParams *)param;
+	attrs = dsaPubTemplate;
+	PK11_SETATTRS(attrs, CKA_PRIME, dsaParams->prime.data,
+				dsaParams->prime.len); attrs++;
+	PK11_SETATTRS(attrs, CKA_SUBPRIME, dsaParams->subPrime.data,
+					dsaParams->subPrime.len); attrs++;
+	PK11_SETATTRS(attrs, CKA_BASE, dsaParams->base.data,
+						dsaParams->base.len); attrs++;
+	pubTemplate = dsaPubTemplate;
+	keyType = dsaKey;
+	test_mech.mechanism = CKM_DSA;
+	break;
+    case CKM_DH_PKCS_KEY_PAIR_GEN:
+        dhParams = (SECKEYDHParams *)param;
+        attrs = dhPubTemplate;
+        PK11_SETATTRS(attrs, CKA_PRIME, dhParams->prime.data,
+                      dhParams->prime.len);   attrs++;
+        PK11_SETATTRS(attrs, CKA_BASE, dhParams->base.data,
+                      dhParams->base.len);    attrs++;
+        pubTemplate = dhPubTemplate;
+        keyType = dhKey;
+        test_mech.mechanism = CKM_DH_PKCS_DERIVE;
+	break;
+    case CKM_EC_KEY_PAIR_GEN:
+        ecParams = (SECKEYECParams *)param;
+        attrs = ecPubTemplate;
+        PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data, 
+	              ecParams->len);   attrs++;
+        pubTemplate = ecPubTemplate;
+        keyType = ecKey;
+	/*
+	 * ECC supports 2 different mechanism types (unlike RSA, which
+	 * supports different usages with the same mechanism).
+	 * We may need to query both mechanism types and or the results
+	 * together -- but we only do that if either the user has
+	 * requested both usages, or not specified any usages.
+	 */
+	if ((opFlags & (CKF_SIGN|CKF_DERIVE)) == (CKF_SIGN|CKF_DERIVE)) {
+	    /* We've explicitly turned on both flags, use both mechanism */
+	    test_mech.mechanism = CKM_ECDH1_DERIVE;
+	    test_mech2.mechanism = CKM_ECDSA;
+	} else if (opFlags & CKF_SIGN) {
+	    /* just do signing */
+	    test_mech.mechanism = CKM_ECDSA;
+	} else if (opFlags & CKF_DERIVE) {
+	    /* just do ECDH */
+	    test_mech.mechanism = CKM_ECDH1_DERIVE;
+	} else {
+	    /* neither was specified default to both */
+	    test_mech.mechanism = CKM_ECDH1_DERIVE;
+	    test_mech2.mechanism = CKM_ECDSA;
+	}
+        break;
+    default:
+	PORT_SetError( SEC_ERROR_BAD_KEY );
+	return NULL;
+    }
+
+    /* now query the slot to find out how "good" a key we can generate */
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
+				test_mech.mechanism,&mechanism_info);
+    /*
+     * EC keys are used in multiple different types of mechanism, if we
+     * are using dual use keys, we need to query the second mechanism
+     * as well.
+     */
+    if (test_mech2.mechanism != CKM_INVALID_MECHANISM) {
+	CK_MECHANISM_INFO mechanism_info2;
+	CK_RV crv2;
+
+	if (crv != CKR_OK) {
+	    /* the first failed, make sure there is no trash in the
+	     * mechanism flags when we or it below */
+	    mechanism_info.flags = 0;
+	}
+	crv2 = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
+				test_mech2.mechanism, &mechanism_info2);
+	if (crv2 == CKR_OK) {
+	    crv = CKR_OK; /* succeed if either mechnaism info succeeds */
+	    /* combine the 2 sets of mechnanism flags */
+	    mechanism_info.flags |= mechanism_info2.flags;
+	}
+    }
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    if ((crv != CKR_OK) || (mechanism_info.flags == 0)) {
+	/* must be old module... guess what it should be... */
+	switch (test_mech.mechanism) {
+	case CKM_RSA_PKCS:
+	    mechanism_info.flags = (CKF_SIGN | CKF_DECRYPT | 
+		CKF_WRAP | CKF_VERIFY_RECOVER | CKF_ENCRYPT | CKF_WRAP);
+	    break;
+	case CKM_DSA:
+	    mechanism_info.flags = CKF_SIGN | CKF_VERIFY;
+	    break;
+	case CKM_DH_PKCS_DERIVE:
+	    mechanism_info.flags = CKF_DERIVE;
+	    break;
+	case CKM_ECDH1_DERIVE:
+	    mechanism_info.flags = CKF_DERIVE;
+	    if (test_mech2.mechanism == CKM_ECDSA) {
+		mechanism_info.flags |= CKF_SIGN | CKF_VERIFY;
+	    }
+	    break;
+	case CKM_ECDSA:
+	    mechanism_info.flags =  CKF_SIGN | CKF_VERIFY;
+	    break;
+	default:
+	    break;
+	}
+    }
+    /* now adjust our flags according to the user's key usage passed to us */
+    mechanism_info.flags = (mechanism_info.flags & (~opFlagsMask)) | opFlags;
+    /* set the public key attributes */
+    attrs += pk11_AttrFlagsToAttributes(pubKeyAttrFlags, attrs,
+						&cktrue, &ckfalse);
+    PK11_SETATTRS(attrs, CKA_DERIVE, 
+		mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); attrs++;
+    PK11_SETATTRS(attrs, CKA_WRAP, 
+		mechanism_info.flags & CKF_WRAP ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); attrs++;
+    PK11_SETATTRS(attrs, CKA_VERIFY, 
+		mechanism_info.flags & CKF_VERIFY ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); attrs++;
+    PK11_SETATTRS(attrs, CKA_VERIFY_RECOVER, 
+		mechanism_info.flags & CKF_VERIFY_RECOVER ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); attrs++;
+    PK11_SETATTRS(attrs, CKA_ENCRYPT, 
+		mechanism_info.flags & CKF_ENCRYPT? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); attrs++;
+    /* set the private key attributes */
+    PK11_SETATTRS(privattrs, CKA_DERIVE, 
+		mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); privattrs++;
+    PK11_SETATTRS(privattrs, CKA_UNWRAP, 
+		mechanism_info.flags & CKF_UNWRAP ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); privattrs++;
+    PK11_SETATTRS(privattrs, CKA_SIGN, 
+		mechanism_info.flags & CKF_SIGN ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); privattrs++;
+    PK11_SETATTRS(privattrs, CKA_DECRYPT, 
+		mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse,
+					 sizeof(CK_BBOOL)); privattrs++;
+
+    if (token) {
+	session_handle = PK11_GetRWSession(slot);
+	haslock = PK11_RWSessionHasLock(slot,session_handle);
+	restore = PR_TRUE;
+    } else {
+	session_handle = slot->session;
+	if (session_handle != CK_INVALID_SESSION)
+	    PK11_EnterSlotMonitor(slot);
+	restore = PR_FALSE;
+	haslock = PR_TRUE;
+    }
+
+    if (session_handle == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+	return NULL;
+    }
+    privCount = privattrs - privTemplate;
+    pubCount = attrs - pubTemplate;
+    crv = PK11_GETTAB(slot)->C_GenerateKeyPair(session_handle, &mechanism,
+	pubTemplate,pubCount,privTemplate,privCount,&pubID,&privID);
+
+    if (crv != CKR_OK) {
+	if (restore)  {
+	    PK11_RestoreROSession(slot,session_handle);
+	} else PK11_ExitSlotMonitor(slot);
+	PORT_SetError( PK11_MapError(crv) );
+	return NULL;
+    }
+    /* This locking code is dangerous and needs to be more thought
+     * out... the real problem is that we're holding the mutex open this long
+     */
+    if (haslock) { PK11_ExitSlotMonitor(slot); }
+
+    /* swap around the ID's for older PKCS #11 modules */
+    keyClass = PK11_ReadULongAttribute(slot,pubID,CKA_CLASS);
+    if (keyClass != CKO_PUBLIC_KEY) {
+	CK_OBJECT_HANDLE tmp = pubID;
+	pubID = privID;
+	privID = tmp;
+    }
+
+    *pubKey = PK11_ExtractPublicKey(slot, keyType, pubID);
+    if (*pubKey == NULL) {
+	if (restore)  {
+	    /* we may have to restore the mutex so it get's exited properly
+	     * in RestoreROSession */
+            if (haslock)  PK11_EnterSlotMonitor(slot); 
+	    PK11_RestoreROSession(slot,session_handle);
+	} 
+	PK11_DestroyObject(slot,pubID);
+	PK11_DestroyObject(slot,privID);
+	return NULL;
+    }
+
+    /* set the ID to the public key so we can find it again */
+    cka_id = pk11_MakeIDFromPublicKey(*pubKey);
+    pubIsToken = (PRBool)PK11_HasAttributeSet(slot,pubID, CKA_TOKEN);
+
+    PK11_SETATTRS(&setTemplate, CKA_ID, cka_id->data, cka_id->len);
+
+    if (haslock) { PK11_EnterSlotMonitor(slot); }
+    crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, privID,
+		&setTemplate, 1);
+   
+    if (crv == CKR_OK && pubIsToken) {
+    	crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, pubID,
+		&setTemplate, 1);
+    }
+
+
+    if (restore) {
+	PK11_RestoreROSession(slot,session_handle);
+    } else {
+	PK11_ExitSlotMonitor(slot);
+    }
+    SECITEM_FreeItem(cka_id,PR_TRUE);
+
+
+    if (crv != CKR_OK) {
+	PK11_DestroyObject(slot,pubID);
+	PK11_DestroyObject(slot,privID);
+	PORT_SetError( PK11_MapError(crv) );
+	*pubKey = NULL;
+	return NULL;
+    }
+
+    privKey = PK11_MakePrivKey(slot,keyType,!token,privID,wincx);
+    if (privKey == NULL) {
+	SECKEY_DestroyPublicKey(*pubKey);
+	PK11_DestroyObject(slot,privID);
+	*pubKey = NULL;
+	return NULL;
+    }
+
+    return privKey;
+}
+
+SECKEYPrivateKey *
+PK11_GenerateKeyPairWithFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 
+   void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, void *wincx)
+{
+    return PK11_GenerateKeyPairWithOpFlags(slot,type,param,pubKey,attrFlags,
+					   0, 0, wincx);
+}
+
+/*
+ * Use the token to generate a key pair.
+ */
+SECKEYPrivateKey *
+PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 
+   void *param, SECKEYPublicKey **pubKey, PRBool token, 
+					PRBool sensitive, void *wincx)
+{
+    PK11AttrFlags attrFlags = 0;
+
+    if (token) {
+	attrFlags |= PK11_ATTR_TOKEN;
+    } else {
+	attrFlags |= PK11_ATTR_SESSION;
+    }
+    if (sensitive) {
+	attrFlags |= (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE);
+    } else {
+	attrFlags |= (PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC);
+    }
+    return PK11_GenerateKeyPairWithFlags(slot, type, param, pubKey,
+						attrFlags, wincx);
+}
+
+/* build a public KEA key from the public value */
+SECKEYPublicKey *
+PK11_MakeKEAPubKey(unsigned char *keyData,int length)
+{
+    SECKEYPublicKey *pubk;
+    SECItem pkData;
+    SECStatus rv;
+    PRArenaPool *arena;
+
+    pkData.data = keyData;
+    pkData.len = length;
+
+    arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL)
+	return NULL;
+
+    pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
+    if (pubk == NULL) {
+	PORT_FreeArena (arena, PR_FALSE);
+	return NULL;
+    }
+
+    pubk->arena = arena;
+    pubk->pkcs11Slot = 0;
+    pubk->pkcs11ID = CK_INVALID_HANDLE;
+    pubk->keyType = fortezzaKey;
+    rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData);
+    if (rv != SECSuccess) {
+	PORT_FreeArena (arena, PR_FALSE);
+	return NULL;
+    }
+    return pubk;
+}
+
+SECStatus 
+PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot,
+			SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem,
+			SECItem *nickname, SECItem *publicValue, PRBool isPerm,
+			PRBool isPrivate, KeyType keyType, 
+			unsigned int keyUsage, void *wincx)
+{
+    CK_MECHANISM_TYPE pbeMechType;
+    SECItem *crypto_param = NULL;
+    PK11SymKey *key = NULL;
+    SECStatus rv = SECSuccess;
+    CK_MECHANISM_TYPE cryptoMechType;
+    SECKEYPrivateKey *privKey = NULL;
+    PRBool faulty3DES = PR_FALSE;
+    int usageCount = 0;
+    CK_KEY_TYPE key_type;
+    CK_ATTRIBUTE_TYPE *usage = NULL;
+    CK_ATTRIBUTE_TYPE rsaUsage[] = {
+		 CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER };
+    CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN };
+    CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE };
+    CK_ATTRIBUTE_TYPE ecUsage[] = { CKA_SIGN, CKA_DERIVE };
+    if((epki == NULL) || (pwitem == NULL))
+	return SECFailure;
+
+    pbeMechType = PK11_AlgtagToMechanism(SECOID_FindOIDTag(
+					&epki->algorithm.algorithm));
+
+    switch (keyType) {
+    default:
+    case rsaKey:
+	key_type = CKK_RSA;
+	switch  (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) {
+	case KU_KEY_ENCIPHERMENT:
+	    usage = rsaUsage;
+	    usageCount = 2;
+	    break;
+	case KU_DIGITAL_SIGNATURE:
+	    usage = &rsaUsage[2];
+	    usageCount = 2;
+	    break;
+	case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE:
+	case 0: /* default to everything */
+	    usage = rsaUsage;
+	    usageCount = 4;
+	    break;
+	}
+        break;
+    case dhKey:
+	key_type = CKK_DH;
+	usage = dhUsage;
+	usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]);
+	break;
+    case dsaKey:
+	key_type = CKK_DSA;
+	usage = dsaUsage;
+	usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]);
+	break;
+    case ecKey:
+	key_type = CKK_EC;
+	switch  (keyUsage & (KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) {
+	case KU_DIGITAL_SIGNATURE:
+	    usage = ecUsage;
+	    usageCount = 1;
+	    break;
+	case KU_KEY_AGREEMENT:
+	    usage = &ecUsage[1];
+	    usageCount = 1;
+	    break;
+	case KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT:
+	default: /* default to everything */
+	    usage = ecUsage;
+	    usageCount = 2;
+	    break;
+	}
+	break;	
+    }
+
+try_faulty_3des:
+
+    key = PK11_PBEKeyGen(slot, &epki->algorithm, pwitem, faulty3DES, wincx);
+    if (key == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+    cryptoMechType = pk11_GetPBECryptoMechanism(&epki->algorithm,
+					 &crypto_param, pwitem, faulty3DES);
+    if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	rv = SECFailure;
+	goto done;
+    }
+
+
+    cryptoMechType = PK11_GetPadMechanism(cryptoMechType);
+
+    PORT_Assert(usage != NULL);
+    PORT_Assert(usageCount != 0);
+    privKey = PK11_UnwrapPrivKey(slot, key, cryptoMechType, 
+				 crypto_param, &epki->encryptedData, 
+				 nickname, publicValue, isPerm, isPrivate,
+				 key_type, usage, usageCount, wincx);
+    if(privKey) {
+	SECKEY_DestroyPrivateKey(privKey);
+	privKey = NULL;
+	rv = SECSuccess;
+	goto done;
+    }
+
+    /* if we are unable to import the key and the pbeMechType is 
+     * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that
+     * the encrypted blob was created with a buggy key generation method
+     * which is described in the PKCS 12 implementation notes.  So we
+     * need to try importing via that method.
+     */ 
+    if((pbeMechType == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC) && (!faulty3DES)) {
+	/* clean up after ourselves before redoing the key generation. */
+
+	PK11_FreeSymKey(key);
+	key = NULL;
+
+	if(crypto_param) {
+	    SECITEM_ZfreeItem(crypto_param, PR_TRUE);
+	    crypto_param = NULL;
+	}
+
+	faulty3DES = PR_TRUE;
+	goto try_faulty_3des;
+    }
+
+    /* key import really did fail */
+    rv = SECFailure;
+
+done:
+    if(crypto_param != NULL) {
+	SECITEM_ZfreeItem(crypto_param, PR_TRUE);
+    }
+
+    if(key != NULL) {
+    	PK11_FreeSymKey(key);
+    }
+
+    return rv;
+}
+
+SECKEYPrivateKeyInfo *
+PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx)
+{
+    return NULL;
+}
+
+SECKEYEncryptedPrivateKeyInfo * 
+PK11_ExportEncryptedPrivKeyInfo(
+   PK11SlotInfo     *slot,      /* optional, encrypt key in this slot */
+   SECOidTag         algTag,    /* encrypt key with this algorithm */
+   SECItem          *pwitem,    /* password for PBE encryption */
+   SECKEYPrivateKey *pk,        /* encrypt this private key */
+   int               iteration, /* interations for PBE alg */
+   void             *wincx)     /* context for password callback ? */
+{
+    SECKEYEncryptedPrivateKeyInfo *epki      = NULL;
+    PRArenaPool                   *arena     = NULL;
+    SECAlgorithmID                *algid;
+    SECOidTag			  pbeAlgTag = SEC_OID_UNKNOWN;
+    SECItem                       *crypto_param = NULL;
+    PK11SymKey                    *key       = NULL;
+    SECKEYPrivateKey		  *tmpPK = NULL;
+    SECStatus                      rv        = SECSuccess;
+    CK_RV                          crv;
+    CK_ULONG                       encBufLen;
+    CK_MECHANISM_TYPE              pbeMechType;
+    CK_MECHANISM_TYPE              cryptoMechType;
+    CK_MECHANISM                   cryptoMech;
+
+    if (!pwitem || !pk) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    algid = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, SEC_OID_UNKNOWN,
+				&pbeAlgTag, 0, NULL, iteration);
+    if (algid == NULL) {
+	return NULL;
+    }
+
+    arena = PORT_NewArena(2048);
+    if (arena)
+	epki = PORT_ArenaZNew(arena, SECKEYEncryptedPrivateKeyInfo);
+    if(epki == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    epki->arena = arena;
+
+
+    /* if we didn't specify a slot, use the slot the private key was in */
+    if (!slot) {
+	slot = pk->pkcs11Slot;
+    }
+
+    /* if we specified a different slot, and the private key slot can do the
+     * pbe key gen, generate the key in the private key slot so we don't have 
+     * to move it later */
+    pbeMechType = PK11_AlgtagToMechanism(pbeAlgTag);
+    if (slot != pk->pkcs11Slot) {
+	if (PK11_DoesMechanism(pk->pkcs11Slot,pbeMechType)) {
+	    slot = pk->pkcs11Slot;
+	}
+    }
+    key = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, wincx);
+    if (key == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &crypto_param, pwitem);
+    if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType);
+    cryptoMech.pParameter = crypto_param ? crypto_param->data : NULL;
+    cryptoMech.ulParameterLen = crypto_param ? crypto_param->len : 0;
+
+    /* If the key isn't in the private key slot, move it */
+    if (key->slot != pk->pkcs11Slot) {
+	PK11SymKey *newkey = pk11_CopyToSlot(pk->pkcs11Slot,
+						key->type, CKA_WRAP, key);
+	if (newkey == NULL) {
+            /* couldn't import the wrapping key, try exporting the
+             * private key */
+	    tmpPK = pk11_loadPrivKey(key->slot, pk, NULL, PR_FALSE, PR_TRUE);
+	    if (tmpPK == NULL) {
+		rv = SECFailure;
+		goto loser;
+	    }
+	    pk = tmpPK;
+	} else {
+	    /* free the old key and use the new key */
+	    PK11_FreeSymKey(key);
+	    key = newkey;
+	}
+    }
+    	
+    /* we are extracting an encrypted privateKey structure.
+     * which needs to be freed along with the buffer into which it is
+     * returned.  eventually, we should retrieve an encrypted key using
+     * pkcs8/pkcs5.
+     */
+    encBufLen = 0;
+    PK11_EnterSlotMonitor(pk->pkcs11Slot);
+    crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, 
+    		&cryptoMech, key->objectID, pk->pkcs11ID, NULL, 
+		&encBufLen); 
+    PK11_ExitSlotMonitor(pk->pkcs11Slot);
+    if (crv != CKR_OK) {
+	rv = SECFailure;
+	goto loser;
+    }
+    epki->encryptedData.data = PORT_ArenaAlloc(arena, encBufLen);
+    if (!epki->encryptedData.data) {
+	rv = SECFailure;
+	goto loser;
+    }
+    PK11_EnterSlotMonitor(pk->pkcs11Slot);
+    crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, 
+    		&cryptoMech, key->objectID, pk->pkcs11ID, 
+		epki->encryptedData.data, &encBufLen); 
+    PK11_ExitSlotMonitor(pk->pkcs11Slot);
+    epki->encryptedData.len = (unsigned int) encBufLen;
+    if(crv != CKR_OK) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    if(!epki->encryptedData.len) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = SECOID_CopyAlgorithmID(arena, &epki->algorithm, algid);
+
+loser:
+    if(crypto_param != NULL) {
+	SECITEM_ZfreeItem(crypto_param, PR_TRUE);
+	crypto_param = NULL;
+    }
+
+    if(key != NULL) {
+    	PK11_FreeSymKey(key);
+    }
+    if (tmpPK != NULL) {
+	SECKEY_DestroyPrivateKey(tmpPK);
+    }
+    SECOID_DestroyAlgorithmID(algid, PR_TRUE);
+
+    if(rv == SECFailure) {
+	if(arena != NULL) {
+	    PORT_FreeArena(arena, PR_TRUE);
+	}
+	epki = NULL;
+    }
+
+    return epki;
+}
+
+SECKEYEncryptedPrivateKeyInfo * 
+PK11_ExportEncryptedPrivateKeyInfo(
+   PK11SlotInfo    *slot,      /* optional, encrypt key in this slot */
+   SECOidTag        algTag,    /* encrypt key with this algorithm */
+   SECItem         *pwitem,    /* password for PBE encryption */
+   CERTCertificate *cert,      /* wrap priv key for this user cert */
+   int              iteration, /* interations for PBE alg */
+   void            *wincx)     /* context for password callback ? */
+{
+    SECKEYEncryptedPrivateKeyInfo *epki = NULL;
+    SECKEYPrivateKey              *pk   = PK11_FindKeyByAnyCert(cert, wincx);
+    if (pk != NULL) {
+	epki = PK11_ExportEncryptedPrivKeyInfo(slot, algTag, pwitem, pk, 
+	                                       iteration, wincx);
+	SECKEY_DestroyPrivateKey(pk);
+    }
+    return epki;
+}
+
+SECItem*
+PK11_DEREncodePublicKey(SECKEYPublicKey *pubk)
+{
+    return SECKEY_EncodeDERSubjectPublicKeyInfo(pubk);
+}
+
+char *
+PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey)
+{
+    return PK11_GetObjectNickname(privKey->pkcs11Slot,privKey->pkcs11ID);
+}
+
+char *
+PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey)
+{
+    return PK11_GetObjectNickname(pubKey->pkcs11Slot,pubKey->pkcs11ID);
+}
+
+SECStatus
+PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, const char *nickname)
+{
+    return PK11_SetObjectNickname(privKey->pkcs11Slot,
+					privKey->pkcs11ID,nickname);
+}
+
+SECStatus
+PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, const char *nickname)
+{
+    return PK11_SetObjectNickname(pubKey->pkcs11Slot,
+					pubKey->pkcs11ID,nickname);
+}
+
+SECKEYPQGParams *
+PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey)
+{
+    CK_ATTRIBUTE pTemplate[] = {
+	{ CKA_PRIME, NULL, 0 },
+	{ CKA_SUBPRIME, NULL, 0 },
+	{ CKA_BASE, NULL, 0 },
+    };
+    int pTemplateLen = sizeof(pTemplate)/sizeof(pTemplate[0]);
+    PRArenaPool *arena = NULL;
+    SECKEYPQGParams *params;
+    CK_RV crv;
+
+
+    arena = PORT_NewArena(2048);
+    if (arena == NULL) {
+	goto loser;
+    }
+    params=(SECKEYPQGParams *)PORT_ArenaZAlloc(arena,sizeof(SECKEYPQGParams));
+    if (params == NULL) {
+	goto loser;
+    }
+
+    crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, 
+						pTemplate, pTemplateLen);
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+	goto loser;
+    }
+
+    params->arena = arena;
+    params->prime.data = pTemplate[0].pValue;
+    params->prime.len = pTemplate[0].ulValueLen;
+    params->subPrime.data = pTemplate[1].pValue;
+    params->subPrime.len = pTemplate[1].ulValueLen;
+    params->base.data = pTemplate[2].pValue;
+    params->base.len = pTemplate[2].ulValueLen;
+
+    return params;
+
+loser:
+    if (arena != NULL) {
+	PORT_FreeArena(arena,PR_FALSE);
+    }
+    return NULL;
+}
+
+SECKEYPrivateKey*
+PK11_CopyTokenPrivKeyToSessionPrivKey(PK11SlotInfo *destSlot,
+				      SECKEYPrivateKey *privKey)
+{
+    CK_RV             crv;
+    CK_OBJECT_HANDLE  newKeyID;
+
+    static const CK_BBOOL     ckfalse = CK_FALSE;
+    static const CK_ATTRIBUTE template[1] = { 
+       { CKA_TOKEN, (CK_BBOOL *)&ckfalse, sizeof ckfalse }
+    };
+
+    if (destSlot && destSlot != privKey->pkcs11Slot) {
+	SECKEYPrivateKey *newKey =
+	       pk11_loadPrivKey(destSlot, 
+				privKey, 
+			        NULL,     /* pubKey    */
+			        PR_FALSE, /* token     */
+			        PR_FALSE);/* sensitive */
+	if (newKey)
+	    return newKey;
+    }
+    destSlot = privKey->pkcs11Slot;
+    PK11_Authenticate(destSlot, PR_TRUE, privKey->wincx);
+    PK11_EnterSlotMonitor(destSlot);
+    crv = PK11_GETTAB(destSlot)->C_CopyObject(	destSlot->session, 
+						privKey->pkcs11ID,
+						(CK_ATTRIBUTE *)template, 
+						1, &newKeyID);
+    PK11_ExitSlotMonitor(destSlot);
+
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return NULL;
+    }
+
+    return PK11_MakePrivKey(destSlot, privKey->keyType, PR_TRUE /*isTemp*/, 
+			    newKeyID, privKey->wincx);
+}
+
+SECKEYPrivateKey*
+PK11_ConvertSessionPrivKeyToTokenPrivKey(SECKEYPrivateKey *privk, void* wincx)
+{
+    PK11SlotInfo* slot = privk->pkcs11Slot;
+    CK_ATTRIBUTE template[1];
+    CK_ATTRIBUTE *attrs = template;
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_RV crv;
+    CK_OBJECT_HANDLE newKeyID;
+    CK_SESSION_HANDLE rwsession;
+
+    PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++;
+
+    PK11_Authenticate(slot, PR_TRUE, wincx);
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+	return NULL;
+    }
+    crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, privk->pkcs11ID,
+        template, 1, &newKeyID);
+    PK11_RestoreROSession(slot, rwsession);
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+        return NULL;
+    }
+
+    return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isTemp*/,
+        newKeyID, NULL /*wincx*/);
+}
+
+/*
+ * destroy a private key if there are no matching certs.
+ * this function also frees the privKey structure.
+ */
+SECStatus
+PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force)
+{
+    CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey);
+    SECStatus rv = SECWouldBlock;
+
+    if (!cert || force) {
+	/* now, then it's safe for the key to go away */
+	rv = PK11_DestroyTokenObject(privKey->pkcs11Slot,privKey->pkcs11ID);
+    }
+    if (cert) {
+	CERT_DestroyCertificate(cert);
+    }
+    SECKEY_DestroyPrivateKey(privKey);
+    return rv;
+}
+
+/*
+ * destroy a private key if there are no matching certs.
+ * this function also frees the privKey structure.
+ */
+SECStatus
+PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey)
+{
+    /* now, then it's safe for the key to go away */
+    if (pubKey->pkcs11Slot == NULL) {
+	return SECFailure;
+    }
+    PK11_DestroyTokenObject(pubKey->pkcs11Slot,pubKey->pkcs11ID);
+    SECKEY_DestroyPublicKey(pubKey);
+    return SECSuccess;
+}
+
+/*
+ * key call back structure.
+ */
+typedef struct pk11KeyCallbackStr {
+	SECStatus (* callback)(SECKEYPrivateKey *,void *);
+	void *callbackArg;
+	void *wincx;
+} pk11KeyCallback;
+
+/*
+ * callback to map Object Handles to Private Keys;
+ */
+SECStatus
+pk11_DoKeys(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, void *arg)
+{
+    SECStatus rv = SECSuccess;
+    SECKEYPrivateKey *privKey;
+    pk11KeyCallback *keycb = (pk11KeyCallback *) arg;
+    if (!arg) {
+        return SECFailure;
+    }
+
+    privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,keycb->wincx);
+
+    if (privKey == NULL) {
+	return SECFailure;
+    }
+
+    if (keycb->callback) {
+	rv = (*keycb->callback)(privKey,keycb->callbackArg);
+    }
+
+    SECKEY_DestroyPrivateKey(privKey);	    
+    return rv;
+}
+
+/***********************************************************************
+ * PK11_TraversePrivateKeysInSlot
+ *
+ * Traverses all the private keys on a slot.
+ *
+ * INPUTS
+ *      slot
+ *          The PKCS #11 slot whose private keys you want to traverse.
+ *      callback
+ *          A callback function that will be called for each key.
+ *      arg
+ *          An argument that will be passed to the callback function.
+ */
+SECStatus
+PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot,
+    SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg)
+{
+    pk11KeyCallback perKeyCB;
+    pk11TraverseSlot perObjectCB;
+    CK_OBJECT_CLASS privkClass = CKO_PRIVATE_KEY;
+    CK_BBOOL ckTrue = CK_TRUE;
+    CK_ATTRIBUTE theTemplate[2];
+    int templateSize = 2;
+
+    theTemplate[0].type = CKA_CLASS;
+    theTemplate[0].pValue = &privkClass;
+    theTemplate[0].ulValueLen = sizeof(privkClass);
+    theTemplate[1].type = CKA_TOKEN;
+    theTemplate[1].pValue = &ckTrue;
+    theTemplate[1].ulValueLen = sizeof(ckTrue);
+
+    if(slot==NULL) {
+        return SECSuccess;
+    }
+
+    perObjectCB.callback = pk11_DoKeys;
+    perObjectCB.callbackArg = &perKeyCB;
+    perObjectCB.findTemplate = theTemplate;
+    perObjectCB.templateCount = templateSize;
+    perKeyCB.callback = callback;
+    perKeyCB.callbackArg = arg;
+    perKeyCB.wincx = NULL;
+
+    return PK11_TraverseSlot(slot, &perObjectCB);
+}
+
+/*
+ * return the private key with the given ID
+ */
+CK_OBJECT_HANDLE
+pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, SECItem *keyID)
+{
+    CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY;
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_ID, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 },
+    };
+    /* if you change the array, change the variable below as well */
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    CK_ATTRIBUTE *attrs = theTemplate;
+
+    PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len ); attrs++;
+    PK11_SETATTRS(attrs, CKA_CLASS, &privKey, sizeof(privKey));
+
+    return pk11_FindObjectByTemplate(slot,theTemplate,tsize);
+} 
+
+
+SECKEYPrivateKey *
+PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, void *wincx)
+{
+    CK_OBJECT_HANDLE keyHandle;
+    SECKEYPrivateKey *privKey;
+
+    keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID);
+    if (keyHandle == CK_INVALID_HANDLE) { 
+	return NULL;
+    }
+    privKey =  PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
+    return privKey;
+}
+
+/*
+ * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated
+ * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make
+ * smart cards happy.
+ */
+SECItem *
+PK11_MakeIDFromPubKey(SECItem *pubKeyData) 
+{
+    PK11Context *context;
+    SECItem *certCKA_ID;
+    SECStatus rv;
+
+    if (pubKeyData->len <= SHA1_LENGTH) {
+	/* probably an already hashed value. The strongest known public
+	 * key values <= 160 bits would be less than 40 bit symetric in
+	 * strength. Don't hash them, just return the value. There are
+	 * none at the time of this writing supported by previous versions
+	 * of NSS, so change is binary compatible safe */
+	return SECITEM_DupItem(pubKeyData);
+    }
+
+    context = PK11_CreateDigestContext(SEC_OID_SHA1);
+    if (context == NULL) {
+	return NULL;
+    }
+
+    rv = PK11_DigestBegin(context);
+    if (rv == SECSuccess) {
+    	rv = PK11_DigestOp(context,pubKeyData->data,pubKeyData->len);
+    }
+    if (rv != SECSuccess) {
+	PK11_DestroyContext(context,PR_TRUE);
+	return NULL;
+    }
+
+    certCKA_ID = (SECItem *)PORT_Alloc(sizeof(SECItem));
+    if (certCKA_ID == NULL) {
+	PK11_DestroyContext(context,PR_TRUE);
+	return NULL;
+    }
+
+    certCKA_ID->len = SHA1_LENGTH;
+    certCKA_ID->data = (unsigned char*)PORT_Alloc(certCKA_ID->len);
+    if (certCKA_ID->data == NULL) {
+	PORT_Free(certCKA_ID);
+	PK11_DestroyContext(context,PR_TRUE);
+        return NULL;
+    }
+
+    rv = PK11_DigestFinal(context,certCKA_ID->data,&certCKA_ID->len,
+								SHA1_LENGTH);
+    PK11_DestroyContext(context,PR_TRUE);
+    if (rv != SECSuccess) {
+    	SECITEM_FreeItem(certCKA_ID,PR_TRUE);
+	return NULL;
+    }
+
+    return certCKA_ID;
+}
+
+/* Looking for PK11_GetKeyIDFromPrivateKey?
+ * Call PK11_GetLowLevelKeyIDForPrivateKey instead.
+ */
+
+
+SECItem *
+PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey)
+{
+    return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID);
+}
+
+static SECStatus
+privateKeyListCallback(SECKEYPrivateKey *key, void *arg)
+{
+    SECKEYPrivateKeyList *list = (SECKEYPrivateKeyList*)arg;
+    return SECKEY_AddPrivateKeyToListTail(list, SECKEY_CopyPrivateKey(key));
+}
+
+SECKEYPrivateKeyList*
+PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot)
+{
+    SECStatus status;
+    SECKEYPrivateKeyList *keys;
+
+    keys = SECKEY_NewPrivateKeyList();
+    if(keys == NULL) return NULL;
+
+    status = PK11_TraversePrivateKeysInSlot(slot, privateKeyListCallback,
+		(void*)keys);
+
+    if( status != SECSuccess ) {
+	SECKEY_DestroyPrivateKeyList(keys);
+	keys = NULL;
+    }
+
+    return keys;
+}
+
+SECKEYPublicKeyList*
+PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname)
+{
+    CK_ATTRIBUTE findTemp[4];
+    CK_ATTRIBUTE *attrs;
+    CK_BBOOL ckTrue = CK_TRUE;
+    CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY;
+    int tsize = 0;
+    int objCount = 0;
+    CK_OBJECT_HANDLE *key_ids;
+    SECKEYPublicKeyList *keys;
+    int i,len;
+
+
+    attrs = findTemp;
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
+    if (nickname) {
+	len = PORT_Strlen(nickname);
+	PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
+    }
+    tsize = attrs - findTemp;
+    PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
+
+    key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
+    if (key_ids == NULL) {
+	return NULL;
+    }
+    keys = SECKEY_NewPublicKeyList();
+    if (keys == NULL) {
+	PORT_Free(key_ids);
+	return NULL;
+    }
+
+    for (i=0; i < objCount ; i++) {
+	SECKEYPublicKey *pubKey = 
+				PK11_ExtractPublicKey(slot,nullKey,key_ids[i]);
+	if (pubKey) {
+	    SECKEY_AddPublicKeyToListTail(keys, pubKey);
+	}
+   }
+
+   PORT_Free(key_ids);
+   return keys;
+}
+
+SECKEYPrivateKeyList*
+PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
+{
+    CK_ATTRIBUTE findTemp[4];
+    CK_ATTRIBUTE *attrs;
+    CK_BBOOL ckTrue = CK_TRUE;
+    CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY;
+    int tsize = 0;
+    int objCount = 0;
+    CK_OBJECT_HANDLE *key_ids;
+    SECKEYPrivateKeyList *keys;
+    int i,len;
+
+
+    attrs = findTemp;
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
+    if (nickname) {
+	len = PORT_Strlen(nickname);
+	PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
+    }
+    tsize = attrs - findTemp;
+    PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
+
+    key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
+    if (key_ids == NULL) {
+	return NULL;
+    }
+    keys = SECKEY_NewPrivateKeyList();
+    if (keys == NULL) {
+	PORT_Free(key_ids);
+	return NULL;
+    }
+
+    for (i=0; i < objCount ; i++) {
+	SECKEYPrivateKey *privKey = 
+		PK11_MakePrivKey(slot,nullKey,PR_TRUE,key_ids[i],wincx);
+	SECKEY_AddPrivateKeyToListTail(keys, privKey);
+   }
+
+   PORT_Free(key_ids);
+   return keys;
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11auth.c b/mozilla/security/nss/lib/pk11wrap/pk11auth.c
new file mode 100644
index 0000000..051280e
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11auth.c
@@ -0,0 +1,792 @@
+/* ***** 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 ***** */
+/*
+ * This file deals with PKCS #11 passwords and authentication.
+ */
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11t.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "secerr.h"
+
+#include "pkim.h" 
+
+
+/*************************************************************
+ * local static and global data
+ *************************************************************/
+/*
+ * This structure keeps track of status that spans all the Slots.
+ * NOTE: This is a global data structure. It semantics expect thread crosstalk
+ * be very careful when you see it used. 
+ *  It's major purpose in life is to allow the user to log in one PER 
+ * Tranaction, even if a transaction spans threads. The problem is the user
+ * may have to enter a password one just to be able to look at the 
+ * personalities/certificates (s)he can use. Then if Auth every is one, they
+ * may have to enter the password again to use the card. See PK11_StartTransac
+ * and PK11_EndTransaction.
+ */
+static struct PK11GlobalStruct {
+   int transaction;
+   PRBool inTransaction;
+   char *(PR_CALLBACK *getPass)(PK11SlotInfo *,PRBool,void *);
+   PRBool (PR_CALLBACK *verifyPass)(PK11SlotInfo *,void *);
+   PRBool (PR_CALLBACK *isLoggedIn)(PK11SlotInfo *,void *);
+} PK11_Global = { 1, PR_FALSE, NULL, NULL, NULL };
+ 
+/***********************************************************
+ * Password Utilities
+ ***********************************************************/
+/*
+ * Check the user's password. Log into the card if it's correct.
+ * succeed if the user is already logged in.
+ */
+SECStatus
+pk11_CheckPassword(PK11SlotInfo *slot,char *pw)
+{
+    int len = 0;
+    CK_RV crv;
+    SECStatus rv;
+    int64 currtime = PR_Now();
+    PRBool mustRetry;
+    int retry = 0;
+
+    if (slot->protectedAuthPath) {
+	len = 0;
+	pw = NULL;
+    } else if (pw == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    } else {
+	len = PORT_Strlen(pw);
+    }
+
+    do {
+	PK11_EnterSlotMonitor(slot);
+	crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER,
+						(unsigned char *)pw,len);
+	slot->lastLoginCheck = 0;
+	mustRetry = PR_FALSE;
+	PK11_ExitSlotMonitor(slot);
+	switch (crv) {
+	/* if we're already logged in, we're good to go */
+	case CKR_OK:
+	    slot->authTransact = PK11_Global.transaction;
+	    /* Fall through */
+	case CKR_USER_ALREADY_LOGGED_IN:
+	    slot->authTime = currtime;
+	    rv = SECSuccess;
+	    break;
+	case CKR_PIN_INCORRECT:
+	    PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+	    rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
+	    break;
+	/* someone called reset while we fetched the password, try again once
+	 * if the token is still there. */
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_CLOSED:
+	    if (retry++ == 0) {
+		rv = PK11_InitToken(slot,PR_FALSE);
+		if (rv == SECSuccess) {
+		    if (slot->session != CK_INVALID_SESSION) {
+			mustRetry = PR_TRUE;
+		    } else {
+			PORT_SetError(PK11_MapError(crv));
+			rv = SECFailure;
+		    }
+		}
+		break;
+	    }
+	    /* Fall through */
+	default:
+	    PORT_SetError(PK11_MapError(crv));
+	    rv = SECFailure; /* some failure we can't fix by retrying */
+	}
+    } while (mustRetry);
+    return rv;
+}
+
+/*
+ * Check the user's password. Logout before hand to make sure that
+ * we are really checking the password.
+ */
+SECStatus
+PK11_CheckUserPassword(PK11SlotInfo *slot, const char *pw)
+{
+    int len = 0;
+    CK_RV crv;
+    SECStatus rv;
+    int64 currtime = PR_Now();
+
+    if (slot->protectedAuthPath) {
+	len = 0;
+	pw = NULL;
+    } else if (pw == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    } else {
+	len = PORT_Strlen(pw);
+    }
+
+    /* force a logout */
+    PK11_EnterSlotMonitor(slot);
+    PK11_GETTAB(slot)->C_Logout(slot->session);
+
+    crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER,
+					(unsigned char *)pw,len);
+    slot->lastLoginCheck = 0;
+    PK11_ExitSlotMonitor(slot);
+    switch (crv) {
+    /* if we're already logged in, we're good to go */
+    case CKR_OK:
+	slot->authTransact = PK11_Global.transaction;
+	slot->authTime = currtime;
+	rv = SECSuccess;
+	break;
+    case CKR_PIN_INCORRECT:
+	PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+	rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
+	break;
+    default:
+	PORT_SetError(PK11_MapError(crv));
+	rv = SECFailure; /* some failure we can't fix by retrying */
+    }
+    return rv;
+}
+
+SECStatus
+PK11_Logout(PK11SlotInfo *slot)
+{
+    CK_RV crv;
+
+    /* force a logout */
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_Logout(slot->session);
+    slot->lastLoginCheck = 0;
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return  SECSuccess;
+}
+
+/*
+ * transaction stuff is for when we test for the need to do every
+ * time auth to see if we already did it for this slot/transaction
+ */
+void PK11_StartAuthTransaction(void)
+{
+PK11_Global.transaction++;
+PK11_Global.inTransaction = PR_TRUE;
+}
+
+void PK11_EndAuthTransaction(void)
+{
+PK11_Global.transaction++;
+PK11_Global.inTransaction = PR_FALSE;
+}
+
+/*
+ * before we do a private key op, we check to see if we
+ * need to reauthenticate.
+ */
+void
+PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx)
+{
+    int askpw = slot->askpw;
+    PRBool NeedAuth = PR_FALSE;
+
+    if (!slot->needLogin) return;
+
+    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
+	PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
+
+	if (def_slot) {
+	    askpw = def_slot->askpw;
+	    PK11_FreeSlot(def_slot);
+	}
+    }
+
+    /* timeouts are handled by isLoggedIn */
+    if (!PK11_IsLoggedIn(slot,wincx)) {
+	NeedAuth = PR_TRUE;
+    } else if (askpw == -1) {
+	if (!PK11_Global.inTransaction	||
+			 (PK11_Global.transaction != slot->authTransact)) {
+    	    PK11_EnterSlotMonitor(slot);
+	    PK11_GETTAB(slot)->C_Logout(slot->session);
+	    slot->lastLoginCheck = 0;
+    	    PK11_ExitSlotMonitor(slot);
+	    NeedAuth = PR_TRUE;
+	}
+    }
+    if (NeedAuth) PK11_DoPassword(slot,PR_TRUE,wincx);
+}
+
+void
+PK11_SlotDBUpdate(PK11SlotInfo *slot)
+{
+    SECMOD_UpdateModule(slot->module);
+}
+
+/*
+ * set new askpw and timeout values
+ */
+void
+PK11_SetSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout)
+{
+        slot->askpw = askpw;
+        slot->timeout = timeout;
+        slot->defaultFlags |= PK11_OWN_PW_DEFAULTS;
+        PK11_SlotDBUpdate(slot);
+}
+
+/*
+ * Get the askpw and timeout values for this slot
+ */
+void
+PK11_GetSlotPWValues(PK11SlotInfo *slot,int *askpw, int *timeout)
+{
+    *askpw = slot->askpw;
+    *timeout = slot->timeout;
+
+    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
+	PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
+
+	if (def_slot) {
+	    *askpw = def_slot->askpw;
+	    *timeout = def_slot->timeout;
+	    PK11_FreeSlot(def_slot);
+	}
+    }
+}
+
+/*
+ * Returns true if the token is needLogin and isn't logged in.
+ * This function is used to determine if authentication is needed
+ * before attempting a potentially privelleged operation.
+ */
+PRBool
+pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx)
+{
+    return slot->needLogin && !PK11_IsLoggedIn(slot,wincx);
+}
+
+/*
+ * make sure a slot is authenticated...
+ * This function only does the authentication if it is needed.
+ */
+SECStatus
+PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) {
+    if (pk11_LoginStillRequired(slot,wincx)) {
+	return PK11_DoPassword(slot,loadCerts,wincx);
+    }
+    return SECSuccess;
+}
+
+/*
+ * Authenticate to "unfriendly" tokens (tokens which need to be logged
+ * in to find the certs.
+ */
+SECStatus
+pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
+{
+    SECStatus rv = SECSuccess;
+    if (!PK11_IsFriendly(slot)) {
+	rv = PK11_Authenticate(slot, loadCerts, wincx);
+    }
+    return rv;
+}
+
+
+/*
+ * NOTE: this assumes that we are logged out of the card before hand
+ */
+SECStatus
+PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw)
+{
+    CK_SESSION_HANDLE rwsession;
+    CK_RV crv;
+    SECStatus rv = SECFailure;
+    int len = 0;
+
+    /* get a rwsession */
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+    	return rv;
+    }
+
+    if (slot->protectedAuthPath) {
+	len = 0;
+	ssopw = NULL;
+    } else if (ssopw == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    } else {
+	len = PORT_Strlen(ssopw);
+    }
+
+    /* check the password */
+    crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO,
+						(unsigned char *)ssopw,len);
+    slot->lastLoginCheck = 0;
+    switch (crv) {
+    /* if we're already logged in, we're good to go */
+    case CKR_OK:
+	rv = SECSuccess;
+	break;
+    case CKR_PIN_INCORRECT:
+	PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+	rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
+	break;
+    default:
+	PORT_SetError(PK11_MapError(crv));
+	rv = SECFailure; /* some failure we can't fix by retrying */
+    }
+    PK11_GETTAB(slot)->C_Logout(rwsession);
+    slot->lastLoginCheck = 0;
+
+    /* release rwsession */
+    PK11_RestoreROSession(slot,rwsession);
+    return rv;
+}
+
+/*
+ * make sure the password conforms to your token's requirements.
+ */
+SECStatus
+PK11_VerifyPW(PK11SlotInfo *slot,char *pw)
+{
+    int len = PORT_Strlen(pw);
+
+    if ((slot->minPassword > len) || (slot->maxPassword < len)) {
+	PORT_SetError(SEC_ERROR_BAD_DATA);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * initialize a user PIN Value
+ */
+SECStatus
+PK11_InitPin(PK11SlotInfo *slot, const char *ssopw, const char *userpw)
+{
+    CK_SESSION_HANDLE rwsession = CK_INVALID_SESSION;
+    CK_RV crv;
+    SECStatus rv = SECFailure;
+    int len;
+    int ssolen;
+
+    if (userpw == NULL) userpw = "";
+    if (ssopw == NULL) ssopw = "";
+
+    len = PORT_Strlen(userpw);
+    ssolen = PORT_Strlen(ssopw);
+
+    /* get a rwsession */
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+	slot->lastLoginCheck = 0;
+    	return rv;
+    }
+
+    if (slot->protectedAuthPath) {
+	len = 0;
+	ssolen = 0;
+	ssopw = NULL;
+	userpw = NULL;
+    }
+
+    /* check the password */
+    crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, 
+					  (unsigned char *)ssopw,ssolen);
+    slot->lastLoginCheck = 0;
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	goto done;
+    }
+
+    crv = PK11_GETTAB(slot)->C_InitPIN(rwsession,(unsigned char *)userpw,len);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+    } else {
+    	rv = SECSuccess;
+    }
+
+done:
+    PK11_GETTAB(slot)->C_Logout(rwsession);
+    slot->lastLoginCheck = 0;
+    PK11_RestoreROSession(slot,rwsession);
+    if (rv == SECSuccess) {
+        /* update our view of the world */
+        PK11_InitToken(slot,PR_TRUE);
+	if (slot->needLogin) {
+	    PK11_EnterSlotMonitor(slot);
+	    PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER,
+						(unsigned char *)userpw,len);
+	    slot->lastLoginCheck = 0;
+	    PK11_ExitSlotMonitor(slot);
+	}
+    }
+    return rv;
+}
+
+/*
+ * Change an existing user password
+ */
+SECStatus
+PK11_ChangePW(PK11SlotInfo *slot, const char *oldpw, const char *newpw)
+{
+    CK_RV crv;
+    SECStatus rv = SECFailure;
+    int newLen;
+    int oldLen;
+    CK_SESSION_HANDLE rwsession;
+
+    /* use NULL values to trigger the protected authentication path */
+    if (slot->protectedAuthPath) {
+	if (newpw == NULL) newLen = 0;
+	if (oldpw == NULL) oldLen = 0;
+    } else {
+	if (newpw == NULL) newpw = "";
+	if (oldpw == NULL) oldpw = "";
+	newLen = PORT_Strlen(newpw);
+	oldLen = PORT_Strlen(oldpw);
+    }
+
+
+    /* get a rwsession */
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+    	return rv;
+    }
+
+    crv = PK11_GETTAB(slot)->C_SetPIN(rwsession,
+		(unsigned char *)oldpw,oldLen,(unsigned char *)newpw,newLen);
+    if (crv == CKR_OK) {
+	rv = SECSuccess;
+    } else {
+	PORT_SetError(PK11_MapError(crv));
+    }
+
+    PK11_RestoreROSession(slot,rwsession);
+
+    /* update our view of the world */
+    PK11_InitToken(slot,PR_TRUE);
+    return rv;
+}
+
+static char *
+pk11_GetPassword(PK11SlotInfo *slot, PRBool retry, void * wincx)
+{
+    if (PK11_Global.getPass == NULL) return NULL;
+    return (*PK11_Global.getPass)(slot, retry, wincx);
+}
+
+void
+PK11_SetPasswordFunc(PK11PasswordFunc func)
+{
+    PK11_Global.getPass = func;
+}
+
+void
+PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)
+{
+    PK11_Global.verifyPass = func;
+}
+
+void
+PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func)
+{
+    PK11_Global.isLoggedIn = func;
+}
+
+
+/*
+ * authenticate to a slot. This loops until we can't recover, the user
+ * gives up, or we succeed. If we're already logged in and this function
+ * is called we will still prompt for a password, but we will probably
+ * succeed no matter what the password was (depending on the implementation
+ * of the PKCS 11 module.
+ */
+SECStatus
+PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
+{
+    SECStatus rv = SECFailure;
+    char * password;
+    PRBool attempt = PR_FALSE;
+
+    if (PK11_NeedUserInit(slot)) {
+	PORT_SetError(SEC_ERROR_IO);
+	return SECFailure;
+    }
+
+
+    /*
+     * Central server type applications which control access to multiple
+     * slave applications to single crypto devices need to virtuallize the
+     * login state. This is done by a callback out of PK11_IsLoggedIn and
+     * here. If we are actually logged in, then we got here because the
+     * higher level code told us that the particular client application may
+     * still need to be logged in. If that is the case, we simply tell the
+     * server code that it should now verify the clients password and tell us
+     * the results.
+     */
+    if (PK11_IsLoggedIn(slot,NULL) && 
+    			(PK11_Global.verifyPass != NULL)) {
+	if (!PK11_Global.verifyPass(slot,wincx)) {
+	    PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+	    return SECFailure;
+	}
+	return SECSuccess;
+    }
+
+    /* get the password. This can drop out of the while loop
+     * for the following reasons:
+     * 	(1) the user refused to enter a password. 
+     *			(return error to caller)
+     *	(2) the token user password is disabled [usually due to
+     *	   too many failed authentication attempts].
+     *			(return error to caller)
+     *	(3) the password was successful.
+     */
+    while ((password = pk11_GetPassword(slot, attempt, wincx)) != NULL) {
+	/* if the token has a protectedAuthPath, the application may have
+         * already issued the C_Login as part of it's pk11_GetPassword call.
+         * In this case the application will tell us what the results were in 
+         * the password value (retry or the authentication was successful) so
+	 * we can skip our own C_Login call (which would force the token to
+	 * try to login again).
+	 * 
+	 * Applications that don't know about protectedAuthPath will return a 
+	 * password, which we will ignore and trigger the token to 
+	 * 'authenticate' itself anyway. Hopefully the blinking display on 
+	 * the reader, or the flashing light under the thumbprint reader will 
+	 * attract the user's attention */
+	attempt = PR_TRUE;
+	if (slot->protectedAuthPath) {
+	    /* application tried to authenticate and failed. it wants to try
+	     * again, continue looping */
+	    if (strcmp(password, PK11_PW_RETRY) == 0) {
+		rv = SECWouldBlock;
+		PORT_Free(password);
+		continue;
+	    }
+	    /* applicaton tried to authenticate and succeeded we're done */
+	    if (strcmp(password, PK11_PW_AUTHENTICATED) == 0) {
+		rv = SECSuccess;
+		PORT_Free(password);
+		break;
+	    }
+	}
+	rv = pk11_CheckPassword(slot,password);
+	PORT_Memset(password, 0, PORT_Strlen(password));
+	PORT_Free(password);
+	if (rv != SECWouldBlock) break;
+    }
+    if (rv == SECSuccess) {
+	if (!PK11_IsFriendly(slot)) {
+	    nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
+	                                      slot->nssToken);
+	}
+    } else if (!attempt) PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+    return rv;
+}
+
+void PK11_LogoutAll(void)
+{
+    SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
+    SECMODModuleList *modList;
+    SECMODModuleList *mlp = NULL;
+    int i;
+
+    /* NSS is not initialized, there are not tokens to log out */
+    if (lock == NULL) {
+	return;
+    }
+
+    SECMOD_GetReadLock(lock);
+    modList = SECMOD_GetDefaultModuleList();
+    /* find the number of entries */
+    for (mlp = modList; mlp != NULL; mlp = mlp->next) {
+	for (i=0; i < mlp->module->slotCount; i++) {
+	    PK11_Logout(mlp->module->slots[i]);
+	}
+    }
+
+    SECMOD_ReleaseReadLock(lock);
+}
+
+int
+PK11_GetMinimumPwdLength(PK11SlotInfo *slot)
+{
+    return ((int)slot->minPassword);
+}
+
+/* Does this slot have a protected pin path? */
+PRBool
+PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot)
+{
+	return slot->protectedAuthPath;
+}
+
+/*
+ * we can initialize the password if 1) The toke is not inited 
+ * (need login == true and see need UserInit) or 2) the token has
+ * a NULL password. (slot->needLogin = false & need user Init = false).
+ */
+PRBool PK11_NeedPWInitForSlot(PK11SlotInfo *slot)
+{
+    if (slot->needLogin && PK11_NeedUserInit(slot)) {
+	return PR_TRUE;
+    }
+    if (!slot->needLogin && !PK11_NeedUserInit(slot)) {
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+PRBool PK11_NeedPWInit()
+{
+    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
+    PRBool ret = PK11_NeedPWInitForSlot(slot);
+
+    PK11_FreeSlot(slot);
+    return ret;
+}
+
+PRBool 
+pk11_InDelayPeriod(PRIntervalTime lastTime, PRIntervalTime delayTime, 
+						PRIntervalTime *retTime)
+{
+    PRIntervalTime time;
+
+    *retTime = time = PR_IntervalNow();
+    return (PRBool) (lastTime) && ((time-lastTime) < delayTime);
+}
+
+/*
+ * Determine if the token is logged in. We have to actually query the token,
+ * because it's state can change without intervention from us.
+ */
+PRBool
+PK11_IsLoggedIn(PK11SlotInfo *slot,void *wincx)
+{
+    CK_SESSION_INFO sessionInfo;
+    int askpw = slot->askpw;
+    int timeout = slot->timeout;
+    CK_RV crv;
+    PRIntervalTime curTime;
+    static PRIntervalTime login_delay_time = 0;
+
+    if (login_delay_time == 0) {
+	login_delay_time = PR_SecondsToInterval(1);
+    }
+
+    /* If we don't have our own password default values, use the system
+     * ones */
+    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
+	PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
+
+	if (def_slot) {
+	    askpw = def_slot->askpw;
+	    timeout = def_slot->timeout;
+	    PK11_FreeSlot(def_slot);
+	}
+    }
+
+    if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) &&
+	(*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) { return PR_FALSE; }
+
+
+    /* forget the password if we've been inactive too long */
+    if (askpw == 1) {
+	int64 currtime = PR_Now();
+	int64 result;
+	int64 mult;
+	
+	LL_I2L(result, timeout);
+	LL_I2L(mult, 60*1000*1000);
+	LL_MUL(result,result,mult);
+	LL_ADD(result, result, slot->authTime);
+	if (LL_CMP(result, <, currtime) ) {
+	    PK11_EnterSlotMonitor(slot);
+	    PK11_GETTAB(slot)->C_Logout(slot->session);
+	    slot->lastLoginCheck = 0;
+	    PK11_ExitSlotMonitor(slot);
+	} else {
+	    slot->authTime = currtime;
+	}
+    }
+
+    PK11_EnterSlotMonitor(slot);
+    if (pk11_InDelayPeriod(slot->lastLoginCheck,login_delay_time, &curTime)) {
+	sessionInfo.state = slot->lastState;
+	crv = CKR_OK;
+    } else {
+	crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo);
+	if (crv == CKR_OK) {
+	    slot->lastState = sessionInfo.state;
+	    slot->lastLoginCheck = curTime;
+	}
+    }
+    PK11_ExitSlotMonitor(slot);
+    /* if we can't get session info, something is really wrong */
+    if (crv != CKR_OK) {
+	slot->session = CK_INVALID_SESSION;
+	return PR_FALSE;
+    }
+
+    switch (sessionInfo.state) {
+    case CKS_RW_PUBLIC_SESSION:
+    case CKS_RO_PUBLIC_SESSION:
+    default:
+	break; /* fail */
+    case CKS_RW_USER_FUNCTIONS:
+    case CKS_RW_SO_FUNCTIONS:
+    case CKS_RO_USER_FUNCTIONS:
+	return PR_TRUE;
+    }
+    return PR_FALSE; 
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11cert.c b/mozilla/security/nss/lib/pk11wrap/pk11cert.c
new file mode 100644
index 0000000..a51a604
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11cert.c
@@ -0,0 +1,2519 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * This file manages PKCS #11 instances of certificates.
+ */
+
+#include "secport.h"
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "cert.h"
+#include "certi.h"
+#include "secitem.h"
+#include "key.h" 
+#include "secoid.h"
+#include "pkcs7t.h"
+#include "cmsreclist.h"
+
+#include "certdb.h"
+#include "secerr.h"
+#include "sslerr.h"
+
+#include "pki3hack.h"
+#include "dev3hack.h"
+
+#include "devm.h" 
+#include "nsspki.h"
+#include "pki.h"
+#include "pkim.h"
+#include "pkitm.h"
+#include "pkistore.h" /* to remove temp cert */
+#include "devt.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
+
+struct nss3_cert_cbstr {
+    SECStatus(* callback)(CERTCertificate*, void *);
+    nssList *cached;
+    void *arg;
+};
+
+/* Translate from NSSCertificate to CERTCertificate, then pass the latter
+ * to a callback.
+ */
+static PRStatus convert_cert(NSSCertificate *c, void *arg)
+{
+    CERTCertificate *nss3cert;
+    SECStatus secrv;
+    struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg;
+    /* 'c' is not adopted. caller will free it */
+    nss3cert = STAN_GetCERTCertificate(c);
+    if (!nss3cert) return PR_FAILURE;
+    secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg);
+    return (secrv) ? PR_FAILURE : PR_SUCCESS;
+}
+
+/*
+ * build a cert nickname based on the token name and the label of the 
+ * certificate If the label in NULL, build a label based on the ID.
+ */
+static int toHex(int x) { return (x < 10) ? (x+'0') : (x+'a'-10); }
+#define MAX_CERT_ID 4
+#define DEFAULT_STRING "Cert ID "
+static char *
+pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label,
+			CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id)
+{
+    int prefixLen = PORT_Strlen(slot->token_name);
+    int suffixLen = 0;
+    char *suffix = NULL;
+    char buildNew[sizeof(DEFAULT_STRING)+MAX_CERT_ID*2];
+    char *next,*nickname;
+
+    if (cert_label && (cert_label->ulValueLen)) {
+	suffixLen = cert_label->ulValueLen;
+	suffix = (char*)cert_label->pValue;
+    } else if (key_label && (key_label->ulValueLen)) {
+	suffixLen = key_label->ulValueLen;
+	suffix = (char*)key_label->pValue;
+    } else if (cert_id && cert_id->ulValueLen > 0) {
+	int i,first = cert_id->ulValueLen - MAX_CERT_ID;
+	int offset = sizeof(DEFAULT_STRING);
+	char *idValue = (char *)cert_id->pValue;
+
+	PORT_Memcpy(buildNew,DEFAULT_STRING,sizeof(DEFAULT_STRING)-1);
+	next = buildNew + offset;
+	if (first < 0) first = 0;
+	for (i=first; i < (int) cert_id->ulValueLen; i++) {
+		*next++ = toHex((idValue[i] >> 4) & 0xf);
+		*next++ = toHex(idValue[i] & 0xf);
+	}
+	*next++ = 0;
+	suffix = buildNew;
+	suffixLen = PORT_Strlen(buildNew);
+    } else {
+	PORT_SetError( SEC_ERROR_LIBRARY_FAILURE );
+	return NULL;
+    }
+
+    /* if is internal key slot, add code to skip the prefix!! */
+    next = nickname = (char *)PORT_Alloc(prefixLen+1+suffixLen+1);
+    if (nickname == NULL) return NULL;
+
+    PORT_Memcpy(next,slot->token_name,prefixLen);
+    next += prefixLen;
+    *next++ = ':';
+    PORT_Memcpy(next,suffix,suffixLen);
+    next += suffixLen;
+    *next++ = 0;
+    return nickname;
+}
+
+PRBool
+PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,
+						CK_OBJECT_HANDLE certID)
+{
+    CK_OBJECT_CLASS theClass;
+
+    if (slot == NULL) return PR_FALSE;
+    if (cert == NULL) return PR_FALSE;
+
+    theClass = CKO_PRIVATE_KEY;
+    if (pk11_LoginStillRequired(slot,NULL)) {
+	theClass = CKO_PUBLIC_KEY;
+    }
+    if (PK11_MatchItem(slot, certID , theClass) != CK_INVALID_HANDLE) {
+	return PR_TRUE;
+    }
+
+   if (theClass == CKO_PUBLIC_KEY) {
+	SECKEYPublicKey *pubKey= CERT_ExtractPublicKey(cert);
+	CK_ATTRIBUTE theTemplate;
+
+	if (pubKey == NULL) {
+	   return PR_FALSE;
+	}
+
+	PK11_SETATTRS(&theTemplate,0,NULL,0);
+	switch (pubKey->keyType) {
+	case rsaKey:
+	    PK11_SETATTRS(&theTemplate,CKA_MODULUS, pubKey->u.rsa.modulus.data,
+						pubKey->u.rsa.modulus.len);
+	    break;
+	case dsaKey:
+	    PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dsa.publicValue.data,
+						pubKey->u.dsa.publicValue.len);
+	    break;
+	case dhKey:
+	    PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dh.publicValue.data,
+						pubKey->u.dh.publicValue.len);
+	    break;
+	case ecKey:
+	    PK11_SETATTRS(&theTemplate,CKA_EC_POINT, 
+			  pubKey->u.ec.publicValue.data,
+			  pubKey->u.ec.publicValue.len);
+	    break;
+	case keaKey:
+	case fortezzaKey:
+	case nullKey:
+	    /* fall through and return false */
+	    break;
+	}
+
+	if (theTemplate.ulValueLen == 0) {
+	    SECKEY_DestroyPublicKey(pubKey);
+	    return PR_FALSE;
+	}
+	pk11_SignedToUnsigned(&theTemplate);
+	if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_HANDLE) {
+	    SECKEY_DestroyPublicKey(pubKey);
+	    return PR_TRUE;
+	}
+	SECKEY_DestroyPublicKey(pubKey);
+    }
+    return PR_FALSE;
+}
+
+/*
+ * Check out if a cert has ID of zero. This is a magic ID that tells
+ * NSS that this cert may be an automagically trusted cert.
+ * The Cert has to be self signed as well. That check is done elsewhere.
+ *  
+ */
+PRBool
+pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID)
+{
+    CK_ATTRIBUTE keyID = {CKA_ID, NULL, 0};
+    PRBool isZero = PR_FALSE;
+    int i;
+    CK_RV crv;
+
+
+    crv = PK11_GetAttributes(NULL,slot,certID,&keyID,1);
+    if (crv != CKR_OK) {
+	return isZero;
+    }
+
+    if (keyID.ulValueLen != 0) {
+	char *value = (char *)keyID.pValue;
+	isZero = PR_TRUE; /* ID exists, may be zero */
+	for (i=0; i < (int) keyID.ulValueLen; i++) {
+	    if (value[i] != 0) {
+		isZero = PR_FALSE; /* nope */
+		break;
+	    }
+	}
+    }
+    PORT_Free(keyID.pValue);
+    return isZero;
+
+}
+
+/*
+ * Create an NSSCertificate from a slot/certID pair, return it as a
+ * CERTCertificate.  Optionally, output the nickname string.
+ */
+static CERTCertificate *
+pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, 
+	      CK_ATTRIBUTE *privateLabel, char **nickptr)
+{
+    NSSCertificate *c;
+    nssCryptokiObject *co = NULL;
+    nssPKIObject *pkio;
+    NSSToken *token;
+    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+    PRStatus status;
+
+    /* Get the cryptoki object from the handle */
+    token = PK11Slot_GetNSSToken(slot);
+    if (token->defaultSession) {
+	co = nssCryptokiObject_Create(token, token->defaultSession, certID);
+    } else {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+    }
+    if (!co) {
+	return NULL;
+    }
+
+    /* Create a PKI object from the cryptoki instance */
+    pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor);
+    if (!pkio) {
+	nssCryptokiObject_Destroy(co);
+	return NULL;
+    }
+
+    /* Create a certificate */
+    c = nssCertificate_Create(pkio);
+    if (!c) {
+	nssPKIObject_Destroy(pkio);
+	return NULL;
+    }
+
+    /* Build and output a nickname, if desired. 
+     * This must be done before calling nssTrustDomain_AddCertsToCache
+     * because that function may destroy c, pkio and co!
+     */
+    if ((nickptr) && (co->label)) {
+	CK_ATTRIBUTE label, id;
+
+	label.type = CKA_LABEL;
+	label.pValue = co->label;
+	label.ulValueLen = PORT_Strlen(co->label);
+
+	id.type = CKA_ID;
+	id.pValue = c->id.data;
+	id.ulValueLen = c->id.size;
+
+	*nickptr = pk11_buildNickname(slot, &label, privateLabel, &id);
+    }
+
+    /* This function may destroy the cert in "c" and all its subordinate
+     * structures, and replace the value in "c" with the address of a 
+     * different NSSCertificate that it found in the cache.
+     * Presumably, the nickname which we just output above remains valid. :)
+     */
+    status = nssTrustDomain_AddCertsToCache(td, &c, 1);
+    return STAN_GetCERTCertificateOrRelease(c);
+}
+
+/*
+ * Build an CERTCertificate structure from a PKCS#11 object ID.... certID
+ * Must be a CertObject. This code does not explicitly checks that.
+ */
+CERTCertificate *
+PK11_MakeCertFromHandle(PK11SlotInfo *slot,CK_OBJECT_HANDLE certID,
+						CK_ATTRIBUTE *privateLabel)
+{
+    char * nickname = NULL;
+    CERTCertificate *cert = NULL;
+    CERTCertTrust *trust;
+    PRBool isFortezzaRootCA = PR_FALSE;
+    PRBool swapNickname = PR_FALSE;
+
+    cert = pk11_fastCert(slot,certID,privateLabel, &nickname);
+    if (cert == NULL) 
+    	goto loser;
+	
+    if (nickname) {
+	if (cert->nickname != NULL) {
+	    cert->dbnickname = cert->nickname;
+	} 
+	cert->nickname = PORT_ArenaStrdup(cert->arena,nickname);
+	PORT_Free(nickname);
+	nickname = NULL;
+	swapNickname = PR_TRUE;
+    }
+
+    /* remember where this cert came from.... If we have just looked
+     * it up from the database and it already has a slot, don't add a new
+     * one. */
+    if (cert->slot == NULL) {
+	cert->slot = PK11_ReferenceSlot(slot);
+	cert->pkcs11ID = certID;
+	cert->ownSlot = PR_TRUE;
+	cert->series = slot->series;
+    }
+
+    trust = (CERTCertTrust*)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
+    if (trust == NULL) 
+    	goto loser;
+    PORT_Memset(trust,0, sizeof(CERTCertTrust));
+    cert->trust = trust;
+
+    if(! pk11_HandleTrustObject(slot, cert, trust) ) {
+	unsigned int type;
+
+	/* build some cert trust flags */
+	if (CERT_IsCACert(cert, &type)) {
+	    unsigned int trustflags = CERTDB_VALID_CA;
+	   
+	    /* Allow PKCS #11 modules to give us trusted CA's. We only accept
+	     * valid CA's which are self-signed here. They must have an object
+	     * ID of '0'.  */ 
+	    if (pk11_isID0(slot,certID) && 
+		cert->isRoot) {
+		trustflags |= CERTDB_TRUSTED_CA;
+		/* is the slot a fortezza card? allow the user or
+		 * admin to turn on objectSigning, but don't turn
+		 * full trust on explicitly */
+		if (PK11_DoesMechanism(slot,CKM_KEA_KEY_DERIVE)) {
+		    trust->objectSigningFlags |= CERTDB_VALID_CA;
+		    isFortezzaRootCA = PR_TRUE;
+		}
+	    }
+	    if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
+		trust->sslFlags |= trustflags;
+	    }
+	    if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) {
+		trust->emailFlags |= trustflags;
+	    }
+	    if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA) 
+					== NS_CERT_TYPE_OBJECT_SIGNING_CA) {
+		trust->objectSigningFlags |= trustflags;
+	    }
+	}
+    }
+
+    if (PK11_IsUserCert(slot,cert,certID)) {
+	trust->sslFlags |= CERTDB_USER;
+	trust->emailFlags |= CERTDB_USER;
+	/*    trust->objectSigningFlags |= CERTDB_USER; */
+    }
+    return cert;
+
+loser:
+    if (nickname) 
+    	PORT_Free(nickname);
+    if (cert) 
+    	CERT_DestroyCertificate(cert);
+    return NULL;
+}
+
+	
+/*
+ * Build get a certificate from a private key
+ */
+CERTCertificate *
+PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
+{
+    PK11SlotInfo *slot = privKey->pkcs11Slot;
+    CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
+    CK_OBJECT_HANDLE certID = 
+		PK11_MatchItem(slot,handle,CKO_CERTIFICATE);
+    CERTCertificate *cert;
+
+    if (certID == CK_INVALID_HANDLE) {
+	PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
+	return NULL;
+    }
+    cert = PK11_MakeCertFromHandle(slot,certID,NULL);
+    return (cert);
+
+}
+
+/*
+ * delete a cert and it's private key (if no other certs are pointing to the
+ * private key.
+ */
+SECStatus
+PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx)
+{
+    SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert,wincx);
+    CK_OBJECT_HANDLE pubKey;
+    PK11SlotInfo *slot = NULL;
+
+    pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx);
+    if (privKey) {
+	/* For 3.4, utilize the generic cert delete function */
+	SEC_DeletePermCertificate(cert);
+	PK11_DeleteTokenPrivateKey(privKey, PR_FALSE);
+    }
+    if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) { 
+    	PK11_DestroyTokenObject(slot,pubKey);
+        PK11_FreeSlot(slot);
+    }
+    return SECSuccess;
+}
+
+/*
+ * cert callback structure
+ */
+typedef struct pk11DoCertCallbackStr {
+	SECStatus(* callback)(PK11SlotInfo *slot, CERTCertificate*, void *);
+	SECStatus(* noslotcallback)(CERTCertificate*, void *);
+	SECStatus(* itemcallback)(CERTCertificate*, SECItem *, void *);
+	void *callbackArg;
+} pk11DoCertCallback;
+
+
+typedef struct pk11CertCallbackStr {
+	SECStatus(* callback)(CERTCertificate*,SECItem *,void *);
+	void *callbackArg;
+} pk11CertCallback;
+
+struct fake_der_cb_argstr
+{
+    SECStatus(* callback)(CERTCertificate*, SECItem *, void *);
+    void *arg;
+};
+
+static SECStatus fake_der_cb(CERTCertificate *c, void *a)
+{
+    struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a;
+    return (*fda->callback)(c, &c->derCert, fda->arg);
+}
+
+/*
+ * Extract all the certs on a card from a slot.
+ */
+SECStatus
+PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *),
+						void *arg, void *wincx) 
+{
+    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
+    struct fake_der_cb_argstr fda;
+    struct nss3_cert_cbstr pk11cb;
+
+    /* authenticate to the tokens first */
+    (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, wincx);
+
+    fda.callback = callback;
+    fda.arg = arg;
+    pk11cb.callback = fake_der_cb;
+    pk11cb.arg = &fda;
+    NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
+    return SECSuccess;
+}
+
+static void
+transfer_token_certs_to_collection(nssList *certList, NSSToken *token, 
+                                   nssPKIObjectCollection *collection)
+{
+    NSSCertificate **certs;
+    PRUint32 i, count;
+    NSSToken **tokens, **tp;
+    count = nssList_Count(certList);
+    if (count == 0) {
+	return;
+    }
+    certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
+    if (!certs) {
+	return;
+    }
+    nssList_GetArray(certList, (void **)certs, count);
+    for (i=0; i<count; i++) {
+	tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
+	if (tokens) {
+	    for (tp = tokens; *tp; tp++) {
+		if (*tp == token) {
+		    nssPKIObjectCollection_AddObject(collection, 
+		                                     (nssPKIObject *)certs[i]);
+		}
+	    }
+	    nssTokenArray_Destroy(tokens);
+	}
+	CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
+    }
+    nss_ZFreeIf(certs);
+}
+
+CERTCertificate *
+PK11_FindCertFromNickname(const char *nickname, void *wincx) 
+{
+    PRStatus status;
+    CERTCertificate *rvCert = NULL;
+    NSSCertificate *cert = NULL;
+    NSSCertificate **certs = NULL;
+    static const NSSUsage usage = {PR_TRUE /* ... */ };
+    NSSToken *token;
+    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
+    PK11SlotInfo *slot = NULL;
+    SECStatus rv;
+    char *nickCopy;
+    char *delimit = NULL;
+    char *tokenName;
+
+    nickCopy = PORT_Strdup(nickname);
+    if (!nickCopy) {
+        /* error code is set */
+        return NULL;
+    }
+    if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
+	tokenName = nickCopy;
+	nickname = delimit + 1;
+	*delimit = '\0';
+	/* find token by name */
+	token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
+	if (token) {
+	    slot = PK11_ReferenceSlot(token->pk11slot);
+	} else {
+	    PORT_SetError(SEC_ERROR_NO_TOKEN);
+	}
+	*delimit = ':';
+    } else {
+	slot = PK11_GetInternalKeySlot();
+	token = PK11Slot_GetNSSToken(slot);
+    }
+    if (token) {
+	nssList *certList;
+	nssCryptokiObject **instances;
+	nssPKIObjectCollection *collection;
+	nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+	if (!PK11_IsPresent(slot)) {
+	    goto loser;
+	}
+   	rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+	collection = nssCertificateCollection_Create(defaultTD, NULL);
+	if (!collection) {
+	    goto loser;
+	}
+	certList = nssList_Create(NULL, PR_FALSE);
+	if (!certList) {
+	    nssPKIObjectCollection_Destroy(collection);
+	    goto loser;
+	}
+	(void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, 
+	                                                  nickname, 
+	                                                  certList);
+	transfer_token_certs_to_collection(certList, token, collection);
+	instances = nssToken_FindCertificatesByNickname(token,
+	                                                NULL,
+	                                                nickname,
+	                                                tokenOnly,
+	                                                0,
+	                                                &status);
+	nssPKIObjectCollection_AddInstances(collection, instances, 0);
+	nss_ZFreeIf(instances);
+	/* if it wasn't found, repeat the process for email address */
+	if (nssPKIObjectCollection_Count(collection) == 0 &&
+	    PORT_Strchr(nickname, '@') != NULL) 
+	{
+	    char* lowercaseName = CERT_FixupEmailAddr(nickname);
+	    if (lowercaseName) {
+		(void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, 
+								      lowercaseName, 
+								      certList);
+		transfer_token_certs_to_collection(certList, token, collection);
+		instances = nssToken_FindCertificatesByEmail(token,
+							     NULL,
+							     lowercaseName,
+							     tokenOnly,
+							     0,
+							     &status);
+		nssPKIObjectCollection_AddInstances(collection, instances, 0);
+		nss_ZFreeIf(instances);
+		PORT_Free(lowercaseName);
+	    }
+	}
+	certs = nssPKIObjectCollection_GetCertificates(collection, 
+	                                               NULL, 0, NULL);
+	nssPKIObjectCollection_Destroy(collection);
+	if (certs) {
+	    cert = nssCertificateArray_FindBestCertificate(certs, NULL, 
+	                                                   &usage, NULL);
+	    if (cert) {
+		rvCert = STAN_GetCERTCertificateOrRelease(cert);
+	    }
+	    nssCertificateArray_Destroy(certs);
+	}
+	nssList_Destroy(certList);
+    }
+    if (slot) {
+	PK11_FreeSlot(slot);
+    }
+    if (nickCopy) PORT_Free(nickCopy);
+    return rvCert;
+loser:
+    if (slot) {
+	PK11_FreeSlot(slot);
+    }
+    if (nickCopy) PORT_Free(nickCopy);
+    return NULL;
+}
+
+CERTCertList *
+PK11_FindCertsFromNickname(const char *nickname, void *wincx) 
+{
+    char *nickCopy;
+    char *delimit = NULL;
+    char *tokenName;
+    int i;
+    CERTCertList *certList = NULL;
+    nssPKIObjectCollection *collection = NULL;
+    NSSCertificate **foundCerts = NULL;
+    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
+    NSSCertificate *c;
+    NSSToken *token;
+    PK11SlotInfo *slot;
+    SECStatus rv;
+
+    nickCopy = PORT_Strdup(nickname);
+    if (!nickCopy) {
+        /* error code is set */
+        return NULL;
+    }
+    if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
+	tokenName = nickCopy;
+	nickname = delimit + 1;
+	*delimit = '\0';
+	/* find token by name */
+	token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
+	if (token) {
+	    slot = PK11_ReferenceSlot(token->pk11slot);
+	} else {
+	    PORT_SetError(SEC_ERROR_NO_TOKEN);
+	    slot = NULL;
+	}
+	*delimit = ':';
+    } else {
+	slot = PK11_GetInternalKeySlot();
+	token = PK11Slot_GetNSSToken(slot);
+    }
+    if (token) {
+	PRStatus status;
+	nssList *nameList;
+	nssCryptokiObject **instances;
+	nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+   	rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) {
+	    PK11_FreeSlot(slot);
+    	    if (nickCopy) PORT_Free(nickCopy);
+	    return NULL;
+	}
+	collection = nssCertificateCollection_Create(defaultTD, NULL);
+	if (!collection) {
+	    PK11_FreeSlot(slot);
+	    if (nickCopy) PORT_Free(nickCopy);
+	    return NULL;
+	}
+	nameList = nssList_Create(NULL, PR_FALSE);
+	if (!nameList) {
+	    PK11_FreeSlot(slot);
+	    if (nickCopy) PORT_Free(nickCopy);
+	    return NULL;
+	}
+	(void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
+	                                                  nickname, 
+	                                                  nameList);
+	transfer_token_certs_to_collection(nameList, token, collection);
+	instances = nssToken_FindCertificatesByNickname(token,
+	                                                NULL,
+	                                                nickname,
+	                                                tokenOnly,
+	                                                0,
+	                                                &status);
+	nssPKIObjectCollection_AddInstances(collection, instances, 0);
+	nss_ZFreeIf(instances);
+
+        /* if it wasn't found, repeat the process for email address */
+        if (nssPKIObjectCollection_Count(collection) == 0 &&
+            PORT_Strchr(nickname, '@') != NULL) 
+        {
+            char* lowercaseName = CERT_FixupEmailAddr(nickname);
+            if (lowercaseName) {
+                (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, 
+                                                                      lowercaseName, 
+                                                                      nameList);
+                transfer_token_certs_to_collection(nameList, token, collection);
+                instances = nssToken_FindCertificatesByEmail(token,
+                                                             NULL,
+                                                             lowercaseName,
+                                                             tokenOnly,
+                                                             0,
+                                                             &status);
+                nssPKIObjectCollection_AddInstances(collection, instances, 0);
+                nss_ZFreeIf(instances);
+                PORT_Free(lowercaseName);
+            }
+        }
+
+        nssList_Destroy(nameList);
+	foundCerts = nssPKIObjectCollection_GetCertificates(collection,
+	                                                    NULL, 0, NULL);
+	nssPKIObjectCollection_Destroy(collection);
+    }
+    if (slot) {
+	PK11_FreeSlot(slot);
+    }
+    if (nickCopy) PORT_Free(nickCopy);
+    if (foundCerts) {
+	PRTime now = PR_Now();
+	certList = CERT_NewCertList();
+	for (i=0, c = *foundCerts; c; c = foundCerts[++i]) {
+	    if (certList) {
+	 	CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
+		/* c may be invalid after this, don't reference it */
+		if (certCert) {
+		    /* CERT_AddCertToListSorted adopts certCert  */
+		    CERT_AddCertToListSorted(certList, certCert,
+				CERT_SortCBValidity, &now);
+		}
+	    } else {
+		nssCertificate_Destroy(c);
+	    }
+	}
+	if (certList && CERT_LIST_HEAD(certList) == NULL) {
+	    CERT_DestroyCertList(certList);
+	    certList = NULL;
+	}
+	/* all the certs have been adopted or freed, free the  raw array */
+	nss_ZFreeIf(foundCerts);
+    }
+    return certList;
+}
+
+/*
+ * extract a key ID for a certificate...
+ * NOTE: We call this function from PKCS11.c If we ever use
+ * pkcs11 to extract the public key (we currently do not), this will break.
+ */
+SECItem *
+PK11_GetPubIndexKeyID(CERTCertificate *cert) 
+{
+    SECKEYPublicKey *pubk;
+    SECItem *newItem = NULL;
+
+    pubk = CERT_ExtractPublicKey(cert);
+    if (pubk == NULL) return NULL;
+
+    switch (pubk->keyType) {
+    case rsaKey:
+	newItem = SECITEM_DupItem(&pubk->u.rsa.modulus);
+	break;
+    case dsaKey:
+        newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue);
+	break;
+    case dhKey:
+        newItem = SECITEM_DupItem(&pubk->u.dh.publicValue);
+	break;
+    case ecKey:
+        newItem = SECITEM_DupItem(&pubk->u.ec.publicValue);
+	break;
+    case fortezzaKey:
+    default:
+	newItem = NULL; /* Fortezza Fix later... */
+    }
+    SECKEY_DestroyPublicKey(pubk);
+    /* make hash of it */
+    return newItem;
+}
+
+/*
+ * generate a CKA_ID from a certificate.
+ */
+SECItem *
+pk11_mkcertKeyID(CERTCertificate *cert) 
+{
+    SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert) ;
+    SECItem *certCKA_ID;
+
+    if (pubKeyData == NULL) return NULL;
+    
+    certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData);
+    SECITEM_FreeItem(pubKeyData,PR_TRUE);
+    return certCKA_ID;
+}
+
+/*
+ * Write the cert into the token.
+ */
+SECStatus
+PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, 
+		CK_OBJECT_HANDLE key, const char *nickname, 
+                PRBool includeTrust) 
+{
+    PRStatus status;
+    NSSCertificate *c;
+    nssCryptokiObject *keyobj, *certobj;
+    NSSToken *token = PK11Slot_GetNSSToken(slot);
+    SECItem *keyID = pk11_mkcertKeyID(cert);
+    char *emailAddr = NULL;
+    nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
+    nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
+
+    if (keyID == NULL) {
+	goto loser; /* error code should be set already */
+    }
+    if (!token) {
+    	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	goto loser;
+    }
+
+    if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) {
+	emailAddr = cert->emailAddr;
+    }
+
+    /* need to get the cert as a stan cert */
+    if (cert->nssCertificate) {
+	c = cert->nssCertificate;
+    } else {
+	c = STAN_GetNSSCertificate(cert);
+	if (c == NULL) {
+	    goto loser;
+	}
+    }
+
+    /* set the id for the cert */
+    nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
+    if (!c->id.data) {
+	goto loser;
+    }
+
+    if (key != CK_INVALID_HANDLE) {
+	/* create an object for the key, ... */
+	keyobj = nss_ZNEW(NULL, nssCryptokiObject);
+	if (!keyobj) {
+	    goto loser;
+	}
+	keyobj->token = nssToken_AddRef(token);
+	keyobj->handle = key;
+	keyobj->isTokenObject = PR_TRUE;
+
+	/* ... in order to set matching attributes for the key */
+	status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname, 
+	                                              &c->id, &c->subject);
+	nssCryptokiObject_Destroy(keyobj);
+	if (status != PR_SUCCESS) {
+	    goto loser;
+	}
+    }
+
+    /* do the token import */
+    certobj = nssToken_ImportCertificate(token, NULL,
+                                         NSSCertificateType_PKIX,
+                                         &c->id,
+                                         nickname,
+                                         &c->encoding,
+                                         &c->issuer,
+                                         &c->subject,
+                                         &c->serial,
+					 emailAddr,
+                                         PR_TRUE);
+    if (!certobj) {
+	if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
+	    PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
+	    SECITEM_FreeItem(keyID,PR_TRUE);
+	    return SECFailure;
+	}
+	goto loser;
+    }
+
+    if (c->object.cryptoContext) {
+	/* Delete the temp instance */
+	NSSCryptoContext *cc = c->object.cryptoContext;
+	nssCertificateStore_Lock(cc->certStore, &lockTrace);
+	nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
+	nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace);
+	c->object.cryptoContext = NULL;
+	cert->istemp = PR_FALSE;
+	cert->isperm = PR_TRUE;
+    }
+
+    /* add the new instance to the cert, force an update of the
+     * CERTCertificate, and finish
+     */
+    nssPKIObject_AddInstance(&c->object, certobj);
+    nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
+    (void)STAN_ForceCERTCertificateUpdate(c);
+    SECITEM_FreeItem(keyID,PR_TRUE);
+    return SECSuccess;
+loser:
+    CERT_MapStanError();
+    SECITEM_FreeItem(keyID,PR_TRUE);
+    if (PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
+	PORT_SetError(SEC_ERROR_ADDING_CERT);
+    }
+    return SECFailure;
+}
+
+SECStatus
+PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert,
+		CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) 
+{
+    CERTCertificate *cert;
+    SECStatus rv;
+
+    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+                                   derCert, NULL, PR_FALSE, PR_TRUE);
+    if (cert == NULL) return SECFailure;
+
+    rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust);
+    CERT_DestroyCertificate (cert);
+    return rv;
+}
+
+/*
+ * get a certificate handle, look at the cached handle first..
+ */
+CK_OBJECT_HANDLE
+pk11_getcerthandle(PK11SlotInfo *slot, CERTCertificate *cert, 
+					CK_ATTRIBUTE *theTemplate,int tsize)
+{
+    CK_OBJECT_HANDLE certh;
+
+    if (cert->slot == slot) {
+	certh = cert->pkcs11ID;
+	if ((certh == CK_INVALID_HANDLE) ||
+			(cert->series != slot->series)) {
+    	     certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
+	     cert->pkcs11ID = certh;
+	     cert->series = slot->series;
+	}
+    } else {
+    	certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
+    }
+    return certh;
+}
+
+/*
+ * return the private key From a given Cert
+ */
+SECKEYPrivateKey *
+PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert,
+								 void *wincx) 
+{
+    int err;
+    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_VALUE, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 }
+    };
+    /* if you change the array, change the variable below as well */
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    CK_OBJECT_HANDLE certh;
+    CK_OBJECT_HANDLE keyh;
+    CK_ATTRIBUTE *attrs = theTemplate;
+    PRBool needLogin;
+    SECStatus rv;
+
+    PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, 
+						cert->derCert.len); attrs++;
+    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
+
+    /*
+     * issue the find
+     */
+    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
+    if (rv != SECSuccess) {
+	return NULL;
+    }
+
+    certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
+    if (certh == CK_INVALID_HANDLE) {
+	return NULL;
+    }
+    /*
+     * prevent a login race condition. If slot is logged in between
+     * our call to pk11_LoginStillRequired and the 
+     * PK11_MatchItem. The matchItem call will either succeed, or
+     * we will call it one more time after calling PK11_Authenticate 
+     * (which is a noop on an authenticated token).
+     */
+    needLogin = pk11_LoginStillRequired(slot,wincx);
+    keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
+    if ((keyh == CK_INVALID_HANDLE) && needLogin &&
+                        (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
+			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
+	/* try it again authenticated */
+	rv = PK11_Authenticate(slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) {
+	    return NULL;
+	}
+	keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
+    }
+    if (keyh == CK_INVALID_HANDLE) { 
+	return NULL; 
+    }
+    return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx);
+} 
+
+/*
+ * import a cert for a private key we have already generated. Set the label
+ * on both to be the nickname. This is for the Key Gen, orphaned key case.
+ */
+PK11SlotInfo *
+PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr, 
+								void *wincx) 
+{
+    PK11SlotList *list;
+    PK11SlotListElement *le;
+    SECItem *keyID;
+    CK_OBJECT_HANDLE key;
+    PK11SlotInfo *slot = NULL;
+    SECStatus rv;
+    int err;
+
+    keyID = pk11_mkcertKeyID(cert);
+    /* get them all! */
+    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
+    if ((keyID == NULL) || (list == NULL)) {
+	if (keyID) SECITEM_FreeItem(keyID,PR_TRUE);
+	if (list) PK11_FreeSlotList(list);
+    	return NULL;
+    }
+
+    /* Look for the slot that holds the Key */
+    for (le = list->head ; le; le = le->next) {
+	/*
+	 * prevent a login race condition. If le->slot is logged in between
+	 * our call to pk11_LoginStillRequired and the 
+	 * pk11_FindPrivateKeyFromCertID, the find will either succeed, or
+	 * we will call it one more time after calling PK11_Authenticate 
+	 * (which is a noop on an authenticated token).
+	 */
+	PRBool needLogin = pk11_LoginStillRequired(le->slot,wincx);
+	key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
+	if ((key == CK_INVALID_HANDLE) && needLogin &&
+            		(SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
+			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
+	    /* authenticate and try again */
+	    rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
+	    if (rv != SECSuccess) continue;
+	    key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
+	}
+	if (key != CK_INVALID_HANDLE) {
+	    slot = PK11_ReferenceSlot(le->slot);
+	    if (keyPtr) *keyPtr = key;
+	    break;
+	}
+    }
+
+    SECITEM_FreeItem(keyID,PR_TRUE);
+    PK11_FreeSlotList(list);
+    return slot;
+
+}
+/*
+ * import a cert for a private key we have already generated. Set the label
+ * on both to be the nickname. This is for the Key Gen, orphaned key case.
+ */
+PK11SlotInfo *
+PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr, 
+								void *wincx) 
+{
+    CERTCertificate *cert;
+    PK11SlotInfo *slot = NULL;
+
+    /* letting this use go -- the only thing that the cert is used for is
+     * to get the ID attribute.
+     */
+    cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
+    if (cert == NULL) return NULL;
+
+    slot = PK11_KeyForCertExists(cert, keyPtr, wincx);
+    CERT_DestroyCertificate (cert);
+    return slot;
+}
+
+PK11SlotInfo *
+PK11_ImportCertForKey(CERTCertificate *cert, const char *nickname,
+                      void *wincx) 
+{
+    PK11SlotInfo *slot = NULL;
+    CK_OBJECT_HANDLE key;
+
+    slot = PK11_KeyForCertExists(cert,&key,wincx);
+
+    if (slot) {
+	if (PK11_ImportCert(slot,cert,key,nickname,PR_FALSE) != SECSuccess) {
+	    PK11_FreeSlot(slot);
+	    slot = NULL;
+	}
+    } else {
+	PORT_SetError(SEC_ERROR_ADDING_CERT);
+    }
+
+    return slot;
+}
+
+PK11SlotInfo *
+PK11_ImportDERCertForKey(SECItem *derCert, char *nickname,void *wincx) 
+{
+    CERTCertificate *cert;
+    PK11SlotInfo *slot = NULL;
+
+    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+                                   derCert, NULL, PR_FALSE, PR_TRUE);
+    if (cert == NULL) return NULL;
+
+    slot = PK11_ImportCertForKey(cert, nickname, wincx);
+    CERT_DestroyCertificate (cert);
+    return slot;
+}
+
+static CK_OBJECT_HANDLE
+pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr, 
+		CK_ATTRIBUTE *searchTemplate, int count, void *wincx) 
+{
+    PK11SlotList *list;
+    PK11SlotListElement *le;
+    CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
+    PK11SlotInfo *slot = NULL;
+    SECStatus rv;
+
+    *slotPtr = NULL;
+
+    /* get them all! */
+    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
+    if (list == NULL) {
+    	return CK_INVALID_HANDLE;
+    }
+
+
+    /* Look for the slot that holds the Key */
+    for (le = list->head ; le; le = le->next) {
+	rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) continue;
+
+	certHandle = pk11_FindObjectByTemplate(le->slot,searchTemplate,count);
+	if (certHandle != CK_INVALID_HANDLE) {
+	    slot = PK11_ReferenceSlot(le->slot);
+	    break;
+	}
+    }
+
+    PK11_FreeSlotList(list);
+
+    if (slot == NULL) {
+	return CK_INVALID_HANDLE;
+    }
+    *slotPtr = slot;
+    return certHandle;
+}
+
+CERTCertificate *
+PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot, 
+				CERTIssuerAndSN *issuerSN, void *wincx)
+{
+    CERTCertificate *rvCert = NULL;
+    NSSCertificate *cert = NULL;
+    NSSDER issuer, serial;
+    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+    NSSToken *token = slot->nssToken;
+    nssSession *session;
+    nssCryptokiObject *instance = NULL;
+    nssPKIObject *object = NULL;
+    SECItem *derSerial;
+    PRStatus status;
+
+    if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
+        !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 
+	issuerSN->derIssuer.len    > CERT_MAX_DN_BYTES ||
+	issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) {
+    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    /* Paranoia */
+    if (token == NULL) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+
+
+    /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
+     * CERTIssuerAndSN that actually has the encoded value and pass that
+     * to PKCS#11 (and the crypto context).
+     */
+    derSerial = SEC_ASN1EncodeItem(NULL, NULL,
+                                   &issuerSN->serialNumber,
+                                   SEC_ASN1_GET(SEC_IntegerTemplate));
+    if (!derSerial) {
+	return NULL;
+    }
+
+    NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
+    NSSITEM_FROM_SECITEM(&serial, derSerial);
+
+    session = nssToken_GetDefaultSession(token);
+    if (!session) {
+	goto loser;
+    }
+
+    instance = nssToken_FindCertificateByIssuerAndSerialNumber(token,session,
+		&issuer, &serial, nssTokenSearchType_TokenForced, &status);
+
+    SECITEM_FreeItem(derSerial, PR_TRUE);
+
+    if (!instance) {
+	goto loser;
+    }
+    object = nssPKIObject_Create(NULL, instance, td, NULL, nssPKIMonitor);
+    if (!object) {
+	goto loser;
+    }
+    instance = NULL; /* adopted by the previous call */
+    cert = nssCertificate_Create(object);
+    if (!cert) {
+	goto loser;
+    }
+    object = NULL; /* adopted by the previous call */
+    nssTrustDomain_AddCertsToCache(td, &cert,1);
+    /* on failure, cert is freed below */
+    rvCert = STAN_GetCERTCertificate(cert);
+    if (!rvCert) {
+	goto loser;
+    }
+    return rvCert;
+
+loser:
+    if (instance) {
+	nssCryptokiObject_Destroy(instance);
+    }
+    if (object) {
+	nssPKIObject_Destroy(object);
+    }
+    if (cert) {
+	nssCertificate_Destroy(cert);
+    }
+    return NULL;
+}
+
+/*
+ * We're looking for a cert which we have the private key for that's on the
+ * list of recipients. This searches one slot.
+ * this is the new version for NSS SMIME code
+ * this stuff should REALLY be in the SMIME code, but some things in here are not public
+ * (they should be!)
+ */
+static CERTCertificate *
+pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist, int *rlIndex, void *pwarg)
+{
+    NSSCMSRecipient *ri = NULL;
+    int i;
+
+    for (i=0; (ri = recipientlist[i]) != NULL; i++) {
+	CERTCertificate *cert = NULL;
+	if (ri->kind == RLSubjKeyID) {
+	    SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
+	    if (derCert) {
+		cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg);
+		SECITEM_FreeItem(derCert, PR_TRUE);
+	    }
+	} else {
+	    cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN, 
+						     pwarg);
+	}
+	if (cert) {
+	    /* this isn't our cert */
+	    if ((cert->trust == NULL) ||
+       		((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) {
+		 CERT_DestroyCertificate(cert);
+		continue;
+	    }
+	    ri->slot = PK11_ReferenceSlot(slot);
+	    *rlIndex = i;
+	    return cert;
+	}
+    }
+    *rlIndex = -1;
+    return NULL;
+}
+
+/*
+ * This function is the same as above, but it searches all the slots.
+ * this is the new version for NSS SMIME code
+ * this stuff should REALLY be in the SMIME code, but some things in here are not public
+ * (they should be!)
+ */
+static CERTCertificate *
+pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex)
+{
+    PK11SlotList *list;
+    PK11SlotListElement *le;
+    CERTCertificate *cert = NULL;
+    SECStatus rv;
+
+    /* get them all! */
+    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
+    if (list == NULL) {
+    	return CK_INVALID_HANDLE;
+    }
+
+    /* Look for the slot that holds the Key */
+    for (le = list->head ; le; le = le->next) {
+	rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) continue;
+
+	cert = pk11_FindCertObjectByRecipientNew(le->slot, 
+					recipientlist, rlIndex, wincx);
+	if (cert)
+	    break;
+    }
+
+    PK11_FreeSlotList(list);
+
+    return cert;
+}
+
+/*
+ * We're looking for a cert which we have the private key for that's on the
+ * list of recipients. This searches one slot.
+ */
+static CERTCertificate *
+pk11_FindCertObjectByRecipient(PK11SlotInfo *slot, 
+	SEC_PKCS7RecipientInfo **recipientArray,
+	SEC_PKCS7RecipientInfo **rip, void *pwarg)
+{
+    SEC_PKCS7RecipientInfo *ri = NULL;
+    int i;
+
+    for (i=0; (ri = recipientArray[i]) != NULL; i++) {
+	CERTCertificate *cert;
+
+	cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN, 
+								pwarg);
+        if (cert) {
+	    /* this isn't our cert */
+	    if ((cert->trust == NULL) ||
+       		((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) {
+		 CERT_DestroyCertificate(cert);
+		continue;
+	    }
+	    *rip = ri;
+	    return cert;
+	}
+
+    }
+    *rip = NULL;
+    return NULL;
+}
+
+/*
+ * This function is the same as above, but it searches all the slots.
+ */
+static CERTCertificate *
+pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr, 
+	SEC_PKCS7RecipientInfo **recipientArray,SEC_PKCS7RecipientInfo **rip,
+							void *wincx) 
+{
+    PK11SlotList *list;
+    PK11SlotListElement *le;
+    CERTCertificate * cert = NULL;
+    PK11SlotInfo *slot = NULL;
+    SECStatus rv;
+
+    *slotPtr = NULL;
+
+    /* get them all! */
+    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
+    if (list == NULL) {
+    	return CK_INVALID_HANDLE;
+    }
+
+    *rip = NULL;
+
+    /* Look for the slot that holds the Key */
+    for (le = list->head ; le; le = le->next) {
+	rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) continue;
+
+	cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray, 
+							rip, wincx);
+	if (cert) {
+	    slot = PK11_ReferenceSlot(le->slot);
+	    break;
+	}
+    }
+
+    PK11_FreeSlotList(list);
+
+    if (slot == NULL) {
+	return NULL;
+    }
+    *slotPtr = slot;
+    PORT_Assert(cert != NULL);
+    return cert;
+}
+
+/*
+ * We need to invert the search logic for PKCS 7 because if we search for
+ * each cert on the list over all the slots, we wind up with lots of spurious
+ * password prompts. This way we get only one password prompt per slot, at
+ * the max, and most of the time we can find the cert, and only prompt for
+ * the key...
+ */
+CERTCertificate *
+PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr, 
+	SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip,
+				SECKEYPrivateKey**privKey, void *wincx)
+{
+    CERTCertificate *cert = NULL;
+
+    *privKey = NULL;
+    *slotPtr = NULL;
+    cert = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx);
+    if (!cert) {
+	return NULL;
+    }
+
+    *privKey = PK11_FindKeyByAnyCert(cert, wincx);
+    if (*privKey == NULL) {
+	goto loser;
+    }
+
+    return cert;
+loser:
+    if (cert) CERT_DestroyCertificate(cert);
+    if (*slotPtr) PK11_FreeSlot(*slotPtr);
+    *slotPtr = NULL;
+    return NULL;
+}
+
+static PRCallOnceType keyIDHashCallOnce;
+
+static PRStatus PR_CALLBACK
+pk11_keyIDHash_populate(void *wincx)
+{
+    CERTCertList     *certList;
+    CERTCertListNode *node = NULL;
+    SECItem           subjKeyID = {siBuffer, NULL, 0};
+
+    certList = PK11_ListCerts(PK11CertListUser, wincx);
+    if (!certList) {
+	return PR_FAILURE;
+    }
+
+    for (node = CERT_LIST_HEAD(certList);
+         !CERT_LIST_END(node, certList);
+         node = CERT_LIST_NEXT(node)) {
+	if (CERT_FindSubjectKeyIDExtension(node->cert, 
+	                                   &subjKeyID) == SECSuccess && 
+	    subjKeyID.data != NULL) {
+	    cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert);
+	    SECITEM_FreeItem(&subjKeyID, PR_FALSE);
+	}
+    }
+    CERT_DestroyCertList(certList);
+    return PR_SUCCESS;
+}
+
+/*
+ * This is the new version of the above function for NSS SMIME code
+ * this stuff should REALLY be in the SMIME code, but some things in here are not public
+ * (they should be!)
+ */
+int
+PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx)
+{
+    CERTCertificate *cert;
+    NSSCMSRecipient *rl;
+    PRStatus rv;
+    int rlIndex;
+
+    rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx);
+    if (rv != PR_SUCCESS)
+	return -1;
+
+    cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
+    if (!cert) {
+	return -1;
+    }
+
+    rl = recipientlist[rlIndex];
+
+    /* at this point, rl->slot is set */
+
+    rl->privkey = PK11_FindKeyByAnyCert(cert, wincx);
+    if (rl->privkey == NULL) {
+	goto loser;
+    }
+
+    /* make a cert from the cert handle */
+    rl->cert = cert;
+    return rlIndex;
+
+loser:
+    if (cert) CERT_DestroyCertificate(cert);
+    if (rl->slot) PK11_FreeSlot(rl->slot);
+    rl->slot = NULL;
+    return -1;
+}
+
+CERTCertificate *
+PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
+							 void *wincx)
+{
+    CERTCertificate *rvCert = NULL;
+    NSSCertificate *cert;
+    NSSDER issuer, serial;
+    NSSCryptoContext *cc;
+    SECItem *derSerial;
+
+    if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
+        !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 
+	issuerSN->derIssuer.len    > CERT_MAX_DN_BYTES ||
+	issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) {
+    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    if (slotPtr) *slotPtr = NULL;
+
+    /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
+     * CERTIssuerAndSN that actually has the encoded value and pass that
+     * to PKCS#11 (and the crypto context).
+     */
+    derSerial = SEC_ASN1EncodeItem(NULL, NULL,
+                                   &issuerSN->serialNumber,
+                                   SEC_ASN1_GET(SEC_IntegerTemplate));
+    if (!derSerial) {
+	return NULL;
+    }
+
+    NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
+    NSSITEM_FROM_SECITEM(&serial, derSerial);
+
+    cc = STAN_GetDefaultCryptoContext();
+    cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc, 
+                                                                &issuer, 
+                                                                &serial);
+    if (cert) {
+	SECITEM_FreeItem(derSerial, PR_TRUE);
+	return STAN_GetCERTCertificateOrRelease(cert);
+    }
+
+    do {
+	/* free the old cert on retry. Associated slot was not present */
+	if (rvCert) {
+	    CERT_DestroyCertificate(rvCert);
+	    rvCert = NULL;
+ 	}
+
+	cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
+                                                  STAN_GetDefaultTrustDomain(),
+                                                  &issuer,
+                                                  &serial);
+	if (!cert) {
+	    break;
+	}
+
+	rvCert = STAN_GetCERTCertificateOrRelease(cert);
+	if (rvCert == NULL) {
+	   break;
+	}
+
+	/* Check to see if the cert's token is still there */
+    } while (!PK11_IsPresent(rvCert->slot));
+
+    if (rvCert && slotPtr) *slotPtr = PK11_ReferenceSlot(rvCert->slot);
+
+    SECITEM_FreeItem(derSerial, PR_TRUE);
+    return rvCert;
+}
+
+CK_OBJECT_HANDLE
+PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot)
+{
+    CK_OBJECT_HANDLE certHandle;
+    CK_ATTRIBUTE searchTemplate	= { CKA_VALUE, NULL, 0 };
+    
+    PK11_SETATTRS(&searchTemplate, CKA_VALUE, cert->derCert.data,
+		  cert->derCert.len);
+
+    if (cert->slot) {
+	certHandle = pk11_getcerthandle(cert->slot,cert,&searchTemplate,1);
+	if (certHandle != CK_INVALID_HANDLE) {
+	    *pSlot = PK11_ReferenceSlot(cert->slot);
+	    return certHandle;
+	}
+    }
+
+    certHandle = pk11_FindCertObjectByTemplate(pSlot,&searchTemplate,1,wincx);
+    if (certHandle != CK_INVALID_HANDLE) {
+	if (cert->slot == NULL) {
+	    cert->slot = PK11_ReferenceSlot(*pSlot);
+	    cert->pkcs11ID = certHandle;
+	    cert->ownSlot = PR_TRUE;
+	    cert->series = cert->slot->series;
+	}
+    }
+
+    return(certHandle);
+}
+
+SECKEYPrivateKey *
+PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx)
+{
+    CK_OBJECT_HANDLE certHandle;
+    CK_OBJECT_HANDLE keyHandle;
+    PK11SlotInfo *slot = NULL;
+    SECKEYPrivateKey *privKey = NULL;
+    PRBool needLogin;
+    SECStatus rv;
+    int err;
+
+    certHandle = PK11_FindObjectForCert(cert, wincx, &slot);
+    if (certHandle == CK_INVALID_HANDLE) {
+	 return NULL;
+    }
+    /*
+     * prevent a login race condition. If slot is logged in between
+     * our call to pk11_LoginStillRequired and the 
+     * PK11_MatchItem. The matchItem call will either succeed, or
+     * we will call it one more time after calling PK11_Authenticate 
+     * (which is a noop on an authenticated token).
+     */
+    needLogin = pk11_LoginStillRequired(slot,wincx);
+    keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
+    if ((keyHandle == CK_INVALID_HANDLE) &&  needLogin &&
+			(SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
+			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err ) ) {
+	/* authenticate and try again */
+	rv = PK11_Authenticate(slot, PR_TRUE, wincx);
+	if (rv == SECSuccess) {
+            keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
+	}
+    }
+    if (keyHandle != CK_INVALID_HANDLE) { 
+        privKey =  PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
+    }
+    if (slot) {
+	PK11_FreeSlot(slot);
+    }
+    return privKey;
+}
+
+CK_OBJECT_HANDLE
+pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx)
+{
+    CK_OBJECT_HANDLE certHandle;
+    CK_OBJECT_HANDLE keyHandle;
+
+    certHandle = PK11_FindObjectForCert(cert, wincx, slot);
+    if (certHandle == CK_INVALID_HANDLE) {
+	 return CK_INVALID_HANDLE;
+    }
+    keyHandle = PK11_MatchItem(*slot,certHandle,CKO_PUBLIC_KEY);
+    if (keyHandle == CK_INVALID_HANDLE) { 
+	PK11_FreeSlot(*slot);
+	return CK_INVALID_HANDLE;
+    }
+    return keyHandle;
+}
+
+/*
+ * find the number of certs in the slot with the same subject name
+ */
+int
+PK11_NumberCertsForCertSubject(CERTCertificate *cert)
+{
+    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_SUBJECT, NULL, 0 },
+    };
+    CK_ATTRIBUTE *attr = theTemplate;
+   int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+
+    PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
+    PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len);
+
+    if (cert->slot == NULL) {
+	PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
+							PR_FALSE,PR_TRUE,NULL);
+	PK11SlotListElement *le;
+	int count = 0;
+
+	if (!list) {
+            /* error code is set */
+            return 0;
+	}
+
+	/* loop through all the fortezza tokens */
+	for (le = list->head; le; le = le->next) {
+	    count += PK11_NumberObjectsFor(le->slot,theTemplate,templateSize);
+	}
+	PK11_FreeSlotList(list);
+	return count;
+    }
+
+    return PK11_NumberObjectsFor(cert->slot,theTemplate,templateSize);
+}
+
+/*
+ *  Walk all the certs with the same subject
+ */
+SECStatus
+PK11_TraverseCertsForSubject(CERTCertificate *cert,
+        SECStatus(* callback)(CERTCertificate*, void *), void *arg)
+{
+    if(!cert) {
+	return SECFailure;
+    }
+    if (cert->slot == NULL) {
+	PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
+							PR_FALSE,PR_TRUE,NULL);
+	PK11SlotListElement *le;
+
+	if (!list) {
+            /* error code is set */
+            return SECFailure;
+	}
+	/* loop through all the tokens */
+	for (le = list->head; le; le = le->next) {
+	    PK11_TraverseCertsForSubjectInSlot(cert,le->slot,callback,arg);
+	}
+	PK11_FreeSlotList(list);
+	return SECSuccess;
+
+    }
+
+    return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
+}
+
+SECStatus
+PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
+	SECStatus(* callback)(CERTCertificate*, void *), void *arg)
+{
+    PRStatus nssrv = PR_SUCCESS;
+    NSSToken *token;
+    NSSDER subject;
+    NSSTrustDomain *td;
+    nssList *subjectList;
+    nssPKIObjectCollection *collection;
+    nssCryptokiObject **instances;
+    NSSCertificate **certs;
+    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+    td = STAN_GetDefaultTrustDomain();
+    NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
+    token = PK11Slot_GetNSSToken(slot);
+    if (!nssToken_IsPresent(token)) {
+	return SECSuccess;
+    }
+    collection = nssCertificateCollection_Create(td, NULL);
+    if (!collection) {
+	return SECFailure;
+    }
+    subjectList = nssList_Create(NULL, PR_FALSE);
+    if (!subjectList) {
+	nssPKIObjectCollection_Destroy(collection);
+	return SECFailure;
+    }
+    (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject, 
+                                                     subjectList);
+    transfer_token_certs_to_collection(subjectList, token, collection);
+    instances = nssToken_FindCertificatesBySubject(token, NULL,
+	                                           &subject, 
+	                                           tokenOnly, 0, &nssrv);
+    nssPKIObjectCollection_AddInstances(collection, instances, 0);
+    nss_ZFreeIf(instances);
+    nssList_Destroy(subjectList);
+    certs = nssPKIObjectCollection_GetCertificates(collection,
+                                                   NULL, 0, NULL);
+    nssPKIObjectCollection_Destroy(collection);
+    if (certs) {
+	CERTCertificate *oldie;
+	NSSCertificate **cp;
+	for (cp = certs; *cp; cp++) {
+	    oldie = STAN_GetCERTCertificate(*cp);
+	    if (!oldie) {
+		continue;
+	    }
+	    if ((*callback)(oldie, arg) != SECSuccess) {
+		nssrv = PR_FAILURE;
+		break;
+	    }
+	}
+	nssCertificateArray_Destroy(certs);
+    }
+    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
+}
+
+SECStatus
+PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
+	SECStatus(* callback)(CERTCertificate*, void *), void *arg)
+{
+    struct nss3_cert_cbstr pk11cb;
+    PRStatus nssrv = PR_SUCCESS;
+    NSSToken *token;
+    NSSTrustDomain *td;
+    NSSUTF8 *nick;
+    PRBool created = PR_FALSE;
+    nssCryptokiObject **instances;
+    nssPKIObjectCollection *collection = NULL;
+    NSSCertificate **certs;
+    nssList *nameList = NULL;
+    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+    pk11cb.callback = callback;
+    pk11cb.arg = arg;
+    token = PK11Slot_GetNSSToken(slot);
+    if (!nssToken_IsPresent(token)) {
+	return SECSuccess;
+    }
+    if (nickname->data[nickname->len-1] != '\0') {
+	nick = nssUTF8_Create(NULL, nssStringType_UTF8String, 
+	                      nickname->data, nickname->len);
+	created = PR_TRUE;
+    } else {
+	nick = (NSSUTF8 *)nickname->data;
+    }
+    td = STAN_GetDefaultTrustDomain();
+    collection = nssCertificateCollection_Create(td, NULL);
+    if (!collection) {
+	goto loser;
+    }
+    nameList = nssList_Create(NULL, PR_FALSE);
+    if (!nameList) {
+	goto loser;
+    }
+    (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList);
+    transfer_token_certs_to_collection(nameList, token, collection);
+    instances = nssToken_FindCertificatesByNickname(token, NULL,
+	                                            nick,
+	                                            tokenOnly, 0, &nssrv);
+    nssPKIObjectCollection_AddInstances(collection, instances, 0);
+    nss_ZFreeIf(instances);
+    nssList_Destroy(nameList);
+    certs = nssPKIObjectCollection_GetCertificates(collection,
+                                                   NULL, 0, NULL);
+    nssPKIObjectCollection_Destroy(collection);
+    if (certs) {
+	CERTCertificate *oldie;
+	NSSCertificate **cp;
+	for (cp = certs; *cp; cp++) {
+	    oldie = STAN_GetCERTCertificate(*cp);
+	    if (!oldie) {
+		continue;
+	    }
+	    if ((*callback)(oldie, arg) != SECSuccess) {
+		nssrv = PR_FAILURE;
+		break;
+	    }
+	}
+	nssCertificateArray_Destroy(certs);
+    }
+    if (created) nss_ZFreeIf(nick);
+    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
+loser:
+    if (created) {
+	nss_ZFreeIf(nick);
+    }
+    if (collection) {
+	nssPKIObjectCollection_Destroy(collection);
+    }
+    if (nameList) {
+	nssList_Destroy(nameList);
+    }
+    return SECFailure;
+}
+
+SECStatus
+PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
+	SECStatus(* callback)(CERTCertificate*, void *), void *arg)
+{
+    PRStatus nssrv;
+    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+    NSSToken *tok;
+    nssList *certList = NULL;
+    nssCryptokiObject **instances;
+    nssPKIObjectCollection *collection;
+    NSSCertificate **certs;
+    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+    tok = PK11Slot_GetNSSToken(slot);
+    if (!nssToken_IsPresent(tok)) {
+	return SECSuccess;
+    }
+    collection = nssCertificateCollection_Create(td, NULL);
+    if (!collection) {
+	return SECFailure;
+    }
+    certList = nssList_Create(NULL, PR_FALSE);
+    if (!certList) {
+	nssPKIObjectCollection_Destroy(collection);
+	return SECFailure;
+    }
+    (void *)nssTrustDomain_GetCertsFromCache(td, certList);
+    transfer_token_certs_to_collection(certList, tok, collection);
+    instances = nssToken_FindObjects(tok, NULL, CKO_CERTIFICATE,
+                                     tokenOnly, 0, &nssrv);
+    nssPKIObjectCollection_AddInstances(collection, instances, 0);
+    nss_ZFreeIf(instances);
+    nssList_Destroy(certList);
+    certs = nssPKIObjectCollection_GetCertificates(collection,
+                                                   NULL, 0, NULL);
+    nssPKIObjectCollection_Destroy(collection);
+    if (certs) {
+	CERTCertificate *oldie;
+	NSSCertificate **cp;
+	for (cp = certs; *cp; cp++) {
+	    oldie = STAN_GetCERTCertificate(*cp);
+	    if (!oldie) {
+		continue;
+	    }
+	    if ((*callback)(oldie, arg) != SECSuccess) {
+		nssrv = PR_FAILURE;
+		break;
+	    }
+	}
+	nssCertificateArray_Destroy(certs);
+    }
+    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
+}
+
+/*
+ * return the certificate associated with a derCert 
+ */
+CERTCertificate *
+PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
+								 void *wincx)
+{
+    return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx);
+}
+
+CERTCertificate *
+PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, SECItem *inDerCert,
+								 void *wincx)
+
+{
+    NSSCertificate *c;
+    NSSDER derCert;
+    NSSToken *tok;
+    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+    SECStatus rv;
+
+    tok = PK11Slot_GetNSSToken(slot);
+    NSSITEM_FROM_SECITEM(&derCert, inDerCert);
+    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
+    if (rv != SECSuccess) {
+	PK11_FreeSlot(slot);
+	return NULL;
+    }
+    c = NSSTrustDomain_FindCertificateByEncodedCertificate(td, &derCert);
+    if (c) {
+	PRBool isToken = PR_FALSE;
+	NSSToken **tp;
+	NSSToken **tokens = nssPKIObject_GetTokens(&c->object, NULL);
+	if (tokens) {
+	    for (tp = tokens; *tp; tp++) {
+		if (*tp == tok) {
+		    isToken = PR_TRUE;
+		    break;
+		}
+	    }
+	    if (!isToken) {
+		NSSCertificate_Destroy(c);
+		c = NULL;
+	    }
+	    nssTokenArray_Destroy(tokens);
+	}
+    }
+    return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
+} 
+
+/*
+ * import a cert for a private key we have already generated. Set the label
+ * on both to be the nickname.
+ */
+static CK_OBJECT_HANDLE 
+pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 
+								void *wincx)
+{
+    SECItem *keyID;
+    CK_OBJECT_HANDLE key;
+    SECStatus rv;
+    PRBool needLogin;
+    int err;
+
+    if((slot == NULL) || (cert == NULL)) {
+	return CK_INVALID_HANDLE;
+    }
+
+    keyID = pk11_mkcertKeyID(cert);
+    if(keyID == NULL) {
+	return CK_INVALID_HANDLE;
+    }
+
+    /*
+     * prevent a login race condition. If slot is logged in between
+     * our call to pk11_LoginStillRequired and the 
+     * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or
+     * we will call it one more time after calling PK11_Authenticate 
+     * (which is a noop on an authenticated token).
+     */
+    needLogin = pk11_LoginStillRequired(slot,wincx);
+    key = pk11_FindPrivateKeyFromCertID(slot, keyID);
+    if ((key == CK_INVALID_HANDLE) && needLogin &&
+			(SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
+			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
+	/* authenticate and try again */
+	rv = PK11_Authenticate(slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) goto loser;
+	key = pk11_FindPrivateKeyFromCertID(slot, keyID);
+   }
+
+loser:
+    SECITEM_ZfreeItem(keyID, PR_TRUE);
+    return key;
+}
+
+SECKEYPrivateKey *
+PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 
+								void *wincx)
+{
+    CK_OBJECT_HANDLE keyHandle;
+
+    if((slot == NULL) || (cert == NULL)) {
+	return NULL;
+    }
+
+    keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
+    if (keyHandle == CK_INVALID_HANDLE) {
+	return NULL;
+    }
+
+    return PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,wincx);
+}
+
+SECStatus
+PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert, 
+						char *nickname, 
+						PRBool addCertUsage,void *wincx)
+{
+    CK_OBJECT_HANDLE keyHandle;
+
+    if((slot == NULL) || (cert == NULL) || (nickname == NULL)) {
+	return SECFailure;
+    }
+
+    keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
+    if (keyHandle == CK_INVALID_HANDLE) {
+	return SECFailure;
+    }
+
+    return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage);
+}   
+
+
+/* remove when the real version comes out */
+#define SEC_OID_MISSI_KEA 300  /* until we have v3 stuff merged */
+PRBool
+KEAPQGCompare(CERTCertificate *server,CERTCertificate *cert) {
+
+    if ( SECKEY_KEAParamCompare(server,cert) == SECEqual ) {
+        return PR_TRUE;
+    } else {
+	return PR_FALSE;
+    }
+}
+
+PRBool
+PK11_FortezzaHasKEA(CERTCertificate *cert) 
+{
+   /* look at the subject and see if it is a KEA for MISSI key */
+   SECOidData *oid;
+
+   if ((cert->trust == NULL) ||
+       ((cert->trust->sslFlags & CERTDB_USER) != CERTDB_USER)) {
+       return PR_FALSE;
+   }
+
+   oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
+   if (!oid) {
+       return PR_FALSE;
+   }
+
+   return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) || 
+		(oid->offset == SEC_OID_MISSI_KEA_DSS) ||
+				(oid->offset == SEC_OID_MISSI_KEA)) ;
+}
+
+/*
+ * Find a kea cert on this slot that matches the domain of it's peer
+ */
+static CERTCertificate
+*pk11_GetKEAMate(PK11SlotInfo *slot,CERTCertificate *peer)
+{
+    int i;
+    CERTCertificate *returnedCert = NULL;
+
+    for (i=0; i < slot->cert_count; i++) {
+	CERTCertificate *cert = slot->cert_array[i];
+
+	if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer,cert)) {
+		returnedCert = CERT_DupCertificate(cert);
+		break;
+	}
+    }
+    return returnedCert;
+}
+
+/*
+ * The following is a FORTEZZA only Certificate request. We call this when we
+ * are doing a non-client auth SSL connection. We are only interested in the
+ * fortezza slots, and we are only interested in certs that share the same root
+ * key as the server.
+ */
+CERTCertificate *
+PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx)
+{
+    PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
+							PR_FALSE,PR_TRUE,wincx);
+    PK11SlotListElement *le;
+    CERTCertificate *returnedCert = NULL;
+    SECStatus rv;
+
+    if (!keaList) {
+        /* error code is set */
+        return NULL;
+    }
+
+    /* loop through all the fortezza tokens */
+    for (le = keaList->head; le; le = le->next) {
+        rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
+        if (rv != SECSuccess) continue;
+	if (le->slot->session == CK_INVALID_SESSION) {
+	    continue;
+	}
+	returnedCert = pk11_GetKEAMate(le->slot,server);
+	if (returnedCert) break;
+    }
+    PK11_FreeSlotList(keaList);
+
+    return returnedCert;
+}
+
+/*
+ * find a matched pair of kea certs to key exchange parameters from one 
+ * fortezza card to another as necessary.
+ */
+SECStatus
+PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2,
+	CERTCertificate **cert1, CERTCertificate **cert2)
+{
+    CERTCertificate *returnedCert = NULL;
+    int i;
+
+    for (i=0; i < slot1->cert_count; i++) {
+	CERTCertificate *cert = slot1->cert_array[i];
+
+	if (PK11_FortezzaHasKEA(cert)) {
+	    returnedCert = pk11_GetKEAMate(slot2,cert);
+	    if (returnedCert != NULL) {
+		*cert2 = returnedCert;
+		*cert1 = CERT_DupCertificate(cert);
+		return SECSuccess;
+	    }
+	}
+    }
+    return SECFailure;
+}
+
+/*
+ * return the private key From a given Cert
+ */
+CK_OBJECT_HANDLE
+PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
+{
+    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_VALUE, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 }
+    };
+    /* if you change the array, change the variable below as well */
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    CK_ATTRIBUTE *attrs = theTemplate;
+    SECStatus rv;
+
+    PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
+						cert->derCert.len); attrs++;
+    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
+
+    /*
+     * issue the find
+     */
+    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
+    if (rv != SECSuccess) {
+	return CK_INVALID_HANDLE;
+    }
+
+    return pk11_getcerthandle(slot,cert,theTemplate,tsize);
+}
+
+/* Looking for PK11_GetKeyIDFromCert?  
+ * Use PK11_GetLowLevelKeyIDForCert instead.
+ */
+
+
+struct listCertsStr {
+    PK11CertListType type;
+    CERTCertList *certList;
+};
+
+static PRStatus
+pk11ListCertCallback(NSSCertificate *c, void *arg)
+{
+    struct listCertsStr *listCertP = (struct listCertsStr *)arg;
+    CERTCertificate *newCert = NULL;
+    PK11CertListType type = listCertP->type;
+    CERTCertList *certList = listCertP->certList;
+    PRBool isUnique = PR_FALSE;
+    PRBool isCA = PR_FALSE;
+    char *nickname = NULL;
+    unsigned int certType;
+
+    if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) ||
+        (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique) ) {
+        /* only list one instance of each certificate, even if several exist */
+	isUnique = PR_TRUE;
+    }
+    if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) ||
+        (type == PK11CertListCAUnique)) {
+	isCA = PR_TRUE;
+    }
+
+    /* if we want user certs and we don't have one skip this cert */
+    if ( ( (type == PK11CertListUser) || (type == PK11CertListUserUnique) ) && 
+		!NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
+	return PR_SUCCESS;
+    }
+
+    /* PK11CertListRootUnique means we want CA certs without a private key.
+     * This is for legacy app support . PK11CertListCAUnique should be used
+     * instead to get all CA certs, regardless of private key
+     */
+    if ((type == PK11CertListRootUnique) && 
+		NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
+	return PR_SUCCESS;
+    }
+
+    /* caller still owns the reference to 'c' */
+    newCert = STAN_GetCERTCertificate(c);
+    if (!newCert) {
+	return PR_SUCCESS;
+    }
+    /* if we want CA certs and it ain't one, skip it */
+    if( isCA  && (!CERT_IsCACert(newCert, &certType)) ) {
+	return PR_SUCCESS;
+    }
+    if (isUnique) {
+	CERT_DupCertificate(newCert);
+
+	nickname = STAN_GetCERTCertificateName(certList->arena, c);
+
+	/* put slot certs at the end */
+	if (newCert->slot && !PK11_IsInternal(newCert->slot)) {
+	    CERT_AddCertToListTailWithData(certList,newCert,nickname);
+	} else {
+	    CERT_AddCertToListHeadWithData(certList,newCert,nickname);
+	}
+    } else {
+	/* add multiple instances to the cert list */
+	nssCryptokiObject **ip;
+	nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
+	if (!instances) {
+	    return PR_SUCCESS;
+	}
+	for (ip = instances; *ip; ip++) {
+	    nssCryptokiObject *instance = *ip;
+	    PK11SlotInfo *slot = instance->token->pk11slot;
+
+	    /* put the same CERTCertificate in the list for all instances */
+	    CERT_DupCertificate(newCert);
+
+	    nickname = STAN_GetCERTCertificateNameForInstance(
+			certList->arena, c, instance);
+
+	    /* put slot certs at the end */
+	    if (slot && !PK11_IsInternal(slot)) {
+		CERT_AddCertToListTailWithData(certList,newCert,nickname);
+	    } else {
+		CERT_AddCertToListHeadWithData(certList,newCert,nickname);
+	    }
+	}
+	nssCryptokiObjectArray_Destroy(instances);
+    }
+    return PR_SUCCESS;
+}
+
+
+CERTCertList *
+PK11_ListCerts(PK11CertListType type, void *pwarg)
+{
+    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
+    CERTCertList *certList = NULL;
+    struct listCertsStr listCerts;
+    certList = CERT_NewCertList();
+    listCerts.type = type;
+    listCerts.certList = certList;
+
+    /* authenticate to the slots */
+    (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, pwarg);
+    NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback,
+								 &listCerts);
+    return certList;
+}
+    
+SECItem *
+PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
+					CERTCertificate *cert, void *wincx)
+{
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_VALUE, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 }
+    };
+    /* if you change the array, change the variable below as well */
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    CK_OBJECT_HANDLE certHandle;
+    CK_ATTRIBUTE *attrs = theTemplate;
+    PK11SlotInfo *slotRef = NULL;
+    SECItem *item;
+    SECStatus rv;
+
+    if (slot) {
+	PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, 
+						cert->derCert.len); attrs++;
+ 
+	rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
+	if (rv != SECSuccess) {
+	    return NULL;
+	}
+        certHandle = pk11_getcerthandle(slot,cert,theTemplate,tsize);
+    } else {
+    	certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef);
+	if (certHandle == CK_INVALID_HANDLE) {
+	   return pk11_mkcertKeyID(cert);
+	}
+	slot = slotRef;
+    }
+
+    if (certHandle == CK_INVALID_HANDLE) {
+	 return NULL;
+    }
+
+    item = pk11_GetLowLevelKeyFromHandle(slot,certHandle);
+    if (slotRef) PK11_FreeSlot(slotRef);
+    return item;
+}
+
+/* argument type for listCertsCallback */
+typedef struct {
+    CERTCertList *list;
+    PK11SlotInfo *slot;
+} ListCertsArg;
+
+static SECStatus
+listCertsCallback(CERTCertificate* cert, void*arg)
+{
+    ListCertsArg *cdata = (ListCertsArg*)arg;
+    char *nickname = NULL;
+    nssCryptokiObject *instance, **ci;
+    nssCryptokiObject **instances;
+    NSSCertificate *c = STAN_GetNSSCertificate(cert);
+
+    if (c == NULL) {
+        return SECFailure;
+    }
+    instances = nssPKIObject_GetInstances(&c->object);
+    if (!instances) {
+        return SECFailure;
+    }
+    instance = NULL;
+    for (ci = instances; *ci; ci++) {
+	if ((*ci)->token->pk11slot == cdata->slot) {
+	    instance = *ci;
+	    break;
+	}
+    }
+    PORT_Assert(instance != NULL);
+    if (!instance) {
+	nssCryptokiObjectArray_Destroy(instances);
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena,
+	c, instance);
+    nssCryptokiObjectArray_Destroy(instances);
+
+    return CERT_AddCertToListTailWithData(cdata->list, 
+				CERT_DupCertificate(cert),nickname);
+}
+
+CERTCertList *
+PK11_ListCertsInSlot(PK11SlotInfo *slot)
+{
+    SECStatus status;
+    CERTCertList *certs;
+    ListCertsArg cdata;
+
+    certs = CERT_NewCertList();
+    if(certs == NULL) return NULL;
+    cdata.list = certs;
+    cdata.slot = slot;
+
+    status = PK11_TraverseCertsInSlot(slot, listCertsCallback,
+		&cdata);
+
+    if( status != SECSuccess ) {
+	CERT_DestroyCertList(certs);
+	certs = NULL;
+    }
+
+    return certs;
+}
+
+PK11SlotList *
+PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg)
+{
+    NSSCertificate *c = STAN_GetNSSCertificate(cert);
+    /* add multiple instances to the cert list */
+    nssCryptokiObject **ip;
+    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
+    PK11SlotList *slotList;
+    PRBool found = PR_FALSE;
+
+    if (!cert) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    if (!instances) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+
+    slotList = PK11_NewSlotList();
+    if (!slotList) {
+	nssCryptokiObjectArray_Destroy(instances);
+	return NULL;
+    }
+
+    for (ip = instances; *ip; ip++) {
+	nssCryptokiObject *instance = *ip;
+	PK11SlotInfo *slot = instance->token->pk11slot;
+	if (slot) {
+	    PK11_AddSlotToList(slotList, slot);
+	    found = PR_TRUE;
+	}
+    }
+    if (!found) {
+	PK11_FreeSlotList(slotList);
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	slotList = NULL;
+    }
+
+    nssCryptokiObjectArray_Destroy(instances);
+    return slotList;
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11cxt.c b/mozilla/security/nss/lib/pk11wrap/pk11cxt.c
new file mode 100644
index 0000000..34e24f8
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11cxt.c
@@ -0,0 +1,1068 @@
+/* ***** 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 ***** */
+/*
+ * This file PK11Contexts which are  used in multipart hashing, 
+ * encryption/decryption, and signing/verication operations.
+ */
+
+#include "seccomon.h"
+#include "secmod.h"
+#include "nssilock.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "secoid.h" 
+#include "sechash.h"
+#include "secerr.h"
+
+static const SECItem pk11_null_params = { 0 };
+
+/**********************************************************************
+ *
+ *                   Now Deal with Crypto Contexts
+ *
+ **********************************************************************/
+
+/*
+ * the monitors...
+ */
+void
+PK11_EnterContextMonitor(PK11Context *cx) {
+    /* if we own the session and our slot is ThreadSafe, only monitor
+     * the Context */
+    if ((cx->ownSession) && (cx->slot->isThreadSafe)) {
+	/* Should this use monitors instead? */
+	PZ_Lock(cx->sessionLock);
+    } else {
+	PK11_EnterSlotMonitor(cx->slot);
+    }
+}
+
+void
+PK11_ExitContextMonitor(PK11Context *cx) {
+    /* if we own the session and our slot is ThreadSafe, only monitor
+     * the Context */
+    if ((cx->ownSession) && (cx->slot->isThreadSafe)) {
+	/* Should this use monitors instead? */
+	PZ_Unlock(cx->sessionLock);
+    } else {
+	PK11_ExitSlotMonitor(cx->slot);
+    }
+}
+
+/*
+ * Free up a Cipher Context
+ */
+void
+PK11_DestroyContext(PK11Context *context, PRBool freeit)
+{
+    pk11_CloseSession(context->slot,context->session,context->ownSession);
+    /* initialize the critical fields of the context */
+    if (context->savedData != NULL ) PORT_Free(context->savedData);
+    if (context->key) PK11_FreeSymKey(context->key);
+    if (context->param && context->param != &pk11_null_params)
+	SECITEM_FreeItem(context->param, PR_TRUE);
+    if (context->sessionLock) PZ_DestroyLock(context->sessionLock);
+    PK11_FreeSlot(context->slot);
+    if (freeit) PORT_Free(context);
+}
+
+/*
+ * save the current context. Allocate Space if necessary.
+ */
+static unsigned char *
+pk11_saveContextHelper(PK11Context *context, unsigned char *buffer, 
+                       unsigned long *savedLength)
+{
+    CK_RV crv;
+
+    /* If buffer is NULL, this will get the length */
+    crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session,
+                                                          (CK_BYTE_PTR)buffer,
+                                                          savedLength);
+    if (!buffer || (crv == CKR_BUFFER_TOO_SMALL)) {
+	/* the given buffer wasn't big enough (or was NULL), but we 
+	 * have the length, so try again with a new buffer and the 
+	 * correct length
+	 */
+	unsigned long bufLen = *savedLength;
+	buffer = PORT_Alloc(bufLen);
+	if (buffer == NULL) {
+	    return (unsigned char *)NULL;
+	}
+	crv = PK11_GETTAB(context->slot)->C_GetOperationState(
+	                                                  context->session,
+                                                          (CK_BYTE_PTR)buffer,
+                                                          savedLength);
+	if (crv != CKR_OK) {
+	    PORT_ZFree(buffer, bufLen);
+	}
+    }
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return (unsigned char *)NULL;
+    }
+    return buffer;
+}
+
+void *
+pk11_saveContext(PK11Context *context, void *space, unsigned long *savedLength)
+{
+    return pk11_saveContextHelper(context, 
+                                  (unsigned char *)space, savedLength);
+}
+
+/*
+ * restore the current context
+ */
+SECStatus
+pk11_restoreContext(PK11Context *context,void *space, unsigned long savedLength)
+{
+    CK_RV crv;
+    CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID:
+			CK_INVALID_HANDLE;
+
+    PORT_Assert(space != NULL);
+    if (space == NULL) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session,
+        (CK_BYTE_PTR)space, savedLength, objectID, 0);
+    if (crv != CKR_OK) {
+       PORT_SetError( PK11_MapError(crv));
+       return SECFailure;
+   }
+   return SECSuccess;
+}
+
+SECStatus pk11_Finalize(PK11Context *context);
+
+/*
+ * Context initialization. Used by all flavors of CreateContext
+ */
+static SECStatus 
+pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info)
+{
+    CK_RV crv;
+    PK11SymKey *symKey = context->key;
+    SECStatus rv = SECSuccess;
+
+    switch (context->operation) {
+    case CKA_ENCRYPT:
+	crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session,
+				mech_info, symKey->objectID);
+	break;
+    case CKA_DECRYPT:
+	if (context->fortezzaHack) {
+	    CK_ULONG count = 0;;
+	    /* generate the IV for fortezza */
+	    crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session,
+				mech_info, symKey->objectID);
+	    if (crv != CKR_OK) break;
+	    PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
+				NULL, &count);
+	}
+	crv=PK11_GETTAB(context->slot)->C_DecryptInit(context->session,
+				mech_info, symKey->objectID);
+	break;
+    case CKA_SIGN:
+	crv=PK11_GETTAB(context->slot)->C_SignInit(context->session,
+				mech_info, symKey->objectID);
+	break;
+    case CKA_VERIFY:
+	crv=PK11_GETTAB(context->slot)->C_SignInit(context->session,
+				mech_info, symKey->objectID);
+	break;
+    case CKA_DIGEST:
+	crv=PK11_GETTAB(context->slot)->C_DigestInit(context->session,
+				mech_info);
+	break;
+    default:
+	crv = CKR_OPERATION_NOT_INITIALIZED;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+        return SECFailure;
+    }
+
+    /*
+     * handle session starvation case.. use our last session to multiplex
+     */
+    if (!context->ownSession) {
+	context->savedData = pk11_saveContext(context,context->savedData,
+				&context->savedLength);
+	if (context->savedData == NULL) rv = SECFailure;
+	/* clear out out session for others to use */
+	pk11_Finalize(context);
+    }
+    return rv;
+}
+
+
+/*
+ * Common Helper Function do come up with a new context.
+ */
+static PK11Context *pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type,
+     PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey,
+							     SECItem *param)
+{
+    CK_MECHANISM mech_info;
+    PK11Context *context;
+    SECStatus rv;
+	
+    PORT_Assert(slot != NULL);
+    if (!slot || (!symKey && operation != CKA_DIGEST)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    context = (PK11Context *) PORT_Alloc(sizeof(PK11Context));
+    if (context == NULL) {
+	return NULL;
+    }
+
+    /* now deal with the fortezza hack... the fortezza hack is an attempt
+     * to get around the issue of the card not allowing you to do a FORTEZZA
+     * LoadIV/Encrypt, which was added because such a combination could be
+     * use to circumvent the key escrow system. Unfortunately SSL needs to
+     * do this kind of operation, so in SSL we do a loadIV (to verify it),
+     * Then GenerateIV, and through away the first 8 bytes on either side
+     * of the connection.*/
+    context->fortezzaHack = PR_FALSE;
+    if (type == CKM_SKIPJACK_CBC64) {
+	if (symKey->origin == PK11_OriginFortezzaHack) {
+	    context->fortezzaHack = PR_TRUE;
+	}
+    }
+
+    /* initialize the critical fields of the context */
+    context->operation = operation;
+    context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL;
+    context->slot = PK11_ReferenceSlot(slot);
+    context->session = pk11_GetNewSession(slot,&context->ownSession);
+    context->cx = symKey ? symKey->cx : NULL;
+    /* get our session */
+    context->savedData = NULL;
+
+    /* save the parameters so that some digesting stuff can do multiple
+     * begins on a single context */
+    context->type = type;
+    if (param) {
+	if (param->len > 0) {
+	    context->param = SECITEM_DupItem(param);
+	} else {
+	    context->param = (SECItem *)&pk11_null_params;
+	}
+    } else {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	context->param = NULL;
+    }
+    context->init = PR_FALSE;
+    context->sessionLock = PZ_NewLock(nssILockPK11cxt);
+    if ((context->param == NULL) || (context->sessionLock == NULL)) {
+	PK11_DestroyContext(context,PR_TRUE);
+	return NULL;
+    }
+
+    mech_info.mechanism = type;
+    mech_info.pParameter = param->data;
+    mech_info.ulParameterLen = param->len;
+    PK11_EnterContextMonitor(context);
+    rv = pk11_context_init(context,&mech_info);
+    PK11_ExitContextMonitor(context);
+
+    if (rv != SECSuccess) {
+	PK11_DestroyContext(context,PR_TRUE);
+	return NULL;
+    }
+    context->init = PR_TRUE;
+    return context;
+}
+
+
+/*
+ * put together the various PK11_Create_Context calls used by different
+ * parts of libsec.
+ */
+PK11Context *
+__PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+     PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, 
+						SECItem *param, void *wincx)
+{
+    PK11SymKey *symKey = NULL;
+    PK11Context *context = NULL;
+
+    /* first get a slot */
+    if (slot == NULL) {
+	slot = PK11_GetBestSlot(type,wincx);
+	if (slot == NULL) {
+	    PORT_SetError( SEC_ERROR_NO_MODULE );
+	    goto loser;
+	}
+    } else {
+	PK11_ReferenceSlot(slot);
+    }
+
+    /* now import the key */
+    symKey = PK11_ImportSymKey(slot, type, origin, operation,  key, wincx);
+    if (symKey == NULL) goto loser;
+
+    context = PK11_CreateContextBySymKey(type, operation, symKey, param);
+
+loser:
+    if (symKey) {
+        PK11_FreeSymKey(symKey);
+    }
+    if (slot) {
+        PK11_FreeSlot(slot);
+    }
+
+    return context;
+}
+
+PK11Context *
+PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+     PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, 
+						SECItem *param, void *wincx)
+{
+    return __PK11_CreateContextByRawKey(slot, type, origin, operation,
+                                        key, param, wincx);
+}
+
+
+/*
+ * Create a context from a key. We really should make sure we aren't using
+ * the same key in multiple session!
+ */
+PK11Context *
+PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE operation,
+			PK11SymKey *symKey, SECItem *param)
+{
+    PK11SymKey *newKey;
+    PK11Context *context;
+
+    /* if this slot doesn't support the mechanism, go to a slot that does */
+    newKey = pk11_ForceSlot(symKey,type,operation);
+    if (newKey == NULL) {
+	PK11_ReferenceSymKey(symKey);
+    } else {
+	symKey = newKey;
+    }
+
+
+    /* Context Adopts the symKey.... */
+    context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey,
+							     param);
+    PK11_FreeSymKey(symKey);
+    return context;
+}
+
+/*
+ * Digest contexts don't need keys, but the do need to find a slot.
+ * Macing should use PK11_CreateContextBySymKey.
+ */
+PK11Context *
+PK11_CreateDigestContext(SECOidTag hashAlg)
+{
+    /* digesting has to work without authentication to the slot */
+    CK_MECHANISM_TYPE type;
+    PK11SlotInfo *slot;
+    PK11Context *context;
+    SECItem param;
+
+    type = PK11_AlgtagToMechanism(hashAlg);
+    slot = PK11_GetBestSlot(type, NULL);
+    if (slot == NULL) {
+	PORT_SetError( SEC_ERROR_NO_MODULE );
+	return NULL;
+    }
+
+    /* maybe should really be PK11_GenerateNewParam?? */
+    param.data = NULL;
+    param.len = 0;
+    param.type = 0;
+
+    context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, &param);
+    PK11_FreeSlot(slot);
+    return context;
+}
+
+/*
+ * create a new context which is the clone of the state of old context.
+ */
+PK11Context * PK11_CloneContext(PK11Context *old)
+{
+     PK11Context *newcx;
+     PRBool needFree = PR_FALSE;
+     SECStatus rv = SECSuccess;
+     void *data;
+     unsigned long len;
+
+     newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation,
+						old->key, old->param);
+     if (newcx == NULL) return NULL;
+
+     /* now clone the save state. First we need to find the save state
+      * of the old session. If the old context owns it's session,
+      * the state needs to be saved, otherwise the state is in saveData. */
+     if (old->ownSession) {
+        PK11_EnterContextMonitor(old);
+	data=pk11_saveContext(old,NULL,&len);
+        PK11_ExitContextMonitor(old);
+	needFree = PR_TRUE;
+     } else {
+	data = old->savedData;
+	len = old->savedLength;
+     }
+
+     if (data == NULL) {
+	PK11_DestroyContext(newcx,PR_TRUE);
+	return NULL;
+     }
+
+     /* now copy that state into our new context. Again we have different
+      * work if the new context owns it's own session. If it does, we
+      * restore the state gathered above. If it doesn't, we copy the
+      * saveData pointer... */
+     if (newcx->ownSession) {
+        PK11_EnterContextMonitor(newcx);
+	rv = pk11_restoreContext(newcx,data,len);
+        PK11_ExitContextMonitor(newcx);
+     } else {
+	PORT_Assert(newcx->savedData != NULL);
+	if ((newcx->savedData == NULL) || (newcx->savedLength < len)) {
+	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	    rv = SECFailure;
+	} else {
+	    PORT_Memcpy(newcx->savedData,data,len);
+	    newcx->savedLength = len;
+	}
+    }
+
+    if (needFree) PORT_Free(data);
+
+    if (rv != SECSuccess) {
+	PK11_DestroyContext(newcx,PR_TRUE);
+	return NULL;
+    }
+    return newcx;
+}
+
+/*
+ * save the current context state into a variable. Required to make FORTEZZA
+ * work.
+ */
+SECStatus
+PK11_SaveContext(PK11Context *cx,unsigned char *save,int *len, int saveLength)
+{
+    unsigned char * data = NULL;
+    CK_ULONG length = saveLength;
+
+    if (cx->ownSession) {
+        PK11_EnterContextMonitor(cx);
+	data = pk11_saveContextHelper(cx, save, &length);
+        PK11_ExitContextMonitor(cx);
+	if (data) *len = length;
+    } else if ((unsigned) saveLength >= cx->savedLength) {
+	data = (unsigned char*)cx->savedData;
+	if (cx->savedData) {
+	    PORT_Memcpy(save,cx->savedData,cx->savedLength);
+	}
+	*len = cx->savedLength;
+    }
+    if (data != NULL) {
+	if (cx->ownSession) {
+	    PORT_ZFree(data, length);
+	}
+	return SECSuccess;
+    } else {
+	return SECFailure;
+    }
+}
+
+/* same as above, but may allocate the return buffer. */
+unsigned char *
+PK11_SaveContextAlloc(PK11Context *cx,
+                      unsigned char *preAllocBuf, unsigned int pabLen,
+                      unsigned int *stateLen)
+{
+    unsigned char *stateBuf = NULL;
+    unsigned long length = (unsigned long)pabLen;
+
+    if (cx->ownSession) {
+        PK11_EnterContextMonitor(cx);
+	stateBuf = pk11_saveContextHelper(cx, preAllocBuf, &length);
+        PK11_ExitContextMonitor(cx);
+	*stateLen = (stateBuf != NULL) ? length : 0;
+    } else {
+	if (pabLen < cx->savedLength) {
+	    stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength);
+	    if (!stateBuf) {
+		return (unsigned char *)NULL;
+	    }
+	} else {
+	    stateBuf = preAllocBuf;
+	}
+	if (cx->savedData) {
+	    PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength);
+	}
+	*stateLen = cx->savedLength;
+    }
+    return stateBuf;
+}
+
+/*
+ * restore the context state into a new running context. Also required for
+ * FORTEZZA .
+ */
+SECStatus
+PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len)
+{
+    SECStatus rv = SECSuccess;
+    if (cx->ownSession) {
+        PK11_EnterContextMonitor(cx);
+	pk11_Finalize(cx);
+	rv = pk11_restoreContext(cx,save,len);
+        PK11_ExitContextMonitor(cx);
+    } else {
+	PORT_Assert(cx->savedData != NULL);
+	if ((cx->savedData == NULL) || (cx->savedLength < (unsigned) len)) {
+	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	    rv = SECFailure;
+	} else {
+	    PORT_Memcpy(cx->savedData,save,len);
+	    cx->savedLength = len;
+	}
+    }
+    return rv;
+}
+
+/*
+ * This is  to get FIPS compliance until we can convert
+ * libjar to use PK11_ hashing functions. It returns PR_FALSE
+ * if we can't get a PK11 Context.
+ */
+PRBool
+PK11_HashOK(SECOidTag algID) {
+    PK11Context *cx;
+
+    cx = PK11_CreateDigestContext(algID);
+    if (cx == NULL) return PR_FALSE;
+    PK11_DestroyContext(cx, PR_TRUE);
+    return PR_TRUE;
+}
+
+
+
+/*
+ * start a new digesting or Mac'ing operation on this context
+ */
+SECStatus PK11_DigestBegin(PK11Context *cx)
+{
+    CK_MECHANISM mech_info;
+    SECStatus rv;
+
+    if (cx->init == PR_TRUE) {
+	return SECSuccess;
+    }
+
+    /*
+     * make sure the old context is clear first
+     */
+    PK11_EnterContextMonitor(cx);
+    pk11_Finalize(cx);
+
+    mech_info.mechanism = cx->type;
+    mech_info.pParameter = cx->param->data;
+    mech_info.ulParameterLen = cx->param->len;
+    rv = pk11_context_init(cx,&mech_info);
+    PK11_ExitContextMonitor(cx);
+
+    if (rv != SECSuccess) {
+	return SECFailure;
+    }
+    cx->init = PR_TRUE;
+    return SECSuccess;
+}
+
+SECStatus
+PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in, 
+								PRInt32 len) {
+    PK11Context *context;
+    unsigned int max_length;
+    unsigned int out_length;
+    SECStatus rv;
+
+    /* len will be passed to PK11_DigestOp as unsigned. */
+    if (len < 0) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    context = PK11_CreateDigestContext(hashAlg);
+    if (context == NULL) return SECFailure;
+
+    rv = PK11_DigestBegin(context);
+    if (rv != SECSuccess) {
+	PK11_DestroyContext(context, PR_TRUE);
+	return rv;
+    }
+
+    rv = PK11_DigestOp(context, in, len);
+    if (rv != SECSuccess) {
+	PK11_DestroyContext(context, PR_TRUE);
+	return rv;
+    }
+
+    /* XXX This really should have been an argument to this function! */
+    max_length = HASH_ResultLenByOidTag(hashAlg);
+    PORT_Assert(max_length);
+    if (!max_length)
+    	max_length = HASH_LENGTH_MAX;
+
+    rv = PK11_DigestFinal(context,out,&out_length,max_length);
+    PK11_DestroyContext(context, PR_TRUE);
+    return rv;
+}
+
+
+/*
+ * execute a bulk encryption operation
+ */
+SECStatus
+PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, 
+				int maxout, unsigned char *in, int inlen)
+{
+    CK_RV crv = CKR_OK;
+    CK_ULONG length = maxout;
+    CK_ULONG offset =0;
+    SECStatus rv = SECSuccess;
+    unsigned char *saveOut = out;
+    unsigned char *allocOut = NULL;
+
+    /* if we ran out of session, we need to restore our previously stored
+     * state.
+     */
+    PK11_EnterContextMonitor(context);
+    if (!context->ownSession) {
+        rv = pk11_restoreContext(context,context->savedData,
+							context->savedLength);
+	if (rv != SECSuccess) {
+	    PK11_ExitContextMonitor(context);
+	    return rv;
+	}
+    }
+
+    /*
+     * The fortezza hack is to send 8 extra bytes on the first encrypted and
+     * lose them on the first decrypt.
+     */
+    if (context->fortezzaHack) {
+	unsigned char random[8];
+	if (context->operation == CKA_ENCRYPT) {
+	    PK11_ExitContextMonitor(context);
+	    rv = PK11_GenerateRandom(random,sizeof(random));
+    	    PK11_EnterContextMonitor(context);
+
+	    /* since we are offseting the output, we can't encrypt back into
+	     * the same buffer... allocate a temporary buffer just for this
+	     * call. */
+	    allocOut = out = (unsigned char*)PORT_Alloc(maxout);
+	    if (out == NULL) {
+		PK11_ExitContextMonitor(context);
+		return SECFailure;
+	    }
+	    crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session,
+		random,sizeof(random),out,&length);
+
+	    out += length;
+	    maxout -= length;
+	    offset = length;
+	} else if (context->operation == CKA_DECRYPT) {
+	    length = sizeof(random);
+	    crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session,
+		in,sizeof(random),random,&length);
+	    inlen -= length;
+	    in += length;
+	    context->fortezzaHack = PR_FALSE;
+	}
+    }
+
+    switch (context->operation) {
+    case CKA_ENCRYPT:
+	length = maxout;
+	crv=PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session,
+						in, inlen, out, &length);
+	length += offset;
+	break;
+    case CKA_DECRYPT:
+	length = maxout;
+	crv=PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session,
+						in, inlen, out, &length);
+	break;
+    default:
+	crv = CKR_OPERATION_NOT_INITIALIZED;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+	*outlen = 0;
+        rv = SECFailure;
+    } else {
+    	*outlen = length;
+    }
+
+    if (context->fortezzaHack) {
+	if (context->operation == CKA_ENCRYPT) {
+	    PORT_Assert(allocOut);
+	    PORT_Memcpy(saveOut, allocOut, length);
+	    PORT_Free(allocOut);
+	}
+	context->fortezzaHack = PR_FALSE;
+    }
+
+    /*
+     * handle session starvation case.. use our last session to multiplex
+     */
+    if (!context->ownSession) {
+	context->savedData = pk11_saveContext(context,context->savedData,
+				&context->savedLength);
+	if (context->savedData == NULL) rv = SECFailure;
+	
+	/* clear out out session for others to use */
+	pk11_Finalize(context);
+    }
+    PK11_ExitContextMonitor(context);
+    return rv;
+}
+
+/*
+ * execute a digest/signature operation
+ */
+SECStatus
+PK11_DigestOp(PK11Context *context, const unsigned char * in, unsigned inLen) 
+{
+    CK_RV crv = CKR_OK;
+    SECStatus rv = SECSuccess;
+
+    if (!in) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    /* if we ran out of session, we need to restore our previously stored
+     * state.
+     */
+    context->init = PR_FALSE;
+    PK11_EnterContextMonitor(context);
+    if (!context->ownSession) {
+        rv = pk11_restoreContext(context,context->savedData,
+							context->savedLength);
+	if (rv != SECSuccess) {
+	    PK11_ExitContextMonitor(context);
+	    return rv;
+	}
+    }
+
+    switch (context->operation) {
+    /* also for MAC'ing */
+    case CKA_SIGN:
+	crv=PK11_GETTAB(context->slot)->C_SignUpdate(context->session,
+						     (unsigned char *)in, 
+						     inLen);
+	break;
+    case CKA_VERIFY:
+	crv=PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session,
+						       (unsigned char *)in, 
+						       inLen);
+	break;
+    case CKA_DIGEST:
+	crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session,
+						       (unsigned char *)in, 
+						       inLen);
+	break;
+    default:
+	crv = CKR_OPERATION_NOT_INITIALIZED;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+        rv = SECFailure;
+    }
+
+    /*
+     * handle session starvation case.. use our last session to multiplex
+     */
+    if (!context->ownSession) {
+	context->savedData = pk11_saveContext(context,context->savedData,
+				&context->savedLength);
+	if (context->savedData == NULL) rv = SECFailure;
+	
+	/* clear out out session for others to use */
+	pk11_Finalize(context);
+    }
+    PK11_ExitContextMonitor(context);
+    return rv;
+}
+
+/*
+ * Digest a key if possible./
+ */
+SECStatus
+PK11_DigestKey(PK11Context *context, PK11SymKey *key)
+{
+    CK_RV crv = CKR_OK;
+    SECStatus rv = SECSuccess;
+    PK11SymKey *newKey = NULL;
+
+    if (!context || !key) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    /* if we ran out of session, we need to restore our previously stored
+     * state.
+     */
+    if (context->slot != key->slot) {
+	newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key);
+    } else {
+	newKey = PK11_ReferenceSymKey(key);
+    }
+
+    context->init = PR_FALSE;
+    PK11_EnterContextMonitor(context);
+    if (!context->ownSession) {
+        rv = pk11_restoreContext(context,context->savedData,
+							context->savedLength);
+	if (rv != SECSuccess) {
+	    PK11_ExitContextMonitor(context);
+            PK11_FreeSymKey(newKey);
+	    return rv;
+	}
+    }
+
+
+    if (newKey == NULL) {
+	crv = CKR_KEY_TYPE_INCONSISTENT;
+	if (key->data.data) {
+	    crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session,
+					key->data.data,key->data.len);
+	}
+    } else {
+	crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session,
+							newKey->objectID);
+    }
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+        rv = SECFailure;
+    }
+
+    /*
+     * handle session starvation case.. use our last session to multiplex
+     */
+    if (!context->ownSession) {
+	context->savedData = pk11_saveContext(context,context->savedData,
+				&context->savedLength);
+	if (context->savedData == NULL) rv = SECFailure;
+	
+	/* clear out out session for others to use */
+	pk11_Finalize(context);
+    }
+    PK11_ExitContextMonitor(context);
+    if (newKey) PK11_FreeSymKey(newKey);
+    return rv;
+}
+
+/*
+ * externally callable version of the lowercase pk11_finalize().
+ */
+SECStatus
+PK11_Finalize(PK11Context *context) {
+    SECStatus rv;
+
+    PK11_EnterContextMonitor(context);
+    rv = pk11_Finalize(context);
+    PK11_ExitContextMonitor(context);
+    return rv;
+}
+
+/*
+ * clean up a cipher operation, so the session can be used by
+ * someone new.
+ */
+SECStatus
+pk11_Finalize(PK11Context *context)
+{
+    CK_ULONG count = 0;
+    CK_RV crv;
+    unsigned char stackBuf[256];
+    unsigned char *buffer = NULL;
+
+    if (!context->ownSession) {
+	return SECSuccess;
+    }
+
+finalize:
+    switch (context->operation) {
+    case CKA_ENCRYPT:
+	crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
+	                                               buffer, &count);
+	break;
+    case CKA_DECRYPT:
+	crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session,
+	                                                 buffer, &count);
+	break;
+    case CKA_SIGN:
+	crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session,
+	                                            buffer, &count);
+	break;
+    case CKA_VERIFY:
+	crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session,
+	                                              buffer, count);
+	break;
+    case CKA_DIGEST:
+	crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session,
+	                                              buffer, &count);
+	break;
+    default:
+	crv = CKR_OPERATION_NOT_INITIALIZED;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+	if (buffer != stackBuf) {
+	    PORT_Free(buffer);
+	}
+	if (crv == CKR_OPERATION_NOT_INITIALIZED) {
+	    /* if there's no operation, it is finalized */
+	    return SECSuccess;
+	}
+        PORT_SetError( PK11_MapError(crv) );
+        return SECFailure;
+    }
+
+    /* try to finalize the session with a buffer */
+    if (buffer == NULL) { 
+	if (count <= sizeof stackBuf) {
+	    buffer = stackBuf;
+	} else {
+	    buffer = PORT_Alloc(count);
+	    if (buffer == NULL) {
+		PORT_SetError(SEC_ERROR_NO_MEMORY);
+		return SECFailure;
+	    }
+	}
+	goto finalize;
+    }
+    if (buffer != stackBuf) {
+	PORT_Free(buffer);
+    }
+    return SECSuccess;
+}
+
+/*
+ *  Return the final digested or signed data...
+ *  this routine can either take pre initialized data, or allocate data
+ *  either out of an arena or out of the standard heap.
+ */
+SECStatus
+PK11_DigestFinal(PK11Context *context,unsigned char *data, 
+			unsigned int *outLen, unsigned int length)
+{
+    CK_ULONG len;
+    CK_RV crv;
+    SECStatus rv;
+
+
+    /* if we ran out of session, we need to restore our previously stored
+     * state.
+     */
+    PK11_EnterContextMonitor(context);
+    if (!context->ownSession) {
+        rv = pk11_restoreContext(context,context->savedData,
+							context->savedLength);
+	if (rv != SECSuccess) {
+	    PK11_ExitContextMonitor(context);
+	    return rv;
+	}
+    }
+
+    len = length;
+    switch (context->operation) {
+    case CKA_SIGN:
+	crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session,
+				data,&len);
+	break;
+    case CKA_VERIFY:
+	crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session,
+				data,len);
+	break;
+    case CKA_DIGEST:
+	crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session,
+				data,&len);
+	break;
+    case CKA_ENCRYPT:
+	crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
+				data, &len);
+	break;
+    case CKA_DECRYPT:
+	crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session,
+				data, &len);
+	break;
+    default:
+	crv = CKR_OPERATION_NOT_INITIALIZED;
+	break;
+    }
+    PK11_ExitContextMonitor(context);
+
+    *outLen = (unsigned int) len;
+    context->init = PR_FALSE; /* allow Begin to start up again */
+
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11err.c b/mozilla/security/nss/lib/pk11wrap/pk11err.c
new file mode 100644
index 0000000..a86cb3c
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11err.c
@@ -0,0 +1,161 @@
+/* ***** 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 ***** */
+/* 
+ * this file maps PKCS11 Errors into SECErrors
+ *  This is an information reducing process, since most errors are reflected
+ *  back to the user (the user doesn't care about invalid flags, or active
+ *  operations). If any of these errors need more detail in the upper layers
+ *  which call PK11 library functions, we can add more SEC_ERROR_XXX functions
+ *  and change there mappings here.
+ */
+#include "pkcs11t.h"
+#include "pk11func.h"
+#include "secerr.h"
+#include "prerror.h"
+
+#ifdef PK11_ERROR_USE_ARRAY 
+
+/*
+ * build a static array of entries...
+ */
+static struct {
+	CK_RV pk11_error;
+	int   sec_error;
+} pk11_error_map = {
+#define MAPERROR(x,y) {x, y},
+
+#else
+
+/* the default is to use a big switch statement */
+int
+PK11_MapError(CK_RV rv) {
+
+	switch (rv) {
+#define MAPERROR(x,y) case x: return y;
+
+#endif
+
+/* the guts mapping */
+	MAPERROR(CKR_OK, 0)
+	MAPERROR(CKR_CANCEL, SEC_ERROR_IO)
+	MAPERROR(CKR_HOST_MEMORY, SEC_ERROR_NO_MEMORY)
+	MAPERROR(CKR_SLOT_ID_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_ARGUMENTS_BAD, SEC_ERROR_INVALID_ARGS)
+	MAPERROR(CKR_ATTRIBUTE_READ_ONLY, SEC_ERROR_READ_ONLY)
+	MAPERROR(CKR_ATTRIBUTE_SENSITIVE, SEC_ERROR_IO) /* XX SENSITIVE */
+	MAPERROR(CKR_ATTRIBUTE_TYPE_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_ATTRIBUTE_VALUE_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_BUFFER_TOO_SMALL, SEC_ERROR_OUTPUT_LEN)
+	MAPERROR(CKR_DATA_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_DATA_LEN_RANGE, SEC_ERROR_INPUT_LEN)
+	MAPERROR(CKR_DEVICE_ERROR, SEC_ERROR_PKCS11_DEVICE_ERROR)
+	MAPERROR(CKR_DEVICE_MEMORY, SEC_ERROR_NO_MEMORY)
+	MAPERROR(CKR_DEVICE_REMOVED, SEC_ERROR_NO_TOKEN)
+	MAPERROR(CKR_DOMAIN_PARAMS_INVALID, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_ENCRYPTED_DATA_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_ENCRYPTED_DATA_LEN_RANGE, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_FUNCTION_CANCELED, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_FUNCTION_FAILED, SEC_ERROR_PKCS11_FUNCTION_FAILED)
+	MAPERROR(CKR_FUNCTION_NOT_PARALLEL, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_FUNCTION_NOT_SUPPORTED, PR_NOT_IMPLEMENTED_ERROR)
+	MAPERROR(CKR_GENERAL_ERROR, SEC_ERROR_PKCS11_GENERAL_ERROR)
+	MAPERROR(CKR_KEY_HANDLE_INVALID, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_KEY_SIZE_RANGE, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_KEY_TYPE_INCONSISTENT, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_MECHANISM_INVALID, SEC_ERROR_INVALID_ALGORITHM)
+	MAPERROR(CKR_MECHANISM_PARAM_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_NO_EVENT, SEC_ERROR_NO_EVENT)
+	MAPERROR(CKR_OBJECT_HANDLE_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_OPERATION_ACTIVE, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_OPERATION_NOT_INITIALIZED,SEC_ERROR_LIBRARY_FAILURE )
+	MAPERROR(CKR_PIN_INCORRECT, SEC_ERROR_BAD_PASSWORD)
+	MAPERROR(CKR_PIN_INVALID, SEC_ERROR_INVALID_PASSWORD)
+	MAPERROR(CKR_PIN_LEN_RANGE, SEC_ERROR_INVALID_PASSWORD)
+	MAPERROR(CKR_SESSION_CLOSED, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_SESSION_COUNT, SEC_ERROR_NO_MEMORY) /* XXXX? */
+	MAPERROR(CKR_SESSION_HANDLE_INVALID, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_SESSION_PARALLEL_NOT_SUPPORTED, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_SESSION_READ_ONLY, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_SIGNATURE_INVALID, SEC_ERROR_BAD_SIGNATURE)
+	MAPERROR(CKR_SIGNATURE_LEN_RANGE, SEC_ERROR_BAD_SIGNATURE)
+	MAPERROR(CKR_TEMPLATE_INCOMPLETE, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_TEMPLATE_INCONSISTENT, SEC_ERROR_BAD_DATA)
+	MAPERROR(CKR_TOKEN_NOT_PRESENT, SEC_ERROR_NO_TOKEN)
+	MAPERROR(CKR_TOKEN_NOT_RECOGNIZED, SEC_ERROR_IO)
+	MAPERROR(CKR_TOKEN_WRITE_PROTECTED, SEC_ERROR_READ_ONLY)
+	MAPERROR(CKR_UNWRAPPING_KEY_HANDLE_INVALID, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_UNWRAPPING_KEY_SIZE_RANGE, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_USER_ALREADY_LOGGED_IN, 0)
+	MAPERROR(CKR_USER_NOT_LOGGED_IN, SEC_ERROR_TOKEN_NOT_LOGGED_IN)
+	MAPERROR(CKR_USER_PIN_NOT_INITIALIZED, SEC_ERROR_NO_TOKEN)
+	MAPERROR(CKR_USER_TYPE_INVALID, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_WRAPPED_KEY_INVALID, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_WRAPPED_KEY_LEN_RANGE, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_WRAPPING_KEY_HANDLE_INVALID, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_WRAPPING_KEY_SIZE_RANGE, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_WRAPPING_KEY_TYPE_INCONSISTENT, SEC_ERROR_INVALID_KEY)
+	MAPERROR(CKR_VENDOR_DEFINED, SEC_ERROR_LIBRARY_FAILURE)
+	MAPERROR(CKR_NETSCAPE_CERTDB_FAILED, SEC_ERROR_BAD_DATABASE)
+	MAPERROR(CKR_NETSCAPE_KEYDB_FAILED, SEC_ERROR_BAD_DATABASE)
+	MAPERROR(CKR_CANT_LOCK, SEC_ERROR_INCOMPATIBLE_PKCS11)
+
+#ifdef PK11_ERROR_USE_ARRAY 
+};
+
+int
+PK11_MapError(CK_RV rv) {
+    int size = sizeof(pk11_error_map)/sizeof(pk11_error_map[0]);
+
+    for (i=0; i < size; i++) {
+	if (pk11_error_map[i].pk11_error == rv) {
+	    return pk11_error_map[i].sec_error;
+	}
+    }
+    return SEC_ERROR_IO;
+ }
+
+
+#else
+
+    default:
+	break;
+    }
+    return SEC_ERROR_IO;
+}
+
+
+#endif
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11func.h b/mozilla/security/nss/lib/pk11wrap/pk11func.h
new file mode 100644
index 0000000..30ba255
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11func.h
@@ -0,0 +1,47 @@
+/* ***** 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 ***** */
+#ifndef _PK11FUNC_H_
+#define _PK11FUNC_H_
+
+/*
+ * The original pk11func.h had a mix of public and private functions.
+ * Continue to provide those for backward compatibility.  New code should
+ * include pk11pub.h instead of pk11func.h.
+ */
+#include "pk11pub.h"
+#include "pk11priv.h"
+
+#endif
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11kea.c b/mozilla/security/nss/lib/pk11wrap/pk11kea.c
new file mode 100644
index 0000000..3d2a52a
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11kea.c
@@ -0,0 +1,163 @@
+/* ***** 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 ***** */
+/*
+ * This file implements the Symkey wrapper and the PKCS context
+ * Interfaces.
+ */
+
+#include "seccomon.h"
+#include "secmod.h"
+#include "nssilock.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "key.h"
+#include "secasn1.h"
+#include "sechash.h"
+#include "cert.h"
+#include "secerr.h"
+
+/*
+ * find an RSA public key on a card
+ */
+static CK_OBJECT_HANDLE
+pk11_FindRSAPubKey(PK11SlotInfo *slot)
+{
+    CK_KEY_TYPE key_type = CKK_RSA;
+    CK_OBJECT_CLASS class_type = CKO_PUBLIC_KEY;
+    CK_ATTRIBUTE theTemplate[2];
+    int template_count = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    CK_ATTRIBUTE *attrs = theTemplate;
+
+    PK11_SETATTRS(attrs,CKA_CLASS,&class_type,sizeof(class_type)); attrs++;
+    PK11_SETATTRS(attrs,CKA_KEY_TYPE,&key_type,sizeof(key_type)); attrs++;
+    template_count = attrs - theTemplate;
+    PR_ASSERT(template_count <= sizeof(theTemplate)/sizeof(CK_ATTRIBUTE));
+
+    return pk11_FindObjectByTemplate(slot,theTemplate,template_count);
+}
+
+PK11SymKey *
+pk11_KeyExchange(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
+		 CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, 
+					PRBool isPerm, PK11SymKey *symKey)
+{
+    PK11SymKey *newSymKey = NULL;
+    SECStatus rv;
+    /* performance improvement can go here --- use a generated key at startup
+     * to generate a per token wrapping key. If it exists, use it, otherwise 
+     * do a full key exchange. */
+
+    /* find a common Key Exchange algorithm */
+    /* RSA */
+    if (PK11_DoesMechanism(symKey->slot, CKM_RSA_PKCS) && 
+				PK11_DoesMechanism(slot,CKM_RSA_PKCS)) {
+	CK_OBJECT_HANDLE pubKeyHandle = CK_INVALID_HANDLE;
+	CK_OBJECT_HANDLE privKeyHandle = CK_INVALID_HANDLE;
+	SECKEYPublicKey *pubKey = NULL;
+	SECKEYPrivateKey *privKey = NULL;
+	SECItem wrapData;
+	unsigned int     symKeyLength = PK11_GetKeyLength(symKey);
+
+	wrapData.data = NULL;
+
+	/* find RSA Public Key on target */
+	pubKeyHandle = pk11_FindRSAPubKey(slot);
+	if (pubKeyHandle != CK_INVALID_HANDLE) {
+	    privKeyHandle = PK11_MatchItem(slot,pubKeyHandle,CKO_PRIVATE_KEY);
+	}
+
+	/* if no key exists, generate a key pair */
+	if (privKeyHandle == CK_INVALID_HANDLE) {
+	    PK11RSAGenParams rsaParams;
+
+	    if (symKeyLength > 53) /* bytes */ {
+		/* we'd have to generate an RSA key pair > 512 bits long,
+		** and that's too costly.  Don't even try. 
+		*/
+		PORT_SetError( SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY );
+		goto rsa_failed;
+	    }
+	    rsaParams.keySizeInBits = 
+	        (symKeyLength > 21 || symKeyLength == 0) ? 512 : 256;
+	    rsaParams.pe  = 0x10001;
+	    privKey = PK11_GenerateKeyPair(slot,CKM_RSA_PKCS_KEY_PAIR_GEN, 
+			    &rsaParams, &pubKey,PR_FALSE,PR_TRUE,symKey->cx);
+	} else {
+	    /* if keys exist, build SECKEY data structures for them */
+	    privKey = PK11_MakePrivKey(slot,nullKey, PR_TRUE, privKeyHandle,
+					symKey->cx);
+	    if (privKey != NULL) {
+    		pubKey = PK11_ExtractPublicKey(slot, rsaKey, pubKeyHandle);
+		if (pubKey && pubKey->pkcs11Slot) {
+		    PK11_FreeSlot(pubKey->pkcs11Slot);
+		    pubKey->pkcs11Slot = NULL;
+		    pubKey->pkcs11ID = CK_INVALID_HANDLE;
+		}
+	    }
+	}
+	if (privKey == NULL) goto rsa_failed;
+	if (pubKey == NULL)  goto rsa_failed;
+
+        wrapData.len  = SECKEY_PublicKeyStrength(pubKey);
+        if (!wrapData.len) goto rsa_failed;
+        wrapData.data = PORT_Alloc(wrapData.len);
+        if (wrapData.data == NULL) goto rsa_failed;
+
+	/* now wrap the keys in and out */
+	rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, pubKey, symKey, &wrapData);
+	if (rv == SECSuccess) {
+	    newSymKey = PK11_PubUnwrapSymKeyWithFlagsPerm(privKey,
+			&wrapData,type,operation,symKeyLength,flags,isPerm);
+	    /* make sure we wound up where we wanted to be! */
+	    if (newSymKey && newSymKey->slot != slot) {
+		PK11_FreeSymKey(newSymKey);
+		newSymKey = NULL;
+	    }
+	}
+rsa_failed:
+	if (wrapData.data != NULL) PORT_Free(wrapData.data);
+	if (privKey != NULL) SECKEY_DestroyPrivateKey(privKey);
+	if (pubKey != NULL) SECKEY_DestroyPublicKey(pubKey);
+
+	return  newSymKey;
+    }
+    PORT_SetError( SEC_ERROR_NO_MODULE );
+    return NULL;
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11list.c b/mozilla/security/nss/lib/pk11wrap/pk11list.c
new file mode 100644
index 0000000..24885b8
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11list.c
@@ -0,0 +1,127 @@
+/* ***** 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 ***** */
+/*
+ * Locking and queue management primatives
+ *
+ */
+
+#include "seccomon.h"
+#include "nssilock.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "nssrwlk.h"
+
+/*
+ * create a new lock for a Module List
+ */
+SECMODListLock *SECMOD_NewListLock()
+{
+    return NSSRWLock_New( 10, "moduleListLock");
+}
+
+/*
+ * destroy the lock
+ */
+void SECMOD_DestroyListLock(SECMODListLock *lock) 
+{
+    NSSRWLock_Destroy(lock);
+}
+
+
+/*
+ * Lock the List for Read: NOTE: this assumes the reading isn't so common
+ * the writing will be starved.
+ */
+void SECMOD_GetReadLock(SECMODListLock *modLock) 
+{
+    NSSRWLock_LockRead(modLock);
+}
+
+/*
+ * Release the Read lock
+ */
+void SECMOD_ReleaseReadLock(SECMODListLock *modLock) 
+{
+    NSSRWLock_UnlockRead(modLock);
+}
+
+
+/*
+ * lock the list for Write
+ */
+void SECMOD_GetWriteLock(SECMODListLock *modLock) 
+{
+    NSSRWLock_LockWrite(modLock);
+}
+
+
+/*
+ * Release the Write Lock: NOTE, this code is pretty inefficient if you have
+ * lots of write collisions.
+ */
+void SECMOD_ReleaseWriteLock(SECMODListLock *modLock) 
+{
+    NSSRWLock_UnlockWrite(modLock);
+}
+
+
+/*
+ * must Hold the Write lock
+ */
+void
+SECMOD_RemoveList(SECMODModuleList **parent, SECMODModuleList *child) 
+{
+    *parent = child->next;
+    child->next = NULL;
+}
+
+/*
+ * if lock is not specified, it must already be held
+ */
+void
+SECMOD_AddList(SECMODModuleList *parent, SECMODModuleList *child, 
+							SECMODListLock *lock) 
+{
+    if (lock) { SECMOD_GetWriteLock(lock); }
+
+    child->next = parent->next;
+    parent->next = child;
+
+   if (lock) { SECMOD_ReleaseWriteLock(lock); }
+}
+
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11load.c b/mozilla/security/nss/lib/pk11wrap/pk11load.c
new file mode 100644
index 0000000..61ec684
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11load.c
@@ -0,0 +1,651 @@
+/* ***** 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 ***** */
+/*
+ * The following handles the loading, unloading and management of
+ * various PCKS #11 modules
+ */
+#define FORCE_PR_LOG 1
+#include "seccomon.h"
+#include "pkcs11.h"
+#include "secmod.h"
+#include "prlink.h"
+#include "pk11func.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "nssilock.h"
+#include "secerr.h"
+#include "prenv.h"
+
+#define DEBUG_MODULE 1
+
+#ifdef DEBUG_MODULE
+static char *modToDBG = NULL;
+
+#include "debug_module.c"
+#endif
+
+/* build the PKCS #11 2.01 lock files */
+CK_RV PR_CALLBACK secmodCreateMutext(CK_VOID_PTR_PTR pmutex) {
+    *pmutex = (CK_VOID_PTR) PZ_NewLock(nssILockOther);
+    if ( *pmutex ) return CKR_OK;
+    return CKR_HOST_MEMORY;
+}
+
+CK_RV PR_CALLBACK secmodDestroyMutext(CK_VOID_PTR mutext) {
+    PZ_DestroyLock((PZLock *)mutext);
+    return CKR_OK;
+}
+
+CK_RV PR_CALLBACK secmodLockMutext(CK_VOID_PTR mutext) {
+    PZ_Lock((PZLock *)mutext);
+    return CKR_OK;
+}
+
+CK_RV PR_CALLBACK secmodUnlockMutext(CK_VOID_PTR mutext) {
+    PZ_Unlock((PZLock *)mutext);
+    return CKR_OK;
+}
+
+static SECMODModuleID  nextModuleID = 1;
+static const CK_C_INITIALIZE_ARGS secmodLockFunctions = {
+    secmodCreateMutext, secmodDestroyMutext, secmodLockMutext, 
+    secmodUnlockMutext, CKF_LIBRARY_CANT_CREATE_OS_THREADS|
+	CKF_OS_LOCKING_OK
+    ,NULL
+};
+
+static PRBool loadSingleThreadedModules = PR_TRUE;
+static PRBool enforceAlreadyInitializedError = PR_TRUE;
+static PRBool finalizeModules = PR_TRUE;
+
+/* set global options for NSS PKCS#11 module loader */
+SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules,
+                                PRBool allowAlreadyInitializedModules,
+                                PRBool dontFinalizeModules)
+{
+    if (noSingleThreadedModules) {
+        loadSingleThreadedModules = PR_FALSE;
+    } else {
+        loadSingleThreadedModules = PR_TRUE;
+    }
+    if (allowAlreadyInitializedModules) {
+        enforceAlreadyInitializedError = PR_FALSE;
+    } else {
+        enforceAlreadyInitializedError = PR_TRUE;
+    }
+    if (dontFinalizeModules) {
+        finalizeModules = PR_FALSE;
+    } else {
+        finalizeModules = PR_TRUE;
+    }
+    return SECSuccess;
+}
+
+PRBool pk11_getFinalizeModulesOption(void)
+{
+    return finalizeModules;
+}
+
+/*
+ * Allow specification loading the same module more than once at init time.
+ * This enables 2 things.
+ *
+ *    1) we can load additional databases by manipulating secmod.db/pkcs11.txt.
+ *    2) we can handle the case where some library has already initialized NSS
+ *    before the main application.
+ *
+ * oldModule is the module we have already initialized.
+ * char *modulespec is the full module spec for the library we want to
+ * initialize.
+ */
+static SECStatus
+secmod_handleReload(SECMODModule *oldModule, SECMODModule *newModule)
+{
+    PK11SlotInfo *slot;
+    char *modulespec;
+    char *newModuleSpec;
+    char **children;
+    CK_SLOT_ID *ids;
+    SECStatus rv;
+    SECMODConfigList *conflist;
+    int count = 0;
+
+    /* first look for tokens= key words from the module spec */
+    modulespec = newModule->libraryParams;
+    newModuleSpec = secmod_ParseModuleSpecForTokens(PR_TRUE,
+				newModule->isFIPS, modulespec, &children, &ids);
+    if (!newModuleSpec) {
+	return SECFailure;
+    }
+
+    /* 
+     * We are now trying to open a new slot on an already loaded module.
+     * If that slot represents a cert/key database, we don't want to open
+     * multiple copies of that same database. Unfortunately we understand
+     * the softoken flags well enough to be able to do this, so we can only get
+     * the list of already loaded databases if we are trying to open another
+     * internal module. 
+     */
+    if (oldModule->internal) {
+	conflist = secmod_GetConfigList(oldModule->isFIPS, 
+					oldModule->libraryParams, &count);
+    }
+
+
+    /* don't open multiple of the same db */
+    if (conflist && secmod_MatchConfigList(newModuleSpec, conflist, count)) { 
+	rv = SECSuccess;
+	goto loser;
+    }
+    slot = SECMOD_OpenNewSlot(oldModule, newModuleSpec);
+    if (slot) {
+	int newID;
+	char **thisChild;
+	CK_SLOT_ID *thisID;
+	char *oldModuleSpec;
+
+	if (secmod_IsInternalKeySlot(newModule)) {
+	    pk11_SetInternalKeySlot(slot);
+	}
+	newID = slot->slotID;
+	PK11_FreeSlot(slot);
+	for (thisChild=children, thisID=ids; thisChild && *thisChild; 
+						thisChild++,thisID++) {
+	    if (conflist &&
+		       secmod_MatchConfigList(*thisChild, conflist, count)) {
+		*thisID = (CK_SLOT_ID) -1;
+		continue;
+	    }
+	    slot = SECMOD_OpenNewSlot(oldModule, *thisChild);
+	    if (slot) {
+		*thisID = slot->slotID;
+		PK11_FreeSlot(slot);
+	    } else {
+		*thisID = (CK_SLOT_ID) -1;
+	    }
+	}
+
+	/* update the old module initialization string in case we need to
+	 * shutdown and reinit the whole mess (this is rare, but can happen
+	 * when trying to stop smart card insertion/removal threads)... */
+	oldModuleSpec = secmod_MkAppendTokensList(oldModule->arena, 
+		oldModule->libraryParams, newModuleSpec, newID, 
+		children, ids);
+	if (oldModuleSpec) {
+	    oldModule->libraryParams = oldModuleSpec;
+	}
+	
+	rv = SECSuccess;
+    }
+
+loser:
+    secmod_FreeChildren(children, ids);
+    PORT_Free(newModuleSpec);
+    if (conflist) {
+	secmod_FreeConfigList(conflist, count);
+    }
+    return rv;
+}
+
+/*
+ * collect the steps we need to initialize a module in a single function
+ */
+SECStatus
+secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload, 
+		  PRBool* alreadyLoaded)
+{
+    CK_C_INITIALIZE_ARGS moduleArgs;
+    CK_VOID_PTR pInitArgs;
+    CK_RV crv;
+
+    if (reload) {
+	*reload = NULL;
+    }
+
+    if (!mod || !alreadyLoaded) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (mod->isThreadSafe == PR_FALSE) {
+	pInitArgs = NULL;
+    } else if (mod->libraryParams == NULL) {
+	pInitArgs = (void *) &secmodLockFunctions;
+    } else {
+	moduleArgs = secmodLockFunctions;
+	moduleArgs.LibraryParameters = (void *) mod->libraryParams;
+	pInitArgs = &moduleArgs;
+    }
+    crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
+    if (CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) {
+	SECMODModule *oldModule = NULL;
+
+	/* Library has already been loaded once, if caller expects it, and it
+	 * has additional configuration, try reloading it as well. */
+	if (reload != NULL && mod->libraryParams) {
+	    oldModule = secmod_FindModuleByFuncPtr(mod->functionList);
+	}
+	/* Library has been loaded by NSS. It means it may be capable of
+	 * reloading */
+	if (oldModule) {
+	    SECStatus rv;
+	    rv = secmod_handleReload(oldModule, mod);
+	    if (rv == SECSuccess) {
+		/* This module should go away soon, since we've
+		 * simply expanded the slots on the old module.
+		 * When it goes away, it should not Finalize since
+		 * that will close our old module as well. Setting
+		 * the function list to NULL will prevent that close */
+		mod->functionList = NULL;
+		*reload = oldModule;
+		return SECSuccess;
+	    }
+	    SECMOD_DestroyModule(oldModule);
+	}
+	/* reload not possible, fall back to old semantics */
+	if (!enforceAlreadyInitializedError) {
+       	    *alreadyLoaded = PR_TRUE;
+            return SECSuccess;
+	}
+    }
+    if (crv != CKR_OK) {
+	if (pInitArgs == NULL ||
+		crv == CKR_NETSCAPE_CERTDB_FAILED ||
+		crv == CKR_NETSCAPE_KEYDB_FAILED) {
+	    PORT_SetError(PK11_MapError(crv));
+	    return SECFailure;
+	}
+	if (!loadSingleThreadedModules) {
+	    PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
+	    return SECFailure;
+	}
+	mod->isThreadSafe = PR_FALSE;
+    	crv = PK11_GETTAB(mod)->C_Initialize(NULL);
+	if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
+	    (!enforceAlreadyInitializedError)) {
+	    *alreadyLoaded = PR_TRUE;
+	    return SECSuccess;
+	}
+    	if (crv != CKR_OK)  {
+	    PORT_SetError(PK11_MapError(crv));
+	    return SECFailure;
+	}
+    }
+    return SECSuccess;
+}
+
+/*
+ * set the hasRootCerts flags in the module so it can be stored back
+ * into the database.
+ */
+void
+SECMOD_SetRootCerts(PK11SlotInfo *slot, SECMODModule *mod) {
+    PK11PreSlotInfo *psi = NULL;
+    int i;
+
+    if (slot->hasRootCerts) {
+	for (i=0; i < mod->slotInfoCount; i++) {
+	    if (slot->slotID == mod->slotInfo[i].slotID) {
+		psi = &mod->slotInfo[i];
+		break;
+	    }
+	}
+	if (psi == NULL) {
+	   /* allocate more slots */
+	   PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *)
+		PORT_ArenaAlloc(mod->arena,
+			(mod->slotInfoCount+1)* sizeof(PK11PreSlotInfo));
+	   /* copy the old ones */
+	   if (mod->slotInfoCount > 0) {
+		PORT_Memcpy(psi_list,mod->slotInfo,
+				(mod->slotInfoCount)*sizeof(PK11PreSlotInfo));
+	   }
+	   /* assign psi to the last new slot */
+	   psi = &psi_list[mod->slotInfoCount];
+	   psi->slotID = slot->slotID;
+	   psi->askpw = 0;
+	   psi->timeout = 0;
+	   psi ->defaultFlags = 0;
+
+	   /* increment module count & store new list */
+	   mod->slotInfo = psi_list;
+	   mod->slotInfoCount++;
+	   
+	}
+	psi->hasRootCerts = 1;
+    }
+}
+
+#if 1  /* STATIC LIBRARIES */
+extern CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
+extern CK_RV FC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
+extern char **NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args);
+#else
+static const char* my_shlib_name =
+    SHLIB_PREFIX"nss"SHLIB_VERSION"."SHLIB_SUFFIX;
+static const char* softoken_shlib_name =
+    SHLIB_PREFIX"softokn"SOFTOKEN_SHLIB_VERSION"."SHLIB_SUFFIX;
+static const PRCallOnceType pristineCallOnce;
+static PRCallOnceType loadSoftokenOnce;
+static PRLibrary* softokenLib;
+static PRInt32 softokenLoadCount;
+#endif  /* STATIC LIBRARIES */
+
+#include "prio.h"
+#include "prprf.h"
+#include <stdio.h>
+#include "prsystem.h"
+
+#if 0  /* STATIC LIBRARIES */
+/* This function must be run only once. */
+/*  determine if hybrid platform, then actually load the DSO. */
+static PRStatus
+softoken_LoadDSO( void ) 
+{
+  PRLibrary *  handle;
+
+  handle = PORT_LoadLibraryFromOrigin(my_shlib_name,
+                                      (PRFuncPtr) &softoken_LoadDSO,
+                                      softoken_shlib_name);
+  if (handle) {
+    softokenLib = handle;
+    return PR_SUCCESS;
+  }
+  return PR_FAILURE;
+}
+#endif  /* STATIC LIBRARIES */
+
+/*
+ * load a new module into our address space and initialize it.
+ */
+SECStatus
+secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule) {
+    PRLibrary *library = NULL;
+    CK_C_GetFunctionList entry = NULL;
+    char * full_name;
+    CK_INFO info;
+    CK_ULONG slotCount = 0;
+    SECStatus rv;
+    PRBool alreadyLoaded = PR_FALSE;
+    char *disableUnload = NULL;
+
+    if (mod->loaded) return SECSuccess;
+
+    /* intenal modules get loaded from their internal list */
+    if (mod->internal && (mod->dllName == NULL)) {
+#if 1  /* STATIC LIBRARIES */
+    if (mod->isFIPS) {
+        entry = FC_GetFunctionList;
+    } else {
+        entry = NSC_GetFunctionList;
+    }
+    if (mod->isModuleDB) {
+        mod->moduleDBFunc = NSC_ModuleDBFunc;
+    }
+#else
+    /*
+     * Loads softoken as a dynamic library,
+     * even though the rest of NSS assumes this as the "internal" module.
+     */
+    if (!softokenLib && 
+        PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO))
+        return SECFailure;
+
+    PR_AtomicIncrement(&softokenLoadCount);
+
+    if (mod->isFIPS) {
+        entry = (CK_C_GetFunctionList) 
+                    PR_FindSymbol(softokenLib, "FC_GetFunctionList");
+    } else {
+        entry = (CK_C_GetFunctionList) 
+                    PR_FindSymbol(softokenLib, "NSC_GetFunctionList");
+    }
+
+    if (!entry)
+        return SECFailure;
+
+    if (mod->isModuleDB) {
+        mod->moduleDBFunc = (CK_C_GetFunctionList) 
+                    PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc");
+    }
+#endif
+
+    if (mod->moduleDBOnly) {
+        mod->loaded = PR_TRUE;
+        return SECSuccess;
+    }
+    } else {
+	/* Not internal, load the DLL and look up C_GetFunctionList */
+	if (mod->dllName == NULL) {
+	    return SECFailure;
+	}
+
+	full_name = PORT_Strdup(mod->dllName);
+
+	/* load the library. If this succeeds, then we have to remember to
+	 * unload the library if anything goes wrong from here on out...
+	 */
+	library = PR_LoadLibrary(full_name);
+	mod->library = (void *)library;
+	PORT_Free(full_name);
+
+	if (library == NULL) {
+	    return SECFailure;
+	}
+
+	/*
+	 * now we need to get the entry point to find the function pointers
+	 */
+	if (!mod->moduleDBOnly) {
+	    entry = (CK_C_GetFunctionList)
+			PR_FindSymbol(library, "C_GetFunctionList");
+	}
+	if (mod->isModuleDB) {
+	    mod->moduleDBFunc = (void *)
+			PR_FindSymbol(library, "NSS_ReturnModuleSpecData");
+	}
+	if (mod->moduleDBFunc == NULL) mod->isModuleDB = PR_FALSE;
+	if (entry == NULL) {
+	    if (mod->isModuleDB) {
+		mod->loaded = PR_TRUE;
+		mod->moduleDBOnly = PR_TRUE;
+		return SECSuccess;
+	    }
+	    PR_UnloadLibrary(library);
+	    return SECFailure;
+	}
+    }
+
+    /*
+     * We need to get the function list
+     */
+    if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK) 
+								goto fail;
+
+#ifdef DEBUG_MODULE
+    if (PR_TRUE) {
+	modToDBG = PR_GetEnv("NSS_DEBUG_PKCS11_MODULE");
+	if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
+	    mod->functionList = (void *)nss_InsertDeviceLog(
+	                           (CK_FUNCTION_LIST_PTR)mod->functionList);
+	}
+    }
+#endif
+
+    mod->isThreadSafe = PR_TRUE;
+
+    /* Now we initialize the module */
+    rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded);
+    if (rv != SECSuccess) {
+	goto fail;
+    }
+
+    /* module has been reloaded, this module itself is done, 
+     * return to the caller */
+    if (mod->functionList == NULL) {
+	mod->loaded = PR_TRUE; /* technically the module is loaded.. */
+	return SECSuccess;
+    }
+
+    /* check the version number */
+    if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2;
+    if (info.cryptokiVersion.major != 2) goto fail2;
+    /* all 2.0 are a priori *not* thread safe */
+    if (info.cryptokiVersion.minor < 1) {
+        if (!loadSingleThreadedModules) {
+            PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
+            goto fail2;
+        } else {
+            mod->isThreadSafe = PR_FALSE;
+        }
+    }
+    mod->cryptokiVersion = info.cryptokiVersion;
+
+    /* If we don't have a common name, get it from the PKCS 11 module */
+    if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
+	mod->commonName = PK11_MakeString(mod->arena,NULL,
+	   (char *)info.libraryDescription, sizeof(info.libraryDescription));
+	if (mod->commonName == NULL) goto fail2;
+    }
+    
+
+    /* initialize the Slots */
+    if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) {
+	CK_SLOT_ID *slotIDs;
+	int i;
+	CK_RV crv;
+
+	mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
+					sizeof(PK11SlotInfo *) * slotCount);
+	if (mod->slots == NULL) goto fail2;
+
+	slotIDs = (CK_SLOT_ID *) PORT_Alloc(sizeof(CK_SLOT_ID)*slotCount);
+	if (slotIDs == NULL) {
+	    goto fail2;
+	}  
+	crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount);
+	if (crv != CKR_OK) {
+	    PORT_Free(slotIDs);
+	    goto fail2;
+	}
+
+	/* Initialize each slot */
+	for (i=0; i < (int)slotCount; i++) {
+	    mod->slots[i] = PK11_NewSlotInfo(mod);
+	    PK11_InitSlot(mod,slotIDs[i],mod->slots[i]);
+	    /* look down the slot info table */
+	    PK11_LoadSlotList(mod->slots[i],mod->slotInfo,mod->slotInfoCount);
+	    SECMOD_SetRootCerts(mod->slots[i],mod);
+	}
+	mod->slotCount = slotCount;
+	mod->slotInfoCount = 0;
+	PORT_Free(slotIDs);
+    }
+    
+    mod->loaded = PR_TRUE;
+    mod->moduleID = nextModuleID++;
+    return SECSuccess;
+fail2:
+    if (enforceAlreadyInitializedError || (!alreadyLoaded)) {
+        PK11_GETTAB(mod)->C_Finalize(NULL);
+    }
+fail:
+    mod->functionList = NULL;
+    disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
+    if (library && !disableUnload) {
+        PR_UnloadLibrary(library);
+    }
+    return SECFailure;
+}
+
+SECStatus
+SECMOD_UnloadModule(SECMODModule *mod) {
+    PRLibrary *library;
+    char *disableUnload = NULL;
+
+    if (!mod->loaded) {
+	return SECFailure;
+    }
+    if (finalizeModules) {
+        if (mod->functionList &&!mod->moduleDBOnly) {
+	    PK11_GETTAB(mod)->C_Finalize(NULL);
+	}
+    }
+    mod->moduleID = 0;
+    mod->loaded = PR_FALSE;
+    
+    /* do we want the semantics to allow unloading the internal library?
+     * if not, we should change this to SECFailure and move it above the
+     * mod->loaded = PR_FALSE; */
+    if (mod->internal) {
+#if 0  /* STATIC LIBRARIES */
+        if (0 == PR_AtomicDecrement(&softokenLoadCount)) {
+          if (softokenLib) {
+              disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
+              if (!disableUnload) {
+                  PRStatus status = PR_UnloadLibrary(softokenLib);
+                  PORT_Assert(PR_SUCCESS == status);
+              }
+              softokenLib = NULL;
+          }
+          loadSoftokenOnce = pristineCallOnce;
+        }
+#endif
+	return SECSuccess;
+    }
+
+    library = (PRLibrary *)mod->library;
+    /* paranoia */
+    if (library == NULL) {
+	return SECFailure;
+    }
+
+    disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
+    if (!disableUnload) {
+        PR_UnloadLibrary(library);
+    }
+    return SECSuccess;
+}
+
+void
+nss_DumpModuleLog(void)
+{
+#ifdef DEBUG_MODULE
+    if (modToDBG) {
+	print_final_statistics();
+    }
+#endif
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11mech.c b/mozilla/security/nss/lib/pk11wrap/pk11mech.c
new file mode 100644
index 0000000..f69c7fe
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11mech.c
@@ -0,0 +1,1900 @@
+/* ***** 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):
+ *   Dr Stephen Henson <stephen.henson@gemplus.com>
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * This file maps various PKCS #11 Mechanisms to related mechanisms, key
+ * types, and ASN.1 encodings.
+ */
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "pkcs11t.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "secder.h"
+#include "secasn1.h" 
+#include "secoid.h"
+#include "secerr.h"
+
+/*************************************************************
+ * local static and global data
+ *************************************************************/
+
+/*
+ * Tables used for Extended mechanism mapping (currently not used)
+ */
+typedef struct {
+	CK_MECHANISM_TYPE keyGen;
+	CK_KEY_TYPE keyType;
+	CK_MECHANISM_TYPE type;
+	CK_MECHANISM_TYPE padType;
+	int blockSize;
+	int iv;
+} pk11MechanismData;
+	
+static pk11MechanismData pk11_default = 
+  { CKM_GENERIC_SECRET_KEY_GEN, CKK_GENERIC_SECRET, 
+	CKM_FAKE_RANDOM, CKM_FAKE_RANDOM, 8, 8 };
+static pk11MechanismData *pk11_MechanismTable = NULL;
+static int pk11_MechTableSize = 0;
+static int pk11_MechEntrySize = 0;
+
+/*
+ * list of mechanisms we're willing to wrap secret keys with.
+ * This list is ordered by preference.
+ */
+CK_MECHANISM_TYPE wrapMechanismList[] = {
+    CKM_DES3_ECB,
+    CKM_CAST5_ECB,
+    CKM_AES_ECB,
+    CKM_CAMELLIA_ECB,
+    CKM_SEED_ECB,
+    CKM_CAST5_ECB,
+    CKM_DES_ECB,
+    CKM_KEY_WRAP_LYNKS,
+    CKM_IDEA_ECB,
+    CKM_CAST3_ECB,
+    CKM_CAST_ECB,
+    CKM_RC5_ECB,
+    CKM_RC2_ECB,
+    CKM_CDMF_ECB,
+    CKM_SKIPJACK_WRAP,
+};
+
+int wrapMechanismCount = sizeof(wrapMechanismList)/sizeof(wrapMechanismList[0]);
+
+/*********************************************************************
+ *       Mechanism Mapping functions
+ *********************************************************************/
+
+/*
+ * lookup an entry in the mechanism table. If none found, return the
+ * default structure.
+ */
+static pk11MechanismData *
+pk11_lookup(CK_MECHANISM_TYPE type)
+{
+    int i;
+    for (i=0; i < pk11_MechEntrySize; i++) {
+	if (pk11_MechanismTable[i].type == type) {
+	     return (&pk11_MechanismTable[i]);
+	}
+    }
+    return &pk11_default;
+}
+
+/*
+ * find the best key wrap mechanism for this slot.
+ */
+CK_MECHANISM_TYPE
+PK11_GetBestWrapMechanism(PK11SlotInfo *slot)
+{
+    int i;
+    for (i=0; i < wrapMechanismCount; i++) {
+	if (PK11_DoesMechanism(slot,wrapMechanismList[i])) {
+	    return wrapMechanismList[i];
+	}
+    }
+    return CKM_INVALID_MECHANISM;
+}
+
+/*
+ * NOTE: This is not thread safe. Called at init time, and when loading
+ * a new Entry. It is reasonably safe as long as it is not re-entered
+ * (readers will always see a consistant table)
+ *
+ * This routine is called to add entries to the mechanism table, once there,
+ * they can not be removed.
+ */
+void
+PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key,
+		 	CK_MECHANISM_TYPE keyGen, 
+			CK_MECHANISM_TYPE padType,
+			int ivLen, int blockSize)
+{
+    int tableSize = pk11_MechTableSize;
+    int size = pk11_MechEntrySize;
+    int entry = size++;
+    pk11MechanismData *old = pk11_MechanismTable;
+    pk11MechanismData *newt = pk11_MechanismTable;
+
+	
+    if (size > tableSize) {
+	int oldTableSize = tableSize;
+	tableSize += 10;
+	newt = PORT_NewArray(pk11MechanismData, tableSize);
+	if (newt == NULL) return;
+
+	if (old) PORT_Memcpy(newt, old, oldTableSize*sizeof(*newt));
+    } else old = NULL;
+
+    newt[entry].type = type;
+    newt[entry].keyType = key;
+    newt[entry].keyGen = keyGen;
+    newt[entry].padType = padType;
+    newt[entry].iv = ivLen;
+    newt[entry].blockSize = blockSize;
+
+    pk11_MechanismTable = newt;
+    pk11_MechTableSize = tableSize;
+    pk11_MechEntrySize = size;
+    if (old) PORT_Free(old);
+}
+
+/*
+ * Get the key type needed for the given mechanism
+ */
+CK_MECHANISM_TYPE
+PK11_GetKeyMechanism(CK_KEY_TYPE type)
+{
+    switch (type) {
+    case CKK_SEED:
+	return CKM_SEED_CBC;
+    case CKK_CAMELLIA:
+	return CKM_CAMELLIA_CBC;
+    case CKK_AES:
+	return CKM_AES_CBC;
+    case CKK_DES:
+	return CKM_DES_CBC;
+    case CKK_DES3:
+	return CKM_DES3_KEY_GEN;
+    case CKK_DES2:
+	return CKM_DES2_KEY_GEN;
+    case CKK_CDMF:
+	return CKM_CDMF_CBC;
+    case CKK_RC2:
+	return CKM_RC2_CBC;
+    case CKK_RC4:
+	return CKM_RC4;
+    case CKK_RC5:
+	return CKM_RC5_CBC;
+    case CKK_SKIPJACK:
+	return CKM_SKIPJACK_CBC64;
+    case CKK_BATON:
+	return CKM_BATON_CBC128;
+    case CKK_JUNIPER:
+	return CKM_JUNIPER_CBC128;
+    case CKK_IDEA:
+	return CKM_IDEA_CBC;
+    case CKK_CAST:
+	return CKM_CAST_CBC;
+    case CKK_CAST3:
+	return CKM_CAST3_CBC;
+    case CKK_CAST5:
+	return CKM_CAST5_CBC;
+    case CKK_RSA:
+	return CKM_RSA_PKCS;
+    case CKK_DSA:
+	return CKM_DSA;
+    case CKK_DH:
+	return CKM_DH_PKCS_DERIVE;
+    case CKK_KEA:
+	return CKM_KEA_KEY_DERIVE;
+    case CKK_EC:  /* CKK_ECDSA is deprecated */
+	return CKM_ECDSA;
+    case CKK_GENERIC_SECRET:
+    default:
+	return CKM_SHA_1_HMAC;
+    }
+}
+
+/*
+ * Get the key type needed for the given mechanism
+ */
+CK_MECHANISM_TYPE
+PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len)
+{
+    switch (type) {
+    case CKM_SEED_ECB:
+    case CKM_SEED_CBC:
+    case CKM_SEED_MAC:
+    case CKM_SEED_MAC_GENERAL:
+    case CKM_SEED_CBC_PAD:
+    case CKM_SEED_KEY_GEN:
+	return CKK_SEED;
+    case CKM_CAMELLIA_ECB:
+    case CKM_CAMELLIA_CBC:
+    case CKM_CAMELLIA_MAC:
+    case CKM_CAMELLIA_MAC_GENERAL:
+    case CKM_CAMELLIA_CBC_PAD:
+    case CKM_CAMELLIA_KEY_GEN:
+	return CKK_CAMELLIA;
+    case CKM_AES_ECB:
+    case CKM_AES_CBC:
+    case CKM_AES_MAC:
+    case CKM_AES_MAC_GENERAL:
+    case CKM_AES_CBC_PAD:
+    case CKM_AES_KEY_GEN:
+    case CKM_NETSCAPE_AES_KEY_WRAP:
+    case CKM_NETSCAPE_AES_KEY_WRAP_PAD:
+	return CKK_AES;
+    case CKM_DES_ECB:
+    case CKM_DES_CBC:
+    case CKM_DES_MAC:
+    case CKM_DES_MAC_GENERAL:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES_KEY_GEN:
+    case CKM_KEY_WRAP_LYNKS:
+    case CKM_PBE_MD2_DES_CBC:
+    case CKM_PBE_MD5_DES_CBC:
+	return CKK_DES;
+    case CKM_DES3_ECB:
+    case CKM_DES3_CBC:
+    case CKM_DES3_MAC:
+    case CKM_DES3_MAC_GENERAL:
+    case CKM_DES3_CBC_PAD:
+	return (len == 16) ? CKK_DES2 : CKK_DES3;
+    case CKM_DES2_KEY_GEN:
+    case CKM_PBE_SHA1_DES2_EDE_CBC:
+	return CKK_DES2;
+    case CKM_PBE_SHA1_DES3_EDE_CBC:
+    case CKM_DES3_KEY_GEN:
+	return CKK_DES3;
+    case CKM_CDMF_ECB:
+    case CKM_CDMF_CBC:
+    case CKM_CDMF_MAC:
+    case CKM_CDMF_MAC_GENERAL:
+    case CKM_CDMF_CBC_PAD:
+    case CKM_CDMF_KEY_GEN:
+	return CKK_CDMF;
+    case CKM_RC2_ECB:
+    case CKM_RC2_CBC:
+    case CKM_RC2_MAC:
+    case CKM_RC2_MAC_GENERAL:
+    case CKM_RC2_CBC_PAD:
+    case CKM_RC2_KEY_GEN:
+    case CKM_PBE_SHA1_RC2_128_CBC:
+    case CKM_PBE_SHA1_RC2_40_CBC:
+	return CKK_RC2;
+    case CKM_RC4:
+    case CKM_RC4_KEY_GEN:
+	return CKK_RC4;
+    case CKM_RC5_ECB:
+    case CKM_RC5_CBC:
+    case CKM_RC5_MAC:
+    case CKM_RC5_MAC_GENERAL:
+    case CKM_RC5_CBC_PAD:
+    case CKM_RC5_KEY_GEN:
+	return CKK_RC5;
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_SKIPJACK_KEY_GEN:
+    case CKM_SKIPJACK_WRAP:
+    case CKM_SKIPJACK_PRIVATE_WRAP:
+	return CKK_SKIPJACK;
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_BATON_WRAP:
+    case CKM_BATON_KEY_GEN:
+	return CKK_BATON;
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+    case CKM_JUNIPER_WRAP:
+    case CKM_JUNIPER_KEY_GEN:
+	return CKK_JUNIPER;
+    case CKM_IDEA_CBC:
+    case CKM_IDEA_ECB:
+    case CKM_IDEA_MAC:
+    case CKM_IDEA_MAC_GENERAL:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_IDEA_KEY_GEN:
+	return CKK_IDEA;
+    case CKM_CAST_ECB:
+    case CKM_CAST_CBC:
+    case CKM_CAST_MAC:
+    case CKM_CAST_MAC_GENERAL:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST_KEY_GEN:
+    case CKM_PBE_MD5_CAST_CBC:
+	return CKK_CAST;
+    case CKM_CAST3_ECB:
+    case CKM_CAST3_CBC:
+    case CKM_CAST3_MAC:
+    case CKM_CAST3_MAC_GENERAL:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST3_KEY_GEN:
+    case CKM_PBE_MD5_CAST3_CBC:
+	return CKK_CAST3;
+    case CKM_CAST5_ECB:
+    case CKM_CAST5_CBC:
+    case CKM_CAST5_MAC:
+    case CKM_CAST5_MAC_GENERAL:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_CAST5_KEY_GEN:
+    case CKM_PBE_MD5_CAST5_CBC:
+	return CKK_CAST5;
+    case CKM_RSA_PKCS:
+    case CKM_RSA_9796:
+    case CKM_RSA_X_509:
+    case CKM_MD2_RSA_PKCS:
+    case CKM_MD5_RSA_PKCS:
+    case CKM_SHA1_RSA_PKCS:
+    case CKM_SHA256_RSA_PKCS:
+    case CKM_SHA384_RSA_PKCS:
+    case CKM_SHA512_RSA_PKCS:
+    case CKM_KEY_WRAP_SET_OAEP:
+    case CKM_RSA_PKCS_KEY_PAIR_GEN:
+    case CKM_RSA_X9_31_KEY_PAIR_GEN:
+	return CKK_RSA;
+    case CKM_DSA:
+    case CKM_DSA_SHA1:
+    case CKM_DSA_KEY_PAIR_GEN:
+	return CKK_DSA;
+    case CKM_DH_PKCS_DERIVE:
+    case CKM_DH_PKCS_KEY_PAIR_GEN:
+	return CKK_DH;
+    case CKM_KEA_KEY_DERIVE:
+    case CKM_KEA_KEY_PAIR_GEN:
+	return CKK_KEA;
+    case CKM_ECDSA:
+    case CKM_ECDSA_SHA1:
+    case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
+    case CKM_ECDH1_DERIVE:
+	return CKK_EC;  /* CKK_ECDSA is deprecated */
+    case CKM_SSL3_PRE_MASTER_KEY_GEN:
+    case CKM_GENERIC_SECRET_KEY_GEN:
+    case CKM_SSL3_MASTER_KEY_DERIVE:
+    case CKM_SSL3_MASTER_KEY_DERIVE_DH:
+    case CKM_SSL3_KEY_AND_MAC_DERIVE:
+    case CKM_SSL3_SHA1_MAC:
+    case CKM_SSL3_MD5_MAC:
+    case CKM_TLS_MASTER_KEY_DERIVE:
+    case CKM_TLS_MASTER_KEY_DERIVE_DH:
+    case CKM_TLS_KEY_AND_MAC_DERIVE:
+    case CKM_SHA_1_HMAC:
+    case CKM_SHA_1_HMAC_GENERAL:
+    case CKM_SHA256_HMAC:
+    case CKM_SHA256_HMAC_GENERAL:
+    case CKM_SHA384_HMAC:
+    case CKM_SHA384_HMAC_GENERAL:
+    case CKM_SHA512_HMAC:
+    case CKM_SHA512_HMAC_GENERAL:
+    case CKM_MD2_HMAC:
+    case CKM_MD2_HMAC_GENERAL:
+    case CKM_MD5_HMAC:
+    case CKM_MD5_HMAC_GENERAL:
+    case CKM_TLS_PRF_GENERAL:
+	return CKK_GENERIC_SECRET;
+    default:
+	return pk11_lookup(type)->keyType;
+    }
+}
+
+/*
+ * Get the Key Gen Mechanism needed for the given 
+ * crypto mechanism
+ */
+CK_MECHANISM_TYPE
+PK11_GetKeyGen(CK_MECHANISM_TYPE type)
+{
+    return PK11_GetKeyGenWithSize(type, 0);
+}
+
+CK_MECHANISM_TYPE
+PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size)
+{
+    switch (type) {
+    case CKM_SEED_ECB:
+    case CKM_SEED_CBC:
+    case CKM_SEED_MAC:
+    case CKM_SEED_MAC_GENERAL:
+    case CKM_SEED_CBC_PAD:
+    case CKM_SEED_KEY_GEN:
+	return CKM_SEED_KEY_GEN;
+    case CKM_CAMELLIA_ECB:
+    case CKM_CAMELLIA_CBC:
+    case CKM_CAMELLIA_MAC:
+    case CKM_CAMELLIA_MAC_GENERAL:
+    case CKM_CAMELLIA_CBC_PAD:
+    case CKM_CAMELLIA_KEY_GEN:
+	return CKM_CAMELLIA_KEY_GEN;
+    case CKM_AES_ECB:
+    case CKM_AES_CBC:
+    case CKM_AES_MAC:
+    case CKM_AES_MAC_GENERAL:
+    case CKM_AES_CBC_PAD:
+    case CKM_AES_KEY_GEN:
+	return CKM_AES_KEY_GEN;
+    case CKM_DES_ECB:
+    case CKM_DES_CBC:
+    case CKM_DES_MAC:
+    case CKM_DES_MAC_GENERAL:
+    case CKM_KEY_WRAP_LYNKS:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES_KEY_GEN:
+	return CKM_DES_KEY_GEN;
+    case CKM_DES3_ECB:
+    case CKM_DES3_CBC:
+    case CKM_DES3_MAC:
+    case CKM_DES3_MAC_GENERAL:
+    case CKM_DES3_CBC_PAD:
+	return (size == 16) ? CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN;
+    case CKM_DES3_KEY_GEN:
+	return CKM_DES3_KEY_GEN;
+    case CKM_DES2_KEY_GEN:
+	return CKM_DES2_KEY_GEN;
+    case CKM_CDMF_ECB:
+    case CKM_CDMF_CBC:
+    case CKM_CDMF_MAC:
+    case CKM_CDMF_MAC_GENERAL:
+    case CKM_CDMF_CBC_PAD:
+    case CKM_CDMF_KEY_GEN:
+	return CKM_CDMF_KEY_GEN;
+    case CKM_RC2_ECB:
+    case CKM_RC2_CBC:
+    case CKM_RC2_MAC:
+    case CKM_RC2_MAC_GENERAL:
+    case CKM_RC2_CBC_PAD:
+    case CKM_RC2_KEY_GEN:
+	return CKM_RC2_KEY_GEN;
+    case CKM_RC4:
+    case CKM_RC4_KEY_GEN:
+	return CKM_RC4_KEY_GEN;
+    case CKM_RC5_ECB:
+    case CKM_RC5_CBC:
+    case CKM_RC5_MAC:
+    case CKM_RC5_MAC_GENERAL:
+    case CKM_RC5_CBC_PAD:
+    case CKM_RC5_KEY_GEN:
+	return CKM_RC5_KEY_GEN;
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_SKIPJACK_WRAP:
+    case CKM_SKIPJACK_KEY_GEN:
+	return CKM_SKIPJACK_KEY_GEN;
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_BATON_WRAP:
+    case CKM_BATON_KEY_GEN:
+	return CKM_BATON_KEY_GEN;
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+    case CKM_JUNIPER_WRAP:
+    case CKM_JUNIPER_KEY_GEN:
+	return CKM_JUNIPER_KEY_GEN;
+    case CKM_IDEA_CBC:
+    case CKM_IDEA_ECB:
+    case CKM_IDEA_MAC:
+    case CKM_IDEA_MAC_GENERAL:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_IDEA_KEY_GEN:
+	return CKM_IDEA_KEY_GEN;
+    case CKM_CAST_ECB:
+    case CKM_CAST_CBC:
+    case CKM_CAST_MAC:
+    case CKM_CAST_MAC_GENERAL:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST_KEY_GEN:
+	return CKM_CAST_KEY_GEN;
+    case CKM_CAST3_ECB:
+    case CKM_CAST3_CBC:
+    case CKM_CAST3_MAC:
+    case CKM_CAST3_MAC_GENERAL:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST3_KEY_GEN:
+	return CKM_CAST3_KEY_GEN;
+    case CKM_CAST5_ECB:
+    case CKM_CAST5_CBC:
+    case CKM_CAST5_MAC:
+    case CKM_CAST5_MAC_GENERAL:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_CAST5_KEY_GEN:
+	return CKM_CAST5_KEY_GEN;
+    case CKM_RSA_PKCS:
+    case CKM_RSA_9796:
+    case CKM_RSA_X_509:
+    case CKM_MD2_RSA_PKCS:
+    case CKM_MD5_RSA_PKCS:
+    case CKM_SHA1_RSA_PKCS:
+    case CKM_SHA256_RSA_PKCS:
+    case CKM_SHA384_RSA_PKCS:
+    case CKM_SHA512_RSA_PKCS:
+    case CKM_KEY_WRAP_SET_OAEP:
+    case CKM_RSA_PKCS_KEY_PAIR_GEN:
+	return CKM_RSA_PKCS_KEY_PAIR_GEN;
+    case CKM_RSA_X9_31_KEY_PAIR_GEN:
+	return CKM_RSA_X9_31_KEY_PAIR_GEN;
+    case CKM_DSA:
+    case CKM_DSA_SHA1:
+    case CKM_DSA_KEY_PAIR_GEN:
+	return CKM_DSA_KEY_PAIR_GEN;
+    case CKM_DH_PKCS_DERIVE:
+    case CKM_DH_PKCS_KEY_PAIR_GEN:
+	return CKM_DH_PKCS_KEY_PAIR_GEN;
+    case CKM_KEA_KEY_DERIVE:
+    case CKM_KEA_KEY_PAIR_GEN:
+	return CKM_KEA_KEY_PAIR_GEN;
+    case CKM_ECDSA:
+    case CKM_ECDSA_SHA1:
+    case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
+    case CKM_ECDH1_DERIVE:
+        return CKM_EC_KEY_PAIR_GEN; 
+    case CKM_SSL3_PRE_MASTER_KEY_GEN:
+    case CKM_SSL3_MASTER_KEY_DERIVE:
+    case CKM_SSL3_KEY_AND_MAC_DERIVE:
+    case CKM_SSL3_SHA1_MAC:
+    case CKM_SSL3_MD5_MAC:
+    case CKM_TLS_MASTER_KEY_DERIVE:
+    case CKM_TLS_KEY_AND_MAC_DERIVE:
+	return CKM_SSL3_PRE_MASTER_KEY_GEN;
+    case CKM_SHA_1_HMAC:
+    case CKM_SHA_1_HMAC_GENERAL:
+    case CKM_SHA256_HMAC:
+    case CKM_SHA256_HMAC_GENERAL:
+    case CKM_SHA384_HMAC:
+    case CKM_SHA384_HMAC_GENERAL:
+    case CKM_SHA512_HMAC:
+    case CKM_SHA512_HMAC_GENERAL:
+    case CKM_MD2_HMAC:
+    case CKM_MD2_HMAC_GENERAL:
+    case CKM_MD5_HMAC:
+    case CKM_MD5_HMAC_GENERAL:
+    case CKM_TLS_PRF_GENERAL:
+    case CKM_GENERIC_SECRET_KEY_GEN:
+	return CKM_GENERIC_SECRET_KEY_GEN;
+    case CKM_PBE_MD2_DES_CBC:
+    case CKM_PBE_MD5_DES_CBC:
+    case CKM_PBA_SHA1_WITH_SHA1_HMAC:
+    case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
+    case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
+    case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
+    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
+    case CKM_PBE_SHA1_RC2_40_CBC:
+    case CKM_PBE_SHA1_RC2_128_CBC:
+    case CKM_PBE_SHA1_RC4_40:
+    case CKM_PBE_SHA1_RC4_128:
+    case CKM_PBE_SHA1_DES3_EDE_CBC:
+    case CKM_PBE_SHA1_DES2_EDE_CBC:
+    case CKM_PKCS5_PBKD2:
+    	return type;
+    default:
+	return pk11_lookup(type)->keyGen;
+    }
+}
+
+/*
+ * get the mechanism block size
+ */
+int
+PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params)
+{
+    CK_RC5_PARAMS *rc5_params;
+    CK_RC5_CBC_PARAMS *rc5_cbc_params;
+    switch (type) {
+    case CKM_RC5_ECB:
+	if ((params) && (params->data)) {
+	    rc5_params = (CK_RC5_PARAMS *) params->data;
+	    return (rc5_params->ulWordsize)*2;
+	}
+	return 8;
+    case CKM_RC5_CBC:
+    case CKM_RC5_CBC_PAD:
+	if ((params) && (params->data)) {
+	    rc5_cbc_params = (CK_RC5_CBC_PARAMS *) params->data;
+	    return (rc5_cbc_params->ulWordsize)*2;
+	}
+	return 8;
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_RC2_ECB:
+    case CKM_IDEA_ECB:
+    case CKM_CAST_ECB:
+    case CKM_CAST3_ECB:
+    case CKM_CAST5_ECB:
+    case CKM_RC2_CBC:
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_DES_CBC:
+    case CKM_DES3_CBC:
+    case CKM_IDEA_CBC:
+    case CKM_CAST_CBC:
+    case CKM_CAST3_CBC:
+    case CKM_CAST5_CBC:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES3_CBC_PAD:
+    case CKM_RC2_CBC_PAD:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_PBE_MD2_DES_CBC:
+    case CKM_PBE_MD5_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
+    case CKM_PBE_SHA1_RC2_40_CBC:
+    case CKM_PBE_SHA1_RC2_128_CBC:
+    case CKM_PBE_SHA1_DES3_EDE_CBC:
+    case CKM_PBE_SHA1_DES2_EDE_CBC:
+	return 8;
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+	return 4;
+    case CKM_SEED_ECB:
+    case CKM_SEED_CBC:
+    case CKM_SEED_CBC_PAD:
+    case CKM_CAMELLIA_ECB:
+    case CKM_CAMELLIA_CBC:
+    case CKM_CAMELLIA_CBC_PAD:
+    case CKM_AES_ECB:
+    case CKM_AES_CBC:
+    case CKM_AES_CBC_PAD:
+    case CKM_BATON_ECB128:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+	return 16;
+    case CKM_BATON_ECB96:
+	return 12;
+    case CKM_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
+    case CKM_PBE_SHA1_RC4_40:
+    case CKM_PBE_SHA1_RC4_128:
+	return 0;
+    case CKM_RSA_PKCS:
+    case CKM_RSA_9796:
+    case CKM_RSA_X_509:
+	/*actually it's the modulus length of the key!*/
+	return -1;	/* failure */
+    default:
+	return pk11_lookup(type)->blockSize;
+    }
+}
+
+/*
+ * get the iv length
+ */
+int
+PK11_GetIVLength(CK_MECHANISM_TYPE type)
+{
+    switch (type) {
+    case CKM_SEED_ECB:
+    case CKM_CAMELLIA_ECB:
+    case CKM_AES_ECB:
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_RC2_ECB:
+    case CKM_IDEA_ECB:
+    case CKM_SKIPJACK_WRAP:
+    case CKM_BATON_WRAP:
+    case CKM_RC5_ECB:
+    case CKM_CAST_ECB:
+    case CKM_CAST3_ECB:
+    case CKM_CAST5_ECB:
+	return 0;
+    case CKM_RC2_CBC:
+    case CKM_DES_CBC:
+    case CKM_DES3_CBC:
+    case CKM_IDEA_CBC:
+    case CKM_PBE_MD2_DES_CBC:
+    case CKM_PBE_MD5_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
+    case CKM_PBE_SHA1_RC2_40_CBC:
+    case CKM_PBE_SHA1_RC2_128_CBC:
+    case CKM_PBE_SHA1_DES3_EDE_CBC:
+    case CKM_PBE_SHA1_DES2_EDE_CBC:
+    case CKM_RC5_CBC:
+    case CKM_CAST_CBC:
+    case CKM_CAST3_CBC:
+    case CKM_CAST5_CBC:
+    case CKM_RC2_CBC_PAD:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES3_CBC_PAD:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_RC5_CBC_PAD:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST5_CBC_PAD:
+	return 8;
+    case CKM_SEED_CBC:
+    case CKM_SEED_CBC_PAD:
+    case CKM_CAMELLIA_CBC:
+    case CKM_CAMELLIA_CBC_PAD:
+    case CKM_AES_CBC:
+    case CKM_AES_CBC_PAD:
+	return 16;
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+	return 24;
+    case CKM_RC4:
+    case CKM_RSA_PKCS:
+    case CKM_RSA_9796:
+    case CKM_RSA_X_509:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
+    case CKM_PBE_SHA1_RC4_40:
+    case CKM_PBE_SHA1_RC4_128:
+	return 0;
+    default:
+	return pk11_lookup(type)->iv;
+    }
+}
+
+
+/* These next two utilities are here to help facilitate future
+ * Dynamic Encrypt/Decrypt symetric key mechanisms, and to allow functions
+ * like SSL and S-MIME to automatically add them.
+ */
+SECItem *
+pk11_ParamFromIVWithLen(CK_MECHANISM_TYPE type, SECItem *iv, int keyLen)
+{
+    CK_RC2_CBC_PARAMS *rc2_params = NULL;
+    CK_RC2_PARAMS *rc2_ecb_params = NULL;
+    CK_RC5_PARAMS *rc5_params = NULL;
+    CK_RC5_CBC_PARAMS *rc5_cbc_params = NULL;
+    SECItem *param;
+
+    param = (SECItem *)PORT_Alloc(sizeof(SECItem));
+    if (param == NULL) return NULL;
+    param->data = NULL;
+    param->len = 0;
+    param->type = 0;
+    switch (type) {
+    case CKM_SEED_ECB:
+    case CKM_CAMELLIA_ECB:
+    case CKM_AES_ECB:
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_RSA_PKCS:
+    case CKM_RSA_X_509:
+    case CKM_RSA_9796:
+    case CKM_IDEA_ECB:
+    case CKM_CDMF_ECB:
+    case CKM_CAST_ECB:
+    case CKM_CAST3_ECB:
+    case CKM_CAST5_ECB:
+    case CKM_RC4:
+	break;
+    case CKM_RC2_ECB:
+	rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS));
+	if (rc2_ecb_params == NULL) break;
+	/*  Maybe we should pass the key size in too to get this value? */
+	*rc2_ecb_params = keyLen ? keyLen*8 : 128;
+	param->data = (unsigned char *) rc2_ecb_params;
+	param->len = sizeof(CK_RC2_PARAMS);
+	break;
+    case CKM_RC2_CBC:
+    case CKM_RC2_CBC_PAD:
+	rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS));
+	if (rc2_params == NULL) break;
+	/* Maybe we should pass the key size in too to get this value? */
+	rc2_params->ulEffectiveBits = keyLen ? keyLen*8 : 128;
+	if (iv && iv->data)
+	    PORT_Memcpy(rc2_params->iv,iv->data,sizeof(rc2_params->iv));
+	param->data = (unsigned char *) rc2_params;
+	param->len = sizeof(CK_RC2_CBC_PARAMS);
+	break;
+    case CKM_RC5_CBC:
+    case CKM_RC5_CBC_PAD:
+	rc5_cbc_params = (CK_RC5_CBC_PARAMS *)
+		PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + ((iv) ? iv->len : 0));
+	if (rc5_cbc_params == NULL) break;
+	if (iv && iv->data && iv->len) {
+	    rc5_cbc_params->pIv = ((CK_BYTE_PTR) rc5_cbc_params) 
+						+ sizeof(CK_RC5_CBC_PARAMS);
+	    PORT_Memcpy(rc5_cbc_params->pIv,iv->data,iv->len);
+	    rc5_cbc_params->ulIvLen = iv->len;
+	    rc5_cbc_params->ulWordsize = iv->len/2;
+	} else {
+	    rc5_cbc_params->ulWordsize = 4;
+	    rc5_cbc_params->pIv = NULL;
+	    rc5_cbc_params->ulIvLen = 0;
+	}
+	rc5_cbc_params->ulRounds = 16;
+	param->data = (unsigned char *) rc5_cbc_params;
+	param->len = sizeof(CK_RC5_CBC_PARAMS);
+	break;
+    case CKM_RC5_ECB:
+	rc5_params = (CK_RC5_PARAMS *)PORT_Alloc(sizeof(CK_RC5_PARAMS));
+	if (rc5_params == NULL) break;
+	if (iv && iv->data && iv->len) {
+	    rc5_params->ulWordsize = iv->len/2;
+	} else {
+	    rc5_params->ulWordsize = 4;
+	}
+	rc5_params->ulRounds = 16;
+	param->data = (unsigned char *) rc5_params;
+	param->len = sizeof(CK_RC5_PARAMS);
+	break;
+
+    case CKM_SEED_CBC:
+    case CKM_CAMELLIA_CBC:
+    case CKM_AES_CBC:
+    case CKM_DES_CBC:
+    case CKM_DES3_CBC:
+    case CKM_IDEA_CBC:
+    case CKM_CDMF_CBC:
+    case CKM_CAST_CBC:
+    case CKM_CAST3_CBC:
+    case CKM_CAST5_CBC:
+    case CKM_CAMELLIA_CBC_PAD:
+    case CKM_AES_CBC_PAD:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES3_CBC_PAD:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_CDMF_CBC_PAD:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+	if ((iv == NULL) || (iv->data == NULL)) break;
+	param->data = (unsigned char*)PORT_Alloc(iv->len);
+	if (param->data != NULL) {
+	    PORT_Memcpy(param->data,iv->data,iv->len);
+	    param->len = iv->len;
+	}
+	break;
+     /* unknown mechanism, pass IV in if it's there */
+     default:
+	if (pk11_lookup(type)->iv == 0) {
+	    break;
+	}
+	if ((iv == NULL) || (iv->data == NULL)) {
+	    break;
+	}
+	param->data = (unsigned char*)PORT_Alloc(iv->len);
+	if (param->data != NULL) {
+	    PORT_Memcpy(param->data,iv->data,iv->len);
+	    param->len = iv->len;
+	}
+	break;
+     }
+     return param;
+}
+
+/* These next two utilities are here to help facilitate future
+ * Dynamic Encrypt/Decrypt symetric key mechanisms, and to allow functions
+ * like SSL and S-MIME to automatically add them.
+ */
+SECItem *
+PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv)
+{
+    return pk11_ParamFromIVWithLen(type, iv, 0);
+}
+
+unsigned char *
+PK11_IVFromParam(CK_MECHANISM_TYPE type,SECItem *param,int *len)
+{
+    CK_RC2_CBC_PARAMS *rc2_params;
+    CK_RC5_CBC_PARAMS *rc5_cbc_params;
+
+    *len = 0;
+    switch (type) {
+    case CKM_SEED_ECB:
+    case CKM_CAMELLIA_ECB:
+    case CKM_AES_ECB:
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_RSA_PKCS:
+    case CKM_RSA_X_509:
+    case CKM_RSA_9796:
+    case CKM_IDEA_ECB:
+    case CKM_CDMF_ECB:
+    case CKM_CAST_ECB:
+    case CKM_CAST3_ECB:
+    case CKM_CAST5_ECB:
+    case CKM_RC4:
+	return NULL;
+    case CKM_RC2_ECB:
+	return NULL;
+    case CKM_RC2_CBC:
+    case CKM_RC2_CBC_PAD:
+	rc2_params = (CK_RC2_CBC_PARAMS *)param->data;
+        *len = sizeof(rc2_params->iv);
+	return &rc2_params->iv[0];
+    case CKM_RC5_CBC:
+    case CKM_RC5_CBC_PAD:
+	rc5_cbc_params = (CK_RC5_CBC_PARAMS *) param->data;
+	*len = rc5_cbc_params->ulIvLen;
+	return rc5_cbc_params->pIv;
+    case CKM_SEED_CBC:
+    case CKM_CAMELLIA_CBC:
+    case CKM_AES_CBC:
+    case CKM_DES_CBC:
+    case CKM_DES3_CBC:
+    case CKM_IDEA_CBC:
+    case CKM_CDMF_CBC:
+    case CKM_CAST_CBC:
+    case CKM_CAST3_CBC:
+    case CKM_CAST5_CBC:
+    case CKM_CAMELLIA_CBC_PAD:
+    case CKM_AES_CBC_PAD:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES3_CBC_PAD:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_CDMF_CBC_PAD:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+	break;
+     /* unknown mechanism, pass IV in if it's there */
+     default:
+	break;
+     }
+     if (param->data) {
+	*len = param->len;
+     }
+     return param->data;
+}
+
+typedef struct sec_rc5cbcParameterStr {
+    SECItem version;
+    SECItem rounds;
+    SECItem blockSizeInBits;
+    SECItem iv;
+} sec_rc5cbcParameter;
+
+static const SEC_ASN1Template sec_rc5ecb_parameter_template[] = {
+    { SEC_ASN1_SEQUENCE,
+          0, NULL, sizeof(sec_rc5cbcParameter) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc5cbcParameter,version) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc5cbcParameter,rounds) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc5cbcParameter,blockSizeInBits) },
+    { 0 }
+};
+
+static const SEC_ASN1Template sec_rc5cbc_parameter_template[] = {
+    { SEC_ASN1_SEQUENCE,
+          0, NULL, sizeof(sec_rc5cbcParameter) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc5cbcParameter,version) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc5cbcParameter,rounds) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc5cbcParameter,blockSizeInBits) },
+    { SEC_ASN1_OCTET_STRING,
+          offsetof(sec_rc5cbcParameter,iv) },
+    { 0 }
+};
+
+typedef struct sec_rc2cbcParameterStr {
+    SECItem rc2ParameterVersion;
+    SECItem iv;
+} sec_rc2cbcParameter;
+
+static const SEC_ASN1Template sec_rc2cbc_parameter_template[] = {
+    { SEC_ASN1_SEQUENCE,
+          0, NULL, sizeof(sec_rc2cbcParameter) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc2cbcParameter,rc2ParameterVersion) },
+    { SEC_ASN1_OCTET_STRING,
+          offsetof(sec_rc2cbcParameter,iv) },
+    { 0 }
+};
+
+static const SEC_ASN1Template sec_rc2ecb_parameter_template[] = {
+    { SEC_ASN1_SEQUENCE,
+          0, NULL, sizeof(sec_rc2cbcParameter) },
+    { SEC_ASN1_INTEGER,
+          offsetof(sec_rc2cbcParameter,rc2ParameterVersion) },
+    { 0 }
+};
+
+/* S/MIME picked id values to represent differnt keysizes */
+/* I do have a formula, but it ain't pretty, and it only works because you
+ * can always match three points to a parabola:) */
+static unsigned char  rc2_map(SECItem *version)
+{
+    long x;
+
+    x = DER_GetInteger(version);
+    
+    switch (x) {
+        case 58: return 128;
+        case 120: return 64;
+        case 160: return 40;
+    }
+    return 128; 
+}
+
+static unsigned long  rc2_unmap(unsigned long x)
+{
+    switch (x) {
+        case 128: return 58;
+        case 64: return 120;
+        case 40: return 160;
+    }
+    return 58; 
+}
+
+
+
+/* Generate a mechaism param from a type, and iv. */
+SECItem *
+PK11_ParamFromAlgid(SECAlgorithmID *algid)
+{
+    CK_RC2_CBC_PARAMS * rc2_cbc_params = NULL;
+    CK_RC2_PARAMS *     rc2_ecb_params = NULL;
+    CK_RC5_CBC_PARAMS * rc5_cbc_params = NULL;
+    CK_RC5_PARAMS *     rc5_ecb_params = NULL;
+    PRArenaPool *       arena          = NULL;
+    SECItem *           mech           = NULL;
+    SECOidTag           algtag;
+    SECStatus           rv;
+    CK_MECHANISM_TYPE   type;
+    /* initialize these to prevent UMRs in the ASN1 decoder. */
+    SECItem             iv  =   {siBuffer, NULL, 0};
+    sec_rc2cbcParameter rc2 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0} };
+    sec_rc5cbcParameter rc5 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0},
+                                {siBuffer, NULL, 0}, {siBuffer, NULL, 0} };
+
+    algtag = SECOID_GetAlgorithmTag(algid);
+    type = PK11_AlgtagToMechanism(algtag);
+
+    mech = PORT_New(SECItem);
+    if (mech == NULL) {
+    	return NULL;
+    }
+    mech->type = siBuffer;
+    mech->data = NULL;
+    mech->len  = 0;
+
+    arena = PORT_NewArena(1024);
+    if (!arena) {
+    	goto loser;
+    }
+
+    /* handle the complicated cases */
+    switch (type) {
+    case CKM_RC2_ECB:
+        rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2ecb_parameter_template,
+							&(algid->parameters));
+	if (rv != SECSuccess) { 
+	    goto loser;
+	}
+	rc2_ecb_params = PORT_New(CK_RC2_PARAMS);
+	if (rc2_ecb_params == NULL) {
+	    goto loser;
+	}
+	*rc2_ecb_params = rc2_map(&rc2.rc2ParameterVersion);
+	mech->data = (unsigned char *) rc2_ecb_params;
+	mech->len  = sizeof *rc2_ecb_params;
+	break;
+    case CKM_RC2_CBC:
+    case CKM_RC2_CBC_PAD:
+        rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2cbc_parameter_template,
+							&(algid->parameters));
+	if (rv != SECSuccess) { 
+	    goto loser;
+	}
+	rc2_cbc_params = PORT_New(CK_RC2_CBC_PARAMS);
+	if (rc2_cbc_params == NULL) {
+	    goto loser;
+	}
+	mech->data = (unsigned char *) rc2_cbc_params;
+	mech->len  = sizeof *rc2_cbc_params;
+	rc2_cbc_params->ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion);
+	if (rc2.iv.len != sizeof rc2_cbc_params->iv) {
+	    PORT_SetError(SEC_ERROR_INPUT_LEN);
+	    goto loser;
+	}
+	PORT_Memcpy(rc2_cbc_params->iv, rc2.iv.data, rc2.iv.len);
+	break;
+    case CKM_RC5_ECB:
+        rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5ecb_parameter_template,
+							&(algid->parameters));
+	if (rv != SECSuccess) { 
+	    goto loser;
+	}
+	rc5_ecb_params = PORT_New(CK_RC5_PARAMS);
+	if (rc5_ecb_params == NULL) {
+	    goto loser;
+	}
+	rc5_ecb_params->ulRounds   = DER_GetInteger(&rc5.rounds);
+	rc5_ecb_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8;
+	mech->data = (unsigned char *) rc5_ecb_params;
+	mech->len = sizeof *rc5_ecb_params;
+	break;
+    case CKM_RC5_CBC:
+    case CKM_RC5_CBC_PAD:
+        rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5cbc_parameter_template,
+							&(algid->parameters));
+	if (rv != SECSuccess) { 
+	    goto loser;
+	}
+	rc5_cbc_params = (CK_RC5_CBC_PARAMS *)
+		PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + rc5.iv.len);
+	if (rc5_cbc_params == NULL) {
+	    goto loser;
+	}
+	mech->data = (unsigned char *) rc5_cbc_params;
+	mech->len = sizeof *rc5_cbc_params;
+	rc5_cbc_params->ulRounds   = DER_GetInteger(&rc5.rounds);
+	rc5_cbc_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8;
+        rc5_cbc_params->pIv        = ((CK_BYTE_PTR)rc5_cbc_params)
+						+ sizeof(CK_RC5_CBC_PARAMS);
+        rc5_cbc_params->ulIvLen    = rc5.iv.len;
+	PORT_Memcpy(rc5_cbc_params->pIv, rc5.iv.data, rc5.iv.len);
+	break;
+    case CKM_PBE_MD2_DES_CBC:
+    case CKM_PBE_MD5_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
+    case CKM_PBE_SHA1_DES2_EDE_CBC:
+    case CKM_PBE_SHA1_DES3_EDE_CBC:
+    case CKM_PBE_SHA1_RC2_40_CBC:
+    case CKM_PBE_SHA1_RC2_128_CBC:
+    case CKM_PBE_SHA1_RC4_40:
+    case CKM_PBE_SHA1_RC4_128:
+    case CKM_PKCS5_PBKD2:
+	rv = pbe_PK11AlgidToParam(algid,mech);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+	break;
+    case CKM_RC4:
+    case CKM_SEED_ECB:
+    case CKM_CAMELLIA_ECB:
+    case CKM_AES_ECB:
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_IDEA_ECB:
+    case CKM_CDMF_ECB:
+    case CKM_CAST_ECB:
+    case CKM_CAST3_ECB:
+    case CKM_CAST5_ECB:
+	break;
+
+    default:
+	if (pk11_lookup(type)->iv == 0) {
+	    break;
+	}
+	/* FALL THROUGH */
+    case CKM_SEED_CBC:
+    case CKM_CAMELLIA_CBC:
+    case CKM_AES_CBC:
+    case CKM_DES_CBC:
+    case CKM_DES3_CBC:
+    case CKM_IDEA_CBC:
+    case CKM_CDMF_CBC:
+    case CKM_CAST_CBC:
+    case CKM_CAST3_CBC:
+    case CKM_CAST5_CBC:
+    case CKM_SEED_CBC_PAD:
+    case CKM_CAMELLIA_CBC_PAD:
+    case CKM_AES_CBC_PAD:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES3_CBC_PAD:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_CDMF_CBC_PAD:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+	/* simple cases are simply octet string encoded IVs */
+	rv = SEC_ASN1DecodeItem(arena, &iv,
+                                SEC_ASN1_GET(SEC_OctetStringTemplate),
+                                &(algid->parameters));
+	if (rv != SECSuccess || iv.data == NULL) {
+	    goto loser;
+	}
+	/* XXX Should be some IV length sanity check here. */
+	mech->data = (unsigned char*)PORT_Alloc(iv.len);
+	if (mech->data == NULL) {
+	    goto loser;
+	}
+	PORT_Memcpy(mech->data, iv.data, iv.len);
+	mech->len = iv.len;
+	break;
+    }
+    PORT_FreeArena(arena, PR_FALSE);
+    return mech;
+
+loser:
+    if (arena)
+    	PORT_FreeArena(arena, PR_FALSE);
+    SECITEM_FreeItem(mech,PR_TRUE);
+    return NULL;
+}
+
+/*
+ * Generate an IV for the given mechanism 
+ */
+static SECStatus
+pk11_GenIV(CK_MECHANISM_TYPE type, SECItem *iv) {
+    int iv_size = PK11_GetIVLength(type);
+    SECStatus rv;
+
+    iv->len = iv_size;
+    if (iv_size == 0) { 
+	iv->data = NULL;
+	return SECSuccess;
+    }
+
+    iv->data = (unsigned char *) PORT_Alloc(iv_size);
+    if (iv->data == NULL) {
+	iv->len = 0;
+	return SECFailure;
+    }
+
+    rv = PK11_GenerateRandom(iv->data,iv->len);
+    if (rv != SECSuccess) {
+	PORT_Free(iv->data);
+	iv->data = NULL; iv->len = 0;
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+/*
+ * create a new paramter block from the passed in MECHANISM and the
+ * key. Use Netscape's S/MIME Rules for the New param block.
+ */
+SECItem *
+pk11_GenerateNewParamWithKeyLen(CK_MECHANISM_TYPE type, int keyLen) 
+{ 
+    CK_RC2_CBC_PARAMS *rc2_params;
+    CK_RC2_PARAMS *rc2_ecb_params;
+    SECItem *mech;
+    SECItem iv;
+    SECStatus rv;
+
+
+    mech = (SECItem *) PORT_Alloc(sizeof(SECItem));
+    if (mech == NULL) return NULL;
+
+    rv = SECSuccess;
+    mech->type = siBuffer;
+    switch (type) {
+    case CKM_RC4:
+    case CKM_SEED_ECB:
+    case CKM_CAMELLIA_ECB:
+    case CKM_AES_ECB:
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_IDEA_ECB:
+    case CKM_CDMF_ECB:
+    case CKM_CAST_ECB:
+    case CKM_CAST3_ECB:
+    case CKM_CAST5_ECB:
+	mech->data = NULL;
+	mech->len = 0;
+	break;
+    case CKM_RC2_ECB:
+	rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS));
+	if (rc2_ecb_params == NULL) {
+	    rv = SECFailure;
+	    break;
+	}
+	/* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5,
+	 *   or RC4 key. Of course that wouldn't happen here doing RC2:).*/
+	*rc2_ecb_params = keyLen ? keyLen*8 : 128;
+	mech->data = (unsigned char *) rc2_ecb_params;
+	mech->len = sizeof(CK_RC2_PARAMS);
+	break;
+    case CKM_RC2_CBC:
+    case CKM_RC2_CBC_PAD:
+	rv = pk11_GenIV(type,&iv);
+	if (rv != SECSuccess) {
+	    break;
+	}
+	rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS));
+	if (rc2_params == NULL) {
+	    PORT_Free(iv.data);
+	    rv = SECFailure;
+	    break;
+	}
+	/* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5,
+	 *   or RC4 key. Of course that wouldn't happen here doing RC2:).*/
+	rc2_params->ulEffectiveBits = keyLen ? keyLen*8 : 128;
+	if (iv.data)
+	    PORT_Memcpy(rc2_params->iv,iv.data,sizeof(rc2_params->iv));
+	mech->data = (unsigned char *) rc2_params;
+	mech->len = sizeof(CK_RC2_CBC_PARAMS);
+	PORT_Free(iv.data);
+	break;
+    case CKM_RC5_ECB:
+        PORT_Free(mech);
+	return PK11_ParamFromIV(type,NULL);
+    case CKM_RC5_CBC:
+    case CKM_RC5_CBC_PAD:
+	rv = pk11_GenIV(type,&iv);
+	if (rv != SECSuccess) {
+	    break;
+	}
+        PORT_Free(mech);
+	return PK11_ParamFromIV(type,&iv);
+    default:
+	if (pk11_lookup(type)->iv == 0) {
+	    mech->data = NULL;
+	    mech->len = 0;
+	    break;
+	}
+    case CKM_SEED_CBC:
+    case CKM_CAMELLIA_CBC:
+    case CKM_AES_CBC:
+    case CKM_DES_CBC:
+    case CKM_DES3_CBC:
+    case CKM_IDEA_CBC:
+    case CKM_CDMF_CBC:
+    case CKM_CAST_CBC:
+    case CKM_CAST3_CBC:
+    case CKM_CAST5_CBC:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES3_CBC_PAD:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_CDMF_CBC_PAD:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+	rv = pk11_GenIV(type,&iv);
+	if (rv != SECSuccess) {
+	    break;
+	}
+	mech->data = (unsigned char*)PORT_Alloc(iv.len);
+	if (mech->data == NULL) {
+	    PORT_Free(iv.data);
+	    rv = SECFailure;
+	    break;
+	}
+	PORT_Memcpy(mech->data,iv.data,iv.len);
+	mech->len = iv.len;
+        PORT_Free(iv.data);
+	break;
+    }
+    if (rv !=  SECSuccess) {
+	SECITEM_FreeItem(mech,PR_TRUE);
+	return NULL;
+    }
+    return mech;
+
+}
+
+SECItem *
+PK11_GenerateNewParam(CK_MECHANISM_TYPE type, PK11SymKey *key) 
+{ 
+    int keyLen = key ? PK11_GetKeyLength(key) :  0;
+
+    return pk11_GenerateNewParamWithKeyLen(type, keyLen);
+}
+
+#define RC5_V10 0x10
+
+/* turn a PKCS #11 parameter into a DER Encoded Algorithm ID */
+SECStatus
+PK11_ParamToAlgid(SECOidTag algTag, SECItem *param, 
+				PRArenaPool *arena, SECAlgorithmID *algid) {
+    CK_RC2_CBC_PARAMS *rc2_params;
+    sec_rc2cbcParameter rc2;
+    CK_RC5_CBC_PARAMS *rc5_params;
+    sec_rc5cbcParameter rc5;
+    CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(algTag);
+    SECItem *newParams = NULL;
+    SECStatus rv = SECFailure;
+    unsigned long rc2version;
+
+    switch (type) {
+    case CKM_RC4:
+    case CKM_SEED_ECB:
+    case CKM_CAMELLIA_ECB:
+    case CKM_AES_ECB:
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_IDEA_ECB:
+    case CKM_CDMF_ECB:
+    case CKM_CAST_ECB:
+    case CKM_CAST3_ECB:
+    case CKM_CAST5_ECB:
+	newParams = NULL;
+	rv = SECSuccess;
+	break;
+    case CKM_RC2_ECB:
+	break;
+    case CKM_RC2_CBC:
+    case CKM_RC2_CBC_PAD:
+	rc2_params = (CK_RC2_CBC_PARAMS *)param->data;
+	rc2version = rc2_unmap(rc2_params->ulEffectiveBits);
+	if (SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion),
+					   rc2version) == NULL)
+	    break;
+	rc2.iv.data = rc2_params->iv;
+	rc2.iv.len = sizeof(rc2_params->iv);
+	newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc2,
+                                         sec_rc2cbc_parameter_template);
+        PORT_Free(rc2.rc2ParameterVersion.data);
+	if (newParams == NULL)
+	    break;
+	rv = SECSuccess;
+	break;
+
+    case CKM_RC5_ECB: /* well not really... */
+	break;
+    case CKM_RC5_CBC:
+    case CKM_RC5_CBC_PAD:
+	rc5_params = (CK_RC5_CBC_PARAMS *)param->data;
+	if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.version, RC5_V10) == NULL)
+	    break;
+	if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.blockSizeInBits, 
+					rc5_params->ulWordsize*8) == NULL) {
+            PORT_Free(rc5.version.data);
+	    break;
+	}
+	if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.rounds, 
+					rc5_params->ulWordsize*8) == NULL) {
+            PORT_Free(rc5.blockSizeInBits.data);
+            PORT_Free(rc5.version.data);
+	    break;
+	}
+	rc5.iv.data = rc5_params->pIv;
+	rc5.iv.len = rc5_params->ulIvLen;
+	newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc5,
+                                         sec_rc5cbc_parameter_template);
+        PORT_Free(rc5.version.data);
+        PORT_Free(rc5.blockSizeInBits.data);
+        PORT_Free(rc5.rounds.data);
+	if (newParams == NULL)
+	    break;
+	rv = SECSuccess;
+	break;
+    case CKM_PBE_MD2_DES_CBC:
+    case CKM_PBE_MD5_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
+    case CKM_PBE_SHA1_DES3_EDE_CBC:
+    case CKM_PBE_SHA1_DES2_EDE_CBC:
+    case CKM_PBE_SHA1_RC2_40_CBC:
+    case CKM_PBE_SHA1_RC2_128_CBC:
+    case CKM_PBE_SHA1_RC4_40:
+    case CKM_PBE_SHA1_RC4_128:
+	return PBE_PK11ParamToAlgid(algTag, param, arena, algid);
+    default:
+	if (pk11_lookup(type)->iv == 0) {
+	    rv = SECSuccess;
+	    newParams = NULL;
+	    break;
+	}
+    case CKM_SEED_CBC:
+    case CKM_CAMELLIA_CBC:
+    case CKM_AES_CBC:
+    case CKM_DES_CBC:
+    case CKM_DES3_CBC:
+    case CKM_IDEA_CBC:
+    case CKM_CDMF_CBC:
+    case CKM_CAST_CBC:
+    case CKM_CAST3_CBC:
+    case CKM_CAST5_CBC:
+    case CKM_DES_CBC_PAD:
+    case CKM_DES3_CBC_PAD:
+    case CKM_IDEA_CBC_PAD:
+    case CKM_CDMF_CBC_PAD:
+    case CKM_CAST_CBC_PAD:
+    case CKM_CAST3_CBC_PAD:
+    case CKM_CAST5_CBC_PAD:
+    case CKM_SKIPJACK_CBC64:
+    case CKM_SKIPJACK_ECB64:
+    case CKM_SKIPJACK_OFB64:
+    case CKM_SKIPJACK_CFB64:
+    case CKM_SKIPJACK_CFB32:
+    case CKM_SKIPJACK_CFB16:
+    case CKM_SKIPJACK_CFB8:
+    case CKM_BATON_ECB128:
+    case CKM_BATON_ECB96:
+    case CKM_BATON_CBC128:
+    case CKM_BATON_COUNTER:
+    case CKM_BATON_SHUFFLE:
+    case CKM_JUNIPER_ECB128:
+    case CKM_JUNIPER_CBC128:
+    case CKM_JUNIPER_COUNTER:
+    case CKM_JUNIPER_SHUFFLE:
+	newParams = SEC_ASN1EncodeItem(NULL,NULL,param,
+                                       SEC_ASN1_GET(SEC_OctetStringTemplate) );
+	if (newParams == NULL)
+	    break;
+	rv = SECSuccess;
+	break;
+    }
+
+    if (rv !=  SECSuccess) {
+	if (newParams) SECITEM_FreeItem(newParams,PR_TRUE);
+	return rv;
+    }
+
+    rv = SECOID_SetAlgorithmID(arena, algid, algTag, newParams);
+    SECITEM_FreeItem(newParams,PR_TRUE);
+    return rv;
+}
+
+/* turn an OID algorithm tag into a PKCS #11 mechanism. This allows us to
+ * map OID's directly into the PKCS #11 mechanism we want to call. We find
+ * this mapping in our standard OID table */
+CK_MECHANISM_TYPE
+PK11_AlgtagToMechanism(SECOidTag algTag) {
+    SECOidData *oid = SECOID_FindOIDByTag(algTag);
+
+    if (oid) return (CK_MECHANISM_TYPE) oid->mechanism;
+    return CKM_INVALID_MECHANISM;
+}
+
+/* turn a mechanism into an oid. */
+SECOidTag
+PK11_MechanismToAlgtag(CK_MECHANISM_TYPE type) {
+    SECOidData *oid = SECOID_FindOIDByMechanism((unsigned long)type);
+
+    if (oid) return oid->offset;
+    return SEC_OID_UNKNOWN;
+}
+
+/* Determine appropriate blocking mechanism, used when wrapping private keys
+ * which require PKCS padding.  If the mechanism does not map to a padding
+ * mechanism, we simply return the mechanism.
+ */
+CK_MECHANISM_TYPE
+PK11_GetPadMechanism(CK_MECHANISM_TYPE type) {
+    switch(type) {
+	case CKM_SEED_CBC:
+	    return CKM_SEED_CBC_PAD;
+	case CKM_CAMELLIA_CBC:
+	    return CKM_CAMELLIA_CBC_PAD;
+	case CKM_AES_CBC:
+	    return CKM_AES_CBC_PAD;
+	case CKM_DES_CBC:
+	    return CKM_DES_CBC_PAD;
+	case CKM_DES3_CBC:
+	    return CKM_DES3_CBC_PAD;
+	case CKM_RC2_CBC:
+	    return CKM_RC2_CBC_PAD;
+	case CKM_CDMF_CBC:
+	    return CKM_CDMF_CBC_PAD;
+	case CKM_CAST_CBC:
+	    return CKM_CAST_CBC_PAD;
+	case CKM_CAST3_CBC:
+	    return CKM_CAST3_CBC_PAD;
+	case CKM_CAST5_CBC:
+	    return CKM_CAST5_CBC_PAD;
+	case CKM_RC5_CBC:
+	    return CKM_RC5_CBC_PAD; 
+	case CKM_IDEA_CBC:
+	    return CKM_IDEA_CBC_PAD; 
+	default:
+	    break;
+    }
+
+    return type;
+}
+	    
+static PRBool
+pk11_isAllZero(unsigned char *data,int len) {
+    while (len--) {
+	if (*data++) {
+	    return PR_FALSE;
+	}
+    }
+    return PR_TRUE;
+}
+
+CK_RV
+PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism, 
+				      CK_MECHANISM_PTR pCryptoMechanism,
+				      SECItem *pbe_pwd, PRBool faulty3DES)
+{
+    int iv_len = 0;
+    CK_PBE_PARAMS_PTR pPBEparams;
+    CK_RC2_CBC_PARAMS_PTR rc2_params;
+    CK_ULONG rc2_key_len;
+
+    if((pPBEMechanism == CK_NULL_PTR) || (pCryptoMechanism == CK_NULL_PTR)) {
+	return CKR_HOST_MEMORY;
+    }
+
+    /* pkcs5 v2 cannot be supported by this interface.
+     * use PK11_GetPBECryptoMechanism instead.
+     */
+    if ((pPBEMechanism->mechanism == CKM_INVALID_MECHANISM) || 
+	(pPBEMechanism->mechanism == CKM_PKCS5_PBKD2)) {
+	return CKR_MECHANISM_INVALID;
+    }
+
+    pPBEparams = (CK_PBE_PARAMS_PTR)pPBEMechanism->pParameter;
+    iv_len = PK11_GetIVLength(pPBEMechanism->mechanism);
+
+    if (iv_len) {
+	if (pk11_isAllZero(pPBEparams->pInitVector,iv_len)) {
+	    SECItem param;
+	    PK11SymKey *symKey;
+	    PK11SlotInfo *intSlot = PK11_GetInternalSlot();
+
+	    if (intSlot == NULL) {
+		return CKR_DEVICE_ERROR;
+	    }
+
+	    param.data = pPBEMechanism->pParameter;
+	    param.len = pPBEMechanism->ulParameterLen;
+
+	    symKey = PK11_RawPBEKeyGen(intSlot,
+		pPBEMechanism->mechanism, &param, pbe_pwd, faulty3DES, NULL);
+	    PK11_FreeSlot(intSlot);
+	    if (symKey== NULL) {
+		return CKR_DEVICE_ERROR; /* sigh */
+	    }
+	    PK11_FreeSymKey(symKey);
+	}
+    }
+
+    switch(pPBEMechanism->mechanism) {
+	case CKM_PBE_MD2_DES_CBC:
+	case CKM_PBE_MD5_DES_CBC:
+	case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
+	    pCryptoMechanism->mechanism = CKM_DES_CBC;
+	    goto have_crypto_mechanism;
+	case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
+	case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
+	case CKM_PBE_SHA1_DES3_EDE_CBC:
+	case CKM_PBE_SHA1_DES2_EDE_CBC:
+	    pCryptoMechanism->mechanism = CKM_DES3_CBC;
+have_crypto_mechanism:
+	    pCryptoMechanism->pParameter = PORT_Alloc(iv_len);
+	    pCryptoMechanism->ulParameterLen = (CK_ULONG)iv_len;
+	    if(pCryptoMechanism->pParameter == NULL) {
+		return CKR_HOST_MEMORY;
+	    }
+	    PORT_Memcpy((unsigned char *)(pCryptoMechanism->pParameter),
+			(unsigned char *)(pPBEparams->pInitVector),
+			iv_len);
+	    break;
+	case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
+	case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
+	case CKM_PBE_SHA1_RC4_40:
+	case CKM_PBE_SHA1_RC4_128:
+	    pCryptoMechanism->mechanism = CKM_RC4;
+	    pCryptoMechanism->ulParameterLen = 0;
+	    pCryptoMechanism->pParameter = CK_NULL_PTR;
+	    break;
+	case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
+	case CKM_PBE_SHA1_RC2_40_CBC:
+	    rc2_key_len = 40;
+	    goto have_key_len;
+	case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
+	    rc2_key_len = 128;
+have_key_len:
+	    pCryptoMechanism->mechanism = CKM_RC2_CBC;
+	    pCryptoMechanism->ulParameterLen = (CK_ULONG)
+						sizeof(CK_RC2_CBC_PARAMS);
+	    pCryptoMechanism->pParameter = (CK_RC2_CBC_PARAMS_PTR)
+				PORT_ZAlloc(sizeof(CK_RC2_CBC_PARAMS));
+	    if(pCryptoMechanism->pParameter == NULL) {
+		return CKR_HOST_MEMORY;
+	    }
+	    rc2_params = (CK_RC2_CBC_PARAMS_PTR)pCryptoMechanism->pParameter;
+	    PORT_Memcpy((unsigned char *)rc2_params->iv,
+	    		(unsigned char *)pPBEparams->pInitVector,
+	    		iv_len);
+	    rc2_params->ulEffectiveBits = rc2_key_len;
+	    break;
+	default:
+	    return CKR_MECHANISM_INVALID;
+    }
+
+    return CKR_OK;
+}
+
+/* Make a Key type to an appropriate signing/verification mechanism */
+CK_MECHANISM_TYPE
+PK11_MapSignKeyType(KeyType keyType)
+{
+    switch (keyType) {
+    case rsaKey:
+	return CKM_RSA_PKCS;
+    case fortezzaKey:
+    case dsaKey:
+	return CKM_DSA;
+    case ecKey:
+	return CKM_ECDSA;
+    case dhKey:
+    default:
+	break;
+    }
+    return CKM_INVALID_MECHANISM;
+}
+
+CK_MECHANISM_TYPE
+pk11_mapWrapKeyType(KeyType keyType)
+{
+    switch (keyType) {
+    case rsaKey:
+	return CKM_RSA_PKCS;
+    /* Add fortezza?? */
+    default:
+	break;
+    }
+    return CKM_INVALID_MECHANISM;
+}
+
+SECOidTag 
+PK11_FortezzaMapSig(SECOidTag algTag)
+{
+    switch (algTag) {
+    case SEC_OID_MISSI_KEA_DSS:
+    case SEC_OID_MISSI_DSS:
+    case SEC_OID_MISSI_DSS_OLD:
+    case SEC_OID_MISSI_KEA_DSS_OLD:
+    case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
+	return SEC_OID_ANSIX9_DSA_SIGNATURE;
+    default:
+	break;
+    }
+    return algTag;
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11merge.c b/mozilla/security/nss/lib/pk11wrap/pk11merge.c
new file mode 100644
index 0000000..8279c21
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11merge.c
@@ -0,0 +1,1415 @@
+/*
+ * Merge the source token into the target token.
+ */
+
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pk11pub.h"
+#include "pk11priv.h"
+#include "pkcs11.h"
+#include "seccomon.h"
+#include "secerr.h"
+#include "keyhi.h"
+#include "hasht.h"
+#include "cert.h"
+#include "certdb.h"
+
+/*************************************************************************
+ *
+ *             short utilities to aid in the merge
+ *
+ *************************************************************************/
+
+/*
+ * write a bunch of attributes out to an existing object.
+ */
+static SECStatus
+pk11_setAttributes(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
+		CK_ATTRIBUTE *setTemplate, CK_ULONG setTemplCount)
+{
+    CK_RV crv;
+    CK_SESSION_HANDLE rwsession;
+
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+    	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
+			setTemplate, setTemplCount);
+    PK11_RestoreROSession(slot, rwsession);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+/*
+ * copy a template of attributes from a source object to a target object.
+ * if target object is not given, create it.
+ */
+static SECStatus
+pk11_copyAttributes(PRArenaPool *arena, 
+	PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID,
+	PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID,
+	CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount)
+{
+    SECStatus rv = PK11_GetAttributes(arena, sourceSlot, sourceID, 
+				copyTemplate, copyTemplateCount);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    if (targetID == CK_INVALID_HANDLE) {
+	/* we need to create the object */
+	rv = PK11_CreateNewObject(targetSlot, CK_INVALID_SESSION, 
+		copyTemplate, copyTemplateCount, PR_TRUE, &targetID);
+    } else {
+	/* update the existing object with the new attributes */
+	rv = pk11_setAttributes(targetSlot, targetID, 
+			copyTemplate, copyTemplateCount);
+    }
+    return rv;
+}
+
+/*
+ * look for a matching object across tokens.
+ */
+static SECStatus
+pk11_matchAcrossTokens(PRArenaPool *arena, PK11SlotInfo *targetSlot, 
+		       PK11SlotInfo *sourceSlot,
+		       CK_ATTRIBUTE *template, CK_ULONG tsize, 
+		       CK_OBJECT_HANDLE id, CK_OBJECT_HANDLE *peer)
+{
+
+    CK_RV crv;
+    *peer = CK_INVALID_HANDLE;
+
+    crv = PK11_GetAttributes(arena, sourceSlot, id, template, tsize);
+    if (crv != CKR_OK) {
+ 	PORT_SetError( PK11_MapError(crv) );
+	goto loser;
+    }
+
+    if (template[0].ulValueLen == -1) {
+	crv = CKR_ATTRIBUTE_TYPE_INVALID;
+ 	PORT_SetError( PK11_MapError(crv) );
+	goto loser;
+    }
+
+    *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize);
+    return SECSuccess;
+
+loser:
+    return SECFailure;
+}
+
+/*
+ * Encrypt using key and parameters
+ */
+SECStatus
+pk11_encrypt(PK11SymKey *symKey, CK_MECHANISM_TYPE mechType, SECItem *param,
+	SECItem *input, SECItem **output)
+{
+    PK11Context *ctxt = NULL;
+    SECStatus rv = SECSuccess;
+
+    if (*output) {
+	SECITEM_FreeItem(*output,PR_TRUE);
+    }
+    *output = SECITEM_AllocItem(NULL, NULL, input->len+20 /*slop*/);
+    if (!*output) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    ctxt = PK11_CreateContextBySymKey(mechType, CKA_ENCRYPT, symKey, param);
+    if (ctxt == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    rv = PK11_CipherOp(ctxt, (*output)->data, 
+		(int *)&((*output)->len), 
+		(*output)->len, input->data, input->len);
+
+done:
+    if (ctxt) {
+	PK11_Finalize(ctxt);
+	PK11_DestroyContext(ctxt,PR_TRUE);
+    }
+    if (rv != SECSuccess) {
+	if (*output) {
+	    SECITEM_FreeItem(*output, PR_TRUE);
+	    *output = NULL;
+	}
+    }
+    return rv;
+}
+
+
+
+/*************************************************************************
+ *
+ *            Private Keys
+ *
+ *************************************************************************/
+
+/*
+ * Fetch the key usage based on the pkcs #11 flags
+ */
+unsigned int
+pk11_getPrivateKeyUsage(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
+{
+    unsigned int usage = 0;
+
+    if ((PK11_HasAttributeSet(slot, id, CKA_UNWRAP) || 
+			PK11_HasAttributeSet(slot,id, CKA_DECRYPT))) {
+	usage |= KU_KEY_ENCIPHERMENT;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE)) {
+	usage |= KU_KEY_AGREEMENT;
+    }
+    if ((PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER) || 
+			PK11_HasAttributeSet(slot, id, CKA_SIGN))) {
+	usage |= KU_DIGITAL_SIGNATURE;
+    }
+    return usage;
+}
+    
+	
+/*
+ * merge a private key, 
+ *
+ * Private keys are merged using PBE wrapped keys with a random
+ * value as the 'password'. Once the base key is moved, The remaining
+ * attributes (SUBJECT) is copied.
+ */
+static SECStatus
+pk11_mergePrivateKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+    SECKEYPrivateKey *sourceKey = NULL;
+    CK_OBJECT_HANDLE targetKeyID;
+    SECKEYEncryptedPrivateKeyInfo *epki = NULL;
+    char *nickname = NULL;
+    SECItem nickItem;
+    SECItem pwitem;
+    SECItem publicValue;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+    unsigned int keyUsage;
+    unsigned char randomData[SHA1_LENGTH];
+    SECOidTag algTag = SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC;
+    CK_ATTRIBUTE privTemplate[] = {
+	{ CKA_ID, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 }
+    };
+    CK_ULONG privTemplateCount = sizeof(privTemplate)/sizeof(privTemplate[0]);
+    CK_ATTRIBUTE privCopyTemplate[] = {
+	{ CKA_SUBJECT, NULL, 0 }
+    };
+    CK_ULONG privCopyTemplateCount = 
+		sizeof(privCopyTemplate)/sizeof(privCopyTemplate[0]);
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* check to see if the key is already in the target slot */
+    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, 
+				privTemplateCount, id, &targetKeyID);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    if (targetKeyID != CK_INVALID_HANDLE) {
+	/* match found,  not an error ... */
+	goto done;
+    }
+
+    /* get an NSS representation of our source key */
+    sourceKey = PK11_MakePrivKey(sourceSlot, nullKey, PR_FALSE, 
+				 id, sourcePwArg);
+    if (sourceKey == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* Load the private key */
+    /* generate a random pwitem */
+    rv = PK11_GenerateRandom(randomData, sizeof(randomData));
+    if (rv != SECSuccess) {
+	goto done;
+    }
+    pwitem.data = randomData;
+    pwitem.len = sizeof(randomData);
+    /* fetch the private key encrypted */
+    epki = PK11_ExportEncryptedPrivKeyInfo(sourceSlot, algTag, &pwitem, 
+					   sourceKey, 1, sourcePwArg);
+    if (epki == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+    nickname = PK11_GetObjectNickname(sourceSlot, id);
+    /* NULL nickanme is fine (in fact is often normal) */
+    if (nickname)  {
+	nickItem.data = (unsigned char *)nickname;
+	nickItem.len = PORT_Strlen(nickname);
+    }
+    keyUsage = pk11_getPrivateKeyUsage(sourceSlot, id);
+    /* pass in the CKA_ID */
+    publicValue.data = privTemplate[0].pValue;
+    publicValue.len = privTemplate[0].ulValueLen;
+    rv = PK11_ImportEncryptedPrivateKeyInfo(targetSlot, epki, &pwitem,
+			nickname? &nickItem : NULL , &publicValue, 
+			PR_TRUE, PR_TRUE, sourceKey->keyType, keyUsage, 
+			targetPwArg);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    /* make sure it made it */
+    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, 
+				privTemplateCount, id, &targetKeyID);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    if (targetKeyID == CK_INVALID_HANDLE) {
+	/* this time the key should exist */
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* fill in remaining attributes */
+    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id,
+				privCopyTemplate, privCopyTemplateCount);
+done:
+    /* make sure the 'key' is cleared */
+    PORT_Memset(randomData, 0, sizeof(randomData));
+    if (nickname) {
+	PORT_Free(nickname);
+    }
+    if (sourceKey) {
+	SECKEY_DestroyPrivateKey(sourceKey);
+    }
+    if (epki) {
+	SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
+    }
+    if (arena) {
+         PORT_FreeArena(arena,PR_FALSE);
+    }
+    return rv;
+}
+
+
+/*************************************************************************
+ *
+ *            Secret Keys
+ *
+ *************************************************************************/
+
+/*
+ * we need to find a unique CKA_ID.
+ *  The basic idea is to just increment the lowest byte.
+ *  This code also handles the following corner cases:
+ *   1) the single byte overflows. On overflow we increment the next byte up 
+ *    and so forth until we have overflowed the entire CKA_ID.
+ *   2) If we overflow the entire CKA_ID we expand it by one byte.
+ *   3) the CKA_ID is non-existant, we create a new one with one byte.
+ *    This means no matter what CKA_ID is passed, the result of this function 
+ *    is always a new CKA_ID, and this function will never return the same 
+ *    CKA_ID the it has returned in the passed.
+ */
+static SECStatus
+pk11_incrementID(PRArenaPool *arena, CK_ATTRIBUTE *ptemplate)
+{
+    unsigned char *buf = ptemplate->pValue;
+    CK_ULONG len = ptemplate->ulValueLen;
+
+    if (buf == NULL || len == (CK_ULONG)-1) {
+	/* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
+	len = 0;
+    } else {
+	CK_ULONG i;
+
+	/* walk from the back to front, incrementing
+	 * the CKA_ID until we no longer have a carry,
+	 * or have hit the front of the id. */
+	for (i=len; i != 0; i--) {
+	    buf[i-1]++;
+	    if (buf[i-1] != 0) {
+		/* no more carries, the increment is complete */
+		return SECSuccess;
+	     }
+	}
+	/* we've now overflowed, fall through and expand the CKA_ID by 
+	 * one byte */
+    } 
+    /* if we are here we've run the counter to zero (indicating an overflow).
+     * create an CKA_ID that is all zeros, but has one more zero than
+     * the previous CKA_ID */
+    buf = PORT_ArenaZAlloc(arena, len+1);
+    if (buf == NULL) {
+	return SECFailure;
+    }
+    ptemplate->pValue = buf;
+    ptemplate->ulValueLen = len+1;
+    return SECSuccess;
+}
+
+
+static CK_FLAGS
+pk11_getSecretKeyFlags(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
+{
+    CK_FLAGS flags = 0;
+
+    if (PK11_HasAttributeSet(slot, id, CKA_UNWRAP)) {
+	flags |= CKF_UNWRAP;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_WRAP)) {
+	flags |= CKF_WRAP;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_ENCRYPT)) {
+	flags |= CKF_ENCRYPT;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_DECRYPT)) {
+	flags |= CKF_DECRYPT;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE)) {
+	flags |= CKF_DERIVE;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_SIGN)) {
+	flags |= CKF_SIGN;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER)) {
+	flags |= CKF_SIGN_RECOVER;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY)) {
+	flags |= CKF_VERIFY;
+    }
+    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY_RECOVER)) {
+	flags |= CKF_VERIFY_RECOVER;
+    }
+    return flags;
+}
+
+static const char testString[] = 
+	"My Encrytion Test Data (should be at least 32 bytes long)";
+/*
+ * merge a secret key, 
+ *
+ * Secret keys may collide by CKA_ID as we merge 2 token. If we collide
+ * on the CKA_ID, we need to make sure we are dealing with different keys.
+ * The reason for this is it is possible that we've merged this database
+ * before, and this key could have been merged already.  If the keys are
+ * the same, we are done. If they are not, we need to update the CKA_ID of
+ * the source key and try again.
+ * 
+ * Once we know we have a unique key to merge in, we use NSS's underlying
+ * key Move function which will do a key exchange if necessary to move
+ * the key from one token to another. Then we set the CKA_ID and additional
+ * pkcs #11 attributes.
+ */
+static SECStatus
+pk11_mergeSecretKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+    PK11SymKey *sourceKey = NULL;
+    PK11SymKey *targetKey = NULL;
+    SECItem *sourceOutput = NULL;
+    SECItem *targetOutput = NULL;
+    SECItem *param = NULL;
+    SECItem input;
+    CK_OBJECT_HANDLE targetKeyID;
+    CK_FLAGS flags;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+    CK_MECHANISM_TYPE keyMechType, cryptoMechType;
+    CK_KEY_TYPE sourceKeyType, targetKeyType;
+    CK_ATTRIBUTE symTemplate[] = {
+	{ CKA_ID, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 }
+    };
+    CK_ULONG symTemplateCount = sizeof(symTemplate)/sizeof(symTemplate[0]);
+    CK_ATTRIBUTE symCopyTemplate[] = {
+	{ CKA_LABEL, NULL, 0 }
+    };
+    CK_ULONG symCopyTemplateCount = 
+		sizeof(symCopyTemplate)/sizeof(symCopyTemplate[0]);
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    sourceKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE);
+    if (sourceKeyType == (CK_ULONG) -1) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* get the key mechanism */
+    keyMechType = PK11_GetKeyMechanism(sourceKeyType);
+    /* get a mechanism suitable to encryption.
+     * PK11_GetKeyMechanism returns a mechanism that is unique to the key
+     * type. It tries to return encryption/decryption mechanisms, however
+     * CKM_DES3_CBC uses and abmiguous keyType, so keyMechType is returned as
+     * 'keygen' mechanism. Detect that case here */
+    cryptoMechType =  keyMechType;
+    if ((keyMechType == CKM_DES3_KEY_GEN) ||  
+				(keyMechType == CKM_DES2_KEY_GEN)) {
+	cryptoMechType = CKM_DES3_CBC;
+    }
+
+    sourceKey = PK11_SymKeyFromHandle(sourceSlot, NULL, PK11_OriginDerive,
+				keyMechType , id, PR_FALSE, sourcePwArg);
+    if (sourceKey == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* check to see a key with the same CKA_ID  already exists in 
+     * the target slot. If it does, then we need to verify if the keys
+     * really matches. If they don't import the key with a new CKA_ID
+     * value. */
+    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot,
+			symTemplate, symTemplateCount, id, &targetKeyID);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    /* set up the input test */
+    input.data = (unsigned char *)testString;
+    input.len = PK11_GetBlockSize(cryptoMechType, NULL);
+    if (input.len < 0) {
+	rv = SECFailure;
+	goto done;
+    }
+    if (input.len == 0) {
+	input.len = sizeof (testString);
+    }
+    while (targetKeyID != CK_INVALID_HANDLE) {
+	/* test to see if the keys are identical */
+	targetKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE);
+	if (targetKeyType == sourceKeyType) {
+		/* same keyType  - see if it's the same key */
+		targetKey = PK11_SymKeyFromHandle(targetSlot, NULL, 
+			PK11_OriginDerive, keyMechType, targetKeyID, PR_FALSE,
+			targetPwArg);
+		/* get a parameter if we don't already have one */
+		if (!param) {
+		    param = PK11_GenerateNewParam(cryptoMechType, sourceKey);
+		    if (param == NULL) {
+			rv = SECFailure;
+			goto done;
+		    }
+		}
+		/* use the source key to encrypt a reference */
+		if (!sourceOutput) {
+		    rv = pk11_encrypt(sourceKey, cryptoMechType, param, &input,
+			&sourceOutput);
+		    if (rv != SECSuccess) {
+			goto done;
+		    }
+		}
+		/* encrypt the reference with the target key */
+		rv = pk11_encrypt(targetKey, cryptoMechType, param, &input,
+			&targetOutput);
+		if (rv == SECSuccess) {
+		    if (SECITEM_ItemsAreEqual(sourceOutput, targetOutput)) {
+			/* they produce the same output, they must be the
+			 * same key */
+			goto done;
+		    }
+		    SECITEM_FreeItem(targetOutput, PR_TRUE);
+		    targetOutput = NULL;
+		}
+		PK11_FreeSymKey(targetKey);
+		targetKey = NULL;
+	}
+	/* keys aren't equal, update the KEY_ID and look again */
+	rv = pk11_incrementID(arena, &symTemplate[0]);
+	if (rv != SECSuccess) {
+	    goto done;
+	}
+	targetKeyID = pk11_FindObjectByTemplate(targetSlot, 
+					symTemplate, symTemplateCount);
+    }
+
+    /* we didn't find a matching key, import this one with the new
+     * CKAID */
+    flags = pk11_getSecretKeyFlags(sourceSlot, id);
+    targetKey = PK11_MoveSymKey(targetSlot, PK11_OriginDerive, flags, PR_TRUE,
+			sourceKey);
+    if (targetKey == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+    /* set the key new CKAID */
+    rv = pk11_setAttributes(targetSlot, targetKey->objectID, symTemplate, 1);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    /* fill in remaining attributes */
+    rv = pk11_copyAttributes(arena, targetSlot, targetKey->objectID, 
+			sourceSlot, id, symCopyTemplate, symCopyTemplateCount);
+done:
+    if (sourceKey) {
+	PK11_FreeSymKey(sourceKey);
+    }
+    if (targetKey) {
+	PK11_FreeSymKey(targetKey);
+    }
+    if (sourceOutput) {
+	SECITEM_FreeItem(sourceOutput, PR_TRUE);
+    }
+    if (targetOutput) {
+	SECITEM_FreeItem(targetOutput, PR_TRUE);
+    }
+    if (param) {
+	SECITEM_FreeItem(param, PR_TRUE);
+    }
+    if (arena) {
+         PORT_FreeArena(arena,PR_FALSE);
+    }
+    return rv;
+}
+
+/*************************************************************************
+ *
+ *            Public Keys
+ *
+ *************************************************************************/
+
+/*
+ * Merge public key
+ *
+ * Use the high level NSS calls to extract the public key and import it
+ * into the token. Extra attributes are then copied to the new token.
+ */
+static SECStatus
+pk11_mergePublicKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+    SECKEYPublicKey *sourceKey = NULL;
+    CK_OBJECT_HANDLE targetKeyID;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+    CK_ATTRIBUTE pubTemplate[] = {
+	{ CKA_ID, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 }
+    };
+    CK_ULONG pubTemplateCount = sizeof(pubTemplate)/sizeof(pubTemplate[0]);
+    CK_ATTRIBUTE pubCopyTemplate[] = {
+	{ CKA_ID, NULL, 0 },
+	{ CKA_LABEL, NULL, 0 },
+	{ CKA_SUBJECT, NULL, 0 }
+    };
+    CK_ULONG pubCopyTemplateCount = 
+		sizeof(pubCopyTemplate)/sizeof(pubCopyTemplate[0]);
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+
+    /* check to see if the key is already in the target slot */
+    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, pubTemplate, 
+				pubTemplateCount, id, &targetKeyID);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    /* Key is already in the target slot */
+    if (targetKeyID != CK_INVALID_HANDLE) {
+	/* not an error ... */
+	goto done;
+    }
+
+    /* fetch an NSS representation of the public key */
+    sourceKey = PK11_ExtractPublicKey(sourceSlot, nullKey, id);
+    if (sourceKey== NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* load the public key into the target token. */
+    targetKeyID = PK11_ImportPublicKey(targetSlot, sourceKey, PR_TRUE);
+    if (targetKeyID == CK_INVALID_HANDLE) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* fill in remaining attributes */
+    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id,
+				pubCopyTemplate, pubCopyTemplateCount);
+
+
+done:
+    if (sourceKey) {
+	SECKEY_DestroyPublicKey(sourceKey);
+    }
+    if (arena) {
+         PORT_FreeArena(arena,PR_FALSE);
+    }
+    return rv;
+}
+
+/*************************************************************************
+ *
+ *            Certificates
+ *
+ *************************************************************************/
+
+/*
+ * Two copies of the source code for this algorithm exist in NSS.  
+ * Changes must be made in both copies.
+ * The other copy is in sftkdb_resolveConflicts() in softoken/sftkdb.c.
+ */
+static char *
+pk11_IncrementNickname(char *nickname)
+{
+    char *newNickname = NULL;
+    int end;
+    int digit;
+    int len = strlen(nickname);
+
+    /* does nickname end with " #n*" ? */
+    for (end = len - 1; 
+         end >= 2 && (digit = nickname[end]) <= '9' &&  digit >= '0'; 
+	 end--)  /* just scan */ ;
+    if (len >= 3 &&
+        end < (len - 1) /* at least one digit */ &&
+	nickname[end]     == '#'  && 
+	nickname[end - 1] == ' ') {
+    	/* Already has a suitable suffix string */
+    } else {
+	/* ... append " #2" to the name */
+	static const char num2[] = " #2";
+	newNickname = PORT_Realloc(nickname, len + sizeof(num2));
+	if (newNickname) {
+	    PORT_Strcat(newNickname, num2);
+	} else {
+	    PORT_Free(nickname);
+	}
+	return newNickname;
+    }
+
+    for (end = len - 1; 
+	 end >= 0 && (digit = nickname[end]) <= '9' &&  digit >= '0'; 
+	 end--) {
+	if (digit < '9') {
+	    nickname[end]++;
+	    return nickname;
+	}
+	nickname[end] = '0';
+    }
+
+    /* we overflowed, insert a new '1' for a carry in front of the number */
+    newNickname = PORT_Realloc(nickname, len + 2);
+    if (newNickname) {
+	newNickname[++end] = '1';
+	PORT_Memset(&newNickname[end + 1], '0', len - end);
+	newNickname[len + 1] = 0;
+    } else {
+	PORT_Free(nickname);
+    }
+    return newNickname;
+}
+
+/*
+ * merge a certificate object
+ *
+ * Use the high level NSS calls to extract and import the certificate.
+ */
+static SECStatus
+pk11_mergeCert(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+    CERTCertificate *sourceCert = NULL;
+    CK_OBJECT_HANDLE targetCertID = CK_INVALID_HANDLE;
+    char *nickname = NULL;
+    SECStatus rv = SECSuccess;
+    PRArenaPool *arena = NULL;
+    CK_ATTRIBUTE sourceCKAID = {CKA_ID, NULL, 0};
+    CK_ATTRIBUTE targetCKAID = {CKA_ID, NULL, 0};
+    SECStatus lrv = SECSuccess;
+    int error;
+
+
+    sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL);
+    if (sourceCert == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    nickname = PK11_GetObjectNickname(sourceSlot, id);
+
+    /* The database code will prevent nickname collisions for certs with
+     * different subjects. This code will prevent us from getting
+     * actual import errors */
+    if (nickname) {
+	const char *tokenName = PK11_GetTokenName(targetSlot);
+	char *tokenNickname = NULL;
+
+	do {
+	    tokenNickname = PR_smprintf("%s:%s",tokenName, nickname);
+	    if (!tokenNickname) {
+		break;
+	    }
+	    if (!SEC_CertNicknameConflict(tokenNickname, 
+			&sourceCert->derSubject, CERT_GetDefaultCertDB())) {
+		break;
+	     }
+	    nickname = pk11_IncrementNickname(nickname);
+	    if (!nickname) {
+		break;
+	    }
+	    PR_smprintf_free(tokenNickname);
+	} while (1);
+	if (tokenNickname) {
+	    PR_smprintf_free(tokenNickname);
+	}
+    }
+
+	
+
+    /* see if the cert is already there */
+    targetCertID = PK11_FindCertInSlot(targetSlot, sourceCert, targetPwArg);
+    if (targetCertID == CK_INVALID_HANDLE) {
+	/* cert doesn't exist load the cert in. */
+	/* OK for the nickname to be NULL, not all certs have nicknames */
+	rv = PK11_ImportCert(targetSlot, sourceCert, CK_INVALID_HANDLE,
+			     nickname, PR_FALSE);
+	goto done;
+    }
+
+    /* the cert already exists, see if the nickname and/or  CKA_ID need
+     * to be updated */
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* does our source have a CKA_ID ? */
+    rv = PK11_GetAttributes(arena, sourceSlot, id,  &sourceCKAID, 1);
+    if (rv != SECSuccess) {
+	sourceCKAID.ulValueLen = 0;
+    }
+
+    /* if we have a source CKA_ID, see of we need to update the
+     * target's CKA_ID */
+    if (sourceCKAID.ulValueLen != 0) {
+	rv = PK11_GetAttributes(arena, targetSlot, targetCertID,
+				    &targetCKAID, 1);
+	if (rv != SECSuccess) {
+	    targetCKAID.ulValueLen = 0;
+	}
+	/* if the target has no CKA_ID, update it from the source */
+	if (targetCKAID.ulValueLen == 0) {
+	    lrv=pk11_setAttributes(targetSlot, targetCertID, &sourceCKAID, 1);
+	    if (lrv != SECSuccess) {
+		error = PORT_GetError();
+	    }
+	}
+    }
+    rv = SECSuccess;
+
+    /* now check if we need to update the nickname */
+    if (nickname && *nickname) {
+	char *targetname;
+	targetname = PK11_GetObjectNickname(targetSlot, targetCertID);
+	if (!targetname || !*targetname) {
+	    /* target has no nickname, or it's empty, update it */
+	    rv = PK11_SetObjectNickname(targetSlot, targetCertID, nickname);
+	}
+	if (targetname) {
+	    PORT_Free(targetname);
+	}
+    }
+
+    /* restore the error code if CKA_ID failed, but nickname didn't */
+    if ((rv == SECSuccess) && (lrv != SECSuccess)) {
+	rv = lrv;
+	PORT_SetError(error);
+    }
+
+done:
+    if (nickname) {
+	PORT_Free(nickname);
+    }
+    if (sourceCert) {
+	CERT_DestroyCertificate(sourceCert);
+    }
+    if (arena) {
+         PORT_FreeArena(arena,PR_FALSE);
+    }
+    return rv;
+}
+
+
+/*************************************************************************
+ *
+ *            Crls
+ *
+ *************************************************************************/
+
+/*
+ * Use the raw PKCS #11 interface to merge the CRLs.
+ *
+ * In the case where of collision, choose the newest CRL that is valid.
+ */
+static SECStatus
+pk11_mergeCrl(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+    CK_OBJECT_HANDLE targetCrlID;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+    CK_ATTRIBUTE crlTemplate[] = {
+	{ CKA_SUBJECT, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_NSS_KRL, NULL, 0 }
+    };
+    CK_ULONG crlTemplateCount = sizeof(crlTemplate)/sizeof(crlTemplate[0]);
+    CK_ATTRIBUTE crlCopyTemplate[] = {
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_LABEL, NULL, 0 },
+	{ CKA_PRIVATE, NULL, 0 },
+	{ CKA_MODIFIABLE, NULL, 0 },
+	{ CKA_SUBJECT, NULL, 0 },
+	{ CKA_NSS_KRL, NULL, 0 },
+	{ CKA_NSS_URL, NULL, 0 },
+	{ CKA_VALUE, NULL, 0 }
+    };
+    CK_ULONG crlCopyTemplateCount = 
+		sizeof(crlCopyTemplate)/sizeof(crlCopyTemplate[0]);
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+    /* check to see if the crl is already in the target slot */
+    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, crlTemplate, 
+				crlTemplateCount, id, &targetCrlID);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+    if (targetCrlID != CK_INVALID_HANDLE) {
+	/* we already have a CRL, check to see which is more up-to-date. */
+	goto done;
+    }
+
+    /* load the CRL into the target token. */
+    rv = pk11_copyAttributes(arena, targetSlot, targetCrlID, sourceSlot, id,
+				crlCopyTemplate, crlCopyTemplateCount);
+done:
+    if (arena) {
+         PORT_FreeArena(arena,PR_FALSE);
+    }
+    return rv;
+}
+
+/*************************************************************************
+ *
+ *            SMIME objects
+ *
+ *************************************************************************/
+
+/*
+ * use the raw PKCS #11 interface to merge the S/MIME records
+ */
+static SECStatus
+pk11_mergeSmime(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+    CK_OBJECT_HANDLE targetSmimeID;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+    CK_ATTRIBUTE smimeTemplate[] = {
+	{ CKA_SUBJECT, NULL, 0 },
+	{ CKA_NSS_EMAIL, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 },
+    };
+    CK_ULONG smimeTemplateCount = 
+		sizeof(smimeTemplate)/sizeof(smimeTemplate[0]);
+    CK_ATTRIBUTE smimeCopyTemplate[] = {
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_LABEL, NULL, 0 },
+	{ CKA_PRIVATE, NULL, 0 },
+	{ CKA_MODIFIABLE, NULL, 0 },
+	{ CKA_SUBJECT, NULL, 0 },
+	{ CKA_NSS_EMAIL, NULL, 0 },
+	{ CKA_NSS_SMIME_TIMESTAMP, NULL, 0 },
+	{ CKA_VALUE, NULL, 0 }
+    };
+    CK_ULONG smimeCopyTemplateCount = 
+		sizeof(smimeCopyTemplate)/sizeof(smimeCopyTemplate[0]);
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+    /* check to see if the crl is already in the target slot */
+    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, smimeTemplate, 
+				smimeTemplateCount, id, &targetSmimeID);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+    if (targetSmimeID != CK_INVALID_HANDLE) {
+	/* we already have a SMIME record */
+	goto done;
+    }
+
+    /* load the SMime Record into the target token. */
+    rv = pk11_copyAttributes(arena, targetSlot, targetSmimeID, sourceSlot, id,
+				smimeCopyTemplate, smimeCopyTemplateCount);
+done:
+    if (arena) {
+         PORT_FreeArena(arena,PR_FALSE);
+    }
+    return rv;
+}
+
+/*************************************************************************
+ *
+ *            Trust Objects
+ *
+ *************************************************************************/
+
+
+/*
+ * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target)
+ */
+#define USE_TARGET PR_FALSE
+#define USE_SOURCE PR_TRUE
+PRBool
+pk11_mergeTrustEntry(CK_ATTRIBUTE *target, CK_ATTRIBUTE *source)
+{
+    CK_ULONG targetTrust = (target->ulValueLen == sizeof (CK_LONG)) ?
+		*(CK_ULONG *)target->pValue : CKT_NSS_TRUST_UNKNOWN;
+    CK_ULONG sourceTrust = (source->ulValueLen == sizeof (CK_LONG)) ?
+		*(CK_ULONG *)source->pValue : CKT_NSS_TRUST_UNKNOWN;
+
+    /*
+     * Examine a single entry and deside if the source or target version
+     * should win out. When all the entries have been checked, if there is
+     * any case we need to update, we will write the whole source record
+     * to the target database. That means for each individual record, if the
+     * target wins, we need to update the source (in case later we have a
+     * case where the source wins). If the source wins, it already 
+     */
+    if (sourceTrust == targetTrust) {
+	return USE_TARGET;  /* which equates to 'do nothing' */
+    }
+
+    if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) {
+	return USE_TARGET; 
+    }
+
+    /* target has no idea, use the source's idea of the trust value */
+    if (targetTrust == CKT_NSS_TRUST_UNKNOWN) {
+	/* source overwrites the target */
+	return USE_SOURCE;
+    }
+
+    /* so both the target and the source have some idea of what this 
+     * trust attribute should be, and neither agree exactly. 
+     * At this point, we prefer 'hard' attributes over 'soft' ones. 
+     * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and
+     * CKT_NSS_UNTRUTED. Soft ones are ones which don't change the
+     * actual trust of the cert (CKT_MUST_VERIFY, CKT_NSS_VALID,
+     * CKT_NSS_VALID_DELEGATOR).
+     */
+    if ((sourceTrust == CKT_NSS_MUST_VERIFY) 
+	|| (sourceTrust == CKT_NSS_VALID)
+	|| (sourceTrust == CKT_NSS_VALID_DELEGATOR)) {
+	return USE_TARGET;
+    }
+    if ((targetTrust == CKT_NSS_MUST_VERIFY) 
+	|| (targetTrust == CKT_NSS_VALID)
+	|| (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
+	/* source overrites the target */
+	return USE_SOURCE;
+    }
+
+    /* both have hard attributes, we have a conflict, let the target win. */
+    return USE_TARGET;
+}
+/*
+ * use the raw PKCS #11 interface to merge the S/MIME records
+ */
+static SECStatus
+pk11_mergeTrust(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+    CK_OBJECT_HANDLE targetTrustID;
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECSuccess;
+    int error = 0;
+    CK_ATTRIBUTE trustTemplate[] = {
+	{ CKA_ISSUER, NULL, 0 },
+	{ CKA_SERIAL_NUMBER, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 },
+    };
+    CK_ULONG trustTemplateCount = 
+		sizeof(trustTemplate)/sizeof(trustTemplate[0]);
+    CK_ATTRIBUTE trustCopyTemplate[] = {
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_LABEL, NULL, 0 },
+	{ CKA_PRIVATE, NULL, 0 },
+	{ CKA_MODIFIABLE, NULL, 0 },
+	{ CKA_ISSUER, NULL, 0},
+	{ CKA_SERIAL_NUMBER, NULL, 0},
+	{ CKA_CERT_SHA1_HASH, NULL, 0 },
+	{ CKA_CERT_MD5_HASH, NULL, 0 },
+	{ CKA_TRUST_SERVER_AUTH, NULL, 0 },
+	{ CKA_TRUST_CLIENT_AUTH, NULL, 0 },
+	{ CKA_TRUST_CODE_SIGNING, NULL, 0 },
+	{ CKA_TRUST_EMAIL_PROTECTION, NULL, 0 },
+	{ CKA_TRUST_STEP_UP_APPROVED, NULL, 0 }
+    };
+    CK_ULONG trustCopyTemplateCount = 
+		sizeof(trustCopyTemplate)/sizeof(trustCopyTemplate[0]);
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	rv = SECFailure;
+	goto done;
+    }
+    /* check to see if the crl is already in the target slot */
+    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, trustTemplate, 
+				trustTemplateCount, id, &targetTrustID);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+    if (targetTrustID != CK_INVALID_HANDLE) {
+	/* a matching trust record already exists, merge it in */
+	CK_ATTRIBUTE_TYPE trustAttrs[] = {
+	    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH,
+	    CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, 
+	    CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, 
+	    CKA_TRUST_TIME_STAMPING
+	};
+	CK_ULONG trustAttrsCount = 
+		sizeof(trustAttrs)/sizeof(trustAttrs[0]);
+
+	int i;
+	CK_ATTRIBUTE targetTemplate, sourceTemplate;
+
+	/* existing trust record, merge the two together */
+        for (i=0; i < trustAttrsCount; i++) {
+	    targetTemplate.type = sourceTemplate.type = trustAttrs[i];
+	    targetTemplate.pValue = sourceTemplate.pValue = NULL;
+	    targetTemplate.ulValueLen = sourceTemplate.ulValueLen = 0;
+	    PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
+	    PK11_GetAttributes(arena, targetSlot, targetTrustID, 
+							&targetTemplate, 1);
+	    if (pk11_mergeTrustEntry(&targetTemplate, &sourceTemplate)) {
+		/* source wins, write out the source attribute to the target */
+		SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID, 
+				   &sourceTemplate, 1);
+		if (lrv != SECSuccess) {
+		    rv = SECFailure;
+		    error = PORT_GetError();
+		}
+	    }
+	}
+
+	/* handle step */
+	sourceTemplate.type = CKA_TRUST_STEP_UP_APPROVED;
+	sourceTemplate.pValue = NULL;
+	sourceTemplate.ulValueLen = 0;
+
+	/* if the source has steup set, then set it in the target */
+	PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
+	if ((sourceTemplate.ulValueLen == sizeof(CK_BBOOL)) && 
+		(sourceTemplate.pValue) &&
+		(*(CK_BBOOL *)sourceTemplate.pValue == CK_TRUE)) {
+	    SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID, 
+				   &sourceTemplate, 1);
+	    if (lrv != SECSuccess) {
+		rv = SECFailure;
+		error = PORT_GetError();
+	    }
+	}
+
+	goto done;
+
+    }
+
+    /* load the new trust Record into the target token. */
+    rv = pk11_copyAttributes(arena, targetSlot, targetTrustID, sourceSlot, id,
+				trustCopyTemplate, trustCopyTemplateCount);
+done:
+    if (arena) {
+         PORT_FreeArena(arena,PR_FALSE);
+    }
+
+    /* restore the error code */
+    if (rv == SECFailure && error) {
+	PORT_SetError(error);
+    }
+	
+    return rv;
+}
+
+/*************************************************************************
+ *
+ *            Central merge code
+ *
+ *************************************************************************/
+/*
+ * merge a single object from sourceToken to targetToken
+ */
+static SECStatus
+pk11_mergeObject(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
+{
+
+    CK_OBJECT_CLASS objClass;
+
+
+    objClass = PK11_ReadULongAttribute(sourceSlot, id, CKA_CLASS);
+    if (objClass == (CK_ULONG) -1) {
+	PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE );
+	return SECFailure;
+    }
+
+    switch (objClass) {
+    case CKO_CERTIFICATE:
+	return pk11_mergeCert(targetSlot, sourceSlot, id, 
+					targetPwArg, sourcePwArg);
+    case CKO_NSS_TRUST:
+	return pk11_mergeTrust(targetSlot, sourceSlot, id, 
+					targetPwArg, sourcePwArg);
+    case CKO_PUBLIC_KEY:
+	return pk11_mergePublicKey(targetSlot, sourceSlot, id,
+					targetPwArg, sourcePwArg);
+    case CKO_PRIVATE_KEY:
+	return pk11_mergePrivateKey(targetSlot, sourceSlot, id, 
+					targetPwArg, sourcePwArg);
+    case CKO_SECRET_KEY:
+	return pk11_mergeSecretKey(targetSlot, sourceSlot, id, 
+					targetPwArg, sourcePwArg);
+    case CKO_NSS_CRL:
+	return pk11_mergeCrl(targetSlot, sourceSlot, id, 
+					targetPwArg, sourcePwArg);
+    case CKO_NSS_SMIME:
+	return pk11_mergeSmime(targetSlot, sourceSlot, id, 
+					targetPwArg, sourcePwArg);
+    default:
+	break;
+    }
+
+    PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE );
+    return SECFailure;
+}
+
+PK11MergeLogNode *
+pk11_newMergeLogNode(PRArenaPool *arena, 
+		     PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error)
+{
+    PK11MergeLogNode *newLog;
+    PK11GenericObject *obj;
+
+    newLog = PORT_ArenaZNew(arena, PK11MergeLogNode);
+    if (newLog == NULL) {
+	return NULL;
+    }
+
+    obj = PORT_ArenaZNew(arena, PK11GenericObject);
+    if ( !obj ) {
+	return NULL;
+    }
+
+    /* initialize it */
+    obj->slot = slot;
+    obj->objectID = id;
+
+    newLog->object= obj;
+    newLog->error = error;
+    return newLog;
+}
+
+/*
+ * walk down each entry and merge it. keep track of the errors in the log
+ */
+static SECStatus
+pk11_mergeByObjectIDs(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		CK_OBJECT_HANDLE *objectIDs, int count,
+		PK11MergeLog *log, void *targetPwArg, void *sourcePwArg)
+{
+    SECStatus rv = SECSuccess;
+    int error, i;
+    
+    for (i=0; i < count; i++) {
+	/* try to update the entire database. On failure, keep going,
+	 * but remember the error to report back to the caller */
+	SECStatus lrv;
+	PK11MergeLogNode *newLog;
+
+	lrv= pk11_mergeObject(targetSlot, sourceSlot, objectIDs[i], 
+				targetPwArg, sourcePwArg);
+	if (lrv == SECSuccess) {
+	   /* merged with no problem, go to next object */
+	   continue;
+	}
+
+	/* remember that we failed and why */
+	rv = SECFailure;
+	error = PORT_GetError();
+
+	/* log the errors */
+	if (!log) {
+	    /* not logging, go to next entry */
+	    continue;
+	}
+	newLog = pk11_newMergeLogNode(log->arena, sourceSlot, 
+				      objectIDs[i], error);
+	if (!newLog) {
+	    /* failed to allocate entry, just keep going */
+	    continue;
+	}
+
+	/* link in the errorlog entry */
+	newLog->next = NULL;
+	if (log->tail) {
+	    log->tail->next = newLog;
+	} else {
+	    log->head = newLog;
+	}
+	newLog->prev = log->tail;
+	log->tail = newLog;
+    }
+
+    /* restore the last error code */
+    if (rv != SECSuccess) {
+	PORT_SetError(error);
+    }
+    return rv;
+}
+
+/*
+ * Merge all the records in sourceSlot that aren't in targetSlot
+ * 
+ *   This function will return failure if not all the objects
+ *   successfully merged.
+ *
+ *   Applications can pass in an optional error log which will record
+ *   each failing object and why it failed to import. PK11MergeLog
+ *   is modelled after the CERTVerifyLog.
+ */
+SECStatus
+PK11_MergeTokens(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+		PK11MergeLog *log, void *targetPwArg, void *sourcePwArg)
+{
+    SECStatus rv = SECSuccess, lrv = SECSuccess;
+    int error, count = 0;
+    CK_ATTRIBUTE search[2];
+    CK_OBJECT_HANDLE *objectIDs = NULL;
+    CK_BBOOL ck_true = CK_TRUE;
+    CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY;
+
+    PK11_SETATTRS(&search[0], CKA_TOKEN, &ck_true, sizeof(ck_true));
+    PK11_SETATTRS(&search[1], CKA_CLASS, &privKey, sizeof(privKey));
+    /*
+     * make sure both tokens are already authenticated if need be.
+     */
+    rv = PK11_Authenticate(targetSlot, PR_TRUE, targetPwArg);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    /* turns out the old DB's are rather fragile if the private keys aren't
+     * merged in first, so do the private keys explicity. */
+    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 2, &count);
+    if (objectIDs) {
+	lrv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, 
+				    objectIDs, count, log, 
+				    targetPwArg, sourcePwArg);
+	if (lrv != SECSuccess) {
+	    error = PORT_GetError();
+	}
+	PORT_Free(objectIDs);
+	count = 0;
+    }
+
+    /* now do the rest  (NOTE: this will repeat the private keys, but
+     * that shouldnt' be an issue as we will notice they are already
+     * merged in */
+    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 1, &count);
+    if (!objectIDs) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, objectIDs, count, log, 
+			targetPwArg, sourcePwArg);
+    if (rv == SECSuccess) {
+	/* if private keys failed, but the rest succeeded, be sure to let
+	 * the caller know that private keys failed and why.
+	 * NOTE: this is highly unlikely since the same keys that failed
+	 * in the previous merge call will most likely fail in this one */
+	if (lrv != SECSuccess) {
+	    rv = lrv;
+	    PORT_SetError(error);
+	}
+    }
+
+loser:
+    if (objectIDs) {
+	PORT_Free(objectIDs);
+    }
+    return rv;
+}
+
+PK11MergeLog *
+PK11_CreateMergeLog(void)
+{
+    PRArenaPool *arena;
+    PK11MergeLog *log;
+
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	return NULL;
+    }
+
+    log = PORT_ArenaZNew(arena, PK11MergeLog);
+    if (log == NULL) {
+         PORT_FreeArena(arena,PR_FALSE);
+	return NULL;
+    }
+    log->arena = arena;
+    log->version = 1;
+    return log;
+}
+
+void
+PK11_DestroyMergeLog(PK11MergeLog *log)
+{
+   if (log && log->arena) {
+	PORT_FreeArena(log->arena, PR_FALSE);
+    }
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11nobj.c b/mozilla/security/nss/lib/pk11wrap/pk11nobj.c
new file mode 100644
index 0000000..412ba3c
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11nobj.c
@@ -0,0 +1,817 @@
+/* ***** 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 ***** */
+/*
+ * This file manages Netscape specific PKCS #11 objects (CRLs, Trust objects,
+ * etc).
+ */
+
+#include "secport.h"
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "cert.h"
+#include "certi.h" 
+#include "secitem.h"
+#include "sechash.h" 
+#include "secoid.h"
+
+#include "certdb.h" 
+#include "secerr.h"
+#include "sslerr.h"
+
+#include "pki3hack.h"
+#include "dev3hack.h" 
+
+#include "devm.h" 
+#include "pki.h"
+#include "pkim.h" 
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+CK_TRUST
+pk11_GetTrustField(PK11SlotInfo *slot, PRArenaPool *arena, 
+                   CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type)
+{
+  CK_TRUST rv = 0;
+  SECItem item;
+
+  item.data = NULL;
+  item.len = 0;
+
+  if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) {
+    PORT_Assert(item.len == sizeof(CK_TRUST));
+    PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST));
+    /* Damn, is there an endian problem here? */
+    return rv;
+  }
+
+  return 0;
+}
+
+PRBool
+pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust)
+{
+  PRArenaPool *arena;
+
+  CK_ATTRIBUTE tobjTemplate[] = {
+    { CKA_CLASS, NULL, 0 },
+    { CKA_CERT_SHA1_HASH, NULL, 0 },
+  };
+
+  CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
+  CK_OBJECT_HANDLE tobjID;
+  unsigned char sha1_hash[SHA1_LENGTH];
+
+  CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth;
+
+  PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len);
+
+  PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc));
+  PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash, 
+                SHA1_LENGTH);
+
+  tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate, 
+                                     sizeof(tobjTemplate)/sizeof(tobjTemplate[0]));
+  if( CK_INVALID_HANDLE == tobjID ) {
+    return PR_FALSE;
+  }
+
+  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+  if( NULL == arena ) return PR_FALSE;
+
+  /* Unfortunately, it seems that PK11_GetAttributes doesn't deal
+   * well with nonexistant attributes.  I guess we have to check 
+   * the trust info fields one at a time.
+   */
+
+  /* We could verify CKA_CERT_HASH here */
+
+  /* We could verify CKA_EXPIRES here */
+
+
+  /* "Purpose" trust information */
+  serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH);
+  clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH);
+  codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING);
+  emailProtection = pk11_GetTrustField(slot, arena, tobjID, 
+						CKA_TRUST_EMAIL_PROTECTION);
+  /* Here's where the fun logic happens.  We have to map back from the 
+   * key usage, extended key usage, purpose, and possibly other trust values 
+   * into the old trust-flags bits.  */
+
+  /* First implementation: keep it simple for testing.  We can study what other
+   * mappings would be appropriate and add them later.. fgmr 20000724 */
+
+  if ( serverAuth ==  CKT_NETSCAPE_TRUSTED ) {
+    trust->sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+  }
+
+  if ( serverAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
+    trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | 
+							CERTDB_NS_TRUSTED_CA;
+  }
+  if ( clientAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
+    trust->sslFlags |=  CERTDB_TRUSTED_CLIENT_CA ;
+  }
+
+  if ( emailProtection == CKT_NETSCAPE_TRUSTED ) {
+    trust->emailFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+  }
+
+  if ( emailProtection == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
+    trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
+  }
+
+  if( codeSigning == CKT_NETSCAPE_TRUSTED ) {
+    trust->objectSigningFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+  }
+
+  if( codeSigning == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
+    trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
+  }
+
+  /* There's certainly a lot more logic that can go here.. */
+
+  PORT_FreeArena(arena, PR_FALSE);
+
+  return PR_TRUE;
+}
+
+static SECStatus
+pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg)
+{
+    SECItem derCrl;
+    CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg;
+    CERTCrlNode *new_node = NULL;
+    CK_ATTRIBUTE fetchCrl[3] = {
+	 { CKA_VALUE, NULL, 0},
+	 { CKA_NETSCAPE_KRL, NULL, 0},
+	 { CKA_NETSCAPE_URL, NULL, 0},
+    };
+    const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]);
+    CK_RV crv;
+    SECStatus rv = SECFailure;
+
+    crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize);
+    if (CKR_OK != crv) {
+	PORT_SetError(PK11_MapError(crv));
+	goto loser;
+    }
+
+    if (!fetchCrl[1].pValue) {
+	PORT_SetError(SEC_ERROR_CRL_INVALID);
+	goto loser;
+    }
+
+    new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
+    if (new_node == NULL) {
+        goto loser;
+    }
+
+    if (*((CK_BBOOL *)fetchCrl[1].pValue))
+        new_node->type = SEC_KRL_TYPE;
+    else
+        new_node->type = SEC_CRL_TYPE;
+
+    derCrl.type = siBuffer;
+    derCrl.data = (unsigned char *)fetchCrl[0].pValue;
+    derCrl.len = fetchCrl[0].ulValueLen;
+    new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type);
+    if (new_node->crl == NULL) {
+	goto loser;
+    }
+
+    if (fetchCrl[2].pValue) {
+        int nnlen = fetchCrl[2].ulValueLen;
+        new_node->crl->url  = (char *)PORT_ArenaAlloc(head->arena, nnlen+1);
+        if ( !new_node->crl->url ) {
+            goto loser;
+        }
+        PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
+        new_node->crl->url[nnlen] = 0;
+    } else {
+        new_node->crl->url = NULL;
+    }
+
+
+    new_node->next = NULL;
+    if (head->last) {
+        head->last->next = new_node;
+        head->last = new_node;
+    } else {
+        head->first = head->last = new_node;
+    }
+    rv = SECSuccess;
+
+loser:
+    return(rv);
+}
+
+/*
+ * Return a list of all the CRLs .
+ * CRLs are allocated in the list's arena.
+ */
+SECStatus
+PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) {
+    pk11TraverseSlot creater;
+    CK_ATTRIBUTE theTemplate[2];
+    CK_ATTRIBUTE *attrs;
+    CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL;
+    CK_BBOOL isKrl = CK_FALSE;
+
+    attrs = theTemplate;
+    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++;
+    if (type != -1) {
+	isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE);
+        PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++;
+    }
+
+    creater.callback = pk11_CollectCrls;
+    creater.callbackArg = (void *) nodes;
+    creater.findTemplate = theTemplate;
+    creater.templateCount = (attrs - theTemplate);
+
+    return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
+}
+
+struct crlOptionsStr {
+    CERTCrlHeadNode* head;
+    PRInt32 decodeOptions;
+};
+
+typedef struct crlOptionsStr crlOptions;
+
+static SECStatus
+pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID,
+                          void *arg)
+{
+    SECItem* derCrl = NULL;
+    crlOptions* options = (crlOptions*) arg;
+    CERTCrlHeadNode *head = options->head;
+    CERTCrlNode *new_node = NULL;
+    CK_ATTRIBUTE fetchCrl[3] = {
+	 { CKA_VALUE, NULL, 0},
+	 { CKA_NETSCAPE_KRL, NULL, 0},
+	 { CKA_NETSCAPE_URL, NULL, 0},
+    };
+    const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]);
+    CK_RV crv;
+    SECStatus rv = SECFailure;
+    PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory
+                                  successfully */
+    int i;
+
+    crv = PK11_GetAttributes(NULL,slot,crlID,fetchCrl,fetchCrlSize);
+    if (CKR_OK != crv) {
+	PORT_SetError(PK11_MapError(crv));
+	goto loser;
+    }
+
+    if (!fetchCrl[1].pValue) {
+        /* reject KRLs */
+	PORT_SetError(SEC_ERROR_CRL_INVALID);
+	goto loser;
+    }
+
+    new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena,
+                                              sizeof(CERTCrlNode));
+    if (new_node == NULL) {
+        goto loser;
+    }
+
+    new_node->type = SEC_CRL_TYPE;
+
+    derCrl = SECITEM_AllocItem(NULL, NULL, 0);
+    if (!derCrl) {
+        goto loser;
+    }
+    derCrl->type = siBuffer;
+    derCrl->data = (unsigned char *)fetchCrl[0].pValue;
+    derCrl->len = fetchCrl[0].ulValueLen;
+    new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl,new_node->type,
+                                               options->decodeOptions);
+    if (new_node->crl == NULL) {
+	goto loser;
+    }    
+    adopted = PR_TRUE; /* now that the CRL has adopted the DER memory,
+                          we won't need to free it upon exit */
+
+    if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) {
+        /* copy the URL if there is one */
+        int nnlen = fetchCrl[2].ulValueLen;
+        new_node->crl->url  = (char *)PORT_ArenaAlloc(new_node->crl->arena,
+                                                      nnlen+1);
+        if ( !new_node->crl->url ) {
+            goto loser;
+        }
+        PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
+        new_node->crl->url[nnlen] = 0;
+    } else {
+        new_node->crl->url = NULL;
+    }
+
+    new_node->next = NULL;
+    if (head->last) {
+        head->last->next = new_node;
+        head->last = new_node;
+    } else {
+        head->first = head->last = new_node;
+    }
+    rv = SECSuccess;
+    new_node->crl->slot = PK11_ReferenceSlot(slot);
+    new_node->crl->pkcs11ID = crlID;
+
+loser:
+    /* free attributes that weren't adopted by the CRL */
+    for (i=1;i<fetchCrlSize;i++) {
+        if (fetchCrl[i].pValue) {
+            PORT_Free(fetchCrl[i].pValue);
+        }
+    }
+    /* free the DER if the CRL object didn't adopt it */
+    if (fetchCrl[0].pValue && PR_FALSE == adopted) {
+        PORT_Free(fetchCrl[0].pValue);
+    }
+    if (derCrl && !adopted) {
+        /* clear the data fields, which we already took care of above */
+        derCrl->data = NULL;
+        derCrl->len = 0;
+        /* free the memory for the SECItem structure itself */
+        SECITEM_FreeItem(derCrl, PR_TRUE);
+    }
+    return(rv);
+}
+
+/*
+ * Return a list of CRLs matching specified issuer and type
+ * CRLs are not allocated in the list's arena, but rather in their own,
+ * arena, so that they can be used individually in the CRL cache .
+ * CRLs are always partially decoded for efficiency.
+ */
+SECStatus pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem* issuer,
+                            void *wincx)
+{
+    pk11TraverseSlot creater;
+    CK_ATTRIBUTE theTemplate[2];
+    CK_ATTRIBUTE *attrs;
+    CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL;
+    crlOptions options;
+
+    attrs = theTemplate;
+    PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++;
+
+    options.head = nodes;
+
+    /* - do a partial decoding - we don't need to decode the entries while
+       fetching
+       - don't copy the DER for optimal performance - CRL can be very large
+       - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it
+       - keep bad CRL objects. The CRL cache is interested in them, for
+         security purposes. Bad CRL objects are a sign of something amiss.
+    */
+
+    options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER |
+                            CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL;
+    if (issuer)
+    {
+        PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len); attrs++;
+    }
+
+    creater.callback = pk11_RetrieveCrlsCallback;
+    creater.callbackArg = (void *) &options;
+    creater.findTemplate = theTemplate;
+    creater.templateCount = (attrs - theTemplate);
+
+    return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
+}
+
+/*
+ * return the crl associated with a derSubjectName 
+ */
+SECItem *
+PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle,
+					 SECItem *name, int type, char **pUrl)
+{
+    NSSCRL **crls, **crlp, *crl = NULL;
+    NSSDER subject;
+    SECItem *rvItem;
+    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+    char * url = NULL;
+
+    PORT_SetError(0);
+    NSSITEM_FROM_SECITEM(&subject, name);
+    if (*slot) {
+	nssCryptokiObject **instances;
+	nssPKIObjectCollection *collection;
+	nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+	NSSToken *token = PK11Slot_GetNSSToken(*slot);
+	collection = nssCRLCollection_Create(td, NULL);
+	if (!collection) {
+	    goto loser;
+	}
+	instances = nssToken_FindCRLsBySubject(token, NULL, &subject, 
+	                                       tokenOnly, 0, NULL);
+	nssPKIObjectCollection_AddInstances(collection, instances, 0);
+	nss_ZFreeIf(instances);
+	crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
+	nssPKIObjectCollection_Destroy(collection);
+    } else {
+	crls = nssTrustDomain_FindCRLsBySubject(td, &subject);
+    }
+    if ((!crls) || (*crls == NULL)) {
+	if (crls) {
+	    nssCRLArray_Destroy(crls);
+	}
+	if (NSS_GetError() == NSS_ERROR_NOT_FOUND) {
+	    PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+	}
+	goto loser;
+    }
+    for (crlp = crls; *crlp; crlp++) {
+	if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) ||
+	    ((*crlp)->isKRL && type != SEC_CRL_TYPE)) 
+	{
+	    crl = nssCRL_AddRef(*crlp);
+	    break;
+	}
+    }
+    nssCRLArray_Destroy(crls);
+    if (!crl) { 
+	/* CRL collection was found, but no interesting CRL's were on it.
+	 * Not an error */
+	PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+	goto loser;
+    }
+    if (crl->url) {
+	url = PORT_Strdup(crl->url);
+	if (!url) {
+	    goto loser;
+	}
+    }
+    rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size);
+    if (!rvItem) {
+	goto loser;
+    }
+    memcpy(rvItem->data, crl->encoding.data, crl->encoding.size);
+    *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot);
+    *crlHandle = crl->object.instances[0]->handle;
+    *pUrl = url;
+    nssCRL_Destroy(crl);
+    return rvItem;
+
+loser:
+    if (url)
+    	PORT_Free(url);
+    if (crl)
+	nssCRL_Destroy(crl);
+    if (PORT_GetError() == 0) {
+	PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+    }
+    return NULL;
+}
+
+CK_OBJECT_HANDLE
+PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name, 
+							char *url, int type)
+{
+    NSSItem derCRL, derSubject;
+    NSSToken *token = PK11Slot_GetNSSToken(slot);
+    nssCryptokiObject *object;
+    PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE;
+    CK_OBJECT_HANDLE rvH;
+
+    NSSITEM_FROM_SECITEM(&derSubject, name);
+    NSSITEM_FROM_SECITEM(&derCRL, crl);
+
+    object = nssToken_ImportCRL(token, NULL, 
+                                &derSubject, &derCRL, isKRL, url, PR_TRUE);
+
+    if (object) {
+	rvH = object->handle;
+	nssCryptokiObject_Destroy(object);
+    } else {
+	rvH = CK_INVALID_HANDLE;
+        PORT_SetError(SEC_ERROR_CRL_IMPORT_FAILED);
+    }
+    return rvH;
+}
+
+
+/*
+ * delete a crl.
+ */
+SECStatus
+SEC_DeletePermCRL(CERTSignedCrl *crl)
+{
+    PRStatus status;
+    NSSToken *token;
+    nssCryptokiObject *object;
+    PK11SlotInfo *slot = crl->slot;
+
+    if (slot == NULL) {
+        PORT_Assert(slot);
+	/* shouldn't happen */
+	PORT_SetError( SEC_ERROR_CRL_INVALID);
+	return SECFailure;
+    }
+    token = PK11Slot_GetNSSToken(slot);
+
+    object = nss_ZNEW(NULL, nssCryptokiObject);
+    if (!object) {
+        return SECFailure;
+    }
+    object->token = nssToken_AddRef(token);
+    object->handle = crl->pkcs11ID;
+    object->isTokenObject = PR_TRUE;
+
+    status = nssToken_DeleteStoredObject(object);
+
+    nssCryptokiObject_Destroy(object);
+    return (status == PR_SUCCESS) ? SECSuccess : SECFailure;
+}
+
+/*
+ * return the certificate associated with a derCert 
+ */
+SECItem *
+PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr,
+				 SECItem *name, SECItem **profileTime)
+{
+    CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME;
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_SUBJECT, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_NETSCAPE_EMAIL, NULL, 0 },
+    };
+    CK_ATTRIBUTE smimeData[] =  {
+	{ CKA_SUBJECT, NULL, 0 },
+	{ CKA_VALUE, NULL, 0 },
+    };
+    /* if you change the array, change the variable below as well */
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
+    CK_ATTRIBUTE *attrs = theTemplate;
+    CK_RV crv;
+    SECItem *emailProfile = NULL;
+
+    if (!emailAddr || !emailAddr[0]) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++;
+    PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); 
+								    attrs++;
+
+    if (*slot) {
+    	smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize);
+    } else {
+	PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
+							PR_FALSE,PR_TRUE,NULL);
+	PK11SlotListElement *le;
+
+	if (!list) {
+	    return NULL;
+	}
+	/* loop through all the slots */
+	for (le = list->head; le; le = le->next) {
+	    smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize);
+	    if (smimeh != CK_INVALID_HANDLE) {
+		*slot = PK11_ReferenceSlot(le->slot);
+		break;
+	    }
+	}
+	PK11_FreeSlotList(list);
+    }
+    
+    if (smimeh == CK_INVALID_HANDLE) {
+	PORT_SetError(SEC_ERROR_NO_KRL);
+	return NULL;
+    }
+
+    if (profileTime) {
+    	PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0);
+    } 
+    
+    crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError (crv));
+	goto loser;
+    }
+
+    if (!profileTime) {
+	SECItem profileSubject;
+
+	profileSubject.data = (unsigned char*) smimeData[0].pValue;
+	profileSubject.len = smimeData[0].ulValueLen;
+	if (!SECITEM_ItemsAreEqual(&profileSubject,name)) {
+	    goto loser;
+	}
+    }
+
+    emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    
+    if (emailProfile == NULL) {
+	goto loser;
+    }
+
+    emailProfile->data = (unsigned char*) smimeData[1].pValue;
+    emailProfile->len = smimeData[1].ulValueLen;
+
+    if (profileTime) {
+	*profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    
+	if (*profileTime) {
+	    (*profileTime)->data = (unsigned char*) smimeData[0].pValue;
+	    (*profileTime)->len = smimeData[0].ulValueLen;
+	}
+    }
+
+loser:
+    if (emailProfile == NULL) {
+	if (smimeData[1].pValue) {
+	    PORT_Free(smimeData[1].pValue);
+	}
+    }
+    if (profileTime == NULL || *profileTime == NULL) {
+	if (smimeData[0].pValue) {
+	    PORT_Free(smimeData[0].pValue);
+	}
+    }
+    return emailProfile;
+}
+
+
+SECStatus
+PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj,
+				 SECItem *emailProfile,  SECItem *profileTime)
+{
+    CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME;
+    CK_BBOOL ck_true = CK_TRUE;
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_SUBJECT, NULL, 0 },
+	{ CKA_NETSCAPE_EMAIL, NULL, 0 },
+	{ CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 },
+	{ CKA_VALUE, NULL, 0 }
+    };
+    /* if you change the array, change the variable below as well */
+    int realSize = 0;
+    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
+    CK_ATTRIBUTE *attrs = theTemplate;
+    CK_SESSION_HANDLE rwsession;
+    PK11SlotInfo *free_slot = NULL;
+    CK_RV crv;
+#ifdef DEBUG
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+#endif
+
+    PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++;
+    PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++;
+    PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, 
+				emailAddr, PORT_Strlen(emailAddr)+1); attrs++;
+    if (profileTime) {
+	PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data,
+	                                            profileTime->len); attrs++;
+	PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data,
+	                                            emailProfile->len); attrs++;
+    }
+    realSize = attrs - theTemplate;
+    PORT_Assert (realSize <= tsize);
+
+    if (slot == NULL) {
+	free_slot = slot = PK11_GetInternalKeySlot();
+	/* we need to free the key slot in the end!!! */
+    }
+
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_READ_ONLY);
+	if (free_slot) {
+	    PK11_FreeSlot(free_slot);
+	}
+	return SECFailure;
+    }
+
+    crv = PK11_GETTAB(slot)->
+                        C_CreateObject(rwsession,theTemplate,realSize,&smimeh);
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+    }
+
+    PK11_RestoreROSession(slot,rwsession);
+
+    if (free_slot) {
+	PK11_FreeSlot(free_slot);
+    }
+    return SECSuccess;
+}
+
+
+CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot,char *url,
+                  CERTSignedCrl *newCrl, SECItem *derCrl, int type);
+
+/* import the CRL into the token */
+
+CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url,
+    int type, void *wincx, PRInt32 importOptions, PRArenaPool* arena,
+    PRInt32 decodeoptions)
+{
+    CERTSignedCrl *newCrl, *crl;
+    SECStatus rv;
+    CERTCertificate *caCert = NULL;
+
+    newCrl = crl = NULL;
+
+    do {
+        newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type,
+                                            decodeoptions);
+        if (newCrl == NULL) {
+            if (type == SEC_CRL_TYPE) {
+                /* only promote error when the error code is too generic */
+                if (PORT_GetError () == SEC_ERROR_BAD_DER)
+                    PORT_SetError(SEC_ERROR_CRL_INVALID);
+	        } else {
+                PORT_SetError(SEC_ERROR_KRL_INVALID);
+            }
+            break;		
+        }
+
+        if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){
+            CERTCertDBHandle* handle = CERT_GetDefaultCertDB();
+            PR_ASSERT(handle != NULL);
+            caCert = CERT_FindCertByName (handle,
+                                          &newCrl->crl.derName);
+            if (caCert == NULL) {
+                PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);	    
+                break;
+            }
+
+            /* If caCert is a v3 certificate, make sure that it can be used for
+               crl signing purpose */
+            rv = CERT_CheckCertUsage (caCert, KU_CRL_SIGN);
+            if (rv != SECSuccess) {
+                break;
+            }
+
+            rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert,
+                                       PR_Now(), wincx);
+            if (rv != SECSuccess) {
+                if (type == SEC_CRL_TYPE) {
+                    PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
+                } else {
+                    PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
+                }
+                break;
+            }
+        }
+
+	crl = crl_storeCRL(slot, url, newCrl, derCRL, type);
+
+    } while (0);
+
+    if (crl == NULL) {
+	SEC_DestroyCrl (newCrl);
+    }
+    if (caCert) {
+        CERT_DestroyCertificate(caCert);
+    }
+    return (crl);
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11obj.c b/mozilla/security/nss/lib/pk11wrap/pk11obj.c
new file mode 100644
index 0000000..4323ebc
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11obj.c
@@ -0,0 +1,1821 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * This file manages object type indepentent functions.
+ */
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pkcs11t.h"
+#include "pk11func.h"
+#include "key.h" 
+#include "secitem.h"
+#include "secerr.h"
+#include "sslerr.h"
+
+#define PK11_SEARCH_CHUNKSIZE 10
+
+/*
+ * Build a block big enough to hold the data
+ */
+SECItem *
+PK11_BlockData(SECItem *data,unsigned long size) {
+    SECItem *newData;
+
+    newData = (SECItem *)PORT_Alloc(sizeof(SECItem));
+    if (newData == NULL) return NULL;
+
+    newData->len = (data->len + (size-1))/size;
+    newData->len *= size;
+
+    newData->data = (unsigned char *) PORT_ZAlloc(newData->len); 
+    if (newData->data == NULL) {
+	PORT_Free(newData);
+	return NULL;
+    }
+    PORT_Memset(newData->data,newData->len-data->len,newData->len); 
+    PORT_Memcpy(newData->data,data->data,data->len);
+    return newData;
+}
+
+
+SECStatus
+PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) {
+    CK_RV crv;
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session,object);
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+SECStatus
+PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) {
+    CK_RV crv;
+    SECStatus rv = SECSuccess;
+    CK_SESSION_HANDLE rwsession;
+
+    
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+    	return SECFailure;
+    }
+
+    crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession,object);
+    if (crv != CKR_OK) {
+	rv = SECFailure;
+	PORT_SetError(PK11_MapError(crv));
+    }
+    PK11_RestoreROSession(slot,rwsession);
+    return rv;
+}
+
+/*
+ * Read in a single attribute into a SECItem. Allocate space for it with 
+ * PORT_Alloc unless an arena is supplied. In the latter case use the arena
+ * to allocate the space.
+ */
+SECStatus
+PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
+	 CK_ATTRIBUTE_TYPE type, PRArenaPool *arena, SECItem *result) {
+    CK_ATTRIBUTE attr = { 0, NULL, 0 };
+    CK_RV crv;
+
+    attr.type = type;
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
+    if (crv != CKR_OK) {
+	PK11_ExitSlotMonitor(slot);
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    if (arena) {
+    	attr.pValue = PORT_ArenaAlloc(arena,attr.ulValueLen);
+    } else {
+    	attr.pValue = PORT_Alloc(attr.ulValueLen);
+    }
+    if (attr.pValue == NULL) {
+	PK11_ExitSlotMonitor(slot);
+	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	if (!arena) PORT_Free(attr.pValue);
+	return SECFailure;
+    }
+
+    result->data = (unsigned char*)attr.pValue;
+    result->len = attr.ulValueLen;
+
+    return SECSuccess;
+}
+
+/*
+ * Read in a single attribute into As a Ulong. 
+ */
+CK_ULONG
+PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
+	 CK_ATTRIBUTE_TYPE type) {
+    CK_ATTRIBUTE attr;
+    CK_ULONG value = CK_UNAVAILABLE_INFORMATION;
+    CK_RV crv;
+
+    PK11_SETATTRS(&attr,type,&value,sizeof(value));
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+    }
+    return value;
+}
+
+/*
+ * check to see if a bool has been set.
+ */
+CK_BBOOL
+PK11_HasAttributeSet( PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
+				                      CK_ATTRIBUTE_TYPE type )
+{
+    CK_BBOOL ckvalue = CK_FALSE;
+    CK_ATTRIBUTE theTemplate;
+    CK_RV crv;
+
+    /* Prepare to retrieve the attribute. */
+    PK11_SETATTRS( &theTemplate, type, &ckvalue, sizeof( CK_BBOOL ) );
+
+    /* Retrieve attribute value. */
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB( slot )->C_GetAttributeValue( slot->session, id,
+                                                    &theTemplate, 1 );
+    PK11_ExitSlotMonitor(slot);
+    if( crv != CKR_OK ) {
+        PORT_SetError( PK11_MapError( crv ) );
+        return CK_FALSE;
+    }
+
+    return ckvalue;
+}
+
+/*
+ * returns a full list of attributes. Allocate space for them. If an arena is
+ * provided, allocate space out of the arena.
+ */
+CK_RV
+PK11_GetAttributes(PRArenaPool *arena,PK11SlotInfo *slot,
+			CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count)
+{
+    int i;
+    /* make pedantic happy... note that it's only used arena != NULL */ 
+    void *mark = NULL; 
+    CK_RV crv;
+    PORT_Assert(slot->session != CK_INVALID_SESSION);
+    if (slot->session == CK_INVALID_SESSION)
+	return CKR_SESSION_HANDLE_INVALID;
+
+    /*
+     * first get all the lengths of the parameters.
+     */
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count);
+    if (crv != CKR_OK) {
+	PK11_ExitSlotMonitor(slot);
+	return crv;
+    }
+
+    if (arena) {
+    	mark = PORT_ArenaMark(arena);
+	if (mark == NULL) return CKR_HOST_MEMORY;
+    }
+
+    /*
+     * now allocate space to store the results.
+     */
+    for (i=0; i < count; i++) {
+	if (attr[i].ulValueLen == 0)
+	    continue;
+	if (arena) {
+	    attr[i].pValue = PORT_ArenaAlloc(arena,attr[i].ulValueLen);
+	    if (attr[i].pValue == NULL) {
+		/* arena failures, just release the mark */
+		PORT_ArenaRelease(arena,mark);
+		PK11_ExitSlotMonitor(slot);
+		return CKR_HOST_MEMORY;
+	    }
+	} else {
+	    attr[i].pValue = PORT_Alloc(attr[i].ulValueLen);
+	    if (attr[i].pValue == NULL) {
+		/* Separate malloc failures, loop to release what we have 
+		 * so far */
+		int j;
+		for (j= 0; j < i; j++) { 
+		    PORT_Free(attr[j].pValue);
+		    /* don't give the caller pointers to freed memory */
+		    attr[j].pValue = NULL; 
+		}
+		PK11_ExitSlotMonitor(slot);
+		return CKR_HOST_MEMORY;
+	    }
+	}
+    }
+
+    /*
+     * finally get the results.
+     */
+    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count);
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	if (arena) {
+	    PORT_ArenaRelease(arena,mark);
+	} else {
+	    for (i= 0; i < count; i++) {
+		PORT_Free(attr[i].pValue);
+		/* don't give the caller pointers to freed memory */
+		attr[i].pValue = NULL;
+	    }
+	}
+    } else if (arena && mark) {
+	PORT_ArenaUnmark(arena,mark);
+    }
+    return crv;
+}
+
+PRBool
+PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
+{
+    return (PRBool) PK11_HasAttributeSet(slot, handle, CKA_TOKEN);
+}
+
+char *
+PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) 
+{
+    char *nickname = NULL;
+    SECItem result;
+    SECStatus rv;
+
+    rv = PK11_ReadAttribute(slot,id,CKA_LABEL,NULL,&result);
+    if (rv != SECSuccess) {
+	return NULL;
+    }
+
+    nickname = PORT_ZAlloc(result.len+1);
+    if (nickname == NULL) {
+	PORT_Free(result.data);
+	return NULL;
+    }
+    PORT_Memcpy(nickname, result.data, result.len);
+    PORT_Free(result.data);
+    return nickname;
+}
+
+SECStatus
+PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 
+						const char *nickname) 
+{
+    int len = PORT_Strlen(nickname);
+    CK_ATTRIBUTE setTemplate;
+    CK_RV crv;
+    CK_SESSION_HANDLE rwsession;
+
+    if (len < 0) {
+	return SECFailure;
+    }
+
+    PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *) nickname, len);
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+    	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
+			&setTemplate, 1);
+    PK11_RestoreROSession(slot, rwsession);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * strip leading zero's from key material
+ */
+void
+pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) {
+    char *ptr = (char *)attrib->pValue;
+    unsigned long len = attrib->ulValueLen;
+
+    while (len && (*ptr == 0)) {
+	len--;
+	ptr++;
+    }
+    attrib->pValue = ptr;
+    attrib->ulValueLen = len;
+}
+
+/*
+ * get a new session on a slot. If we run out of session, use the slot's
+ * 'exclusive' session. In this case owner becomes false.
+ */
+CK_SESSION_HANDLE
+pk11_GetNewSession(PK11SlotInfo *slot,PRBool *owner)
+{
+    CK_SESSION_HANDLE session;
+    *owner =  PR_TRUE;
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    if ( PK11_GETTAB(slot)->C_OpenSession(slot->slotID,CKF_SERIAL_SESSION, 
+			slot,pk11_notify,&session) != CKR_OK) {
+	*owner = PR_FALSE;
+	session = slot->session;
+    }
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+
+    return session;
+}
+
+void
+pk11_CloseSession(PK11SlotInfo *slot,CK_SESSION_HANDLE session,PRBool owner)
+{
+    if (!owner) return;
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    (void) PK11_GETTAB(slot)->C_CloseSession(session);
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+}
+
+
+SECStatus
+PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
+				const CK_ATTRIBUTE *theTemplate, int count, 
+				PRBool token, CK_OBJECT_HANDLE *objectID)
+{
+	CK_SESSION_HANDLE rwsession;
+	CK_RV crv;
+	SECStatus rv = SECSuccess;
+
+	rwsession = session;
+	if (token) {
+	    rwsession =  PK11_GetRWSession(slot);
+	} else if (rwsession == CK_INVALID_SESSION) {
+	    rwsession =  slot->session;
+	    if (rwsession != CK_INVALID_SESSION)
+		PK11_EnterSlotMonitor(slot);
+	}
+	if (rwsession == CK_INVALID_SESSION) {
+	    PORT_SetError(SEC_ERROR_BAD_DATA);
+	    return SECFailure;
+	}
+	crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, 
+	      /* cast away const :-( */         (CK_ATTRIBUTE_PTR)theTemplate,
+						count, objectID);
+	if(crv != CKR_OK) {
+	    PORT_SetError( PK11_MapError(crv) );
+	    rv = SECFailure;
+	}
+	if (token) {
+	    PK11_RestoreROSession(slot, rwsession);
+	} else if (session == CK_INVALID_SESSION) {
+	    PK11_ExitSlotMonitor(slot);
+        }
+
+	return rv;
+}
+
+
+/* This function may add a maximum of 9 attributes. */
+unsigned int
+pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue)
+{
+
+    const static CK_ATTRIBUTE_TYPE attrTypes[12] = {
+	CKA_ENCRYPT,      CKA_DECRYPT, 0 /* DIGEST */,     CKA_SIGN,
+	CKA_SIGN_RECOVER, CKA_VERIFY,  CKA_VERIFY_RECOVER, 0 /* GEN */,
+	0 /* GEN PAIR */, CKA_WRAP,    CKA_UNWRAP,         CKA_DERIVE 
+    };
+
+    const CK_ATTRIBUTE_TYPE *pType	= attrTypes;
+          CK_ATTRIBUTE      *attr	= attrs;
+          CK_FLAGS          test	= CKF_ENCRYPT;
+
+
+    PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS));
+    flags &= CKF_KEY_OPERATION_FLAGS;
+
+    for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) {
+    	if (test & flags) {
+	    flags ^= test;
+	    PR_ASSERT(*pType);
+	    PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); 
+	    ++attr;
+	}
+    }
+    return (attr - attrs);
+}
+
+/*
+ * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE
+ * and PK11_ATTR_PUBLIC are set.
+ */
+PRBool
+pk11_BadAttrFlags(PK11AttrFlags attrFlags)
+{
+    PK11AttrFlags trueFlags = attrFlags & 0x55555555;
+    PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555;
+    return ((trueFlags & falseFlags) != 0);
+}
+
+/*
+ * This function may add a maximum of 5 attributes.
+ * The caller must make sure the attribute flags don't have conflicts.
+ */
+unsigned int
+pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs,
+				CK_BBOOL *ckTrue, CK_BBOOL *ckFalse)
+{
+    const static CK_ATTRIBUTE_TYPE attrTypes[5] = {
+	CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE,
+	CKA_EXTRACTABLE
+    };
+
+    const CK_ATTRIBUTE_TYPE *pType	= attrTypes;
+          CK_ATTRIBUTE      *attr	= attrs;
+          PK11AttrFlags      test	= PK11_ATTR_TOKEN;
+
+    PR_ASSERT(!pk11_BadAttrFlags(attrFlags));
+
+    /* we test two related bitflags in each iteration */
+    for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) {
+    	if (test & attrFlags) {
+	    attrFlags ^= test;
+	    PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); 
+	    ++attr;
+	} else if ((test << 1) & attrFlags) {
+	    attrFlags ^= (test << 1);
+	    PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse); 
+	    ++attr;
+	}
+    }
+    return (attr - attrs);
+}
+
+/*
+ * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually
+ * set up a signature to get the signaure length.
+ */
+static int
+pk11_backupGetSignLength(SECKEYPrivateKey *key)
+{
+    PK11SlotInfo *slot = key->pkcs11Slot;
+    CK_MECHANISM mech = {0, NULL, 0 };
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_ULONG len;
+    CK_RV crv;
+    unsigned char h_data[20]  = { 0 };
+    unsigned char buf[20]; /* obviously to small */
+    CK_ULONG smallLen = sizeof(buf);
+
+    mech.mechanism = PK11_MapSignKeyType(key->keyType);
+
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID);
+    if (crv != CKR_OK) {
+	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+	pk11_CloseSession(slot,session,owner);
+	PORT_SetError( PK11_MapError(crv) );
+	return -1;
+    }
+    len = 0;
+    crv = PK11_GETTAB(slot)->C_Sign(session,h_data,sizeof(h_data),
+					NULL, &len);
+    /* now call C_Sign with too small a buffer to clear the session state */
+    (void) PK11_GETTAB(slot)->
+			C_Sign(session,h_data,sizeof(h_data),buf,&smallLen);
+	
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return -1;
+    }
+    return len;
+}
+
+/*
+ * get the length of a signature object based on the key
+ */
+int
+PK11_SignatureLen(SECKEYPrivateKey *key)
+{
+    int val;
+    CK_ATTRIBUTE theTemplate = { CKA_EC_PARAMS, NULL, 0 };
+    SECItem params = {siBuffer, NULL, 0};
+    int length; 
+
+    switch (key->keyType) {
+    case rsaKey:
+	val = PK11_GetPrivateModulusLen(key);
+	if (val == -1) {
+	    return pk11_backupGetSignLength(key);
+	}
+	return (unsigned long) val;
+	
+    case fortezzaKey:
+    case dsaKey:
+	return 40;
+    case ecKey:
+	if (PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID,
+			       &theTemplate, 1) == CKR_OK) {
+	    if (theTemplate.pValue != NULL) {
+	        params.len = theTemplate.ulValueLen;
+		params.data = (unsigned char *) theTemplate.pValue;
+	        length = SECKEY_ECParamsToBasePointOrderLen(&params);
+	        PORT_Free(theTemplate.pValue);
+		if (length == 0) {
+		    return pk11_backupGetSignLength(key);
+		}
+		length = ((length + 7)/8) * 2;
+		return length;
+	    }
+	}
+	break;
+    default:
+	break;
+    }
+    PORT_SetError( SEC_ERROR_INVALID_KEY );
+    return 0;
+}
+
+/*
+ * copy a key (or any other object) on a token
+ */
+CK_OBJECT_HANDLE
+PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject)
+{
+    CK_OBJECT_HANDLE destObject;
+    CK_RV crv;
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_CopyObject(slot->session,srcObject,NULL,0,
+				&destObject);
+    PK11_ExitSlotMonitor(slot);
+    if (crv == CKR_OK) return destObject;
+    PORT_SetError( PK11_MapError(crv) );
+    return CK_INVALID_HANDLE;
+}
+
+PRBool
+pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs,
+						CK_ATTRIBUTE_TYPE target)
+{
+    for (; numAttrs > 0; ++attr, --numAttrs) {
+    	if (attr->type == target)
+	    return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+	
+/*
+ * Recover the Signed data. We need this because our old verify can't
+ * figure out which hash algorithm to use until we decryptted this.
+ */
+SECStatus
+PK11_VerifyRecover(SECKEYPublicKey *key,
+			 	SECItem *sig, SECItem *dsig, void *wincx)
+{
+    PK11SlotInfo *slot = key->pkcs11Slot;
+    CK_OBJECT_HANDLE id = key->pkcs11ID;
+    CK_MECHANISM mech = {0, NULL, 0 };
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_ULONG len;
+    CK_RV crv;
+
+    mech.mechanism = PK11_MapSignKeyType(key->keyType);
+
+    if (slot == NULL) {
+	slot = PK11_GetBestSlot(mech.mechanism,wincx);
+	if (slot == NULL) {
+	    	PORT_SetError( SEC_ERROR_NO_MODULE );
+		return SECFailure;
+	}
+	id = PK11_ImportPublicKey(slot,key,PR_FALSE);
+    } else {
+	PK11_ReferenceSlot(slot);
+    }
+
+    if (id == CK_INVALID_HANDLE) {
+	PK11_FreeSlot(slot);
+	PORT_SetError( SEC_ERROR_BAD_KEY );
+	return SECFailure;
+    }
+
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session,&mech,id);
+    if (crv != CKR_OK) {
+	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+	pk11_CloseSession(slot,session,owner);
+	PORT_SetError( PK11_MapError(crv) );
+	PK11_FreeSlot(slot);
+	return SECFailure;
+    }
+    len = dsig->len;
+    crv = PK11_GETTAB(slot)->C_VerifyRecover(session,sig->data,
+						sig->len, dsig->data, &len);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    dsig->len = len;
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	PK11_FreeSlot(slot);
+	return SECFailure;
+    }
+    PK11_FreeSlot(slot);
+    return SECSuccess;
+}
+
+/*
+ * verify a signature from its hash.
+ */
+SECStatus
+PK11_Verify(SECKEYPublicKey *key, SECItem *sig, SECItem *hash, void *wincx)
+{
+    PK11SlotInfo *slot = key->pkcs11Slot;
+    CK_OBJECT_HANDLE id = key->pkcs11ID;
+    CK_MECHANISM mech = {0, NULL, 0 };
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_RV crv;
+
+    mech.mechanism = PK11_MapSignKeyType(key->keyType);
+
+    if (slot == NULL) {
+	slot = PK11_GetBestSlot(mech.mechanism,wincx);
+       
+	if (slot == NULL) {
+	    PORT_SetError( SEC_ERROR_NO_MODULE );
+	    return SECFailure;
+	}
+	id = PK11_ImportPublicKey(slot,key,PR_FALSE);
+            
+    } else {
+	PK11_ReferenceSlot(slot);
+    }
+
+    if (id == CK_INVALID_HANDLE) {
+	PK11_FreeSlot(slot);
+	PORT_SetError( SEC_ERROR_BAD_KEY );
+	return SECFailure;
+    }
+
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_VerifyInit(session,&mech,id);
+    if (crv != CKR_OK) {
+	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+	pk11_CloseSession(slot,session,owner);
+	PK11_FreeSlot(slot);
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_Verify(session,hash->data,
+					hash->len, sig->data, sig->len);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    PK11_FreeSlot(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * sign a hash. The algorithm is determined by the key.
+ */
+SECStatus
+PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash)
+{
+    PK11SlotInfo *slot = key->pkcs11Slot;
+    CK_MECHANISM mech = {0, NULL, 0 };
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_ULONG len;
+    CK_RV crv;
+
+    mech.mechanism = PK11_MapSignKeyType(key->keyType);
+
+    if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) {
+	PK11_HandlePasswordCheck(slot, key->wincx);
+    }
+
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID);
+    if (crv != CKR_OK) {
+	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+	pk11_CloseSession(slot,session,owner);
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    len = sig->len;
+    crv = PK11_GETTAB(slot)->C_Sign(session,hash->data,
+					hash->len, sig->data, &len);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    sig->len = len;
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * Now SSL 2.0 uses raw RSA stuff. These next to functions *must* use
+ * RSA keys, or they'll fail. We do the checks up front. If anyone comes
+ * up with a meaning for rawdecrypt for any other public key operation,
+ * then we need to move this check into some of PK11_PubDecrypt callers,
+ * (namely SSL 2.0).
+ */
+static SECStatus
+pk11_PrivDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, 
+	unsigned *outLen, unsigned int maxLen, unsigned char *enc,
+				    unsigned encLen, CK_MECHANISM_PTR mech)
+{
+    PK11SlotInfo *slot = key->pkcs11Slot;
+    CK_ULONG out = maxLen;
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_RV crv;
+
+    if (key->keyType != rsaKey) {
+	PORT_SetError( SEC_ERROR_INVALID_KEY );
+	return SECFailure;
+    }
+
+    /* Why do we do a PK11_handle check here? for simple
+     * decryption? .. because the user may have asked for 'ask always'
+     * and this is a private key operation. In practice, thought, it's mute
+     * since only servers wind up using this function */
+    if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) {
+	PK11_HandlePasswordCheck(slot, key->wincx);
+    }
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID);
+    if (crv != CKR_OK) {
+	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+	pk11_CloseSession(slot,session,owner);
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_Decrypt(session,enc, encLen, data, &out);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    *outLen = out;
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+SECStatus
+PK11_PubDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, 
+	unsigned *outLen, unsigned int maxLen, unsigned char *enc,
+				    unsigned encLen)
+{
+    CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 };
+    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
+}
+
+SECStatus
+PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key, unsigned char *data, 
+	unsigned *outLen, unsigned int maxLen, unsigned char *enc,
+				    unsigned encLen)
+{
+    CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 };
+    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
+}
+
+static SECStatus
+pk11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc,
+		    unsigned char *data, unsigned dataLen, 
+		    CK_MECHANISM_PTR mech, void *wincx)
+{
+    PK11SlotInfo *slot;
+    CK_OBJECT_HANDLE id;
+    CK_ULONG out;
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_RV crv;
+
+    if (!key || key->keyType != rsaKey) {
+	PORT_SetError( SEC_ERROR_BAD_KEY );
+	return SECFailure;
+    }
+    out = SECKEY_PublicKeyStrength(key);
+
+    slot = PK11_GetBestSlot(mech->mechanism, wincx);
+    if (slot == NULL) {
+	PORT_SetError( SEC_ERROR_NO_MODULE );
+	return SECFailure;
+    }
+
+    id = PK11_ImportPublicKey(slot,key,PR_FALSE);
+
+    if (id == CK_INVALID_HANDLE) {
+	PK11_FreeSlot(slot);
+	PORT_SetError( SEC_ERROR_BAD_KEY );
+	return SECFailure;
+    }
+
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id);
+    if (crv != CKR_OK) {
+	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+	pk11_CloseSession(slot,session,owner);
+	PK11_FreeSlot(slot);
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_Encrypt(session,data,dataLen,enc,&out);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    PK11_FreeSlot(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+SECStatus
+PK11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc,
+		unsigned char *data, unsigned dataLen, void *wincx)
+{
+    CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 };
+    return pk11_PubEncryptRaw(key, enc, data, dataLen, &mech, wincx);
+}
+
+SECStatus
+PK11_PubEncryptPKCS1(SECKEYPublicKey *key, unsigned char *enc,
+		unsigned char *data, unsigned dataLen, void *wincx)
+{
+    CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 };
+    return pk11_PubEncryptRaw(key, enc, data, dataLen, &mech, wincx);
+}
+
+SECKEYPrivateKey *
+PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
+		   CK_MECHANISM_TYPE wrapType, SECItem *param, 
+		   SECItem *wrappedKey, SECItem *label, 
+		   SECItem *idValue, PRBool perm, PRBool sensitive,
+		   CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage,
+		   int usageCount, void *wincx)
+{
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
+    CK_ATTRIBUTE keyTemplate[15] ;
+    int templateCount = 0;
+    CK_OBJECT_HANDLE privKeyID;
+    CK_MECHANISM mechanism;
+    CK_ATTRIBUTE *attrs = keyTemplate;
+    SECItem *param_free = NULL, *ck_id;
+    CK_RV crv;
+    CK_SESSION_HANDLE rwsession;
+    PK11SymKey *newKey = NULL;
+    int i;
+
+    if(!slot || !wrappedKey || !idValue) {
+	/* SET AN ERROR!!! */
+	return NULL;
+    }
+
+    ck_id = PK11_MakeIDFromPubKey(idValue);
+    if(!ck_id) {
+	return NULL;
+    }
+
+    PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse,
+					 sizeof(cktrue)); attrs++;
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++;
+    PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse,
+					 sizeof(cktrue)); attrs++;
+    PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse,
+					sizeof(cktrue)); attrs++;
+    if (label && label->data) {
+	PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); attrs++;
+    }
+    PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++;
+    for (i=0; i < usageCount; i++) {
+    	PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); attrs++;
+    }
+
+    if (PK11_IsInternal(slot)) {
+	PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, idValue->data, 
+		      idValue->len); attrs++;
+    }
+
+    templateCount = attrs - keyTemplate;
+    PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)) );
+
+    mechanism.mechanism = wrapType;
+    if(!param) param = param_free= PK11_ParamFromIV(wrapType, NULL);
+    if(param) {
+	mechanism.pParameter = param->data;
+	mechanism.ulParameterLen = param->len;
+    } else {
+	mechanism.pParameter = NULL;
+	mechanism.ulParameterLen = 0;
+    }
+
+    if (wrappingKey->slot != slot) {
+	newKey = pk11_CopyToSlot(slot,wrapType,CKA_UNWRAP,wrappingKey);
+    } else {
+	newKey = PK11_ReferenceSymKey(wrappingKey);
+    }
+
+    if (newKey) {
+	if (perm) {
+	    /* Get RW Session will either lock the monitor if necessary, 
+	     *  or return a thread safe session handle, or fail. */ 
+	    rwsession = PK11_GetRWSession(slot);
+	} else {
+	    rwsession = slot->session;
+	    if (rwsession != CK_INVALID_SESSION) 
+		PK11_EnterSlotMonitor(slot);
+	}
+	if (rwsession == CK_INVALID_SESSION) {
+	    PK11_FreeSymKey(newKey);
+	    PORT_SetError(SEC_ERROR_BAD_DATA);
+	    return NULL;
+	}
+	crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, 
+					 newKey->objectID,
+					 wrappedKey->data, 
+					 wrappedKey->len, keyTemplate, 
+					 templateCount, &privKeyID);
+
+	if (perm) {
+	    PK11_RestoreROSession(slot, rwsession);
+	} else {
+	    PK11_ExitSlotMonitor(slot);
+	}
+	PK11_FreeSymKey(newKey);
+    } else {
+	crv = CKR_FUNCTION_NOT_SUPPORTED;
+    }
+
+    if(ck_id) {
+	SECITEM_FreeItem(ck_id, PR_TRUE);
+	ck_id = NULL;
+    }
+
+    if (crv != CKR_OK) {
+	/* we couldn't unwrap the key, use the internal module to do the
+	 * unwrap, then load the new key into the token */
+	 PK11SlotInfo *int_slot = PK11_GetInternalSlot();
+
+	if (int_slot && (slot != int_slot)) {
+	    SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot,
+			wrappingKey, wrapType, param, wrappedKey, label,
+			idValue, PR_FALSE, PR_FALSE, 
+			keyType, usage, usageCount, wincx);
+	    if (privKey) {
+		SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot,privKey,
+						NULL,perm,sensitive);
+		SECKEY_DestroyPrivateKey(privKey);
+		PK11_FreeSlot(int_slot);
+		return newPrivKey;
+	    }
+	}
+	if (int_slot) PK11_FreeSlot(int_slot);
+	PORT_SetError( PK11_MapError(crv) );
+	return NULL;
+    }
+    return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx);
+}
+
+/*
+ * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey
+ * The strategy is to get both keys to reside in the same slot,
+ * one that can perform the desired crypto mechanism and then
+ * call C_WrapKey after all the setup has taken place.
+ */
+SECStatus
+PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, 
+		 SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, 
+		 SECItem *param, SECItem *wrappedKey, void *wincx)
+{
+    PK11SlotInfo     *privSlot   = privKey->pkcs11Slot; /* The slot where
+							 * the private key
+							 * we are going to
+							 * wrap lives.
+							 */
+    PK11SymKey       *newSymKey  = NULL;
+    SECKEYPrivateKey *newPrivKey = NULL;
+    SECItem          *param_free = NULL;
+    CK_ULONG          len        = wrappedKey->len;
+    CK_MECHANISM      mech;
+    CK_RV             crv;
+
+    if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) {
+        /* Figure out a slot that does the mechanism and try to import
+	 * the private key onto that slot.
+	 */
+        PK11SlotInfo *int_slot = PK11_GetInternalSlot();
+
+	privSlot = int_slot; /* The private key has a new home */
+	newPrivKey = PK11_LoadPrivKey(privSlot,privKey,NULL,PR_FALSE,PR_FALSE);
+	/* newPrivKey has allocated its own reference to the slot, so it's
+	 * safe until we destroy newPrivkey.
+	 */
+	PK11_FreeSlot(int_slot);
+	if (newPrivKey == NULL) {
+	    return SECFailure;
+	}
+	privKey = newPrivKey;
+    }
+
+    if (privSlot != wrappingKey->slot) {
+        newSymKey = pk11_CopyToSlot (privSlot, wrapType, CKA_WRAP, 
+				     wrappingKey);
+	wrappingKey = newSymKey;
+    }
+
+    if (wrappingKey == NULL) {
+        if (newPrivKey) {
+		SECKEY_DestroyPrivateKey(newPrivKey);
+	}
+	return SECFailure;
+    }
+    mech.mechanism = wrapType;
+    if (!param) {
+        param = param_free = PK11_ParamFromIV(wrapType, NULL);
+    }
+    if (param) {
+        mech.pParameter     = param->data;
+	mech.ulParameterLen = param->len;
+    } else {
+        mech.pParameter     = NULL;
+	mech.ulParameterLen = 0;
+    }
+
+    PK11_EnterSlotMonitor(privSlot);
+    crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech, 
+					   wrappingKey->objectID, 
+					   privKey->pkcs11ID,
+					   wrappedKey->data, &len);
+    PK11_ExitSlotMonitor(privSlot);
+
+    if (newSymKey) {
+        PK11_FreeSymKey(newSymKey);
+    }
+    if (newPrivKey) {
+        SECKEY_DestroyPrivateKey(newPrivKey);
+    }
+    if (param_free) {
+	SECITEM_FreeItem(param_free,PR_TRUE);
+    }
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+
+    wrappedKey->len = len;
+    return SECSuccess;
+}
+
+#if 0
+/*
+ * Sample code relating to linked list returned by PK11_FindGenericObjects
+ */
+
+/*
+ * You can walk the list with the following code:
+ */
+    firstObj = PK11_FindGenericObjects(slot, objClass);
+    for (thisObj=firstObj;
+         thisObj; 
+         thisObj=PK11_GetNextGenericObject(thisObj)) {
+        /* operate on thisObj */
+    }
+/*
+ * If you want a particular object from the list...
+ */
+    firstObj = PK11_FindGenericObjects(slot, objClass);
+    for (thisObj=firstObj;
+         thisObj; 
+         thisObj=PK11_GetNextGenericObject(thisObj)) {
+   	if (isMyObj(thisObj)) {
+  	    if ( thisObj == firstObj) {
+                /* NOTE: firstObj could be NULL at this point */
+  		firstObj = PK11_GetNextGenericObject(thsObj); 
+  	    }
+  	    PK11_UnlinkGenericObject(thisObj);
+            myObj = thisObj;
+            break;
+        }
+    }
+
+    PK11_DestroyGenericObjects(firstObj);
+
+      /* use myObj */
+
+    PK11_DestroyGenericObject(myObj);
+#endif /* sample code */
+
+/*
+ * return a linked, non-circular list of generic objects.
+ * If you are only interested
+ * in one object, just use the first object in the list. To find the
+ * rest of the list use PK11_GetNextGenericObject() to return the next object.
+ */
+PK11GenericObject *
+PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass)
+{
+    CK_ATTRIBUTE template[1];
+    CK_ATTRIBUTE *attrs = template;
+    CK_OBJECT_HANDLE *objectIDs = NULL;
+    PK11GenericObject *lastObj = NULL, *obj;
+    PK11GenericObject *firstObj = NULL;
+    int i, count = 0;
+
+
+    PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++;
+
+    objectIDs = pk11_FindObjectsByTemplate(slot,template,1,&count);
+    if (objectIDs == NULL) {
+	return NULL;
+    }
+
+    /* where we connect our object once we've created it.. */
+    for (i=0; i < count; i++) {
+	obj = PORT_New(PK11GenericObject);
+	if ( !obj ) {
+	    if (firstObj) {
+		PK11_DestroyGenericObjects(firstObj);
+	    }
+	    PORT_Free(objectIDs);
+	    return NULL;
+	}
+	/* initialize it */	
+	obj->slot = PK11_ReferenceSlot(slot);
+	obj->objectID = objectIDs[i];
+	obj->next = NULL;
+	obj->prev = NULL;
+
+	/* link it in */
+	if (firstObj == NULL) {
+	    firstObj = obj;
+	} else {
+	    PK11_LinkGenericObject(lastObj, obj);
+	}
+	lastObj = obj;
+    }
+    PORT_Free(objectIDs);
+    return firstObj;
+}
+
+/*
+ * get the Next Object in the list.
+ */
+PK11GenericObject *
+PK11_GetNextGenericObject(PK11GenericObject *object)
+{
+    return object->next;
+}
+
+PK11GenericObject *
+PK11_GetPrevGenericObject(PK11GenericObject *object)
+{
+    return object->prev;
+}
+
+/*
+ * Link a single object into a new list.
+ * if the object is already in another list, remove it first.
+ */
+SECStatus
+PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object)
+{
+    PK11_UnlinkGenericObject(object);
+    object->prev = list;
+    object->next = list->next;
+    list->next = object;
+    if (object->next != NULL) {
+	object->next->prev = object;
+    }
+   return SECSuccess;
+}
+
+/*
+ * remove an object from the list. If the object isn't already in
+ * a list unlink becomes a noop.
+ */
+SECStatus
+PK11_UnlinkGenericObject(PK11GenericObject *object)
+{
+    if (object->prev != NULL) {
+	object->prev->next = object->next;
+    }
+    if (object->next != NULL) {
+	object->next->prev = object->prev;
+    }
+
+    object->next = NULL;
+    object->prev = NULL;
+    return SECSuccess;
+}
+
+/*
+ * This function removes a single object from the list and destroys it.
+ * For an already unlinked object there is no difference between
+ * PK11_DestroyGenericObject and PK11_DestroyGenericObjects
+ */
+SECStatus 
+PK11_DestroyGenericObject(PK11GenericObject *object)
+{
+    if (object == NULL) {
+	return SECSuccess;
+    }
+
+    PK11_UnlinkGenericObject(object);
+    if (object->slot) {
+	PK11_FreeSlot(object->slot);
+    }
+    PORT_Free(object);
+    return SECSuccess;
+}
+
+/*
+ * walk down a link list of generic objects destroying them.
+ * This will destroy all objects in a list that the object is linked into.
+ * (the list is traversed in both directions).
+ */
+SECStatus 
+PK11_DestroyGenericObjects(PK11GenericObject *objects)
+{
+    PK11GenericObject *nextObject;
+    PK11GenericObject *prevObject;
+ 
+    if (objects == NULL) {
+	return SECSuccess;
+    }
+
+    nextObject = objects->next;
+    prevObject = objects->prev;
+
+    /* delete all the objects after it in the list */
+    for (; objects;  objects = nextObject) {
+	nextObject = objects->next;
+	PK11_DestroyGenericObject(objects);
+    }
+    /* delete all the objects before it in the list */
+    for (objects = prevObject; objects;  objects = prevObject) {
+	prevObject = objects->prev;
+	PK11_DestroyGenericObject(objects);
+    }
+    return SECSuccess;
+}
+
+
+/*
+ * Hand Create a new object and return the Generic object for our new object.
+ */
+PK11GenericObject *
+PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate,
+		int count,  PRBool token)
+{
+    CK_OBJECT_HANDLE objectID;
+    PK11GenericObject *obj;
+    CK_RV crv;
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count, 
+			       token, &objectID);
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return NULL;
+    }
+
+    obj = PORT_New(PK11GenericObject);
+    if ( !obj ) {
+	/* error set by PORT_New */
+	return NULL;
+    }
+
+    /* initialize it */	
+    obj->slot = PK11_ReferenceSlot(slot);
+    obj->objectID = objectID;
+    obj->next = NULL;
+    obj->prev = NULL;
+    return obj;
+}
+
+/*
+ * Change an attribute on a raw object
+ */
+SECStatus
+PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec, 
+				CK_ATTRIBUTE_TYPE attrType, SECItem *item)
+{
+    PK11SlotInfo *slot = NULL;
+    CK_OBJECT_HANDLE handle;
+    CK_ATTRIBUTE setTemplate;
+    CK_RV crv;
+    CK_SESSION_HANDLE rwsession;
+
+    switch (objType) {
+    case PK11_TypeGeneric:
+	slot = ((PK11GenericObject *)objSpec)->slot;
+	handle = ((PK11GenericObject *)objSpec)->objectID;
+	break;
+    case PK11_TypePrivKey:
+	slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
+	handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
+	break;
+    case PK11_TypePubKey:
+	slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
+	handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
+	break;
+    case PK11_TypeSymKey:
+	slot = ((PK11SymKey *)objSpec)->slot;
+	handle = ((PK11SymKey *)objSpec)->objectID;
+	break;
+    case PK11_TypeCert: /* don't handle cert case for now */
+    default:
+	break;
+    }
+    if (slot == NULL) {
+	PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
+	return SECFailure;
+    }
+
+    PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *) item->data, item->len);
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+    	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle,
+			&setTemplate, 1);
+    PK11_RestoreROSession(slot, rwsession);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+SECStatus
+PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec, 
+				CK_ATTRIBUTE_TYPE attrType, SECItem *item)
+{
+    PK11SlotInfo *slot = NULL;
+    CK_OBJECT_HANDLE handle;
+
+    switch (objType) {
+    case PK11_TypeGeneric:
+	slot = ((PK11GenericObject *)objSpec)->slot;
+	handle = ((PK11GenericObject *)objSpec)->objectID;
+	break;
+    case PK11_TypePrivKey:
+	slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
+	handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
+	break;
+    case PK11_TypePubKey:
+	slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
+	handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
+	break;
+    case PK11_TypeSymKey:
+	slot = ((PK11SymKey *)objSpec)->slot;
+	handle = ((PK11SymKey *)objSpec)->objectID;
+	break;
+    case PK11_TypeCert: /* don't handle cert case for now */
+    default:
+	break;
+    }
+    if (slot == NULL) {
+	PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
+	return SECFailure;
+    }
+
+    return PK11_ReadAttribute(slot, handle, attrType, NULL, item);
+}
+
+
+/*
+ * return the object handle that matches the template
+ */
+CK_OBJECT_HANDLE
+pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize)
+{
+    CK_OBJECT_HANDLE object;
+    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
+    CK_ULONG objectCount;
+
+    /*
+     * issue the find
+     */
+    PK11_EnterSlotMonitor(slot);
+    if (slot->session != CK_INVALID_SESSION) {
+	crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, 
+	                                           theTemplate, tsize);
+    }
+    if (crv != CKR_OK) {
+        PK11_ExitSlotMonitor(slot);
+	PORT_SetError( PK11_MapError(crv) );
+	return CK_INVALID_HANDLE;
+    }
+
+    crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount);
+    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
+    PK11_ExitSlotMonitor(slot);
+    if ((crv != CKR_OK) || (objectCount < 1)) {
+	/* shouldn't use SSL_ERROR... here */
+	PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) :
+						  SSL_ERROR_NO_CERTIFICATE);
+	return CK_INVALID_HANDLE;
+    }
+
+    /* blow up if the PKCS #11 module returns us and invalid object handle */
+    PORT_Assert(object != CK_INVALID_HANDLE);
+    return object;
+} 
+
+/*
+ * return all the object handles that matches the template
+ */
+CK_OBJECT_HANDLE *
+pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
+                           int templCount, int *object_count) 
+{
+    CK_OBJECT_HANDLE *objID = NULL;
+    CK_ULONG returned_count = 0;
+    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
+
+    PK11_EnterSlotMonitor(slot);
+    if (slot->session != CK_INVALID_SESSION) {
+	crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, 
+	                                           findTemplate, templCount);
+    }
+    if (crv != CKR_OK) {
+	PK11_ExitSlotMonitor(slot);
+	PORT_SetError( PK11_MapError(crv) );
+	*object_count = -1;
+	return NULL;
+    }
+
+
+    /*
+     * collect all the Matching Objects
+     */
+    do {
+	CK_OBJECT_HANDLE *oldObjID = objID;
+
+	if (objID == NULL) {
+    	    objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)*
+				(*object_count+ PK11_SEARCH_CHUNKSIZE));
+	} else {
+    	    objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID,
+		sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE));
+	}
+
+	if (objID == NULL) {
+	    if (oldObjID) PORT_Free(oldObjID);
+	    break;
+	}
+    	crv = PK11_GETTAB(slot)->C_FindObjects(slot->session,
+		&objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count);
+	if (crv != CKR_OK) {
+	    PORT_SetError( PK11_MapError(crv) );
+	    PORT_Free(objID);
+	    objID = NULL;
+	    break;
+    	}
+	*object_count += returned_count;
+    } while (returned_count == PK11_SEARCH_CHUNKSIZE);
+
+    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
+    PK11_ExitSlotMonitor(slot);
+
+    if (objID && (*object_count == 0)) {
+	PORT_Free(objID);
+	return NULL;
+    }
+    if (objID == NULL) *object_count = -1;
+    return objID;
+}
+/*
+ * given a PKCS #11 object, match it's peer based on the KeyID. searchID
+ * is typically a privateKey or a certificate while the peer is the opposite
+ */
+CK_OBJECT_HANDLE
+PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID,
+				 		CK_OBJECT_CLASS matchclass)
+{
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_ID, NULL, 0 },
+	{ CKA_CLASS, NULL, 0 }
+    };
+    /* if you change the array, change the variable below as well */
+    CK_ATTRIBUTE *keyclass = &theTemplate[1];
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    /* if you change the array, change the variable below as well */
+    CK_OBJECT_HANDLE peerID;
+    CK_OBJECT_HANDLE parent;
+    PRArenaPool *arena;
+    CK_RV crv;
+
+    /* now we need to create space for the public key */
+    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) return CK_INVALID_HANDLE;
+
+    crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize);
+    if (crv != CKR_OK) {
+	PORT_FreeArena(arena,PR_FALSE);
+	PORT_SetError( PK11_MapError(crv) );
+	return CK_INVALID_HANDLE;
+    }
+
+    if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
+	PORT_FreeArena(arena,PR_FALSE);
+	if (matchclass == CKO_CERTIFICATE)
+	    PORT_SetError(SEC_ERROR_BAD_KEY);
+	else
+	    PORT_SetError(SEC_ERROR_NO_KEY);
+	return CK_INVALID_HANDLE;
+     }
+	
+	
+
+    /*
+     * issue the find
+     */
+    parent = *(CK_OBJECT_CLASS *)(keyclass->pValue);
+    *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;
+
+    peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
+    PORT_FreeArena(arena,PR_FALSE);
+
+    return peerID;
+}
+
+/*
+ * count the number of objects that match the template.
+ */
+int
+PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, 
+							int templCount)
+{
+    CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE];
+    int object_count = 0;
+    CK_ULONG returned_count = 0;
+    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
+
+    PK11_EnterSlotMonitor(slot);
+    if (slot->session != CK_INVALID_SESSION) {
+	crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
+						   findTemplate, templCount);
+    }
+    if (crv != CKR_OK) {
+        PK11_ExitSlotMonitor(slot);
+	PORT_SetError( PK11_MapError(crv) );
+	return object_count;
+    }
+
+    /*
+     * collect all the Matching Objects
+     */
+    do {
+    	crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID, 
+	                                       PK11_SEARCH_CHUNKSIZE, 
+					       &returned_count);
+	if (crv != CKR_OK) {
+	    PORT_SetError( PK11_MapError(crv) );
+	    break;
+    	}
+	object_count += returned_count;
+    } while (returned_count == PK11_SEARCH_CHUNKSIZE);
+
+    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
+    PK11_ExitSlotMonitor(slot);
+    return object_count;
+}
+
+/*
+ * Traverse all the objects in a given slot.
+ */
+SECStatus
+PK11_TraverseSlot(PK11SlotInfo *slot, void *arg)
+{
+    int i;
+    CK_OBJECT_HANDLE *objID = NULL;
+    int object_count = 0;
+    pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg;
+
+    objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate,
+		slotcb->templateCount,&object_count);
+
+    /*Actually this isn't a failure... there just were no objs to be found*/
+    if (object_count == 0) {
+	return SECSuccess;
+    }
+
+    if (objID == NULL) {
+	return SECFailure;
+    }
+
+    for (i=0; i < object_count; i++) {
+	(*slotcb->callback)(slot,objID[i],slotcb->callbackArg);
+    }
+    PORT_Free(objID);
+    return SECSuccess;
+}
+
+/*
+ * Traverse all the objects in all slots.
+ */
+SECStatus
+pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), 
+				void *arg, PRBool forceLogin, void *wincx) {
+    PK11SlotList *list;
+    PK11SlotListElement *le;
+    SECStatus rv;
+
+    /* get them all! */
+    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx);
+    if (list == NULL) return SECFailure;
+
+    /* look at each slot and authenticate as necessary */
+    for (le = list->head ; le; le = le->next) {
+	if (forceLogin) {
+	    rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx);
+	    if (rv != SECSuccess) {
+		continue;
+	    }
+	}
+	if (callback) {
+	    (*callback)(le->slot,arg);
+	}
+    }
+
+    PK11_FreeSlotList(list);
+
+    return SECSuccess;
+}
+
+CK_OBJECT_HANDLE *
+PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr,
+		CK_OBJECT_CLASS objclass, int *returnCount, void *wincx)
+{
+    char *tokenName;
+    char *delimit;
+    PK11SlotInfo *slot;
+    CK_OBJECT_HANDLE *objID;
+    CK_ATTRIBUTE findTemplate[] = {
+	 { CKA_LABEL, NULL, 0},
+	 { CKA_CLASS, NULL, 0},
+    };
+    int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]);
+    SECStatus rv;
+    PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass));
+
+    *slotptr = slot = NULL;
+    *returnCount = 0;
+    /* first find the slot associated with this nickname */
+    if ((delimit = PORT_Strchr(nickname,':')) != NULL) {
+	int len = delimit - nickname;
+	tokenName = (char*)PORT_Alloc(len+1);
+	PORT_Memcpy(tokenName,nickname,len);
+	tokenName[len] = 0;
+
+        slot = *slotptr = PK11_FindSlotByName(tokenName);
+        PORT_Free(tokenName);
+	/* if we couldn't find a slot, assume the nickname is an internal cert
+	 * with no proceding slot name */
+	if (slot == NULL) {
+		slot = *slotptr = PK11_GetInternalKeySlot();
+	} else {
+		nickname = delimit+1;
+	}
+    } else {
+	*slotptr = slot = PK11_GetInternalKeySlot();
+    }
+    if (slot == NULL) {
+        return CK_INVALID_HANDLE;
+    }
+
+    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
+    if (rv != SECSuccess) {
+	PK11_FreeSlot(slot);
+	*slotptr = NULL;
+	return CK_INVALID_HANDLE;
+    }
+
+    findTemplate[0].pValue = nickname;
+    findTemplate[0].ulValueLen = PORT_Strlen(nickname);
+    objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount);
+    if (objID == NULL) {
+	/* PKCS #11 isn't clear on whether or not the NULL is
+	 * stored in the template.... try the find again with the
+	 * full null terminated string. */
+    	findTemplate[0].ulValueLen += 1;
+        objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,
+								returnCount);
+	if (objID == NULL) {
+	    /* Well that's the best we can do. It's just not here */
+	    /* what about faked nicknames? */
+	    PK11_FreeSlot(slot);
+	    *slotptr = NULL;
+	    *returnCount = 0;
+	}
+    }
+
+    return objID;
+}
+
+SECItem *
+pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) 
+{
+    CK_ATTRIBUTE theTemplate[] = {
+	{ CKA_ID, NULL, 0 },
+    };
+    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
+    CK_RV crv;
+    SECItem *item;
+
+    item = SECITEM_AllocItem(NULL, NULL, 0);
+
+    if (item == NULL) {
+	return NULL;
+    }
+
+    crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize);
+    if (crv != CKR_OK) {
+	SECITEM_FreeItem(item,PR_TRUE);
+	PORT_SetError( PK11_MapError(crv) );
+	return NULL;
+    }
+
+    item->data = (unsigned char*) theTemplate[0].pValue;
+    item->len =theTemplate[0].ulValueLen;
+
+    return item;
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11pars.c b/mozilla/security/nss/lib/pk11wrap/pk11pars.c
new file mode 100644
index 0000000..c36cd25
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11pars.c
@@ -0,0 +1,1226 @@
+/* ***** 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) 2001
+ * 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 ***** */
+/*
+ * The following handles the loading, unloading and management of
+ * various PCKS #11 modules
+ */
+
+#include <ctype.h>
+#include "pkcs11.h"
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pki3hack.h"
+#include "secerr.h"
+   
+#include "pk11pars.h" 
+
+/* create a new module */
+static  SECMODModule *
+secmod_NewModule(void)
+{
+    SECMODModule *newMod;
+    PRArenaPool *arena;
+
+
+    /* create an arena in which dllName and commonName can be
+     * allocated.
+     */
+    arena = PORT_NewArena(512);
+    if (arena == NULL) {
+	return NULL;
+    }
+
+    newMod = (SECMODModule *)PORT_ArenaAlloc(arena,sizeof (SECMODModule));
+    if (newMod == NULL) {
+	PORT_FreeArena(arena,PR_FALSE);
+	return NULL;
+    }
+
+    /*
+     * initialize of the fields of the module
+     */
+    newMod->arena = arena;
+    newMod->internal = PR_FALSE;
+    newMod->loaded = PR_FALSE;
+    newMod->isFIPS = PR_FALSE;
+    newMod->dllName = NULL;
+    newMod->commonName = NULL;
+    newMod->library = NULL;
+    newMod->functionList = NULL;
+    newMod->slotCount = 0;
+    newMod->slots = NULL;
+    newMod->slotInfo = NULL;
+    newMod->slotInfoCount = 0;
+    newMod->refCount = 1;
+    newMod->ssl[0] = 0;
+    newMod->ssl[1] = 0;
+    newMod->libraryParams = NULL;
+    newMod->moduleDBFunc = NULL;
+    newMod->parent = NULL;
+    newMod->isCritical = PR_FALSE;
+    newMod->isModuleDB = PR_FALSE;
+    newMod->moduleDBOnly = PR_FALSE;
+    newMod->trustOrder = 0;
+    newMod->cipherOrder = 0;
+    newMod->evControlMask = 0;
+    newMod->refLock = PZ_NewLock(nssILockRefLock);
+    if (newMod->refLock == NULL) {
+	PORT_FreeArena(arena,PR_FALSE);
+	return NULL;
+    }
+    return newMod;
+    
+}
+
+/* private flags for isModuleDB (field in SECMODModule). */
+/* The meaing of these flags is as follows:
+ *
+ * SECMOD_FLAG_MODULE_DB_IS_MODULE_DB - This is a module that accesses the 
+ *   database of other modules to load. Module DBs are loadable modules that
+ *   tells NSS which PKCS #11 modules to load and when. These module DBs are 
+ *   chainable. That is, one module DB can load another one. NSS system init 
+ *   design takes advantage of this feature. In system NSS, a fixed system 
+ *   module DB loads the system defined libraries, then chains out to the 
+ *   traditional module DBs to load any system or user configured modules 
+ *   (like smart cards). This bit is the same as the already existing meaning 
+ *   of  isModuleDB = PR_TRUE. None of the other module db flags should be set 
+ *   if this flag isn't on.
+ *
+ * SECMOD_FLAG_MODULE_DB_SKIP_FIRST - This flag tells NSS to skip the first 
+ *   PKCS #11 module presented by a module DB. This allows the OS to load a 
+ *   softoken from the system module, then ask the existing module DB code to 
+ *   load the other PKCS #11 modules in that module DB (skipping it's request 
+ *   to load softoken). This gives the system init finer control over the 
+ *   configuration of that softoken module.
+ *
+ * SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB - This flag allows system init to mark a 
+ *   different module DB as the 'default' module DB (the one in which 
+ *   'Add module' changes will go). Without this flag NSS takes the first 
+ *   module as the default Module DB, but in system NSS, that first module 
+ *   is the system module, which is likely read only (at least to the user).
+ *   This  allows system NSS to delegate those changes to the user's module DB, 
+ *   preserving the user's ability to load new PKCS #11 modules (which only 
+ *   affect him), from existing applications like Firefox.
+ */
+#define SECMOD_FLAG_MODULE_DB_IS_MODULE_DB  0x01 /* must be set if any of the 
+						  *other flags are set */
+#define SECMOD_FLAG_MODULE_DB_SKIP_FIRST    0x02
+#define SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB 0x04
+
+
+/* private flags for internal (field in SECMODModule). */
+/* The meaing of these flags is as follows:
+ *
+ * SECMOD_FLAG_INTERNAL_IS_INTERNAL - This is a marks the the module is
+ *   the internal module (that is, softoken). This bit is the same as the 
+ *   already existing meaning of internal = PR_TRUE. None of the other 
+ *   internal flags should be set if this flag isn't on.
+ *
+ * SECMOD_FLAG_MODULE_INTERNAL_KEY_SLOT - This flag allows system init to mark 
+ *   a  different slot returned byt PK11_GetInternalKeySlot(). The 'primary'
+ *   slot defined by this module will be the new internal key slot.
+ */
+#define SECMOD_FLAG_INTERNAL_IS_INTERNAL       0x01 /* must be set if any of 
+						     *the other flags are set */
+#define SECMOD_FLAG_INTERNAL_KEY_SLOT          0x02
+
+/*
+ * for 3.4 we continue to use the old SECMODModule structure
+ */
+SECMODModule *
+SECMOD_CreateModule(const char *library, const char *moduleName, 
+				const char *parameters, const char *nss)
+{
+    SECMODModule *mod = secmod_NewModule();
+    char *slotParams,*ciphers;
+    /* pk11pars.h still does not have const char * interfaces */
+    char *nssc = (char *)nss;
+    if (mod == NULL) return NULL;
+
+    mod->commonName = PORT_ArenaStrdup(mod->arena,moduleName ? moduleName : "");
+    if (library) {
+	mod->dllName = PORT_ArenaStrdup(mod->arena,library);
+    }
+    /* new field */
+    if (parameters) {
+	mod->libraryParams = PORT_ArenaStrdup(mod->arena,parameters);
+    }
+    mod->internal   = secmod_argHasFlag("flags","internal",nssc);
+    mod->isFIPS     = secmod_argHasFlag("flags","FIPS",nssc);
+    mod->isCritical = secmod_argHasFlag("flags","critical",nssc);
+    slotParams      = secmod_argGetParamValue("slotParams",nssc);
+    mod->slotInfo   = secmod_argParseSlotInfo(mod->arena,slotParams,
+							&mod->slotInfoCount);
+    if (slotParams) PORT_Free(slotParams);
+    /* new field */
+    mod->trustOrder  = secmod_argReadLong("trustOrder",nssc,
+					SECMOD_DEFAULT_TRUST_ORDER,NULL);
+    /* new field */
+    mod->cipherOrder = secmod_argReadLong("cipherOrder",nssc,
+					SECMOD_DEFAULT_CIPHER_ORDER,NULL);
+    /* new field */
+    mod->isModuleDB   = secmod_argHasFlag("flags","moduleDB",nssc);
+    mod->moduleDBOnly = secmod_argHasFlag("flags","moduleDBOnly",nssc);
+    if (mod->moduleDBOnly) mod->isModuleDB = PR_TRUE;
+
+    /* we need more bits, but we also want to preserve binary compatibility 
+     * so we overload the isModuleDB PRBool with additional flags. 
+     * These flags are only valid if mod->isModuleDB is already set.
+     * NOTE: this depends on the fact that PRBool is at least a char on 
+     * all platforms. These flags are only valid if moduleDB is set, so 
+     * code checking if (mod->isModuleDB) will continue to work correctly. */
+    if (mod->isModuleDB) {
+	char flags = SECMOD_FLAG_MODULE_DB_IS_MODULE_DB;
+	if (secmod_argHasFlag("flags","skipFirst",nssc)) {
+	    flags |= SECMOD_FLAG_MODULE_DB_SKIP_FIRST;
+	}
+	if (secmod_argHasFlag("flags","defaultModDB",nssc)) {
+	    flags |= SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB;
+	}
+	/* additional moduleDB flags could be added here in the future */
+	mod->isModuleDB = (PRBool) flags;
+    }
+
+    if (mod->internal) {
+	char flags = SECMOD_FLAG_INTERNAL_IS_INTERNAL;
+
+	if (secmod_argHasFlag("flags", "internalKeySlot", nssc)) {
+	    flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT;
+	}
+	mod->internal = (PRBool) flags;
+    }
+
+    ciphers = secmod_argGetParamValue("ciphers",nssc);
+    secmod_argSetNewCipherFlags(&mod->ssl[0],ciphers);
+    if (ciphers) PORT_Free(ciphers);
+
+    secmod_PrivateModuleCount++;
+
+    return mod;
+}
+
+PRBool
+SECMOD_GetSkipFirstFlag(SECMODModule *mod)
+{
+   char flags = (char) mod->isModuleDB;
+
+   return (flags & SECMOD_FLAG_MODULE_DB_SKIP_FIRST) ? PR_TRUE : PR_FALSE;
+}
+
+PRBool
+SECMOD_GetDefaultModDBFlag(SECMODModule *mod)
+{
+   char flags = (char) mod->isModuleDB;
+
+   return (flags & SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB) ? PR_TRUE : PR_FALSE;
+}
+
+PRBool
+secmod_IsInternalKeySlot(SECMODModule *mod)
+{
+   char flags = (char) mod->internal;
+
+   return (flags & SECMOD_FLAG_INTERNAL_KEY_SLOT) ? PR_TRUE : PR_FALSE;
+}
+
+/* forward declarations */
+static int secmod_escapeSize(const char *string, char quote);
+static char *secmod_addEscape(const char *string, char quote);
+
+/*
+ * copy desc and value into target. Target is known to be big enough to
+ * hold desc +2 +value, which is good because the result of this will be
+ * *desc"*value". We may, however, have to add some escapes for special
+ * characters imbedded into value (rare). This string potentially comes from
+ * a user, so we don't want the user overflowing the target buffer by using
+ * excessive escapes. To prevent this we count the escapes we need to add and
+ * try to expand the buffer with Realloc.
+ */
+static char *
+secmod_doDescCopy(char *target, int *targetLen, const char *desc,
+			int descLen, char *value)
+{
+    int diff, esc_len;
+
+    esc_len = secmod_escapeSize(value, '\"') - 1;
+    diff = esc_len - strlen(value);
+    if (diff > 0) {
+	/* we need to escape... expand newSpecPtr as well to make sure
+	 * we don't overflow it */
+	char *newPtr = PORT_Realloc(target, *targetLen * diff);
+	if (!newPtr) {
+	    return target; /* not enough space, just drop the whole copy */
+	}
+	*targetLen += diff;
+	target = newPtr;
+	value = secmod_addEscape(value, '\"');
+	if (value == NULL) {
+	    return target; /* couldn't escape value, just drop the copy */
+	}
+    }
+    PORT_Memcpy(target, desc, descLen);
+    target += descLen;
+    *target++='\"';
+    PORT_Memcpy(target, value, esc_len);
+    target += esc_len;
+    *target++='\"';
+    return target;
+}
+
+#define SECMOD_SPEC_COPY(new, start, end)    \
+  if (end > start) {                         \
+	int _cnt = end - start;	             \
+	PORT_Memcpy(new, start, _cnt);       \
+	new += _cnt;                         \
+  }
+#define SECMOD_TOKEN_DESCRIPTION "tokenDescription="
+#define SECMOD_SLOT_DESCRIPTION   "slotDescription="
+
+
+/*
+ * Find any tokens= values in the module spec. 
+ * Always return a new spec which does not have any tokens= arguments.
+ * If tokens= arguments are found, Split the the various tokens defined into
+ * an array of child specs to return.
+ *
+ * Caller is responsible for freeing the child spec and the new token
+ * spec.
+ */
+char *
+secmod_ParseModuleSpecForTokens(PRBool convert, PRBool isFIPS, 
+				char *moduleSpec, char ***children, 
+				CK_SLOT_ID **ids)
+{
+    int        newSpecLen   = PORT_Strlen(moduleSpec)+2;
+    char       *newSpec     = PORT_Alloc(newSpecLen);
+    char       *newSpecPtr  = newSpec;
+    char       *modulePrev  = moduleSpec;
+    char       *target      = NULL;
+    char *tmp = NULL;
+    char       **childArray = NULL;
+    char       *tokenIndex;
+    CK_SLOT_ID *idArray     = NULL;
+    int        tokenCount = 0;
+    int        i;
+
+    if (newSpec == NULL) {
+	return NULL;
+    }
+
+    *children = NULL;
+    if (ids) {
+	*ids = NULL;
+    }
+    moduleSpec = secmod_argStrip(moduleSpec);
+    SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
+
+    /* Notes on 'convert' and 'isFIPS' flags: The base parameters for opening 
+     * a new softoken module takes the following parameters to name the 
+     * various tokens:
+     *  
+     *  cryptoTokenDescription: name of the non-fips crypto token.
+     *  cryptoSlotDescription: name of the non-fips crypto slot.
+     *  dbTokenDescription: name of the non-fips db token.
+     *  dbSlotDescription: name of the non-fips db slot.
+     *  FIPSTokenDescription: name of the fips db/crypto token.
+     *  FIPSSlotDescription: name of the fips db/crypto slot.
+     *
+     * if we are opening a new slot, we need to have the following
+     * parameters:
+     *  tokenDescription: name of the token.
+     *  slotDescription: name of the slot.
+     *
+     *
+     * The convert flag tells us to drop the unnecessary *TokenDescription 
+     * and *SlotDescription arguments and convert the appropriate pair 
+     * (either db or FIPS based on the isFIPS flag) to tokenDescription and 
+     * slotDescription).
+     */
+    /*
+     * walk down the list. if we find a tokens= argument, save it,
+     * otherise copy the argument.
+     */
+    while (*moduleSpec) {
+	int next;
+	modulePrev = moduleSpec;
+	SECMOD_HANDLE_STRING_ARG(moduleSpec, target, "tokens=",
+			modulePrev = moduleSpec; /* skip copying */ )
+	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoTokenDescription=",
+			if (convert) { modulePrev = moduleSpec; } );
+	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoSlotDescription=",
+			if (convert) { modulePrev = moduleSpec; } );
+	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "dbTokenDescription=",
+			if (convert) {
+			    modulePrev = moduleSpec; 
+			    if (!isFIPS) {
+				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
+				    &newSpecLen, SECMOD_TOKEN_DESCRIPTION, 
+				    sizeof(SECMOD_TOKEN_DESCRIPTION)-1, tmp);
+			    }
+			});
+	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "dbSlotDescription=",
+			if (convert) {
+			    modulePrev = moduleSpec; /* skip copying */ 
+			    if (!isFIPS) {
+				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
+				    &newSpecLen, SECMOD_SLOT_DESCRIPTION, 
+				    sizeof(SECMOD_SLOT_DESCRIPTION)-1, tmp);
+			    }
+			} );
+	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSTokenDescription=",
+			if (convert) {
+			    modulePrev = moduleSpec; /* skip copying */ 
+			    if (isFIPS) {
+				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
+				    &newSpecLen, SECMOD_TOKEN_DESCRIPTION, 
+				    sizeof(SECMOD_TOKEN_DESCRIPTION)-1, tmp);
+			    }
+			} );
+	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSSlotDescription=",
+			if (convert) {
+			    modulePrev = moduleSpec; /* skip copying */ 
+			    if (isFIPS) {
+				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
+				    &newSpecLen, SECMOD_SLOT_DESCRIPTION, 
+				    sizeof(SECMOD_SLOT_DESCRIPTION)-1, tmp);
+			    }
+			} );
+	SECMOD_HANDLE_FINAL_ARG(moduleSpec)
+	SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
+    }
+    if (tmp) {
+	PORT_Free(tmp);
+	tmp = NULL;
+    }
+    *newSpecPtr = 0;
+
+    /* no target found, return the newSpec */
+    if (target == NULL) {
+	return newSpec;
+    }
+
+    /* now build the child array from target */
+    /*first count them */
+    for (tokenIndex = secmod_argStrip(target); *tokenIndex;
+	tokenIndex = secmod_argStrip(secmod_argSkipParameter(tokenIndex))) {
+	tokenCount++;
+    }
+
+    childArray = PORT_NewArray(char *, tokenCount+1);
+    if (childArray == NULL) {
+	/* just return the spec as is then */
+	PORT_Free(target);
+	return newSpec;
+    }
+    if (ids) {
+	idArray = PORT_NewArray(CK_SLOT_ID, tokenCount+1);
+	if (idArray == NULL) {
+	    PORT_Free(childArray);
+	    PORT_Free(target);
+	    return newSpec;
+	}
+    }
+
+    /* now fill them in */
+    for (tokenIndex = secmod_argStrip(target), i=0 ; 
+			*tokenIndex && (i < tokenCount); 
+			tokenIndex=secmod_argStrip(tokenIndex)) {
+	int next;
+	char *name = secmod_argGetName(tokenIndex, &next);
+	tokenIndex += next;
+
+ 	if (idArray) {
+	   idArray[i] = secmod_argDecodeNumber(name);
+	}
+
+	PORT_Free(name); /* drop the explicit number */
+
+	/* if anything is left, copy the args to the child array */
+	if (!secmod_argIsBlank(*tokenIndex)) {
+	    childArray[i++] = secmod_argFetchValue(tokenIndex, &next);
+	    tokenIndex += next;
+	}
+    }
+
+    PORT_Free(target);
+    childArray[i] = 0;
+    if (idArray) {
+	idArray[i] = 0;
+    }
+
+    /* return it */
+    *children = childArray;
+    if (ids) {
+	*ids = idArray;
+    }
+    return newSpec;
+}
+
+/* get the database and flags from the spec */
+static char *
+secmod_getConfigDir(char *spec, char **certPrefix, char **keyPrefix,
+			  PRBool *readOnly)
+{
+    char * config = NULL;
+
+    *certPrefix = NULL;
+    *keyPrefix = NULL;
+    *readOnly = secmod_argHasFlag("flags","readOnly",spec);
+
+    spec = secmod_argStrip(spec);
+    while (*spec) {
+	int next;
+	SECMOD_HANDLE_STRING_ARG(spec, config, "configdir=", ;)
+	SECMOD_HANDLE_STRING_ARG(spec, *certPrefix, "certPrefix=", ;)
+	SECMOD_HANDLE_STRING_ARG(spec, *keyPrefix, "keyPrefix=", ;)
+	SECMOD_HANDLE_FINAL_ARG(spec)
+    }
+    return config;
+}
+
+struct SECMODConfigListStr {
+    char *config;
+    char *certPrefix;
+    char *keyPrefix;
+    PRBool isReadOnly;
+};
+
+/*
+ * return an array of already openned databases from a spec list.
+ */
+SECMODConfigList *
+secmod_GetConfigList(PRBool isFIPS, char *spec, int *count)
+{
+    char **children;
+    CK_SLOT_ID *ids;
+    char *strippedSpec;
+    int childCount;
+    SECMODConfigList *conflist = NULL;
+    int i;
+
+    strippedSpec = secmod_ParseModuleSpecForTokens(PR_TRUE, isFIPS, 
+						spec,&children,&ids);
+    if (strippedSpec == NULL) {
+	return NULL;
+    }
+
+    for (childCount=0; children && children[childCount]; childCount++) ;
+    *count = childCount+1; /* include strippedSpec */
+    conflist = PORT_NewArray(SECMODConfigList,*count);
+    if (conflist == NULL) {
+	*count = 0;
+	goto loser;
+    }
+
+    conflist[0].config = secmod_getConfigDir(strippedSpec, 
+					    &conflist[0].certPrefix, 
+					    &conflist[0].keyPrefix,
+					    &conflist[0].isReadOnly);
+    for (i=0; i < childCount; i++) {
+	conflist[i+1].config = secmod_getConfigDir(children[i], 
+					    &conflist[i+1].certPrefix, 
+					    &conflist[i+1].keyPrefix,
+					    &conflist[i+1].isReadOnly);
+    }
+
+loser:
+    secmod_FreeChildren(children, ids);
+    PORT_Free(strippedSpec);
+    return conflist;
+}
+
+/*
+ * determine if we are trying to open an old dbm database. For this test
+ * RDB databases should return PR_FALSE.
+ */
+static PRBool
+secmod_configIsDBM(char *configDir)
+{
+    char *env;
+
+    /* explicit dbm open */
+    if (strncmp(configDir, "dbm:", 4) == 0) {
+	return PR_TRUE;
+    }
+    /* explicit open of a non-dbm database */
+    if ((strncmp(configDir, "sql:",4) == 0) 
+	|| (strncmp(configDir, "rdb:", 4) == 0)
+	|| (strncmp(configDir, "extern:", 7) == 0)) {
+	return PR_FALSE;
+    }
+    env = PR_GetEnv("NSS_DEFAULT_DB_TYPE");
+    /* implicit dbm open */
+    if ((env == NULL) || (strcmp(env,"dbm") == 0)) {
+	return PR_TRUE;
+    }
+    /* implicit non-dbm open */
+    return PR_FALSE;
+}
+
+/*
+ * match two prefixes. prefix may be NULL. NULL patches '\0'
+ */
+static PRBool
+secmod_matchPrefix(char *prefix1, char *prefix2)
+{
+    if ((prefix1 == NULL) || (*prefix1 == 0)) {
+	if ((prefix2 == NULL) || (*prefix2 == 0)) {
+	    return PR_TRUE;
+	}
+	return PR_FALSE;
+    }
+    if (strcmp(prefix1, prefix2) == 0) {
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+/*
+ * return true if we are requesting a database that is already openned.
+ */
+PRBool
+secmod_MatchConfigList(char *spec, SECMODConfigList *conflist, int count)
+{
+    char *config;
+    char *certPrefix;
+    char *keyPrefix;
+    PRBool isReadOnly;
+    PRBool ret=PR_FALSE;
+    int i;
+
+    config = secmod_getConfigDir(spec, &certPrefix, &keyPrefix, &isReadOnly);
+    if (!config) {
+	ret=PR_TRUE;
+	goto done;
+    }
+
+    /* NOTE: we dbm isn't multiple open safe. If we open the same database 
+     * twice from two different locations, then we can corrupt our database
+     * (the cache will be inconsistent). Protect against this by claiming
+     * for comparison only that we are always openning dbm databases read only.
+     */
+    if (secmod_configIsDBM(config)) {
+	isReadOnly = 1;
+    }
+    for (i=0; i < count; i++) {
+	if ((strcmp(config,conflist[i].config) == 0)  &&
+	    secmod_matchPrefix(certPrefix, conflist[i].certPrefix) &&
+	    secmod_matchPrefix(keyPrefix, conflist[i].keyPrefix) &&
+	    /* this last test -- if we just need the DB open read only,
+	     * than any open will suffice, but if we requested it read/write
+	     * and it's only open read only, we need to open it again */
+	    (isReadOnly || !conflist[i].isReadOnly)) {
+	    ret = PR_TRUE;
+	    goto done;
+	}
+    }
+
+    ret = PR_FALSE;
+done:
+    PORT_Free(config);
+    PORT_Free(certPrefix);
+    PORT_Free(keyPrefix);
+    return ret;
+}
+
+void
+secmod_FreeConfigList(SECMODConfigList *conflist, int count)
+{
+    int i;
+    for (i=0; i < count; i++) {
+	PORT_Free(conflist[i].config);
+	PORT_Free(conflist[i].certPrefix);
+	PORT_Free(conflist[i].keyPrefix);
+    }
+    PORT_Free(conflist);
+}
+
+void
+secmod_FreeChildren(char **children, CK_SLOT_ID *ids)
+{
+    char **thisChild;
+
+    if (!children) {
+	return;
+    }
+
+    for (thisChild = children; thisChild && *thisChild; thisChild++ ) {
+	PORT_Free(*thisChild);
+    }
+    PORT_Free(children);
+    if (ids) {
+	PORT_Free(ids);
+    }
+    return;
+}
+
+
+static int
+secmod_escapeSize(const char *string, char quote)
+{
+    int escapes = 0, size = 0;
+    const char *src;
+    for (src=string; *src ; src++) {
+        if ((*src == quote) || (*src == '\\')) escapes++;
+        size++;
+    }
+
+    return escapes+size+1;
+}
+
+
+/*
+ * add escapes to protect quote characters...
+ */
+static char *
+secmod_addEscape(const char *string, char quote)
+{
+    char *newString = 0;
+    int size = 0;
+    const char *src;
+    char *dest;
+
+
+    size = secmod_escapeSize(string,quote);
+    newString = PORT_ZAlloc(size);
+    if (newString == NULL) {
+        return NULL;
+    }
+
+    for (src=string, dest=newString; *src; src++,dest++) {
+        if ((*src == '\\') || (*src == quote)) {
+            *dest++ = '\\';
+        }
+        *dest = *src;
+    }
+
+    return newString;
+}
+
+static int
+secmod_doubleEscapeSize(const char *string, char quote1, char quote2)
+{
+    int escapes = 0, size = 0;
+    const char *src;
+    for (src=string; *src ; src++) {
+        if (*src == '\\')   escapes+=3; /* \\\\ */
+        if (*src == quote1) escapes+=2; /* \\quote1 */
+        if (*src == quote2) escapes++;   /* \quote2 */
+        size++;
+    }
+
+    return escapes+size+1;
+}
+
+char *
+secmod_DoubleEscape(const char *string, char quote1, char quote2)
+{
+    char *round1 = NULL;
+    char *retValue = NULL;
+    if (string == NULL) {
+        goto done;
+    }
+    round1 = secmod_addEscape(string,quote1);
+    if (round1) {
+        retValue = secmod_addEscape(round1,quote2);
+        PORT_Free(round1);
+    }
+
+done:
+    if (retValue == NULL) {
+        retValue = PORT_Strdup("");
+    }
+    return retValue;
+}
+
+
+/*
+ * caclulate the length of each child record:
+ * " 0x{id}=<{escaped_child}>"
+ */
+static int
+secmod_getChildLength(char *child, CK_SLOT_ID id)
+{
+    int length = secmod_doubleEscapeSize(child, '>', ']');
+    if (id == 0) {
+	length++;
+    }
+    while (id) {
+	length++;
+	id = id >> 4;
+    }
+    length += 6; /* {sp}0x[id]=<{child}> */
+    return length;
+}
+
+/*
+ * Build a child record:
+ * " 0x{id}=<{escaped_child}>"
+ */
+static SECStatus
+secmod_mkTokenChild(char **next, int *length, char *child, CK_SLOT_ID id)
+{
+    int len;
+    char *escSpec;
+
+    len = PR_snprintf(*next, *length, " 0x%x=<",id);
+    if (len < 0) {
+	return SECFailure;
+    }
+    *next += len;
+    *length -= len;
+    escSpec = secmod_DoubleEscape(child, '>', ']');
+    if (escSpec == NULL) {
+	return SECFailure;
+    }
+    if (*child && (*escSpec == 0)) {
+	PORT_Free(escSpec);
+	return SECFailure;
+    }
+    len = strlen(escSpec);
+    if (len+1 > *length) {
+	PORT_Free(escSpec);
+	return SECFailure;
+    }
+    PORT_Memcpy(*next,escSpec, len);
+    *next += len;
+    *length -= len;
+    PORT_Free(escSpec);
+    **next = '>';
+    (*next)++;
+    (*length)--;
+    return SECSuccess;
+}
+
+#define TOKEN_STRING " tokens=["
+
+char *
+secmod_MkAppendTokensList(PRArenaPool *arena, char *oldParam, char *newToken, 
+			CK_SLOT_ID newID, char **children, CK_SLOT_ID *ids)
+{
+    char *rawParam = NULL;	/* oldParam with tokens stripped off */
+    char *newParam = NULL;	/* space for the return parameter */
+    char *nextParam = NULL;	/* current end of the new parameter */
+    char **oldChildren = NULL;
+    CK_SLOT_ID *oldIds = NULL;
+    void *mark = NULL;         /* mark the arena pool in case we need 
+				* to release it */
+    int length, i, tmpLen;
+    SECStatus rv;
+
+    /* first strip out and save the old tokenlist */
+    rawParam = secmod_ParseModuleSpecForTokens(PR_FALSE,PR_FALSE, 
+					oldParam,&oldChildren,&oldIds);
+    if (!rawParam) {
+	goto loser;
+    }
+
+    /* now calculate the total length of the new buffer */
+    /* First the 'fixed stuff', length of rawparam (does not include a NULL),
+     * length of the token string (does include the NULL), closing bracket */
+    length = strlen(rawParam) + sizeof(TOKEN_STRING) + 1;
+    /* now add then length of all the old children */
+    for (i=0; oldChildren && oldChildren[i]; i++) {
+	length += secmod_getChildLength(oldChildren[i], oldIds[i]);
+    }
+
+    /* add the new token */
+    length += secmod_getChildLength(newToken, newID);
+
+    /* and it's new children */
+    for (i=0; children && children[i]; i++) {
+	if (ids[i] == -1) {
+	    continue;
+	}
+	length += secmod_getChildLength(children[i], ids[i]);
+    }
+
+    /* now allocate and build the string */
+    mark = PORT_ArenaMark(arena);
+    if (!mark) {
+	goto loser;
+    }
+    newParam =  PORT_ArenaAlloc(arena,length);
+    if (!newParam) {
+	goto loser;
+    }
+
+    PORT_Strcpy(newParam, oldParam);
+    tmpLen = strlen(oldParam);
+    nextParam = newParam + tmpLen;
+    length -= tmpLen;
+    PORT_Memcpy(nextParam, TOKEN_STRING, sizeof(TOKEN_STRING)-1);
+    nextParam += sizeof(TOKEN_STRING)-1;
+    length -= sizeof(TOKEN_STRING)-1;
+
+    for (i=0; oldChildren && oldChildren[i]; i++) {
+	rv = secmod_mkTokenChild(&nextParam,&length,oldChildren[i],oldIds[i]);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+    }
+
+    rv = secmod_mkTokenChild(&nextParam, &length, newToken, newID);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    for (i=0; children && children[i]; i++) {
+	if (ids[i] == -1) {
+	    continue;
+	}
+	rv = secmod_mkTokenChild(&nextParam, &length, children[i], ids[i]);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+    }
+
+    if (length < 2) {
+	goto loser;
+    }
+
+    *nextParam++ = ']';
+    *nextParam++ = 0;
+
+    /* we are going to return newParam now, don't release the mark */
+    PORT_ArenaUnmark(arena, mark);
+    mark = NULL;
+
+loser:
+    if (mark) {
+	PORT_ArenaRelease(arena, mark);
+	newParam = NULL; /* if the mark is still active, 
+			  * don't return the param */
+    }
+    if (rawParam) {
+	PORT_Free(rawParam);
+    }
+    if (oldChildren) {
+	secmod_FreeChildren(oldChildren, oldIds);
+    }
+    return newParam;
+}
+    
+static char *
+secmod_mkModuleSpec(SECMODModule * module)
+{
+    char *nss = NULL, *modSpec = NULL, **slotStrings = NULL;
+    int slotCount, i, si;
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+
+    /* allocate target slot info strings */
+    slotCount = 0;
+
+    SECMOD_GetReadLock(moduleLock);
+    if (module->slotCount) {
+	for (i=0; i < module->slotCount; i++) {
+	    if (module->slots[i]->defaultFlags !=0) {
+		slotCount++;
+	    }
+	}
+    } else {
+	slotCount = module->slotInfoCount;
+    }
+
+    slotStrings = (char **)PORT_ZAlloc(slotCount*sizeof(char *));
+    if (slotStrings == NULL) {
+        SECMOD_ReleaseReadLock(moduleLock);
+	goto loser;
+    }
+
+
+    /* build the slot info strings */
+    if (module->slotCount) {
+	for (i=0, si= 0; i < module->slotCount; i++) {
+	    if (module->slots[i]->defaultFlags) {
+		PORT_Assert(si < slotCount);
+		if (si >= slotCount) break;
+		slotStrings[si] = secmod_mkSlotString(module->slots[i]->slotID,
+			module->slots[i]->defaultFlags,
+			module->slots[i]->timeout,
+			module->slots[i]->askpw,
+			module->slots[i]->hasRootCerts,
+			module->slots[i]->hasRootTrust);
+		si++;
+	    }
+	}
+     } else {
+	for (i=0; i < slotCount; i++) {
+		slotStrings[i] = secmod_mkSlotString(module->slotInfo[i].slotID,
+			module->slotInfo[i].defaultFlags,
+			module->slotInfo[i].timeout,
+			module->slotInfo[i].askpw,
+			module->slotInfo[i].hasRootCerts,
+			module->slotInfo[i].hasRootTrust);
+	}
+    }
+
+    SECMOD_ReleaseReadLock(moduleLock);
+    nss = secmod_mkNSS(slotStrings,slotCount,module->internal, module->isFIPS,
+		       module->isModuleDB, module->moduleDBOnly, 
+		       module->isCritical, module->trustOrder,
+		       module->cipherOrder,module->ssl[0],module->ssl[1]);
+    modSpec= secmod_mkNewModuleSpec(module->dllName,module->commonName,
+						module->libraryParams,nss);
+    PORT_Free(slotStrings);
+    PR_smprintf_free(nss);
+loser:
+    return (modSpec);
+}
+    
+
+char **
+SECMOD_GetModuleSpecList(SECMODModule *module)
+{
+    SECMODModuleDBFunc func = (SECMODModuleDBFunc) module->moduleDBFunc;
+    if (func) {
+	return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND,
+		module->libraryParams,NULL);
+    }
+    return NULL;
+}
+
+SECStatus
+SECMOD_AddPermDB(SECMODModule *module)
+{
+    SECMODModuleDBFunc func;
+    char *moduleSpec;
+    char **retString;
+
+    if (module->parent == NULL) return SECFailure;
+
+    func  = (SECMODModuleDBFunc) module->parent->moduleDBFunc;
+    if (func) {
+	moduleSpec = secmod_mkModuleSpec(module);
+	retString = (*func)(SECMOD_MODULE_DB_FUNCTION_ADD,
+		module->parent->libraryParams,moduleSpec);
+	PORT_Free(moduleSpec);
+	if (retString != NULL) return SECSuccess;
+    }
+    return SECFailure;
+}
+
+SECStatus
+SECMOD_DeletePermDB(SECMODModule *module)
+{
+    SECMODModuleDBFunc func;
+    char *moduleSpec;
+    char **retString;
+
+    if (module->parent == NULL) return SECFailure;
+
+    func  = (SECMODModuleDBFunc) module->parent->moduleDBFunc;
+    if (func) {
+	moduleSpec = secmod_mkModuleSpec(module);
+	retString = (*func)(SECMOD_MODULE_DB_FUNCTION_DEL,
+		module->parent->libraryParams,moduleSpec);
+	PORT_Free(moduleSpec);
+	if (retString != NULL) return SECSuccess;
+    }
+    return SECFailure;
+}
+
+SECStatus
+SECMOD_FreeModuleSpecList(SECMODModule *module, char **moduleSpecList)
+{
+    SECMODModuleDBFunc func = (SECMODModuleDBFunc) module->moduleDBFunc;
+    char **retString;
+    if (func) {
+	retString = (*func)(SECMOD_MODULE_DB_FUNCTION_RELEASE,
+		module->libraryParams,moduleSpecList);
+	if (retString != NULL) return SECSuccess;
+    }
+    return SECFailure;
+}
+
+/*
+ * load a PKCS#11 module but do not add it to the default NSS trust domain
+ */
+SECMODModule *
+SECMOD_LoadModule(char *modulespec,SECMODModule *parent, PRBool recurse)
+{
+    char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss= NULL;
+    SECStatus status;
+    SECMODModule *module = NULL;
+    SECMODModule *oldModule = NULL;
+    SECStatus rv;
+
+    /* initialize the underlying module structures */
+    SECMOD_Init();
+
+    status = secmod_argParseModuleSpec(modulespec, &library, &moduleName, 
+							&parameters, &nss);
+    if (status != SECSuccess) {
+	goto loser;
+    }
+
+    module = SECMOD_CreateModule(library, moduleName, parameters, nss);
+    if (library) PORT_Free(library);
+    if (moduleName) PORT_Free(moduleName);
+    if (parameters) PORT_Free(parameters);
+    if (nss) PORT_Free(nss);
+    if (!module) {
+	goto loser;
+    }
+    if (parent) {
+    	module->parent = SECMOD_ReferenceModule(parent);
+	if (module->internal && secmod_IsInternalKeySlot(parent)) {
+	    module->internal = parent->internal;
+	}
+    }
+
+    /* load it */
+    rv = secmod_LoadPKCS11Module(module, &oldModule);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    /* if we just reload an old module, no need to add it to any lists.
+     * we simple release all our references */
+    if (oldModule) {
+	/* This module already exists, don't link it anywhere. This
+	 * will probably destroy this module */
+	SECMOD_DestroyModule(module);
+	return oldModule;
+    }
+
+    if (recurse && module->isModuleDB) {
+	char ** moduleSpecList;
+	PORT_SetError(0);
+
+	moduleSpecList = SECMOD_GetModuleSpecList(module);
+	if (moduleSpecList) {
+	    char **index;
+
+	    index = moduleSpecList;
+	    if (*index && SECMOD_GetSkipFirstFlag(module)) {
+		index++;
+	    }
+
+	    for (; *index; index++) {
+		SECMODModule *child;
+		child = SECMOD_LoadModule(*index,module,PR_TRUE);
+		if (!child) break;
+		if (child->isCritical && !child->loaded) {
+		    int err = PORT_GetError();
+		    if (!err)  
+			err = SEC_ERROR_NO_MODULE;
+		    SECMOD_DestroyModule(child);
+		    PORT_SetError(err);
+		    rv = SECFailure;
+		    break;
+		}
+		SECMOD_DestroyModule(child);
+	    }
+	    SECMOD_FreeModuleSpecList(module,moduleSpecList);
+	} else {
+	    if (!PORT_GetError())
+		PORT_SetError(SEC_ERROR_NO_MODULE);
+	    rv = SECFailure;
+	}
+    }
+
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+
+    /* inherit the reference */
+    if (!module->moduleDBOnly) {
+	SECMOD_AddModuleToList(module);
+    } else {
+	SECMOD_AddModuleToDBOnlyList(module);
+    }
+   
+    /* handle any additional work here */
+    return module;
+
+loser:
+    if (module) {
+	if (module->loaded) {
+	    SECMOD_UnloadModule(module);
+	}
+	SECMOD_AddModuleToUnloadList(module);
+    }
+    return module;
+}
+
+/*
+ * load a PKCS#11 module and add it to the default NSS trust domain
+ */
+SECMODModule *
+SECMOD_LoadUserModule(char *modulespec,SECMODModule *parent, PRBool recurse)
+{
+    SECStatus rv = SECSuccess;
+    SECMODModule * newmod = SECMOD_LoadModule(modulespec, parent, recurse);
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+
+    if (newmod) {
+	SECMOD_GetReadLock(moduleLock);
+        rv = STAN_AddModuleToDefaultTrustDomain(newmod);
+	SECMOD_ReleaseReadLock(moduleLock);
+        if (SECSuccess != rv) {
+            SECMOD_DestroyModule(newmod);
+            return NULL;
+        }
+    }
+    return newmod;
+}
+
+/*
+ * remove the PKCS#11 module from the default NSS trust domain, call
+ * C_Finalize, and destroy the module structure
+ */
+SECStatus SECMOD_UnloadUserModule(SECMODModule *mod)
+{
+    SECStatus rv = SECSuccess;
+    int atype = 0;
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+    if (!mod) {
+        return SECFailure;
+    }
+
+    SECMOD_GetReadLock(moduleLock);
+    rv = STAN_RemoveModuleFromDefaultTrustDomain(mod);
+    SECMOD_ReleaseReadLock(moduleLock);
+    if (SECSuccess != rv) {
+        return SECFailure;
+    }
+    return SECMOD_DeleteModuleEx(NULL, mod, &atype, PR_FALSE);
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11pbe.c b/mozilla/security/nss/lib/pk11wrap/pk11pbe.c
new file mode 100644
index 0000000..9874286
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11pbe.c
@@ -0,0 +1,1460 @@
+/* ***** 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 "plarena.h"
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "secport.h"
+#include "hasht.h"
+#include "pkcs11t.h"
+#include "sechash.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "secoid.h"
+#include "secerr.h"
+#include "secmod.h"
+#include "pk11func.h"
+#include "secpkcs5.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "key.h"
+
+typedef struct SEC_PKCS5PBEParameterStr SEC_PKCS5PBEParameter;
+struct SEC_PKCS5PBEParameterStr {
+    PRArenaPool     *poolp;
+    SECItem         salt;           /* octet string */
+    SECItem         iteration;      /* integer */
+    SECItem         keyLength;	/* PKCS5v2 only */
+    SECAlgorithmID  *pPrfAlgId;	/* PKCS5v2 only */
+    SECAlgorithmID  prfAlgId;	/* PKCS5v2 only */
+};
+
+/* PKCS5 V2 has an algorithm ID for the encryption and for 
+ * the key generation. This is valid for SEC_OID_PKCS5_PBES2 
+ * and SEC_OID_PKCS5_PBMAC1
+ */
+struct sec_pkcs5V2ParameterStr {
+    PRArenaPool    *poolp;
+    SECAlgorithmID pbeAlgId;   /* real pbe algorithms */
+    SECAlgorithmID cipherAlgId; /* encryption/mac */
+};
+
+typedef struct sec_pkcs5V2ParameterStr sec_pkcs5V2Parameter;
+
+
+/* template for PKCS 5 PBE Parameter.  This template has been expanded
+ * based upon the additions in PKCS 12.  This should eventually be moved
+ * if RSA updates PKCS 5.
+ */
+const SEC_ASN1Template SEC_PKCS5PBEParameterTemplate[] =
+{
+    { SEC_ASN1_SEQUENCE, 
+	0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    { SEC_ASN1_OCTET_STRING, 
+	offsetof(SEC_PKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER,
+	offsetof(SEC_PKCS5PBEParameter, iteration) },
+    { 0 }
+};
+
+const SEC_ASN1Template SEC_V2PKCS12PBEParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) },
+    { 0 }
+};
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+/* SECOID_PKCS5_PBKDF2 */
+const SEC_ASN1Template SEC_PKCS5V2PBEParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    /* This is really a choice, but since we only understand this
+     * choice, just inline it */
+    { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) },
+    { SEC_ASN1_INTEGER|SEC_ASN1_OPTIONAL, 
+		      offsetof(SEC_PKCS5PBEParameter, keyLength) },
+    { SEC_ASN1_POINTER | SEC_ASN1_XTRN | SEC_ASN1_OPTIONAL, 
+	offsetof(SEC_PKCS5PBEParameter, pPrfAlgId),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { 0 }
+};
+
+/* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */
+const SEC_ASN1Template SEC_PKCS5V2ParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(sec_pkcs5V2Parameter, pbeAlgId),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	offsetof(sec_pkcs5V2Parameter, cipherAlgId),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { 0 }
+};
+
+
+/*
+ * maps a PBE algorithm to a crypto algorithm. for PKCS12 and PKCS5v1
+ * for PKCS5v2 it returns SEC_OID_PKCS5_PBKDF2.
+ */
+SECOidTag
+sec_pkcs5GetCryptoFromAlgTag(SECOidTag algorithm)
+{
+    switch(algorithm)
+    {
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:
+	    return SEC_OID_DES_EDE3_CBC;
+	case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:
+	    return SEC_OID_DES_CBC;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	    return SEC_OID_RC2_CBC;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	    return SEC_OID_RC4;
+	case SEC_OID_PKCS5_PBKDF2:
+	case SEC_OID_PKCS5_PBES2:
+	case SEC_OID_PKCS5_PBMAC1:
+	    return SEC_OID_PKCS5_PBKDF2;
+	default:
+	    break;
+    }
+
+    return SEC_OID_UNKNOWN;
+}
+
+/*
+ * get a new PKCS5 V2 Parameter from the algorithm id.
+ *  if arena is passed in, use it, otherwise create a new arena.
+ */
+sec_pkcs5V2Parameter *
+sec_pkcs5_v2_get_v2_param(PRArenaPool *arena, SECAlgorithmID *algid)
+{
+    PRArenaPool *localArena = NULL;
+    sec_pkcs5V2Parameter *pbeV2_param;
+    SECStatus rv;
+
+    if (arena == NULL) {
+	localArena = arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+	if (arena == NULL) {
+	    return NULL;
+	}
+    }
+    pbeV2_param = PORT_ArenaZNew(arena, sec_pkcs5V2Parameter);
+    if (pbeV2_param == NULL) {
+	goto loser;
+    }
+	
+    rv = SEC_ASN1DecodeItem(arena, pbeV2_param,
+		SEC_PKCS5V2ParameterTemplate, &algid->parameters);
+    if (rv == SECFailure) {
+	goto loser;
+    }
+
+    pbeV2_param->poolp = arena;
+    return pbeV2_param;
+loser:
+    if (localArena) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return NULL;
+}
+
+void
+sec_pkcs5_v2_destroy_v2_param(sec_pkcs5V2Parameter *param)
+{
+   if (param && param->poolp) {
+	PORT_FreeArena(param->poolp, PR_TRUE);
+   }
+}
+	
+
+/* maps crypto algorithm from PBE algorithm.
+ */
+SECOidTag 
+SEC_PKCS5GetCryptoAlgorithm(SECAlgorithmID *algid)
+{
+
+    SECOidTag pbeAlg;
+    SECOidTag cipherAlg;
+
+    if(algid == NULL)
+	return SEC_OID_UNKNOWN;
+
+    pbeAlg = SECOID_GetAlgorithmTag(algid);
+    cipherAlg = sec_pkcs5GetCryptoFromAlgTag(pbeAlg);
+    if ((cipherAlg == SEC_OID_PKCS5_PBKDF2)  &&
+	 (pbeAlg != SEC_OID_PKCS5_PBKDF2)) {
+	sec_pkcs5V2Parameter *pbeV2_param;
+	cipherAlg = SEC_OID_UNKNOWN;
+
+	pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+	if (pbeV2_param != NULL) {
+	    cipherAlg = SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId);
+	    sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+	}
+    }
+
+    return cipherAlg;
+}
+
+/* check to see if an oid is a pbe algorithm
+ */ 
+PRBool 
+SEC_PKCS5IsAlgorithmPBEAlg(SECAlgorithmID *algid)
+{
+    return (PRBool)(SEC_PKCS5GetCryptoAlgorithm(algid) != SEC_OID_UNKNOWN);
+}
+
+PRBool 
+SEC_PKCS5IsAlgorithmPBEAlgTag(SECOidTag algtag)
+{
+    return (PRBool)(sec_pkcs5GetCryptoFromAlgTag(algtag) != SEC_OID_UNKNOWN);
+}
+
+/*
+ * find the most appropriate PKCS5v2 overall oid tag from a regular
+ * cipher/hash algorithm tag.
+ */
+static SECOidTag
+sec_pkcs5v2_get_pbe(SECOidTag algTag)
+{
+    /* if it's a valid hash oid... */
+    if (HASH_GetHashOidTagByHMACOidTag(algTag) != SEC_OID_UNKNOWN) {
+	/* use the MAC tag */
+	return SEC_OID_PKCS5_PBMAC1;
+    }
+    if (HASH_GetHashTypeByOidTag(algTag) != HASH_AlgNULL) {
+	/* eliminate Hash algorithms */
+	return SEC_OID_UNKNOWN;
+    }
+    if (PK11_AlgtagToMechanism(algTag) != CKM_INVALID_MECHANISM) {
+	/* it's not a hash, if it has a PKCS #11 mechanism associated
+	 * with it, assume it's a cipher. (NOTE this will generate
+	 * some false positives). */
+	return SEC_OID_PKCS5_PBES2;
+    }
+    return SEC_OID_UNKNOWN;
+}
+
+/* 
+ * maps PBE algorithm from crypto algorithm, assumes SHA1 hashing.
+ *  input keyLen in bits.
+ */
+SECOidTag 
+SEC_PKCS5GetPBEAlgorithm(SECOidTag algTag, int keyLen)
+{
+    switch(algTag)
+    {
+	case SEC_OID_DES_EDE3_CBC:
+	    switch(keyLen) {
+		case 168:
+		case 192:
+		case 0:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC;
+		case 128:
+		case 92:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC;
+		default:
+		    break;
+	    }
+	    break;
+	case SEC_OID_DES_CBC:
+	    return SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC;
+	case SEC_OID_RC2_CBC:
+	    switch(keyLen) {
+		case 40:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
+		case 128:
+		case 0:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC;
+		default:
+		    break;
+	    }
+	    break;
+	case SEC_OID_RC4:
+	    switch(keyLen) {
+		case 40:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4;
+		case 128:
+		case 0:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4;
+		default:
+		    break;
+	    }
+	    break;
+	default:
+	    return sec_pkcs5v2_get_pbe(algTag);
+    }
+
+    return SEC_OID_UNKNOWN;
+}
+
+/*
+ * get the key length in bytes from a PKCS5 PBE
+ */
+int
+sec_pkcs5v2_key_length(SECAlgorithmID *algid)
+{
+    SECOidTag algorithm;
+    PRArenaPool *arena = NULL;
+    SEC_PKCS5PBEParameter p5_param;
+    SECStatus rv;
+    int length = -1;
+
+    algorithm = SECOID_GetAlgorithmTag(algid);
+    /* sanity check, they should all be PBKDF2 here */
+    if (algorithm != SEC_OID_PKCS5_PBKDF2) {
+	return -1;
+    }
+
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+    PORT_Memset(&p5_param, 0, sizeof(p5_param));
+    rv = SEC_ASN1DecodeItem(arena,&p5_param,
+			 SEC_PKCS5V2PBEParameterTemplate, &algid->parameters);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    if (p5_param.keyLength.data != NULL) {
+        length = DER_GetInteger(&p5_param.keyLength);
+    }
+
+loser:
+    if (arena) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return length;
+}
+
+/*
+ *  get the key length in bytes needed for the PBE algorithm
+ */
+int 
+SEC_PKCS5GetKeyLength(SECAlgorithmID *algid)
+{
+
+    SECOidTag algorithm;
+
+    if(algid == NULL)
+	return SEC_OID_UNKNOWN;
+
+    algorithm = SECOID_GetAlgorithmTag(algid);
+
+    switch(algorithm)
+    {
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
+	    return 24;
+	case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:
+	    return 8;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	    return 5;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	    return 16;
+	case SEC_OID_PKCS5_PBKDF2:
+	    return sec_pkcs5v2_key_length(algid);
+	case SEC_OID_PKCS5_PBES2:
+	case SEC_OID_PKCS5_PBMAC1:
+	    {
+		sec_pkcs5V2Parameter *pbeV2_param;
+		int length = -1;
+		pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+		if (pbeV2_param != NULL) {
+	    	    length = sec_pkcs5v2_key_length(&pbeV2_param->pbeAlgId);
+		    sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+		}
+		return length;
+	    }
+	
+	default:
+	    break;
+    }
+    return -1;
+}
+
+
+/* the PKCS12 V2 algorithms only encode the salt, there is no iteration
+ * count so we need a check for V2 algorithm parameters.
+ */
+static PRBool
+sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(SECOidTag algorithm)
+{
+    switch(algorithm) 
+    {
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	    return PR_TRUE;
+	default:
+	    break;
+    }
+
+    return PR_FALSE;
+}
+
+static PRBool
+sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(SECOidTag algorithm)
+{
+    switch(algorithm) 
+    {
+	case SEC_OID_PKCS5_PBES2:
+	case SEC_OID_PKCS5_PBMAC1:
+	case SEC_OID_PKCS5_PBKDF2:
+	    return PR_TRUE;
+	default:
+	    break;
+    }
+
+    return PR_FALSE;
+}
+
+/* destroy a pbe parameter.  it assumes that the parameter was 
+ * generated using the appropriate create function and therefor
+ * contains an arena pool.
+ */
+static void 
+sec_pkcs5_destroy_pbe_param(SEC_PKCS5PBEParameter *pbe_param)
+{
+    if(pbe_param != NULL)
+	PORT_FreeArena(pbe_param->poolp, PR_TRUE);
+}
+
+/* creates a PBE parameter based on the PBE algorithm.  the only required
+ * parameters are algorithm and interation.  the return is a PBE parameter
+ * which conforms to PKCS 5 parameter unless an extended parameter is needed.
+ * this is primarily if keyLength and a variable key length algorithm are
+ * specified.
+ *   salt -  if null, a salt will be generated from random bytes.
+ *   iteration - number of iterations to perform hashing.
+ *   keyLength - only used in variable key length algorithms. if specified,
+ *            should be in bytes.
+ * once a parameter is allocated, it should be destroyed calling 
+ * sec_pkcs5_destroy_pbe_parameter or SEC_PKCS5DestroyPBEParameter.
+ */
+#define DEFAULT_SALT_LENGTH 16
+static SEC_PKCS5PBEParameter *
+sec_pkcs5_create_pbe_parameter(SECOidTag algorithm, 
+			SECItem *salt, 
+			int iteration,
+			int keyLength,
+			SECOidTag prfAlg)
+{
+    PRArenaPool *poolp = NULL;
+    SEC_PKCS5PBEParameter *pbe_param = NULL;
+    SECStatus rv= SECSuccess; 
+    void *dummy = NULL;
+
+    if(iteration < 0) {
+	return NULL;
+    }
+
+    poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if(poolp == NULL)
+	return NULL;
+
+    pbe_param = (SEC_PKCS5PBEParameter *)PORT_ArenaZAlloc(poolp,
+	sizeof(SEC_PKCS5PBEParameter));
+    if(!pbe_param) {
+	PORT_FreeArena(poolp, PR_TRUE);
+	return NULL;
+    }
+
+    pbe_param->poolp = poolp;
+
+    rv = SECFailure;
+    if (salt && salt->data) {
+    	rv = SECITEM_CopyItem(poolp, &pbe_param->salt, salt);
+    } else {
+	/* sigh, the old interface generated salt on the fly, so we have to
+	 * preserve the semantics */
+	pbe_param->salt.len = DEFAULT_SALT_LENGTH;
+	pbe_param->salt.data = PORT_ArenaZAlloc(poolp,DEFAULT_SALT_LENGTH);
+	if (pbe_param->salt.data) {
+	   rv = PK11_GenerateRandom(pbe_param->salt.data,DEFAULT_SALT_LENGTH);
+	}
+    }
+
+    if(rv != SECSuccess) {
+	PORT_FreeArena(poolp, PR_TRUE);
+	return NULL;
+    }
+
+    /* encode the integer */
+    dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->iteration, 
+		iteration);
+    rv = (dummy) ? SECSuccess : SECFailure;
+
+    if(rv != SECSuccess) {
+	PORT_FreeArena(poolp, PR_FALSE);
+	return NULL;
+    }
+
+    /*
+     * for PKCS5 v2 Add the keylength and the prf
+     */
+    if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->keyLength, 
+		keyLength);
+	rv = (dummy) ? SECSuccess : SECFailure;
+	if (rv != SECSuccess) {
+	    PORT_FreeArena(poolp, PR_FALSE);
+	    return NULL;
+	}
+	rv = SECOID_SetAlgorithmID(poolp, &pbe_param->prfAlgId, prfAlg, NULL);
+	if (rv != SECSuccess) {
+	    PORT_FreeArena(poolp, PR_FALSE);
+	    return NULL;
+	}
+	pbe_param->pPrfAlgId = &pbe_param->prfAlgId;
+    }
+
+    return pbe_param;
+}
+
+/* creates a algorithm ID containing the PBE algorithm and appropriate
+ * parameters.  the required parameter is the algorithm.  if salt is
+ * not specified, it is generated randomly.  
+ *
+ * the returned SECAlgorithmID should be destroyed using 
+ * SECOID_DestroyAlgorithmID
+ */
+SECAlgorithmID *
+sec_pkcs5CreateAlgorithmID(SECOidTag algorithm, 
+			   SECOidTag cipherAlgorithm,
+			   SECOidTag prfAlg,
+			   SECOidTag *pPbeAlgorithm,
+			   int keyLength,
+			   SECItem *salt, 
+			   int iteration)
+{
+    PRArenaPool *poolp = NULL;
+    SECAlgorithmID *algid, *ret_algid = NULL;
+    SECOidTag pbeAlgorithm = algorithm;
+    SECItem der_param;
+    void *dummy;
+    SECStatus rv = SECFailure;
+    SEC_PKCS5PBEParameter *pbe_param = NULL;
+    sec_pkcs5V2Parameter pbeV2_param;
+
+    if(iteration <= 0) {
+	return NULL;
+    }
+
+    poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if(!poolp) {
+	goto loser;
+    }
+
+    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm) ||
+    	 	sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
+	/* use PKCS 5 v2 */
+	SECItem *cipherParams;
+
+	/*
+	 * if we ask for pkcs5 Algorithms directly, then the
+	 * application needs to supply the cipher algorithm,
+	 * otherwise we are implicitly using pkcs5 v2 and the
+	 * passed in algorithm is the encryption algorithm.
+	 */
+	if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
+	    if (cipherAlgorithm == SEC_OID_UNKNOWN) {
+		goto loser;
+	    }
+	} else {
+	    cipherAlgorithm = algorithm;
+	    /* force algorithm to be chosen below */
+	    algorithm = SEC_OID_PKCS5_PBKDF2;
+	}
+	
+	pbeAlgorithm = SEC_OID_PKCS5_PBKDF2;
+	/*
+	 * 'algorithm' is the overall algorithm oid tag used to wrap the 
+	 * entire algoithm ID block. For PKCS5v1 and PKCS12, this 
+	 * algorithm OID has encoded in it both the PBE KDF function 
+	 * and the encryption algorithm. For PKCS 5v2, PBE KDF and
+	 * encryption/macing oids are encoded as parameters in
+	 * the algorithm ID block. 
+	 *
+	 * Thus in PKCS5 v1 and PKCS12, this algorithm maps to a pkcs #11
+	 * mechanism, where as in PKCS 5v2, this alogithm tag does not map
+	 * directly to a PKCS #11 mechanim, instead the 2 oids in the 
+	 * algorithm ID block map the the actual PKCS #11 mechanism.
+	 * gorithm is). We use choose this algorithm oid based on the 
+	 * cipherAlgorithm to determine what this should be (MAC1 or PBES2).
+	 */
+	if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	     /* choose mac or pbes */
+	     algorithm = sec_pkcs5v2_get_pbe(cipherAlgorithm);
+	}
+
+	/* set the PKCS5v2 specific parameters */
+	if (keyLength == 0) {
+	    SECOidTag hashAlg = HASH_GetHashOidTagByHMACOidTag(cipherAlgorithm);
+    	    if (hashAlg != SEC_OID_UNKNOWN) {
+	        keyLength = HASH_ResultLenByOidTag(hashAlg);
+	    } else {
+		CK_MECHANISM_TYPE cryptoMech;
+		cryptoMech = PK11_AlgtagToMechanism(cipherAlgorithm);
+		if (cryptoMech == CKM_INVALID_MECHANISM) {
+		    goto loser;
+		}
+	        keyLength = PK11_GetMaxKeyLength(cryptoMech);
+	    }
+	    if (keyLength == 0) {
+		goto loser;
+	    }
+	}
+	/* currently only SEC_OID_HMAC_SHA1 is defined */
+	if (prfAlg == SEC_OID_UNKNOWN) {
+	    prfAlg = SEC_OID_HMAC_SHA1;
+	}
+
+	/* build the PKCS5v2 cipher algorithm id */
+	cipherParams = pk11_GenerateNewParamWithKeyLen(	
+			PK11_AlgtagToMechanism(cipherAlgorithm), keyLength);
+	if (!cipherParams) {
+	    goto loser;
+	}
+
+	PORT_Memset(&pbeV2_param, 0, sizeof (pbeV2_param));
+
+	rv = PK11_ParamToAlgid(cipherAlgorithm, cipherParams, 
+				poolp, &pbeV2_param.cipherAlgId);
+	SECITEM_FreeItem(cipherParams, PR_TRUE);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+    }
+	
+
+    /* generate the parameter */
+    pbe_param = sec_pkcs5_create_pbe_parameter(pbeAlgorithm, salt, iteration,
+			keyLength, prfAlg);
+    if(!pbe_param) {
+	goto loser;
+    }
+
+    /* generate the algorithm id */
+    algid = (SECAlgorithmID *)PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
+    if(algid == NULL) {
+	goto loser;
+    }
+
+    der_param.data = NULL;
+    der_param.len = 0;
+    if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
+	/* first encode the PBE algorithm ID */
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
+					SEC_PKCS5V2PBEParameterTemplate);
+	if (dummy == NULL) {
+	    goto loser;
+	}
+	rv = SECOID_SetAlgorithmID(poolp, &pbeV2_param.pbeAlgId, 
+				   pbeAlgorithm, &der_param);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+
+	/* now encode the Full PKCS 5 parameter */
+	der_param.data = NULL;
+	der_param.len = 0;
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, &pbeV2_param,
+					SEC_PKCS5V2ParameterTemplate);
+    } else if(!sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
+					SEC_PKCS5PBEParameterTemplate);
+    } else {
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
+	    				SEC_V2PKCS12PBEParameterTemplate);
+    }
+    if (dummy == NULL) {
+	goto loser;
+    }
+
+    rv = SECOID_SetAlgorithmID(poolp, algid, algorithm, &der_param);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID));
+    if (ret_algid == NULL) {
+	goto loser;
+    }
+
+    rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid);
+    if (rv != SECSuccess) {
+	SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE);
+	ret_algid = NULL;
+    } else if (pPbeAlgorithm) {
+	*pPbeAlgorithm = pbeAlgorithm;
+    }
+
+loser:
+    if (poolp != NULL) {
+	PORT_FreeArena(poolp, PR_TRUE);
+	algid = NULL;
+    }
+
+    if (pbe_param) {
+	sec_pkcs5_destroy_pbe_param(pbe_param);
+    }
+
+    return ret_algid;
+}
+
+SECStatus
+pbe_PK11AlgidToParam(SECAlgorithmID *algid,SECItem *mech)
+{
+    SEC_PKCS5PBEParameter p5_param;
+    SECItem *salt = NULL;
+    SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
+    PRArenaPool *arena = NULL;
+    SECStatus rv = SECFailure;
+    unsigned char *paramData = NULL;
+    unsigned char *pSalt = NULL;
+    CK_ULONG iterations;
+    int paramLen = 0;
+    int iv_len;
+    
+
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+
+
+    /*
+     * decode the algid based on the pbe type
+     */
+    PORT_Memset(&p5_param, 0, sizeof(p5_param));
+    if (sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {
+        iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm));
+        rv = SEC_ASN1DecodeItem(arena, &p5_param,
+			 SEC_V2PKCS12PBEParameterTemplate, &algid->parameters);
+    } else if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	iv_len = 0;
+        rv = SEC_ASN1DecodeItem(arena,&p5_param,
+			 SEC_PKCS5V2PBEParameterTemplate, &algid->parameters);
+    } else {
+        iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm));
+        rv = SEC_ASN1DecodeItem(arena,&p5_param,SEC_PKCS5PBEParameterTemplate, 
+						&algid->parameters);
+    }
+
+    if (iv_len < 0) {
+	goto loser;
+    }
+
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+        
+    /* get salt */
+    salt = &p5_param.salt;
+    iterations = (CK_ULONG) DER_GetInteger(&p5_param.iteration);
+
+    /* allocate and fill in the PKCS #11 parameters
+     * based on the algorithm. */
+    if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	SECOidTag prfAlgTag;
+    	CK_PKCS5_PBKD2_PARAMS *pbeV2_params = 
+		(CK_PKCS5_PBKD2_PARAMS *)PORT_ZAlloc(
+			sizeof(CK_PKCS5_PBKD2_PARAMS)+ salt->len);
+
+	if (pbeV2_params == NULL) {
+	    goto loser;
+	}
+	paramData = (unsigned char *)pbeV2_params;
+	paramLen = sizeof(CK_PKCS5_PBKD2_PARAMS);
+
+	/* set the prf */
+	prfAlgTag = SEC_OID_HMAC_SHA1;
+ 	if (p5_param.pPrfAlgId &&
+ 	    p5_param.pPrfAlgId->algorithm.data != 0) {
+ 	    prfAlgTag = SECOID_GetAlgorithmTag(p5_param.pPrfAlgId);
+	}
+	if (prfAlgTag == SEC_OID_HMAC_SHA1) {
+	    pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
+	} else {
+	    /* only SHA1_HMAC is currently supported by PKCS #11 */
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    goto loser;
+	}
+	
+	/* probably should fetch these from the prfAlgid */
+	pbeV2_params->pPrfData = NULL;
+	pbeV2_params->ulPrfDataLen = 0;
+	pbeV2_params->saltSource = CKZ_SALT_SPECIFIED;
+	pSalt = ((CK_CHAR_PTR) pbeV2_params)+sizeof(CK_PKCS5_PBKD2_PARAMS);
+        PORT_Memcpy(pSalt, salt->data, salt->len);
+	pbeV2_params->pSaltSourceData = pSalt;
+	pbeV2_params->ulSaltSourceDataLen = salt->len;
+	pbeV2_params->iterations = iterations;
+    } else {
+	CK_PBE_PARAMS *pbe_params = NULL;
+    	pbe_params = (CK_PBE_PARAMS *)PORT_ZAlloc(sizeof(CK_PBE_PARAMS)+
+						salt->len+iv_len);
+	if (pbe_params == NULL) {
+	    goto loser;
+	}
+	paramData = (unsigned char *)pbe_params;
+	paramLen = sizeof(CK_PBE_PARAMS);
+
+	pSalt = ((CK_CHAR_PTR) pbe_params)+sizeof(CK_PBE_PARAMS);
+    	pbe_params->pSalt = pSalt;
+        PORT_Memcpy(pSalt, salt->data, salt->len);
+	pbe_params->ulSaltLen = salt->len;
+	if (iv_len) {
+	    pbe_params->pInitVector = 
+		((CK_CHAR_PTR) pbe_params)+ sizeof(CK_PBE_PARAMS)+salt->len;
+	}
+	pbe_params->ulIteration = iterations;
+    }
+
+    /* copy into the mechanism sec item */
+    mech->data = paramData;
+    mech->len = paramLen;
+    if (arena) {
+	PORT_FreeArena(arena,PR_TRUE);
+    }
+    return SECSuccess;
+
+loser:
+    if (paramData) {
+	PORT_Free(paramData);
+    }
+    if (arena) {
+	PORT_FreeArena(arena,PR_TRUE);
+    }
+    return SECFailure;
+}
+
+/*
+ * public, deprecated, not valid for pkcs5 v2 
+ * 
+ * use PK11_CreatePBEV2AlgorithmID or PK11_CreatePBEAlgorithmID to create
+ * PBE algorithmID's directly.
+ */
+SECStatus
+PBE_PK11ParamToAlgid(SECOidTag algTag, SECItem *param, PRArenaPool *arena, 
+		     SECAlgorithmID *algId)
+{
+    CK_PBE_PARAMS *pbe_param;
+    SECItem pbeSalt;
+    SECAlgorithmID *pbeAlgID = NULL;
+    SECStatus rv;
+
+    if(!param || !algId) {
+	return SECFailure;
+    }
+
+    pbe_param = (CK_PBE_PARAMS *)param->data;
+    pbeSalt.data = (unsigned char *)pbe_param->pSalt;
+    pbeSalt.len = pbe_param->ulSaltLen;
+    pbeAlgID = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, 
+	SEC_OID_UNKNOWN, NULL, 0, &pbeSalt, (int)pbe_param->ulIteration);
+    if(!pbeAlgID) {
+	return SECFailure;
+    }
+
+    rv = SECOID_CopyAlgorithmID(arena, algId, pbeAlgID);
+    SECOID_DestroyAlgorithmID(pbeAlgID, PR_TRUE);
+    return rv;
+}
+
+/*
+ * public, Deprecated, This function is only for binary compatibility with 
+ * older applications. Does not support PKCS5v2.
+ *
+ * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for
+ * iv values rather than generating PBE bits directly.
+ */
+PBEBitGenContext *
+PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose,
+	SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded,
+	unsigned int iterations)
+{
+    SECItem *context = NULL;
+    SECItem mechItem;
+    CK_PBE_PARAMS pbe_params;
+    CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
+    PK11SlotInfo *slot;
+    PK11SymKey *symKey = NULL;
+    unsigned char ivData[8];
+    
+
+    /* use the purpose to select the low level keygen algorithm */
+    switch (bitGenPurpose) {
+    case pbeBitGenIntegrityKey:
+	switch (hashAlgorithm) {
+	case SEC_OID_SHA1:
+	    mechanism = CKM_PBA_SHA1_WITH_SHA1_HMAC;
+	    break;
+	case SEC_OID_MD2:
+	    mechanism = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN;
+	    break;
+	case SEC_OID_MD5:
+	    mechanism = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN;
+	    break;
+	default:
+	    break;
+	}
+	break;
+    case pbeBitGenCipherIV:
+	if (bitsNeeded > 64) {
+	    break;
+	}
+	if (hashAlgorithm != SEC_OID_SHA1) {
+	    break;
+	}
+	mechanism = CKM_PBE_SHA1_DES3_EDE_CBC;
+	break;
+    case pbeBitGenCipherKey:
+	if (hashAlgorithm != SEC_OID_SHA1) {
+	    break;
+	}
+	switch (bitsNeeded) {
+	case 40:
+	    mechanism = CKM_PBE_SHA1_RC4_40;
+	    break;
+	case 128:
+	    mechanism = CKM_PBE_SHA1_RC4_128;
+	    break;
+	default:
+	    break;
+	}
+    case pbeBitGenIDNull:
+	break;
+    }
+
+    if (mechanism == CKM_INVALID_MECHANISM) {
+	/* we should set an error, but this is a deprecated function, and
+	 * we are keeping bug for bug compatibility;)... */
+	    return NULL;
+    } 
+
+    pbe_params.pInitVector = ivData;
+    pbe_params.pPassword = pwitem->data;
+    pbe_params.ulPasswordLen = pwitem->len;
+    pbe_params.pSalt = salt->data;
+    pbe_params.ulSaltLen = salt->len;
+    pbe_params.ulIteration = iterations;
+    mechItem.data = (unsigned char *) &pbe_params;
+    mechItem.len = sizeof(pbe_params);
+
+
+    slot = PK11_GetInternalSlot();
+    symKey = PK11_RawPBEKeyGen(slot,mechanism,
+					&mechItem, pwitem, PR_FALSE, NULL);
+    PK11_FreeSlot(slot);
+    if (symKey != NULL) {
+	if (bitGenPurpose == pbeBitGenCipherIV) {
+	    /* NOTE: this assumes that bitsNeeded is a multiple of 8! */
+	    SECItem ivItem;
+
+	    ivItem.data = ivData;
+	    ivItem.len = bitsNeeded/8;
+	    context = SECITEM_DupItem(&ivItem);
+	} else {
+	    SECItem *keyData;
+	    PK11_ExtractKeyValue(symKey);
+	    keyData = PK11_GetKeyData(symKey);
+
+	    /* assert bitsNeeded with length? */
+	    if (keyData) {
+	    	context = SECITEM_DupItem(keyData);
+	    }
+	}
+	PK11_FreeSymKey(symKey);
+    }
+
+    return (PBEBitGenContext *)context;
+}
+
+/*
+ * public, Deprecated, This function is only for binary compatibility with 
+ * older applications. Does not support PKCS5v2.
+ * 
+ * Applications should use PK11_PBEKeyGen() for keys and PK11_GetIV() for
+ * iv values rather than generating PBE bits directly.
+ */
+SECItem *
+PBE_GenerateBits(PBEBitGenContext *context)
+{
+    return (SECItem *)context;
+}
+
+/*
+ * public, Deprecated, This function is only for binary compatibility with 
+ * older applications. Does not support PKCS5v2.
+ * 
+ * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for
+ * iv values rather than generating PBE bits directly.
+ */
+void
+PBE_DestroyContext(PBEBitGenContext *context)
+{
+    SECITEM_FreeItem((SECItem *)context,PR_TRUE);
+}
+
+/*
+ * public, deprecated. Replaced with PK11_GetPBEIV().
+ */
+SECItem *
+SEC_PKCS5GetIV(SECAlgorithmID *algid, SECItem *pwitem, PRBool faulty3DES)
+{
+    /* pbe stuff */
+    CK_MECHANISM_TYPE type;
+    SECItem *param = NULL;
+    SECItem *iv = NULL;
+    SECItem src;
+    int iv_len = 0;
+    PK11SymKey *symKey;
+    PK11SlotInfo *slot;
+    CK_PBE_PARAMS_PTR pPBEparams;
+    SECOidTag	pbeAlg;
+
+    pbeAlg = SECOID_GetAlgorithmTag(algid);
+    if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) {
+	unsigned char *ivData;
+	sec_pkcs5V2Parameter *pbeV2_param = NULL;
+
+	/* can only return the IV if the crypto Algorithm exists */
+	if (pbeAlg == SEC_OID_PKCS5_PBKDF2) {
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    goto loser;
+	}
+	pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+	if (pbeV2_param == NULL) {
+	    goto loser;
+	}
+	/* extract the IV from the cipher algid portion of our pkcs 5 v2
+	 * algorithm id */
+    	type = PK11_AlgtagToMechanism(
+    		SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId));
+	param = PK11_ParamFromAlgid(&pbeV2_param->cipherAlgId);
+	sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+	if (!param) {
+	    goto loser;
+	}
+	/* NOTE: NULL is a permissible return here */
+	ivData = PK11_IVFromParam(type, param, &iv_len);
+	src.data = ivData;
+	src.len = iv_len;
+	goto done;
+    }
+
+    type = PK11_AlgtagToMechanism(pbeAlg);
+    param = PK11_ParamFromAlgid(algid);
+    if (param == NULL) {
+	goto done;
+    }
+    slot = PK11_GetInternalSlot();
+    symKey = PK11_RawPBEKeyGen(slot, type, param, pwitem, faulty3DES, NULL);
+    PK11_FreeSlot(slot);
+    if (symKey == NULL) {
+	goto loser;
+    }
+    PK11_FreeSymKey(symKey);
+    pPBEparams = (CK_PBE_PARAMS_PTR)param->data;
+    iv_len = PK11_GetIVLength(type);
+
+    src.data = (unsigned char *)pPBEparams->pInitVector;
+    src.len = iv_len;
+
+done:
+    iv = SECITEM_DupItem(&src);
+
+loser:
+    if (param) {
+	SECITEM_ZfreeItem(param, PR_TRUE);
+    }
+    return iv;
+}
+
+/*
+ * Subs from nss 3.x that are deprecated
+ */
+PBEBitGenContext *
+__PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose,
+	SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded,
+	unsigned int iterations)
+{
+    PORT_Assert("__PBE_CreateContext is Deprecated" == NULL);
+    return NULL;
+}
+
+SECItem *
+__PBE_GenerateBits(PBEBitGenContext *context)
+{
+    PORT_Assert("__PBE_GenerateBits is Deprecated" == NULL);
+    return NULL;
+}
+
+void
+__PBE_DestroyContext(PBEBitGenContext *context)
+{
+    PORT_Assert("__PBE_DestroyContext is Deprecated" == NULL);
+}
+
+SECStatus
+RSA_FormatBlock(SECItem *result, unsigned modulusLen,
+                int blockType, SECItem *data)
+{
+    PORT_Assert("RSA_FormatBlock is Deprecated" == NULL);
+    return SECFailure;
+}
+
+/****************************************************************************
+ *
+ * Now Do The PBE Functions Here...
+ *
+ ****************************************************************************/
+
+static void
+pk11_destroy_ck_pbe_params(CK_PBE_PARAMS *pbe_params)
+{
+    if (pbe_params) {
+	if (pbe_params->pPassword)
+	    PORT_ZFree(pbe_params->pPassword, pbe_params->ulPasswordLen);
+	if (pbe_params->pSalt)
+	    PORT_ZFree(pbe_params->pSalt, pbe_params->ulSaltLen);
+	PORT_ZFree(pbe_params, sizeof(CK_PBE_PARAMS));
+    }
+}
+
+/*
+ * public, deprecated.  use PK11_CreatePBEAlgorithmID or 
+ * PK11_CreatePBEV2AlgorithmID instead. If you needthe pkcs #11 parameters, 
+ * use PK11_ParamFromAlgid from the algorithm id you created using 
+ * PK11_CreatePBEAlgorithmID or PK11_CreatePBEV2AlgorithmID.
+ */
+SECItem * 
+PK11_CreatePBEParams(SECItem *salt, SECItem *pwd, unsigned int iterations)
+{
+    CK_PBE_PARAMS *pbe_params = NULL;
+    SECItem *paramRV = NULL;
+
+    paramRV = SECITEM_AllocItem(NULL, NULL, sizeof(CK_PBE_PARAMS));
+    if (!paramRV ) {
+	goto loser;
+    }
+    /* init paramRV->data with zeros. SECITEM_AllocItem does not do it */
+    PORT_Memset(paramRV->data, 0, sizeof(CK_PBE_PARAMS));
+
+    pbe_params = (CK_PBE_PARAMS *)paramRV->data;
+    pbe_params->pPassword = (CK_CHAR_PTR)PORT_ZAlloc(pwd->len);
+    if (!pbe_params->pPassword) {
+        goto loser;
+    }
+    PORT_Memcpy(pbe_params->pPassword, pwd->data, pwd->len);
+    pbe_params->ulPasswordLen = pwd->len;
+
+    pbe_params->pSalt = (CK_CHAR_PTR)PORT_ZAlloc(salt->len);
+    if (!pbe_params->pSalt) {
+	goto loser;
+    }
+    PORT_Memcpy(pbe_params->pSalt, salt->data, salt->len);
+    pbe_params->ulSaltLen = salt->len;
+
+    pbe_params->ulIteration = (CK_ULONG)iterations;
+    return paramRV;
+
+loser:
+    if (pbe_params)
+        pk11_destroy_ck_pbe_params(pbe_params);
+    if (paramRV) 
+    	PORT_ZFree(paramRV, sizeof(SECItem));
+    return NULL;
+}
+
+/*
+ * public, deprecated.
+ */
+void
+PK11_DestroyPBEParams(SECItem *pItem)
+{
+    if (pItem) {
+	CK_PBE_PARAMS * params = (CK_PBE_PARAMS *)(pItem->data);
+	if (params)
+	    pk11_destroy_ck_pbe_params(params);
+	PORT_ZFree(pItem, sizeof(SECItem));
+    }
+}
+
+/*
+ * public, Partially supports PKCS5 V2 (some parameters are not controllable
+ * through this interface). Use PK11_CreatePBEV2AlgorithmID() if you need
+ * finer control these.
+ */
+SECAlgorithmID *
+PK11_CreatePBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt)
+{
+    SECAlgorithmID *algid = NULL;
+    algid = sec_pkcs5CreateAlgorithmID(algorithm,
+		 SEC_OID_UNKNOWN, SEC_OID_UNKNOWN, NULL, 0, salt, iteration);
+    return algid;
+}
+
+/*
+ * public, fully support pkcs5v2.
+ */
+SECAlgorithmID *
+PK11_CreatePBEV2AlgorithmID(SECOidTag pbeAlgTag, SECOidTag cipherAlgTag,
+			    SECOidTag prfAlgTag, int keyLength, int iteration, 
+			    SECItem *salt)
+{
+    SECAlgorithmID *algid = NULL;
+    algid = sec_pkcs5CreateAlgorithmID(pbeAlgTag, cipherAlgTag, prfAlgTag,
+					NULL, keyLength, salt, iteration);
+    return algid;
+}
+
+/*
+ * private.
+ */
+PK11SymKey *
+pk11_RawPBEKeyGenWithKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 
+			SECItem *params, CK_KEY_TYPE keyType, int keyLen,
+			SECItem *pwitem, void *wincx)
+{
+    CK_ULONG pwLen;
+    /* do some sanity checks */
+    if ((params == NULL) || (params->data == NULL)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    if (type == CKM_INVALID_MECHANISM) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return NULL;
+    }
+
+    /* set the password pointer in the parameters... */
+    if (type == CKM_PKCS5_PBKD2) {
+    	CK_PKCS5_PBKD2_PARAMS *pbev2_params;
+	if (params->len < sizeof(CK_PKCS5_PBKD2_PARAMS)) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return NULL;
+	}
+	pbev2_params = (CK_PKCS5_PBKD2_PARAMS *)params->data;
+	pbev2_params->pPassword = pwitem->data;
+	pwLen = pwitem->len;
+	pbev2_params->ulPasswordLen = &pwLen;
+    } else {
+    	CK_PBE_PARAMS *pbe_params;
+	if (params->len < sizeof(CK_PBE_PARAMS)) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return NULL;
+	}
+	pbe_params = (CK_PBE_PARAMS *)params->data;
+	pbe_params->pPassword = pwitem->data;
+	pbe_params->ulPasswordLen = pwitem->len;
+    }
+
+    /* generate the key (and sometimes the IV as a side effect...) */
+    return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, params, keyType, 
+	   keyLen, NULL, CKF_SIGN|CKF_ENCRYPT|CKF_DECRYPT|CKF_UNWRAP|CKF_WRAP, 
+	   0, wincx);
+}
+
+/*
+ * public, deprecated. use PK11_PBEKeyGen instead.
+ */
+PK11SymKey *
+PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *mech,
+			 SECItem *pwitem, PRBool faulty3DES, void *wincx)
+{
+    if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) {
+	type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC;
+    }
+    return pk11_RawPBEKeyGenWithKeyType(slot, type, mech, -1, 0, pwitem, wincx);
+}
+
+/*
+ * pubic, supports pkcs5 v2.
+ *
+ * Create symkey from a PBE key. The algid can be created with
+ *  PK11_CreatePBEV2AlgorithmID and PK11_CreatePBEAlgorithmID, or by
+ *  extraction of der data.
+ */
+PK11SymKey *
+PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem,
+	       					PRBool faulty3DES, void *wincx)
+{
+    CK_MECHANISM_TYPE type;
+    SECItem *param = NULL;
+    PK11SymKey *symKey;
+    SECOidTag	pbeAlg;
+    CK_KEY_TYPE keyType = -1;
+    int keyLen = 0;
+
+    pbeAlg = SECOID_GetAlgorithmTag(algid);
+    /* if we're using PKCS5v2, extract the additional information we need
+     * (key length, key type, and pbeAlg). */
+    if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) {
+	CK_MECHANISM_TYPE cipherMech;
+	sec_pkcs5V2Parameter *pbeV2_param;
+
+	pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+	if (pbeV2_param == NULL) {
+	    return NULL;
+	}
+	cipherMech = PK11_AlgtagToMechanism(
+		SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId));
+	pbeAlg = SECOID_GetAlgorithmTag(&pbeV2_param->pbeAlgId);
+	param = PK11_ParamFromAlgid(&pbeV2_param->pbeAlgId);
+	sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+	keyLen = SEC_PKCS5GetKeyLength(algid);
+	if (keyLen == -1) {
+	    keyLen = 0;
+	}
+	keyType = PK11_GetKeyType(cipherMech, keyLen);
+    } else {
+	param = PK11_ParamFromAlgid(algid);
+    }
+    if(param == NULL) {
+	return NULL;
+    }
+
+    type = PK11_AlgtagToMechanism(pbeAlg);	
+    if (type == CKM_INVALID_MECHANISM) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return NULL;
+    }
+    if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) {
+	type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC;
+    }
+    symKey = pk11_RawPBEKeyGenWithKeyType(slot, type, param, keyType, keyLen, 
+					pwitem, wincx);
+
+    SECITEM_ZfreeItem(param, PR_TRUE);
+    return symKey;
+}
+
+/*
+ * public, supports pkcs5v2
+ */
+SECItem *
+PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem)
+{
+    return SEC_PKCS5GetIV(algid, pwitem, PR_FALSE);
+}
+
+CK_MECHANISM_TYPE
+pk11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param, 
+			   SECItem *pbe_pwd, PRBool faulty3DES)
+{
+    int keyLen = 0;
+    SECOidTag algTag = SEC_PKCS5GetCryptoAlgorithm(algid);
+    CK_MECHANISM_TYPE mech = PK11_AlgtagToMechanism(algTag);
+    CK_MECHANISM_TYPE returnedMechanism = CKM_INVALID_MECHANISM;
+    SECItem *iv = NULL;
+
+    if (mech == CKM_INVALID_MECHANISM) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	goto loser;
+    }
+    if (PK11_GetIVLength(mech)) {
+	iv = SEC_PKCS5GetIV(algid, pbe_pwd, faulty3DES);
+	if (iv == NULL) {
+	    goto loser;
+	}
+    }
+
+    keyLen = SEC_PKCS5GetKeyLength(algid);
+
+    *param = pk11_ParamFromIVWithLen(mech, iv, keyLen);
+    if (*param == NULL) {
+	goto loser;
+    }
+    returnedMechanism = mech;
+
+loser:
+    if (iv) {
+	SECITEM_FreeItem(iv,PR_TRUE);
+    }
+    return returnedMechanism;
+}
+
+/*
+ * public, supports pkcs5 v2
+ *
+ * get a the crypto mechanism directly from the pbe algorithmid.
+ *
+ * it's important to go directly from the algorithm id so that we can
+ * handle both the PKCS #5 v1, PKCS #12, and PKCS #5 v2 cases.
+ *
+ * This function returns both the mechanism an the paramter for the mechanism.
+ * The caller is responsible for freeing the parameter.
+ */
+CK_MECHANISM_TYPE
+PK11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param, 
+			   SECItem *pbe_pwd)
+{
+    return pk11_GetPBECryptoMechanism(algid, param, pbe_pwd, PR_FALSE);
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11pk12.c b/mozilla/security/nss/lib/pk11wrap/pk11pk12.c
new file mode 100644
index 0000000..c135b7c
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11pk12.c
@@ -0,0 +1,559 @@
+
+/* ***** 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 ***** */
+/*
+ * This file PKCS #12 fuctions that should really be moved to the
+ * PKCS #12 directory, however we can't do that in a point release
+ * because that will break binary compatibility, so we keep them here for now.
+ */
+
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "key.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+
+
+/* These data structures should move to a common .h file shared between the
+ * wrappers and the pkcs 12 code. */
+
+/*
+** RSA Raw Private Key structures
+*/
+
+/* member names from PKCS#1, section 7.2 */
+struct SECKEYRSAPrivateKeyStr {
+    PRArenaPool * arena;
+    SECItem version;
+    SECItem modulus;
+    SECItem publicExponent;
+    SECItem privateExponent;
+    SECItem prime1;
+    SECItem prime2;
+    SECItem exponent1;
+    SECItem exponent2;
+    SECItem coefficient;
+};
+typedef struct SECKEYRSAPrivateKeyStr SECKEYRSAPrivateKey;
+
+
+/*
+** DSA Raw Private Key structures
+*/
+
+struct SECKEYDSAPrivateKeyStr {
+    SECKEYPQGParams params;
+    SECItem privateValue;
+};
+typedef struct SECKEYDSAPrivateKeyStr SECKEYDSAPrivateKey;
+
+/*
+** Diffie-Hellman Raw Private Key structures
+** Structure member names suggested by PKCS#3.
+*/
+struct SECKEYDHPrivateKeyStr {
+    PRArenaPool * arena;
+    SECItem prime;
+    SECItem base;
+    SECItem privateValue;
+};
+typedef struct SECKEYDHPrivateKeyStr SECKEYDHPrivateKey;
+
+/*
+** raw private key object
+*/
+struct SECKEYRawPrivateKeyStr {
+    PLArenaPool *arena;
+    KeyType keyType;
+    union {
+        SECKEYRSAPrivateKey rsa;
+        SECKEYDSAPrivateKey dsa;
+        SECKEYDHPrivateKey  dh;
+    } u;
+};
+typedef struct SECKEYRawPrivateKeyStr SECKEYRawPrivateKey;
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+/* ASN1 Templates for new decoder/encoder */
+/*
+ * Attribute value for PKCS8 entries (static?)
+ */
+const SEC_ASN1Template SECKEY_AttributeTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+        0, NULL, sizeof(SECKEYAttribute) },
+    { SEC_ASN1_OBJECT_ID, offsetof(SECKEYAttribute, attrType) },
+    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(SECKEYAttribute, attrValue),
+        SEC_ASN1_SUB(SEC_AnyTemplate) },
+    { 0 }
+};
+
+const SEC_ASN1Template SECKEY_SetOfAttributeTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SECKEY_AttributeTemplate },
+};
+
+const SEC_ASN1Template SECKEY_PrivateKeyInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPrivateKeyInfo) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPrivateKeyInfo,version) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+        offsetof(SECKEYPrivateKeyInfo,algorithm),
+        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPrivateKeyInfo,privateKey) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+        offsetof(SECKEYPrivateKeyInfo,attributes),
+        SECKEY_SetOfAttributeTemplate },
+    { 0 }
+};
+
+const SEC_ASN1Template SECKEY_PointerToPrivateKeyInfoTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SECKEY_PrivateKeyInfoTemplate }
+};
+
+const SEC_ASN1Template SECKEY_RSAPrivateKeyExportTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.version) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.modulus) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.publicExponent) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.privateExponent) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.prime1) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.prime2) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.exponent1) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.exponent2) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.rsa.coefficient) },
+    { 0 }
+};
+
+const SEC_ASN1Template SECKEY_DSAPrivateKeyExportTemplate[] = {
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.dsa.privateValue) },
+};
+
+const SEC_ASN1Template SECKEY_DHPrivateKeyExportTemplate[] = {
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.dh.privateValue) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.dh.base) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey,u.dh.prime) },
+};
+
+const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+        0, NULL, sizeof(SECKEYEncryptedPrivateKeyInfo) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+        offsetof(SECKEYEncryptedPrivateKeyInfo,algorithm),
+        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OCTET_STRING,
+        offsetof(SECKEYEncryptedPrivateKeyInfo,encryptedData) },
+    { 0 }
+};
+
+const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[] = {
+        { SEC_ASN1_POINTER, 0, SECKEY_EncryptedPrivateKeyInfoTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_EncryptedPrivateKeyInfoTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToEncryptedPrivateKeyInfoTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PrivateKeyInfoTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToPrivateKeyInfoTemplate)
+
+/*
+ * See bugzilla bug 125359
+ * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
+ * all of the templates above that en/decode into integers must be converted
+ * from ASN.1's signed integer type.  This is done by marking either the
+ * source or destination (encoding or decoding, respectively) type as
+ * siUnsignedInteger.
+ */
+
+static void
+prepare_rsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
+{
+    key->u.rsa.modulus.type = siUnsignedInteger;
+    key->u.rsa.publicExponent.type = siUnsignedInteger;
+    key->u.rsa.privateExponent.type = siUnsignedInteger;
+    key->u.rsa.prime1.type = siUnsignedInteger;
+    key->u.rsa.prime2.type = siUnsignedInteger;
+    key->u.rsa.exponent1.type = siUnsignedInteger;
+    key->u.rsa.exponent2.type = siUnsignedInteger;
+    key->u.rsa.coefficient.type = siUnsignedInteger;
+}
+
+static void
+prepare_dsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
+{
+    key->u.dsa.privateValue.type = siUnsignedInteger;
+    key->u.dsa.params.prime.type = siUnsignedInteger;
+    key->u.dsa.params.subPrime.type = siUnsignedInteger;
+    key->u.dsa.params.base.type = siUnsignedInteger;
+}
+
+static void
+prepare_dh_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
+{
+    key->u.dh.privateValue.type = siUnsignedInteger;
+    key->u.dh.prime.type = siUnsignedInteger;
+    key->u.dh.base.type = siUnsignedInteger;
+}
+
+
+SECStatus
+PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, SECItem *derPKI, 
+	SECItem *nickname, SECItem *publicValue, PRBool isPerm, 
+	PRBool isPrivate, unsigned int keyUsage, void *wincx) 
+{
+    return PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, derPKI,
+	nickname, publicValue, isPerm, isPrivate, keyUsage, NULL, wincx);
+}
+
+SECStatus
+PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECItem *derPKI, 
+	SECItem *nickname, SECItem *publicValue, PRBool isPerm, 
+	PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey** privk,
+	void *wincx) 
+{
+    SECKEYPrivateKeyInfo *pki = NULL;
+    PRArenaPool *temparena = NULL;
+    SECStatus rv = SECFailure;
+
+    temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!temparena)
+        return rv;
+    pki = PORT_ArenaZNew(temparena, SECKEYPrivateKeyInfo);
+    if (!pki) {
+        PORT_FreeArena(temparena, PR_FALSE);
+        return rv;
+    }
+    pki->arena = temparena;
+
+    rv = SEC_ASN1DecodeItem(pki->arena, pki, SECKEY_PrivateKeyInfoTemplate,
+		derPKI);
+    if( rv != SECSuccess ) {
+	goto finish;
+    }
+
+    rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
+		publicValue, isPerm, isPrivate, keyUsage, privk, wincx);
+
+finish:
+    /* this zeroes the key and frees the arena */
+    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE /*freeit*/);
+    return rv;
+}
+        
+SECStatus
+PK11_ImportAndReturnPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk, 
+	SECItem *nickname, SECItem *publicValue, PRBool isPerm, 
+	PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk,
+	void *wincx) 
+{
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
+    CK_KEY_TYPE keyType = CKK_RSA;
+    CK_OBJECT_HANDLE objectID;
+    CK_ATTRIBUTE theTemplate[20];
+    int templateCount = 0;
+    SECStatus rv = SECFailure;
+    CK_ATTRIBUTE *attrs;
+    CK_ATTRIBUTE *signedattr = NULL;
+    int signedcount = 0;
+    CK_ATTRIBUTE *ap;
+    SECItem *ck_id = NULL;
+
+    attrs = theTemplate;
+
+
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse, 
+						sizeof(CK_BBOOL) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_SENSITIVE, isPrivate ? &cktrue : &ckfalse, 
+						sizeof(CK_BBOOL) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_PRIVATE, isPrivate ? &cktrue : &ckfalse,
+						 sizeof(CK_BBOOL) ); attrs++;
+
+    switch (lpk->keyType) {
+    case rsaKey:
+	    keyType = CKK_RSA;
+	    PK11_SETATTRS(attrs, CKA_UNWRAP, (keyUsage & KU_KEY_ENCIPHERMENT) ?
+				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
+	    PK11_SETATTRS(attrs, CKA_DECRYPT, (keyUsage & KU_DATA_ENCIPHERMENT) ?
+				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
+	    PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? 
+				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
+	    PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, 
+				(keyUsage & KU_DIGITAL_SIGNATURE) ? 
+				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
+	    ck_id = PK11_MakeIDFromPubKey(&lpk->u.rsa.modulus);
+	    if (ck_id == NULL) {
+		goto loser;
+	    }
+	    PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++;
+	    if (nickname) {
+		PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; 
+	    } 
+	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_MODULUS, lpk->u.rsa.modulus.data,
+						lpk->u.rsa.modulus.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, 
+	     			lpk->u.rsa.publicExponent.data,
+				lpk->u.rsa.publicExponent.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_PRIVATE_EXPONENT, 
+	     			lpk->u.rsa.privateExponent.data,
+				lpk->u.rsa.privateExponent.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_PRIME_1, 
+	     			lpk->u.rsa.prime1.data,
+				lpk->u.rsa.prime1.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_PRIME_2, 
+	     			lpk->u.rsa.prime2.data,
+				lpk->u.rsa.prime2.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_EXPONENT_1, 
+	     			lpk->u.rsa.exponent1.data,
+				lpk->u.rsa.exponent1.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_EXPONENT_2, 
+	     			lpk->u.rsa.exponent2.data,
+				lpk->u.rsa.exponent2.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_COEFFICIENT, 
+	     			lpk->u.rsa.coefficient.data,
+				lpk->u.rsa.coefficient.len); attrs++;
+	    break;
+    case dsaKey:
+	    keyType = CKK_DSA;
+	    /* To make our intenal PKCS #11 module work correctly with 
+	     * our database, we need to pass in the public key value for 
+	     * this dsa key. We have a netscape only CKA_ value to do this.
+	     * Only send it to internal slots */
+	    if( publicValue == NULL ) {
+		goto loser;
+	    }
+	    if (PK11_IsInternal(slot)) {
+	        PK11_SETATTRS(attrs, CKA_NETSCAPE_DB,
+				publicValue->data, publicValue->len); attrs++;
+	    }
+	    PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); attrs++;
+	    PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &cktrue, sizeof(CK_BBOOL)); attrs++;
+	    if(nickname) {
+		PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
+		attrs++; 
+	    } 
+	    ck_id = PK11_MakeIDFromPubKey(publicValue);
+	    if (ck_id == NULL) {
+		goto loser;
+	    }
+	    PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++;
+	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_PRIME,    lpk->u.dsa.params.prime.data,
+				lpk->u.dsa.params.prime.len); attrs++;
+	    PK11_SETATTRS(attrs,CKA_SUBPRIME,lpk->u.dsa.params.subPrime.data,
+				lpk->u.dsa.params.subPrime.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_BASE,  lpk->u.dsa.params.base.data,
+					lpk->u.dsa.params.base.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VALUE,    lpk->u.dsa.privateValue.data, 
+					lpk->u.dsa.privateValue.len); attrs++;
+	    break;
+     case dhKey:
+	    keyType = CKK_DH;
+	    /* To make our intenal PKCS #11 module work correctly with 
+	     * our database, we need to pass in the public key value for 
+	     * this dh key. We have a netscape only CKA_ value to do this.
+	     * Only send it to internal slots */
+	    if (PK11_IsInternal(slot)) {
+	        PK11_SETATTRS(attrs, CKA_NETSCAPE_DB,
+				publicValue->data, publicValue->len); attrs++;
+	    }
+	    PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); attrs++;
+	    if(nickname) {
+		PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
+		attrs++; 
+	    } 
+	    ck_id = PK11_MakeIDFromPubKey(publicValue);
+	    if (ck_id == NULL) {
+		goto loser;
+	    }
+	    PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++;
+	    signedattr = attrs;
+	    PK11_SETATTRS(attrs, CKA_PRIME,    lpk->u.dh.prime.data,
+				lpk->u.dh.prime.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_BASE,  lpk->u.dh.base.data,
+					lpk->u.dh.base.len); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VALUE,    lpk->u.dh.privateValue.data, 
+					lpk->u.dh.privateValue.len); attrs++;
+	    break;
+	/* what about fortezza??? */
+    default:
+	    PORT_SetError(SEC_ERROR_BAD_KEY);
+	    goto loser;
+    }
+    templateCount = attrs - theTemplate;
+    PORT_Assert(templateCount <= sizeof(theTemplate)/sizeof(CK_ATTRIBUTE));
+    PORT_Assert(signedattr != NULL);
+    signedcount = attrs - signedattr;
+
+    for (ap=signedattr; signedcount; ap++, signedcount--) {
+	pk11_SignedToUnsigned(ap);
+    }
+
+    rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION,
+			theTemplate, templateCount, isPerm, &objectID);
+
+    /* create and return a SECKEYPrivateKey */
+    if( rv == SECSuccess && privk != NULL) {
+	*privk = PK11_MakePrivKey(slot, lpk->keyType, !isPerm, objectID, wincx);
+	if( *privk == NULL ) {
+	    rv = SECFailure;
+	}
+    }
+loser:
+    if (ck_id) {
+	SECITEM_ZfreeItem(ck_id, PR_TRUE);
+    }
+    return rv;
+}
+
+SECStatus
+PK11_ImportPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk, 
+	SECItem *nickname, SECItem *publicValue, PRBool isPerm, 
+	PRBool isPrivate, unsigned int keyUsage, void *wincx) 
+{
+    return PK11_ImportAndReturnPrivateKey(slot, lpk, nickname, publicValue,
+	isPerm, isPrivate, keyUsage, NULL, wincx);
+}
+
+SECStatus
+PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot,
+	SECKEYPrivateKeyInfo *pki, SECItem *nickname, SECItem *publicValue,
+	PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
+	SECKEYPrivateKey **privk, void *wincx) 
+{
+    CK_KEY_TYPE keyType = CKK_RSA;
+    SECStatus rv = SECFailure;
+    SECKEYRawPrivateKey *lpk = NULL;
+    const SEC_ASN1Template *keyTemplate, *paramTemplate;
+    void *paramDest = NULL;
+    PRArenaPool *arena;
+
+    arena = PORT_NewArena(2048);
+    if(!arena) {
+	return SECFailure;
+    }
+
+    /* need to change this to use RSA/DSA keys */
+    lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena,
+						  sizeof(SECKEYRawPrivateKey));
+    if(lpk == NULL) {
+	goto loser;
+    }
+    lpk->arena = arena;
+
+    switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
+	case SEC_OID_PKCS1_RSA_ENCRYPTION:
+	    prepare_rsa_priv_key_export_for_asn1(lpk);
+	    keyTemplate = SECKEY_RSAPrivateKeyExportTemplate;
+	    paramTemplate = NULL;
+	    paramDest = NULL;
+	    lpk->keyType = rsaKey;
+	    keyType = CKK_RSA;
+	    break;
+	case SEC_OID_ANSIX9_DSA_SIGNATURE:
+	    prepare_dsa_priv_key_export_for_asn1(lpk);
+	    keyTemplate = SECKEY_DSAPrivateKeyExportTemplate;
+	    paramTemplate = SECKEY_PQGParamsTemplate;
+	    paramDest = &(lpk->u.dsa.params);
+	    lpk->keyType = dsaKey;
+	    keyType = CKK_DSA;
+	    break;
+	case SEC_OID_X942_DIFFIE_HELMAN_KEY:
+	    if(!publicValue) {
+		goto loser;
+	    }
+	    prepare_dh_priv_key_export_for_asn1(lpk);
+	    keyTemplate = SECKEY_DHPrivateKeyExportTemplate;
+	    paramTemplate = NULL;
+	    paramDest = NULL;
+	    lpk->keyType = dhKey;
+	    keyType = CKK_DH;
+	    break;
+
+	default:
+	    keyTemplate   = NULL;
+	    paramTemplate = NULL;
+	    paramDest     = NULL;
+	    break;
+    }
+
+    if(!keyTemplate) {
+	goto loser;
+    }
+
+    /* decode the private key and any algorithm parameters */
+    rv = SEC_ASN1DecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
+    if(rv != SECSuccess) {
+	goto loser;
+    }
+    if(paramDest && paramTemplate) {
+	rv = SEC_ASN1DecodeItem(arena, paramDest, paramTemplate, 
+				 &(pki->algorithm.parameters));
+	if(rv != SECSuccess) {
+	    goto loser;
+	}
+    }
+
+    rv = PK11_ImportAndReturnPrivateKey(slot,lpk,nickname,publicValue, isPerm, 
+	isPrivate,  keyUsage, privk, wincx);
+
+
+loser:
+    if (lpk!= NULL) {
+	PORT_FreeArena(arena, PR_TRUE);
+    }
+
+    return rv;
+}
+
+SECStatus
+PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, SECKEYPrivateKeyInfo *pki, 
+	SECItem *nickname, SECItem *publicValue, PRBool isPerm, 
+	PRBool isPrivate, unsigned int keyUsage, void *wincx) 
+{
+    return PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
+	publicValue, isPerm, isPrivate, keyUsage, NULL, wincx);
+
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11pqg.c b/mozilla/security/nss/lib/pk11wrap/pk11pqg.c
new file mode 100644
index 0000000..e0443e1
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11pqg.c
@@ -0,0 +1,470 @@
+/* ***** 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-2001
+ * 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 ***** */
+/* Thse functions are stub functions which will get replaced with calls through
+ * PKCS #11.
+ */
+
+#include "pk11func.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11t.h"
+#include "pk11pqg.h"
+#include "secerr.h"
+
+
+/* Generate PQGParams and PQGVerify structs.
+ * Length of P specified by j.  Length of h will match length of P.
+ * Length of SEED in bytes specified in seedBytes.
+ * seedBbytes must be in the range [20..255] or an error will result.
+ */
+extern SECStatus
+PK11_PQG_ParamGenSeedLen( unsigned int j, unsigned int seedBytes,
+				 PQGParams **pParams, PQGVerify **pVfy)
+{
+    PK11SlotInfo *slot = NULL;
+    CK_ATTRIBUTE genTemplate[5];
+    CK_ATTRIBUTE *attrs = genTemplate;
+    int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
+    CK_MECHANISM mechanism;
+    CK_OBJECT_HANDLE objectID = CK_INVALID_HANDLE;
+    CK_RV crv;
+    CK_ATTRIBUTE pTemplate[] = {
+	{ CKA_PRIME, NULL, 0 },
+	{ CKA_SUBPRIME, NULL, 0 },
+	{ CKA_BASE, NULL, 0 },
+    };
+    CK_ATTRIBUTE vTemplate[] = {
+	{ CKA_NETSCAPE_PQG_COUNTER, NULL, 0 },
+	{ CKA_NETSCAPE_PQG_SEED, NULL, 0 },
+	{ CKA_NETSCAPE_PQG_H, NULL, 0 },
+    };
+    int pTemplateCount = sizeof(pTemplate)/sizeof(pTemplate[0]);
+    int vTemplateCount = sizeof(vTemplate)/sizeof(vTemplate[0]);
+    PRArenaPool *parena = NULL;
+    PRArenaPool *varena = NULL;
+    PQGParams *params = NULL;
+    PQGVerify *verify = NULL;
+    CK_ULONG primeBits = PQG_INDEX_TO_PBITS(j);
+    CK_ULONG seedBits = seedBytes*8;
+
+    *pParams = NULL;
+    *pVfy =  NULL;
+
+    if (primeBits == (CK_ULONG)-1) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	goto loser;
+    }
+    PK11_SETATTRS(attrs, CKA_PRIME_BITS,&primeBits,sizeof(primeBits)); attrs++;
+    if (seedBits != 0) {
+    	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_SEED_BITS, 
+					&seedBits, sizeof(seedBits)); attrs++;
+    }
+    count = attrs - genTemplate;
+    PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE));
+
+    slot = PK11_GetInternalSlot();
+    if (slot == NULL) {
+	/* set error */
+	goto loser;
+    }
+
+    /* Initialize the Key Gen Mechanism */
+    mechanism.mechanism = CKM_DSA_PARAMETER_GEN;
+    mechanism.pParameter = NULL;
+    mechanism.ulParameterLen = 0;
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GenerateKey(slot->session,
+			 &mechanism, genTemplate, count, &objectID);
+    PK11_ExitSlotMonitor(slot);
+
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	goto loser;
+    }
+
+    parena = PORT_NewArena(60);
+    if (!parena) {
+	goto loser;
+    }        
+
+    crv = PK11_GetAttributes(parena, slot, objectID, pTemplate, pTemplateCount);
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	goto loser;
+    }
+
+
+    params = (PQGParams *)PORT_ArenaAlloc(parena,sizeof(PQGParams));
+    if (params == NULL) {
+	goto loser;
+    }
+
+    /* fill in Params */
+    params->arena = parena;
+    params->prime.type = siUnsignedInteger;
+    params->prime.data = pTemplate[0].pValue;
+    params->prime.len = pTemplate[0].ulValueLen;
+    params->subPrime.type = siUnsignedInteger;
+    params->subPrime.data = pTemplate[1].pValue;
+    params->subPrime.len = pTemplate[1].ulValueLen;
+    params->base.type = siUnsignedInteger;
+    params->base.data = pTemplate[2].pValue;
+    params->base.len = pTemplate[2].ulValueLen;
+
+
+    varena = PORT_NewArena(60);
+    if (!varena) {
+	goto loser;
+    }        
+
+    crv = PK11_GetAttributes(varena, slot, objectID, vTemplate, vTemplateCount);
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	goto loser;
+    }
+
+
+    verify = (PQGVerify *)PORT_ArenaAlloc(varena,sizeof(PQGVerify));
+    if (verify == NULL) {
+	goto loser;
+    }
+    /* fill in Params */
+    verify->arena = varena;
+    verify->counter = (unsigned int)(*(CK_ULONG*)vTemplate[0].pValue);
+    verify->seed.type = siUnsignedInteger;
+    verify->seed.data = vTemplate[1].pValue;
+    verify->seed.len = vTemplate[1].ulValueLen;
+    verify->h.type = siUnsignedInteger;
+    verify->h.data = vTemplate[2].pValue;
+    verify->h.len = vTemplate[2].ulValueLen;
+
+    PK11_DestroyObject(slot,objectID);
+    PK11_FreeSlot(slot);
+
+    *pParams = params;
+    *pVfy =  verify;
+
+    return SECSuccess;
+
+loser:
+    if (objectID != CK_INVALID_HANDLE) {
+	PK11_DestroyObject(slot,objectID);
+    }
+    if (parena != NULL) {
+	PORT_FreeArena(parena,PR_FALSE);
+    }
+    if (varena != NULL) {
+	PORT_FreeArena(varena,PR_FALSE);
+    }
+    if (slot) {
+	PK11_FreeSlot(slot);
+    }
+    return SECFailure;
+}
+
+/* Generate PQGParams and PQGVerify structs.
+ * Length of seed and length of h both equal length of P. 
+ * All lengths are specified by "j", according to the table above.
+ */
+extern SECStatus
+PK11_PQG_ParamGen(unsigned int j, PQGParams **pParams, PQGVerify **pVfy)
+{
+    return PK11_PQG_ParamGenSeedLen(j, 0, pParams, pVfy);
+}
+
+/*  Test PQGParams for validity as DSS PQG values.
+ *  If vfy is non-NULL, test PQGParams to make sure they were generated
+ *       using the specified seed, counter, and h values.
+ *
+ *  Return value indicates whether Verification operation ran successfully
+ *  to completion, but does not indicate if PQGParams are valid or not.
+ *  If return value is SECSuccess, then *pResult has these meanings:
+ *       SECSuccess: PQGParams are valid.
+ *       SECFailure: PQGParams are invalid.
+ */
+
+extern SECStatus
+PK11_PQG_VerifyParams(const PQGParams *params, const PQGVerify *vfy, 
+							SECStatus *result)
+{
+    CK_ATTRIBUTE keyTempl[] = {
+	{ CKA_CLASS, NULL, 0 },
+	{ CKA_KEY_TYPE, NULL, 0 },
+	{ CKA_PRIME, NULL, 0 },
+	{ CKA_SUBPRIME, NULL, 0 },
+	{ CKA_BASE, NULL, 0 },
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_NETSCAPE_PQG_COUNTER, NULL, 0 },
+	{ CKA_NETSCAPE_PQG_SEED, NULL, 0 },
+	{ CKA_NETSCAPE_PQG_H, NULL, 0 },
+    };
+    CK_ATTRIBUTE *attrs;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_OBJECT_CLASS class = CKO_KG_PARAMETERS;
+    CK_KEY_TYPE keyType = CKK_DSA;
+    SECStatus rv = SECSuccess;
+    PK11SlotInfo *slot;
+    int keyCount;
+    CK_OBJECT_HANDLE objectID;
+    CK_ULONG counter;
+    CK_RV crv;
+
+    attrs = keyTempl;
+    PK11_SETATTRS(attrs, CKA_CLASS, &class, sizeof(class)); attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++;
+    PK11_SETATTRS(attrs, CKA_PRIME, params->prime.data, 
+						params->prime.len); attrs++;
+    PK11_SETATTRS(attrs, CKA_SUBPRIME, params->subPrime.data, 
+						params->subPrime.len); attrs++;
+    PK11_SETATTRS(attrs, CKA_BASE,params->base.data,params->base.len); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, &ckfalse, sizeof(ckfalse)); attrs++;
+    if (vfy) {
+	counter = vfy->counter;
+	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_COUNTER, 
+			&counter, sizeof(counter)); attrs++;
+	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_SEED, 
+			vfy->seed.data, vfy->seed.len); attrs++;
+	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_H, 
+			vfy->h.data, vfy->h.len); attrs++;
+    }
+
+    keyCount = attrs - keyTempl;
+    PORT_Assert(keyCount <= sizeof(keyTempl)/sizeof(keyTempl[0]));
+
+
+    slot = PK11_GetInternalSlot();
+    if (slot == NULL) {
+	return SECFailure;
+    }
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_CreateObject(slot->session, keyTempl, keyCount, 
+								&objectID);
+    PK11_ExitSlotMonitor(slot);
+
+    /* throw away the keys, we only wanted the return code */
+    PK11_DestroyObject(slot,objectID);
+    PK11_FreeSlot(slot);
+
+    *result = SECSuccess;
+    if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
+	*result = SECFailure;
+    } else if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	rv = SECFailure;
+    }
+    return rv;
+
+}
+
+
+
+/**************************************************************************
+ *  Free the PQGParams struct and the things it points to.                *
+ **************************************************************************/
+extern void 
+PK11_PQG_DestroyParams(PQGParams *params) {
+    if (params == NULL) 
+    	return;
+    if (params->arena != NULL) {
+	PORT_FreeArena(params->arena, PR_FALSE);	/* don't zero it */
+    } else {
+	SECITEM_FreeItem(&params->prime,    PR_FALSE); /* don't free prime */
+	SECITEM_FreeItem(&params->subPrime, PR_FALSE); /* don't free subPrime */
+	SECITEM_FreeItem(&params->base,     PR_FALSE); /* don't free base */
+	PORT_Free(params);
+    }
+}
+
+/**************************************************************************
+ *  Free the PQGVerify struct and the things it points to.                *
+ **************************************************************************/
+extern void
+PK11_PQG_DestroyVerify(PQGVerify *vfy) {
+    if (vfy == NULL) 
+    	return;
+    if (vfy->arena != NULL) {
+	PORT_FreeArena(vfy->arena, PR_FALSE);	/* don't zero it */
+    } else {
+	SECITEM_FreeItem(&vfy->seed,   PR_FALSE); /* don't free seed */
+	SECITEM_FreeItem(&vfy->h,      PR_FALSE); /* don't free h */
+	PORT_Free(vfy);
+    }
+}
+
+#define PQG_DEFAULT_CHUNKSIZE 2048	/* bytes */
+
+/**************************************************************************
+ *  Return a pointer to a new PQGParams struct that is constructed from   *
+ *  copies of the arguments passed in.                                    *
+ *  Return NULL on failure.                                               *
+ **************************************************************************/
+extern PQGParams *
+PK11_PQG_NewParams(const SECItem * prime, const SECItem * subPrime, 
+                                 		const SECItem * base) {
+    PRArenaPool *arena;
+    PQGParams *dest;
+    SECStatus status;
+
+    arena = PORT_NewArena(PQG_DEFAULT_CHUNKSIZE);
+    if (arena == NULL)
+	goto loser;
+
+    dest = (PQGParams*)PORT_ArenaZAlloc(arena, sizeof(PQGParams));
+    if (dest == NULL)
+	goto loser;
+
+    dest->arena = arena;
+
+    status = SECITEM_CopyItem(arena, &dest->prime, prime);
+    if (status != SECSuccess)
+	goto loser;
+
+    status = SECITEM_CopyItem(arena, &dest->subPrime, subPrime);
+    if (status != SECSuccess)
+	goto loser;
+
+    status = SECITEM_CopyItem(arena, &dest->base, base);
+    if (status != SECSuccess)
+	goto loser;
+
+    return dest;
+
+loser:
+    if (arena != NULL)
+	PORT_FreeArena(arena, PR_FALSE);
+    return NULL;
+}
+
+
+/**************************************************************************
+ * Fills in caller's "prime" SECItem with the prime value in params.
+ * Contents can be freed by calling SECITEM_FreeItem(prime, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus 
+PK11_PQG_GetPrimeFromParams(const PQGParams *params, SECItem * prime) {
+    return SECITEM_CopyItem(NULL, prime, &params->prime);
+}
+
+
+/**************************************************************************
+ * Fills in caller's "subPrime" SECItem with the prime value in params.
+ * Contents can be freed by calling SECITEM_FreeItem(subPrime, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus
+PK11_PQG_GetSubPrimeFromParams(const PQGParams *params, SECItem * subPrime) {
+    return SECITEM_CopyItem(NULL, subPrime, &params->subPrime);
+}
+
+
+/**************************************************************************
+ * Fills in caller's "base" SECItem with the base value in params.
+ * Contents can be freed by calling SECITEM_FreeItem(base, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus 
+PK11_PQG_GetBaseFromParams(const PQGParams *params, SECItem *base) {
+    return SECITEM_CopyItem(NULL, base, &params->base);
+}
+
+
+/**************************************************************************
+ *  Return a pointer to a new PQGVerify struct that is constructed from   *
+ *  copies of the arguments passed in.                                    *
+ *  Return NULL on failure.                                               *
+ **************************************************************************/
+extern PQGVerify *
+PK11_PQG_NewVerify(unsigned int counter, const SECItem * seed, 
+							const SECItem * h) {
+    PRArenaPool *arena;
+    PQGVerify *  dest;
+    SECStatus    status;
+
+    arena = PORT_NewArena(PQG_DEFAULT_CHUNKSIZE);
+    if (arena == NULL)
+	goto loser;
+
+    dest = (PQGVerify*)PORT_ArenaZAlloc(arena, sizeof(PQGVerify));
+    if (dest == NULL)
+	goto loser;
+
+    dest->arena   = arena;
+    dest->counter = counter;
+
+    status = SECITEM_CopyItem(arena, &dest->seed, seed);
+    if (status != SECSuccess)
+	goto loser;
+
+    status = SECITEM_CopyItem(arena, &dest->h, h);
+    if (status != SECSuccess)
+	goto loser;
+
+    return dest;
+
+loser:
+    if (arena != NULL)
+	PORT_FreeArena(arena, PR_FALSE);
+    return NULL;
+}
+
+
+/**************************************************************************
+ * Returns "counter" value from the PQGVerify.
+ **************************************************************************/
+extern unsigned int 
+PK11_PQG_GetCounterFromVerify(const PQGVerify *verify) {
+    return verify->counter;
+}
+
+/**************************************************************************
+ * Fills in caller's "seed" SECItem with the seed value in verify.
+ * Contents can be freed by calling SECITEM_FreeItem(seed, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus 
+PK11_PQG_GetSeedFromVerify(const PQGVerify *verify, SECItem *seed) {
+    return SECITEM_CopyItem(NULL, seed, &verify->seed);
+}
+
+
+/**************************************************************************
+ * Fills in caller's "h" SECItem with the h value in verify.
+ * Contents can be freed by calling SECITEM_FreeItem(h, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus 
+PK11_PQG_GetHFromVerify(const PQGVerify *verify, SECItem * h) {
+    return SECITEM_CopyItem(NULL, h, &verify->h);
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11pqg.h b/mozilla/security/nss/lib/pk11wrap/pk11pqg.h
new file mode 100644
index 0000000..2877f42
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11pqg.h
@@ -0,0 +1,155 @@
+/* ***** 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-2001
+ * 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 ***** */
+/* Thse functions are stub functions which will get replaced with calls through
+ * PKCS #11.
+ */
+
+#ifndef _PK11PQG_H_
+#define  _PK11PQG_H_ 1
+
+#include "blapit.h"
+
+SEC_BEGIN_PROTOS
+
+/* Generate PQGParams and PQGVerify structs.
+ * Length of seed and length of h both equal length of P. 
+ * All lengths are specified by "j", according to the table above.
+ */
+extern SECStatus PK11_PQG_ParamGen(unsigned int j, PQGParams **pParams, 
+							PQGVerify **pVfy);
+
+/* Generate PQGParams and PQGVerify structs.
+ * Length of P specified by j.  Length of h will match length of P.
+ * Length of SEED in bytes specified in seedBytes.
+ * seedBbytes must be in the range [20..255] or an error will result.
+ */
+extern SECStatus PK11_PQG_ParamGenSeedLen( unsigned int j, 
+	unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy);
+
+/*  Test PQGParams for validity as DSS PQG values.
+ *  If vfy is non-NULL, test PQGParams to make sure they were generated
+ *       using the specified seed, counter, and h values.
+ *
+ *  Return value indicates whether Verification operation ran successfully
+ *  to completion, but does not indicate if PQGParams are valid or not.
+ *  If return value is SECSuccess, then *pResult has these meanings:
+ *       SECSuccess: PQGParams are valid.
+ *       SECFailure: PQGParams are invalid.
+ *
+ * Verify the following 12 facts about PQG counter SEED g and h
+ * 1.  Q is 160 bits long.
+ * 2.  P is one of the 9 valid lengths.
+ * 3.  G < P
+ * 4.  P % Q == 1
+ * 5.  Q is prime
+ * 6.  P is prime
+ * Steps 7-12 are done only if the optional PQGVerify is supplied.
+ * 7.  counter < 4096
+ * 8.  g >= 160 and g < 2048   (g is length of seed in bits)
+ * 9.  Q generated from SEED matches Q in PQGParams.
+ * 10. P generated from (L, counter, g, SEED, Q) matches P in PQGParams.
+ * 11. 1 < h < P-1
+ * 12. G generated from h matches G in PQGParams.
+ */
+
+extern SECStatus PK11_PQG_VerifyParams(const PQGParams *params, 
+                                    const PQGVerify *vfy, SECStatus *result);
+extern void PK11_PQG_DestroyParams(PQGParams *params);
+extern void PK11_PQG_DestroyVerify(PQGVerify *vfy);
+
+/**************************************************************************
+ *  Return a pointer to a new PQGParams struct that is constructed from   *
+ *  copies of the arguments passed in.                                    *
+ *  Return NULL on failure.                                               *
+ **************************************************************************/
+extern PQGParams * PK11_PQG_NewParams(const SECItem * prime, const 
+				SECItem * subPrime, const SECItem * base);
+
+
+/**************************************************************************
+ * Fills in caller's "prime" SECItem with the prime value in params.
+ * Contents can be freed by calling SECITEM_FreeItem(prime, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus PK11_PQG_GetPrimeFromParams(const PQGParams *params, 
+							SECItem * prime);
+
+
+/**************************************************************************
+ * Fills in caller's "subPrime" SECItem with the prime value in params.
+ * Contents can be freed by calling SECITEM_FreeItem(subPrime, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus PK11_PQG_GetSubPrimeFromParams(const PQGParams *params, 
+							SECItem * subPrime);
+
+
+/**************************************************************************
+ * Fills in caller's "base" SECItem with the base value in params.
+ * Contents can be freed by calling SECITEM_FreeItem(base, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus PK11_PQG_GetBaseFromParams(const PQGParams *params, 
+							SECItem *base);
+
+
+/**************************************************************************
+ *  Return a pointer to a new PQGVerify struct that is constructed from   *
+ *  copies of the arguments passed in.                                    *
+ *  Return NULL on failure.                                               *
+ **************************************************************************/
+extern PQGVerify * PK11_PQG_NewVerify(unsigned int counter, 
+				const SECItem * seed, const SECItem * h);
+
+
+/**************************************************************************
+ * Returns "counter" value from the PQGVerify.
+ **************************************************************************/
+extern unsigned int PK11_PQG_GetCounterFromVerify(const PQGVerify *verify);
+
+/**************************************************************************
+ * Fills in caller's "seed" SECItem with the seed value in verify.
+ * Contents can be freed by calling SECITEM_FreeItem(seed, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus PK11_PQG_GetSeedFromVerify(const PQGVerify *verify, 
+							SECItem *seed);
+
+/**************************************************************************
+ * Fills in caller's "h" SECItem with the h value in verify.
+ * Contents can be freed by calling SECITEM_FreeItem(h, PR_FALSE);	
+ **************************************************************************/
+extern SECStatus PK11_PQG_GetHFromVerify(const PQGVerify *verify, SECItem * h);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11priv.h b/mozilla/security/nss/lib/pk11wrap/pk11priv.h
new file mode 100644
index 0000000..6f88e93
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11priv.h
@@ -0,0 +1,219 @@
+/* ***** 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 ***** */
+#ifndef _PK11PRIV_H_
+#define _PK11PRIV_H_
+#include "plarena.h"
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secdert.h"
+#include "keyt.h"
+#include "certt.h"
+#include "pkcs11t.h"
+#include "secmodt.h"
+#include "seccomon.h"
+#include "pkcs7t.h"
+#include "cmsreclist.h"
+
+/*
+ * These are the private NSS functions. They are not exported by nss.def, and
+ * are not callable outside nss3.dll. 
+ */
+
+SEC_BEGIN_PROTOS
+
+/************************************************************
+ * Generic Slot Lists Management
+ ************************************************************/
+PK11SlotList * PK11_NewSlotList(void);
+PK11SlotList * PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type,
+						PRBool needRW,void *wincx);
+SECStatus PK11_AddSlotToList(PK11SlotList *list,PK11SlotInfo *slot);
+SECStatus PK11_DeleteSlotFromList(PK11SlotList *list,PK11SlotListElement *le);
+PK11SlotListElement *PK11_FindSlotElement(PK11SlotList *list,
+							PK11SlotInfo *slot);
+PK11SlotInfo *PK11_FindSlotBySerial(char *serial);
+int PK11_GetMaxKeyLength(CK_MECHANISM_TYPE type);
+
+/************************************************************
+ * Generic Slot Management
+ ************************************************************/
+CK_OBJECT_HANDLE PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject);
+SECStatus PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
+         CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result);
+CK_ULONG PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
+         CK_ATTRIBUTE_TYPE type);
+char * PK11_MakeString(PLArenaPool *arena,char *space,char *staticSring,
+								int stringLen);
+int PK11_MapError(CK_RV error);
+CK_SESSION_HANDLE PK11_GetRWSession(PK11SlotInfo *slot);
+void PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession);
+PRBool PK11_RWSessionHasLock(PK11SlotInfo *slot,
+					 CK_SESSION_HANDLE session_handle);
+PK11SlotInfo *PK11_NewSlotInfo(SECMODModule *mod);
+void PK11_EnterSlotMonitor(PK11SlotInfo *);
+void PK11_ExitSlotMonitor(PK11SlotInfo *);
+void PK11_CleanKeyList(PK11SlotInfo *slot);
+
+
+/************************************************************
+ *  Slot Password Management
+ ************************************************************/
+SECStatus PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx);
+SECStatus PK11_VerifyPW(PK11SlotInfo *slot,char *pw);
+void PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx);
+void PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func);
+void PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func);
+
+/************************************************************
+ * Manage the built-In Slot Lists
+ ************************************************************/
+SECStatus PK11_InitSlotLists(void);
+void PK11_DestroySlotLists(void);
+PK11SlotList *PK11_GetSlotList(CK_MECHANISM_TYPE type);
+void PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count);
+void PK11_ClearSlotList(PK11SlotInfo *slot);
+
+
+/******************************************************************
+ *           Slot initialization
+ ******************************************************************/
+SECStatus PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts);
+void PK11_InitSlot(SECMODModule *mod,CK_SLOT_ID slotID,PK11SlotInfo *slot);
+PRBool PK11_NeedPWInitForSlot(PK11SlotInfo *slot);
+SECStatus PK11_ReadSlotCerts(PK11SlotInfo *slot);
+void pk11_SetInternalKeySlot(PK11SlotInfo *slot);
+
+/*********************************************************************
+ *       Mechanism Mapping functions
+ *********************************************************************/
+void PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key,
+	 	CK_MECHANISM_TYPE keygen, CK_MECHANISM_TYPE pad, 
+		int ivLen, int blocksize);
+CK_MECHANISM_TYPE PK11_GetKeyMechanism(CK_KEY_TYPE type);
+CK_MECHANISM_TYPE PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size);
+
+/**********************************************************************
+ *                   Symetric, Public, and Private Keys 
+ **********************************************************************/
+/* Key Generation specialized for SDR (fixed DES3 key) */
+PK11SymKey *PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx);
+SECKEYPublicKey *PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType,
+					 CK_OBJECT_HANDLE id);
+CK_OBJECT_HANDLE PK11_FindObjectForCert(CERTCertificate *cert,
+					void *wincx, PK11SlotInfo **pSlot);
+PK11SymKey * pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
+		 	CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey);
+
+/**********************************************************************
+ *                   Certs
+ **********************************************************************/
+SECStatus PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot,
+    SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg);
+SECKEYPrivateKey * PK11_FindPrivateKeyFromNickname(char *nickname, void *wincx);
+CK_OBJECT_HANDLE * PK11_FindObjectsFromNickname(char *nickname,
+	PK11SlotInfo **slotptr, CK_OBJECT_CLASS objclass, int *returnCount, 
+								void *wincx);
+CK_OBJECT_HANDLE PK11_MatchItem(PK11SlotInfo *slot,CK_OBJECT_HANDLE peer,
+						CK_OBJECT_CLASS o_class); 
+CK_BBOOL PK11_HasAttributeSet( PK11SlotInfo *slot,
+			       CK_OBJECT_HANDLE id,
+			       CK_ATTRIBUTE_TYPE type );
+CK_RV PK11_GetAttributes(PLArenaPool *arena,PK11SlotInfo *slot,
+			 CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count);
+int PK11_NumberCertsForCertSubject(CERTCertificate *cert);
+SECStatus PK11_TraverseCertsForSubject(CERTCertificate *cert, 
+	SECStatus(*callback)(CERTCertificate *, void *), void *arg);
+SECStatus PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1,
+   PK11SlotInfo *slot2, CERTCertificate **cert1, CERTCertificate **cert2);
+SECStatus PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
+       SECStatus(* callback)(CERTCertificate*, void *), void *arg);
+SECStatus PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx);
+
+
+/**********************************************************************
+ *                   Crypto Contexts
+ **********************************************************************/
+PK11Context * PK11_CreateContextByRawKey(PK11SlotInfo *slot, 
+    CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation,
+			 	SECItem *key, SECItem *param, void *wincx);
+PRBool PK11_HashOK(SECOidTag hashAlg);
+
+
+/**********************************************************************
+ * Functions which are  deprecated....
+ **********************************************************************/
+
+SECItem *
+PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *handle,
+					SECItem *derName, int type, char **url);
+
+CK_OBJECT_HANDLE
+PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, 
+				SECItem *name, char *url, int type);
+
+SECItem *
+PK11_FindSMimeProfile(PK11SlotInfo **slotp, char *emailAddr, SECItem *derSubj,
+					SECItem **profileTime);
+SECStatus
+PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj,
+			SECItem *emailProfile, SECItem *profileTime);
+
+PRBool PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle);
+
+char * PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) ;
+SECStatus PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 
+						const char *nickname) ;
+
+
+/* private */
+SECStatus pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *),
+	void *cbArg, PRBool forceLogin, void *pwArg);
+
+/* fetch multiple CRLs for a specific issuer */
+SECStatus pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem* issuer,
+                                   void *wincx);
+
+/* set global options for NSS PKCS#11 module loader */
+SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules,
+                                PRBool allowAlreadyInitializedModules,
+                                PRBool dontFinalizeModules);
+
+/* return whether NSS is allowed to call C_Finalize */
+PRBool pk11_getFinalizeModulesOption(void);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11pub.h b/mozilla/security/nss/lib/pk11wrap/pk11pub.h
new file mode 100644
index 0000000..615624c
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11pub.h
@@ -0,0 +1,830 @@
+/* ***** 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):
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+#ifndef _PK11PUB_H_
+#define _PK11PUB_H_
+#include "plarena.h"
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secdert.h"
+#include "keyt.h"
+#include "certt.h"
+#include "pkcs11t.h"
+#include "secmodt.h"
+#include "seccomon.h"
+#include "pkcs7t.h"
+#include "cmsreclist.h"
+
+/*
+ * Exported PK11 wrap functions.
+ */
+
+SEC_BEGIN_PROTOS
+
+/************************************************************
+ * Generic Slot Lists Management
+ ************************************************************/
+void PK11_FreeSlotList(PK11SlotList *list);
+SECStatus PK11_FreeSlotListElement(PK11SlotList *list, PK11SlotListElement *le);
+PK11SlotListElement * PK11_GetFirstSafe(PK11SlotList *list);
+PK11SlotListElement *PK11_GetNextSafe(PK11SlotList *list, 
+				PK11SlotListElement *le, PRBool restart);
+
+/************************************************************
+ * Generic Slot Management
+ ************************************************************/
+PK11SlotInfo *PK11_ReferenceSlot(PK11SlotInfo *slot);
+void PK11_FreeSlot(PK11SlotInfo *slot);
+SECStatus PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object);
+SECStatus PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object);
+PK11SlotInfo *PK11_GetInternalKeySlot(void);
+PK11SlotInfo *PK11_GetInternalSlot(void);
+SECStatus PK11_Logout(PK11SlotInfo *slot);
+void PK11_LogoutAll(void);
+
+
+/************************************************************
+ *  Slot Password Management
+ ************************************************************/
+void PK11_SetSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout);
+void PK11_GetSlotPWValues(PK11SlotInfo *slot,int *askpw, int *timeout);
+SECStatus PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw);
+SECStatus PK11_CheckUserPassword(PK11SlotInfo *slot, const char *pw);
+PRBool PK11_IsLoggedIn(PK11SlotInfo *slot, void *wincx);
+SECStatus PK11_InitPin(PK11SlotInfo *slot,const char *ssopw,
+                       const char *pk11_userpwd);
+SECStatus PK11_ChangePW(PK11SlotInfo *slot, const char *oldpw,
+                        const char *newpw);
+void PK11_SetPasswordFunc(PK11PasswordFunc func);
+int PK11_GetMinimumPwdLength(PK11SlotInfo *slot);
+SECStatus PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd);
+SECStatus PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx);
+SECStatus PK11_TokenRefresh(PK11SlotInfo *slot);
+
+
+/******************************************************************
+ *           Slot info functions
+ ******************************************************************/
+PK11SlotInfo *PK11_FindSlotByName(const char *name);
+/******************************************************************
+ * PK11_FindSlotsByNames searches for a PK11SlotInfo using one or
+ * more criteria : dllName, slotName and tokenName . In addition, if
+ * presentOnly is set , only slots with a token inserted will be
+ * returned.
+ ******************************************************************/
+PK11SlotList *PK11_FindSlotsByNames(const char *dllName,
+        const char* slotName, const char* tokenName, PRBool presentOnly);
+PRBool PK11_IsReadOnly(PK11SlotInfo *slot);
+PRBool PK11_IsInternal(PK11SlotInfo *slot);
+PRBool PK11_IsInternalKeySlot(PK11SlotInfo *slot);
+char * PK11_GetTokenName(PK11SlotInfo *slot);
+char * PK11_GetSlotName(PK11SlotInfo *slot);
+PRBool PK11_NeedLogin(PK11SlotInfo *slot);
+PRBool PK11_IsFriendly(PK11SlotInfo *slot);
+PRBool PK11_IsHW(PK11SlotInfo *slot);
+PRBool PK11_IsRemovable(PK11SlotInfo *slot);
+PRBool PK11_NeedUserInit(PK11SlotInfo *slot);
+PRBool PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot);
+int PK11_GetSlotSeries(PK11SlotInfo *slot);
+int PK11_GetCurrentWrapIndex(PK11SlotInfo *slot);
+unsigned long PK11_GetDefaultFlags(PK11SlotInfo *slot);
+CK_SLOT_ID PK11_GetSlotID(PK11SlotInfo *slot);
+SECMODModuleID PK11_GetModuleID(PK11SlotInfo *slot);
+SECStatus PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info);
+SECStatus PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info);
+PRBool PK11_IsDisabled(PK11SlotInfo *slot);
+PRBool PK11_HasRootCerts(PK11SlotInfo *slot);
+PK11DisableReasons PK11_GetDisabledReason(PK11SlotInfo *slot);
+/* Prevents the slot from being used, and set disable reason to user-disable */
+/* NOTE: Mechanisms that were ON continue to stay ON */
+/*       Therefore, when the slot is enabled, it will remember */
+/*       what mechanisms needs to be turned on */
+PRBool PK11_UserDisableSlot(PK11SlotInfo *slot);
+/* Allow all mechanisms that are ON before UserDisableSlot() */
+/* was called to be available again */
+PRBool PK11_UserEnableSlot(PK11SlotInfo *slot);
+/*
+ * wait for a specific slot event.
+ * event is a specific event to wait for. Currently only 
+ *    PK11TokenChangeOrRemovalEvent and PK11TokenPresentEvents are defined.
+ * timeout can be an interval time to wait, PR_INTERVAL_NO_WAIT (meaning only
+ * poll once), or PR_INTERVAL_NO_TIMEOUT (meaning block until a change).
+ * pollInterval is a suggested pulling interval value. '0' means use the 
+ *  default. Future implementations that don't poll may ignore this value.
+ * series is the current series for the last slot. This should be the series 
+ *  value for the slot the last time you read persistant information from the
+ *  slot. For instance, if you publish a cert from the slot, you should obtain
+ *  the slot series at that time. Then PK11_WaitForTokenEvent can detect a 
+ *  a change in the slot between the time you publish and the time 
+ *  PK11_WaitForTokenEvent is called, elliminating potential race conditions.
+ *
+ * The current status that is returned is:
+ *   PK11TokenNotRemovable - always returned for any non-removable token.
+ *   PK11TokenPresent - returned when the token is present and we are waiting
+ *     on a PK11TokenPresentEvent. Then next event to look for is a 
+ *     PK11TokenChangeOrRemovalEvent.
+ *   PK11TokenChanged - returned when the old token has been removed and a new
+ *     token ad been inserted, and we are waiting for a 
+ *     PK11TokenChangeOrRemovalEvent. The next event to look for is another
+ *     PK11TokenChangeOrRemovalEvent.
+ *   PK11TokenRemoved - returned when the token is not present and we are 
+ *     waiting for a PK11TokenChangeOrRemovalEvent. The next event to look for 
+ *     is a PK11TokenPresentEvent.
+ */
+PK11TokenStatus PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event,
+	PRIntervalTime timeout, PRIntervalTime pollInterval, int series);
+
+PRBool PK11_NeedPWInit(void);
+PRBool PK11_TokenExists(CK_MECHANISM_TYPE);
+SECStatus PK11_GetModInfo(SECMODModule *mod, CK_INFO *info);
+PRBool PK11_IsFIPS(void);
+SECMODModule *PK11_GetModule(PK11SlotInfo *slot);
+
+/*********************************************************************
+ *            Slot mapping utility functions.
+ *********************************************************************/
+PRBool PK11_IsPresent(PK11SlotInfo *slot);
+PRBool PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type);
+PK11SlotList * PK11_GetAllTokens(CK_MECHANISM_TYPE type,PRBool needRW,
+					PRBool loadCerts, void *wincx);
+PK11SlotInfo *PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int count,
+							void *wincx);
+PK11SlotInfo *PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx);
+CK_MECHANISM_TYPE PK11_GetBestWrapMechanism(PK11SlotInfo *slot);
+int PK11_GetBestKeyLength(PK11SlotInfo *slot, CK_MECHANISM_TYPE type);
+
+/*
+ * Open a new database using the softoken. The caller is responsible for making
+ * sure the module spec is correct and usable. The caller should ask for one
+ * new database per call if the caller wants to get meaningful information
+ * about the new database.
+ *
+ * moduleSpec is the same data that you would pass to softoken at
+ * initialization time under the 'tokens' options. For example, if you were
+ * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
+ * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
+ * module spec here. The slot ID will be calculated for you by
+ * SECMOD_OpenUserDB().
+ *
+ * Typical parameters here are configdir, tokenDescription and flags.
+ *
+ * a Full list is below:
+ *
+ *
+ *  configDir - The location of the databases for this token. If configDir is
+ *         not specified, and noCertDB and noKeyDB is not specified, the load
+ *         will fail.
+ *   certPrefix - Cert prefix for this token.
+ *   keyPrefix - Prefix for the key database for this token. (if not specified,
+ *         certPrefix will be used).
+ *   tokenDescription - The label value for this token returned in the
+ *         CK_TOKEN_INFO structure with an internationalize string (UTF8).
+ *         This value will be truncated at 32 bytes (no NULL, partial UTF8
+ *         characters dropped). You should specify a user friendly name here
+ *         as this is the value the token will be refered to in most
+ *         application UI's. You should make sure tokenDescription is unique.
+ *   slotDescription - The slotDescription value for this token returned
+ *         in the CK_SLOT_INFO structure with an internationalize string
+ *         (UTF8). This value will be truncated at 64 bytes (no NULL, partial
+ *         UTF8 characters dropped). This name will not change after the
+ *         database is closed. It should have some number to make this unique.
+ *   minPWLen - minimum password length for this token.
+ *   flags - comma separated list of flag values, parsed case-insensitive.
+ *         Valid flags are:
+ *              readOnly - Databases should be opened read only.
+ *              noCertDB - Don't try to open a certificate database.
+ *              noKeyDB - Don't try to open a key database.
+ *              forceOpen - Don't fail to initialize the token if the
+ *                databases could not be opened.
+ *              passwordRequired - zero length passwords are not acceptable
+ *                (valid only if there is a keyDB).
+ *              optimizeSpace - allocate smaller hash tables and lock tables.
+ *                When this flag is not specified, Softoken will allocate
+ *                large tables to prevent lock contention.
+ */
+PK11SlotInfo *SECMOD_OpenUserDB(const char *moduleSpec);
+SECStatus SECMOD_CloseUserDB(PK11SlotInfo *slot);
+
+/*
+ * This is exactly the same as OpenUserDB except it can be called on any
+ * module that understands softoken style new slot entries. The resulting
+ * slot can be closed using SECMOD_CloseUserDB above. Value of moduleSpec
+ * is token specific.
+ */
+PK11SlotInfo *SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec);
+
+
+/*
+ * merge the permanent objects from on token to another 
+ */
+SECStatus PK11_MergeTokens(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
+                PK11MergeLog *log, void *targetPwArg, void *sourcePwArg);
+
+/*
+ * create and destroy merge logs needed by PK11_MergeTokens
+ */
+PK11MergeLog * PK11_CreateMergeLog(void);
+void PK11_DestroyMergeLog(PK11MergeLog *log);
+
+
+
+/*********************************************************************
+ *       Mechanism Mapping functions
+ *********************************************************************/
+CK_MECHANISM_TYPE PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len);
+CK_MECHANISM_TYPE PK11_GetKeyGen(CK_MECHANISM_TYPE type);
+int PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params);
+int PK11_GetIVLength(CK_MECHANISM_TYPE type);
+SECItem *PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv);
+unsigned char *PK11_IVFromParam(CK_MECHANISM_TYPE type,SECItem *param,int *len);
+SECItem * PK11_BlockData(SECItem *data,unsigned long size);
+
+/* PKCS #11 to DER mapping functions */
+SECItem *PK11_ParamFromAlgid(SECAlgorithmID *algid);
+SECItem *PK11_GenerateNewParam(CK_MECHANISM_TYPE, PK11SymKey *);
+CK_MECHANISM_TYPE PK11_AlgtagToMechanism(SECOidTag algTag);
+SECOidTag PK11_MechanismToAlgtag(CK_MECHANISM_TYPE type);
+SECOidTag PK11_FortezzaMapSig(SECOidTag algTag);
+SECStatus PK11_ParamToAlgid(SECOidTag algtag, SECItem *param,
+                                   PLArenaPool *arena, SECAlgorithmID *algid);
+SECStatus PK11_SeedRandom(PK11SlotInfo *,unsigned char *data,int len);
+SECStatus PK11_GenerateRandomOnSlot(PK11SlotInfo *,unsigned char *data,int len);
+SECStatus PK11_RandomUpdate(void *data, size_t bytes);
+SECStatus PK11_GenerateRandom(unsigned char *data,int len);
+
+/* warning: cannot work with pkcs 5 v2
+ * use algorithm ID s instead of pkcs #11 mechanism pointers */
+CK_RV PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism,
+					    CK_MECHANISM_PTR pCryptoMechanism,
+					    SECItem *pbe_pwd, PRBool bad3DES);
+CK_MECHANISM_TYPE PK11_GetPadMechanism(CK_MECHANISM_TYPE);
+CK_MECHANISM_TYPE PK11_MapSignKeyType(KeyType keyType);
+
+/**********************************************************************
+ *                   Symetric, Public, and Private Keys 
+ **********************************************************************/
+void PK11_FreeSymKey(PK11SymKey *key);
+PK11SymKey *PK11_ReferenceSymKey(PK11SymKey *symKey);
+PK11SymKey *PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+    PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx);
+PK11SymKey *PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, 
+    CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation, 
+    SECItem *key, CK_FLAGS flags, PRBool isPerm, void *wincx);
+PK11SymKey *PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent,
+    PK11Origin origin, CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, 
+    PRBool owner, void *wincx);
+PK11SymKey *PK11_GetWrapKey(PK11SlotInfo *slot, int wrap,
+			      CK_MECHANISM_TYPE type,int series, void *wincx);
+/*
+ * This function is not thread-safe.  It can only be called when only
+ * one thread has a reference to wrapKey.
+ */
+void PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey);
+CK_MECHANISM_TYPE PK11_GetMechanism(PK11SymKey *symKey);
+/*
+ * import a public key into the desired slot
+ *  
+ * This function takes a public key structure and creates a public key in a 
+ * given slot. If isToken is set, then a persistant public key is created.
+ *
+ * Note: it is possible for this function to return a handle for a key which
+ * is persistant, even if isToken is not set.
+ */
+CK_OBJECT_HANDLE PK11_ImportPublicKey(PK11SlotInfo *slot, 
+				SECKEYPublicKey *pubKey, PRBool isToken);
+PK11SymKey *PK11_KeyGen(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
+				SECItem *param,	int keySize,void *wincx);
+PK11SymKey *PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+				SECItem *param, int keySize, SECItem *keyid,
+				PRBool isToken, void *wincx);
+PK11SymKey *PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot,
+				CK_MECHANISM_TYPE type, SECItem *param,
+				int keySize, SECItem *keyid, CK_FLAGS opFlags,
+				PK11AttrFlags attrFlags, void *wincx);
+PK11SymKey * PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname,
+								void *wincx);
+PK11SymKey *PK11_GetNextSymKey(PK11SymKey *symKey);
+CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *key);
+CK_OBJECT_HANDLE PK11_GetSymKeyHandle(PK11SymKey *symKey);
+
+
+/*
+ * PK11_SetSymKeyUserData
+ *   sets generic user data on keys (usually a pointer to a data structure)
+ * that can later be retrieved by PK11_GetSymKeyUserData().
+ *    symKey - key where data will be set.
+ *    data - data to be set.
+ *    freefunc - function used to free the data.
+ * Setting user data on symKeys with existing user data already set will cause 
+ * the existing user data to be freed before the new user data is set.
+ * Freeing user data is done by calling the user specified freefunc. 
+ * If freefunc is NULL, the user data is assumed to be global or static an 
+ * not freed. Passing NULL for user data to PK11_SetSymKeyUserData has the 
+ * effect of freeing any existing user data, and clearing the user data 
+ * pointer. If user data exists when the symKey is finally freed, that 
+ * data will be freed with freefunc.
+ *
+ * Applications should only use this function on keys which the application
+ * has created directly, as there is only one user data value per key.
+ */
+void PK11_SetSymKeyUserData(PK11SymKey *symKey, void *data, 
+                                 PK11FreeDataFunc freefunc);
+/* PK11_GetSymKeyUserData 
+ *   retrieves generic user data which was set on a key by 
+ * PK11_SetSymKeyUserData.
+ *    symKey - key with data to be fetched
+ *
+ * If no data exists, or the data has been cleared, PK11_GetSymKeyUserData
+ * will return NULL. Returned data is still owned and managed by the SymKey,
+ * the caller should not free the data.
+ *
+ */
+void *PK11_GetSymKeyUserData(PK11SymKey *symKey);
+
+SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
+				PK11SymKey *symKey, SECItem *wrappedKey);
+SECStatus PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *params,
+	 PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey);
+/* move a key to 'slot' optionally set the key attributes according to either
+ * operation or the  flags and making the key permanent at the same time.
+ * If the key is moved to the same slot, operation and flags values are 
+ * currently ignored */
+PK11SymKey *PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, 
+			CK_FLAGS flags, PRBool  perm, PK11SymKey *symKey);
+/*
+ * derive a new key from the base key.
+ *  PK11_Derive returns a key which can do exactly one operation, and is
+ * ephemeral (session key).
+ *  PK11_DeriveWithFlags is the same as PK11_Derive, except you can use
+ * CKF_ flags to enable more than one operation.
+ *  PK11_DeriveWithFlagsPerm is the same as PK11_DeriveWithFlags except you can
+ *  (optionally) make the key permanent (token key).
+ */
+PK11SymKey *PK11_Derive(PK11SymKey *baseKey, CK_MECHANISM_TYPE mechanism,
+   			SECItem *param, CK_MECHANISM_TYPE target, 
+		        CK_ATTRIBUTE_TYPE operation, int keySize);
+PK11SymKey *PK11_DeriveWithFlags( PK11SymKey *baseKey, 
+	CK_MECHANISM_TYPE derive, SECItem *param, CK_MECHANISM_TYPE target, 
+	CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags);
+PK11SymKey * PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, 
+	CK_MECHANISM_TYPE derive, 
+	SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+	int keySize, CK_FLAGS flags, PRBool isPerm);
+
+PK11SymKey *PK11_PubDerive( SECKEYPrivateKey *privKey, 
+ SECKEYPublicKey *pubKey, PRBool isSender, SECItem *randomA, SECItem *randomB,
+ CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
+		 CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx) ;
+PK11SymKey *PK11_PubDeriveWithKDF( SECKEYPrivateKey *privKey, 
+ SECKEYPublicKey *pubKey, PRBool isSender, SECItem *randomA, SECItem *randomB,
+ CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
+		 CK_ATTRIBUTE_TYPE operation, int keySize,
+		 CK_ULONG kdf, SECItem *sharedData, void *wincx);
+
+/*
+ * unwrap a new key with a symetric key.
+ *  PK11_Unwrap returns a key which can do exactly one operation, and is
+ * ephemeral (session key).
+ *  PK11_UnwrapWithFlags is the same as PK11_Unwrap, except you can use
+ * CKF_ flags to enable more than one operation.
+ *  PK11_UnwrapWithFlagsPerm is the same as PK11_UnwrapWithFlags except you can
+ *  (optionally) make the key permanent (token key).
+ */
+PK11SymKey *PK11_UnwrapSymKey(PK11SymKey *key, 
+	CK_MECHANISM_TYPE wraptype, SECItem *param, SECItem *wrapppedKey,  
+	CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize);
+PK11SymKey *PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, 
+	CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey, 
+	CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize, 
+	CK_FLAGS flags);
+PK11SymKey * PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, 
+	CK_MECHANISM_TYPE wrapType,
+        SECItem *param, SECItem *wrappedKey, 
+	CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+	 int keySize, CK_FLAGS flags, PRBool isPerm);
+
+/*
+ * unwrap a new key with a private key.
+ *  PK11_PubUnwrap returns a key which can do exactly one operation, and is
+ * ephemeral (session key).
+ *  PK11_PubUnwrapWithFlagsPerm is the same as PK11_PubUnwrap except you can 
+ * use * CKF_ flags to enable more than one operation, and optionally make 
+ * the key permanent (token key).
+ */
+PK11SymKey *PK11_PubUnwrapSymKey(SECKEYPrivateKey *key, SECItem *wrapppedKey,
+	 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize);
+PK11SymKey * PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, 
+	  SECItem *wrappedKey, CK_MECHANISM_TYPE target, 
+	  CK_ATTRIBUTE_TYPE operation, int keySize,
+	  CK_FLAGS flags, PRBool isPerm);
+PK11SymKey *PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 
+						SECItem *keyID, void *wincx);
+SECStatus PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey,PRBool force);
+SECStatus PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey);
+SECStatus PK11_DeleteTokenSymKey(PK11SymKey *symKey);
+SECStatus PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx);
+SECKEYPrivateKey * PK11_LoadPrivKey(PK11SlotInfo *slot,
+		SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 
+					PRBool token, PRBool sensitive);
+char * PK11_GetSymKeyNickname(PK11SymKey *symKey);
+char * PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey);
+char * PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey);
+SECStatus PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname);
+SECStatus PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, 
+							const char *nickname);
+SECStatus PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, 
+							const char *nickname);
+
+/* size to hold key in bytes */
+unsigned int PK11_GetKeyLength(PK11SymKey *key);
+/* size of actual secret parts of key in bits */
+/* algid is because RC4 strength is determined by the effective bits as well
+ * as the key bits */
+unsigned int PK11_GetKeyStrength(PK11SymKey *key,SECAlgorithmID *algid);
+SECStatus PK11_ExtractKeyValue(PK11SymKey *symKey);
+SECItem * PK11_GetKeyData(PK11SymKey *symKey);
+PK11SlotInfo * PK11_GetSlotFromKey(PK11SymKey *symKey);
+void *PK11_GetWindow(PK11SymKey *symKey);
+
+/*
+ * Explicitly set the key usage for the generated private key.
+ *
+ * This allows us to specify single use EC and RSA keys whose usage
+ * can be regulated by the underlying token.
+ *
+ * The underlying key usage is set using opFlags. opFlagsMask specifies
+ * which operations are specified by opFlags. For instance to turn encrypt
+ * on and signing off, opFlags would be CKF_ENCRYPT|CKF_DECRYPT and 
+ * opFlagsMask would be CKF_ENCRYPT|CKF_DECRYPT|CKF_SIGN|CKF_VERIFY. You
+ * need to specify both the public and private key flags, 
+ * PK11_GenerateKeyPairWithOpFlags will sort out the correct flag to the 
+ * correct key type. Flags not specified in opFlagMask will be defaulted 
+ * according to mechanism type and token capabilities.
+ */
+SECKEYPrivateKey *PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot,
+   CK_MECHANISM_TYPE type, void *param, SECKEYPublicKey **pubk,
+   PK11AttrFlags attrFlags, CK_FLAGS opFlags, CK_FLAGS opFlagsMask,
+    void *wincx);
+/*
+ * The attrFlags is the logical OR of the PK11_ATTR_XXX bitflags.
+ * These flags apply to the private key.  The PK11_ATTR_TOKEN,
+ * PK11_ATTR_SESSION, PK11_ATTR_MODIFIABLE, and PK11_ATTR_UNMODIFIABLE
+ * flags also apply to the public key.
+ */
+SECKEYPrivateKey *PK11_GenerateKeyPairWithFlags(PK11SlotInfo *slot,
+   CK_MECHANISM_TYPE type, void *param, SECKEYPublicKey **pubk,
+		 	    PK11AttrFlags attrFlags, void *wincx);
+SECKEYPrivateKey *PK11_GenerateKeyPair(PK11SlotInfo *slot,
+   CK_MECHANISM_TYPE type, void *param, SECKEYPublicKey **pubk,
+		 	    PRBool isPerm, PRBool isSensitive, void *wincx);
+SECKEYPrivateKey * PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot,
+				 	CERTCertificate *cert, void *wincx);
+SECKEYPrivateKey * PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx);
+SECKEYPrivateKey * PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID,
+				       void *wincx);
+int PK11_GetPrivateModulusLen(SECKEYPrivateKey *key); 
+
+/* note: despite the name, this function takes a private key. */
+SECStatus PK11_PubDecryptRaw(SECKEYPrivateKey *key, unsigned char *data,
+   unsigned *outLen, unsigned int maxLen, unsigned char *enc, unsigned encLen);
+#define PK11_PrivDecryptRaw PK11_PubDecryptRaw
+/* The encrypt function that complements the above decrypt function. */
+SECStatus PK11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc,
+                unsigned char *data, unsigned dataLen, void *wincx);
+
+SECStatus PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key, unsigned char *data,
+   unsigned *outLen, unsigned int maxLen, unsigned char *enc, unsigned encLen);
+/* The encrypt function that complements the above decrypt function. */
+SECStatus PK11_PubEncryptPKCS1(SECKEYPublicKey *key, unsigned char *enc,
+                unsigned char *data, unsigned dataLen, void *wincx);
+
+SECStatus PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, 
+		SECKEYPrivateKeyInfo *pki, SECItem *nickname,
+		SECItem *publicValue, PRBool isPerm, PRBool isPrivate,
+		unsigned int usage, void *wincx);
+SECStatus PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, 
+		SECKEYPrivateKeyInfo *pki, SECItem *nickname,
+		SECItem *publicValue, PRBool isPerm, PRBool isPrivate,
+		unsigned int usage, SECKEYPrivateKey** privk, void *wincx);
+SECStatus PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, 
+		SECItem *derPKI, SECItem *nickname,
+		SECItem *publicValue, PRBool isPerm, PRBool isPrivate,
+		unsigned int usage, void *wincx);
+SECStatus PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, 
+		SECItem *derPKI, SECItem *nickname,
+		SECItem *publicValue, PRBool isPerm, PRBool isPrivate,
+		unsigned int usage, SECKEYPrivateKey** privk, void *wincx);
+SECStatus PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, 
+		SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, 
+		SECItem *nickname, SECItem *publicValue, PRBool isPerm,
+		PRBool isPrivate, KeyType type, 
+		unsigned int usage, void *wincx);
+SECKEYPrivateKeyInfo *PK11_ExportPrivateKeyInfo(
+		CERTCertificate *cert, void *wincx);
+SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivKeyInfo(
+		PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem,
+		SECKEYPrivateKey *pk, int iteration, void *wincx);
+SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivateKeyInfo(
+		PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem,
+		CERTCertificate *cert, int iteration, void *wincx);
+SECKEYPrivateKey *PK11_FindKeyByDERCert(PK11SlotInfo *slot, 
+					CERTCertificate *cert, void *wincx);
+SECKEYPublicKey *PK11_MakeKEAPubKey(unsigned char *data, int length);
+SECStatus PK11_DigestKey(PK11Context *context, PK11SymKey *key);
+PRBool PK11_VerifyKeyOK(PK11SymKey *key);
+SECKEYPrivateKey *PK11_UnwrapPrivKey(PK11SlotInfo *slot, 
+		PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
+		SECItem *param, SECItem *wrappedKey, SECItem *label, 
+		SECItem *publicValue, PRBool token, PRBool sensitive,
+		CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, int usageCount,
+		void *wincx);
+SECStatus PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
+			   SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType,
+			   SECItem *param, SECItem *wrappedKey, void *wincx);
+/*
+ * The caller of PK11_DEREncodePublicKey should free the returned SECItem with
+ * a SECITEM_FreeItem(..., PR_TRUE) call.
+ */
+SECItem* PK11_DEREncodePublicKey(SECKEYPublicKey *pubk);
+PK11SymKey* PK11_CopySymKeyForSigning(PK11SymKey *originalKey,
+	CK_MECHANISM_TYPE mech);
+SECKEYPrivateKeyList* PK11_ListPrivKeysInSlot(PK11SlotInfo *slot,
+						 char *nickname, void *wincx);
+SECKEYPublicKeyList* PK11_ListPublicKeysInSlot(PK11SlotInfo *slot,
+							char *nickname);
+SECKEYPQGParams *PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey);
+/* deprecated */
+SECKEYPrivateKeyList* PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot);
+
+PK11SymKey *PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk,
+	void *wincx);
+SECKEYPrivateKey *PK11_ConvertSessionPrivKeyToTokenPrivKey(
+	SECKEYPrivateKey *privk, void* wincx);
+SECKEYPrivateKey * PK11_CopyTokenPrivKeyToSessionPrivKey(PK11SlotInfo *destSlot,
+				      SECKEYPrivateKey *privKey);
+
+/**********************************************************************
+ *                   Certs
+ **********************************************************************/
+SECItem *PK11_MakeIDFromPubKey(SECItem *pubKeyData);
+SECStatus PK11_TraverseSlotCerts(
+     SECStatus(* callback)(CERTCertificate*,SECItem *,void *),
+                                                void *arg, void *wincx);
+CERTCertificate * PK11_FindCertFromNickname(const char *nickname, void *wincx);
+CERTCertList * PK11_FindCertsFromNickname(const char *nickname, void *wincx);
+CERTCertificate *PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey);
+SECStatus PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert,
+                CK_OBJECT_HANDLE key, const char *nickname, 
+                PRBool includeTrust);
+SECStatus PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert,
+                CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust);
+PK11SlotInfo *PK11_ImportCertForKey(CERTCertificate *cert, 
+                                    const char *nickname, void *wincx);
+PK11SlotInfo *PK11_ImportDERCertForKey(SECItem *derCert, char *nickname,
+								void *wincx);
+PK11SlotInfo *PK11_KeyForCertExists(CERTCertificate *cert,
+					CK_OBJECT_HANDLE *keyPtr, void *wincx);
+PK11SlotInfo *PK11_KeyForDERCertExists(SECItem *derCert,
+					CK_OBJECT_HANDLE *keyPtr, void *wincx);
+CERTCertificate * PK11_FindCertByIssuerAndSN(PK11SlotInfo **slot,
+					CERTIssuerAndSN *sn, void *wincx);
+CERTCertificate * PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slot,
+	SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip,
+				SECKEYPrivateKey**privKey, void *wincx);
+int PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist,
+				void *wincx);
+SECStatus PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert,
+	PK11SlotInfo *slot, SECStatus(*callback)(CERTCertificate *, void *),
+	void *arg);
+CERTCertificate *PK11_FindCertFromDERCert(PK11SlotInfo *slot, 
+					  CERTCertificate *cert, void *wincx);
+CERTCertificate *PK11_FindCertFromDERCertItem(PK11SlotInfo *slot,
+                                          SECItem *derCert, void *wincx);
+SECStatus PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert,
+					char *nickname, PRBool addUsage,
+					void *wincx);
+CERTCertificate *PK11_FindBestKEAMatch(CERTCertificate *serverCert,void *wincx);
+PRBool PK11_FortezzaHasKEA(CERTCertificate *cert);
+CK_OBJECT_HANDLE PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert,
+				     void *wincx);
+SECStatus PK11_TraverseCertsForNicknameInSlot(SECItem *nickname,
+	PK11SlotInfo *slot, SECStatus(*callback)(CERTCertificate *, void *),
+	void *arg);
+CERTCertList * PK11_ListCerts(PK11CertListType type, void *pwarg);
+CERTCertList * PK11_ListCertsInSlot(PK11SlotInfo *slot);
+CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url,
+    int type, void *wincx, PRInt32 importOptions, PLArenaPool* arena, PRInt32 decodeOptions);
+
+/**********************************************************************
+ *                   Sign/Verify 
+ **********************************************************************/
+
+/*
+ * Return the length in bytes of a signature generated with the
+ * private key.
+ *
+ * Return 0 or -1 on failure.  (XXX Should we fix it to always return
+ * -1 on failure?)
+ */
+int PK11_SignatureLen(SECKEYPrivateKey *key);
+PK11SlotInfo * PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key);
+SECStatus PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash);
+SECStatus PK11_VerifyRecover(SECKEYPublicKey *key, SECItem *sig,
+						 SECItem *dsig, void * wincx);
+SECStatus PK11_Verify(SECKEYPublicKey *key, SECItem *sig, 
+						SECItem *hash, void *wincx);
+
+
+
+/**********************************************************************
+ *                   Crypto Contexts
+ **********************************************************************/
+void PK11_DestroyContext(PK11Context *context, PRBool freeit);
+PK11Context *PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,
+	CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, SECItem *param);
+PK11Context *PK11_CreateDigestContext(SECOidTag hashAlg);
+PK11Context *PK11_CloneContext(PK11Context *old);
+SECStatus PK11_DigestBegin(PK11Context *cx);
+/*
+ * The output buffer 'out' must be big enough to hold the output of
+ * the hash algorithm 'hashAlg'.
+ */
+SECStatus PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in,
+					PRInt32 len);
+SECStatus PK11_DigestOp(PK11Context *context, const unsigned char *in, 
+                        unsigned len);
+SECStatus PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, 
+				int maxout, unsigned char *in, int inlen);
+SECStatus PK11_Finalize(PK11Context *context);
+SECStatus PK11_DigestFinal(PK11Context *context, unsigned char *data, 
+				unsigned int *outLen, unsigned int length);
+SECStatus PK11_SaveContext(PK11Context *cx,unsigned char *save,
+						int *len, int saveLength);
+
+/* Save the context's state, with possible allocation.
+ * The caller may supply an already allocated buffer in preAllocBuf,
+ * with length pabLen.  If the buffer is large enough for the context's
+ * state, it will receive the state.
+ * If the buffer is not large enough (or NULL), then a new buffer will
+ * be allocated with PORT_Alloc.
+ * In either case, the state will be returned as a buffer, and the length
+ * of the state will be given in *stateLen.
+ */
+unsigned char *
+PK11_SaveContextAlloc(PK11Context *cx,
+                      unsigned char *preAllocBuf, unsigned int pabLen,
+                      unsigned int *stateLen);
+
+SECStatus PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len);
+SECStatus PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len);
+void PK11_SetFortezzaHack(PK11SymKey *symKey) ;
+
+
+/**********************************************************************
+ *                   PBE functions 
+ **********************************************************************/
+
+/* This function creates PBE parameters from the given inputs.  The result
+ * can be used to create a password integrity key for PKCS#12, by sending
+ * the return value to PK11_KeyGen along with the appropriate mechanism.
+ */
+SECItem * 
+PK11_CreatePBEParams(SECItem *salt, SECItem *pwd, unsigned int iterations);
+
+/* free params created above (can be called after keygen is done */
+void PK11_DestroyPBEParams(SECItem *params);
+
+SECAlgorithmID *
+PK11_CreatePBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt);
+
+/* use to create PKCS5 V2 algorithms with finder control than that provided
+ * by PK11_CreatePBEAlgorithmID. */
+SECAlgorithmID *
+PK11_CreatePBEV2AlgorithmID(SECOidTag pbeAlgTag, SECOidTag cipherAlgTag,
+                            SECOidTag prfAlgTag, int keyLength, int iteration,
+                            SECItem *salt);
+PK11SymKey *
+PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid,  SECItem *pwitem,
+	       PRBool faulty3DES, void *wincx);
+
+/* warning: cannot work with PKCS 5 v2 use PK11_PBEKeyGen instead */
+PK11SymKey *
+PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *params,
+		SECItem *pwitem, PRBool faulty3DES, void *wincx);
+SECItem *
+PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem);
+/*
+ * Get the Mechanism and parameter of the base encryption or mac scheme from
+ * a PBE algorithm ID.
+ *  Caller is responsible for freeing the return parameter (param).
+ */
+CK_MECHANISM_TYPE
+PK11_GetPBECryptoMechanism(SECAlgorithmID *algid, 
+			   SECItem **param, SECItem *pwd);
+
+/**********************************************************************
+ * Functions to manage secmod flags
+ **********************************************************************/
+PK11DefaultArrayEntry * PK11_GetDefaultArray(int *);
+SECStatus PK11_UpdateSlotAttribute(PK11SlotInfo *, PK11DefaultArrayEntry *,
+							PRBool );
+
+/**********************************************************************
+ * Functions to look at PKCS #11 dependent data
+ **********************************************************************/
+PK11GenericObject *PK11_FindGenericObjects(PK11SlotInfo *slot, 
+						CK_OBJECT_CLASS objClass);
+PK11GenericObject *PK11_GetNextGenericObject(PK11GenericObject *object);
+PK11GenericObject *PK11_GetPrevGenericObject(PK11GenericObject *object);
+SECStatus PK11_UnlinkGenericObject(PK11GenericObject *object);
+SECStatus PK11_LinkGenericObject(PK11GenericObject *list,
+				 PK11GenericObject *object);
+SECStatus PK11_DestroyGenericObjects(PK11GenericObject *object);
+SECStatus PK11_DestroyGenericObject(PK11GenericObject *object);
+PK11GenericObject *PK11_CreateGenericObject(PK11SlotInfo *slot, 
+				   const CK_ATTRIBUTE *pTemplate, 
+				   int count, PRBool token);
+
+/*
+ * PK11_ReadRawAttribute and PK11_WriteRawAttribute are generic
+ * functions to read and modify the actual PKCS #11 attributes of
+ * the underlying pkcs #11 object.
+ * 
+ * object is a pointer to an NSS object that represents the underlying
+ *  PKCS #11 object. It's type must match the type of PK11ObjectType
+ *  as follows:
+ *
+ *     type                           object
+ *   PK11_TypeGeneric            PK11GenericObject *
+ *   PK11_TypePrivKey            SECKEYPrivateKey *
+ *   PK11_TypePubKey             SECKEYPublicKey *
+ *   PK11_TypeSymKey             PK11SymKey *
+ *
+ *  All other types are considered invalid. If type does not match the object
+ *  passed, unpredictable results will occur.
+ *
+ * PK11_ReadRawAttribute allocates the buffer for returning the attribute
+ * value.  The caller of PK11_ReadRawAttribute should free the data buffer
+ * pointed to by item using a SECITEM_FreeItem(item, PR_FALSE) or
+ * PORT_Free(item->data) call.
+ */
+SECStatus PK11_ReadRawAttribute(PK11ObjectType type, void *object, 
+				CK_ATTRIBUTE_TYPE attr, SECItem *item);
+SECStatus PK11_WriteRawAttribute(PK11ObjectType type, void *object, 
+				CK_ATTRIBUTE_TYPE attr, SECItem *item);
+
+/*
+ * PK11_GetAllSlotsForCert returns all the slots that a given certificate
+ * exists on, since it's possible for a cert to exist on more than one
+ * PKCS#11 token.
+ */
+PK11SlotList *
+PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg);
+
+/**********************************************************************
+ * New functions which are already deprecated....
+ **********************************************************************/
+SECItem *
+PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
+					CERTCertificate *cert, void *pwarg);
+SECItem *
+PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *key);
+
+PRBool SECMOD_HasRootCerts(void);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11sdr.c b/mozilla/security/nss/lib/pk11wrap/pk11sdr.c
new file mode 100644
index 0000000..a9511b3
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11sdr.c
@@ -0,0 +1,410 @@
+/* ***** 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):
+ *   thayes@netscape.com
+ *
+ * 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 "seccomon.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "pk11sdr.h"
+
+/*
+ * Data structure and template for encoding the result of an SDR operation
+ *  This is temporary.  It should include the algorithm ID of the encryption mechanism
+ */
+struct SDRResult
+{
+  SECItem keyid;
+  SECAlgorithmID alg;
+  SECItem data;
+};
+typedef struct SDRResult SDRResult;
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+static SEC_ASN1Template template[] = {
+  { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (SDRResult) },
+  { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, keyid) },
+  { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SDRResult, alg),
+    SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+  { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, data) },
+  { 0 }
+};
+
+static unsigned char keyID[] = {
+  0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+};
+
+static SECItem keyIDItem = {
+  0,
+  keyID,
+  sizeof keyID
+};
+
+/* local utility function for padding an incoming data block
+ * to the mechanism block size.
+ */
+static SECStatus
+padBlock(SECItem *data, int blockSize, SECItem *result)
+{
+  SECStatus rv = SECSuccess;
+  int padLength;
+  unsigned int i;
+
+  result->data = 0;
+  result->len = 0;
+
+  /* This algorithm always adds to the block (to indicate the number
+   * of pad bytes).  So allocate a block large enough.
+   */
+  padLength = blockSize - (data->len % blockSize);
+  result->len = data->len + padLength;
+  result->data = (unsigned char *)PORT_Alloc(result->len);
+
+  /* Copy the data */
+  PORT_Memcpy(result->data, data->data, data->len);
+
+  /* Add the pad values */
+  for(i = data->len; i < result->len; i++)
+    result->data[i] = (unsigned char)padLength;
+
+  return rv;
+}
+
+static SECStatus
+unpadBlock(SECItem *data, int blockSize, SECItem *result)
+{
+  SECStatus rv = SECSuccess;
+  int padLength;
+  int i;
+
+  result->data = 0;
+  result->len = 0;
+
+  /* Remove the padding from the end if the input data */
+  if (data->len == 0 || data->len % blockSize  != 0) { rv = SECFailure; goto loser; }
+
+  padLength = data->data[data->len-1];
+  if (padLength > blockSize) { rv = SECFailure; goto loser; }
+
+  /* verify padding */
+  for (i=data->len - padLength; i < data->len; i++) {
+    if (data->data[i] != padLength) {
+	rv = SECFailure;
+	goto loser;
+    }
+  }
+
+  result->len = data->len - padLength;
+  result->data = (unsigned char *)PORT_Alloc(result->len);
+  if (!result->data) { rv = SECFailure; goto loser; }
+
+  PORT_Memcpy(result->data, data->data, result->len);
+
+  if (padLength < 2) {
+    return SECWouldBlock;
+  }
+
+loser:
+  return rv;
+}
+
+static PRLock *pk11sdrLock = NULL;
+
+void
+pk11sdr_Init (void)
+{
+   pk11sdrLock = PR_NewLock();
+}
+
+void
+pk11sdr_Shutdown(void)
+{
+    if (pk11sdrLock) {
+	PR_DestroyLock(pk11sdrLock);
+	pk11sdrLock = NULL;
+    }
+}
+
+/*
+ * PK11SDR_Encrypt
+ *  Encrypt a block of data using the symmetric key identified.  The result
+ *  is an ASN.1 (DER) encoded block of keyid, params and data.
+ */
+SECStatus
+PK11SDR_Encrypt(SECItem *keyid, SECItem *data, SECItem *result, void *cx)
+{
+  SECStatus rv = SECSuccess;
+  PK11SlotInfo *slot = 0;
+  PK11SymKey *key = 0;
+  SECItem *params = 0;
+  PK11Context *ctx = 0;
+  CK_MECHANISM_TYPE type;
+  SDRResult sdrResult;
+  SECItem paddedData;
+  SECItem *pKeyID;
+  PLArenaPool *arena = 0;
+
+  /* Initialize */
+  paddedData.len = 0;
+  paddedData.data = 0;
+
+  arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+  if (!arena) { rv = SECFailure; goto loser; }
+
+  /* 1. Locate the requested keyid, or the default key (which has a keyid)
+   * 2. Create an encryption context
+   * 3. Encrypt
+   * 4. Encode the results (using ASN.1)
+   */
+
+  slot = PK11_GetInternalKeySlot();
+  if (!slot) { rv = SECFailure; goto loser; }
+
+  /* Use triple-DES */
+  type = CKM_DES3_CBC;
+
+  /*
+   * Login to the internal token before we look for the key, otherwise we
+   * won't find it.
+   */
+  rv = PK11_Authenticate(slot, PR_TRUE, cx);
+  if (rv != SECSuccess) goto loser;
+
+  /* Find the key to use */
+  pKeyID = keyid;
+  if (pKeyID->len == 0) {
+	  pKeyID = &keyIDItem;  /* Use default value */
+
+	  /* put in a course lock to prevent a race between not finding the 
+	   * key and creating  one.
+	   */
+
+	  if (pk11sdrLock) PR_Lock(pk11sdrLock);
+
+	  /* Try to find the key */
+	  key = PK11_FindFixedKey(slot, type, pKeyID, cx);
+	  
+	  /* If the default key doesn't exist yet, try to create it */
+	  if (!key) key = PK11_GenDES3TokenKey(slot, pKeyID, cx);
+	  if (pk11sdrLock) PR_Unlock(pk11sdrLock);
+  } else {
+	  key = PK11_FindFixedKey(slot, type, pKeyID, cx);
+  }
+
+  if (!key) { rv = SECFailure; goto loser; }
+
+  params = PK11_GenerateNewParam(type, key);
+  if (!params) { rv = SECFailure; goto loser; }
+
+  ctx = PK11_CreateContextBySymKey(type, CKA_ENCRYPT, key, params);
+  if (!ctx) { rv = SECFailure; goto loser; }
+
+  rv = padBlock(data, PK11_GetBlockSize(type, 0), &paddedData);
+  if (rv != SECSuccess) goto loser;
+
+  sdrResult.data.len = paddedData.len;
+  sdrResult.data.data = (unsigned char *)PORT_ArenaAlloc(arena, sdrResult.data.len);
+
+  rv = PK11_CipherOp(ctx, sdrResult.data.data, (int*)&sdrResult.data.len, sdrResult.data.len,
+                     paddedData.data, paddedData.len);
+  if (rv != SECSuccess) goto loser;
+
+  PK11_Finalize(ctx);
+
+  sdrResult.keyid = *pKeyID;
+
+  rv = PK11_ParamToAlgid(SEC_OID_DES_EDE3_CBC, params, arena, &sdrResult.alg);
+  if (rv != SECSuccess) goto loser;
+
+  if (!SEC_ASN1EncodeItem(0, result, &sdrResult, template)) { rv = SECFailure; goto loser; }
+
+loser:
+  SECITEM_ZfreeItem(&paddedData, PR_FALSE);
+  if (arena) PORT_FreeArena(arena, PR_TRUE);
+  if (ctx) PK11_DestroyContext(ctx, PR_TRUE);
+  if (params) SECITEM_ZfreeItem(params, PR_TRUE);
+  if (key) PK11_FreeSymKey(key);
+  if (slot) PK11_FreeSlot(slot);
+
+  return rv;
+}
+
+/* decrypt a block */
+static SECStatus
+pk11Decrypt(PK11SlotInfo *slot, PLArenaPool *arena, 
+	    CK_MECHANISM_TYPE type, PK11SymKey *key, 
+	    SECItem *params, SECItem *in, SECItem *result)
+{
+  PK11Context *ctx = 0;
+  SECItem paddedResult;
+  SECStatus rv;
+
+  paddedResult.len = 0;
+  paddedResult.data = 0;
+
+  ctx = PK11_CreateContextBySymKey(type, CKA_DECRYPT, key, params);
+  if (!ctx) { rv = SECFailure; goto loser; }
+
+  paddedResult.len = in->len;
+  paddedResult.data = PORT_ArenaAlloc(arena, paddedResult.len);
+
+  rv = PK11_CipherOp(ctx, paddedResult.data, 
+			(int*)&paddedResult.len, paddedResult.len,
+			in->data, in->len);
+  if (rv != SECSuccess) goto loser;
+
+  PK11_Finalize(ctx);
+
+  /* Remove the padding */
+  rv = unpadBlock(&paddedResult, PK11_GetBlockSize(type, 0), result);
+  if (rv) goto loser;
+
+loser:
+  if (ctx) PK11_DestroyContext(ctx, PR_TRUE);
+  return rv;
+}
+
+/*
+ * PK11SDR_Decrypt
+ *  Decrypt a block of data produced by PK11SDR_Encrypt.  The key used is identified
+ *  by the keyid field within the input.
+ */
+SECStatus
+PK11SDR_Decrypt(SECItem *data, SECItem *result, void *cx)
+{
+  SECStatus rv = SECSuccess;
+  PK11SlotInfo *slot = 0;
+  PK11SymKey *key = 0;
+  CK_MECHANISM_TYPE type;
+  SDRResult sdrResult;
+  SECItem *params = 0;
+  SECItem possibleResult = { 0, NULL, 0 };
+  PLArenaPool *arena = 0;
+
+  arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+  if (!arena) { rv = SECFailure; goto loser; }
+
+  /* Decode the incoming data */
+  memset(&sdrResult, 0, sizeof sdrResult);
+  rv = SEC_QuickDERDecodeItem(arena, &sdrResult, template, data);
+  if (rv != SECSuccess) goto loser;  /* Invalid format */
+
+  /* Find the slot and key for the given keyid */
+  slot = PK11_GetInternalKeySlot();
+  if (!slot) { rv = SECFailure; goto loser; }
+
+  rv = PK11_Authenticate(slot, PR_TRUE, cx);
+  if (rv != SECSuccess) goto loser;
+
+  /* Get the parameter values from the data */
+  params = PK11_ParamFromAlgid(&sdrResult.alg);
+  if (!params) { rv = SECFailure; goto loser; }
+
+  /* Use triple-DES (Should look up the algorithm) */
+  type = CKM_DES3_CBC;
+  key = PK11_FindFixedKey(slot, type, &sdrResult.keyid, cx);
+  if (!key) { 
+	rv = SECFailure;  
+  } else {
+	rv = pk11Decrypt(slot, arena, type, key, params, 
+			&sdrResult.data, result);
+  }
+
+  /*
+   * if the pad value was too small (1 or 2), then it's statistically
+   * 'likely' that (1 in 256) that we may not have the correct key.
+   * Check the other keys for a better match. If we find none, use
+   * this result.
+   */
+  if (rv == SECWouldBlock) {
+	possibleResult = *result;
+  }
+
+  /*
+   * handle the case where your key indicies may have been broken
+   */
+  if (rv != SECSuccess) {
+	PK11SymKey *keyList = PK11_ListFixedKeysInSlot(slot, NULL, cx);
+	PK11SymKey *testKey = NULL;
+	PK11SymKey *nextKey = NULL;
+
+	for (testKey = keyList; testKey; 
+				testKey = PK11_GetNextSymKey(testKey)) {
+	    rv = pk11Decrypt(slot, arena, type, testKey, params, 
+			     &sdrResult.data, result);
+	    if (rv == SECSuccess) {
+		break;
+	    } 
+	    /* found a close match. If it's our first remember it */
+	    if (rv == SECWouldBlock) {
+		if (possibleResult.data) {
+		    /* this is unlikely but possible. If we hit this condition,
+		     * we have no way of knowing which possibility to prefer.
+		     * in this case we just match the key the application
+		     * thought was the right one */
+		    SECITEM_ZfreeItem(result, PR_FALSE);
+		} else {
+		    possibleResult = *result;
+		}
+	    }
+	}
+
+	/* free the list */
+	for (testKey = keyList; testKey; testKey = nextKey) {
+	    nextKey = PK11_GetNextSymKey(testKey);
+	    PK11_FreeSymKey(testKey);
+	}
+  }
+
+  /* we didn't find a better key, use the one with a small pad value */
+  if ((rv != SECSuccess) && (possibleResult.data)) {
+	*result = possibleResult;
+	possibleResult.data = NULL;
+	rv = SECSuccess;
+  }
+
+loser:
+  if (arena) PORT_FreeArena(arena, PR_TRUE);
+  if (key) PK11_FreeSymKey(key);
+  if (params) SECITEM_ZfreeItem(params, PR_TRUE);
+  if (slot) PK11_FreeSlot(slot);
+  if (possibleResult.data) SECITEM_ZfreeItem(&possibleResult, PR_FALSE);
+
+  return rv;
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11sdr.h b/mozilla/security/nss/lib/pk11wrap/pk11sdr.h
new file mode 100644
index 0000000..02e769a
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11sdr.h
@@ -0,0 +1,60 @@
+/* ***** 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 ***** */
+
+#ifndef _PK11SDR_H_
+#define _PK11SDR_H_
+
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+ * PK11SDR_Encrypt - encrypt data using the specified key id or SDR default
+ * result should be freed with SECItem_ZfreeItem
+ */
+SECStatus
+PK11SDR_Encrypt(SECItem *keyid, SECItem *data, SECItem *result, void *cx);
+
+/*
+ * PK11SDR_Decrypt - decrypt data previously encrypted with PK11SDR_Encrypt
+ * result should be freed with SECItem_ZfreeItem
+ */
+SECStatus
+PK11SDR_Decrypt(SECItem *data, SECItem *result, void *cx);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11skey.c b/mozilla/security/nss/lib/pk11wrap/pk11skey.c
new file mode 100644
index 0000000..acf65ac
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11skey.c
@@ -0,0 +1,2311 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * This file implements the Symkey wrapper and the PKCS context
+ * Interfaces.
+ */
+
+#include "seccomon.h"
+#include "secmod.h"
+#include "nssilock.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "secerr.h"
+#include "hasht.h"
+
+/* forward static declarations. */
+static PK11SymKey *pk11_DeriveWithTemplate(PK11SymKey *baseKey, 
+	CK_MECHANISM_TYPE derive, SECItem *param, CK_MECHANISM_TYPE target, 
+	CK_ATTRIBUTE_TYPE operation, int keySize, CK_ATTRIBUTE *userAttr, 
+	unsigned int numAttrs, PRBool isPerm);
+
+static void
+pk11_EnterKeyMonitor(PK11SymKey *symKey) {
+    if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe)) 
+	PK11_EnterSlotMonitor(symKey->slot);
+}
+
+static void
+pk11_ExitKeyMonitor(PK11SymKey *symKey) {
+    if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe)) 
+    	PK11_ExitSlotMonitor(symKey->slot);
+}
+
+/*
+ * pk11_getKeyFromList returns a symKey that has a session (if needSession
+ * was specified), or explicitly does not have a session (if needSession
+ * was not specified).
+ */
+static PK11SymKey *
+pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession) {
+    PK11SymKey *symKey = NULL;
+
+    PZ_Lock(slot->freeListLock);
+    /* own session list are symkeys with sessions that the symkey owns.
+     * 'most' symkeys will own their own session. */
+    if (needSession) {
+	if (slot->freeSymKeysWithSessionHead) {
+    	    symKey = slot->freeSymKeysWithSessionHead;
+	    slot->freeSymKeysWithSessionHead = symKey->next;
+	    slot->keyCount--;
+	}
+    }
+    /* if we don't need a symkey with its own session, or we couldn't find
+     * one on the owner list, get one from the non-owner free list. */
+    if (!symKey) {
+	if (slot->freeSymKeysHead) {
+    	    symKey = slot->freeSymKeysHead;
+	    slot->freeSymKeysHead = symKey->next;
+	    slot->keyCount--;
+	}
+    }
+    PZ_Unlock(slot->freeListLock);
+    if (symKey) {
+	symKey->next = NULL;
+	if (!needSession) {
+	    return symKey;
+	}
+	/* if we are getting an owner key, make sure we have a valid session.
+         * session could be invalid if the token has been removed or because
+         * we got it from the non-owner free list */
+	if ((symKey->series != slot->series) || 
+			 (symKey->session == CK_INVALID_SESSION)) {
+	    symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
+	}
+	PORT_Assert(symKey->session != CK_INVALID_SESSION);
+	if (symKey->session != CK_INVALID_SESSION)
+	    return symKey;
+	PK11_FreeSymKey(symKey);
+	/* if we are here, we need a session, but couldn't get one, it's 
+	 * unlikely we pk11_GetNewSession will succeed if we call it a second
+	 * time. */
+	return NULL;
+    }
+
+    symKey = PORT_New(PK11SymKey);
+    if (symKey == NULL) {
+	return NULL;
+    }
+
+    symKey->next = NULL;
+    if (needSession) {
+	symKey->session = pk11_GetNewSession(slot,&symKey->sessionOwner);
+	PORT_Assert(symKey->session != CK_INVALID_SESSION);
+        if (symKey->session == CK_INVALID_SESSION) {
+	    PK11_FreeSymKey(symKey);
+	    symKey = NULL;
+	}
+    } else {
+	symKey->session = CK_INVALID_SESSION;
+    }
+    return symKey;
+}
+
+/* Caller MUST hold slot->freeListLock (or ref count == 0?) !! */
+void
+PK11_CleanKeyList(PK11SlotInfo *slot)
+{
+    PK11SymKey *symKey = NULL;
+
+    while (slot->freeSymKeysWithSessionHead) {
+    	symKey = slot->freeSymKeysWithSessionHead;
+	slot->freeSymKeysWithSessionHead = symKey->next;
+	pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
+	PORT_Free(symKey);
+    }
+    while (slot->freeSymKeysHead) {
+    	symKey = slot->freeSymKeysHead;
+	slot->freeSymKeysHead = symKey->next;
+	pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
+	PORT_Free(symKey);
+    }
+    return;
+}
+
+/*
+ * create a symetric key:
+ *      Slot is the slot to create the key in.
+ *      type is the mechanism type 
+ *      owner is does this symKey structure own it's object handle (rare
+ *        that this is false).
+ *      needSession means the returned symKey will return with a valid session
+ *        allocated already.
+ */
+static PK11SymKey *
+pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 
+		  PRBool owner, PRBool needSession, void *wincx)
+{
+
+    PK11SymKey *symKey = pk11_getKeyFromList(slot, needSession);
+
+    if (symKey == NULL) {
+	return NULL;
+    }
+    /* if needSession was specified, make sure we have a valid session.
+     * callers which specify needSession as false should do their own
+     * check of the session before returning the symKey */
+    if (needSession && symKey->session == CK_INVALID_SESSION) {
+    	PK11_FreeSymKey(symKey);
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return NULL;
+    }
+
+    symKey->type = type;
+    symKey->data.type = siBuffer;
+    symKey->data.data = NULL;
+    symKey->data.len = 0;
+    symKey->owner = owner;
+    symKey->objectID = CK_INVALID_HANDLE;
+    symKey->slot = slot;
+    symKey->series = slot->series;
+    symKey->cx = wincx;
+    symKey->size = 0;
+    symKey->refCount = 1;
+    symKey->origin = PK11_OriginNULL;
+    symKey->parent = NULL;
+    symKey->freeFunc = NULL;
+    symKey->userData = NULL;
+    PK11_ReferenceSlot(slot);
+    return symKey;
+}
+
+/*
+ * destroy a symetric key
+ */
+void
+PK11_FreeSymKey(PK11SymKey *symKey)
+{
+    PK11SlotInfo *slot;
+    PRBool freeit = PR_TRUE;
+
+    if (PR_AtomicDecrement(&symKey->refCount) == 0) {
+	PK11SymKey *parent = symKey->parent;
+
+	symKey->parent = NULL;
+	if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) {
+	    pk11_EnterKeyMonitor(symKey);
+	    (void) PK11_GETTAB(symKey->slot)->
+		C_DestroyObject(symKey->session, symKey->objectID);
+	    pk11_ExitKeyMonitor(symKey);
+	}
+	if (symKey->data.data) {
+	    PORT_Memset(symKey->data.data, 0, symKey->data.len);
+	    PORT_Free(symKey->data.data);
+	}
+	/* free any existing data */
+	if (symKey->userData && symKey->freeFunc) {
+	    (*symKey->freeFunc)(symKey->userData);
+	}
+        slot = symKey->slot;
+        PZ_Lock(slot->freeListLock);
+	if (slot->keyCount < slot->maxKeyCount) {
+	    /* 
+             * freeSymkeysWithSessionHead contain a list of reusable
+	     *  SymKey structures with valid sessions.
+	     *    sessionOwner must be true.
+             *    session must be valid.
+             * freeSymKeysHead contain a list of SymKey structures without
+             *  valid session.
+             *    session must be CK_INVALID_SESSION.
+	     *    though sessionOwner is false, callers should not depend on
+	     *    this fact.
+	     */
+	    if (symKey->sessionOwner) {
+		PORT_Assert (symKey->session != CK_INVALID_SESSION);
+		symKey->next = slot->freeSymKeysWithSessionHead;
+		slot->freeSymKeysWithSessionHead = symKey;
+	    } else {
+		symKey->session = CK_INVALID_SESSION;
+		symKey->next = slot->freeSymKeysHead;
+		slot->freeSymKeysHead = symKey;
+	    }
+	    slot->keyCount++;
+	    symKey->slot = NULL;
+	    freeit = PR_FALSE;
+        }
+	PZ_Unlock(slot->freeListLock);
+        if (freeit) {
+	    pk11_CloseSession(symKey->slot, symKey->session,
+							symKey->sessionOwner);
+	    PORT_Free(symKey);
+	}
+	PK11_FreeSlot(slot);
+
+	if (parent) {
+	    PK11_FreeSymKey(parent);
+	}
+    }
+}
+
+PK11SymKey *
+PK11_ReferenceSymKey(PK11SymKey *symKey)
+{
+    PR_AtomicIncrement(&symKey->refCount);
+    return symKey;
+}
+
+/*
+ * Accessors
+ */
+CK_MECHANISM_TYPE
+PK11_GetMechanism(PK11SymKey *symKey)
+{
+    return symKey->type;
+}
+
+/*
+ * return the slot associated with a symetric key
+ */
+PK11SlotInfo *
+PK11_GetSlotFromKey(PK11SymKey *symKey)
+{
+    return PK11_ReferenceSlot(symKey->slot);
+}
+
+CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *symKey)
+{
+    return PK11_GetKeyType(symKey->type,symKey->size);
+}
+
+PK11SymKey *
+PK11_GetNextSymKey(PK11SymKey *symKey)
+{
+    return symKey ? symKey->next : NULL;
+}
+
+char *
+PK11_GetSymKeyNickname(PK11SymKey *symKey)
+{
+    return PK11_GetObjectNickname(symKey->slot,symKey->objectID);
+}
+
+SECStatus
+PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname)
+{
+    return PK11_SetObjectNickname(symKey->slot,symKey->objectID,nickname);
+}
+
+void *
+PK11_GetSymKeyUserData(PK11SymKey *symKey)
+{
+    return symKey->userData;
+}
+
+void
+PK11_SetSymKeyUserData(PK11SymKey *symKey, void *userData, 
+                                              PK11FreeDataFunc freeFunc)
+{
+    /* free any existing data */
+    if (symKey->userData && symKey->freeFunc) {
+	(*symKey->freeFunc)(symKey->userData);
+    }
+    symKey->userData = userData;
+    symKey->freeFunc = freeFunc;
+    return;
+}
+
+/*
+ * turn key handle into an appropriate key object
+ */
+PK11SymKey *
+PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, PK11Origin origin,
+    CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, PRBool owner, void *wincx)
+{
+    PK11SymKey *symKey;
+    PRBool needSession = !(owner && parent);
+
+    if (keyID == CK_INVALID_HANDLE) {
+	return NULL;
+    }
+
+    symKey = pk11_CreateSymKey(slot, type, owner, needSession, wincx);
+    if (symKey == NULL) {
+	return NULL;
+    }
+
+    symKey->objectID = keyID;
+    symKey->origin = origin;
+
+    /* adopt the parent's session */
+    /* This is only used by SSL. What we really want here is a session
+     * structure with a ref count so  the session goes away only after all the
+     * keys do. */
+    if (!needSession) {
+	symKey->sessionOwner = PR_FALSE;
+	symKey->session = parent->session;
+	symKey->parent = PK11_ReferenceSymKey(parent);
+        /* This is the only case where pk11_CreateSymKey does not explicitly
+	 * check symKey->session. We need to assert here to make sure.
+	 * the session isn't invalid. */
+	PORT_Assert(parent->session != CK_INVALID_SESSION);
+	if (parent->session == CK_INVALID_SESSION) {
+	    PK11_FreeSymKey(symKey);
+	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	    return NULL;
+	}
+    }
+
+    return symKey;
+}
+
+/*
+ * turn key handle into an appropriate key object
+ */
+PK11SymKey *
+PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type,
+						    int series, void *wincx)
+{
+    PK11SymKey *symKey = NULL;
+
+    if (slot->series != series) return NULL;
+    if (slot->refKeys[wrap] == CK_INVALID_HANDLE) return NULL;
+    if (type == CKM_INVALID_MECHANISM) type = slot->wrapMechanism;
+
+    symKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
+		 slot->wrapMechanism, slot->refKeys[wrap], PR_FALSE, wincx);
+    return symKey;
+}
+
+/*
+ * This function is not thread-safe because it sets wrapKey->sessionOwner
+ * without using a lock or atomic routine.  It can only be called when
+ * only one thread has a reference to wrapKey.
+ */
+void
+PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey)
+{
+    /* save the handle and mechanism for the wrapping key */
+    /* mark the key and session as not owned by us to they don't get freed
+     * when the key goes way... that lets us reuse the key later */
+    slot->refKeys[wrap] = wrapKey->objectID;
+    wrapKey->owner = PR_FALSE;
+    wrapKey->sessionOwner = PR_FALSE;
+    slot->wrapMechanism = wrapKey->type;
+}
+
+
+/*
+ * figure out if a key is still valid or if it is stale.
+ */
+PRBool
+PK11_VerifyKeyOK(PK11SymKey *key) {
+    if (!PK11_IsPresent(key->slot)) {
+	return PR_FALSE;
+    }
+    return (PRBool)(key->series == key->slot->series);
+}
+
+static PK11SymKey *
+pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+                  PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
+		  unsigned int templateCount, SECItem *key, void *wincx)
+{
+    PK11SymKey *    symKey;
+    SECStatus	    rv;
+
+    symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
+    if (symKey == NULL) {
+	return NULL;
+    }
+
+    symKey->size = key->len;
+
+    PK11_SETATTRS(&keyTemplate[templateCount], CKA_VALUE, key->data, key->len);
+    templateCount++;
+
+    if (SECITEM_CopyItem(NULL,&symKey->data,key) != SECSuccess) {
+	PK11_FreeSymKey(symKey);
+	return NULL;
+    }
+
+    symKey->origin = origin;
+
+    /* import the keys */
+    rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
+		 	templateCount, isToken, &symKey->objectID);
+    if ( rv != SECSuccess) {
+	PK11_FreeSymKey(symKey);
+	return NULL;
+    }
+
+    return symKey;
+}
+
+/*
+ * turn key bits into an appropriate key object
+ */
+PK11SymKey *
+PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+     PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,void *wincx)
+{
+    PK11SymKey *    symKey;
+    unsigned int    templateCount = 0;
+    CK_OBJECT_CLASS keyClass 	= CKO_SECRET_KEY;
+    CK_KEY_TYPE     keyType 	= CKK_GENERIC_SECRET;
+    CK_BBOOL        cktrue 	= CK_TRUE; /* sigh */
+    CK_ATTRIBUTE    keyTemplate[5];
+    CK_ATTRIBUTE *  attrs 	= keyTemplate;
+
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
+    PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
+    templateCount = attrs - keyTemplate;
+    PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
+
+    keyType = PK11_GetKeyType(type,key->len);
+    symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE, 
+				keyTemplate, templateCount, key, wincx);
+    return symKey;
+}
+
+
+/*
+ * turn key bits into an appropriate key object
+ */
+PK11SymKey *
+PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+     PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
+     CK_FLAGS flags, PRBool isPerm, void *wincx)
+{
+    PK11SymKey *    symKey;
+    unsigned int    templateCount = 0;
+    CK_OBJECT_CLASS keyClass 	= CKO_SECRET_KEY;
+    CK_KEY_TYPE     keyType 	= CKK_GENERIC_SECRET;
+    CK_BBOOL        cktrue 	= CK_TRUE; /* sigh */
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    CK_ATTRIBUTE *  attrs 	= keyTemplate;
+
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
+    if (isPerm) {
+	PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue) ); attrs++;
+	/* sigh some tokens think CKA_PRIVATE = false is a reasonable 
+	 * default for secret keys */
+	PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue) ); attrs++;
+    }
+    attrs += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
+    if ((operation != CKA_FLAGS_ONLY) &&
+    	 !pk11_FindAttrInTemplate(keyTemplate, attrs-keyTemplate, operation)) {
+        PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue)); attrs++;
+    }
+    templateCount = attrs - keyTemplate;
+    PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
+
+    keyType = PK11_GetKeyType(type,key->len);
+    symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
+				 keyTemplate, templateCount, key, wincx);
+    if (symKey && isPerm) {
+	symKey->owner = PR_FALSE;
+    }
+    return symKey;
+}
+
+
+PK11SymKey *
+PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID,
+								void *wincx)
+{
+    CK_ATTRIBUTE findTemp[4];
+    CK_ATTRIBUTE *attrs;
+    CK_BBOOL ckTrue = CK_TRUE;
+    CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
+    int tsize = 0;
+    CK_OBJECT_HANDLE key_id;
+
+    attrs = findTemp;
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
+    if (keyID) {
+        PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len); attrs++;
+    }
+    tsize = attrs - findTemp;
+    PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
+
+    key_id = pk11_FindObjectByTemplate(slot,findTemp,tsize);
+    if (key_id == CK_INVALID_HANDLE) {
+	return NULL;
+    }
+    return PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, type, key_id,
+		 				PR_FALSE, wincx);
+}
+
+PK11SymKey *
+PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
+{
+    CK_ATTRIBUTE findTemp[4];
+    CK_ATTRIBUTE *attrs;
+    CK_BBOOL ckTrue = CK_TRUE;
+    CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
+    int tsize = 0;
+    int objCount = 0;
+    CK_OBJECT_HANDLE *key_ids;
+    PK11SymKey *nextKey = NULL;
+    PK11SymKey *topKey = NULL;
+    int i,len;
+
+    attrs = findTemp;
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
+    if (nickname) {
+	len = PORT_Strlen(nickname);
+	PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
+    }
+    tsize = attrs - findTemp;
+    PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
+
+    key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
+    if (key_ids == NULL) {
+	return NULL;
+    }
+
+    for (i=0; i < objCount ; i++) {
+	SECItem typeData;
+	CK_KEY_TYPE type = CKK_GENERIC_SECRET;
+        SECStatus rv = PK11_ReadAttribute(slot, key_ids[i], 
+						CKA_KEY_TYPE, NULL, &typeData);
+	if (rv == SECSuccess) {
+	    if (typeData.len == sizeof(CK_KEY_TYPE)) {
+	    	type = *(CK_KEY_TYPE *)typeData.data;
+	    }
+	    PORT_Free(typeData.data);
+	}
+	nextKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, 
+		PK11_GetKeyMechanism(type), key_ids[i], PR_FALSE, wincx);
+	if (nextKey) {
+	    nextKey->next = topKey;
+	    topKey = nextKey;
+	}
+   }
+   PORT_Free(key_ids);
+   return topKey;
+}
+
+void *
+PK11_GetWindow(PK11SymKey *key)
+{
+   return key->cx;
+}
+    
+
+/*
+ * extract a symetric key value. NOTE: if the key is sensitive, we will
+ * not be able to do this operation. This function is used to move
+ * keys from one token to another */
+SECStatus
+PK11_ExtractKeyValue(PK11SymKey *symKey)
+{
+    SECStatus rv;
+
+    if (symKey->data.data != NULL) {
+	if (symKey->size == 0) {
+	   symKey->size = symKey->data.len;
+	}
+	return SECSuccess;
+    }
+
+    if (symKey->slot == NULL) {
+	PORT_SetError( SEC_ERROR_INVALID_KEY );
+	return SECFailure;
+    }
+
+    rv = PK11_ReadAttribute(symKey->slot,symKey->objectID,CKA_VALUE,NULL,
+				&symKey->data);
+    if (rv == SECSuccess) {
+	symKey->size = symKey->data.len;
+    }
+    return rv;
+}
+
+SECStatus
+PK11_DeleteTokenSymKey(PK11SymKey *symKey)
+{
+    if (!PK11_IsPermObject(symKey->slot, symKey->objectID)) {
+	return SECFailure;
+    }
+    PK11_DestroyTokenObject(symKey->slot,symKey->objectID);
+    symKey->objectID = CK_INVALID_HANDLE;
+    return SECSuccess;
+}
+
+SECItem *
+PK11_GetKeyData(PK11SymKey *symKey)
+{
+    return &symKey->data;
+}
+
+/* This symbol is exported for backward compatibility. */
+SECItem *
+__PK11_GetKeyData(PK11SymKey *symKey)
+{
+    return PK11_GetKeyData(symKey);
+}
+
+
+/*
+ * PKCS #11 key Types with predefined length
+ */
+unsigned int
+pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType)
+{
+    int length = 0;
+    switch (keyType) {
+      case CKK_DES: length = 8; break;
+      case CKK_DES2: length = 16; break;
+      case CKK_DES3: length = 24; break;
+      case CKK_SKIPJACK: length = 10; break;
+      case CKK_BATON: length = 20; break;
+      case CKK_JUNIPER: length = 20; break;
+      default: break;
+    }
+    return length;
+}
+
+/* return the keylength if possible.  '0' if not */
+unsigned int
+PK11_GetKeyLength(PK11SymKey *key)
+{
+    CK_KEY_TYPE keyType;
+
+    if (key->size != 0) return key->size;
+
+    /* First try to figure out the key length from its type */
+    keyType = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_KEY_TYPE);
+    key->size = pk11_GetPredefinedKeyLength(keyType);
+    if ((keyType == CKK_GENERIC_SECRET) &&
+	(key->type == CKM_SSL3_PRE_MASTER_KEY_GEN))  {
+	key->size=48;
+    }
+
+   if( key->size != 0 ) return key->size;
+
+   if (key->data.data == NULL) {
+	PK11_ExtractKeyValue(key);
+   }
+   /* key is probably secret. Look up its length */
+   /*  this is new PKCS #11 version 2.0 functionality. */
+   if (key->size == 0) {
+	CK_ULONG keyLength;
+
+	keyLength = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_VALUE_LEN);
+	if (keyLength != CK_UNAVAILABLE_INFORMATION) {
+	    key->size = (unsigned int)keyLength;
+	}
+    }
+
+   return key->size;
+}
+
+/* return the strength of a key. This is different from length in that
+ * 1) it returns the size in bits, and 2) it returns only the secret portions
+ * of the key minus any checksums or parity.
+ */
+unsigned int
+PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid) 
+{
+     int size=0;
+     CK_MECHANISM_TYPE mechanism= CKM_INVALID_MECHANISM; /* RC2 only */
+     SECItem *param = NULL; /* RC2 only */
+     CK_RC2_CBC_PARAMS *rc2_params = NULL; /* RC2 ONLY */
+     unsigned int effectiveBits = 0; /* RC2 ONLY */
+
+     switch (PK11_GetKeyType(key->type,0)) {
+     case CKK_CDMF:
+	return 40;
+     case CKK_DES:
+	return 56;
+     case CKK_DES3:
+     case CKK_DES2:
+	size = PK11_GetKeyLength(key);
+	if (size == 16) {
+	   /* double des */
+	   return 112; /* 16*7 */
+	}
+	return 168;
+    /*
+     * RC2 has is different than other ciphers in that it allows the user
+     * to deprecating keysize while still requiring all the bits for the 
+     * original key. The info
+     * on what the effective key strength is in the parameter for the key.
+     * In S/MIME this parameter is stored in the DER encoded algid. In Our 
+     * other uses of RC2, effectiveBits == keyBits, so this code functions
+     * correctly without an algid.
+     */
+    case CKK_RC2:
+	/* if no algid was provided, fall through to default */
+        if (!algid) {
+	    break; 
+	}
+	/* verify that the algid is for RC2 */
+	mechanism = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(algid));
+	if ((mechanism != CKM_RC2_CBC) && (mechanism != CKM_RC2_ECB)) {
+	    break;
+	}
+
+	/* now get effective bits from the algorithm ID. */
+	param = PK11_ParamFromAlgid(algid);
+	/* if we couldn't get memory just use key length */
+	if (param == NULL) {
+	    break;
+	}
+
+	rc2_params = (CK_RC2_CBC_PARAMS *) param->data;
+	/* paranoia... shouldn't happen */
+	PORT_Assert(param->data != NULL);
+	if (param->data == NULL) {
+	    SECITEM_FreeItem(param,PR_TRUE);
+	    break;
+	}
+	effectiveBits = (unsigned int)rc2_params->ulEffectiveBits;
+	SECITEM_FreeItem(param,PR_TRUE);
+	param = NULL; rc2_params=NULL; /* paranoia */
+
+	/* we have effective bits, is and allocated memory is free, now
+	 * we need to return the smaller of effective bits and keysize */
+	size = PK11_GetKeyLength(key);
+	if ((unsigned int)size*8 > effectiveBits) {
+	    return effectiveBits;
+	}
+
+	return size*8; /* the actual key is smaller, the strength can't be
+			* greater than the actual key size */
+	
+    default:
+	break;
+    }
+    return PK11_GetKeyLength(key) * 8;
+}
+
+/*
+ * The next three utilities are to deal with the fact that a given operation
+ * may be a multi-slot affair. This creates a new key object that is copied
+ * into the new slot.
+ */
+PK11SymKey *
+pk11_CopyToSlotPerm(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 
+	 	CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, 
+		PRBool isPerm, PK11SymKey *symKey)
+{
+    SECStatus rv;
+    PK11SymKey *newKey = NULL;
+
+    /* Extract the raw key data if possible */
+    if (symKey->data.data == NULL) {
+	rv = PK11_ExtractKeyValue(symKey);
+	/* KEY is sensitive, we're try key exchanging it. */
+	if (rv != SECSuccess) {
+	    return pk11_KeyExchange(slot, type, operation, 
+						flags, isPerm, symKey);
+	}
+    }
+
+    newKey = PK11_ImportSymKeyWithFlags(slot,  type, symKey->origin,
+	operation, &symKey->data, flags, isPerm, symKey->cx);
+    if (newKey == NULL) {
+	newKey = pk11_KeyExchange(slot, type, operation, flags, isPerm, symKey);
+    }
+    return newKey;
+}
+
+PK11SymKey *
+pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
+	CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey)
+{
+   return pk11_CopyToSlotPerm(slot, type, operation, 0, PR_FALSE, symKey);
+}
+
+/*
+ * Make sure the slot we are in the correct slot for the operation
+ */
+PK11SymKey *
+pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type,
+						CK_ATTRIBUTE_TYPE operation)
+{
+    PK11SlotInfo *slot = symKey->slot;
+    PK11SymKey *newKey = NULL;
+
+    if ((slot== NULL) || !PK11_DoesMechanism(slot,type)) {
+	slot = PK11_GetBestSlot(type,symKey->cx);
+	if (slot == NULL) {
+	    PORT_SetError( SEC_ERROR_NO_MODULE );
+	    return NULL;
+	}
+	newKey = pk11_CopyToSlot(slot, type, operation, symKey);
+	PK11_FreeSlot(slot);
+    }
+    return newKey;
+}
+
+PK11SymKey *
+PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, 
+			CK_FLAGS flags, PRBool  perm, PK11SymKey *symKey)
+{
+    if (symKey->slot == slot) {
+	if (perm) {
+	   return PK11_ConvertSessionSymKeyToTokenSymKey(symKey,symKey->cx);
+	} else {
+	   return PK11_ReferenceSymKey(symKey);
+	}
+    }
+    
+    return pk11_CopyToSlotPerm(slot, symKey->type, 
+					operation, flags, perm, symKey);
+}
+
+/*
+ * Use the token to generate a key. 
+ * 
+ * keySize must be 'zero' for fixed key length algorithms. A nonzero 
+ *  keySize causes the CKA_VALUE_LEN attribute to be added to the template 
+ *  for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN 
+ *  attribute for keys with fixed length. The exception is DES2. If you
+ *  select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
+ *  paramter and use the key size to determine which underlying DES keygen
+ *  function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
+ *
+ * keyType must be -1 for most algorithms. Some PBE algorthims cannot 
+ *  determine the correct key type from the mechanism or the paramters,
+ *  so key type must be specified. Other PKCS #11 mechanisms may do so in
+ *  the future. Currently there is no need to export this publically.
+ *  Keep it private until there is a need in case we need to expand the
+ *  keygen parameters again...
+ *
+ * CK_FLAGS flags: key operation flags
+ * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
+ */
+PK11SymKey *
+pk11_TokenKeyGenWithFlagsAndKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+    SECItem *param, CK_KEY_TYPE keyType, int keySize, SECItem *keyid, 
+    CK_FLAGS opFlags, PK11AttrFlags attrFlags, void *wincx)
+{
+    PK11SymKey *symKey;
+    CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS];
+    CK_ATTRIBUTE *attrs = genTemplate;
+    int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
+    CK_SESSION_HANDLE session;
+    CK_MECHANISM mechanism;
+    CK_RV crv;
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_ULONG ck_key_size;       /* only used for variable-length keys */
+    PRBool isToken = ((attrFlags & PK11_ATTR_TOKEN) != 0);
+
+    if (pk11_BadAttrFlags(attrFlags)) {
+	PORT_SetError( SEC_ERROR_INVALID_ARGS );
+	return NULL;
+    }
+
+    if ((keySize != 0) && (type != CKM_DES3_CBC) && 
+		(type !=CKM_DES3_CBC_PAD) && (type != CKM_DES3_ECB)) {
+        ck_key_size = keySize; /* Convert to PK11 type */
+
+        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size)); 
+							attrs++;
+    }
+
+    if (keyType != -1) {
+        PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE)); 
+							attrs++;
+    }
+
+    /* Include key id value if provided */
+    if (keyid) {
+        PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++;
+    }
+
+    attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
+    attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
+
+    count = attrs - genTemplate;
+    PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE));
+
+    /* Initialize the Key Gen Mechanism */
+    mechanism.mechanism = PK11_GetKeyGenWithSize(type, keySize);
+    if (mechanism.mechanism == CKM_FAKE_RANDOM) {
+	PORT_SetError( SEC_ERROR_NO_MODULE );
+	return NULL;
+    }
+
+    /* find a slot to generate the key into */
+    /* Only do slot management if this is not a token key */
+    if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot,type))) {
+        PK11SlotInfo *bestSlot;
+
+        bestSlot = PK11_GetBestSlot(type,wincx);
+        if (bestSlot == NULL) {
+	    PORT_SetError( SEC_ERROR_NO_MODULE );
+	    return NULL;
+	}
+
+        symKey = pk11_CreateSymKey(bestSlot, type, !isToken, PR_TRUE, wincx);
+
+        PK11_FreeSlot(bestSlot);
+    } else {
+	symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
+    }
+    if (symKey == NULL) return NULL;
+
+    symKey->size = keySize;
+    symKey->origin = PK11_OriginGenerated;
+
+    /* Set the parameters for the key gen if provided */
+    mechanism.pParameter = NULL;
+    mechanism.ulParameterLen = 0;
+    if (param) {
+	mechanism.pParameter = param->data;
+	mechanism.ulParameterLen = param->len;
+    }
+
+    /* Get session and perform locking */
+    if (isToken) {
+	PK11_Authenticate(symKey->slot,PR_TRUE,wincx);
+	/* Should always be original slot */
+        session = PK11_GetRWSession(symKey->slot);  
+	symKey->owner = PR_FALSE;
+    } else {
+        session = symKey->session;
+	if (session != CK_INVALID_SESSION) 
+	    pk11_EnterKeyMonitor(symKey);
+    }
+    if (session == CK_INVALID_SESSION) {
+	PK11_FreeSymKey(symKey);
+	PORT_SetError(SEC_ERROR_BAD_DATA);
+	return NULL;
+    }
+
+    crv = PK11_GETTAB(symKey->slot)->C_GenerateKey(session,
+			 &mechanism, genTemplate, count, &symKey->objectID);
+
+    /* Release lock and session */
+    if (isToken) {
+        PK11_RestoreROSession(symKey->slot, session);
+    } else {
+        pk11_ExitKeyMonitor(symKey);
+    }
+
+    if (crv != CKR_OK) {
+	PK11_FreeSymKey(symKey);
+	PORT_SetError( PK11_MapError(crv) );
+	return NULL;
+    }
+
+    return symKey;
+}
+
+/*
+ * Use the token to generate a key.  - Public
+ * 
+ * keySize must be 'zero' for fixed key length algorithms. A nonzero 
+ *  keySize causes the CKA_VALUE_LEN attribute to be added to the template 
+ *  for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN 
+ *  attribute for keys with fixed length. The exception is DES2. If you
+ *  select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
+ *  paramter and use the key size to determine which underlying DES keygen
+ *  function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
+ *
+ * CK_FLAGS flags: key operation flags
+ * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
+ */
+PK11SymKey *
+PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+    SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags,
+    PK11AttrFlags attrFlags, void *wincx)
+{
+    return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, -1, keySize, 
+	keyid, opFlags, attrFlags, wincx);
+}
+
+/*
+ * Use the token to generate a key. keySize must be 'zero' for fixed key
+ * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute
+ * to be added to the template for the key. PKCS #11 modules fail if you
+ * specify the CKA_VALUE_LEN attribute for keys with fixed length.
+ * NOTE: this means to generate a DES2 key from this interface you must
+ * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying
+ * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
+ */
+PK11SymKey *
+PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
+    int keySize, SECItem *keyid, PRBool isToken, void *wincx)
+{
+    PK11SymKey *symKey;
+    PRBool weird = PR_FALSE;   /* hack for fortezza */
+    CK_FLAGS opFlags = CKF_SIGN;
+    PK11AttrFlags attrFlags = 0;
+
+    if ((keySize == -1) && (type == CKM_SKIPJACK_CBC64)) {
+	weird = PR_TRUE;
+	keySize = 0;
+    }
+
+    opFlags |= weird ? CKF_DECRYPT : CKF_ENCRYPT;
+
+    if (isToken) {
+	attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
+    }
+
+    symKey = pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, 
+			-1, keySize, keyid, opFlags, attrFlags, wincx);
+    if (symKey && weird) {
+	PK11_SetFortezzaHack(symKey);
+    }
+
+    return symKey;
+}
+
+PK11SymKey *
+PK11_KeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
+						int keySize, void *wincx)
+{
+    return PK11_TokenKeyGen(slot, type, param, keySize, 0, PR_FALSE, wincx);
+}
+
+/* --- */
+PK11SymKey *
+PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx)
+{
+  return PK11_TokenKeyGen(slot, CKM_DES3_CBC, 0, 0, keyid, PR_TRUE, cx);
+}
+
+PK11SymKey*
+PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
+{
+    PK11SlotInfo* slot = symk->slot;
+    CK_ATTRIBUTE template[1];
+    CK_ATTRIBUTE *attrs = template;
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_RV crv;
+    CK_OBJECT_HANDLE newKeyID;
+    CK_SESSION_HANDLE rwsession;
+
+    PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++;
+
+    PK11_Authenticate(slot, PR_TRUE, wincx);
+    rwsession = PK11_GetRWSession(slot);
+    if (rwsession == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_BAD_DATA);
+	return NULL;
+    }
+    crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID,
+        template, 1, &newKeyID);
+    PK11_RestoreROSession(slot, rwsession);
+
+    if (crv != CKR_OK) {
+        PORT_SetError( PK11_MapError(crv) );
+        return NULL;
+    }
+
+    return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin,
+        symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
+}
+
+/*
+ * This function does a straight public key wrap (which only RSA can do).
+ * Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
+ * Diffie-Hellman Ciphers. */
+SECStatus
+PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
+				PK11SymKey *symKey, SECItem *wrappedKey)
+{
+    PK11SlotInfo *slot;
+    CK_ULONG len =  wrappedKey->len;
+    PK11SymKey *newKey = NULL;
+    CK_OBJECT_HANDLE id;
+    CK_MECHANISM mechanism;
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_RV crv;
+
+    /* if this slot doesn't support the mechanism, go to a slot that does */
+    newKey = pk11_ForceSlot(symKey,type,CKA_ENCRYPT);
+    if (newKey != NULL) {
+	symKey = newKey;
+    }
+
+    if ((symKey == NULL) || (symKey->slot == NULL)) {
+	PORT_SetError( SEC_ERROR_NO_MODULE );
+	return SECFailure;
+    }
+
+    slot = symKey->slot;
+    mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
+    mechanism.pParameter = NULL;
+    mechanism.ulParameterLen = 0;
+
+    id = PK11_ImportPublicKey(slot,pubKey,PR_FALSE);
+    if (id == CK_INVALID_HANDLE) {
+	if (newKey) {
+	    PK11_FreeSymKey(newKey);
+	}
+	return SECFailure;   /* Error code has been set. */
+    }
+
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_WrapKey(session,&mechanism,
+		id,symKey->objectID,wrappedKey->data,&len);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    if (newKey) {
+	PK11_FreeSymKey(newKey);
+    }
+
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    wrappedKey->len = len;
+    return SECSuccess;
+} 
+
+/*
+ * this little function uses the Encrypt function to wrap a key, just in
+ * case we have problems with the wrap implementation for a token.
+ */
+static SECStatus
+pk11_HandWrap(PK11SymKey *wrappingKey, SECItem *param, CK_MECHANISM_TYPE type,
+			 SECItem *inKey, SECItem *outKey)
+{
+    PK11SlotInfo *slot;
+    CK_ULONG len;
+    SECItem *data;
+    CK_MECHANISM mech;
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_RV crv;
+
+    slot = wrappingKey->slot;
+    /* use NULL IV's for wrapping */
+    mech.mechanism = type;
+    if (param) {
+	mech.pParameter = param->data;
+	mech.ulParameterLen = param->len;
+    } else {
+	mech.pParameter = NULL;
+	mech.ulParameterLen = 0;
+    }
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_EncryptInit(session,&mech,
+							wrappingKey->objectID);
+    if (crv != CKR_OK) {
+        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+        pk11_CloseSession(slot,session,owner);
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+
+    /* keys are almost always aligned, but if we get this far,
+     * we've gone above and beyond anyway... */
+    data = PK11_BlockData(inKey,PK11_GetBlockSize(type,param));
+    if (data == NULL) {
+        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+        pk11_CloseSession(slot,session,owner);
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    len = outKey->len;
+    crv = PK11_GETTAB(slot)->C_Encrypt(session,data->data,data->len,
+							   outKey->data, &len);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    SECITEM_FreeItem(data,PR_TRUE);
+    outKey->len = len;
+    if (crv != CKR_OK) {
+	PORT_SetError( PK11_MapError(crv) );
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*
+ * This function does a symetric based wrap.
+ */
+SECStatus
+PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *param, 
+	PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey)
+{
+    PK11SlotInfo *slot;
+    CK_ULONG len = wrappedKey->len;
+    PK11SymKey *newKey = NULL;
+    SECItem *param_save = NULL;
+    CK_MECHANISM mechanism;
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+    CK_RV crv;
+    SECStatus rv;
+
+    /* if this slot doesn't support the mechanism, go to a slot that does */
+    /* Force symKey and wrappingKey into the same slot */
+    if ((wrappingKey->slot == NULL) || (symKey->slot != wrappingKey->slot)) {
+	/* first try copying the wrapping Key to the symKey slot */
+	if (symKey->slot && PK11_DoesMechanism(symKey->slot,type)) {
+	    newKey = pk11_CopyToSlot(symKey->slot,type,CKA_WRAP,wrappingKey);
+	}
+	/* Nope, try it the other way */
+	if (newKey == NULL) {
+	    if (wrappingKey->slot) {
+	        newKey = pk11_CopyToSlot(wrappingKey->slot,
+					symKey->type, CKA_ENCRYPT, symKey);
+	    }
+	    /* just not playing... one last thing, can we get symKey's data?
+	     * If it's possible, we it should already be in the 
+	     * symKey->data.data pointer because pk11_CopyToSlot would have
+	     * tried to put it there. */
+	    if (newKey == NULL) {
+		/* Can't get symKey's data: Game Over */
+		if (symKey->data.data == NULL) {
+		    PORT_SetError( SEC_ERROR_NO_MODULE );
+		    return SECFailure;
+		}
+		if (param == NULL) {
+		    param_save = param = PK11_ParamFromIV(type,NULL);
+		}
+		rv = pk11_HandWrap(wrappingKey, param, type,
+						&symKey->data,wrappedKey);
+		if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
+		return rv;
+	    }
+	    /* we successfully moved the sym Key */
+	    symKey = newKey;
+	} else {
+	    /* we successfully moved the wrapping Key */
+	    wrappingKey = newKey;
+	}
+    }
+
+    /* at this point both keys are in the same token */
+    slot = wrappingKey->slot;
+    mechanism.mechanism = type;
+    /* use NULL IV's for wrapping */
+    if (param == NULL) {
+    	param_save = param = PK11_ParamFromIV(type,NULL);
+    }
+    if (param) {
+	mechanism.pParameter = param->data;
+	mechanism.ulParameterLen = param->len;
+    } else {
+	mechanism.pParameter = NULL;
+	mechanism.ulParameterLen = 0;
+    }
+
+    len = wrappedKey->len;
+
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
+		 wrappingKey->objectID, symKey->objectID, 
+						wrappedKey->data, &len);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    rv = SECSuccess;
+    if (crv != CKR_OK) {
+	/* can't wrap it? try hand wrapping it... */
+	do {
+	    if (symKey->data.data == NULL) {
+		rv = PK11_ExtractKeyValue(symKey);
+		if (rv != SECSuccess) break;
+	    }
+	    rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data,
+								 wrappedKey);
+	} while (PR_FALSE);
+    } else {
+        wrappedKey->len = len;
+    }
+    if (newKey) PK11_FreeSymKey(newKey);
+    if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
+    return rv;
+} 
+
+/*
+ * This Generates a new key based on a symetricKey
+ */
+PK11SymKey *
+PK11_Derive( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param, 
+             CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
+	     int keySize)
+{
+    return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
+				   keySize, NULL, 0, PR_FALSE);
+}
+
+
+PK11SymKey *
+PK11_DeriveWithFlags( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
+	SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+	int keySize, CK_FLAGS flags)
+{
+    CK_BBOOL        ckTrue	= CK_TRUE; 
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    unsigned int    templateCount;
+
+    templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
+    return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
+		  keySize, keyTemplate, templateCount, PR_FALSE);
+}
+
+PK11SymKey *
+PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
+	SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+	int keySize, CK_FLAGS flags, PRBool isPerm)
+{
+    CK_BBOOL        cktrue	= CK_TRUE; 
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    CK_ATTRIBUTE    *attrs;
+    unsigned int    templateCount = 0;
+
+    attrs = keyTemplate;
+    if (isPerm) {
+        PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
+    }
+    templateCount = attrs - keyTemplate;
+    templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
+    return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
+				   keySize, keyTemplate, templateCount, isPerm);
+}
+
+static PK11SymKey *
+pk11_DeriveWithTemplate( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
+	SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+	int keySize, CK_ATTRIBUTE *userAttr, unsigned int numAttrs,
+							 PRBool isPerm)
+{
+    PK11SlotInfo *  slot	= baseKey->slot;
+    PK11SymKey *    symKey;
+    PK11SymKey *    newBaseKey	= NULL;
+    CK_BBOOL        cktrue	= CK_TRUE; 
+    CK_OBJECT_CLASS keyClass	= CKO_SECRET_KEY;
+    CK_KEY_TYPE     keyType	= CKK_GENERIC_SECRET;
+    CK_ULONG        valueLen	= 0;
+    CK_MECHANISM    mechanism; 
+    CK_RV           crv;
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    CK_ATTRIBUTE *  attrs	= keyTemplate;
+    CK_SESSION_HANDLE session;
+    unsigned int    templateCount;
+
+    if (numAttrs > MAX_TEMPL_ATTRS) {
+    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    /* first copy caller attributes in. */
+    for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
+    	*attrs++ = *userAttr++;
+    }
+
+    /* We only add the following attributes to the template if the caller
+    ** didn't already supply them.
+    */
+    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
+	PK11_SETATTRS(attrs, CKA_CLASS,     &keyClass, sizeof keyClass); 
+	attrs++;
+    }
+    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
+	keyType = PK11_GetKeyType(target, keySize);
+	PK11_SETATTRS(attrs, CKA_KEY_TYPE,  &keyType,  sizeof keyType ); 
+	attrs++;
+    }
+    if (keySize > 0 &&
+    	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
+	valueLen = (CK_ULONG)keySize;
+	PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen); 
+	attrs++;
+    }
+    if ((operation != CKA_FLAGS_ONLY) &&
+	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
+	PK11_SETATTRS(attrs, operation, &cktrue, sizeof cktrue); attrs++;
+    }
+
+    templateCount = attrs - keyTemplate;
+    PR_ASSERT(templateCount <= MAX_TEMPL_ATTRS);
+
+    /* move the key to a slot that can do the function */
+    if (!PK11_DoesMechanism(slot,derive)) {
+	/* get a new base key & slot */
+	PK11SlotInfo *newSlot = PK11_GetBestSlot(derive, baseKey->cx);
+
+	if (newSlot == NULL) return NULL;
+
+        newBaseKey = pk11_CopyToSlot (newSlot, derive, CKA_DERIVE, 
+				     baseKey);
+	PK11_FreeSlot(newSlot);
+	if (newBaseKey == NULL) 
+	    return NULL;	
+	baseKey = newBaseKey;
+	slot = baseKey->slot;
+    }
+
+
+    /* get our key Structure */
+    symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, baseKey->cx);
+    if (symKey == NULL) {
+	return NULL;
+    }
+
+    symKey->size = keySize;
+
+    mechanism.mechanism = derive;
+    if (param) {
+	mechanism.pParameter = param->data;
+	mechanism.ulParameterLen = param->len;
+    } else {
+	mechanism.pParameter = NULL;
+	mechanism.ulParameterLen = 0;
+    }
+    symKey->origin=PK11_OriginDerive;
+
+    if (isPerm) {
+	session =  PK11_GetRWSession(slot);
+    } else {
+        pk11_EnterKeyMonitor(symKey);
+	session = symKey->session;
+    }
+    if (session == CK_INVALID_SESSION) {
+	if (!isPerm)
+	    pk11_ExitKeyMonitor(symKey);
+	crv = CKR_SESSION_HANDLE_INVALID;
+    } else {
+	crv = PK11_GETTAB(slot)->C_DeriveKey(session, &mechanism,
+	     baseKey->objectID, keyTemplate, templateCount, &symKey->objectID);
+	if (isPerm) {
+	    PK11_RestoreROSession(slot, session);
+	} else {
+	    pk11_ExitKeyMonitor(symKey);
+	}
+    }
+    if (newBaseKey) 
+    	PK11_FreeSymKey(newBaseKey);
+    if (crv != CKR_OK) {
+	PK11_FreeSymKey(symKey);
+	return NULL;
+    }
+    return symKey;
+}
+
+/*
+ * This Generates a wrapping key based on a privateKey, publicKey, and two
+ * random numbers. For Mail usage RandomB should be NULL. In the Sender's
+ * case RandomA is generate, outherwize it is passed.
+ */
+static unsigned char *rb_email = NULL;
+
+PK11SymKey *
+PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 
+   PRBool isSender, SECItem *randomA, SECItem *randomB, 
+    CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
+			CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx)
+{
+    PK11SlotInfo *slot = privKey->pkcs11Slot;
+    CK_MECHANISM mechanism;
+    PK11SymKey *symKey;
+    CK_RV crv;
+
+
+    if (rb_email == NULL) {
+	rb_email = PORT_ZAlloc(128);
+	if (rb_email == NULL) {
+	    return NULL;
+	}
+	rb_email[127] = 1;
+    }
+
+    /* get our key Structure */
+    symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
+    if (symKey == NULL) {
+	return NULL;
+    }
+
+    symKey->origin = PK11_OriginDerive;
+
+    switch (privKey->keyType) {
+    case rsaKey:
+    case nullKey:
+	PORT_SetError(SEC_ERROR_BAD_KEY);
+	break;
+    case dsaKey:
+    case keaKey:
+    case fortezzaKey:
+	{
+	    CK_KEA_DERIVE_PARAMS param;
+	    param.isSender = (CK_BBOOL) isSender;
+	    param.ulRandomLen = randomA->len;
+	    param.pRandomA = randomA->data;
+	    param.pRandomB = rb_email;
+	    if (randomB)
+		 param.pRandomB = randomB->data;
+	    if (pubKey->keyType == fortezzaKey) {
+		param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
+		param.pPublicData = pubKey->u.fortezza.KEAKey.data;
+	    } else {
+		/* assert type == keaKey */
+		/* XXX change to match key key types */
+		param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
+		param.pPublicData = pubKey->u.fortezza.KEAKey.data;
+	    }
+
+	    mechanism.mechanism = derive;
+	    mechanism.pParameter = &param;
+	    mechanism.ulParameterLen = sizeof(param);
+
+	    /* get a new symKey structure */
+	    pk11_EnterKeyMonitor(symKey);
+	    crv=PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
+			privKey->pkcs11ID, NULL, 0, &symKey->objectID);
+	    pk11_ExitKeyMonitor(symKey);
+	    if (crv == CKR_OK) return symKey;
+	    PORT_SetError( PK11_MapError(crv) );
+	}
+	break;
+    case dhKey:
+	{
+	    CK_BBOOL cktrue = CK_TRUE;
+	    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+	    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+	    CK_ULONG key_size = 0;
+	    CK_ATTRIBUTE keyTemplate[4];
+	    int templateCount;
+	    CK_ATTRIBUTE *attrs = keyTemplate;
+
+	    if (pubKey->keyType != dhKey) {
+		PORT_SetError(SEC_ERROR_BAD_KEY);
+		break;
+	    }
+
+	    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
+	    attrs++;
+	    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
+	    attrs++;
+	    PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); 
+	    attrs++;
+	    templateCount =  attrs - keyTemplate;
+	    PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
+
+	    keyType = PK11_GetKeyType(target,keySize);
+	    key_size = keySize;
+	    symKey->size = keySize;
+	    if (key_size == 0) templateCount--;
+
+	    mechanism.mechanism = derive;
+
+	    /* we can undefine these when we define diffie-helman keys */
+
+	    mechanism.pParameter = pubKey->u.dh.publicValue.data; 
+	    mechanism.ulParameterLen = pubKey->u.dh.publicValue.len;
+		
+	    pk11_EnterKeyMonitor(symKey);
+	    crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
+	     privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
+	    pk11_ExitKeyMonitor(symKey);
+	    if (crv == CKR_OK) return symKey;
+	    PORT_SetError( PK11_MapError(crv) );
+	}
+	break;
+    case ecKey:
+        {
+	    CK_BBOOL cktrue = CK_TRUE;
+	    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+	    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+	    CK_ULONG key_size = 0;
+	    CK_ATTRIBUTE keyTemplate[4];
+	    int templateCount;
+	    CK_ATTRIBUTE *attrs = keyTemplate;
+	    CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
+
+	    if (pubKey->keyType != ecKey) {
+		PORT_SetError(SEC_ERROR_BAD_KEY);
+		break;
+	    }
+
+	    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
+	    attrs++;
+	    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
+	    attrs++;
+	    PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
+	    PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); 
+	    attrs++;
+	    templateCount =  attrs - keyTemplate;
+	    PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
+
+	    keyType = PK11_GetKeyType(target,keySize);
+	    key_size = keySize;
+	    if (key_size == 0) {
+		if (pk11_GetPredefinedKeyLength(keyType)) {
+		    templateCount --;
+		} else {
+		    /* sigh, some tokens can't figure this out and require
+		     * CKA_VALUE_LEN to be set */
+		    key_size = SHA1_LENGTH;
+		}
+	    }
+	    symKey->size = key_size;
+
+	    mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS); 
+	    mechParams->kdf = CKD_SHA1_KDF;
+	    mechParams->ulSharedDataLen = 0;
+	    mechParams->pSharedData = NULL;
+	    mechParams->ulPublicDataLen =  pubKey->u.ec.publicValue.len;
+	    mechParams->pPublicData =  pubKey->u.ec.publicValue.data;
+
+	    mechanism.mechanism = derive;
+	    mechanism.pParameter = mechParams;
+	    mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
+
+	    pk11_EnterKeyMonitor(symKey);
+	    crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, 
+		&mechanism, privKey->pkcs11ID, keyTemplate, 
+		templateCount, &symKey->objectID);
+	    pk11_ExitKeyMonitor(symKey);
+
+	    /* old PKCS #11 spec was ambiguous on what needed to be passed,
+	     * try this again with and encoded public key */
+	    if (crv != CKR_OK) {
+		SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
+			&pubKey->u.ec.publicValue,
+			SEC_ASN1_GET(SEC_OctetStringTemplate));
+		if (pubValue == NULL) {
+	    	    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
+		    break;
+		}
+		mechParams->ulPublicDataLen =  pubValue->len;
+		mechParams->pPublicData =  pubValue->data;
+
+		pk11_EnterKeyMonitor(symKey);
+		crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, 
+		    &mechanism, privKey->pkcs11ID, keyTemplate, 
+		    templateCount, &symKey->objectID);
+		pk11_ExitKeyMonitor(symKey);
+
+		SECITEM_FreeItem(pubValue,PR_TRUE);
+	    }
+
+	    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
+
+	    if (crv == CKR_OK) return symKey;
+	    PORT_SetError( PK11_MapError(crv) );
+	}
+   }
+
+   PK11_FreeSymKey(symKey);
+   return NULL;
+}
+
+static PK11SymKey *
+pk11_PubDeriveECKeyWithKDF(
+		    SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
+		    PRBool isSender, SECItem *randomA, SECItem *randomB,
+		    CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
+		    CK_ATTRIBUTE_TYPE operation, int keySize,
+		    CK_ULONG kdf, SECItem *sharedData, void *wincx)
+{
+    PK11SlotInfo           *slot            = privKey->pkcs11Slot;
+    PK11SymKey             *symKey;
+    CK_MECHANISM            mechanism;
+    CK_RV                   crv;
+    CK_BBOOL                cktrue          = CK_TRUE;
+    CK_OBJECT_CLASS         keyClass        = CKO_SECRET_KEY;
+    CK_KEY_TYPE             keyType         = CKK_GENERIC_SECRET;
+    CK_ULONG                key_size        = 0;
+    CK_ATTRIBUTE            keyTemplate[4];
+    int                     templateCount;
+    CK_ATTRIBUTE           *attrs           = keyTemplate;
+    CK_ECDH1_DERIVE_PARAMS *mechParams      = NULL;
+
+    if (pubKey->keyType != ecKey) {
+	PORT_SetError(SEC_ERROR_BAD_KEY);
+	return NULL;
+    }
+    if ((kdf < CKD_NULL) || (kdf > CKD_SHA1_KDF)) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return NULL;
+    }
+
+    /* get our key Structure */
+    symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
+    if (symKey == NULL) {
+	return NULL;
+    }
+
+    symKey->origin = PK11_OriginDerive;
+
+    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));     attrs++;
+    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));    attrs++;
+    PK11_SETATTRS(attrs, operation, &cktrue, 1);                      attrs++;
+    PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); attrs++;
+    templateCount =  attrs - keyTemplate;
+    PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
+
+    keyType = PK11_GetKeyType(target,keySize);
+    key_size = keySize;
+    if (key_size == 0) {
+	if (pk11_GetPredefinedKeyLength(keyType)) {
+	    templateCount --;
+	} else {
+	    /* sigh, some tokens can't figure this out and require
+	     * CKA_VALUE_LEN to be set */
+	    switch (kdf) {
+	    case CKD_NULL:
+		key_size = (pubKey->u.ec.publicValue.len-1)/2;
+		break;
+	    case CKD_SHA1_KDF:
+		key_size = SHA1_LENGTH;
+		break;
+	    default:
+		PORT_Assert(!"Invalid CKD");
+		PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+		return NULL;
+	    }
+	}
+    }
+    symKey->size = key_size;
+
+    mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
+    if (!mechParams) {
+	PK11_FreeSymKey(symKey);
+	return NULL;
+    }
+    mechParams->kdf = kdf;
+    if (sharedData == NULL) {
+	mechParams->ulSharedDataLen = 0;
+	mechParams->pSharedData     = NULL;
+    } else {
+	mechParams->ulSharedDataLen = sharedData->len;
+	mechParams->pSharedData     = sharedData->data;
+    }
+    mechParams->ulPublicDataLen =  pubKey->u.ec.publicValue.len;
+    mechParams->pPublicData =  pubKey->u.ec.publicValue.data;
+
+    mechanism.mechanism      = derive;
+    mechanism.pParameter     = mechParams;
+    mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
+
+    pk11_EnterKeyMonitor(symKey);
+    crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism, 
+    	privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
+    pk11_ExitKeyMonitor(symKey);
+
+    /* old PKCS #11 spec was ambiguous on what needed to be passed,
+     * try this again with and encoded public key */
+    if (crv != CKR_OK) {
+	SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
+		&pubKey->u.ec.publicValue,
+		SEC_ASN1_GET(SEC_OctetStringTemplate));
+	if (pubValue == NULL) {
+	    goto loser;
+	}
+	mechParams->ulPublicDataLen =  pubValue->len;
+	mechParams->pPublicData =  pubValue->data;
+
+	pk11_EnterKeyMonitor(symKey);
+	crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, 
+	    &mechanism, privKey->pkcs11ID, keyTemplate, 
+	    templateCount, &symKey->objectID);
+	pk11_ExitKeyMonitor(symKey);
+
+	SECITEM_FreeItem(pubValue,PR_TRUE);
+    }
+
+loser:
+    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
+
+    if (crv != CKR_OK) {
+	PK11_FreeSymKey(symKey);
+	symKey = NULL;
+	PORT_SetError( PK11_MapError(crv) );
+    }
+    return symKey;
+}
+
+PK11SymKey *
+PK11_PubDeriveWithKDF(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 
+		      PRBool isSender, SECItem *randomA, SECItem *randomB, 
+		      CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
+		      CK_ATTRIBUTE_TYPE operation, int keySize,
+		      CK_ULONG kdf, SECItem *sharedData, void *wincx)
+{
+
+    switch (privKey->keyType) {
+    case rsaKey:
+    case nullKey:
+    case dsaKey:
+    case keaKey:
+    case fortezzaKey:
+    case dhKey:
+	return PK11_PubDerive(privKey, pubKey, isSender, randomA, randomB,
+		derive, target, operation, keySize, wincx);
+    case ecKey:
+	return pk11_PubDeriveECKeyWithKDF( privKey, pubKey, isSender, 
+		randomA, randomB, derive, target, operation, keySize, 
+		kdf, sharedData, wincx);
+    default: break;
+    }
+
+    return NULL;
+}
+
+/*
+ * this little function uses the Decrypt function to unwrap a key, just in
+ * case we are having problem with unwrap. NOTE: The key size may
+ * not be preserved properly for some algorithms!
+ */
+static PK11SymKey *
+pk11_HandUnwrap(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
+                CK_MECHANISM *mech, SECItem *inKey, CK_MECHANISM_TYPE target, 
+		CK_ATTRIBUTE *keyTemplate, unsigned int templateCount, 
+		int key_size, void * wincx, CK_RV *crvp, PRBool isPerm)
+{
+    CK_ULONG len;
+    SECItem outKey;
+    PK11SymKey *symKey;
+    CK_RV crv;
+    PRBool owner = PR_TRUE;
+    CK_SESSION_HANDLE session;
+
+    /* remove any VALUE_LEN parameters */
+    if (keyTemplate[templateCount-1].type == CKA_VALUE_LEN) {
+        templateCount--;
+    }
+
+    /* keys are almost always aligned, but if we get this far,
+     * we've gone above and beyond anyway... */
+    outKey.data = (unsigned char*)PORT_Alloc(inKey->len);
+    if (outKey.data == NULL) {
+	PORT_SetError( SEC_ERROR_NO_MEMORY );
+	if (crvp) *crvp = CKR_HOST_MEMORY;
+	return NULL;
+    }
+    len = inKey->len;
+
+    /* use NULL IV's for wrapping */
+    session = pk11_GetNewSession(slot,&owner);
+    if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_DecryptInit(session,mech,wrappingKey);
+    if (crv != CKR_OK) {
+	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+	pk11_CloseSession(slot,session,owner);
+	PORT_Free(outKey.data);
+	PORT_SetError( PK11_MapError(crv) );
+	if (crvp) *crvp =crv;
+	return NULL;
+    }
+    crv = PK11_GETTAB(slot)->C_Decrypt(session,inKey->data,inKey->len,
+							   outKey.data, &len);
+    if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
+    pk11_CloseSession(slot,session,owner);
+    if (crv != CKR_OK) {
+	PORT_Free(outKey.data);
+	PORT_SetError( PK11_MapError(crv) );
+	if (crvp) *crvp =crv;
+	return NULL;
+    }
+
+    outKey.len = (key_size == 0) ? len : key_size;
+    outKey.type = siBuffer;
+
+    if (PK11_DoesMechanism(slot,target)) {
+	symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap, 
+	                                    isPerm, keyTemplate, 
+					    templateCount, &outKey, wincx);
+    } else {
+	slot = PK11_GetBestSlot(target,wincx);
+	if (slot == NULL) {
+	    PORT_SetError( SEC_ERROR_NO_MODULE );
+	    PORT_Free(outKey.data);
+	    if (crvp) *crvp = CKR_DEVICE_ERROR; 
+	    return NULL;
+	}
+	symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap, 
+	                                    isPerm, keyTemplate,
+					    templateCount, &outKey, wincx);
+	PK11_FreeSlot(slot);
+    }
+    PORT_Free(outKey.data);
+
+    if (crvp) *crvp = symKey? CKR_OK : CKR_DEVICE_ERROR; 
+    return symKey;
+}
+
+/*
+ * The wrap/unwrap function is pretty much the same for private and
+ * public keys. It's just getting the Object ID and slot right. This is
+ * the combined unwrap function.
+ */
+static PK11SymKey *
+pk11_AnyUnwrapKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
+    CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey, 
+    CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize, 
+    void *wincx, CK_ATTRIBUTE *userAttr, unsigned int numAttrs, PRBool isPerm)
+{
+    PK11SymKey *    symKey;
+    SECItem *       param_free	= NULL;
+    CK_BBOOL        cktrue	= CK_TRUE; 
+    CK_OBJECT_CLASS keyClass	= CKO_SECRET_KEY;
+    CK_KEY_TYPE     keyType	= CKK_GENERIC_SECRET;
+    CK_ULONG        valueLen	= 0;
+    CK_MECHANISM    mechanism;
+    CK_SESSION_HANDLE rwsession;
+    CK_RV           crv;
+    CK_MECHANISM_INFO mechanism_info;
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    CK_ATTRIBUTE *  attrs	= keyTemplate;
+    unsigned int    templateCount;
+
+    if (numAttrs > MAX_TEMPL_ATTRS) {
+    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+    /* first copy caller attributes in. */
+    for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
+    	*attrs++ = *userAttr++;
+    }
+
+    /* We only add the following attributes to the template if the caller
+    ** didn't already supply them.
+    */
+    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
+	PK11_SETATTRS(attrs, CKA_CLASS,     &keyClass, sizeof keyClass); 
+	attrs++;
+    }
+    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
+	keyType = PK11_GetKeyType(target, keySize);
+	PK11_SETATTRS(attrs, CKA_KEY_TYPE,  &keyType,  sizeof keyType ); 
+	attrs++;
+    }
+    if ((operation != CKA_FLAGS_ONLY) &&
+	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
+	PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
+    }
+
+    /*
+     * must be last in case we need to use this template to import the key
+     */
+    if (keySize > 0 &&
+    	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
+	valueLen = (CK_ULONG)keySize;
+	PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen); 
+	attrs++;
+    }
+
+    templateCount = attrs - keyTemplate;
+    PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
+
+
+    /* find out if we can do wrap directly. Because the RSA case if *very*
+     * common, cache the results for it. */
+    if ((wrapType == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
+	mechanism_info.flags = slot->RSAInfoFlags;
+    } else {
+	if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+	crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,wrapType,
+				 &mechanism_info);
+    	if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    	if (crv != CKR_OK) {
+	     mechanism_info.flags = 0;
+    	}
+        if (wrapType == CKM_RSA_PKCS) {
+	    slot->RSAInfoFlags = mechanism_info.flags;
+	    slot->hasRSAInfo = PR_TRUE;
+	}
+    }
+
+    /* initialize the mechanism structure */
+    mechanism.mechanism = wrapType;
+    /* use NULL IV's for wrapping */
+    if (param == NULL) 
+	param = param_free = PK11_ParamFromIV(wrapType,NULL);
+    if (param) {
+	mechanism.pParameter = param->data;
+	mechanism.ulParameterLen = param->len;
+    } else {
+	mechanism.pParameter = NULL;
+	mechanism.ulParameterLen = 0;
+    }
+
+    if ((mechanism_info.flags & CKF_DECRYPT)  
+				&& !PK11_DoesMechanism(slot,target)) {
+	symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey, 
+	                         target, keyTemplate, templateCount, keySize, 
+				 wincx, &crv, isPerm);
+	if (symKey) {
+	    if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
+	    return symKey;
+	}
+	/*
+	 * if the RSA OP simply failed, don't try to unwrap again 
+	 * with this module.
+	 */
+	if (crv == CKR_DEVICE_ERROR){
+	    if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
+	    return NULL;
+	}
+	/* fall through, maybe they incorrectly set CKF_DECRYPT */
+    }
+
+    /* get our key Structure */
+    symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, wincx);
+    if (symKey == NULL) {
+	if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
+	return NULL;
+    }
+
+    symKey->size = keySize;
+    symKey->origin = PK11_OriginUnwrap;
+
+    if (isPerm) {
+	rwsession = PK11_GetRWSession(slot);
+    } else {
+        pk11_EnterKeyMonitor(symKey);
+	rwsession = symKey->session;
+    }
+    PORT_Assert(rwsession != CK_INVALID_SESSION);
+    if (rwsession == CK_INVALID_SESSION) 
+    	crv = CKR_SESSION_HANDLE_INVALID;
+    else
+	crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession,&mechanism,wrappingKey,
+		wrappedKey->data, wrappedKey->len, keyTemplate, templateCount, 
+							  &symKey->objectID);
+    if (isPerm) {
+	if (rwsession != CK_INVALID_SESSION)
+	    PK11_RestoreROSession(slot, rwsession);
+    } else {
+        pk11_ExitKeyMonitor(symKey);
+    }
+    if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
+    if (crv != CKR_OK) {
+	PK11_FreeSymKey(symKey);
+	symKey = NULL;
+	if (crv != CKR_DEVICE_ERROR) {
+	    /* try hand Unwrapping */
+	    symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey, 
+				     target, keyTemplate, templateCount,
+				     keySize, wincx, NULL, isPerm);
+	}
+   }
+
+   return symKey;
+}
+
+/* use a symetric key to unwrap another symetric key */
+PK11SymKey *
+PK11_UnwrapSymKey( PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
+                   SECItem *param, SECItem *wrappedKey, 
+		   CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+		   int keySize)
+{
+    return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
+		    wrapType, param, wrappedKey, target, operation, keySize, 
+		    wrappingKey->cx, NULL, 0, PR_FALSE);
+}
+
+/* use a symetric key to unwrap another symetric key */
+PK11SymKey *
+PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
+                   SECItem *param, SECItem *wrappedKey, 
+		   CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+		   int keySize, CK_FLAGS flags)
+{
+    CK_BBOOL        ckTrue	= CK_TRUE; 
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    unsigned int    templateCount;
+
+    templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
+    return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
+		    wrapType, param, wrappedKey, target, operation, keySize, 
+		    wrappingKey->cx, keyTemplate, templateCount, PR_FALSE);
+}
+
+PK11SymKey *
+PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, 
+		   CK_MECHANISM_TYPE wrapType,
+                   SECItem *param, SECItem *wrappedKey, 
+		   CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
+		   int keySize, CK_FLAGS flags, PRBool isPerm)
+{
+    CK_BBOOL        cktrue	= CK_TRUE; 
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    CK_ATTRIBUTE    *attrs;
+    unsigned int    templateCount;
+
+    attrs = keyTemplate;
+    if (isPerm) {
+        PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
+    }
+    templateCount = attrs-keyTemplate;
+    templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
+
+    return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
+		    wrapType, param, wrappedKey, target, operation, keySize, 
+		    wrappingKey->cx, keyTemplate, templateCount, isPerm);
+}
+
+
+/* unwrap a symetric key with a private key. */
+PK11SymKey *
+PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
+	  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
+{
+    CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
+    PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
+
+    if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
+	PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
+    }
+    
+    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
+	wrapType, NULL, wrappedKey, target, operation, keySize, 
+	wrappingKey->wincx, NULL, 0, PR_FALSE);
+}
+
+/* unwrap a symetric key with a private key. */
+PK11SymKey *
+PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey, 
+	  SECItem *wrappedKey, CK_MECHANISM_TYPE target, 
+	  CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags)
+{
+    CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
+    CK_BBOOL        ckTrue	= CK_TRUE; 
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    unsigned int    templateCount;
+    PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
+
+    templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
+
+    if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
+	PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
+    }
+    
+    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
+	wrapType, NULL, wrappedKey, target, operation, keySize, 
+	wrappingKey->wincx, keyTemplate, templateCount, PR_FALSE);
+}
+
+PK11SymKey *
+PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, 
+	  SECItem *wrappedKey, CK_MECHANISM_TYPE target, 
+	  CK_ATTRIBUTE_TYPE operation, int keySize,
+	  CK_FLAGS flags, PRBool isPerm)
+{
+    CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
+    CK_BBOOL        cktrue	= CK_TRUE; 
+    CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
+    CK_ATTRIBUTE    *attrs;
+    unsigned int    templateCount;
+    PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
+
+    attrs = keyTemplate;
+    if (isPerm) {
+        PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
+    }
+    templateCount = attrs-keyTemplate;
+
+    templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
+
+    if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
+	PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
+    }
+    
+    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
+	wrapType, NULL, wrappedKey, target, operation, keySize, 
+	wrappingKey->wincx, keyTemplate, templateCount, isPerm);
+}
+
+PK11SymKey*
+PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech)
+{
+    CK_RV crv;
+    CK_ATTRIBUTE setTemplate;
+    CK_BBOOL ckTrue = CK_TRUE; 
+    PK11SlotInfo *slot = originalKey->slot;
+
+    /* first just try to set this key up for signing */
+    PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue));
+    pk11_EnterKeyMonitor(originalKey);
+    crv = PK11_GETTAB(slot)-> C_SetAttributeValue(originalKey->session, 
+				originalKey->objectID, &setTemplate, 1);
+    pk11_ExitKeyMonitor(originalKey);
+    if (crv == CKR_OK) {
+	return PK11_ReferenceSymKey(originalKey);
+    }
+
+    /* nope, doesn't like it, use the pk11 copy object command */
+    return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey);
+}
+    
+void   
+PK11_SetFortezzaHack(PK11SymKey *symKey) { 
+   symKey->origin = PK11_OriginFortezzaHack;
+}
+
+/*
+ * This is required to allow FORTEZZA_NULL and FORTEZZA_RC4
+ * working. This function simply gets a valid IV for the keys.
+ */
+SECStatus
+PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len)
+{
+    CK_MECHANISM mech_info;
+    CK_ULONG count = 0;
+    CK_RV crv;
+    SECStatus rv = SECFailure;
+
+    mech_info.mechanism = CKM_SKIPJACK_CBC64;
+    mech_info.pParameter = iv;
+    mech_info.ulParameterLen = len;
+
+    /* generate the IV for fortezza */
+    PK11_EnterSlotMonitor(symKey->slot);
+    crv=PK11_GETTAB(symKey->slot)->C_EncryptInit(symKey->slot->session,
+				&mech_info, symKey->objectID);
+    if (crv == CKR_OK) {
+	PK11_GETTAB(symKey->slot)->C_EncryptFinal(symKey->slot->session, 
+								NULL, &count);
+	rv = SECSuccess;
+    }
+    PK11_ExitSlotMonitor(symKey->slot);
+    return rv;
+}
+
+CK_OBJECT_HANDLE
+PK11_GetSymKeyHandle(PK11SymKey *symKey)
+{
+    return symKey->objectID;
+}
+
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11slot.c b/mozilla/security/nss/lib/pk11wrap/pk11slot.c
new file mode 100644
index 0000000..dc5483e
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11slot.c
@@ -0,0 +1,2295 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * Deal with PKCS #11 Slots.
+ */
+#include "seccomon.h"
+#include "secmod.h"
+#include "nssilock.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11t.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "secerr.h"
+
+#include "dev.h" 
+#include "dev3hack.h" 
+#include "pkim.h"
+
+
+/*************************************************************
+ * local static and global data
+ *************************************************************/
+
+/*
+ * This array helps parsing between names, mechanisms, and flags.
+ * to make the config files understand more entries, add them
+ * to this table. (NOTE: we need function to export this table and it's size)
+ */
+PK11DefaultArrayEntry PK11_DefaultArray[] = {
+	{ "RSA", SECMOD_RSA_FLAG, CKM_RSA_PKCS },
+	{ "DSA", SECMOD_DSA_FLAG, CKM_DSA },
+	{ "DH", SECMOD_DH_FLAG, CKM_DH_PKCS_DERIVE },
+	{ "RC2", SECMOD_RC2_FLAG, CKM_RC2_CBC },
+	{ "RC4", SECMOD_RC4_FLAG, CKM_RC4 },
+	{ "DES", SECMOD_DES_FLAG, CKM_DES_CBC },
+	{ "AES", SECMOD_AES_FLAG, CKM_AES_CBC },
+	{ "Camellia", SECMOD_CAMELLIA_FLAG, CKM_CAMELLIA_CBC },
+	{ "SEED", SECMOD_SEED_FLAG, CKM_SEED_CBC },
+	{ "RC5", SECMOD_RC5_FLAG, CKM_RC5_CBC },
+	{ "SHA-1", SECMOD_SHA1_FLAG, CKM_SHA_1 },
+	{ "SHA256", SECMOD_SHA256_FLAG, CKM_SHA256 },
+/*	{ "SHA384", SECMOD_SHA512_FLAG, CKM_SHA384 }, */
+	{ "SHA512", SECMOD_SHA512_FLAG, CKM_SHA512 },
+	{ "MD5", SECMOD_MD5_FLAG, CKM_MD5 },
+	{ "MD2", SECMOD_MD2_FLAG, CKM_MD2 },
+	{ "SSL", SECMOD_SSL_FLAG, CKM_SSL3_PRE_MASTER_KEY_GEN },
+	{ "TLS", SECMOD_TLS_FLAG, CKM_TLS_MASTER_KEY_DERIVE },
+	{ "SKIPJACK", SECMOD_FORTEZZA_FLAG, CKM_SKIPJACK_CBC64 },
+	{ "Publicly-readable certs", SECMOD_FRIENDLY_FLAG, CKM_INVALID_MECHANISM },
+	{ "Random Num Generator", SECMOD_RANDOM_FLAG, CKM_FAKE_RANDOM },
+};
+const int num_pk11_default_mechanisms = 
+                sizeof(PK11_DefaultArray) / sizeof(PK11_DefaultArray[0]);
+
+PK11DefaultArrayEntry *
+PK11_GetDefaultArray(int *size)
+{
+    if (size) {
+	*size = num_pk11_default_mechanisms;
+    }
+    return PK11_DefaultArray;
+}
+
+/*
+ * These  slotlists are lists of modules which provide default support for
+ *  a given algorithm or mechanism.
+ */
+static PK11SlotList 
+    pk11_seedSlotList,
+    pk11_camelliaSlotList,
+    pk11_aesSlotList,
+    pk11_desSlotList,
+    pk11_rc4SlotList,
+    pk11_rc2SlotList,
+    pk11_rc5SlotList,
+    pk11_sha1SlotList,
+    pk11_md5SlotList,
+    pk11_md2SlotList,
+    pk11_rsaSlotList,
+    pk11_dsaSlotList,
+    pk11_dhSlotList,
+    pk11_ecSlotList,
+    pk11_ideaSlotList,
+    pk11_sslSlotList,
+    pk11_tlsSlotList,
+    pk11_randomSlotList,
+    pk11_sha256SlotList,
+    pk11_sha512SlotList;	/* slots do SHA512 and SHA384 */
+
+/************************************************************
+ * Generic Slot List and Slot List element manipulations
+ ************************************************************/
+
+/*
+ * allocate a new list 
+ */
+PK11SlotList *
+PK11_NewSlotList(void)
+{
+    PK11SlotList *list;
+ 
+    list = (PK11SlotList *)PORT_Alloc(sizeof(PK11SlotList));
+    if (list == NULL) return NULL;
+    list->head = NULL;
+    list->tail = NULL;
+    list->lock = PZ_NewLock(nssILockList);
+    if (list->lock == NULL) {
+	PORT_Free(list);
+	return NULL;
+    }
+
+    return list;
+}
+
+/*
+ * free a list element when all the references go away.
+ */
+SECStatus
+PK11_FreeSlotListElement(PK11SlotList *list, PK11SlotListElement *le)
+{
+    PRBool freeit = PR_FALSE;
+
+    if (list == NULL || le == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    PZ_Lock(list->lock);
+    if (le->refCount-- == 1) {
+	freeit = PR_TRUE;
+    }
+    PZ_Unlock(list->lock);
+    if (freeit) {
+    	PK11_FreeSlot(le->slot);
+	PORT_Free(le);
+    }
+    return SECSuccess;
+}
+
+static void
+pk11_FreeSlotListStatic(PK11SlotList *list)
+{
+    PK11SlotListElement *le, *next ;
+    if (list == NULL) return;
+
+    for (le = list->head ; le; le = next) {
+	next = le->next;
+	PK11_FreeSlotListElement(list,le);
+    }
+    if (list->lock) {
+    	PZ_DestroyLock(list->lock);
+    }
+    list->lock = NULL;
+    list->head = NULL;
+}
+
+/*
+ * if we are freeing the list, we must be the only ones with a pointer
+ * to the list.
+ */
+void
+PK11_FreeSlotList(PK11SlotList *list)
+{
+    pk11_FreeSlotListStatic(list);
+    PORT_Free(list);
+}
+
+/*
+ * add a slot to a list
+ */
+SECStatus
+PK11_AddSlotToList(PK11SlotList *list,PK11SlotInfo *slot)
+{
+    PK11SlotListElement *le;
+
+    le = (PK11SlotListElement *) PORT_Alloc(sizeof(PK11SlotListElement));
+    if (le == NULL) return SECFailure;
+
+    le->slot = PK11_ReferenceSlot(slot);
+    le->prev = NULL;
+    le->refCount = 1;
+    PZ_Lock(list->lock);
+    if (list->head) list->head->prev = le; else list->tail = le;
+    le->next = list->head;
+    list->head = le;
+    PZ_Unlock(list->lock);
+
+    return SECSuccess;
+}
+
+/*
+ * remove a slot entry from the list
+ */
+SECStatus
+PK11_DeleteSlotFromList(PK11SlotList *list,PK11SlotListElement *le)
+{
+    PZ_Lock(list->lock);
+    if (le->prev) le->prev->next = le->next; else list->head = le->next;
+    if (le->next) le->next->prev = le->prev; else list->tail = le->prev;
+    le->next = le->prev = NULL;
+    PZ_Unlock(list->lock);
+    PK11_FreeSlotListElement(list,le);
+    return SECSuccess;
+}
+
+/*
+ * Move a list to the end of the target list. NOTE: There is no locking
+ * here... This assumes BOTH lists are private copy lists.
+ */
+SECStatus
+PK11_MoveListToList(PK11SlotList *target,PK11SlotList *src)
+{
+    if (src->head == NULL) return SECSuccess;
+
+    if (target->tail == NULL) {
+	target->head = src->head;
+    } else {
+	target->tail->next = src->head;
+    }
+    src->head->prev = target->tail;
+    target->tail = src->tail;
+    src->head = src->tail = NULL;
+    return SECSuccess;
+}
+
+/*
+ * get an element from the list with a reference. You must own the list.
+ */
+PK11SlotListElement *
+PK11_GetFirstRef(PK11SlotList *list)
+{
+    PK11SlotListElement *le;
+
+    le = list->head;
+    if (le != NULL) (le)->refCount++;
+    return le;
+}
+
+/*
+ * get the next element from the list with a reference. You must own the list.
+ */
+PK11SlotListElement *
+PK11_GetNextRef(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
+{
+    PK11SlotListElement *new_le;
+    new_le = le->next;
+    if (new_le) new_le->refCount++;
+    PK11_FreeSlotListElement(list,le);
+    return new_le;
+}
+
+/*
+ * get an element safely from the list. This just makes sure that if
+ * this element is not deleted while we deal with it.
+ */
+PK11SlotListElement *
+PK11_GetFirstSafe(PK11SlotList *list)
+{
+    PK11SlotListElement *le;
+
+    PZ_Lock(list->lock);
+    le = list->head;
+    if (le != NULL) (le)->refCount++;
+    PZ_Unlock(list->lock);
+    return le;
+}
+
+/*
+ * NOTE: if this element gets deleted, we can no longer safely traverse using
+ * it's pointers. We can either terminate the loop, or restart from the
+ * beginning. This is controlled by the restart option.
+ */
+PK11SlotListElement *
+PK11_GetNextSafe(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
+{
+    PK11SlotListElement *new_le;
+    PZ_Lock(list->lock);
+    new_le = le->next;
+    if (le->next == NULL) {
+	/* if the prev and next fields are NULL then either this element
+	 * has been removed and we need to walk the list again (if restart
+	 * is true) or this was the only element on the list */
+	if ((le->prev == NULL) && restart &&  (list->head != le)) {
+	    new_le = list->head;
+	}
+    }
+    if (new_le) new_le->refCount++;
+    PZ_Unlock(list->lock);
+    PK11_FreeSlotListElement(list,le);
+    return new_le;
+}
+
+
+/*
+ * Find the element that holds this slot
+ */
+PK11SlotListElement *
+PK11_FindSlotElement(PK11SlotList *list,PK11SlotInfo *slot)
+{
+    PK11SlotListElement *le;
+
+    for (le = PK11_GetFirstSafe(list); le;
+			 	le = PK11_GetNextSafe(list,le,PR_TRUE)) {
+	if (le->slot == slot) return le;
+    }
+    return NULL;
+}
+
+/************************************************************
+ * Generic Slot Utilities
+ ************************************************************/
+/*
+ * Create a new slot structure
+ */
+PK11SlotInfo *
+PK11_NewSlotInfo(SECMODModule *mod)
+{
+    PK11SlotInfo *slot;
+
+    slot = (PK11SlotInfo *)PORT_Alloc(sizeof(PK11SlotInfo));
+    if (slot == NULL) return slot;
+
+    slot->sessionLock = mod->isThreadSafe ?
+	PZ_NewLock(nssILockSession) : mod->refLock;
+    if (slot->sessionLock == NULL) {
+	PORT_Free(slot);
+	return NULL;
+    }
+    slot->freeListLock = PZ_NewLock(nssILockFreelist);
+    if (slot->freeListLock == NULL) {
+	if (mod->isThreadSafe) {
+	    PZ_DestroyLock(slot->sessionLock);
+	}
+	PORT_Free(slot);
+	return NULL;
+    }
+    slot->freeSymKeysWithSessionHead = NULL;
+    slot->freeSymKeysHead = NULL;
+    slot->keyCount = 0;
+    slot->maxKeyCount = 0;
+    slot->functionList = NULL;
+    slot->needTest = PR_TRUE;
+    slot->isPerm = PR_FALSE;
+    slot->isHW = PR_FALSE;
+    slot->isInternal = PR_FALSE;
+    slot->isThreadSafe = PR_FALSE;
+    slot->disabled = PR_FALSE;
+    slot->series = 1;
+    slot->wrapKey = 0;
+    slot->wrapMechanism = CKM_INVALID_MECHANISM;
+    slot->refKeys[0] = CK_INVALID_HANDLE;
+    slot->reason = PK11_DIS_NONE;
+    slot->readOnly = PR_TRUE;
+    slot->needLogin = PR_FALSE;
+    slot->hasRandom = PR_FALSE;
+    slot->defRWSession = PR_FALSE;
+    slot->protectedAuthPath = PR_FALSE;
+    slot->flags = 0;
+    slot->session = CK_INVALID_SESSION;
+    slot->slotID = 0;
+    slot->defaultFlags = 0;
+    slot->refCount = 1;
+    slot->askpw = 0;
+    slot->timeout = 0;
+    slot->mechanismList = NULL;
+    slot->mechanismCount = 0;
+    slot->cert_array = NULL;
+    slot->cert_count = 0;
+    slot->slot_name[0] = 0;
+    slot->token_name[0] = 0;
+    PORT_Memset(slot->serial,' ',sizeof(slot->serial));
+    slot->module = NULL;
+    slot->authTransact = 0;
+    slot->authTime = LL_ZERO;
+    slot->minPassword = 0;
+    slot->maxPassword = 0;
+    slot->hasRootCerts = PR_FALSE;
+    slot->nssToken = NULL;
+    return slot;
+}
+    
+/* create a new reference to a slot so it doesn't go away */
+PK11SlotInfo *
+PK11_ReferenceSlot(PK11SlotInfo *slot)
+{
+    PR_AtomicIncrement(&slot->refCount);
+    return slot;
+}
+
+/* Destroy all info on a slot we have built up */
+void
+PK11_DestroySlot(PK11SlotInfo *slot)
+{
+   /* free up the cached keys and sessions */
+   PK11_CleanKeyList(slot);
+   
+   /* free up all the sessions on this slot */
+   if (slot->functionList) {
+	PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
+   }
+
+   if (slot->mechanismList) {
+	PORT_Free(slot->mechanismList);
+   }
+   if (slot->isThreadSafe && slot->sessionLock) {
+	PZ_DestroyLock(slot->sessionLock);
+   }
+   slot->sessionLock = NULL;
+   if (slot->freeListLock) {
+	PZ_DestroyLock(slot->freeListLock);
+	slot->freeListLock = NULL;
+   }
+
+   /* finally Tell our parent module that we've gone away so it can unload */
+   if (slot->module) {
+	SECMOD_SlotDestroyModule(slot->module,PR_TRUE);
+   }
+
+   /* ok, well not quit finally... now we free the memory */
+   PORT_Free(slot);
+}
+
+
+/* We're all done with the slot, free it */
+void
+PK11_FreeSlot(PK11SlotInfo *slot)
+{
+    if (PR_AtomicDecrement(&slot->refCount) == 0) {
+	PK11_DestroySlot(slot);
+    }
+}
+
+void
+PK11_EnterSlotMonitor(PK11SlotInfo *slot) {
+    PZ_Lock(slot->sessionLock);
+}
+
+void
+PK11_ExitSlotMonitor(PK11SlotInfo *slot) {
+    PZ_Unlock(slot->sessionLock);
+}
+
+/***********************************************************
+ * Functions to find specific slots.
+ ***********************************************************/
+PRBool
+SECMOD_HasRootCerts(void)
+{
+   SECMODModuleList *mlp;
+   SECMODModuleList *modules;
+   SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+   int i;
+   PRBool found = PR_FALSE;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return found;
+    }
+
+   /* work through all the slots */
+   SECMOD_GetReadLock(moduleLock);
+   modules = SECMOD_GetDefaultModuleList();
+   for(mlp = modules; mlp != NULL; mlp = mlp->next) {
+	for (i=0; i < mlp->module->slotCount; i++) {
+	    PK11SlotInfo *tmpSlot = mlp->module->slots[i];
+	    if (PK11_IsPresent(tmpSlot)) {
+		if (tmpSlot->hasRootCerts) {
+		    found = PR_TRUE;
+		    break;
+		}
+	    }
+	}
+	if (found) break;
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    return found;
+}
+
+/***********************************************************
+ * Functions to find specific slots.
+ ***********************************************************/
+PK11SlotList *
+PK11_FindSlotsByNames(const char *dllName, const char* slotName,
+                        const char* tokenName, PRBool presentOnly)
+{
+    SECMODModuleList *mlp;
+    SECMODModuleList *modules;
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+    int i;
+    PK11SlotList* slotList = NULL;
+    PRUint32 slotcount = 0;
+    SECStatus rv = SECSuccess;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return slotList;
+    }
+
+    slotList = PK11_NewSlotList();
+    if (!slotList) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return slotList;
+    }
+
+    if ( ((NULL == dllName) || (0 == *dllName)) &&
+        ((NULL == slotName) || (0 == *slotName)) &&
+        ((NULL == tokenName) || (0 == *tokenName)) ) {
+        /* default to softoken */
+        PK11_AddSlotToList(slotList, PK11_GetInternalKeySlot());
+        return slotList;
+    }
+
+    /* work through all the slots */
+    SECMOD_GetReadLock(moduleLock);
+    modules = SECMOD_GetDefaultModuleList();
+    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
+        PORT_Assert(mlp->module);
+        if (!mlp->module) {
+            rv = SECFailure;
+            break;
+        }
+        if ((!dllName) || (mlp->module->dllName &&
+            (0 == PORT_Strcmp(mlp->module->dllName, dllName)))) {
+            for (i=0; i < mlp->module->slotCount; i++) {
+                PK11SlotInfo *tmpSlot = (mlp->module->slots?mlp->module->slots[i]:NULL);
+                PORT_Assert(tmpSlot);
+                if (!tmpSlot) {
+                    rv = SECFailure;
+                    break;
+                }
+                if ((PR_FALSE == presentOnly || PK11_IsPresent(tmpSlot)) &&
+                    ( (!tokenName) || (tmpSlot->token_name &&
+                    (0==PORT_Strcmp(tmpSlot->token_name, tokenName)))) &&
+                    ( (!slotName) || (tmpSlot->slot_name &&
+                    (0==PORT_Strcmp(tmpSlot->slot_name, slotName)))) ) {
+                    if (tmpSlot) {
+                        PK11_AddSlotToList(slotList, tmpSlot);
+                        slotcount++;
+                    }
+                }
+            }
+        }
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    if ( (0 == slotcount) || (SECFailure == rv) ) {
+        PORT_SetError(SEC_ERROR_NO_TOKEN);
+        PK11_FreeSlotList(slotList);
+        slotList = NULL;
+    }
+
+    if (SECFailure == rv) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+    }
+
+    return slotList;
+}
+
+PK11SlotInfo *
+PK11_FindSlotByName(const char *name)
+{
+   SECMODModuleList *mlp;
+   SECMODModuleList *modules;
+   SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+   int i;
+   PK11SlotInfo *slot = NULL;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return slot;
+    }
+   if ((name == NULL) || (*name == 0)) {
+	return PK11_GetInternalKeySlot();
+   }
+
+   /* work through all the slots */
+   SECMOD_GetReadLock(moduleLock);
+   modules = SECMOD_GetDefaultModuleList();
+   for(mlp = modules; mlp != NULL; mlp = mlp->next) {
+	for (i=0; i < mlp->module->slotCount; i++) {
+	    PK11SlotInfo *tmpSlot = mlp->module->slots[i];
+	    if (PK11_IsPresent(tmpSlot)) {
+		if (PORT_Strcmp(tmpSlot->token_name,name) == 0) {
+		    slot = PK11_ReferenceSlot(tmpSlot);
+		    break;
+		}
+	    }
+	}
+	if (slot != NULL) break;
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    if (slot == NULL) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+    }
+
+    return slot;
+}
+
+
+PK11SlotInfo *
+PK11_FindSlotBySerial(char *serial)
+{
+   SECMODModuleList *mlp;
+   SECMODModuleList *modules;
+   SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+   int i;
+   PK11SlotInfo *slot = NULL;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return slot;
+    }
+   /* work through all the slots */
+   SECMOD_GetReadLock(moduleLock);
+   modules = SECMOD_GetDefaultModuleList();
+   for(mlp = modules; mlp != NULL; mlp = mlp->next) {
+	for (i=0; i < mlp->module->slotCount; i++) {
+	    PK11SlotInfo *tmpSlot = mlp->module->slots[i];
+	    if (PK11_IsPresent(tmpSlot)) {
+		if (PORT_Memcmp(tmpSlot->serial,serial,
+					sizeof(tmpSlot->serial)) == 0) {
+		    slot = PK11_ReferenceSlot(tmpSlot);
+		    break;
+		}
+	    }
+	}
+	if (slot != NULL) break;
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    if (slot == NULL) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+    }
+
+    return slot;
+}
+
+/*
+ * notification stub. If we ever get interested in any events that
+ * the pkcs11 functions may pass back to use, we can catch them here...
+ * currently pdata is a slotinfo structure.
+ */
+CK_RV pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event,
+							 CK_VOID_PTR pdata)
+{
+    return CKR_OK;
+}
+
+/*
+ * grab a new RW session
+ * !!! has a side effect of grabbing the Monitor if either the slot's default
+ * session is RW or the slot is not thread safe. Monitor is release in function
+ * below
+ */
+CK_SESSION_HANDLE PK11_GetRWSession(PK11SlotInfo *slot)
+{
+    CK_SESSION_HANDLE rwsession;
+    CK_RV crv;
+    PRBool haveMonitor = PR_FALSE;
+
+    if (!slot->isThreadSafe || slot->defRWSession) {
+    	PK11_EnterSlotMonitor(slot);
+	haveMonitor = PR_TRUE;
+    }
+    if (slot->defRWSession) {
+	PORT_Assert(slot->session != CK_INVALID_SESSION);
+	if (slot->session != CK_INVALID_SESSION) 
+	    return slot->session;
+    }
+
+    crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
+				CKF_RW_SESSION|CKF_SERIAL_SESSION,
+				  	  slot, pk11_notify,&rwsession);
+    PORT_Assert(rwsession != CK_INVALID_SESSION || crv != CKR_OK);
+    if (crv != CKR_OK || rwsession == CK_INVALID_SESSION) {
+	if (crv == CKR_OK) 
+	    crv = CKR_DEVICE_ERROR;
+	if (haveMonitor)
+	    PK11_ExitSlotMonitor(slot);
+	PORT_SetError(PK11_MapError(crv));
+	return CK_INVALID_SESSION;
+    }
+    if (slot->defRWSession) { /* we have the monitor */
+    	slot->session = rwsession;
+    }
+    return rwsession;
+}
+
+PRBool
+PK11_RWSessionHasLock(PK11SlotInfo *slot,CK_SESSION_HANDLE session_handle) 
+{
+    PRBool hasLock;
+    hasLock = (PRBool)(!slot->isThreadSafe || 
+    	      (slot->defRWSession && slot->session != CK_INVALID_SESSION));
+    return hasLock;
+}
+
+static PRBool
+pk11_RWSessionIsDefault(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
+{
+    PRBool isDefault;
+    isDefault = (PRBool)(slot->session == rwsession &&
+    	                 slot->defRWSession && 
+			 slot->session != CK_INVALID_SESSION);
+    return isDefault;
+}
+
+/*
+ * close the rwsession and restore our readonly session
+ * !!! has a side effect of releasing the Monitor if either the slot's default
+ * session is RW or the slot is not thread safe.
+ */
+void
+PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
+{
+    PORT_Assert(rwsession != CK_INVALID_SESSION);
+    if (rwsession != CK_INVALID_SESSION) {
+    	PRBool doExit = PK11_RWSessionHasLock(slot, rwsession);
+	if (!pk11_RWSessionIsDefault(slot, rwsession))
+	    PK11_GETTAB(slot)->C_CloseSession(rwsession);
+	if (doExit)
+	    PK11_ExitSlotMonitor(slot);
+    }
+}
+
+/************************************************************
+ * Manage the built-In Slot Lists
+ ************************************************************/
+
+/* Init the static built int slot list (should actually integrate
+ * with PK11_NewSlotList */
+static void
+pk11_InitSlotListStatic(PK11SlotList *list)
+{
+    list->lock = PZ_NewLock(nssILockList);
+    list->head = NULL;
+}
+
+
+/* initialize the system slotlists */
+SECStatus
+PK11_InitSlotLists(void)
+{
+    pk11_InitSlotListStatic(&pk11_seedSlotList);
+    pk11_InitSlotListStatic(&pk11_camelliaSlotList);
+    pk11_InitSlotListStatic(&pk11_aesSlotList);
+    pk11_InitSlotListStatic(&pk11_desSlotList);
+    pk11_InitSlotListStatic(&pk11_rc4SlotList);
+    pk11_InitSlotListStatic(&pk11_rc2SlotList);
+    pk11_InitSlotListStatic(&pk11_rc5SlotList);
+    pk11_InitSlotListStatic(&pk11_md5SlotList);
+    pk11_InitSlotListStatic(&pk11_md2SlotList);
+    pk11_InitSlotListStatic(&pk11_sha1SlotList);
+    pk11_InitSlotListStatic(&pk11_rsaSlotList);
+    pk11_InitSlotListStatic(&pk11_dsaSlotList);
+    pk11_InitSlotListStatic(&pk11_dhSlotList);
+    pk11_InitSlotListStatic(&pk11_ecSlotList);
+    pk11_InitSlotListStatic(&pk11_ideaSlotList);
+    pk11_InitSlotListStatic(&pk11_sslSlotList);
+    pk11_InitSlotListStatic(&pk11_tlsSlotList);
+    pk11_InitSlotListStatic(&pk11_randomSlotList);
+    pk11_InitSlotListStatic(&pk11_sha256SlotList);
+    pk11_InitSlotListStatic(&pk11_sha512SlotList);
+    return SECSuccess;
+}
+
+void
+PK11_DestroySlotLists(void)
+{
+    pk11_FreeSlotListStatic(&pk11_seedSlotList);
+    pk11_FreeSlotListStatic(&pk11_camelliaSlotList);
+    pk11_FreeSlotListStatic(&pk11_aesSlotList);
+    pk11_FreeSlotListStatic(&pk11_desSlotList);
+    pk11_FreeSlotListStatic(&pk11_rc4SlotList);
+    pk11_FreeSlotListStatic(&pk11_rc2SlotList);
+    pk11_FreeSlotListStatic(&pk11_rc5SlotList);
+    pk11_FreeSlotListStatic(&pk11_md5SlotList);
+    pk11_FreeSlotListStatic(&pk11_md2SlotList);
+    pk11_FreeSlotListStatic(&pk11_sha1SlotList);
+    pk11_FreeSlotListStatic(&pk11_rsaSlotList);
+    pk11_FreeSlotListStatic(&pk11_dsaSlotList);
+    pk11_FreeSlotListStatic(&pk11_dhSlotList);
+    pk11_FreeSlotListStatic(&pk11_ecSlotList);
+    pk11_FreeSlotListStatic(&pk11_ideaSlotList);
+    pk11_FreeSlotListStatic(&pk11_sslSlotList);
+    pk11_FreeSlotListStatic(&pk11_tlsSlotList);
+    pk11_FreeSlotListStatic(&pk11_randomSlotList);
+    pk11_FreeSlotListStatic(&pk11_sha256SlotList);
+    pk11_FreeSlotListStatic(&pk11_sha512SlotList);
+    return;
+}
+
+/* return a system slot list based on mechanism */
+PK11SlotList *
+PK11_GetSlotList(CK_MECHANISM_TYPE type)
+{
+/* XXX a workaround for Bugzilla bug #55267 */
+#if defined(HPUX) && defined(__LP64__)
+    if (CKM_INVALID_MECHANISM == type)
+        return NULL;
+#endif
+    switch (type) {
+    case CKM_SEED_CBC:
+    case CKM_SEED_ECB:
+	return &pk11_seedSlotList;
+    case CKM_CAMELLIA_CBC:
+    case CKM_CAMELLIA_ECB:
+	return &pk11_camelliaSlotList;
+    case CKM_AES_CBC:
+    case CKM_AES_ECB:
+	return &pk11_aesSlotList;
+    case CKM_DES_CBC:
+    case CKM_DES_ECB:
+    case CKM_DES3_ECB:
+    case CKM_DES3_CBC:
+	return &pk11_desSlotList;
+    case CKM_RC4:
+	return &pk11_rc4SlotList;
+    case CKM_RC5_CBC:
+	return &pk11_rc5SlotList;
+    case CKM_SHA_1:
+	return &pk11_sha1SlotList;
+    case CKM_SHA256:
+	return &pk11_sha256SlotList;
+    case CKM_SHA384:
+    case CKM_SHA512:
+	return &pk11_sha512SlotList;
+    case CKM_MD5:
+	return &pk11_md5SlotList;
+    case CKM_MD2:
+	return &pk11_md2SlotList;
+    case CKM_RC2_ECB:
+    case CKM_RC2_CBC:
+	return &pk11_rc2SlotList;
+    case CKM_RSA_PKCS:
+    case CKM_RSA_PKCS_KEY_PAIR_GEN:
+    case CKM_RSA_X_509:
+	return &pk11_rsaSlotList;
+    case CKM_DSA:
+	return &pk11_dsaSlotList;
+    case CKM_DH_PKCS_KEY_PAIR_GEN:
+    case CKM_DH_PKCS_DERIVE:
+	return &pk11_dhSlotList;
+    case CKM_ECDSA:
+    case CKM_ECDSA_SHA1:
+    case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
+    case CKM_ECDH1_DERIVE:
+	return &pk11_ecSlotList;
+    case CKM_SSL3_PRE_MASTER_KEY_GEN:
+    case CKM_SSL3_MASTER_KEY_DERIVE:
+    case CKM_SSL3_SHA1_MAC:
+    case CKM_SSL3_MD5_MAC:
+	return &pk11_sslSlotList;
+    case CKM_TLS_MASTER_KEY_DERIVE:
+    case CKM_TLS_KEY_AND_MAC_DERIVE:
+	return &pk11_tlsSlotList;
+    case CKM_IDEA_CBC:
+    case CKM_IDEA_ECB:
+	return &pk11_ideaSlotList;
+    case CKM_FAKE_RANDOM:
+	return &pk11_randomSlotList;
+    }
+    return NULL;
+}
+
+/*
+ * load the static SlotInfo structures used to select a PKCS11 slot.
+ * preSlotInfo has a list of all the default flags for the slots on this
+ * module.
+ */
+void
+PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count)
+{
+    int i;
+
+    for (i=0; i < count; i++) {
+	if (psi[i].slotID == slot->slotID)
+	    break;
+    }
+
+    if (i == count) return;
+
+    slot->defaultFlags = psi[i].defaultFlags;
+    slot->askpw = psi[i].askpw;
+    slot->timeout = psi[i].timeout;
+    slot->hasRootCerts = psi[i].hasRootCerts;
+
+    /* if the slot is already disabled, don't load them into the
+     * default slot lists. We get here so we can save the default
+     * list value. */
+    if (slot->disabled) return;
+
+    /* if the user has disabled us, don't load us in */
+    if (slot->defaultFlags & PK11_DISABLE_FLAG) {
+	slot->disabled = PR_TRUE;
+	slot->reason = PK11_DIS_USER_SELECTED;
+	/* free up sessions and things?? */
+	return;
+    }
+
+    for (i=0; i < num_pk11_default_mechanisms; i++) {
+	if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
+	    CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
+	    PK11SlotList *slotList = PK11_GetSlotList(mechanism);
+
+	    if (slotList) PK11_AddSlotToList(slotList,slot);
+	}
+    }
+
+    return;
+}
+
+
+/*
+ * update a slot to its new attribute according to the slot list
+ * returns: SECSuccess if nothing to do or add/delete is successful
+ */
+SECStatus
+PK11_UpdateSlotAttribute(PK11SlotInfo *slot, PK11DefaultArrayEntry *entry,
+                        PRBool add)  
+                        /* add: PR_TRUE if want to turn on */
+{
+    SECStatus result = SECSuccess;
+    PK11SlotList *slotList = PK11_GetSlotList(entry->mechanism);
+
+    if (add) { /* trying to turn on a mechanism */
+                 
+        /* turn on the default flag in the slot */
+        slot->defaultFlags |= entry->flag;
+        
+        /* add this slot to the list */
+        if (slotList!=NULL)
+            result = PK11_AddSlotToList(slotList, slot);
+        
+    } else { /* trying to turn off */
+            
+        /* turn OFF the flag in the slot */ 
+        slot->defaultFlags &= ~entry->flag;
+        
+        if (slotList) {
+            /* find the element in the list & delete it */
+            PK11SlotListElement *le = PK11_FindSlotElement(slotList, slot);
+
+            /* remove the slot from the list */
+            if (le)
+                result = PK11_DeleteSlotFromList(slotList, le);
+        }
+    }
+    return result;
+}
+
+/*
+ * clear a slot off of all of it's default list
+ */
+void
+PK11_ClearSlotList(PK11SlotInfo *slot)
+{
+    int i;
+
+    if (slot->disabled) return;
+    if (slot->defaultFlags == 0) return;
+
+    for (i=0; i < num_pk11_default_mechanisms; i++) {
+	if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
+	    CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
+	    PK11SlotList *slotList = PK11_GetSlotList(mechanism);
+	    PK11SlotListElement *le = NULL;
+
+	    if (slotList) le = PK11_FindSlotElement(slotList,slot);
+
+	    if (le) {
+		PK11_DeleteSlotFromList(slotList,le);
+		PK11_FreeSlotListElement(slotList,le);
+	    }
+	}
+    }
+}
+
+
+/******************************************************************
+ *           Slot initialization
+ ******************************************************************/
+/*
+ * turn a PKCS11 Static Label into a string
+ */
+char *
+PK11_MakeString(PRArenaPool *arena,char *space,
+					char *staticString,int stringLen)
+{
+	int i;
+	char *newString;
+	for(i=(stringLen-1); i >= 0; i--) {
+	  if (staticString[i] != ' ') break;
+	}
+	/* move i to point to the last space */
+	i++;
+	if (arena) {
+	    newString = (char*)PORT_ArenaAlloc(arena,i+1 /* space for NULL */);
+	} else if (space) {
+	    newString = space;
+	} else {
+	    newString = (char*)PORT_Alloc(i+1 /* space for NULL */);
+	}
+	if (newString == NULL) return NULL;
+
+	if (i) PORT_Memcpy(newString,staticString, i);
+	newString[i] = 0;
+
+	return newString;
+}
+
+/*
+ * Reads in the slots mechanism list for later use
+ */
+SECStatus
+PK11_ReadMechanismList(PK11SlotInfo *slot)
+{
+    CK_ULONG count;
+    CK_RV crv;
+    PRUint32 i;
+
+    if (slot->mechanismList) {
+	PORT_Free(slot->mechanismList);
+	slot->mechanismList = NULL;
+    }
+    slot->mechanismCount = 0;
+
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,NULL,&count);
+    if (crv != CKR_OK) {
+	if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+
+    slot->mechanismList = (CK_MECHANISM_TYPE *)
+			    PORT_Alloc(count *sizeof(CK_MECHANISM_TYPE));
+    if (slot->mechanismList == NULL) {
+	if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+	return SECFailure;
+    }
+    crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,
+						slot->mechanismList, &count);
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_Free(slot->mechanismList);
+	slot->mechanismList = NULL;
+	PORT_SetError(PK11_MapError(crv));
+	return SECSuccess;
+    }
+    slot->mechanismCount = count;
+    PORT_Memset(slot->mechanismBits, 0, sizeof(slot->mechanismBits));
+
+    for (i=0; i < count; i++) {
+	CK_MECHANISM_TYPE mech = slot->mechanismList[i];
+	if (mech < 0x7ff) {
+	    slot->mechanismBits[mech & 0xff] |= 1 << (mech >> 8);
+	}
+    }
+    return SECSuccess;
+}
+
+/*
+ * initialize a new token
+ * unlike initialize slot, this can be called multiple times in the lifetime
+ * of NSS. It reads the information associated with a card or token,
+ * that is not going to change unless the card or token changes.
+ */
+SECStatus
+PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts)
+{
+    CK_TOKEN_INFO tokenInfo;
+    CK_RV crv;
+    char *tmp;
+    SECStatus rv;
+    PRStatus status;
+
+    /* set the slot flags to the current token values */
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+
+    /* set the slot flags to the current token values */
+    slot->series++; /* allow other objects to detect that the 
+		      * slot is different */
+    slot->flags = tokenInfo.flags;
+    slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ? 
+							PR_TRUE : PR_FALSE);
+    slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ? 
+							PR_TRUE : PR_FALSE);
+	
+	 
+    slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
+    slot->protectedAuthPath =
+    		((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) 
+	 						? PR_TRUE : PR_FALSE);
+    slot->lastLoginCheck = 0;
+    slot->lastState = 0;
+    /* on some platforms Active Card incorrectly sets the 
+     * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
+    if (slot->isActiveCard) {
+	slot->protectedAuthPath = PR_FALSE;
+    }
+    tmp = PK11_MakeString(NULL,slot->token_name,
+			(char *)tokenInfo.label, sizeof(tokenInfo.label));
+    slot->minPassword = tokenInfo.ulMinPinLen;
+    slot->maxPassword = tokenInfo.ulMaxPinLen;
+    PORT_Memcpy(slot->serial,tokenInfo.serialNumber,sizeof(slot->serial));
+
+    nssToken_UpdateName(slot->nssToken);
+
+    slot->defRWSession = (PRBool)((!slot->readOnly) && 
+					(tokenInfo.ulMaxSessionCount == 1));
+    rv = PK11_ReadMechanismList(slot);
+    if (rv != SECSuccess) return rv;
+
+    slot->hasRSAInfo = PR_FALSE;
+    slot->RSAInfoFlags = 0;
+
+    /* initialize the maxKeyCount value */
+    if (tokenInfo.ulMaxSessionCount == 0) {
+	slot->maxKeyCount = 800; /* should be #define or a config param */
+    } else if (tokenInfo.ulMaxSessionCount < 20) {
+	/* don't have enough sessions to keep that many keys around */
+	slot->maxKeyCount = 0;
+    } else {
+	slot->maxKeyCount = tokenInfo.ulMaxSessionCount/2;
+    }
+
+    /* Make sure our session handle is valid */
+    if (slot->session == CK_INVALID_SESSION) {
+	/* we know we don't have a valid session, go get one */
+	CK_SESSION_HANDLE session;
+
+	/* session should be Readonly, serial */
+	if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+	crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
+	      (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
+				  slot,pk11_notify,&session);
+	if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+	if (crv != CKR_OK) {
+	    PORT_SetError(PK11_MapError(crv));
+	    return SECFailure;
+	}
+	slot->session = session;
+    } else {
+	/* The session we have may be defunct (the token associated with it)
+	 * has been removed   */
+	CK_SESSION_INFO sessionInfo;
+
+	if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+	crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo);
+        if (crv == CKR_DEVICE_ERROR) {
+	    PK11_GETTAB(slot)->C_CloseSession(slot->session);
+	    crv = CKR_SESSION_CLOSED;
+	}
+	if ((crv==CKR_SESSION_CLOSED) || (crv==CKR_SESSION_HANDLE_INVALID)) {
+	    crv =PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
+	      (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
+					slot,pk11_notify,&slot->session);
+	    if (crv != CKR_OK) {
+	        PORT_SetError(PK11_MapError(crv));
+		slot->session = CK_INVALID_SESSION;
+		if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+		return SECFailure;
+	    }
+	}
+	if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    }
+
+    status = nssToken_Refresh(slot->nssToken);
+    if (status != PR_SUCCESS)
+    	return SECFailure;
+
+    if (!(slot->isInternal) && (slot->hasRandom)) {
+	/* if this slot has a random number generater, use it to add entropy
+	 * to the internal slot. */
+	PK11SlotInfo *int_slot = PK11_GetInternalSlot();
+
+	if (int_slot) {
+	    unsigned char random_bytes[32];
+
+	    /* if this slot can issue random numbers, get some entropy from
+	     * that random number generater and give it to our internal token.
+	     */
+	    PK11_EnterSlotMonitor(slot);
+	    crv = PK11_GETTAB(slot)->C_GenerateRandom
+			(slot->session,random_bytes, sizeof(random_bytes));
+	    PK11_ExitSlotMonitor(slot);
+	    if (crv == CKR_OK) {
+	        PK11_EnterSlotMonitor(int_slot);
+		PK11_GETTAB(int_slot)->C_SeedRandom(int_slot->session,
+					random_bytes, sizeof(random_bytes));
+	        PK11_ExitSlotMonitor(int_slot);
+	    }
+
+	    /* Now return the favor and send entropy to the token's random 
+	     * number generater */
+	    PK11_EnterSlotMonitor(int_slot);
+	    crv = PK11_GETTAB(int_slot)->C_GenerateRandom(int_slot->session,
+					random_bytes, sizeof(random_bytes));
+	    PK11_ExitSlotMonitor(int_slot);
+	    if (crv == CKR_OK) {
+	        PK11_EnterSlotMonitor(slot);
+		crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session,
+					random_bytes, sizeof(random_bytes));
+	        PK11_ExitSlotMonitor(slot);
+	    }
+	    PK11_FreeSlot(int_slot);
+	}
+    }
+    /* work around a problem in softoken where it incorrectly
+     * reports databases opened read only as read/write. */
+    if (slot->isInternal && !slot->readOnly) {
+	CK_SESSION_HANDLE session = CK_INVALID_SESSION;
+
+	/* try to open a R/W session */
+	crv =PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
+	      CKF_RW_SESSION|CKF_SERIAL_SESSION, slot, pk11_notify ,&session);
+	/* what a well behaved token should return if you open 
+	 * a RW session on a read only token */
+	if (crv == CKR_TOKEN_WRITE_PROTECTED) {
+	    slot->readOnly = PR_TRUE;
+	} else if (crv == CKR_OK) {
+	    CK_SESSION_INFO sessionInfo;
+
+	    /* Because of a second bug in softoken, which silently returns
+	     * a RO session, we need to check what type of session we got. */
+	    crv = PK11_GETTAB(slot)->C_GetSessionInfo(session, &sessionInfo);
+	    if (crv == CKR_OK) {
+		if ((sessionInfo.flags & CKF_RW_SESSION) == 0) {
+		    /* session was readonly, so this softoken slot must be 			     * readonly */
+		    slot->readOnly = PR_TRUE;
+		}
+	    }
+	    PK11_GETTAB(slot)->C_CloseSession(session);
+	}
+    }
+	
+    return SECSuccess;
+}
+
+/*
+ * initialize a new token
+ * unlike initialize slot, this can be called multiple times in the lifetime
+ * of NSS. It reads the information associated with a card or token,
+ * that is not going to change unless the card or token changes.
+ */
+SECStatus
+PK11_TokenRefresh(PK11SlotInfo *slot)
+{
+    CK_TOKEN_INFO tokenInfo;
+    CK_RV crv;
+
+    /* set the slot flags to the current token values */
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+
+    slot->flags = tokenInfo.flags;
+    slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ? 
+							PR_TRUE : PR_FALSE);
+    slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ? 
+							PR_TRUE : PR_FALSE);
+    slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
+    slot->protectedAuthPath =
+    		((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) 
+	 						? PR_TRUE : PR_FALSE);
+    /* on some platforms Active Card incorrectly sets the 
+     * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
+    if (slot->isActiveCard) {
+	slot->protectedAuthPath = PR_FALSE;
+    }
+    return SECSuccess;
+}
+
+static PRBool
+pk11_isRootSlot(PK11SlotInfo *slot) 
+{
+    CK_ATTRIBUTE findTemp[1];
+    CK_ATTRIBUTE *attrs;
+    CK_OBJECT_CLASS oclass = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
+    int tsize;
+    CK_OBJECT_HANDLE handle;
+
+    attrs = findTemp;
+    PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass)); attrs++;
+    tsize = attrs - findTemp;
+    PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
+
+    handle = pk11_FindObjectByTemplate(slot,findTemp,tsize);
+    if (handle == CK_INVALID_HANDLE) {
+	return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+/*
+ * Initialize the slot :
+ * This initialization code is called on each slot a module supports when
+ * it is loaded. It does the bringup initialization. The difference between
+ * this and InitToken is Init slot does those one time initialization stuff,
+ * usually associated with the reader, while InitToken may get called multiple
+ * times as tokens are removed and re-inserted.
+ */
+void
+PK11_InitSlot(SECMODModule *mod,CK_SLOT_ID slotID,PK11SlotInfo *slot)
+{
+    SECStatus rv;
+    char *tmp;
+    CK_SLOT_INFO slotInfo;
+
+    slot->functionList = mod->functionList;
+    slot->isInternal = mod->internal;
+    slot->slotID = slotID;
+    slot->isThreadSafe = mod->isThreadSafe;
+    slot->hasRSAInfo = PR_FALSE;
+    
+    if (PK11_GETTAB(slot)->C_GetSlotInfo(slotID,&slotInfo) != CKR_OK) {
+	slot->disabled = PR_TRUE;
+	slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
+	return;
+    }
+
+    /* test to make sure claimed mechanism work */
+    slot->needTest = mod->internal ? PR_FALSE : PR_TRUE;
+    slot->module = mod; /* NOTE: we don't make a reference here because
+			 * modules have references to their slots. This
+			 * works because modules keep implicit references
+			 * from their slots, and won't unload and disappear
+			 * until all their slots have been freed */
+    tmp = PK11_MakeString(NULL,slot->slot_name,
+	 (char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
+    slot->isHW = (PRBool)((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT);
+#define ACTIVE_CARD "ActivCard SA"
+    slot->isActiveCard = (PRBool)(PORT_Strncmp((char *)slotInfo.manufacturerID,
+				ACTIVE_CARD, sizeof(ACTIVE_CARD)-1) == 0);
+    if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == 0) {
+	slot->isPerm = PR_TRUE;
+	/* permanment slots must have the token present always */
+	if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
+	    slot->disabled = PR_TRUE;
+	    slot->reason = PK11_DIS_TOKEN_NOT_PRESENT;
+	    return; /* nothing else to do */
+	}
+    }
+    /* if the token is present, initialize it */
+    if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
+	rv = PK11_InitToken(slot,PR_TRUE);
+	/* the only hard failures are on permanent devices, or function
+	 * verify failures... function verify failures are already handled
+	 * by tokenInit */
+	if ((rv != SECSuccess) && (slot->isPerm) && (!slot->disabled)) {
+	    slot->disabled = PR_TRUE;
+	    slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
+	}
+	if (rv == SECSuccess && pk11_isRootSlot(slot)) {
+	    if (!slot->hasRootCerts) {
+		slot->module->trustOrder = 100;
+	    }
+	    slot->hasRootCerts= PR_TRUE;
+	}
+    }
+}
+
+	
+
+/*********************************************************************
+ *            Slot mapping utility functions.
+ *********************************************************************/
+
+/*
+ * determine if the token is present. If the token is present, make sure
+ * we have a valid session handle. Also set the value of needLogin 
+ * appropriately.
+ */
+static PRBool
+pk11_IsPresentCertLoad(PK11SlotInfo *slot, PRBool loadCerts)
+{
+    CK_SLOT_INFO slotInfo;
+    CK_SESSION_INFO sessionInfo;
+    CK_RV crv;
+
+    /* disabled slots are never present */
+    if (slot->disabled) {
+	return PR_FALSE;
+    }
+
+    /* permanent slots are always present */
+    if (slot->isPerm && (slot->session != CK_INVALID_SESSION)) {
+	return PR_TRUE;
+    }
+
+    if (slot->nssToken) {
+	return nssToken_IsPresent(slot->nssToken);
+    }
+
+    /* removable slots have a flag that says they are present */
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    if (PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,&slotInfo) != CKR_OK) {
+        if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+	return PR_FALSE;
+    }
+    if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
+	/* if the slot is no longer present, close the session */
+	if (slot->session != CK_INVALID_SESSION) {
+	    PK11_GETTAB(slot)->C_CloseSession(slot->session);
+	    slot->session = CK_INVALID_SESSION;
+	}
+        if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+	return PR_FALSE;
+    }
+
+    /* use the session Info to determine if the card has been removed and then
+     * re-inserted */
+    if (slot->session != CK_INVALID_SESSION) {
+	if (slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+	crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
+	if (crv != CKR_OK) {
+	    PK11_GETTAB(slot)->C_CloseSession(slot->session);
+	    slot->session = CK_INVALID_SESSION;
+	}
+        if (slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    }
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+
+    /* card has not been removed, current token info is correct */
+    if (slot->session != CK_INVALID_SESSION) return PR_TRUE;
+
+    /* initialize the token info state */
+    if (PK11_InitToken(slot,loadCerts) != SECSuccess) {
+	return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+
+/*
+ * old version of the routine
+ */
+PRBool
+PK11_IsPresent(PK11SlotInfo *slot) {
+   return pk11_IsPresentCertLoad(slot,PR_TRUE);
+}
+
+/* is the slot disabled? */
+PRBool
+PK11_IsDisabled(PK11SlotInfo *slot)
+{
+    return slot->disabled;
+}
+
+/* and why? */
+PK11DisableReasons
+PK11_GetDisabledReason(PK11SlotInfo *slot)
+{
+    return slot->reason;
+}
+
+/* returns PR_TRUE if successfully disable the slot */
+/* returns PR_FALSE otherwise */
+PRBool PK11_UserDisableSlot(PK11SlotInfo *slot) {
+
+    slot->defaultFlags |= PK11_DISABLE_FLAG;
+    slot->disabled = PR_TRUE;
+    slot->reason = PK11_DIS_USER_SELECTED;
+    
+    return PR_TRUE;
+}
+
+PRBool PK11_UserEnableSlot(PK11SlotInfo *slot) {
+
+    slot->defaultFlags &= ~PK11_DISABLE_FLAG;
+    slot->disabled = PR_FALSE;
+    slot->reason = PK11_DIS_NONE;
+    return PR_TRUE;
+}
+
+PRBool PK11_HasRootCerts(PK11SlotInfo *slot) {
+    return slot->hasRootCerts;
+}
+
+/* Get the module this slot is attached to */
+SECMODModule *
+PK11_GetModule(PK11SlotInfo *slot)
+{
+	return slot->module;
+}
+
+/* return the default flags of a slot */
+unsigned long
+PK11_GetDefaultFlags(PK11SlotInfo *slot)
+{
+	return slot->defaultFlags;
+}
+
+/*
+ * The following wrapper functions allow us to export an opaque slot
+ * function to the rest of libsec and the world... */
+PRBool
+PK11_IsReadOnly(PK11SlotInfo *slot)
+{
+    return slot->readOnly;
+}
+
+PRBool
+PK11_IsHW(PK11SlotInfo *slot)
+{
+    return slot->isHW;
+}
+
+PRBool
+PK11_IsRemovable(PK11SlotInfo *slot)
+{
+    return !slot->isPerm;
+}
+
+PRBool
+PK11_IsInternal(PK11SlotInfo *slot)
+{
+    return slot->isInternal;
+}
+
+PRBool
+PK11_IsInternalKeySlot(PK11SlotInfo *slot)
+{
+    PK11SlotInfo *int_slot;
+    PRBool result;
+
+    if (!slot->isInternal) {
+	return PR_FALSE;
+    }
+
+    int_slot = PK11_GetInternalKeySlot();
+    result = (int_slot == slot) ? PR_TRUE : PR_FALSE;
+    PK11_FreeSlot(int_slot);
+    return result;
+}
+
+PRBool
+PK11_NeedLogin(PK11SlotInfo *slot)
+{
+    return slot->needLogin;
+}
+
+PRBool
+PK11_IsFriendly(PK11SlotInfo *slot)
+{
+    /* internal slot always has public readable certs */
+    return (PRBool)(slot->isInternal || 
+		    ((slot->defaultFlags & SECMOD_FRIENDLY_FLAG) == 
+		     SECMOD_FRIENDLY_FLAG));
+}
+
+char *
+PK11_GetTokenName(PK11SlotInfo *slot)
+{
+     return slot->token_name;
+}
+
+char *
+PK11_GetSlotName(PK11SlotInfo *slot)
+{
+     return slot->slot_name;
+}
+
+int
+PK11_GetSlotSeries(PK11SlotInfo *slot)
+{
+    return slot->series;
+}
+
+int
+PK11_GetCurrentWrapIndex(PK11SlotInfo *slot)
+{
+    return slot->wrapKey;
+}
+
+CK_SLOT_ID
+PK11_GetSlotID(PK11SlotInfo *slot)
+{
+    return slot->slotID;
+}
+
+SECMODModuleID
+PK11_GetModuleID(PK11SlotInfo *slot)
+{
+    return slot->module->moduleID;
+}
+
+static void
+pk11_zeroTerminatedToBlankPadded(CK_CHAR *buffer, size_t buffer_size)
+{
+    CK_CHAR *walk = buffer;
+    CK_CHAR *end = buffer + buffer_size;
+
+    /* find the NULL */
+    while (walk < end && *walk != '\0') {
+	walk++;
+    }
+
+    /* clear out the buffer */
+    while (walk < end) {
+	*walk++ = ' ';
+    }
+}
+
+/* return the slot info structure */
+SECStatus
+PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info)
+{
+    CK_RV crv;
+
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    /*
+     * some buggy drivers do not fill the buffer completely, 
+     * erase the buffer first
+     */
+    PORT_Memset(info->slotDescription,' ',sizeof(info->slotDescription));
+    PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
+    crv = PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,info);
+    pk11_zeroTerminatedToBlankPadded(info->slotDescription,
+					sizeof(info->slotDescription));
+    pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
+					sizeof(info->manufacturerID));
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/*  return the token info structure */
+SECStatus
+PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info)
+{
+    CK_RV crv;
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    /*
+     * some buggy drivers do not fill the buffer completely, 
+     * erase the buffer first
+     */
+    PORT_Memset(info->label,' ',sizeof(info->label));
+    PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
+    PORT_Memset(info->model,' ',sizeof(info->model));
+    PORT_Memset(info->serialNumber,' ',sizeof(info->serialNumber));
+    crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,info);
+    pk11_zeroTerminatedToBlankPadded(info->label,sizeof(info->label));
+    pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
+					sizeof(info->manufacturerID));
+    pk11_zeroTerminatedToBlankPadded(info->model,sizeof(info->model));
+    pk11_zeroTerminatedToBlankPadded(info->serialNumber,
+					sizeof(info->serialNumber));
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/* Find out if we need to initialize the user's pin */
+PRBool
+PK11_NeedUserInit(PK11SlotInfo *slot)
+{
+    PRBool needUserInit = (PRBool) ((slot->flags & CKF_USER_PIN_INITIALIZED) 
+					== 0);
+
+    if (needUserInit) {
+	CK_TOKEN_INFO info;
+	SECStatus rv;
+
+	/* see if token has been initialized off line */
+	rv = PK11_GetTokenInfo(slot, &info);
+	if (rv == SECSuccess) {
+	    slot->flags = info.flags;
+	}
+    }
+    return (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
+}
+
+static PK11SlotInfo *pk11InternalKeySlot = NULL;
+void
+pk11_SetInternalKeySlot(PK11SlotInfo *slot)
+{
+   if (pk11InternalKeySlot) {
+	PK11_FreeSlot(pk11InternalKeySlot);
+   }
+   pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
+}
+
+
+/* get the internal key slot. FIPS has only one slot for both key slots and
+ * default slots */
+PK11SlotInfo *
+PK11_GetInternalKeySlot(void)
+{
+    SECMODModule *mod;
+
+    if (pk11InternalKeySlot) {
+	return PK11_ReferenceSlot(pk11InternalKeySlot);
+    }
+
+    mod = SECMOD_GetInternalModule();
+    PORT_Assert(mod != NULL);
+    if (!mod) {
+	PORT_SetError( SEC_ERROR_NO_MODULE );
+	return NULL;
+    }
+    return PK11_ReferenceSlot(mod->isFIPS ? mod->slots[0] : mod->slots[1]);
+}
+
+/* get the internal default slot */
+PK11SlotInfo *
+PK11_GetInternalSlot(void) 
+{
+    SECMODModule * mod = SECMOD_GetInternalModule();
+    PORT_Assert(mod != NULL);
+    if (!mod) {
+	PORT_SetError( SEC_ERROR_NO_MODULE );
+	return NULL;
+    }
+    if (mod->isFIPS) {
+	return PK11_GetInternalKeySlot();
+    }
+    return PK11_ReferenceSlot(mod->slots[0]);
+}
+
+/*
+ * check if a given slot supports the requested mechanism
+ */
+PRBool
+PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type)
+{
+    int i;
+
+    /* CKM_FAKE_RANDOM is not a real PKCS mechanism. It's a marker to
+     * tell us we're looking form someone that has implemented get
+     * random bits */
+    if (type == CKM_FAKE_RANDOM) {
+	return slot->hasRandom;
+    }
+
+    /* for most mechanism, bypass the linear lookup */
+    if (type < 0x7ff) {
+	return (slot->mechanismBits[type & 0xff] & (1 << (type >> 8)))  ?
+		PR_TRUE : PR_FALSE;
+    }
+	   
+    for (i=0; i < (int) slot->mechanismCount; i++) {
+	if (slot->mechanismList[i] == type) return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+/*
+ * Return true if a token that can do the desired mechanism exists.
+ * This allows us to have hardware tokens that can do function XYZ magically
+ * allow SSL Ciphers to appear if they are plugged in.
+ */
+PRBool
+PK11_TokenExists(CK_MECHANISM_TYPE type)
+{
+    SECMODModuleList *mlp;
+    SECMODModuleList *modules;
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+    PK11SlotInfo *slot;
+    PRBool found = PR_FALSE;
+    int i;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return found;
+    }
+    /* we only need to know if there is a token that does this mechanism.
+     * check the internal module first because it's fast, and supports 
+     * almost everything. */
+    slot = PK11_GetInternalSlot();
+    if (slot) {
+    	found = PK11_DoesMechanism(slot,type);
+	PK11_FreeSlot(slot);
+    }
+    if (found) return PR_TRUE; /* bypass getting module locks */
+
+    SECMOD_GetReadLock(moduleLock);
+    modules = SECMOD_GetDefaultModuleList();
+    for(mlp = modules; mlp != NULL && (!found); mlp = mlp->next) {
+	for (i=0; i < mlp->module->slotCount; i++) {
+	    slot = mlp->module->slots[i];
+	    if (PK11_IsPresent(slot)) {
+		if (PK11_DoesMechanism(slot,type)) {
+		    found = PR_TRUE;
+		    break;
+		}
+	    }
+	}
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+    return found;
+}
+
+/*
+ * get all the currently available tokens in a list.
+ * that can perform the given mechanism. If mechanism is CKM_INVALID_MECHANISM,
+ * get all the tokens. Make sure tokens that need authentication are put at
+ * the end of this list.
+ */
+PK11SlotList *
+PK11_GetAllTokens(CK_MECHANISM_TYPE type, PRBool needRW, PRBool loadCerts, 
+                  void *wincx)
+{
+    PK11SlotList *     list;
+    PK11SlotList *     loginList;
+    PK11SlotList *     friendlyList;
+    SECMODModuleList * mlp;
+    SECMODModuleList * modules;
+    SECMODListLock *   moduleLock;
+    int                i;
+#if defined( XP_WIN32 ) 
+    int                j            = 0;
+    PRInt32            waste[16];
+#endif
+
+    moduleLock   = SECMOD_GetDefaultModuleListLock();
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return NULL;
+    }
+
+    list         = PK11_NewSlotList();
+    loginList    = PK11_NewSlotList();
+    friendlyList = PK11_NewSlotList();
+    if ((list == NULL)  || (loginList == NULL) || (friendlyList == NULL)) {
+	if (list) PK11_FreeSlotList(list);
+	if (loginList) PK11_FreeSlotList(loginList);
+	if (friendlyList) PK11_FreeSlotList(friendlyList);
+	return NULL;
+    }
+
+    SECMOD_GetReadLock(moduleLock);
+
+    modules      = SECMOD_GetDefaultModuleList();
+    for(mlp = modules; mlp != NULL; mlp = mlp->next) {
+
+#if defined( XP_WIN32 ) 
+	/* This is works around some horrible cache/page thrashing problems 
+	** on Win32.  Without this, this loop can take up to 6 seconds at 
+	** 100% CPU on a Pentium-Pro 200.  The thing this changes is to 
+	** increase the size of the stack frame and modify it.  
+	** Moving the loop code itself seems to have no effect.
+	** Dunno why this combination makes a difference, but it does.
+	*/
+	waste[ j & 0xf] = j++; 
+#endif
+
+	for (i = 0; i < mlp->module->slotCount; i++) {
+	    PK11SlotInfo *slot = mlp->module->slots[i];
+
+	    if (pk11_IsPresentCertLoad(slot, loadCerts)) {
+		if (needRW &&  slot->readOnly) continue;
+		if ((type == CKM_INVALID_MECHANISM) 
+					|| PK11_DoesMechanism(slot, type)) {
+		    if (pk11_LoginStillRequired(slot,wincx)) {
+			if (PK11_IsFriendly(slot)) {
+			    PK11_AddSlotToList(friendlyList, slot);
+			} else {
+			    PK11_AddSlotToList(loginList, slot);
+			}
+		    } else {
+			PK11_AddSlotToList(list, slot);
+		    }
+		}
+	    }
+	}
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    PK11_MoveListToList(list,friendlyList);
+    PK11_FreeSlotList(friendlyList);
+    PK11_MoveListToList(list,loginList);
+    PK11_FreeSlotList(loginList);
+
+    return list;
+}
+
+/*
+ * NOTE: This routine is working from a private List generated by 
+ * PK11_GetAllTokens. That is why it does not need to lock.
+ */
+PK11SlotList *
+PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type,PRBool needRW,void *wincx)
+{
+    PK11SlotList *list = PK11_GetAllTokens(type,needRW,PR_TRUE,wincx);
+    PK11SlotListElement *le, *next ;
+    SECStatus rv;
+
+    if (list == NULL) return list;
+
+    for (le = list->head ; le; le = next) {
+	next = le->next; /* save the pointer here in case we have to 
+			  * free the element later */
+        rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
+	if (rv != SECSuccess) {
+	    PK11_DeleteSlotFromList(list,le);
+	    continue;
+	}
+    }
+    return list;
+}
+
+
+/*
+ * find the best slot which supports the given
+ * Mechanism. In normal cases this should grab the first slot on the list
+ * with no fuss.
+ */
+PK11SlotInfo *
+PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int mech_count, void *wincx)
+{
+    PK11SlotList *list = NULL;
+    PK11SlotListElement *le ;
+    PK11SlotInfo *slot = NULL;
+    PRBool freeit = PR_FALSE;
+    PRBool listNeedLogin = PR_FALSE;
+    int i;
+    SECStatus rv;
+
+    list = PK11_GetSlotList(type[0]);
+
+    if ((list == NULL) || (list->head == NULL)) {
+	/* We need to look up all the tokens for the mechanism */
+	list = PK11_GetAllTokens(type[0],PR_FALSE,PR_TRUE,wincx);
+	freeit = PR_TRUE;
+    }
+
+    /* no one can do it! */
+    if (list == NULL) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+
+    PORT_SetError(0);
+
+
+    listNeedLogin = PR_FALSE;
+    for (i=0; i < mech_count; i++) {
+	if ((type[i] != CKM_FAKE_RANDOM) && 
+	    (type[i] != CKM_SHA_1) &&
+	    (type[i] != CKM_SHA256) &&
+	    (type[i] != CKM_SHA384) &&
+	    (type[i] != CKM_SHA512) &&
+	    (type[i] != CKM_MD5) && 
+	    (type[i] != CKM_MD2)) {
+	    listNeedLogin = PR_TRUE;
+	    break;
+	}
+    }
+
+    for (le = PK11_GetFirstSafe(list); le;
+			 	le = PK11_GetNextSafe(list,le,PR_TRUE)) {
+	if (PK11_IsPresent(le->slot)) {
+	    PRBool doExit = PR_FALSE;
+	    for (i=0; i < mech_count; i++) {
+	    	if (!PK11_DoesMechanism(le->slot,type[i])) {
+		    doExit = PR_TRUE;
+		    break;
+		}
+	    }
+	    if (doExit) continue;
+	      
+	    if (listNeedLogin && le->slot->needLogin) {
+		rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
+		if (rv != SECSuccess) continue;
+	    }
+	    slot = le->slot;
+	    PK11_ReferenceSlot(slot);
+	    PK11_FreeSlotListElement(list,le);
+	    if (freeit) { PK11_FreeSlotList(list); }
+	    return slot;
+	}
+    }
+    if (freeit) { PK11_FreeSlotList(list); }
+    if (PORT_GetError() == 0) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+    }
+    return NULL;
+}
+
+/* original get best slot now calls the multiple version with only one type */
+PK11SlotInfo *
+PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx)
+{
+    return PK11_GetBestSlotMultiple(&type, 1, wincx);
+}
+
+int
+PK11_GetBestKeyLength(PK11SlotInfo *slot,CK_MECHANISM_TYPE mechanism)
+{
+    CK_MECHANISM_INFO mechanism_info;
+    CK_RV crv;
+
+    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
+                               mechanism,&mechanism_info);
+    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) return 0;
+
+    if (mechanism_info.ulMinKeySize == mechanism_info.ulMaxKeySize) 
+		return 0;
+    return mechanism_info.ulMaxKeySize;
+}
+
+
+/*
+ * This function uses the existing PKCS #11 module to find the
+ * longest supported key length in the preferred token for a mechanism.
+ * This varies from the above function in that 1) it returns the key length
+ * even for fixed key algorithms, and 2) it looks through the tokens
+ * generally rather than for a specific token. This is used in liu of
+ * a PK11_GetKeyLength function in pk11mech.c since we can actually read
+ * supported key lengths from PKCS #11.
+ *
+ * For symmetric key operations the length is returned in bytes.
+ */
+int
+PK11_GetMaxKeyLength(CK_MECHANISM_TYPE mechanism)
+{
+    CK_MECHANISM_INFO mechanism_info;
+    PK11SlotList *list = NULL;
+    PK11SlotListElement *le ;
+    PRBool freeit = PR_FALSE;
+    int keyLength = 0;
+
+    list = PK11_GetSlotList(mechanism);
+
+    if ((list == NULL) || (list->head == NULL)) {
+	/* We need to look up all the tokens for the mechanism */
+	list = PK11_GetAllTokens(mechanism,PR_FALSE,PR_FALSE,NULL);
+	freeit = PR_TRUE;
+    }
+
+    /* no tokens recognize this mechanism */
+    if (list == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return 0;
+    }
+
+    for (le = PK11_GetFirstSafe(list); le;
+			 	le = PK11_GetNextSafe(list,le,PR_TRUE)) {
+	PK11SlotInfo *slot = le->slot;
+	CK_RV crv;
+	if (PK11_IsPresent(slot)) {
+	    if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
+	    crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
+                               mechanism,&mechanism_info);
+ 	    if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
+	    if ((crv == CKR_OK)  && (mechanism_info.ulMaxKeySize != 0)
+		&& (mechanism_info.ulMaxKeySize != 0xffffffff)) {
+		keyLength = mechanism_info.ulMaxKeySize;
+		break;
+	    }
+	}
+    }
+    if (le) 
+	PK11_FreeSlotListElement(list, le);
+    if (freeit) 
+	PK11_FreeSlotList(list);
+    return keyLength;
+}
+
+SECStatus
+PK11_SeedRandom(PK11SlotInfo *slot, unsigned char *data, int len) {
+    CK_RV crv;
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session, data, (CK_ULONG)len);
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+SECStatus
+PK11_GenerateRandomOnSlot(PK11SlotInfo *slot, unsigned char *data, int len) {
+    CK_RV crv;
+
+    if (!slot->isInternal) PK11_EnterSlotMonitor(slot);
+    crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session,data, 
+							(CK_ULONG)len);
+    if (!slot->isInternal) PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return  SECFailure;
+    }
+    return SECSuccess;
+}
+
+/* Attempts to update the Best Slot for "FAKE RANDOM" generation.
+** If that's not the internal slot, then it also attempts to update the
+** internal slot.
+** The return value indicates if the INTERNAL slot was updated OK.
+*/
+SECStatus
+PK11_RandomUpdate(void *data, size_t bytes)
+{
+    PK11SlotInfo *slot;
+    PRBool        bestIsInternal;
+    SECStatus     status;
+
+    slot = PK11_GetBestSlot(CKM_FAKE_RANDOM, NULL);
+    if (slot == NULL) {
+	slot = PK11_GetInternalSlot();
+	if (!slot)
+	    return SECFailure;
+    }
+
+    bestIsInternal = PK11_IsInternal(slot);
+    status = PK11_SeedRandom(slot, data, bytes);
+    PK11_FreeSlot(slot);
+
+    if (!bestIsInternal) {
+    	/* do internal slot, too. */
+    	slot = PK11_GetInternalSlot();	/* can't fail */
+	status = PK11_SeedRandom(slot, data, bytes);
+	PK11_FreeSlot(slot);
+    }
+    return status;
+}
+
+
+SECStatus
+PK11_GenerateRandom(unsigned char *data,int len) {
+    PK11SlotInfo *slot;
+    SECStatus rv;
+
+    slot = PK11_GetBestSlot(CKM_FAKE_RANDOM,NULL);
+    if (slot == NULL) return SECFailure;
+
+    rv = PK11_GenerateRandomOnSlot(slot, data, len);
+    PK11_FreeSlot(slot);
+    return rv;
+}
+
+/*
+ * Reset the token to it's initial state. For the internal module, this will
+ * Purge your keydb, and reset your cert db certs to USER_INIT.
+ */
+SECStatus 
+PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd)
+{
+    unsigned char tokenName[32];
+    int tokenNameLen;
+    CK_RV crv;
+
+    /* reconstruct the token name */
+    tokenNameLen = PORT_Strlen(slot->token_name);
+    if (tokenNameLen > sizeof(tokenName)) {
+	tokenNameLen = sizeof(tokenName);
+    }
+
+    PORT_Memcpy(tokenName,slot->token_name,tokenNameLen);
+    if (tokenNameLen < sizeof(tokenName)) {
+	PORT_Memset(&tokenName[tokenNameLen],' ',
+					 sizeof(tokenName)-tokenNameLen);
+    }
+
+    /* initialize the token */    
+    PK11_EnterSlotMonitor(slot);
+
+    /* first shutdown the token. Existing sessions will get closed here */
+    PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
+    slot->session = CK_INVALID_SESSION;
+
+    /* now re-init the token */ 
+    crv = PK11_GETTAB(slot)->C_InitToken(slot->slotID,
+	(unsigned char *)sso_pwd, sso_pwd ? PORT_Strlen(sso_pwd): 0, tokenName);
+
+    /* finally bring the token back up */
+    PK11_InitToken(slot,PR_TRUE);
+    PK11_ExitSlotMonitor(slot);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
+	                                      slot->nssToken);
+    return SECSuccess;
+}
+void
+PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst) 
+{
+    sl->nssToken = nsst;
+}
+
+NSSToken *
+PK11Slot_GetNSSToken(PK11SlotInfo *sl) 
+{
+    return sl->nssToken;
+}
+
+/*
+ * wait for a token to change it's state. The application passes in the expected
+ * new state in event. 
+ */
+PK11TokenStatus
+PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event, 
+	PRIntervalTime timeout, PRIntervalTime latency, int series)
+{
+   PRIntervalTime first_time = 0;
+   PRBool first_time_set = PR_FALSE;
+   PRBool waitForRemoval;
+
+   if (slot->isPerm) {
+	return PK11TokenNotRemovable;
+   }
+   if (latency == 0) {
+	latency = PR_SecondsToInterval(5);
+   }
+   waitForRemoval = (PRBool) (event == PK11TokenRemovedOrChangedEvent);
+
+   if (series == 0) {
+	series = PK11_GetSlotSeries(slot);
+   }
+   while (PK11_IsPresent(slot) == waitForRemoval ) {
+	PRIntervalTime interval;
+
+	if (waitForRemoval && series != PK11_GetSlotSeries(slot)) {
+	    return PK11TokenChanged;
+	}
+	if (timeout == PR_INTERVAL_NO_WAIT) {
+	    return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
+	}
+	if (timeout != PR_INTERVAL_NO_TIMEOUT ) {
+	    interval = PR_IntervalNow();
+	    if (!first_time_set) {
+		first_time = interval;
+		first_time_set = PR_TRUE;
+	    }
+	    if ((interval-first_time) > timeout) {
+		return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
+	    }
+	}
+	PR_Sleep(latency);
+   }
+   return waitForRemoval ? PK11TokenRemoved : PK11TokenPresent;
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/pk11util.c b/mozilla/security/nss/lib/pk11wrap/pk11util.c
new file mode 100644
index 0000000..b1ce50c
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/pk11util.c
@@ -0,0 +1,1506 @@
+/* ***** 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 ***** */
+/*
+ * Initialize the PCKS 11 subsystem
+ */
+#include "seccomon.h"
+#include "secmod.h"
+#include "nssilock.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pk11func.h"
+#include "pki3hack.h"
+#include "secerr.h"
+#include "dev.h"
+#include "pkcs11ni.h"
+
+/* these are for displaying error messages */
+
+static  SECMODModuleList *modules = NULL;
+static  SECMODModuleList *modulesDB = NULL;
+static  SECMODModuleList *modulesUnload = NULL;
+static  SECMODModule *internalModule = NULL;
+static  SECMODModule *defaultDBModule = NULL;
+static  SECMODModule *pendingModule = NULL;
+static SECMODListLock *moduleLock = NULL;
+
+int secmod_PrivateModuleCount = 0;
+
+extern PK11DefaultArrayEntry PK11_DefaultArray[];
+extern int num_pk11_default_mechanisms;
+
+
+void
+SECMOD_Init() 
+{
+    /* don't initialize twice */
+    if (moduleLock) return;
+
+    moduleLock = SECMOD_NewListLock();
+    PK11_InitSlotLists();
+}
+
+
+SECStatus
+SECMOD_Shutdown() 
+{
+    /* destroy the lock */
+    if (moduleLock) {
+	SECMOD_DestroyListLock(moduleLock);
+	moduleLock = NULL;
+    }
+    /* free the internal module */
+    if (internalModule) {
+	SECMOD_DestroyModule(internalModule);
+	internalModule = NULL;
+    }
+
+    /* free the default database module */
+    if (defaultDBModule) {
+	SECMOD_DestroyModule(defaultDBModule);
+	defaultDBModule = NULL;
+    }
+	
+    /* destroy the list */
+    if (modules) {
+	SECMOD_DestroyModuleList(modules);
+	modules = NULL;
+    }
+   
+    if (modulesDB) {
+	SECMOD_DestroyModuleList(modulesDB);
+	modulesDB = NULL;
+    }
+
+    if (modulesUnload) {
+	SECMOD_DestroyModuleList(modulesUnload);
+	modulesUnload = NULL;
+    }
+
+    /* make all the slots and the lists go away */
+    PK11_DestroySlotLists();
+
+    nss_DumpModuleLog();
+
+#ifdef DEBUG
+    if (PR_GetEnv("NSS_STRICT_SHUTDOWN")) {
+	PORT_Assert(secmod_PrivateModuleCount == 0);
+    }
+#endif
+    if (secmod_PrivateModuleCount) {
+    	PORT_SetError(SEC_ERROR_BUSY);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+/*
+ * retrieve the internal module
+ */
+SECMODModule *
+SECMOD_GetInternalModule(void)
+{
+   return internalModule;
+}
+
+
+SECStatus
+secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule)
+{
+    SECMODModuleList *mlp, *newListElement, *last = NULL;
+
+    newListElement = SECMOD_NewModuleListElement();
+    if (newListElement == NULL) {
+	return SECFailure;
+    }
+
+    newListElement->module = SECMOD_ReferenceModule(newModule);
+
+    SECMOD_GetWriteLock(moduleLock);
+    /* Added it to the end (This is very inefficient, but Adding a module
+     * on the fly should happen maybe 2-3 times through the life this program
+     * on a given computer, and this list should be *SHORT*. */
+    for(mlp = *moduleList; mlp != NULL; mlp = mlp->next) {
+	last = mlp;
+    }
+
+    if (last == NULL) {
+	*moduleList = newListElement;
+    } else {
+	SECMOD_AddList(last,newListElement,NULL);
+    }
+    SECMOD_ReleaseWriteLock(moduleLock);
+    return SECSuccess;
+}
+
+SECStatus
+SECMOD_AddModuleToList(SECMODModule *newModule)
+{
+    if (newModule->internal && !internalModule) {
+	internalModule = SECMOD_ReferenceModule(newModule);
+    }
+    return secmod_AddModuleToList(&modules,newModule);
+}
+
+SECStatus
+SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule)
+{
+    if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) {
+	SECMOD_DestroyModule(defaultDBModule);
+	defaultDBModule = SECMOD_ReferenceModule(newModule);
+    } else if (defaultDBModule == NULL) {
+	defaultDBModule = SECMOD_ReferenceModule(newModule);
+    }
+    return secmod_AddModuleToList(&modulesDB,newModule);
+}
+
+SECStatus
+SECMOD_AddModuleToUnloadList(SECMODModule *newModule)
+{
+    return secmod_AddModuleToList(&modulesUnload,newModule);
+}
+
+/*
+ * get the list of PKCS11 modules that are available.
+ */
+SECMODModuleList * SECMOD_GetDefaultModuleList() { return modules; }
+SECMODModuleList *SECMOD_GetDeadModuleList() { return modulesUnload; }
+SECMODModuleList *SECMOD_GetDBModuleList() { return modulesDB; }
+
+/*
+ * This lock protects the global module lists.
+ * it also protects changes to the slot array (module->slots[]) and slot count 
+ * (module->slotCount) in each module. It is a read/write lock with multiple 
+ * readers or one writer. Writes are uncommon. 
+ * Because of legacy considerations protection of the slot array and count is 
+ * only necessary in applications if the application calls 
+ * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new
+ * applications are encouraged to acquire this lock when reading the
+ * slot array information directly.
+ */
+SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; }
+
+
+
+/*
+ * find a module by name, and add a reference to it.
+ * return that module.
+ */
+SECMODModule *
+SECMOD_FindModule(const char *name)
+{
+    SECMODModuleList *mlp;
+    SECMODModule *module = NULL;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return module;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    for(mlp = modules; mlp != NULL; mlp = mlp->next) {
+	if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
+	    module = mlp->module;
+	    SECMOD_ReferenceModule(module);
+	    break;
+	}
+    }
+    if (module) {
+	goto found;
+    }
+    for(mlp = modulesUnload; mlp != NULL; mlp = mlp->next) {
+	if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
+	    module = mlp->module;
+	    SECMOD_ReferenceModule(module);
+	    break;
+	}
+    }
+
+found:
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    return module;
+}
+
+/*
+ * find a module by ID, and add a reference to it.
+ * return that module.
+ */
+SECMODModule *
+SECMOD_FindModuleByID(SECMODModuleID id) 
+{
+    SECMODModuleList *mlp;
+    SECMODModule *module = NULL;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return module;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    for(mlp = modules; mlp != NULL; mlp = mlp->next) {
+	if (id == mlp->module->moduleID) {
+	    module = mlp->module;
+	    SECMOD_ReferenceModule(module);
+	    break;
+	}
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+    if (module == NULL) {
+	PORT_SetError(SEC_ERROR_NO_MODULE);
+    }
+    return module;
+}
+
+/*
+ * find the function pointer.
+ */
+SECMODModule *
+secmod_FindModuleByFuncPtr(void *funcPtr) 
+{
+    SECMODModuleList *mlp;
+    SECMODModule *module = NULL;
+
+    SECMOD_GetReadLock(moduleLock);
+    for(mlp = modules; mlp != NULL; mlp = mlp->next) {
+	/* paranoia, shouldn't ever happen */
+	if (!mlp->module) {
+	    continue;
+	}
+	if (funcPtr == mlp->module->functionList) {
+	    module = mlp->module;
+	    SECMOD_ReferenceModule(module);
+	    break;
+	}
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+    if (module == NULL) {
+	PORT_SetError(SEC_ERROR_NO_MODULE);
+    }
+    return module;
+}
+
+/*
+ * Find the Slot based on ID and the module.
+ */
+PK11SlotInfo *
+SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID)
+{
+    int i;
+    PK11SlotInfo *slot = NULL;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return slot;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    for (i=0; i < module->slotCount; i++) {
+	PK11SlotInfo *cSlot = module->slots[i];
+
+	if (cSlot->slotID == slotID) {
+	    slot = PK11_ReferenceSlot(cSlot);
+	    break;
+	}
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    if (slot == NULL) {
+	PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
+    }
+    return slot;
+}
+
+/*
+ * lookup the Slot module based on it's module ID and slot ID.
+ */
+PK11SlotInfo *
+SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID) 
+{
+    SECMODModule *module;
+    PK11SlotInfo *slot;
+
+    module = SECMOD_FindModuleByID(moduleID);
+    if (module == NULL) return NULL;
+
+    slot = SECMOD_FindSlotByID(module, slotID);
+    SECMOD_DestroyModule(module);
+    return slot;
+}
+
+
+/*
+ * find a module by name or module pointer and delete it off the module list.
+ * optionally remove it from secmod.db.
+ */
+SECStatus
+SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod, 
+						int *type, PRBool permdb) 
+{
+    SECMODModuleList *mlp;
+    SECMODModuleList **mlpp;
+    SECStatus rv = SECFailure;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return rv;
+    }
+
+    *type = SECMOD_EXTERNAL;
+
+    SECMOD_GetWriteLock(moduleLock);
+    for (mlpp = &modules,mlp = modules; 
+				mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
+	if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
+							mod == mlp->module) {
+	    /* don't delete the internal module */
+	    if (!mlp->module->internal) {
+		SECMOD_RemoveList(mlpp,mlp);
+		/* delete it after we release the lock */
+		rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
+	    } else if (mlp->module->isFIPS) {
+		*type = SECMOD_FIPS;
+	    } else {
+		*type = SECMOD_INTERNAL;
+	    }
+	    break;
+	}
+    }
+    if (mlp) {
+	goto found;
+    }
+    /* not on the internal list, check the unload list */
+    for (mlpp = &modulesUnload,mlp = modulesUnload; 
+				mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
+	if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
+							mod == mlp->module) {
+	    /* don't delete the internal module */
+	    if (!mlp->module->internal) {
+		SECMOD_RemoveList(mlpp,mlp);
+		rv = SECSuccess;
+	    } else if (mlp->module->isFIPS) {
+		*type = SECMOD_FIPS;
+	    } else {
+		*type = SECMOD_INTERNAL;
+	    }
+	    break;
+	}
+    }
+found:
+    SECMOD_ReleaseWriteLock(moduleLock);
+
+
+    if (rv == SECSuccess) {
+	if (permdb) {
+ 	    SECMOD_DeletePermDB(mlp->module);
+	}
+	SECMOD_DestroyModuleListElement(mlp);
+    }
+    return rv;
+}
+
+/*
+ * find a module by name and delete it off the module list
+ */
+SECStatus
+SECMOD_DeleteModule(const char *name, int *type) 
+{
+    return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE);
+}
+
+/*
+ * find a module by name and delete it off the module list
+ */
+SECStatus
+SECMOD_DeleteInternalModule(const char *name) 
+{
+    SECMODModuleList *mlp;
+    SECMODModuleList **mlpp;
+    SECStatus rv = SECFailure;
+
+    if (pendingModule) {
+	PORT_SetError(SEC_ERROR_MODULE_STUCK);
+	return rv;
+    }
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return rv;
+    }
+
+    SECMOD_GetWriteLock(moduleLock);
+    for(mlpp = &modules,mlp = modules; 
+				mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
+	if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
+	    /* don't delete the internal module */
+	    if (mlp->module->internal) {
+		SECMOD_RemoveList(mlpp,mlp);
+		rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
+	    } 
+	    break;
+	}
+    }
+    SECMOD_ReleaseWriteLock(moduleLock);
+
+    if (rv == SECSuccess) {
+	SECMODModule *newModule,*oldModule;
+
+	if (mlp->module->isFIPS) {
+    	    newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME,
+				NULL, SECMOD_INT_FLAGS);
+	} else {
+    	    newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME,
+				NULL, SECMOD_FIPS_FLAGS);
+	}
+	if (newModule) {
+	    newModule->libraryParams = 
+	     PORT_ArenaStrdup(newModule->arena,mlp->module->libraryParams);
+	    rv = SECMOD_AddModule(newModule);
+	    if (rv != SECSuccess) {
+		SECMOD_DestroyModule(newModule);
+		newModule = NULL;
+	    }
+	}
+	if (newModule == NULL) {
+	    SECMODModuleList *last = NULL,*mlp2;
+	   /* we're in pretty deep trouble if this happens...Security
+	    * not going to work well... try to put the old module back on
+	    * the list */
+	   SECMOD_GetWriteLock(moduleLock);
+	   for(mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) {
+		last = mlp2;
+	   }
+
+	   if (last == NULL) {
+		modules = mlp;
+	   } else {
+		SECMOD_AddList(last,mlp,NULL);
+	   }
+	   SECMOD_ReleaseWriteLock(moduleLock);
+	   return SECFailure; 
+	}
+	pendingModule = oldModule = internalModule;
+	internalModule = NULL;
+	SECMOD_DestroyModule(oldModule);
+ 	SECMOD_DeletePermDB(mlp->module);
+	SECMOD_DestroyModuleListElement(mlp);
+	internalModule = newModule; /* adopt the module */
+    }
+    return rv;
+}
+
+SECStatus
+SECMOD_AddModule(SECMODModule *newModule) 
+{
+    SECStatus rv;
+    SECMODModule *oldModule;
+
+    /* Test if a module w/ the same name already exists */
+    /* and return SECWouldBlock if so. */
+    /* We should probably add a new return value such as */
+    /* SECDublicateModule, but to minimize ripples, I'll */
+    /* give SECWouldBlock a new meaning */
+    if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) {
+	SECMOD_DestroyModule(oldModule);
+        return SECWouldBlock;
+        /* module already exists. */
+    }
+
+    rv = secmod_LoadPKCS11Module(newModule, NULL);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+
+    if (newModule->parent == NULL) {
+	newModule->parent = SECMOD_ReferenceModule(defaultDBModule);
+    }
+
+    SECMOD_AddPermDB(newModule);
+    SECMOD_AddModuleToList(newModule);
+
+    rv = STAN_AddModuleToDefaultTrustDomain(newModule);
+
+    return rv;
+}
+
+PK11SlotInfo *
+SECMOD_FindSlot(SECMODModule *module,const char *name) 
+{
+    int i;
+    char *string;
+    PK11SlotInfo *retSlot = NULL;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return retSlot;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    for (i=0; i < module->slotCount; i++) {
+	PK11SlotInfo *slot = module->slots[i];
+
+	if (PK11_IsPresent(slot)) {
+	    string = PK11_GetTokenName(slot);
+	} else {
+	    string = PK11_GetSlotName(slot);
+	}
+	if (PORT_Strcmp(name,string) == 0) {
+	    retSlot = PK11_ReferenceSlot(slot);
+	    break;
+	}
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+
+    if (retSlot == NULL) {
+	PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
+    }
+    return retSlot;
+}
+
+SECStatus
+PK11_GetModInfo(SECMODModule *mod,CK_INFO *info)
+{
+    CK_RV crv;
+
+    if (mod->functionList == NULL) return SECFailure;
+    crv = PK11_GETTAB(mod)->C_GetInfo(info);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+    }	
+    return (crv == CKR_OK) ? SECSuccess : SECFailure;
+}
+
+/* Determine if we have the FIP's module loaded as the default
+ * module to trigger other bogus FIPS requirements in PKCS #12 and
+ * SSL
+ */
+PRBool
+PK11_IsFIPS(void)
+{
+    SECMODModule *mod = SECMOD_GetInternalModule();
+
+    if (mod && mod->internal) {
+	return mod->isFIPS;
+    }
+
+    return PR_FALSE;
+}
+
+/* combines NewModule() & AddModule */
+/* give a string for the module name & the full-path for the dll, */
+/* installs the PKCS11 module & update registry */
+SECStatus 
+SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath,
+                              unsigned long defaultMechanismFlags,
+                              unsigned long cipherEnableFlags,
+                              char* modparms, char* nssparms)
+{
+    SECMODModule *module;
+    SECStatus result = SECFailure;
+    int s,i;
+    PK11SlotInfo* slot;
+
+    PR_SetErrorText(0, NULL);
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return result;
+    }
+
+    module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms);
+
+    if (module == NULL) {
+	return result;
+    }
+
+    if (module->dllName != NULL) {
+        if (module->dllName[0] != 0) {
+            result = SECMOD_AddModule(module);
+            if (result == SECSuccess) {
+                /* turn on SSL cipher enable flags */
+                module->ssl[0] = cipherEnableFlags;
+
+ 		SECMOD_GetReadLock(moduleLock);
+                /* check each slot to turn on appropriate mechanisms */
+                for (s = 0; s < module->slotCount; s++) {
+                    slot = (module->slots)[s];
+                    /* for each possible mechanism */
+                    for (i=0; i < num_pk11_default_mechanisms; i++) {
+                        /* we are told to turn it on by default ? */
+			PRBool add = 
+			 (PK11_DefaultArray[i].flag & defaultMechanismFlags) ?
+						PR_TRUE: PR_FALSE;
+                        result = PK11_UpdateSlotAttribute(slot, 
+					&(PK11_DefaultArray[i]),  add);
+                    } /* for each mechanism */
+                    /* disable each slot if the defaultFlags say so */
+                    if (defaultMechanismFlags & PK11_DISABLE_FLAG) {
+                        PK11_UserDisableSlot(slot);
+                    }
+                } /* for each slot of this module */
+ 		SECMOD_ReleaseReadLock(moduleLock);
+
+                /* delete and re-add module in order to save changes 
+		 * to the module */
+		result = SECMOD_UpdateModule(module);
+            }
+        }
+    }
+    SECMOD_DestroyModule(module);
+    return result;
+}
+
+SECStatus 
+SECMOD_AddNewModule(const char* moduleName, const char* dllPath,
+                              unsigned long defaultMechanismFlags,
+                              unsigned long cipherEnableFlags)
+{
+    return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags,
+                  cipherEnableFlags, 
+                  NULL, NULL); /* don't pass module or nss params */
+}
+
+SECStatus 
+SECMOD_UpdateModule(SECMODModule *module)
+{
+    SECStatus result;
+
+    result = SECMOD_DeletePermDB(module);
+                
+    if (result == SECSuccess) {          
+	result = SECMOD_AddPermDB(module);
+    }
+    return result;
+}
+
+/* Public & Internal(Security Library)  representation of
+ * encryption mechanism flags conversion */
+
+/* Currently, the only difference is that internal representation 
+ * puts RANDOM_FLAG at bit 31 (Most-significant bit), but
+ * public representation puts this bit at bit 28
+ */
+unsigned long 
+SECMOD_PubMechFlagstoInternal(unsigned long publicFlags)
+{
+    unsigned long internalFlags = publicFlags;
+
+    if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) {
+        internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG;
+        internalFlags |= SECMOD_RANDOM_FLAG;
+    }
+    return internalFlags;
+}
+
+unsigned long 
+SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) 
+{
+    unsigned long publicFlags = internalFlags;
+
+    if (internalFlags & SECMOD_RANDOM_FLAG) {
+        publicFlags &= ~SECMOD_RANDOM_FLAG;
+        publicFlags |= PUBLIC_MECH_RANDOM_FLAG;
+    }
+    return publicFlags;
+}
+
+
+/* Public & Internal(Security Library)  representation of */
+/* cipher flags conversion */
+/* Note: currently they are just stubs */
+unsigned long 
+SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) 
+{
+    return publicFlags;
+}
+
+unsigned long 
+SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) 
+{
+    return internalFlags;
+}
+
+/* Funtion reports true if module of modType is installed/configured */
+PRBool 
+SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags )
+{
+    PRBool result = PR_FALSE;
+    SECMODModuleList *mods;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return result;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    mods = SECMOD_GetDefaultModuleList();
+    for ( ; mods != NULL; mods = mods->next) {
+        if (mods->module->ssl[0] & 
+		SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) {
+            result = PR_TRUE;
+        }
+    }
+
+    SECMOD_ReleaseReadLock(moduleLock);
+    return result;
+}
+
+/* create a new ModuleListElement */
+SECMODModuleList *SECMOD_NewModuleListElement(void) 
+{
+    SECMODModuleList *newModList;
+
+    newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList));
+    if (newModList) {
+	newModList->next = NULL;
+	newModList->module = NULL;
+    }
+    return newModList;
+}
+
+/*
+ * make a new reference to a module so It doesn't go away on us
+ */
+SECMODModule *
+SECMOD_ReferenceModule(SECMODModule *module) 
+{
+    PZ_Lock(module->refLock);
+    PORT_Assert(module->refCount > 0);
+
+    module->refCount++;
+    PZ_Unlock(module->refLock);
+    return module;
+}
+
+
+/* destroy an existing module */
+void
+SECMOD_DestroyModule(SECMODModule *module) 
+{
+    PRBool willfree = PR_FALSE;
+    int slotCount;
+    int i;
+
+    PZ_Lock(module->refLock);
+    if (module->refCount-- == 1) {
+	willfree = PR_TRUE;
+    }
+    PORT_Assert(willfree || (module->refCount > 0));
+    PZ_Unlock(module->refLock);
+
+    if (!willfree) {
+	return;
+    }
+   
+    if (module->parent != NULL) {
+	SECMODModule *parent = module->parent;
+	/* paranoia, don't loop forever if the modules are looped */
+	module->parent = NULL;
+	SECMOD_DestroyModule(parent);
+    }
+
+    /* slots can't really disappear until our module starts freeing them,
+     * so this check is safe */
+    slotCount = module->slotCount;
+    if (slotCount == 0) {
+	SECMOD_SlotDestroyModule(module,PR_FALSE);
+	return;
+    }
+
+    /* now free all out slots, when they are done, they will cause the
+     * module to disappear altogether */
+    for (i=0 ; i < slotCount; i++) {
+	if (!module->slots[i]->disabled) {
+		PK11_ClearSlotList(module->slots[i]);
+	}
+	PK11_FreeSlot(module->slots[i]);
+    }
+    /* WARNING: once the last slot has been freed is it possible (even likely)
+     * that module is no more... touching it now is a good way to go south */
+}
+
+
+/* we can only get here if we've destroyed the module, or some one has
+ * erroneously freed a slot that wasn't referenced. */
+void
+SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) 
+{
+    PRBool willfree = PR_FALSE;
+    if (fromSlot) {
+        PORT_Assert(module->refCount == 0);
+	PZ_Lock(module->refLock);
+	if (module->slotCount-- == 1) {
+	    willfree = PR_TRUE;
+	}
+	PORT_Assert(willfree || (module->slotCount > 0));
+	PZ_Unlock(module->refLock);
+        if (!willfree) return;
+    }
+
+    if (module == pendingModule) {
+	pendingModule = NULL;
+    }
+
+    if (module->loaded) {
+	SECMOD_UnloadModule(module);
+    }
+    PZ_DestroyLock(module->refLock);
+    PORT_FreeArena(module->arena,PR_FALSE);
+    secmod_PrivateModuleCount--;
+}
+
+/* destroy a list element
+ * this destroys a single element, and returns the next element
+ * on the chain. It makes it easy to implement for loops to delete
+ * the chain. It also make deleting a single element easy */
+SECMODModuleList *
+SECMOD_DestroyModuleListElement(SECMODModuleList *element) 
+{
+    SECMODModuleList *next = element->next;
+
+    if (element->module) {
+	SECMOD_DestroyModule(element->module);
+	element->module = NULL;
+    }
+    PORT_Free(element);
+    return next;
+}
+
+
+/*
+ * Destroy an entire module list
+ */
+void
+SECMOD_DestroyModuleList(SECMODModuleList *list) 
+{
+    SECMODModuleList *lp;
+
+    for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ;
+}
+
+PRBool
+SECMOD_CanDeleteInternalModule(void)
+{
+    return (PRBool) (pendingModule == NULL);
+}
+
+/*
+ * check to see if the module has added new slots. PKCS 11 v2.20 allows for
+ * modules to add new slots, but never remove them. Slots cannot be added 
+ * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent
+ * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently
+ * grow on the caller. It is permissible for the slots to increase between
+ * successive calls with NULL to get the size.
+ */
+SECStatus
+SECMOD_UpdateSlotList(SECMODModule *mod)
+{
+    CK_RV crv;
+    CK_ULONG count;
+    CK_ULONG i, oldCount;
+    PRBool freeRef = PR_FALSE;
+    void *mark = NULL;
+    CK_ULONG *slotIDs = NULL;
+    PK11SlotInfo **newSlots = NULL;
+    PK11SlotInfo **oldSlots = NULL;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return SECFailure;
+    }
+
+    /* C_GetSlotList is not a session function, make sure 
+     * calls are serialized */
+    PZ_Lock(mod->refLock);
+    freeRef = PR_TRUE;
+    /* see if the number of slots have changed */
+    crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	goto loser;
+    }
+    /* nothing new, blow out early, we want this function to be quick
+     * and cheap in the normal case  */
+    if (count == mod->slotCount) {
+ 	PZ_Unlock(mod->refLock);
+	return SECSuccess;
+    }
+    if (count < (CK_ULONG)mod->slotCount) {
+	/* shouldn't happen with a properly functioning PKCS #11 module */
+	PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 );
+	goto loser;
+    }
+
+    /* get the new slot list */
+    slotIDs = PORT_NewArray(CK_SLOT_ID, count);
+    if (slotIDs == NULL) {
+	goto loser;
+    }
+
+    crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count);
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	goto loser;
+    }
+    freeRef = PR_FALSE;
+    PZ_Unlock(mod->refLock);
+    mark = PORT_ArenaMark(mod->arena);
+    if (mark == NULL) {
+	goto loser;
+    }
+    newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count);
+
+    /* walk down the new slot ID list returned from the module. We keep
+     * the old slots which match a returned ID, and we initialize the new 
+     * slots. */
+    for (i=0; i < count; i++) {
+	PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]);
+
+	if (!slot) {
+	    /* we have a new slot create a new slot data structure */
+	    slot = PK11_NewSlotInfo(mod);
+	    if (!slot) {
+		goto loser;
+	    }
+	    PK11_InitSlot(mod, slotIDs[i], slot);
+	    STAN_InitTokenForSlotInfo(NULL, slot);
+	}
+	newSlots[i] = slot;
+    }
+    STAN_ResetTokenInterator(NULL);
+    PORT_Free(slotIDs);
+    slotIDs = NULL;
+    PORT_ArenaUnmark(mod->arena, mark);
+
+    /* until this point we're still using the old slot list. Now we update
+     * module slot list. We update the slots (array) first then the count, 
+     * since we've already guarrenteed that count has increased (just in case 
+     * someone is looking at the slots field of  module without holding the 
+     * moduleLock */
+    SECMOD_GetWriteLock(moduleLock);
+    oldCount =mod->slotCount;
+    oldSlots = mod->slots;
+    mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is
+			    * allocated out of the module arena and won't
+			    * be freed until the module is freed */
+    mod->slotCount = count;
+    SECMOD_ReleaseWriteLock(moduleLock);
+    /* free our old references before forgetting about oldSlot*/
+    for (i=0; i < oldCount; i++) {
+	PK11_FreeSlot(oldSlots[i]);
+    }
+    return SECSuccess;
+
+loser:
+    if (freeRef) {
+	PZ_Unlock(mod->refLock);
+    }
+    if (slotIDs) {
+	PORT_Free(slotIDs);
+    }
+    /* free all the slots we allocated. newSlots are part of the
+     * mod arena. NOTE: the newSlots array contain both new and old
+     * slots, but we kept a reference to the old slots when we built the new
+     * array, so we need to free all the slots in newSlots array. */
+    if (newSlots) {
+	for (i=0; i < count; i++) {
+	    if (newSlots[i] == NULL) {
+		break; /* hit the last one */
+	    }
+	    PK11_FreeSlot(newSlots[i]);
+	}
+    }
+    /* must come after freeing newSlots */
+    if (mark) {
+ 	PORT_ArenaRelease(mod->arena, mark);
+    }
+    return SECFailure;
+}
+
+/*
+ * this handles modules that do not support C_WaitForSlotEvent().
+ * The internal flags are stored. Note that C_WaitForSlotEvent() does not
+ * have a timeout, so we don't have one for handleWaitForSlotEvent() either.
+ */
+PK11SlotInfo *
+secmod_HandleWaitForSlotEvent(SECMODModule *mod,  unsigned long flags,
+						PRIntervalTime latency)
+{
+    PRBool removableSlotsFound = PR_FALSE;
+    int i;
+    int error = SEC_ERROR_NO_EVENT;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return NULL;
+    }
+    PZ_Lock(mod->refLock);
+    if (mod->evControlMask & SECMOD_END_WAIT) {
+	mod->evControlMask &= ~SECMOD_END_WAIT;
+	PZ_Unlock(mod->refLock);
+	PORT_SetError(SEC_ERROR_NO_EVENT);
+	return NULL;
+    }
+    mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT;
+    while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) {
+	PZ_Unlock(mod->refLock);
+	/* now is a good time to see if new slots have been added */
+	SECMOD_UpdateSlotList(mod);
+
+	/* loop through all the slots on a module */
+	SECMOD_GetReadLock(moduleLock);
+	for (i=0; i < mod->slotCount; i++) {
+	    PK11SlotInfo *slot = mod->slots[i];
+	    uint16 series;
+	    PRBool present;
+
+	    /* perm modules do not change */
+	    if (slot->isPerm) {
+		continue;
+	    }
+	    removableSlotsFound = PR_TRUE;
+	    /* simulate the PKCS #11 module flags. are the flags different
+	     * from the last time we called? */
+	    series = slot->series;
+	    present = PK11_IsPresent(slot);
+	    if ((slot->flagSeries != series) || (slot->flagState != present)) {
+		slot->flagState = present;
+		slot->flagSeries = series;
+		SECMOD_ReleaseReadLock(moduleLock);
+		PZ_Lock(mod->refLock);
+		mod->evControlMask &= ~SECMOD_END_WAIT;
+		PZ_Unlock(mod->refLock);
+		return PK11_ReferenceSlot(slot);
+	    }
+	}
+	SECMOD_ReleaseReadLock(moduleLock);
+	/* if everything was perm modules, don't lock up forever */
+	if (!removableSlotsFound) {
+	    error =SEC_ERROR_NO_SLOT_SELECTED;
+	    PZ_Lock(mod->refLock);
+	    break;
+	}
+	if (flags & CKF_DONT_BLOCK) {
+	    PZ_Lock(mod->refLock);
+	    break;
+	}
+	PR_Sleep(latency);
+ 	PZ_Lock(mod->refLock);
+    }
+    mod->evControlMask &= ~SECMOD_END_WAIT;
+    PZ_Unlock(mod->refLock);
+    PORT_SetError(error);
+    return NULL;
+}
+
+/*
+ * this function waits for a token event on any slot of a given module
+ * This function should not be called from more than one thread of the
+ * same process (though other threads can make other library calls
+ * on this module while this call is blocked).
+ */
+PK11SlotInfo *
+SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags,
+						 PRIntervalTime latency)
+{
+    CK_SLOT_ID id;
+    CK_RV crv;
+    PK11SlotInfo *slot;
+
+    if (!pk11_getFinalizeModulesOption() ||
+        ((mod->cryptokiVersion.major == 2) &&
+         (mod->cryptokiVersion.minor < 1))) { 
+        /* if we are sharing the module with other software in our
+         * address space, we can't reliably use C_WaitForSlotEvent(),
+         * and if the module is version 2.0, C_WaitForSlotEvent() doesn't
+         * exist */
+	return secmod_HandleWaitForSlotEvent(mod, flags, latency);
+    }
+    /* first the the PKCS #11 call */
+    PZ_Lock(mod->refLock);
+    if (mod->evControlMask & SECMOD_END_WAIT) {
+	goto end_wait;
+    }
+    mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT;
+    PZ_Unlock(mod->refLock);
+    crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL);
+    PZ_Lock(mod->refLock);
+    mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT;
+    /* if we are in end wait, short circuit now, don't even risk
+     * going into secmod_HandleWaitForSlotEvent */
+    if (mod->evControlMask & SECMOD_END_WAIT) {
+	goto end_wait;
+    }
+    PZ_Unlock(mod->refLock);
+    if (crv == CKR_FUNCTION_NOT_SUPPORTED) {
+	/* module doesn't support that call, simulate it */
+	return secmod_HandleWaitForSlotEvent(mod, flags, latency);
+    }
+    if (crv != CKR_OK) {
+	/* we can get this error if finalize was called while we were
+	 * still running. This is the only way to force a C_WaitForSlotEvent()
+	 * to return in PKCS #11. In this case, just return that there
+	 * was no event. */
+	if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) {
+	    PORT_SetError(SEC_ERROR_NO_EVENT);
+	} else {
+	    PORT_SetError(PK11_MapError(crv));
+	}
+	return NULL;
+    }
+    slot = SECMOD_FindSlotByID(mod, id);
+    if (slot == NULL) {
+	/* possibly a new slot that was added? */
+	SECMOD_UpdateSlotList(mod);
+	slot = SECMOD_FindSlotByID(mod, id);
+    }
+    /* if we are in the delay period for the "isPresent" call, reset
+     * the delay since we know things have probably changed... */
+    if (slot && slot->nssToken && slot->nssToken->slot) {
+	nssSlot_ResetDelay(slot->nssToken->slot);
+    }
+    return slot;
+
+    /* must be called with the lock on. */
+end_wait:
+    mod->evControlMask &= ~SECMOD_END_WAIT;
+    PZ_Unlock(mod->refLock);
+    PORT_SetError(SEC_ERROR_NO_EVENT);
+    return NULL;
+}
+
+/*
+ * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic
+ * function, possibly bringing down the pkcs #11 module in question. This
+ * should be OK because 1) it does reinitialize, and 2) it should only be
+ * called when we are on our way to tear the whole system down anyway.
+ */
+SECStatus
+SECMOD_CancelWait(SECMODModule *mod)
+{
+    unsigned long controlMask = mod->evControlMask;
+    SECStatus rv = SECSuccess;
+    CK_RV crv;
+
+    PZ_Lock(mod->refLock);
+    mod->evControlMask |= SECMOD_END_WAIT;
+    controlMask = mod->evControlMask;
+    if (controlMask & SECMOD_WAIT_PKCS11_EVENT) {
+        if (!pk11_getFinalizeModulesOption()) {
+            /* can't get here unless pk11_getFinalizeModulesOption is set */
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            rv = SECFailure;
+            goto loser;
+        }
+	/* NOTE: this call will drop all transient keys, in progress
+	 * operations, and any authentication. This is the only documented
+	 * way to get WaitForSlotEvent to return. Also note: for non-thread
+	 * safe tokens, we need to hold the module lock, this is not yet at
+	 * system shutdown/startup time, so we need to protect these calls */
+	crv = PK11_GETTAB(mod)->C_Finalize(NULL);
+	/* ok, we slammed the module down, now we need to reinit it in case
+	 * we intend to use it again */
+	if (CKR_OK == crv) {
+            PRBool alreadyLoaded;
+	    secmod_ModuleInit(mod, NULL, &alreadyLoaded);
+	} else {
+	    /* Finalized failed for some reason,  notify the application
+	     * so maybe it has a prayer of recovering... */
+	    PORT_SetError(PK11_MapError(crv));
+	    rv = SECFailure;
+	}
+    } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) {
+	mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; 
+				/* Simulated events will eventually timeout
+				 * and wake up in the loop */
+    }
+loser:
+    PZ_Unlock(mod->refLock);
+    return rv;
+}
+
+/*
+ * check to see if the module has removable slots that we may need to
+ * watch for.
+ */
+PRBool
+SECMOD_HasRemovableSlots(SECMODModule *mod)
+{
+    int i;
+    PRBool ret = PR_FALSE;
+
+    if (!moduleLock) {
+    	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+	return ret;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    for (i=0; i < mod->slotCount; i++) {
+	PK11SlotInfo *slot = mod->slots[i];
+	/* perm modules are not inserted or removed */
+	if (slot->isPerm) {
+	    continue;
+	}
+	ret = PR_TRUE;
+	break;
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+    return ret;
+}
+
+/*
+ * helper function to actually create and destroy user defined slots
+ */
+static SECStatus
+secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass, 
+		const char *sendSpec)
+{
+    CK_OBJECT_HANDLE dummy;
+    CK_ATTRIBUTE template[2] ;
+    CK_ATTRIBUTE *attrs = template;
+    CK_RV crv;
+
+    PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++;
+    PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec,
+					 strlen(sendSpec)+1); attrs++;
+
+    PORT_Assert(attrs-template <= 2);
+
+
+    PK11_EnterSlotMonitor(slot);
+    crv = PK11_CreateNewObject(slot, slot->session,
+	template, attrs-template, PR_FALSE, &dummy);
+    PK11_ExitSlotMonitor(slot);
+
+    if (crv != CKR_OK) {
+	PORT_SetError(PK11_MapError(crv));
+	return SECFailure;
+    }
+    return SECMOD_UpdateSlotList(slot->module);
+}
+
+/*
+ * return true if the selected slot ID is not present or doesn't exist
+ */
+static PRBool
+secmod_SlotIsEmpty(SECMODModule *mod,  CK_SLOT_ID slotID)
+{
+    PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID);
+    if (slot) {
+	PRBool present = PK11_IsPresent(slot);
+	PK11_FreeSlot(slot);
+	if (present) {
+	    return PR_FALSE;
+	}
+    }
+    /* it doesn't exist or isn't present, it's available */
+    return PR_TRUE;
+}
+
+/*
+ * Find an unused slot id in module.
+ */
+static CK_SLOT_ID
+secmod_FindFreeSlot(SECMODModule *mod)
+{
+    CK_SLOT_ID i, minSlotID, maxSlotID;
+
+    /* look for a free slot id on the internal module */
+    if (mod->internal && mod->isFIPS) {
+	minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID;
+	maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID;
+    } else {
+	minSlotID = SFTK_MIN_USER_SLOT_ID;
+	maxSlotID = SFTK_MAX_USER_SLOT_ID;
+    }
+    for (i=minSlotID; i < maxSlotID; i++) {
+	if (secmod_SlotIsEmpty(mod,i)) {
+	    return i;
+	}
+    }
+    PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
+    return (CK_SLOT_ID) -1;
+}
+
+/*
+ * Attempt to open a new slot.
+ *
+ * This works the same os OpenUserDB except it can be called against
+ * any module that understands the softoken protocol for opening new
+ * slots, not just the softoken itself. If the selected module does not
+ * understand the protocol, C_CreateObject will fail with 
+ * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set
+ * SEC_ERROR_BAD_DATA.
+ * 
+ * NewSlots can be closed with SECMOD_CloseUserDB();
+ *
+ * Modulespec is module dependent.
+ */
+PK11SlotInfo *
+SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec)
+{
+    CK_SLOT_ID slotID = 0;
+    PK11SlotInfo *slot;
+    char *escSpec;
+    char *sendSpec;
+    SECStatus rv;
+
+    slotID = secmod_FindFreeSlot(mod);
+    if (slotID == (CK_SLOT_ID) -1) {
+	return NULL;
+    }
+
+    if (mod->slotCount == 0) {
+	return NULL;
+    }
+
+    /* just grab the first slot in the module, any present slot should work */
+    slot = PK11_ReferenceSlot(mod->slots[0]);
+    if (slot == NULL) {
+	return NULL;
+    }
+
+    /* we've found the slot, now build the moduleSpec */
+    escSpec = secmod_DoubleEscape(moduleSpec, '>', ']');
+    if (escSpec == NULL) {
+	PK11_FreeSlot(slot);
+	return NULL;
+    }
+    sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec);
+    PORT_Free(escSpec);
+
+    if (sendSpec == NULL) {
+	/* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */
+	PK11_FreeSlot(slot);
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+    rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec);
+    PR_smprintf_free(sendSpec);
+    PK11_FreeSlot(slot);
+    if (rv != SECSuccess) {
+	return NULL;
+    }
+
+    return SECMOD_FindSlotByID(mod, slotID);
+}
+
+/*
+ * Open a new database using the softoken. The caller is responsible for making
+ * sure the module spec is correct and usable. The caller should ask for one
+ * new database per call if the caller wants to get meaningful information 
+ * about the new database.
+ *
+ * moduleSpec is the same data that you would pass to softoken at 
+ * initialization time under the 'tokens' options. For example, if you were
+ * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
+ * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
+ * module spec here. The slot ID will be calculated for you by 
+ * SECMOD_OpenUserDB().
+ *
+ * Typical parameters here are configdir, tokenDescription and flags.
+ *
+ * a Full list is below:
+ *
+ *
+ *  configDir - The location of the databases for this token. If configDir is 
+ *         not specified, and noCertDB and noKeyDB is not specified, the load
+ *         will fail.
+ *   certPrefix - Cert prefix for this token.
+ *   keyPrefix - Prefix for the key database for this token. (if not specified,
+ *         certPrefix will be used).
+ *   tokenDescription - The label value for this token returned in the 
+ *         CK_TOKEN_INFO structure with an internationalize string (UTF8). 
+ *         This value will be truncated at 32 bytes (no NULL, partial UTF8 
+ *         characters dropped). You should specify a user friendly name here
+ *         as this is the value the token will be refered to in most 
+ *         application UI's. You should make sure tokenDescription is unique.
+ *   slotDescription - The slotDescription value for this token returned 
+ *         in the CK_SLOT_INFO structure with an internationalize string 
+ *         (UTF8). This value will be truncated at 64 bytes (no NULL, partial 
+ *         UTF8 characters dropped). This name will not change after the 
+ *         database is closed. It should have some number to make this unique.
+ *   minPWLen - minimum password length for this token.
+ *   flags - comma separated list of flag values, parsed case-insensitive.
+ *         Valid flags are:
+ *              readOnly - Databases should be opened read only.
+ *              noCertDB - Don't try to open a certificate database.
+ *              noKeyDB - Don't try to open a key database.
+ *              forceOpen - Don't fail to initialize the token if the 
+ *                databases could not be opened.
+ *              passwordRequired - zero length passwords are not acceptable 
+ *                (valid only if there is a keyDB).
+ *              optimizeSpace - allocate smaller hash tables and lock tables.
+ *                When this flag is not specified, Softoken will allocate 
+ *                large tables to prevent lock contention. 
+ */
+PK11SlotInfo *
+SECMOD_OpenUserDB(const char *moduleSpec)
+{
+    SECMODModule *mod;
+
+    if (moduleSpec == NULL) {
+	return NULL;
+    }
+
+    /* NOTE: unlike most PK11 function, this does not return a reference
+     * to the module */
+    mod = SECMOD_GetInternalModule();
+    if (!mod) {
+	/* shouldn't happen */
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return NULL;
+    }
+    return SECMOD_OpenNewSlot(mod, moduleSpec);
+}
+
+
+/*
+ * close an already opened user database. NOTE: the database must be
+ * in the internal token, and must be one created with SECMOD_OpenUserDB().
+ * Once the database is closed, the slot will remain as an empty slot
+ * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot().
+ */
+SECStatus
+SECMOD_CloseUserDB(PK11SlotInfo *slot)
+{
+    SECStatus rv;
+    char *sendSpec;
+    
+    sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID);
+    if (sendSpec == NULL) {
+	/* PR_smprintf does not set no memory error */
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec);
+    PR_smprintf_free(sendSpec);
+    return rv;
+}
diff --git a/mozilla/security/nss/lib/pk11wrap/secmod.h b/mozilla/security/nss/lib/pk11wrap/secmod.h
new file mode 100644
index 0000000..4dc930d
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/secmod.h
@@ -0,0 +1,184 @@
+/* ***** 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 ***** */
+#ifndef _SECMOD_H_
+#define _SEDMOD_H_
+#include "seccomon.h"
+#include "secmodt.h"
+#include "prinrval.h"
+
+/* These mechanisms flags are visible to all other libraries. */
+/* They must be converted to internal SECMOD_*_FLAG */
+/* if used inside the functions of the security library */
+#define PUBLIC_MECH_RSA_FLAG         0x00000001ul
+#define PUBLIC_MECH_DSA_FLAG         0x00000002ul
+#define PUBLIC_MECH_RC2_FLAG         0x00000004ul
+#define PUBLIC_MECH_RC4_FLAG         0x00000008ul
+#define PUBLIC_MECH_DES_FLAG         0x00000010ul
+#define PUBLIC_MECH_DH_FLAG          0x00000020ul
+#define PUBLIC_MECH_FORTEZZA_FLAG    0x00000040ul
+#define PUBLIC_MECH_RC5_FLAG         0x00000080ul
+#define PUBLIC_MECH_SHA1_FLAG        0x00000100ul
+#define PUBLIC_MECH_MD5_FLAG         0x00000200ul
+#define PUBLIC_MECH_MD2_FLAG         0x00000400ul
+#define PUBLIC_MECH_SSL_FLAG         0x00000800ul
+#define PUBLIC_MECH_TLS_FLAG         0x00001000ul
+#define PUBLIC_MECH_AES_FLAG         0x00002000ul
+#define PUBLIC_MECH_SHA256_FLAG      0x00004000ul
+#define PUBLIC_MECH_SHA512_FLAG      0x00008000ul
+#define PUBLIC_MECH_CAMELLIA_FLAG    0x00010000ul
+#define PUBLIC_MECH_SEED_FLAG        0x00020000ul
+
+#define PUBLIC_MECH_RANDOM_FLAG      0x08000000ul
+#define PUBLIC_MECH_FRIENDLY_FLAG    0x10000000ul
+#define PUBLIC_OWN_PW_DEFAULTS       0X20000000ul
+#define PUBLIC_DISABLE_FLAG          0x40000000ul
+
+/* warning: reserved means reserved */
+#define PUBLIC_MECH_RESERVED_FLAGS   0x87FF0000ul
+
+/* These cipher flags are visible to all other libraries, */
+/* But they must be converted before used in functions */
+/* withing the security module */
+#define PUBLIC_CIPHER_FORTEZZA_FLAG  0x00000001ul
+
+/* warning: reserved means reserved */
+#define PUBLIC_CIPHER_RESERVED_FLAGS 0xFFFFFFFEul
+
+SEC_BEGIN_PROTOS
+
+/*
+ * the following functions are going to be deprecated in NSS 4.0 in
+ * favor of the new stan functions.
+ */
+
+/* Initialization */
+extern SECMODModule *SECMOD_LoadModule(char *moduleSpec,SECMODModule *parent,
+							PRBool recurse);
+
+extern SECMODModule *SECMOD_LoadUserModule(char *moduleSpec,SECMODModule *parent,
+							PRBool recurse);
+
+SECStatus SECMOD_UnloadUserModule(SECMODModule *mod);
+
+SECMODModule * SECMOD_CreateModule(const char *lib, const char *name,
+					const char *param, const char *nss);
+
+
+/* Module Management */
+char **SECMOD_GetModuleSpecList(SECMODModule *module);
+SECStatus SECMOD_FreeModuleSpecList(SECMODModule *module,char **moduleSpecList);
+
+ 
+/* protoypes */
+/* Get a list of active PKCS #11 modules */
+extern SECMODModuleList *SECMOD_GetDefaultModuleList(void); 
+/* Get a list of defined but not loaded PKCS #11 modules */
+extern SECMODModuleList *SECMOD_GetDeadModuleList(void);
+/* Get a list of Modules which define PKCS #11 modules to load */
+extern SECMODModuleList *SECMOD_GetDBModuleList(void);
+
+/* lock to protect all three module lists above */
+extern SECMODListLock *SECMOD_GetDefaultModuleListLock(void);
+
+extern SECStatus SECMOD_UpdateModule(SECMODModule *module);
+
+/* lock management */
+extern void SECMOD_GetReadLock(SECMODListLock *);
+extern void SECMOD_ReleaseReadLock(SECMODListLock *);
+
+/* Operate on modules by name */
+extern SECMODModule *SECMOD_FindModule(const char *name);
+extern SECStatus SECMOD_DeleteModule(const char *name, int *type);
+extern SECStatus SECMOD_DeleteModuleEx(const char * name, 
+                                       SECMODModule *mod, 
+                                       int *type, 
+                                       PRBool permdb);
+extern SECStatus SECMOD_DeleteInternalModule(const char *name);
+extern PRBool SECMOD_CanDeleteInternalModule(void);
+extern SECStatus SECMOD_AddNewModule(const char* moduleName, 
+			      const char* dllPath,
+                              unsigned long defaultMechanismFlags,
+                              unsigned long cipherEnableFlags);
+extern SECStatus SECMOD_AddNewModuleEx(const char* moduleName,
+			      const char* dllPath,
+                              unsigned long defaultMechanismFlags,
+                              unsigned long cipherEnableFlags,
+                              char* modparms,
+                              char* nssparms);
+
+/* database/memory management */
+extern SECMODModule *SECMOD_GetInternalModule(void);
+extern SECMODModule *SECMOD_ReferenceModule(SECMODModule *module);
+extern void SECMOD_DestroyModule(SECMODModule *module);
+extern PK11SlotInfo *SECMOD_LookupSlot(SECMODModuleID module,
+							unsigned long slotID);
+extern PK11SlotInfo *SECMOD_FindSlot(SECMODModule *module,const char *name);
+
+/* Funtion reports true if at least one of the modules */
+/* of modType has been installed */
+PRBool SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags );
+
+/* accessors */
+PRBool SECMOD_GetSkipFirstFlag(SECMODModule *mod);
+PRBool SECMOD_GetDefaultModDBFlag(SECMODModule *mod);
+
+/* Functions used to convert between internal & public representation
+ * of Mechanism Flags and Cipher Enable Flags */
+extern unsigned long SECMOD_PubMechFlagstoInternal(unsigned long publicFlags);
+extern unsigned long SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags);
+
+PRBool SECMOD_HasRemovableSlots(SECMODModule *mod);
+PK11SlotInfo *SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, 
+				unsigned long flags, PRIntervalTime latency);
+/*
+ * Warning: the SECMOD_CancelWait function is highly destructive, potentially 
+ * finalizing  the module 'mod' (causing inprogress operations to fail, 
+ * and session key material to disappear). It should only be called when 
+ * shutting down  the module. 
+ */
+SECStatus SECMOD_CancelWait(SECMODModule *mod);
+/*
+ * check to see if the module has added new slots. PKCS 11 v2.20 allows for
+ * modules to add new slots, but never remove them. Slots not be added between 
+ * a call to C_GetSlotLlist(Flag, NULL, &count) and the corresponding
+ * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently
+ * grow on the caller. It is permissible for the slots to increase between
+ * corresponding calls with NULL to get the size.
+ */
+SECStatus SECMOD_UpdateSlotList(SECMODModule *mod);
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/pk11wrap/secmodi.h b/mozilla/security/nss/lib/pk11wrap/secmodi.h
new file mode 100644
index 0000000..b67e6df
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/secmodi.h
@@ -0,0 +1,206 @@
+/* ***** 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 ***** */
+/*
+ * Internal header file included only by files in pkcs11 dir, or in
+ * pkcs11 specific client and server files.
+ */
+#ifndef _SECMODI_H_
+#define _SECMODI_H_ 1
+#include "pkcs11.h"
+#include "nssilock.h"
+#include "secoidt.h"
+#include "secdert.h"
+#include "certt.h"
+#include "secmodt.h"
+#include "keyt.h"
+
+SEC_BEGIN_PROTOS
+
+/* proto-types */
+extern SECStatus SECMOD_DeletePermDB(SECMODModule *module);
+extern SECStatus SECMOD_AddPermDB(SECMODModule *module);
+extern SECStatus SECMOD_Shutdown(void);
+void nss_DumpModuleLog(void);
+
+extern int secmod_PrivateModuleCount;
+
+extern void SECMOD_Init(void);
+SECStatus secmod_ModuleInit(SECMODModule *mod, SECMODModule **oldModule,
+			    PRBool* alreadyLoaded);
+
+/* list managment */
+extern SECStatus SECMOD_AddModuleToList(SECMODModule *newModule);
+extern SECStatus SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule);
+extern SECStatus SECMOD_AddModuleToUnloadList(SECMODModule *newModule);
+extern void SECMOD_RemoveList(SECMODModuleList **,SECMODModuleList *);
+extern void SECMOD_AddList(SECMODModuleList *,SECMODModuleList *,SECMODListLock *);
+extern SECMODListLock *SECMOD_NewListLock(void);
+extern void SECMOD_DestroyListLock(SECMODListLock *);
+extern void SECMOD_GetWriteLock(SECMODListLock *);
+extern void SECMOD_ReleaseWriteLock(SECMODListLock *);
+
+/* Operate on modules by name */
+extern SECMODModule *SECMOD_FindModuleByID(SECMODModuleID);
+extern SECMODModule *secmod_FindModuleByFuncPtr(void *funcPtr);
+
+/* database/memory management */
+extern SECMODModuleList *SECMOD_NewModuleListElement(void);
+extern SECMODModuleList *SECMOD_DestroyModuleListElement(SECMODModuleList *);
+extern void SECMOD_DestroyModuleList(SECMODModuleList *);
+extern SECStatus SECMOD_AddModule(SECMODModule *newModule);
+
+extern unsigned long SECMOD_InternaltoPubMechFlags(unsigned long internalFlags);
+extern unsigned long SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags);
+
+/* Library functions */
+SECStatus secmod_LoadPKCS11Module(SECMODModule *, SECMODModule **oldModule);
+SECStatus SECMOD_UnloadModule(SECMODModule *);
+void SECMOD_SetInternalModule(SECMODModule *);
+PRBool secmod_IsInternalKeySlot(SECMODModule *);
+
+/* tools for checking if we are loading the same database twice */
+typedef struct SECMODConfigListStr SECMODConfigList;
+/* collect all the databases in a given spec */
+SECMODConfigList *secmod_GetConfigList(PRBool isFIPS, char *spec, int *count);
+/* see is a spec matches a database on the list */
+PRBool secmod_MatchConfigList(char *spec, 
+			      SECMODConfigList *conflist, int count);
+/* free our list of databases */
+void secmod_FreeConfigList(SECMODConfigList *conflist, int count);
+
+/* parsing parameters */
+/* returned char * must be freed by caller with PORT_Free */
+/* children and ids are null terminated arrays which must be freed with
+ * secmod_FreeChildren */
+char *secmod_ParseModuleSpecForTokens(PRBool convert,
+				      PRBool isFIPS,
+				      char *moduleSpec,
+				      char ***children, 
+				      CK_SLOT_ID **ids);
+void secmod_FreeChildren(char **children, CK_SLOT_ID *ids);
+char *secmod_MkAppendTokensList(PRArenaPool *arena, char *origModuleSpec, 
+				char *newModuleSpec, CK_SLOT_ID newID,
+				char **children, CK_SLOT_ID *ids);
+char *secmod_DoubleEscape(const char *string, char quote1, char quote2);
+
+
+
+void SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot);
+CK_RV pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event,
+                                                         CK_VOID_PTR pdata);
+void pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib);
+CK_OBJECT_HANDLE pk11_FindObjectByTemplate(PK11SlotInfo *slot,
+					CK_ATTRIBUTE *inTemplate,int tsize);
+CK_OBJECT_HANDLE *pk11_FindObjectsByTemplate(PK11SlotInfo *slot,
+			CK_ATTRIBUTE *inTemplate,int tsize, int *objCount);
+SECStatus PK11_UpdateSlotAttribute(PK11SlotInfo *slot,
+				 PK11DefaultArrayEntry *entry, PRBool add);
+
+#define PK11_GETTAB(x) ((CK_FUNCTION_LIST_PTR)((x)->functionList))
+#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
+		(x)->pValue=(v); (x)->ulValueLen = (l);
+SECStatus PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
+                               const CK_ATTRIBUTE *theTemplate, int count,
+                                PRBool token, CK_OBJECT_HANDLE *objectID);
+
+SECStatus pbe_PK11AlgidToParam(SECAlgorithmID *algid,SECItem *mech);
+SECStatus PBE_PK11ParamToAlgid(SECOidTag algTag, SECItem *param, 
+				PRArenaPool *arena, SECAlgorithmID *algId);
+
+PK11SymKey *pk11_TokenKeyGenWithFlagsAndKeyType(PK11SlotInfo *slot,
+	CK_MECHANISM_TYPE type, SECItem *param, CK_KEY_TYPE keyType, 
+	int keySize, SECItem *keyId, CK_FLAGS opFlags, 
+	PK11AttrFlags attrFlags, void *wincx);
+
+CK_MECHANISM_TYPE pk11_GetPBECryptoMechanism(SECAlgorithmID *algid,
+                   SECItem **param, SECItem *pwd, PRBool faulty3DES);
+
+
+
+extern void pk11sdr_Init(void);
+extern void pk11sdr_Shutdown(void);
+
+/*
+ * Private to pk11wrap.
+ */
+
+PRBool pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx);
+CK_SESSION_HANDLE pk11_GetNewSession(PK11SlotInfo *slot, PRBool *owner);
+void pk11_CloseSession(PK11SlotInfo *slot, CK_SESSION_HANDLE sess, PRBool own);
+PK11SymKey *pk11_ForceSlot(PK11SymKey *symKey, CK_MECHANISM_TYPE type,
+						CK_ATTRIBUTE_TYPE operation);
+/* Convert key operation flags to PKCS #11 attributes. */
+unsigned int pk11_OpFlagsToAttributes(CK_FLAGS flags, 
+				CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue);
+/* Check for bad (conflicting) attribute flags */
+PRBool pk11_BadAttrFlags(PK11AttrFlags attrFlags);
+/* Convert key attribute flags to PKCS #11 attributes. */
+unsigned int pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags,
+		CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue, CK_BBOOL *ckFalse);
+PRBool pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs,
+					CK_ATTRIBUTE_TYPE target);
+
+CK_MECHANISM_TYPE pk11_mapWrapKeyType(KeyType keyType);
+PK11SymKey *pk11_KeyExchange(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+		CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, PRBool isPerm,
+						PK11SymKey *symKey);
+
+PRBool pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert,
+							 CERTCertTrust *trust);
+CK_OBJECT_HANDLE pk11_FindPubKeyByAnyCert(CERTCertificate *cert,
+					 PK11SlotInfo **slot, void *wincx);
+SECStatus pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts,
+							void *wincx);
+int PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
+						int templateCount);
+SECItem *pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, 
+						CK_OBJECT_HANDLE handle);
+SECStatus PK11_TraverseSlot(PK11SlotInfo *slot, void *arg);
+CK_OBJECT_HANDLE pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, 
+							SECItem *keyID);
+SECKEYPrivateKey *PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, 
+			PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx);
+CERTCertificate *PK11_MakeCertFromHandle(PK11SlotInfo *slot,
+			CK_OBJECT_HANDLE certID, CK_ATTRIBUTE *privateLabel);
+
+SECItem *pk11_GenerateNewParamWithKeyLen(CK_MECHANISM_TYPE type, int keyLen);
+SECItem *pk11_ParamFromIVWithLen(CK_MECHANISM_TYPE type, 
+				 SECItem *iv, int keyLen);
+
+SEC_END_PROTOS
+
+#endif
+
diff --git a/mozilla/security/nss/lib/pk11wrap/secmodti.h b/mozilla/security/nss/lib/pk11wrap/secmodti.h
new file mode 100644
index 0000000..874a38d
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/secmodti.h
@@ -0,0 +1,220 @@
+/* ***** 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 ***** */
+/*
+ * Internal header file included only by files in pkcs11 dir, or in
+ * pkcs11 specific client and server files.
+ */
+
+#ifndef  _SECMODTI_H_
+#define  _SECMODTI_H_ 1
+#include "prmon.h"
+#include "prtypes.h"
+#include "nssilckt.h"
+#include "pk11init.h"
+#include "secmodt.h"
+#include "pkcs11t.h"
+
+#include "nssdevt.h"
+
+/* internal data structures */
+
+/* Traverse slots callback */
+typedef struct pk11TraverseSlotStr {
+    SECStatus (*callback)(PK11SlotInfo *,CK_OBJECT_HANDLE, void *);
+    void *callbackArg;
+    CK_ATTRIBUTE *findTemplate;
+    int templateCount;
+} pk11TraverseSlot;
+
+
+/* represent a pkcs#11 slot reference counted. */
+struct PK11SlotInfoStr {
+    /* the PKCS11 function list for this slot */
+    void *functionList;
+    SECMODModule *module; /* our parent module */
+    /* Boolean to indicate the current state of this slot */
+    PRBool needTest;	/* Has this slot been tested for Export complience */
+    PRBool isPerm;	/* is this slot a permanment device */
+    PRBool isHW;	/* is this slot a hardware device */
+    PRBool isInternal;  /* is this slot one of our internal PKCS #11 devices */
+    PRBool disabled;	/* is this slot disabled... */
+    PK11DisableReasons reason; 	/* Why this slot is disabled */
+    PRBool readOnly;	/* is the token in this slot read-only */
+    PRBool needLogin;	/* does the token of the type that needs 
+			 * authentication (still true even if token is logged 
+			 * in) */
+    PRBool hasRandom;   /* can this token generated random numbers */
+    PRBool defRWSession; /* is the default session RW (we open our default 
+			  * session rw if the token can only handle one session
+			  * at a time. */
+    PRBool isThreadSafe; /* copied from the module */
+    /* The actual flags (many of which are distilled into the above PRBools) */
+    CK_FLAGS flags;      /* flags from PKCS #11 token Info */
+    /* a default session handle to do quick and dirty functions */
+    CK_SESSION_HANDLE session; 
+    PZLock *sessionLock; /* lock for this session */
+    /* our ID */
+    CK_SLOT_ID slotID;
+    /* persistant flags saved from startup to startup */
+    unsigned long defaultFlags;
+    /* keep track of who is using us so we don't accidently get freed while
+     * still in use */
+    PRInt32 refCount;    /* to be in/decremented by atomic calls ONLY! */
+    PZLock *freeListLock;
+    PK11SymKey *freeSymKeysWithSessionHead;
+    PK11SymKey *freeSymKeysHead;
+    int keyCount;
+    int maxKeyCount;
+    /* Password control functions for this slot. many of these are only
+     * active if the appropriate flag is on in defaultFlags */
+    int askpw;		/* what our password options are */
+    int timeout;	/* If we're ask_timeout, what is our timeout time is 
+			 * seconds */
+    int authTransact;   /* allow multiple authentications off one password if
+		         * they are all part of the same transaction */
+    int64 authTime;     /* when were we last authenticated */
+    int minPassword;	/* smallest legal password */
+    int maxPassword;	/* largest legal password */
+    uint16 series;	/* break up the slot info into various groups of 
+			 * inserted tokens so that keys and certs can be
+			 * invalidated */
+    uint16 flagSeries;	/* record the last series for the last event
+                         * returned for this slot */
+    PRBool flagState;	/* record the state of the last event returned for this
+			 * slot. */
+    uint16 wrapKey;	/* current wrapping key for SSL master secrets */
+    CK_MECHANISM_TYPE wrapMechanism;
+			/* current wrapping mechanism for current wrapKey */
+    CK_OBJECT_HANDLE refKeys[1]; /* array of existing wrapping keys for */
+    CK_MECHANISM_TYPE *mechanismList; /* list of mechanism supported by this
+				       * token */
+    int mechanismCount;
+    /* cache the certificates stored on the token of this slot */
+    CERTCertificate **cert_array;
+    int array_size;
+    int cert_count;
+    char serial[16];
+    /* since these are odd sizes, keep them last. They are odd sizes to 
+     * allow them to become null terminated strings */
+    char slot_name[65];
+    char token_name[33];
+    PRBool hasRootCerts;
+    PRBool hasRootTrust;
+    PRBool hasRSAInfo;
+    CK_FLAGS RSAInfoFlags;
+    PRBool protectedAuthPath;
+    PRBool isActiveCard;
+    PRIntervalTime lastLoginCheck;
+    unsigned int lastState;
+    /* for Stan */
+    NSSToken *nssToken;
+    /* fast mechanism lookup */
+    char mechanismBits[256];
+};
+
+/* Symetric Key structure. Reference Counted */
+struct PK11SymKeyStr {
+    CK_MECHANISM_TYPE type;	/* type of operation this key was created for*/
+    CK_OBJECT_HANDLE  objectID; /* object id of this key in the slot */
+    PK11SlotInfo      *slot;    /* Slot this key is loaded into */
+    void	      *cx;	/* window context in case we need to loggin */
+    PK11SymKey	      *next;
+    PRBool	      owner;
+    SECItem	      data;	/* raw key data if available */
+    CK_SESSION_HANDLE session;
+    PRBool	      sessionOwner;
+    PRInt32	      refCount;	/* number of references to this key */
+    int		      size;	/* key size in bytes */
+    PK11Origin	      origin;	/* where this key came from 
+                                 * (see def in secmodt.h) */
+    PK11SymKey        *parent;  /* potential owner key of the session */
+    uint16 series;		/* break up the slot info into various groups 
+				 * of inserted tokens so that keys and certs 
+				 * can be invalidated */
+    void *userData;		/* random data the application can attach to
+                                 * this key */
+    PK11FreeDataFunc freeFunc;	/* function to free the user data */
+};
+
+
+/*
+ * hold a hash, encryption or signing context for multi-part operations.
+ * hold enough information so that multiple contexts can be interleaved
+ * if necessary. ... Not RefCounted.
+ */
+struct PK11ContextStr {
+    CK_ATTRIBUTE_TYPE	operation; /* type of operation this context is doing
+				    * (CKA_ENCRYPT, CKA_SIGN, CKA_HASH, etc. */
+    PK11SymKey  	*key;	   /* symetric key used in this context */
+    PK11SlotInfo	*slot;	   /* slot this context is operationing on */
+    CK_SESSION_HANDLE	session;   /* session this context is using */
+    PZLock		*sessionLock; /* lock before accessing a PKCS #11 
+				       * session */
+    PRBool		ownSession;/* do we own the session? */
+    void 		*cx;	   /* window context in case we need to loggin*/
+    void		*savedData;/* save data when we are multiplexing on a
+				    * single context */
+    unsigned long	savedLength; /* length of the saved context */
+    SECItem		*param;	    /* mechanism parameters used to build this
+								context */
+    PRBool		init;	    /* has this contexted been initialized */
+    CK_MECHANISM_TYPE	type;	    /* what is the PKCS #11 this context is
+				     * representing (usually what algorithm is
+				     * being used (CKM_RSA_PKCS, CKM_DES,
+				     * CKM_SHA, etc.*/
+    PRBool		fortezzaHack; /*Fortezza SSL has some special
+				       * non-standard semantics*/
+};
+
+/*
+ * structure to hold a pointer to a unique PKCS #11 object 
+ * (pointer to the slot and the object id).
+ */
+struct PK11GenericObjectStr {
+    PK11GenericObject *prev;
+    PK11GenericObject *next;
+    PK11SlotInfo *slot;
+    CK_OBJECT_HANDLE objectID;
+};
+
+
+#define MAX_TEMPL_ATTRS 16 /* maximum attributes in template */
+
+/* This mask includes all CK_FLAGs with an equivalent CKA_ attribute. */
+#define CKF_KEY_OPERATION_FLAGS 0x000e7b00UL
+
+
+#endif /* _SECMODTI_H_ */
diff --git a/mozilla/security/nss/lib/pk11wrap/secpkcs5.h b/mozilla/security/nss/lib/pk11wrap/secpkcs5.h
new file mode 100644
index 0000000..3858563
--- /dev/null
+++ b/mozilla/security/nss/lib/pk11wrap/secpkcs5.h
@@ -0,0 +1,94 @@
+/* ***** 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 ***** */
+#ifndef _SECPKCS5_H_
+#define _SECPKCS5_H_
+#include "seccomon.h"
+#include "secmodt.h"
+
+/* used for V2 PKCS 12 Draft Spec */
+typedef enum {
+    pbeBitGenIDNull = 0,
+    pbeBitGenCipherKey = 0x01,
+    pbeBitGenCipherIV = 0x02,
+    pbeBitGenIntegrityKey = 0x03
+} PBEBitGenID;
+
+typedef struct PBEBitGenContextStr PBEBitGenContext;
+
+SEC_BEGIN_PROTOS
+
+/* private */
+SECAlgorithmID *
+sec_pkcs5CreateAlgorithmID(SECOidTag algorithm, SECOidTag cipherAlgorithm,
+			SECOidTag prfAlg, SECOidTag *pPbeAlgorithm,
+			int keyLengh, SECItem *salt, int iteration);
+
+/* Get the initialization vector.  The password is passed in, hashing
+ * is performed, and the initialization vector is returned.
+ *  algid is a pointer to a PBE algorithm ID
+ *  pwitem is the password
+ * If an error occurs or the algorithm id is not a PBE algrithm,
+ * NULL is returned.  Otherwise, the iv is returned in a secitem.
+ */
+SECItem *
+SEC_PKCS5GetIV(SECAlgorithmID *algid, SECItem *pwitem, PRBool faulty3DES);
+
+SECOidTag SEC_PKCS5GetCryptoAlgorithm(SECAlgorithmID *algid);
+PRBool SEC_PKCS5IsAlgorithmPBEAlg(SECAlgorithmID *algid);
+PRBool SEC_PKCS5IsAlgorithmPBEAlgTag(SECOidTag algTag);
+SECOidTag SEC_PKCS5GetPBEAlgorithm(SECOidTag algTag, int keyLen);
+int SEC_PKCS5GetKeyLength(SECAlgorithmID *algid);
+
+/**********************************************************************
+ * Deprecated PBE functions.  Use the PBE functions in pk11func.h
+ * instead.
+ **********************************************************************/
+
+PBEBitGenContext *
+PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose,
+        SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded,
+        unsigned int iterations);
+
+void
+PBE_DestroyContext(PBEBitGenContext *context);
+
+
+SECItem *
+PBE_GenerateBits(PBEBitGenContext *context);
+
+SEC_END_PROTOS
+
+#endif /* _SECPKS5_H_ */
diff --git a/mozilla/security/nss/lib/pkcs7/certread.c b/mozilla/security/nss/lib/pkcs7/certread.c
new file mode 100644
index 0000000..3142209
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/certread.c
@@ -0,0 +1,456 @@
+/* ***** 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 "cert.h"
+#include "secpkcs7.h"
+#include "base64.h"
+#include "secitem.h"
+#include "secder.h"
+#include "secasn1.h"
+#include "secoid.h"
+#include "secerr.h"
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+
+SECStatus
+SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg)
+{
+    SEC_PKCS7ContentInfo *contentInfo = NULL;
+    SECStatus rv;
+    SECItem **certs;
+    int count;
+
+    contentInfo = SEC_PKCS7DecodeItem(pkcs7Item, NULL, NULL, NULL, NULL, NULL, 
+				      NULL, NULL);
+    if ( contentInfo == NULL ) {
+	goto loser;
+    }
+
+    if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_PKCS7_SIGNED_DATA ) {
+	goto loser;
+    }
+
+    certs = contentInfo->content.signedData->rawCerts;
+    if ( certs ) {
+	count = 0;
+	
+	while ( *certs ) {
+	    count++;
+	    certs++;
+	}
+	rv = (* f)(arg, contentInfo->content.signedData->rawCerts, count);
+    }
+    
+    rv = SECSuccess;
+    
+    goto done;
+loser:
+    rv = SECFailure;
+    
+done:
+    if ( contentInfo ) {
+	SEC_PKCS7DestroyContentInfo(contentInfo);
+    }
+
+    return(rv);
+}
+
+const SEC_ASN1Template SEC_CertSequenceTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
+};
+
+SECStatus
+SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg)
+{
+    SECStatus rv;
+    SECItem **certs;
+    int count;
+    SECItem **rawCerts = NULL;
+    PRArenaPool *arena;
+    SEC_PKCS7ContentInfo *contentInfo = NULL;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	return SECFailure;
+    }
+
+    contentInfo = SEC_PKCS7DecodeItem(certsItem, NULL, NULL, NULL, NULL, NULL, 
+				      NULL, NULL);
+    if ( contentInfo == NULL ) {
+	goto loser;
+    }
+
+    if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) {
+	goto loser;
+    }
+
+
+    rv = SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate,
+		    contentInfo->content.data);
+
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    certs = rawCerts;
+    if ( certs ) {
+	count = 0;
+	
+	while ( *certs ) {
+	    count++;
+	    certs++;
+	}
+	rv = (* f)(arg, rawCerts, count);
+    }
+    
+    rv = SECSuccess;
+    
+    goto done;
+loser:
+    rv = SECFailure;
+    
+done:
+    if ( contentInfo ) {
+	SEC_PKCS7DestroyContentInfo(contentInfo);
+    }
+
+    if ( arena ) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    
+    return(rv);
+}
+
+CERTCertificate *
+CERT_ConvertAndDecodeCertificate(char *certstr)
+{
+    CERTCertificate *cert;
+    SECStatus rv;
+    SECItem der;
+
+    rv = ATOB_ConvertAsciiToItem(&der, certstr);
+    if (rv != SECSuccess)
+	return NULL;
+
+    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 
+                                   &der, NULL, PR_FALSE, PR_TRUE);
+
+    PORT_Free(der.data);
+    return cert;
+}
+
+static const char NS_CERT_HEADER[]  = "-----BEGIN CERTIFICATE-----";
+static const char NS_CERT_TRAILER[] = "-----END CERTIFICATE-----";
+#define NS_CERT_HEADER_LEN  ((sizeof NS_CERT_HEADER) - 1)
+#define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1)
+
+static const char CERTIFICATE_TYPE_STRING[] = "certificate";
+#define CERTIFICATE_TYPE_LEN (sizeof(CERTIFICATE_TYPE_STRING)-1)
+
+/*
+ * read an old style ascii or binary certificate chain
+ */
+SECStatus
+CERT_DecodeCertPackage(char *certbuf,
+		       int certlen,
+		       CERTImportCertificateFunc f,
+		       void *arg)
+{
+    unsigned char *cp;
+    unsigned char *bincert = NULL;
+    char *         ascCert = NULL;
+    SECStatus      rv;
+    
+    if ( certbuf == NULL ) {
+	return(SECFailure);
+    }
+    
+    cp = (unsigned char *)certbuf;
+
+    /* is a DER encoded certificate of some type? */
+    if ( ( *cp  & 0x1f ) == SEC_ASN1_SEQUENCE ) {
+	SECItem certitem;
+	SECItem *pcertitem = &certitem;
+	int seqLen, seqLenLen;
+
+	cp++;
+	
+	if ( *cp & 0x80) {
+	    /* Multibyte length */
+	    seqLenLen = cp[0] & 0x7f;
+	    
+	    switch (seqLenLen) {
+	      case 4:
+		seqLen = ((unsigned long)cp[1]<<24) |
+		    ((unsigned long)cp[2]<<16) | (cp[3]<<8) | cp[4];
+		break;
+	      case 3:
+		seqLen = ((unsigned long)cp[1]<<16) | (cp[2]<<8) | cp[3];
+		break;
+	      case 2:
+		seqLen = (cp[1]<<8) | cp[2];
+		break;
+	      case 1:
+		seqLen = cp[1];
+		break;
+	      default:
+		/* indefinite length */
+		seqLen = 0;
+	    }
+	    cp += ( seqLenLen + 1 );
+
+	} else {
+	    seqLenLen = 0;
+	    seqLen = *cp;
+	    cp++;
+	}
+
+	/* check entire length if definite length */
+	if ( seqLen || seqLenLen ) {
+	    if ( certlen != ( seqLen + seqLenLen + 2 ) ) {
+		if (certlen > ( seqLen + seqLenLen + 2 ))
+		    PORT_SetError(SEC_ERROR_EXTRA_INPUT);
+		else 
+		    PORT_SetError(SEC_ERROR_INPUT_LEN);
+		goto notder;
+	    }
+	}
+	
+	/* check the type string */
+	/* netscape wrapped DER cert */
+	if ( ( cp[0] == SEC_ASN1_OCTET_STRING ) &&
+	    ( cp[1] == CERTIFICATE_TYPE_LEN ) &&
+	    ( PORT_Strcmp((char *)&cp[2], CERTIFICATE_TYPE_STRING) ) ) {
+	    
+	    cp += ( CERTIFICATE_TYPE_LEN + 2 );
+
+	    /* it had better be a certificate by now!! */
+	    certitem.data = cp;
+	    certitem.len = certlen - ( cp - (unsigned char *)certbuf );
+	    
+	    rv = (* f)(arg, &pcertitem, 1);
+	    
+	    return(rv);
+	} else if ( cp[0] == SEC_ASN1_OBJECT_ID ) {
+	    SECOidData *oiddata;
+	    SECItem oiditem;
+	    /* XXX - assume DER encoding of OID len!! */
+	    oiditem.len = cp[1];
+	    oiditem.data = (unsigned char *)&cp[2];
+	    oiddata = SECOID_FindOID(&oiditem);
+	    if ( oiddata == NULL ) {
+		return(SECFailure);
+	    }
+
+	    certitem.data = (unsigned char*)certbuf;
+	    certitem.len = certlen;
+	    
+	    switch ( oiddata->offset ) {
+	      case SEC_OID_PKCS7_SIGNED_DATA:
+		return(SEC_ReadPKCS7Certs(&certitem, f, arg));
+		break;
+	      case SEC_OID_NS_TYPE_CERT_SEQUENCE:
+		return(SEC_ReadCertSequence(&certitem, f, arg));
+		break;
+	      default:
+		break;
+	    }
+	    
+	} else {
+	    /* it had better be a certificate by now!! */
+	    certitem.data = (unsigned char*)certbuf;
+	    certitem.len = certlen;
+	    
+	    rv = (* f)(arg, &pcertitem, 1);
+	    return(rv);
+	}
+    }
+
+    /* now look for a netscape base64 ascii encoded cert */
+notder:
+  {
+    unsigned char *certbegin = NULL; 
+    unsigned char *certend   = NULL;
+    char          *pc;
+    int cl;
+
+    /* Convert the ASCII data into a nul-terminated string */
+    ascCert = (char *)PORT_Alloc(certlen + 1);
+    if (!ascCert) {
+        rv = SECFailure;
+	goto loser;
+    }
+
+    PORT_Memcpy(ascCert, certbuf, certlen);
+    ascCert[certlen] = '\0';
+
+    pc = PORT_Strchr(ascCert, '\n');  /* find an EOL */
+    if (!pc) { /* maybe this is a MAC file */
+	pc = ascCert;
+	while (*pc && NULL != (pc = PORT_Strchr(pc, '\r'))) {
+	    *pc++ = '\n';
+	}
+    }
+
+    cp = (unsigned char *)ascCert;
+    cl = certlen;
+
+    /* find the beginning marker */
+    while ( cl > NS_CERT_HEADER_LEN ) {
+	int found = 0;
+	if ( !PORT_Strncasecmp((char *)cp, NS_CERT_HEADER,
+			        NS_CERT_HEADER_LEN) ) {
+	    cl -= NS_CERT_HEADER_LEN;
+	    cp += NS_CERT_HEADER_LEN;
+	    found = 1;
+	}
+	
+	/* skip to next eol */
+	while ( cl && ( *cp != '\n' )) {
+	    cp++;
+	    cl--;
+	} 
+
+	/* skip all blank lines */
+	while ( cl && ( *cp == '\n' || *cp == '\r' )) {
+	    cp++;
+	    cl--;
+	}
+	if (cl && found) {
+	    certbegin = cp;
+	    break;
+    	}
+    }
+
+    if ( certbegin ) {
+	/* find the ending marker */
+	while ( cl >= NS_CERT_TRAILER_LEN ) {
+	    if ( !PORT_Strncasecmp((char *)cp, NS_CERT_TRAILER,
+				   NS_CERT_TRAILER_LEN) ) {
+		certend = (unsigned char *)cp;
+		break;
+	    }
+
+	    /* skip to next eol */
+	    while ( cl && ( *cp != '\n' )) {
+		cp++;
+		cl--;
+	    }
+
+	    /* skip all blank lines */
+	    while ( cl && ( *cp == '\n' || *cp == '\r' )) {
+		cp++;
+		cl--;
+	    }
+	}
+    }
+
+    if ( certbegin && certend ) {
+	unsigned int binLen;
+
+	*certend = 0;
+	/* convert to binary */
+	bincert = ATOB_AsciiToData(certbegin, &binLen);
+	if (!bincert) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+
+	/* now recurse to decode the binary */
+	rv = CERT_DecodeCertPackage((char *)bincert, binLen, f, arg);
+	
+    } else {
+	PORT_SetError(SEC_ERROR_BAD_DER);
+	rv = SECFailure;
+    }
+  }
+
+loser:
+
+    if ( bincert ) {
+	PORT_Free(bincert);
+    }
+
+    if ( ascCert ) {
+	PORT_Free(ascCert);
+    }
+
+    return(rv);
+}
+
+typedef struct {
+    PRArenaPool *arena;
+    SECItem cert;
+} collect_args;
+
+static SECStatus
+collect_certs(void *arg, SECItem **certs, int numcerts)
+{
+    SECStatus rv;
+    collect_args *collectArgs;
+    
+    collectArgs = (collect_args *)arg;
+    
+    rv = SECITEM_CopyItem(collectArgs->arena, &collectArgs->cert, *certs);
+
+    return(rv);
+}
+
+
+/*
+ * read an old style ascii or binary certificate
+ */
+CERTCertificate *
+CERT_DecodeCertFromPackage(char *certbuf, int certlen)
+{
+    collect_args collectArgs;
+    SECStatus rv;
+    CERTCertificate *cert = NULL;
+    
+    collectArgs.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    
+    rv = CERT_DecodeCertPackage(certbuf, certlen, collect_certs,
+				(void *)&collectArgs);
+    if ( rv == SECSuccess ) {
+	cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+	                               &collectArgs.cert, NULL, 
+	                               PR_FALSE, PR_TRUE);
+    }
+    
+    PORT_FreeArena(collectArgs.arena, PR_FALSE);
+    
+    return(cert);
+}
diff --git a/mozilla/security/nss/lib/pkcs7/p7common.c b/mozilla/security/nss/lib/pkcs7/p7common.c
new file mode 100644
index 0000000..63c9a2c
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/p7common.c
@@ -0,0 +1,724 @@
+/* ***** 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 ***** */
+
+/*
+ * PKCS7 implementation -- the exported parts that are used whether
+ * creating or decoding.
+ *
+ * $Id: p7common.c,v 1.7 2008/02/03 06:08:48 nelson%bolyard.com Exp $
+ */
+
+#include "p7local.h"
+
+#include "cert.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "pk11func.h"
+
+/*
+ * Find out (saving pointer to lookup result for future reference)
+ * and return the inner content type.
+ */
+SECOidTag
+SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo)
+{
+    if (cinfo->contentTypeTag == NULL)
+	cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
+
+    if (cinfo->contentTypeTag == NULL)
+	return SEC_OID_UNKNOWN;
+
+    return cinfo->contentTypeTag->offset;
+}
+
+
+/*
+ * Destroy a PKCS7 contentInfo and all of its sub-pieces.
+ */
+void
+SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
+{
+    SECOidTag kind;
+    CERTCertificate **certs;
+    CERTCertificateList **certlists;
+    SEC_PKCS7SignerInfo **signerinfos;
+    SEC_PKCS7RecipientInfo **recipientinfos;
+
+    PORT_Assert (cinfo->refCount > 0);
+    if (cinfo->refCount <= 0)
+	return;
+
+    cinfo->refCount--;
+    if (cinfo->refCount > 0)
+	return;
+
+    certs = NULL;
+    certlists = NULL;
+    recipientinfos = NULL;
+    signerinfos = NULL;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7EnvelopedData *edp;
+
+	    edp = cinfo->content.envelopedData;
+	    if (edp != NULL) {
+		recipientinfos = edp->recipientInfos;
+	    }
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    if (sdp != NULL) {
+		certs = sdp->certs;
+		certlists = sdp->certLists;
+		signerinfos = sdp->signerInfos;
+	    }
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    if (saedp != NULL) {
+		certs = saedp->certs;
+		certlists = saedp->certLists;
+		recipientinfos = saedp->recipientInfos;
+		signerinfos = saedp->signerInfos;
+		if (saedp->sigKey != NULL)
+		    PK11_FreeSymKey (saedp->sigKey);
+	    }
+	}
+	break;
+      default:
+	/* XXX Anything else that needs to be "manually" freed/destroyed? */
+	break;
+    }
+
+    if (certs != NULL) {
+	CERTCertificate *cert;
+
+	while ((cert = *certs++) != NULL) {
+	    CERT_DestroyCertificate (cert);
+	}
+    }
+
+    if (certlists != NULL) {
+	CERTCertificateList *certlist;
+
+	while ((certlist = *certlists++) != NULL) {
+	    CERT_DestroyCertificateList (certlist);
+	}
+    }
+
+    if (recipientinfos != NULL) {
+	SEC_PKCS7RecipientInfo *ri;
+
+	while ((ri = *recipientinfos++) != NULL) {
+	    if (ri->cert != NULL)
+		CERT_DestroyCertificate (ri->cert);
+	}
+    }
+
+    if (signerinfos != NULL) {
+	SEC_PKCS7SignerInfo *si;
+
+	while ((si = *signerinfos++) != NULL) {
+	    if (si->cert != NULL)
+		CERT_DestroyCertificate (si->cert);
+	    if (si->certList != NULL)
+		CERT_DestroyCertificateList (si->certList);
+	}
+    }
+
+    if (cinfo->poolp != NULL) {
+	PORT_FreeArena (cinfo->poolp, PR_FALSE);	/* XXX clear it? */
+    }
+}
+
+
+/*
+ * Return a copy of the given contentInfo.  The copy may be virtual
+ * or may be real -- either way, the result needs to be passed to
+ * SEC_PKCS7DestroyContentInfo later (as does the original).
+ */
+SEC_PKCS7ContentInfo *
+SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo)
+{
+    if (cinfo == NULL)
+	return NULL;
+
+    PORT_Assert (cinfo->refCount > 0);
+
+    if (cinfo->created) {
+	/*
+	 * Want to do a real copy of these; otherwise subsequent
+	 * changes made to either copy are likely to be a surprise.
+	 * XXX I suspect that this will not actually be called for yet,
+	 * which is why the assert, so to notice if it is...
+	 */
+	PORT_Assert (0);
+	/*
+	 * XXX Create a new pool here, and copy everything from
+	 * within.  For cert stuff, need to call the appropriate
+	 * copy functions, etc.
+	 */
+    }
+
+    cinfo->refCount++;
+    return cinfo;
+}
+
+
+/*
+ * Return a pointer to the actual content.  In the case of those types
+ * which are encrypted, this returns the *plain* content.
+ * XXX Needs revisiting if/when we handle nested encrypted types.
+ */
+SECItem *
+SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
+{
+    SECOidTag kind;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_DATA:
+	return cinfo->content.data;
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+	{
+	    SEC_PKCS7DigestedData *digd;
+
+	    digd = cinfo->content.digestedData;
+	    if (digd == NULL)
+		break;
+	    return SEC_PKCS7GetContent (&(digd->contentInfo));
+	}
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	{
+	    SEC_PKCS7EncryptedData *encd;
+
+	    encd = cinfo->content.encryptedData;
+	    if (encd == NULL)
+		break;
+	    return &(encd->encContentInfo.plainContent);
+	}
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7EnvelopedData *envd;
+
+	    envd = cinfo->content.envelopedData;
+	    if (envd == NULL)
+		break;
+	    return &(envd->encContentInfo.plainContent);
+	}
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sigd;
+
+	    sigd = cinfo->content.signedData;
+	    if (sigd == NULL)
+		break;
+	    return SEC_PKCS7GetContent (&(sigd->contentInfo));
+	}
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saed;
+
+	    saed = cinfo->content.signedAndEnvelopedData;
+	    if (saed == NULL)
+		break;
+	    return &(saed->encContentInfo.plainContent);
+	}
+      default:
+	PORT_Assert(0);
+	break;
+    }
+
+    return NULL;
+}
+
+
+/*
+ * XXX Fix the placement and formatting of the
+ * following routines (i.e. make them consistent with the rest of
+ * the pkcs7 code -- I think some/many belong in other files and
+ * they all need a formatting/style rehaul)
+ */
+
+/* retrieve the algorithm identifier for encrypted data.  
+ * the identifier returned is a copy of the algorithm identifier
+ * in the content info and needs to be freed after being used.
+ *
+ *   cinfo is the content info for which to retrieve the
+ *     encryption algorithm.
+ *
+ * if the content info is not encrypted data or an error 
+ * occurs NULL is returned.
+ */
+SECAlgorithmID *
+SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo)
+{
+  SECAlgorithmID *alg = 0;
+  switch (SEC_PKCS7ContentType(cinfo))
+    {
+    case SEC_OID_PKCS7_ENCRYPTED_DATA:
+      alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg;
+      break;
+    case SEC_OID_PKCS7_ENVELOPED_DATA:
+      alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
+      break;
+    case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+      alg = &cinfo->content.signedAndEnvelopedData
+	->encContentInfo.contentEncAlg;
+      break;
+    default:
+      alg = 0;
+      break;
+    }
+
+    return alg;
+}
+
+/* set the content of the content info.  For data content infos,
+ * the data is set.  For encrytped content infos, the plainContent
+ * is set, and is expected to be encrypted later.
+ *  
+ * cinfo is the content info where the data will be set
+ *
+ * buf is a buffer of the data to set
+ *
+ * len is the length of the data being set.
+ *
+ * in the event of an error, SECFailure is returned.  SECSuccess 
+ * indicates the content was successfully set.
+ */
+SECStatus 
+SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
+		    const char *buf, 
+		    unsigned long len)
+{
+    SECOidTag cinfo_type;
+    SECStatus rv;
+    SECItem content;
+    SECOidData *contentTypeTag = NULL;
+
+    content.data = (unsigned char *)buf;
+    content.len = len;
+
+    cinfo_type = SEC_PKCS7ContentType(cinfo);
+
+    /* set inner content */
+    switch(cinfo_type)
+    {
+	case SEC_OID_PKCS7_SIGNED_DATA:
+	    if(content.len > 0) {
+		/* we "leak" the old content here, but as it's all in the pool */
+		/* it does not really matter */
+
+		/* create content item if necessary */
+		if (cinfo->content.signedData->contentInfo.content.data == NULL)
+		    cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
+		rv = SECITEM_CopyItem(cinfo->poolp, 
+			cinfo->content.signedData->contentInfo.content.data,
+			&content);
+	    } else {
+		cinfo->content.signedData->contentInfo.content.data->data = NULL;
+		cinfo->content.signedData->contentInfo.content.data->len = 0;
+		rv = SECSuccess;
+	    }
+	    if(rv == SECFailure)
+		goto loser;
+	    
+	    break;
+	case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	    /* XXX this forces the inner content type to be "data" */
+	    /* do we really want to override without asking or reason? */
+	    contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
+	    if(contentTypeTag == NULL)
+		goto loser;
+	    rv = SECITEM_CopyItem(cinfo->poolp, 
+		&(cinfo->content.encryptedData->encContentInfo.contentType),
+		&(contentTypeTag->oid));
+	    if(rv == SECFailure)
+		goto loser;
+	    if(content.len > 0) {
+		rv = SECITEM_CopyItem(cinfo->poolp, 
+			&(cinfo->content.encryptedData->encContentInfo.plainContent),
+			&content);
+	    } else {
+		cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
+		cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
+		cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
+		cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
+		rv = SECSuccess;
+	    }
+	    if(rv == SECFailure)
+		goto loser;
+	    break;
+	case SEC_OID_PKCS7_DATA:
+	    cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
+		sizeof(SECItem));
+	    if(cinfo->content.data == NULL)
+		goto loser;
+	    if(content.len > 0) {
+		rv = SECITEM_CopyItem(cinfo->poolp,
+			cinfo->content.data, &content);
+	    } else {
+	    	/* handle case with NULL content */
+		rv = SECSuccess;
+	    }
+	    if(rv == SECFailure)
+		goto loser;
+	    break;
+	default:
+	    goto loser;
+    }
+
+    return SECSuccess;
+
+loser:
+	
+    return SECFailure;
+}
+
+/* the content of an encrypted data content info is encrypted.
+ * it is assumed that for encrypted data, that the data has already
+ * been set and is in the "plainContent" field of the content info.
+ *
+ * cinfo is the content info to encrypt
+ *
+ * key is the key with which to perform the encryption.  if the
+ *     algorithm is a password based encryption algorithm, the
+ *     key is actually a password which will be processed per
+ *     PKCS #5.
+ * 
+ * in the event of an error, SECFailure is returned.  SECSuccess
+ * indicates a success.
+ */
+SECStatus 
+SEC_PKCS7EncryptContents(PRArenaPool *poolp,
+			 SEC_PKCS7ContentInfo *cinfo,
+			 SECItem *key,
+			 void *wincx)
+{
+    SECAlgorithmID *algid 	= NULL;
+    SECItem *       result 	= NULL;
+    SECItem *       src;
+    SECItem *       dest;
+    SECItem *       blocked_data = NULL;
+    void *          mark;
+    void *          cx;
+    PK11SymKey *    eKey 	= NULL;
+    PK11SlotInfo *  slot 	= NULL;
+
+    CK_MECHANISM_TYPE cryptoMechType;
+    int             bs;
+    SECStatus       rv 		= SECFailure;
+    SECItem         *c_param = NULL;
+
+    if((cinfo == NULL) || (key == NULL))
+	return SECFailure;
+
+    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
+	return SECFailure;
+
+    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
+    if(algid == NULL)
+	return SECFailure;
+
+    if(poolp == NULL)
+	poolp = cinfo->poolp;
+
+    mark = PORT_ArenaMark(poolp);
+    
+    src = &cinfo->content.encryptedData->encContentInfo.plainContent;
+    dest = &cinfo->content.encryptedData->encContentInfo.encContent;
+    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
+    dest->len = (src->len + 64);
+    if(dest->data == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    slot = PK11_GetInternalKeySlot();
+    if(slot == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
+    if(eKey == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    
+    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
+    if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    /* block according to PKCS 8 */
+    bs = PK11_GetBlockSize(cryptoMechType, c_param);
+    rv = SECSuccess;
+    if(bs) {
+	char pad_char;
+	pad_char = (char)(bs - (src->len % bs));
+	if(src->len % bs) {
+	    rv = SECSuccess;
+	    blocked_data = PK11_BlockData(src, bs);
+	    if(blocked_data) {
+		PORT_Memset((blocked_data->data + blocked_data->len 
+			    - (int)pad_char), 
+			    pad_char, (int)pad_char);
+	    } else {
+		rv = SECFailure;
+		goto loser;
+	    }
+	} else {
+	    blocked_data = SECITEM_DupItem(src);
+	    if(blocked_data) {
+		blocked_data->data = (unsigned char*)PORT_Realloc(
+						  blocked_data->data,
+						  blocked_data->len + bs);
+		if(blocked_data->data) {
+		    blocked_data->len += bs;
+		    PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
+		} else {
+		    rv = SECFailure;
+		    goto loser;
+		}
+	    } else {
+		rv = SECFailure;
+		goto loser;
+	    }
+	 }
+    } else {
+	blocked_data = SECITEM_DupItem(src);
+	if(!blocked_data) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+    }
+
+    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
+		    		    eKey, c_param);
+    if(cx == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
+		       (int)(src->len + 64), blocked_data->data, 
+		       (int)blocked_data->len);
+    PK11_DestroyContext((PK11Context*)cx, PR_TRUE);
+
+loser:
+    /* let success fall through */
+    if(blocked_data != NULL)
+	SECITEM_ZfreeItem(blocked_data, PR_TRUE);
+
+    if(result != NULL)
+	SECITEM_ZfreeItem(result, PR_TRUE);
+
+    if(rv == SECFailure)
+	PORT_ArenaRelease(poolp, mark);
+    else 
+	PORT_ArenaUnmark(poolp, mark);
+
+    if(eKey != NULL)
+	PK11_FreeSymKey(eKey);
+
+    if(slot != NULL)
+	PK11_FreeSlot(slot);
+
+    if(c_param != NULL) 
+	SECITEM_ZfreeItem(c_param, PR_TRUE);
+	
+    return rv;
+}
+
+/* the content of an encrypted data content info is decrypted.
+ * it is assumed that for encrypted data, that the data has already
+ * been set and is in the "encContent" field of the content info.
+ *
+ * cinfo is the content info to decrypt
+ *
+ * key is the key with which to perform the decryption.  if the
+ *     algorithm is a password based encryption algorithm, the
+ *     key is actually a password which will be processed per
+ *     PKCS #5.
+ * 
+ * in the event of an error, SECFailure is returned.  SECSuccess
+ * indicates a success.
+ */
+SECStatus 
+SEC_PKCS7DecryptContents(PRArenaPool *poolp,
+			 SEC_PKCS7ContentInfo *cinfo,
+			 SECItem *key,
+			 void *wincx)
+{
+    SECAlgorithmID *algid = NULL;
+    SECStatus rv = SECFailure;
+    SECItem *result = NULL, *dest, *src;
+    void *mark;
+
+    PK11SymKey *eKey = NULL;
+    PK11SlotInfo *slot = NULL;
+    CK_MECHANISM_TYPE cryptoMechType;
+    void *cx;
+    SECItem *c_param = NULL;
+    int bs;
+
+    if((cinfo == NULL) || (key == NULL))
+	return SECFailure;
+
+    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
+	return SECFailure;
+
+    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
+    if(algid == NULL)
+	return SECFailure;
+
+    if(poolp == NULL)
+	poolp = cinfo->poolp;
+
+    mark = PORT_ArenaMark(poolp);
+    
+    src = &cinfo->content.encryptedData->encContentInfo.encContent;
+    dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
+    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
+    dest->len = (src->len + 64);
+    if(dest->data == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    slot = PK11_GetInternalKeySlot();
+    if(slot == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
+    if(eKey == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    
+    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
+    if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
+		    		    eKey, c_param);
+    if(cx == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
+		       (int)(src->len + 64), src->data, (int)src->len);
+    PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
+
+    bs = PK11_GetBlockSize(cryptoMechType, c_param);
+    if(bs) {
+	/* check for proper badding in block algorithms.  this assumes
+	 * RC2 cbc or a DES cbc variant.  and the padding is thus defined
+	 */
+	if(((int)dest->data[dest->len-1] <= bs) && 
+	   ((int)dest->data[dest->len-1] > 0)) {
+	    dest->len -= (int)dest->data[dest->len-1];
+	} else {
+	    rv = SECFailure;
+	    /* set an error ? */
+	}
+    } 
+
+loser:
+    /* let success fall through */
+    if(result != NULL)
+	SECITEM_ZfreeItem(result, PR_TRUE);
+
+    if(rv == SECFailure)
+	PORT_ArenaRelease(poolp, mark);
+    else
+	PORT_ArenaUnmark(poolp, mark);
+
+    if(eKey != NULL)
+	PK11_FreeSymKey(eKey);
+
+    if(slot != NULL)
+	PK11_FreeSlot(slot);
+
+    if(c_param != NULL) 
+	SECITEM_ZfreeItem(c_param, PR_TRUE);
+	
+    return rv;
+}
+
+SECItem **
+SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
+{
+    switch(SEC_PKCS7ContentType(cinfo))
+    {
+	case SEC_OID_PKCS7_SIGNED_DATA:
+	    return cinfo->content.signedData->rawCerts;
+	    break;
+	default:
+	    return NULL;
+	    break;
+    }
+}
+
+
+int
+SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
+{
+  if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
+    return cinfo->content.envelopedData->encContentInfo.keysize;
+  else
+    return 0;
+}
+
diff --git a/mozilla/security/nss/lib/pkcs7/p7create.c b/mozilla/security/nss/lib/pkcs7/p7create.c
new file mode 100644
index 0000000..474bc2e
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/p7create.c
@@ -0,0 +1,1321 @@
+/* ***** 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 ***** */
+
+/*
+ * PKCS7 creation.
+ *
+ * $Id: p7create.c,v 1.9 2008/02/03 06:08:48 nelson%bolyard.com Exp $
+ */
+
+#include "p7local.h"
+
+#include "cert.h"
+#include "secasn1.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "pk11func.h"
+#include "prtime.h"
+#include "secerr.h"
+#include "secder.h"
+#include "secpkcs5.h"
+
+static SECStatus
+sec_pkcs7_init_content_info (SEC_PKCS7ContentInfo *cinfo, PRArenaPool *poolp,
+			     SECOidTag kind, PRBool detached)
+{
+    void *thing;
+    int version;
+    SECItem *versionp;
+    SECStatus rv;
+
+    PORT_Assert (cinfo != NULL && poolp != NULL);
+    if (cinfo == NULL || poolp == NULL)
+	return SECFailure;
+
+    cinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
+    PORT_Assert (cinfo->contentTypeTag
+		 && cinfo->contentTypeTag->offset == kind);
+
+    rv = SECITEM_CopyItem (poolp, &(cinfo->contentType),
+			   &(cinfo->contentTypeTag->oid));
+    if (rv != SECSuccess)
+	return rv;
+
+    if (detached)
+	return SECSuccess;
+
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+	thing = PORT_ArenaZAlloc (poolp, sizeof(SECItem));
+	cinfo->content.data = (SECItem*)thing;
+	versionp = NULL;
+	version = -1;
+	break;
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+	thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7DigestedData));
+	cinfo->content.digestedData = (SEC_PKCS7DigestedData*)thing;
+	versionp = &(cinfo->content.digestedData->version);
+	version = SEC_PKCS7_DIGESTED_DATA_VERSION;
+	break;
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EncryptedData));
+	cinfo->content.encryptedData = (SEC_PKCS7EncryptedData*)thing;
+	versionp = &(cinfo->content.encryptedData->version);
+	version = SEC_PKCS7_ENCRYPTED_DATA_VERSION;
+	break;
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EnvelopedData));
+	cinfo->content.envelopedData = 
+	  (SEC_PKCS7EnvelopedData*)thing;
+	versionp = &(cinfo->content.envelopedData->version);
+	version = SEC_PKCS7_ENVELOPED_DATA_VERSION;
+	break;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7SignedData));
+	cinfo->content.signedData = 
+	  (SEC_PKCS7SignedData*)thing;
+	versionp = &(cinfo->content.signedData->version);
+	version = SEC_PKCS7_SIGNED_DATA_VERSION;
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	thing = PORT_ArenaZAlloc(poolp,sizeof(SEC_PKCS7SignedAndEnvelopedData));
+	cinfo->content.signedAndEnvelopedData = 
+	  (SEC_PKCS7SignedAndEnvelopedData*)thing;
+	versionp = &(cinfo->content.signedAndEnvelopedData->version);
+	version = SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION;
+	break;
+    }
+
+    if (thing == NULL)
+	return SECFailure;
+
+    if (versionp != NULL) {
+	SECItem *dummy;
+
+	PORT_Assert (version >= 0);
+	dummy = SEC_ASN1EncodeInteger (poolp, versionp, version);
+	if (dummy == NULL)
+	    return SECFailure;
+	PORT_Assert (dummy == versionp);
+    }
+
+    return SECSuccess;
+}
+
+
+static SEC_PKCS7ContentInfo *
+sec_pkcs7_create_content_info (SECOidTag kind, PRBool detached,
+			       SECKEYGetPasswordKey pwfn, void *pwfn_arg)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    PRArenaPool *poolp;
+    SECStatus rv;
+
+    poolp = PORT_NewArena (1024);	/* XXX what is right value? */
+    if (poolp == NULL)
+	return NULL;
+
+    cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
+    if (cinfo == NULL) {
+	PORT_FreeArena (poolp, PR_FALSE);
+	return NULL;
+    }
+
+    cinfo->poolp = poolp;
+    cinfo->pwfn = pwfn;
+    cinfo->pwfn_arg = pwfn_arg;
+    cinfo->created = PR_TRUE;
+    cinfo->refCount = 1;
+
+    rv = sec_pkcs7_init_content_info (cinfo, poolp, kind, detached);
+    if (rv != SECSuccess) {
+	PORT_FreeArena (poolp, PR_FALSE);
+	return NULL;
+    }
+
+    return cinfo;
+}
+
+
+/*
+ * Add a signer to a PKCS7 thing, verifying the signature cert first.
+ * Any error returns SECFailure.
+ *
+ * XXX Right now this only adds the *first* signer.  It fails if you try
+ * to add a second one -- this needs to be fixed.
+ */
+static SECStatus
+sec_pkcs7_add_signer (SEC_PKCS7ContentInfo *cinfo,
+		      CERTCertificate *     cert,
+		      SECCertUsage          certusage,
+		      CERTCertDBHandle *    certdb,
+		      SECOidTag             digestalgtag,
+		      SECItem *             digestdata)
+{
+    SEC_PKCS7SignerInfo *signerinfo, **signerinfos, ***signerinfosp;
+    SECAlgorithmID      *digestalg,  **digestalgs,  ***digestalgsp;
+    SECItem             *digest,     **digests,     ***digestsp;
+    SECItem *            dummy;
+    void *               mark;
+    SECStatus            rv;
+    SECOidTag            kind;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    digestalgsp = &(sdp->digestAlgorithms);
+	    digestsp = &(sdp->digests);
+	    signerinfosp = &(sdp->signerInfos);
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    digestalgsp = &(saedp->digestAlgorithms);
+	    digestsp = &(saedp->digests);
+	    signerinfosp = &(saedp->signerInfos);
+	}
+	break;
+      default:
+	return SECFailure;		/* XXX set an error? */
+    }
+
+    /*
+     * XXX I think that CERT_VerifyCert should do this if *it* is passed
+     * a NULL database.
+     */
+    if (certdb == NULL) {
+	certdb = CERT_GetDefaultCertDB();
+	if (certdb == NULL)
+	    return SECFailure;		/* XXX set an error? */
+    }
+
+    if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
+			 cinfo->pwfn_arg, NULL) != SECSuccess)
+	{
+	/* XXX Did CERT_VerifyCert set an error? */
+	return SECFailure;
+    }
+
+    /*
+     * XXX This is the check that we do not already have a signer.
+     * This is not what we really want -- we want to allow this
+     * and *add* the new signer.
+     */
+    PORT_Assert (*signerinfosp == NULL
+		 && *digestalgsp == NULL && *digestsp == NULL);
+    if (*signerinfosp != NULL || *digestalgsp != NULL || *digestsp != NULL)
+	return SECFailure;
+
+    mark = PORT_ArenaMark (cinfo->poolp);
+
+    signerinfo = (SEC_PKCS7SignerInfo*)PORT_ArenaZAlloc (cinfo->poolp, 
+						  sizeof(SEC_PKCS7SignerInfo));
+    if (signerinfo == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &signerinfo->version,
+				   SEC_PKCS7_SIGNER_INFO_VERSION);
+    if (dummy == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+    PORT_Assert (dummy == &signerinfo->version);
+
+    signerinfo->cert = CERT_DupCertificate (cert);
+    if (signerinfo->cert == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    signerinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
+    if (signerinfo->issuerAndSN == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    rv = SECOID_SetAlgorithmID (cinfo->poolp, &signerinfo->digestAlg,
+				digestalgtag, NULL);
+    if (rv != SECSuccess) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    /*
+     * Okay, now signerinfo is all set.  We just need to put it and its
+     * companions (another copy of the digest algorithm, and the digest
+     * itself if given) into the main structure.
+     *
+     * XXX If we are handling more than one signer, the following code
+     * needs to look through the digest algorithms already specified
+     * and see if the same one is there already.  If it is, it does not
+     * need to be added again.  Also, if it is there *and* the digest
+     * is not null, then the digest given should match the digest already
+     * specified -- if not, that is an error.  Finally, the new signerinfo
+     * should be *added* to the set already found.
+     */
+
+    signerinfos = (SEC_PKCS7SignerInfo**)PORT_ArenaAlloc (cinfo->poolp,
+				   2 * sizeof(SEC_PKCS7SignerInfo *));
+    if (signerinfos == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+    signerinfos[0] = signerinfo;
+    signerinfos[1] = NULL;
+
+    digestalg = PORT_ArenaZAlloc (cinfo->poolp, sizeof(SECAlgorithmID));
+    digestalgs = PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECAlgorithmID *));
+    if (digestalg == NULL || digestalgs == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+    rv = SECOID_SetAlgorithmID (cinfo->poolp, digestalg, digestalgtag, NULL);
+    if (rv != SECSuccess) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+    digestalgs[0] = digestalg;
+    digestalgs[1] = NULL;
+
+    if (digestdata != NULL) {
+	digest = (SECItem*)PORT_ArenaAlloc (cinfo->poolp, sizeof(SECItem));
+	digests = (SECItem**)PORT_ArenaAlloc (cinfo->poolp, 
+					      2 * sizeof(SECItem *));
+	if (digest == NULL || digests == NULL) {
+	    PORT_ArenaRelease (cinfo->poolp, mark);
+	    return SECFailure;
+	}
+	rv = SECITEM_CopyItem (cinfo->poolp, digest, digestdata);
+	if (rv != SECSuccess) {
+	    PORT_ArenaRelease (cinfo->poolp, mark);
+	    return SECFailure;
+	}
+	digests[0] = digest;
+	digests[1] = NULL;
+    } else {
+	digests = NULL;
+    }
+
+    *signerinfosp = signerinfos;
+    *digestalgsp = digestalgs;
+    *digestsp = digests;
+
+    PORT_ArenaUnmark(cinfo->poolp, mark);
+    return SECSuccess;
+}
+
+
+/*
+ * Helper function for creating an empty signedData.
+ */
+static SEC_PKCS7ContentInfo *
+sec_pkcs7_create_signed_data (SECKEYGetPasswordKey pwfn, void *pwfn_arg)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    SEC_PKCS7SignedData *sigd;
+    SECStatus rv;
+
+    cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_SIGNED_DATA, PR_FALSE,
+					   pwfn, pwfn_arg);
+    if (cinfo == NULL)
+	return NULL;
+
+    sigd = cinfo->content.signedData;
+    PORT_Assert (sigd != NULL);
+
+    /*
+     * XXX Might we want to allow content types other than data?
+     * If so, via what interface?
+     */
+    rv = sec_pkcs7_init_content_info (&(sigd->contentInfo), cinfo->poolp,
+				      SEC_OID_PKCS7_DATA, PR_TRUE);
+    if (rv != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    return cinfo;
+}
+
+
+/*
+ * Start a PKCS7 signing context.
+ *
+ * "cert" is the cert that will be used to sign the data.  It will be
+ * checked for validity.
+ *
+ * "certusage" describes the signing usage (e.g. certUsageEmailSigner)
+ * XXX Maybe SECCertUsage should be split so that our caller just says
+ * "email" and *we* add the "signing" part -- otherwise our caller
+ * could be lying about the usage; we do not want to allow encryption
+ * certs for signing or vice versa.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ * 
+ * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
+ *
+ * "digest" is the actual digest of the data.  It must be provided in
+ * the case of detached data or NULL if the content will be included.
+ *
+ * The return value can be passed to functions which add things to
+ * it like attributes, then eventually to SEC_PKCS7Encode() or to
+ * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
+ * SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateSignedData (CERTCertificate *cert,
+			   SECCertUsage certusage,
+			   CERTCertDBHandle *certdb,
+			   SECOidTag digestalg,
+			   SECItem *digest,
+ 			   SECKEYGetPasswordKey pwfn, void *pwfn_arg)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    SECStatus rv;
+
+    cinfo = sec_pkcs7_create_signed_data (pwfn, pwfn_arg);
+    if (cinfo == NULL)
+	return NULL;
+
+    rv = sec_pkcs7_add_signer (cinfo, cert, certusage, certdb,
+			       digestalg, digest);
+    if (rv != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    return cinfo;
+}
+
+
+static SEC_PKCS7Attribute *
+sec_pkcs7_create_attribute (PRArenaPool *poolp, SECOidTag oidtag,
+			    SECItem *value, PRBool encoded)
+{
+    SEC_PKCS7Attribute *attr;
+    SECItem **values;
+    void *mark;
+
+    PORT_Assert (poolp != NULL);
+    mark = PORT_ArenaMark (poolp);
+
+    attr = (SEC_PKCS7Attribute*)PORT_ArenaAlloc (poolp, 
+						 sizeof(SEC_PKCS7Attribute));
+    if (attr == NULL)
+	goto loser;
+
+    attr->typeTag = SECOID_FindOIDByTag (oidtag);
+    if (attr->typeTag == NULL)
+	goto loser;
+
+    if (SECITEM_CopyItem (poolp, &(attr->type),
+			  &(attr->typeTag->oid)) != SECSuccess)
+	goto loser;
+
+    values = (SECItem**)PORT_ArenaAlloc (poolp, 2 * sizeof(SECItem *));
+    if (values == NULL)
+	goto loser;
+
+    if (value != NULL) {
+	SECItem *copy;
+
+	copy = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
+	if (copy == NULL)
+	    goto loser;
+
+	if (SECITEM_CopyItem (poolp, copy, value) != SECSuccess)
+	    goto loser;
+
+	value = copy;
+    }
+
+    values[0] = value;
+    values[1] = NULL;
+    attr->values = values;
+    attr->encoded = encoded;
+
+    PORT_ArenaUnmark (poolp, mark);
+    return attr;
+
+loser:
+    PORT_Assert (mark != NULL);
+    PORT_ArenaRelease (poolp, mark);
+    return NULL;
+}
+
+
+static SECStatus
+sec_pkcs7_add_attribute (SEC_PKCS7ContentInfo *cinfo,
+			 SEC_PKCS7Attribute ***attrsp,
+			 SEC_PKCS7Attribute *attr)
+{
+    SEC_PKCS7Attribute **attrs;
+    SECItem *ct_value;
+    void *mark;
+
+    PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
+    if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
+	return SECFailure;
+
+    attrs = *attrsp;
+    if (attrs != NULL) {
+	int count;
+
+	/*
+	 * We already have some attributes, and just need to add this
+	 * new one.
+	 */
+
+	/*
+	 * We should already have the *required* attributes, which were
+	 * created/added at the same time the first attribute was added.
+	 */
+	PORT_Assert (sec_PKCS7FindAttribute (attrs,
+					     SEC_OID_PKCS9_CONTENT_TYPE,
+					     PR_FALSE) != NULL);
+	PORT_Assert (sec_PKCS7FindAttribute (attrs,
+					     SEC_OID_PKCS9_MESSAGE_DIGEST,
+					     PR_FALSE) != NULL);
+
+	for (count = 0; attrs[count] != NULL; count++)
+	    ;
+	attrs = (SEC_PKCS7Attribute**)PORT_ArenaGrow (cinfo->poolp, attrs,
+				(count + 1) * sizeof(SEC_PKCS7Attribute *),
+				(count + 2) * sizeof(SEC_PKCS7Attribute *));
+	if (attrs == NULL)
+	    return SECFailure;
+
+	attrs[count] = attr;
+	attrs[count+1] = NULL;
+	*attrsp = attrs;
+
+	return SECSuccess;
+    }
+
+    /*
+     * This is the first time an attribute is going in.
+     * We need to create and add the required attributes, and then
+     * we will also add in the one our caller gave us.
+     */
+
+    /*
+     * There are 2 required attributes, plus the one our caller wants
+     * to add, plus we always end with a NULL one.  Thus, four slots.
+     */
+    attrs = (SEC_PKCS7Attribute**)PORT_ArenaAlloc (cinfo->poolp, 
+					   4 * sizeof(SEC_PKCS7Attribute *));
+    if (attrs == NULL)
+	return SECFailure;
+
+    mark = PORT_ArenaMark (cinfo->poolp);
+
+    /*
+     * First required attribute is the content type of the data
+     * being signed.
+     */
+    ct_value = &(cinfo->content.signedData->contentInfo.contentType);
+    attrs[0] = sec_pkcs7_create_attribute (cinfo->poolp,
+					   SEC_OID_PKCS9_CONTENT_TYPE,
+					   ct_value, PR_FALSE);
+    /*
+     * Second required attribute is the message digest of the data
+     * being signed; we leave the value NULL for now (just create
+     * the place for it to go), and the encoder will fill it in later.
+     */
+    attrs[1] = sec_pkcs7_create_attribute (cinfo->poolp,
+					   SEC_OID_PKCS9_MESSAGE_DIGEST,
+					   NULL, PR_FALSE);
+    if (attrs[0] == NULL || attrs[1] == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure; 
+    }
+
+    attrs[2] = attr;
+    attrs[3] = NULL;
+    *attrsp = attrs;
+
+    PORT_ArenaUnmark (cinfo->poolp, mark);
+    return SECSuccess;
+}
+
+
+/*
+ * Add the signing time to the authenticated (i.e. signed) attributes
+ * of "cinfo".  This is expected to be included in outgoing signed
+ * messages for email (S/MIME) but is likely useful in other situations.
+ *
+ * This should only be added once; a second call will either do
+ * nothing or replace an old signing time with a newer one.
+ *
+ * XXX This will probably just shove the current time into "cinfo"
+ * but it will not actually get signed until the entire item is
+ * processed for encoding.  Is this (expected to be small) delay okay?
+ *
+ * "cinfo" should be of type signedData (the only kind of pkcs7 data
+ * that is allowed authenticated attributes); SECFailure will be returned
+ * if it is not.
+ */
+SECStatus
+SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo)
+{
+    SEC_PKCS7SignerInfo **signerinfos;
+    SEC_PKCS7Attribute *attr;
+    SECItem stime;
+    SECStatus rv;
+    int si;
+
+    PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
+    if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
+	return SECFailure;
+
+    signerinfos = cinfo->content.signedData->signerInfos;
+
+    /* There has to be a signer, or it makes no sense. */
+    if (signerinfos == NULL || signerinfos[0] == NULL)
+	return SECFailure;
+
+    rv = DER_EncodeTimeChoice(NULL, &stime, PR_Now());
+    if (rv != SECSuccess)
+	return rv;
+
+    attr = sec_pkcs7_create_attribute (cinfo->poolp,
+				       SEC_OID_PKCS9_SIGNING_TIME,
+				       &stime, PR_FALSE);
+    SECITEM_FreeItem (&stime, PR_FALSE);
+
+    if (attr == NULL)
+	return SECFailure;
+
+    rv = SECSuccess;
+    for (si = 0; signerinfos[si] != NULL; si++) {
+	SEC_PKCS7Attribute *oattr;
+
+	oattr = sec_PKCS7FindAttribute (signerinfos[si]->authAttr,
+					SEC_OID_PKCS9_SIGNING_TIME, PR_FALSE);
+	PORT_Assert (oattr == NULL);
+	if (oattr != NULL)
+	    continue;	/* XXX or would it be better to replace it? */
+
+	rv = sec_pkcs7_add_attribute (cinfo, &(signerinfos[si]->authAttr),
+				      attr);
+	if (rv != SECSuccess)
+	    break;	/* could try to continue, but may as well give up now */
+    }
+
+    return rv;
+}
+
+
+/*
+ * Add the specified attribute to the authenticated (i.e. signed) attributes
+ * of "cinfo" -- "oidtag" describes the attribute and "value" is the
+ * value to be associated with it.  NOTE! "value" must already be encoded;
+ * no interpretation of "oidtag" is done.  Also, it is assumed that this
+ * signedData has only one signer -- if we ever need to add attributes
+ * when there is more than one signature, we need a way to specify *which*
+ * signature should get the attribute.
+ *
+ * XXX Technically, a signed attribute can have multiple values; if/when
+ * we ever need to support an attribute which takes multiple values, we
+ * either need to change this interface or create an AddSignedAttributeValue
+ * which can be called subsequently, and would then append a value.
+ *
+ * "cinfo" should be of type signedData (the only kind of pkcs7 data
+ * that is allowed authenticated attributes); SECFailure will be returned
+ * if it is not.
+ */
+SECStatus
+SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,
+			     SECOidTag oidtag,
+			     SECItem *value)
+{
+    SEC_PKCS7SignerInfo **signerinfos;
+    SEC_PKCS7Attribute *attr;
+
+    PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
+    if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
+	return SECFailure;
+
+    signerinfos = cinfo->content.signedData->signerInfos;
+
+    /*
+     * No signature or more than one means no deal.
+     */
+    if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
+	return SECFailure;
+
+    attr = sec_pkcs7_create_attribute (cinfo->poolp, oidtag, value, PR_TRUE);
+    if (attr == NULL)
+	return SECFailure;
+
+    return sec_pkcs7_add_attribute (cinfo, &(signerinfos[0]->authAttr), attr);
+}
+ 
+
+/*
+ * Mark that the signer certificates and their issuing chain should
+ * be included in the encoded data.  This is expected to be used
+ * in outgoing signed messages for email (S/MIME).
+ *
+ * "certdb" is the cert database to use for finding the chain.
+ * It can be NULL, meaning use the default database.
+ *
+ * "cinfo" should be of type signedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ */
+SECStatus
+SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,
+			   CERTCertDBHandle *certdb)
+{
+    SECOidTag kind;
+    SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	signerinfos = cinfo->content.signedData->signerInfos;
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
+	break;
+      default:
+	return SECFailure;		/* XXX set an error? */
+    }
+
+    if (signerinfos == NULL)		/* no signer, no certs? */
+	return SECFailure;		/* XXX set an error? */
+
+    if (certdb == NULL) {
+	certdb = CERT_GetDefaultCertDB();
+	if (certdb == NULL) {
+	    PORT_SetError (SEC_ERROR_BAD_DATABASE);
+	    return SECFailure;
+	}
+    }
+
+    /* XXX Should it be an error if we find no signerinfo or no certs? */
+    while ((signerinfo = *signerinfos++) != NULL) {
+	if (signerinfo->cert != NULL)
+	    /* get the cert chain.  don't send the root to avoid contamination
+	     * of old clients with a new root that they don't trust
+	     */
+	    signerinfo->certList = CERT_CertChainFromCert (signerinfo->cert,
+							   certUsageEmailSigner,
+							   PR_FALSE);
+    }
+
+    return SECSuccess;
+}
+
+
+/*
+ * Helper function to add a certificate chain for inclusion in the
+ * bag of certificates in a signedData.
+ */
+static SECStatus
+sec_pkcs7_add_cert_chain (SEC_PKCS7ContentInfo *cinfo,
+			  CERTCertificate *cert,
+			  CERTCertDBHandle *certdb)
+{
+    SECOidTag kind;
+    CERTCertificateList *certlist, **certlists, ***certlistsp;
+    int count;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    certlistsp = &(sdp->certLists);
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    certlistsp = &(saedp->certLists);
+	}
+	break;
+      default:
+	return SECFailure;		/* XXX set an error? */
+    }
+
+    if (certdb == NULL) {
+	certdb = CERT_GetDefaultCertDB();
+	if (certdb == NULL) {
+	    PORT_SetError (SEC_ERROR_BAD_DATABASE);
+	    return SECFailure;
+	}
+    }
+
+    certlist = CERT_CertChainFromCert (cert, certUsageEmailSigner, PR_FALSE);
+    if (certlist == NULL)
+	return SECFailure;
+
+    certlists = *certlistsp;
+    if (certlists == NULL) {
+	count = 0;
+	certlists = (CERTCertificateList**)PORT_ArenaAlloc (cinfo->poolp,
+				     2 * sizeof(CERTCertificateList *));
+    } else {
+	for (count = 0; certlists[count] != NULL; count++)
+	    ;
+	PORT_Assert (count);	/* should be at least one already */
+	certlists = (CERTCertificateList**)PORT_ArenaGrow (cinfo->poolp, 
+				 certlists,
+				(count + 1) * sizeof(CERTCertificateList *),
+				(count + 2) * sizeof(CERTCertificateList *));
+    }
+
+    if (certlists == NULL) {
+	CERT_DestroyCertificateList (certlist);
+	return SECFailure;
+    }
+
+    certlists[count] = certlist;
+    certlists[count + 1] = NULL;
+
+    *certlistsp = certlists;
+
+    return SECSuccess;
+}
+
+
+/*
+ * Helper function to add a certificate for inclusion in the bag of
+ * certificates in a signedData.
+ */
+static SECStatus
+sec_pkcs7_add_certificate (SEC_PKCS7ContentInfo *cinfo,
+			   CERTCertificate *cert)
+{
+    SECOidTag kind;
+    CERTCertificate **certs, ***certsp;
+    int count;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    certsp = &(sdp->certs);
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    certsp = &(saedp->certs);
+	}
+	break;
+      default:
+	return SECFailure;		/* XXX set an error? */
+    }
+
+    cert = CERT_DupCertificate (cert);
+    if (cert == NULL)
+	return SECFailure;
+
+    certs = *certsp;
+    if (certs == NULL) {
+	count = 0;
+	certs = (CERTCertificate**)PORT_ArenaAlloc (cinfo->poolp, 
+					      2 * sizeof(CERTCertificate *));
+    } else {
+	for (count = 0; certs[count] != NULL; count++)
+	    ;
+	PORT_Assert (count);	/* should be at least one already */
+	certs = (CERTCertificate**)PORT_ArenaGrow (cinfo->poolp, certs,
+				(count + 1) * sizeof(CERTCertificate *),
+				(count + 2) * sizeof(CERTCertificate *));
+    }
+
+    if (certs == NULL) {
+	CERT_DestroyCertificate (cert);
+	return SECFailure;
+    }
+
+    certs[count] = cert;
+    certs[count + 1] = NULL;
+
+    *certsp = certs;
+
+    return SECSuccess;
+}
+
+
+/*
+ * Create a PKCS7 certs-only container.
+ *
+ * "cert" is the (first) cert that will be included.
+ *
+ * "include_chain" specifies whether the entire chain for "cert" should
+ * be included.
+ *
+ * "certdb" is the cert database to use for finding the chain.
+ * It can be NULL in when "include_chain" is false, or when meaning
+ * use the default database.
+ *
+ * More certs and chains can be added via AddCertificate and AddCertChain.
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateCertsOnly (CERTCertificate *cert,
+			  PRBool include_chain,
+			  CERTCertDBHandle *certdb)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    SECStatus rv;
+
+    cinfo = sec_pkcs7_create_signed_data (NULL, NULL);
+    if (cinfo == NULL)
+	return NULL;
+
+    if (include_chain)
+	rv = sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
+    else
+	rv = sec_pkcs7_add_certificate (cinfo, cert);
+
+    if (rv != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    return cinfo;
+}
+
+
+/*
+ * Add "cert" and its entire chain to the set of certs included in "cinfo".
+ *
+ * "certdb" is the cert database to use for finding the chain.
+ * It can be NULL, meaning use the default database.
+ *
+ * "cinfo" should be of type signedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ */
+SECStatus
+SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo,
+		       CERTCertificate *cert,
+		       CERTCertDBHandle *certdb)
+{
+    SECOidTag kind;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    if (kind != SEC_OID_PKCS7_SIGNED_DATA
+	&& kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
+	return SECFailure;		/* XXX set an error? */
+
+    return sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
+}
+
+
+/*
+ * Add "cert" to the set of certs included in "cinfo".
+ *
+ * "cinfo" should be of type signedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ */
+SECStatus
+SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert)
+{
+    SECOidTag kind;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    if (kind != SEC_OID_PKCS7_SIGNED_DATA
+	&& kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
+	return SECFailure;		/* XXX set an error? */
+
+    return sec_pkcs7_add_certificate (cinfo, cert);
+}
+
+
+static SECStatus
+sec_pkcs7_init_encrypted_content_info (SEC_PKCS7EncryptedContentInfo *enccinfo,
+				       PRArenaPool *poolp,
+				       SECOidTag kind, PRBool detached,
+				       SECOidTag encalg, int keysize)
+{
+    SECStatus rv;
+
+    PORT_Assert (enccinfo != NULL && poolp != NULL);
+    if (enccinfo == NULL || poolp == NULL)
+	return SECFailure;
+
+    /*
+     * XXX Some day we may want to allow for other kinds.  That needs
+     * more work and modifications to the creation interface, etc.
+     * For now, allow but notice callers who pass in other kinds.
+     * They are responsible for creating the inner type and encoding,
+     * if it is other than DATA.
+     */
+    PORT_Assert (kind == SEC_OID_PKCS7_DATA);
+
+    enccinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
+    PORT_Assert (enccinfo->contentTypeTag
+	       && enccinfo->contentTypeTag->offset == kind);
+
+    rv = SECITEM_CopyItem (poolp, &(enccinfo->contentType),
+			   &(enccinfo->contentTypeTag->oid));
+    if (rv != SECSuccess)
+	return rv;
+
+    /* Save keysize and algorithm for later. */
+    enccinfo->keysize = keysize;
+    enccinfo->encalg = encalg;
+
+    return SECSuccess;
+}
+
+
+/*
+ * Add a recipient to a PKCS7 thing, verifying their cert first.
+ * Any error returns SECFailure.
+ */
+static SECStatus
+sec_pkcs7_add_recipient (SEC_PKCS7ContentInfo *cinfo,
+			 CERTCertificate *cert,
+			 SECCertUsage certusage,
+			 CERTCertDBHandle *certdb)
+{
+    SECOidTag kind;
+    SEC_PKCS7RecipientInfo *recipientinfo, **recipientinfos, ***recipientinfosp;
+    SECItem *dummy;
+    void *mark;
+    int count;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7EnvelopedData *edp;
+
+	    edp = cinfo->content.envelopedData;
+	    recipientinfosp = &(edp->recipientInfos);
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    recipientinfosp = &(saedp->recipientInfos);
+	}
+	break;
+      default:
+	return SECFailure;		/* XXX set an error? */
+    }
+
+    /*
+     * XXX I think that CERT_VerifyCert should do this if *it* is passed
+     * a NULL database.
+     */
+    if (certdb == NULL) {
+	certdb = CERT_GetDefaultCertDB();
+	if (certdb == NULL)
+	    return SECFailure;		/* XXX set an error? */
+    }
+
+    if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
+			 cinfo->pwfn_arg, NULL) != SECSuccess)
+	{
+	/* XXX Did CERT_VerifyCert set an error? */
+	return SECFailure;
+    }
+
+    mark = PORT_ArenaMark (cinfo->poolp);
+
+    recipientinfo = (SEC_PKCS7RecipientInfo*)PORT_ArenaZAlloc (cinfo->poolp,
+				      sizeof(SEC_PKCS7RecipientInfo));
+    if (recipientinfo == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &recipientinfo->version,
+				   SEC_PKCS7_RECIPIENT_INFO_VERSION);
+    if (dummy == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+    PORT_Assert (dummy == &recipientinfo->version);
+
+    recipientinfo->cert = CERT_DupCertificate (cert);
+    if (recipientinfo->cert == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    recipientinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
+    if (recipientinfo->issuerAndSN == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    /*
+     * Okay, now recipientinfo is all set.  We just need to put it into
+     * the main structure.
+     *
+     * If this is the first recipient, allocate a new recipientinfos array;
+     * otherwise, reallocate the array, making room for the new entry.
+     */
+    recipientinfos = *recipientinfosp;
+    if (recipientinfos == NULL) {
+	count = 0;
+	recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaAlloc (
+					  cinfo->poolp,
+					  2 * sizeof(SEC_PKCS7RecipientInfo *));
+    } else {
+	for (count = 0; recipientinfos[count] != NULL; count++)
+	    ;
+	PORT_Assert (count);	/* should be at least one already */
+	recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaGrow (
+				 cinfo->poolp, recipientinfos,
+				(count + 1) * sizeof(SEC_PKCS7RecipientInfo *),
+				(count + 2) * sizeof(SEC_PKCS7RecipientInfo *));
+    }
+
+    if (recipientinfos == NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+	return SECFailure;
+    }
+
+    recipientinfos[count] = recipientinfo;
+    recipientinfos[count + 1] = NULL;
+
+    *recipientinfosp = recipientinfos;
+
+    PORT_ArenaUnmark (cinfo->poolp, mark);
+    return SECSuccess;
+}
+
+
+/*
+ * Start a PKCS7 enveloping context.
+ *
+ * "cert" is the cert for the recipient.  It will be checked for validity.
+ *
+ * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
+ * XXX Maybe SECCertUsage should be split so that our caller just says
+ * "email" and *we* add the "recipient" part -- otherwise our caller
+ * could be lying about the usage; we do not want to allow encryption
+ * certs for signing or vice versa.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ *
+ * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
+ *
+ * "keysize" specifies the bulk encryption key size, in bits.
+ *
+ * The return value can be passed to functions which add things to
+ * it like more recipients, then eventually to SEC_PKCS7Encode() or to
+ * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
+ * SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert,
+			      SECCertUsage certusage,
+			      CERTCertDBHandle *certdb,
+			      SECOidTag encalg,
+			      int keysize,
+ 			      SECKEYGetPasswordKey pwfn, void *pwfn_arg)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    SEC_PKCS7EnvelopedData *envd;
+    SECStatus rv;
+
+    cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENVELOPED_DATA,
+					   PR_FALSE, pwfn, pwfn_arg);
+    if (cinfo == NULL)
+	return NULL;
+
+    rv = sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
+    if (rv != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    envd = cinfo->content.envelopedData;
+    PORT_Assert (envd != NULL);
+
+    /*
+     * XXX Might we want to allow content types other than data?
+     * If so, via what interface?
+     */
+    rv = sec_pkcs7_init_encrypted_content_info (&(envd->encContentInfo),
+						cinfo->poolp,
+						SEC_OID_PKCS7_DATA, PR_FALSE,
+						encalg, keysize);
+    if (rv != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    /* XXX Anything more to do here? */
+
+    return cinfo;
+}
+
+
+/*
+ * Add another recipient to an encrypted message.
+ *
+ * "cinfo" should be of type envelopedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ *
+ * "cert" is the cert for the recipient.  It will be checked for validity.
+ *
+ * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
+ * XXX Maybe SECCertUsage should be split so that our caller just says
+ * "email" and *we* add the "recipient" part -- otherwise our caller
+ * could be lying about the usage; we do not want to allow encryption
+ * certs for signing or vice versa.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ */
+SECStatus
+SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo,
+		       CERTCertificate *cert,
+		       SECCertUsage certusage,
+		       CERTCertDBHandle *certdb)
+{
+    return sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
+}
+
+
+/*
+ * Create an empty PKCS7 data content info.
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateData (void)
+{
+    return sec_pkcs7_create_content_info (SEC_OID_PKCS7_DATA, PR_FALSE,
+					  NULL, NULL);
+}
+
+
+/*
+ * Create an empty PKCS7 encrypted content info.
+ *
+ * "algorithm" specifies the bulk encryption algorithm to use.
+ * 
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize,
+			      SECKEYGetPasswordKey pwfn, void *pwfn_arg)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    SECAlgorithmID *algid;
+    SEC_PKCS7EncryptedData *enc_data;
+    SECStatus rv;
+
+    cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENCRYPTED_DATA, 
+					   PR_FALSE, pwfn, pwfn_arg);
+    if (cinfo == NULL)
+	return NULL;
+
+    enc_data = cinfo->content.encryptedData;
+    algid = &(enc_data->encContentInfo.contentEncAlg);
+
+    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
+	rv = SECOID_SetAlgorithmID (cinfo->poolp, algid, algorithm, NULL);
+    } else {
+        /* Assume password-based-encryption.  
+         * Note: we can't generate pkcs5v2 from this interface.
+         * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
+         * non-PBE oids and assuming that they are pkcs5v2 oids, but
+         * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
+         * CMS encrypted data, so we can't tell SEC_PKCS7CreateEncryptedtedData
+         * to create pkcs5v2 PBEs */
+	SECAlgorithmID *pbe_algid;
+	pbe_algid = PK11_CreatePBEAlgorithmID (algorithm, 1, NULL);
+	if (pbe_algid == NULL) {
+	    rv = SECFailure;
+	} else {
+	    rv = SECOID_CopyAlgorithmID (cinfo->poolp, algid, pbe_algid);
+	    SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
+	}
+    }
+
+    if (rv != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    rv = sec_pkcs7_init_encrypted_content_info (&(enc_data->encContentInfo),
+						cinfo->poolp,
+						SEC_OID_PKCS7_DATA, PR_FALSE,
+						algorithm, keysize);
+    if (rv != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    return cinfo;
+}
+
diff --git a/mozilla/security/nss/lib/pkcs7/p7decode.c b/mozilla/security/nss/lib/pkcs7/p7decode.c
new file mode 100644
index 0000000..966f4fb
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/p7decode.c
@@ -0,0 +1,2055 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+/*
+ * PKCS7 decoding, verification.
+ *
+ * $Id: p7decode.c,v 1.25 2008/03/10 00:01:26 wtc%google.com Exp $
+ */
+
+#include "p7local.h"
+
+#include "cert.h"
+				/* XXX do not want to have to include */
+#include "certdb.h"		/* certdb.h -- the trust stuff needed by */
+     				/* the add certificate code needs to get */
+                           	/* rewritten/abstracted and then this */
+      				/* include should be removed! */
+/*#include "cdbhdl.h" */
+#include "cryptohi.h"
+#include "key.h"
+#include "secasn1.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "pk11func.h"
+#include "prtime.h"
+#include "secerr.h"
+#include "sechash.h"	/* for HASH_GetHashObject() */
+#include "secder.h"
+#include "secpkcs5.h"
+
+struct sec_pkcs7_decoder_worker {
+    int depth;
+    int digcnt;
+    void **digcxs;
+    const SECHashObject **digobjs;
+    sec_PKCS7CipherObject *decryptobj;
+    PRBool saw_contents;
+};
+
+struct SEC_PKCS7DecoderContextStr {
+    SEC_ASN1DecoderContext *dcx;
+    SEC_PKCS7ContentInfo *cinfo;
+    SEC_PKCS7DecoderContentCallback cb;
+    void *cb_arg;
+    SECKEYGetPasswordKey pwfn;
+    void *pwfn_arg;
+    struct sec_pkcs7_decoder_worker worker;
+    PRArenaPool *tmp_poolp;
+    int error;
+    SEC_PKCS7GetDecryptKeyCallback dkcb;
+    void *dkcb_arg;
+    SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb;
+};
+
+/*
+ * Handle one worker, decrypting and digesting the data as necessary.
+ *
+ * XXX If/when we support nested contents, this probably needs to be
+ * revised somewhat to get passed the content-info (which unfortunately
+ * can be two different types depending on whether it is encrypted or not)
+ * corresponding to the given worker.
+ */
+static void
+sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx,
+			     struct sec_pkcs7_decoder_worker *worker,
+			     const unsigned char *data, unsigned long len,
+			     PRBool final)
+{
+    unsigned char *buf = NULL;
+    SECStatus rv;
+    int i;
+
+    /*
+     * We should really have data to process, or we should be trying
+     * to finish/flush the last block.  (This is an overly paranoid
+     * check since all callers are in this file and simple inspection
+     * proves they do it right.  But it could find a bug in future
+     * modifications/development, that is why it is here.)
+     */
+    PORT_Assert ((data != NULL && len) || final);
+
+    /*
+     * Decrypt this chunk.
+     *
+     * XXX If we get an error, we do not want to do the digest or callback,
+     * but we want to keep decoding.  Or maybe we want to stop decoding
+     * altogether if there is a callback, because obviously we are not
+     * sending the data back and they want to know that.
+     */
+    if (worker->decryptobj != NULL) {
+	/* XXX the following lengths should all be longs? */
+	unsigned int inlen;	/* length of data being decrypted */
+	unsigned int outlen;	/* length of decrypted data */
+	unsigned int buflen;	/* length available for decrypted data */
+	SECItem *plain;
+
+	inlen = len;
+	buflen = sec_PKCS7DecryptLength (worker->decryptobj, inlen, final);
+	if (buflen == 0) {
+	    if (inlen == 0)	/* no input and no output */
+		return;
+	    /*
+	     * No output is expected, but the input data may be buffered
+	     * so we still have to call Decrypt.
+	     */
+	    rv = sec_PKCS7Decrypt (worker->decryptobj, NULL, NULL, 0,
+				   data, inlen, final);
+	    if (rv != SECSuccess) {
+		p7dcx->error = PORT_GetError();
+		return;		/* XXX indicate error? */
+	    }
+	    return;
+	}
+
+	if (p7dcx->cb != NULL) {
+	    buf = (unsigned char *) PORT_Alloc (buflen);
+	    plain = NULL;
+	} else {
+	    unsigned long oldlen;
+
+	    /*
+	     * XXX This assumes one level of content only.
+	     * See comment above about nested content types.
+	     * XXX Also, it should work for signedAndEnvelopedData, too!
+	     */
+	    plain = &(p7dcx->cinfo->
+			content.envelopedData->encContentInfo.plainContent);
+
+	    oldlen = plain->len;
+	    if (oldlen == 0) {
+		buf = (unsigned char*)PORT_ArenaAlloc (p7dcx->cinfo->poolp, 
+						       buflen);
+	    } else {
+		buf = (unsigned char*)PORT_ArenaGrow (p7dcx->cinfo->poolp, 
+				      plain->data,
+				      oldlen, oldlen + buflen);
+		if (buf != NULL)
+		    buf += oldlen;
+	    }
+	    plain->data = buf;
+	}
+	if (buf == NULL) {
+	    p7dcx->error = SEC_ERROR_NO_MEMORY;
+	    return;		/* XXX indicate error? */
+	}
+	rv = sec_PKCS7Decrypt (worker->decryptobj, buf, &outlen, buflen,
+			       data, inlen, final);
+	if (rv != SECSuccess) {
+	    p7dcx->error = PORT_GetError();
+	    return;		/* XXX indicate error? */
+	}
+	if (plain != NULL) {
+	    PORT_Assert (final || outlen == buflen);
+	    plain->len += outlen;
+	}
+	data = buf;
+	len = outlen;
+    }
+
+    /*
+     * Update the running digests.
+     */
+    if (len) {
+	for (i = 0; i < worker->digcnt; i++) {
+	    (* worker->digobjs[i]->update) (worker->digcxs[i], data, len);
+	}
+    }
+
+    /*
+     * Pass back the contents bytes, and free the temporary buffer.
+     */
+    if (p7dcx->cb != NULL) {
+	if (len)
+	    (* p7dcx->cb) (p7dcx->cb_arg, (const char *)data, len);
+	if (worker->decryptobj != NULL) {
+	    PORT_Assert (buf != NULL);
+	    PORT_Free (buf);
+	}
+    }
+}
+
+static void
+sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len,
+			  int depth, SEC_ASN1EncodingPart data_kind)
+{
+    SEC_PKCS7DecoderContext *p7dcx;
+    struct sec_pkcs7_decoder_worker *worker;
+
+    /*
+     * Since we do not handle any nested contents, the only bytes we
+     * are really interested in are the actual contents bytes (not
+     * the identifier, length, or end-of-contents bytes).  If we were
+     * handling nested types we would probably need to do something
+     * smarter based on depth and data_kind.
+     */
+    if (data_kind != SEC_ASN1_Contents)
+	return;
+
+    /*
+     * The ASN.1 decoder should not even call us with a length of 0.
+     * Just being paranoid.
+     */
+    PORT_Assert (len);
+    if (len == 0)
+	return;
+
+    p7dcx = (SEC_PKCS7DecoderContext*)arg;
+
+    /*
+     * Handling nested contents would mean that there is a chain
+     * of workers -- one per each level of content.  The following
+     * would start with the first worker and loop over them.
+     */
+    worker = &(p7dcx->worker);
+
+    worker->saw_contents = PR_TRUE;
+
+    sec_pkcs7_decoder_work_data (p7dcx, worker,
+				 (const unsigned char *) data, len, PR_FALSE);
+}
+
+
+/*
+ * Create digest contexts for each algorithm in "digestalgs".
+ * No algorithms is not an error, we just do not do anything.
+ * An error (like trouble allocating memory), marks the error
+ * in "p7dcx" and returns SECFailure, which means that our caller
+ * should just give up altogether.
+ */
+static SECStatus
+sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth,
+				 SECAlgorithmID **digestalgs)
+{
+    int i, digcnt;
+
+    if (digestalgs == NULL)
+	return SECSuccess;
+
+    /*
+     * Count the algorithms.
+     */
+    digcnt = 0;
+    while (digestalgs[digcnt] != NULL)
+	digcnt++;
+
+    /*
+     * No algorithms means no work to do.
+     * Just act as if there were no algorithms specified.
+     */
+    if (digcnt == 0)
+	return SECSuccess;
+
+    p7dcx->worker.digcxs = (void**)PORT_ArenaAlloc (p7dcx->tmp_poolp,
+					    digcnt * sizeof (void *));
+    p7dcx->worker.digobjs = (const SECHashObject**)PORT_ArenaAlloc (p7dcx->tmp_poolp,
+					     digcnt * sizeof (SECHashObject *));
+    if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) {
+	p7dcx->error = SEC_ERROR_NO_MEMORY;
+	return SECFailure;
+    }
+
+    p7dcx->worker.depth = depth;
+    p7dcx->worker.digcnt = 0;
+
+    /*
+     * Create a digest context for each algorithm.
+     */
+    for (i = 0; i < digcnt; i++) {
+	SECAlgorithmID *     algid  = digestalgs[i];
+	SECOidTag            oidTag = SECOID_FindOIDTag(&(algid->algorithm));
+	const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
+	void *digcx;
+
+	/*
+	 * Skip any algorithm we do not even recognize; obviously,
+	 * this could be a problem, but if it is critical then the
+	 * result will just be that the signature does not verify.
+	 * We do not necessarily want to error out here, because
+	 * the particular algorithm may not actually be important,
+	 * but we cannot know that until later.
+	 */
+	if (digobj == NULL) {
+	    p7dcx->worker.digcnt--;
+	    continue;
+	}
+
+	digcx = (* digobj->create)();
+	if (digcx != NULL) {
+	    (* digobj->begin) (digcx);
+	    p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj;
+	    p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx;
+	    p7dcx->worker.digcnt++;
+	}
+    }
+
+    if (p7dcx->worker.digcnt != 0)
+	SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
+				      sec_pkcs7_decoder_filter,
+				      p7dcx,
+				      (PRBool)(p7dcx->cb != NULL));
+    return SECSuccess;
+}
+
+
+/*
+ * Close out all of the digest contexts, storing the results in "digestsp".
+ */
+static SECStatus
+sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx,
+				  PRArenaPool *poolp,
+				  SECItem ***digestsp)
+{
+    struct sec_pkcs7_decoder_worker *worker;
+    const SECHashObject *digobj;
+    void *digcx;
+    SECItem **digests, *digest;
+    int i;
+    void *mark;
+
+    /*
+     * XXX Handling nested contents would mean that there is a chain
+     * of workers -- one per each level of content.  The following
+     * would want to find the last worker in the chain.
+     */
+    worker = &(p7dcx->worker);
+
+    /*
+     * If no digests, then we have nothing to do.
+     */
+    if (worker->digcnt == 0)
+	return SECSuccess;
+
+    /*
+     * No matter what happens after this, we want to stop filtering.
+     * XXX If we handle nested contents, we only want to stop filtering
+     * if we are finishing off the *last* worker.
+     */
+    SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
+
+    /*
+     * If we ended up with no contents, just destroy each
+     * digest context -- they are meaningless and potentially
+     * confusing, because their presence would imply some content
+     * was digested.
+     */
+    if (! worker->saw_contents) {
+	for (i = 0; i < worker->digcnt; i++) {
+	    digcx = worker->digcxs[i];
+	    digobj = worker->digobjs[i];
+	    (* digobj->destroy) (digcx, PR_TRUE);
+	}
+	return SECSuccess;
+    }
+
+    mark = PORT_ArenaMark (poolp);
+
+    /*
+     * Close out each digest context, saving digest away.
+     */
+    digests = 
+      (SECItem**)PORT_ArenaAlloc (poolp,(worker->digcnt+1)*sizeof(SECItem *));
+    digest = (SECItem*)PORT_ArenaAlloc (poolp, worker->digcnt*sizeof(SECItem));
+    if (digests == NULL || digest == NULL) {
+	p7dcx->error = PORT_GetError();
+	PORT_ArenaRelease (poolp, mark);
+	return SECFailure;
+    }
+
+    for (i = 0; i < worker->digcnt; i++, digest++) {
+	digcx = worker->digcxs[i];
+	digobj = worker->digobjs[i];
+
+	digest->data = (unsigned char*)PORT_ArenaAlloc (poolp, digobj->length);
+	if (digest->data == NULL) {
+	    p7dcx->error = PORT_GetError();
+	    PORT_ArenaRelease (poolp, mark);
+	    return SECFailure;
+	}
+
+	digest->len = digobj->length;
+	(* digobj->end) (digcx, digest->data, &(digest->len), digest->len);
+	(* digobj->destroy) (digcx, PR_TRUE);
+
+	digests[i] = digest;
+    }
+    digests[i] = NULL;
+    *digestsp = digests;
+
+    PORT_ArenaUnmark (poolp, mark);
+    return SECSuccess;
+}
+
+/*
+ * XXX Need comment explaining following helper function (which is used
+ * by sec_pkcs7_decoder_start_decrypt).
+ */
+extern const SEC_ASN1Template SEC_SMIMEKEAParamTemplateAllParams[];
+
+static PK11SymKey *
+sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx,
+				     SEC_PKCS7RecipientInfo **recipientinfos,
+				     SEC_PKCS7EncryptedContentInfo *enccinfo)
+{
+    SEC_PKCS7RecipientInfo *ri;
+    CERTCertificate *cert = NULL;
+    SECKEYPrivateKey *privkey = NULL;
+    PK11SymKey *bulkkey = NULL;
+    SECOidTag keyalgtag, bulkalgtag, encalgtag;
+    PK11SlotInfo *slot = NULL;
+    int bulkLength = 0;
+
+    if (recipientinfos == NULL || recipientinfos[0] == NULL) {
+	p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
+	goto no_key_found;
+    }
+
+    cert = PK11_FindCertAndKeyByRecipientList(&slot,recipientinfos,&ri,
+						&privkey, p7dcx->pwfn_arg);
+    if (cert == NULL) {
+	p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
+	goto no_key_found;
+    }
+
+    ri->cert = cert;		/* so we can find it later */
+    PORT_Assert(privkey != NULL);
+
+    keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
+    encalgtag = SECOID_GetAlgorithmTag (&(ri->keyEncAlg));
+    if ((encalgtag != SEC_OID_NETSCAPE_SMIME_KEA) && (keyalgtag != encalgtag)) {
+	p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH;
+	goto no_key_found;
+    }
+    bulkalgtag = SECOID_GetAlgorithmTag (&(enccinfo->contentEncAlg));
+
+    switch (encalgtag) {
+      case SEC_OID_PKCS1_RSA_ENCRYPTION:
+	bulkkey = PK11_PubUnwrapSymKey (privkey, &ri->encKey,
+					PK11_AlgtagToMechanism (bulkalgtag),
+					CKA_DECRYPT, 0);
+	if (bulkkey == NULL) {
+	    p7dcx->error = PORT_GetError();
+	    PORT_SetError(0);
+	    goto no_key_found;
+	}
+	break;
+	/* ### mwelch -- KEA */ 
+        case SEC_OID_NETSCAPE_SMIME_KEA:
+	  {
+	      SECStatus err;
+	      CK_MECHANISM_TYPE bulkType;
+	      PK11SymKey *tek;
+	      SECKEYPublicKey *senderPubKey;
+	      SEC_PKCS7SMIMEKEAParameters   keaParams;
+
+	      (void) memset(&keaParams, 0, sizeof(keaParams));
+
+	      /* Decode the KEA algorithm parameters. */
+	      err = SEC_ASN1DecodeItem(NULL,
+				       &keaParams,
+				       SEC_SMIMEKEAParamTemplateAllParams,
+				       &(ri->keyEncAlg.parameters));
+	      if (err != SECSuccess)
+	      {
+		  p7dcx->error = err;
+		  PORT_SetError(0);
+		  goto no_key_found;
+	      }
+	  
+
+	      /* We just got key data, no key structure. So, we
+		 create one. */
+	     senderPubKey = 
+		  PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
+				     keaParams.originatorKEAKey.len);
+	     if (senderPubKey == NULL)
+	     {
+		    p7dcx->error = PORT_GetError();
+		    PORT_SetError(0);
+		    goto no_key_found;
+	     }
+	      
+	     /* Generate the TEK (token exchange key) which we use
+	         to unwrap the bulk encryption key. */
+	     tek = PK11_PubDerive(privkey, senderPubKey, 
+				   PR_FALSE,
+				   &keaParams.originatorRA,
+				   NULL,
+				   CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
+				   CKA_WRAP, 0, p7dcx->pwfn_arg);
+	     SECKEY_DestroyPublicKey(senderPubKey);
+	      
+	     if (tek == NULL)
+	     {
+		  p7dcx->error = PORT_GetError();
+		  PORT_SetError(0);
+		  goto no_key_found;
+	     }
+	      
+	      /* Now that we have the TEK, unwrap the bulk key
+	         with which to decrypt the message. We have to
+		 do one of two different things depending on 
+		 whether Skipjack was used for bulk encryption 
+		 of the message. */
+	      bulkType = PK11_AlgtagToMechanism (bulkalgtag);
+	      switch(bulkType)
+	      {
+	      case CKM_SKIPJACK_CBC64:
+	      case CKM_SKIPJACK_ECB64:
+	      case CKM_SKIPJACK_OFB64:
+	      case CKM_SKIPJACK_CFB64:
+	      case CKM_SKIPJACK_CFB32:
+	      case CKM_SKIPJACK_CFB16:
+	      case CKM_SKIPJACK_CFB8:
+		  /* Skipjack is being used as the bulk encryption algorithm.*/
+		  /* Unwrap the bulk key. */
+		  bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP,
+					      NULL, &ri->encKey, 
+					      CKM_SKIPJACK_CBC64, 
+					      CKA_DECRYPT, 0);
+		  break;
+	      default:
+		  /* Skipjack was not used for bulk encryption of this
+		     message. Use Skipjack CBC64, with the nonSkipjackIV
+		     part of the KEA key parameters, to decrypt 
+		     the bulk key. If we got a parameter indicating that the
+		     bulk key size is different than the encrypted key size,
+		     pass in the real key size. */
+		  
+		  /* Check for specified bulk key length (unspecified implies
+		     that the bulk key length is the same as encrypted length) */
+		  if (keaParams.bulkKeySize.len > 0)
+		  {
+		      p7dcx->error = SEC_ASN1DecodeItem(NULL, &bulkLength,
+					SEC_ASN1_GET(SEC_IntegerTemplate),
+					&keaParams.bulkKeySize);
+		  }
+		  
+		  if (p7dcx->error != SECSuccess)
+		      goto no_key_found;
+		  
+		  bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64,
+					      &keaParams.nonSkipjackIV, 
+					      &ri->encKey,
+					      bulkType,
+					      CKA_DECRYPT, bulkLength);
+	      }
+	      
+	      
+	      if (bulkkey == NULL)
+	      {
+		  p7dcx->error = PORT_GetError();
+		  PORT_SetError(0);
+		  goto no_key_found;
+	      }
+	      break;
+	  }
+      default:
+	p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG;
+	break;
+    }
+
+no_key_found:
+    if (privkey != NULL)
+	SECKEY_DestroyPrivateKey (privkey);
+    if (slot != NULL)
+	PK11_FreeSlot(slot);
+
+    return bulkkey;
+}
+ 
+/*
+ * XXX The following comment is old -- the function used to only handle
+ * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData
+ * as well (and it had all of the code of the helper function above
+ * built into it), though the comment was left as is.  Fix it...
+ *
+ * We are just about to decode the content of an EnvelopedData.
+ * Set up a decryption context so we can decrypt as we go.
+ * Presumably we are one of the recipients listed in "recipientinfos".
+ * (XXX And if we are not, or if we have trouble, what should we do?
+ *  It would be nice to let the decoding still work.  Maybe it should
+ *  be an error if there is a content callback, but not an error otherwise?)
+ * The encryption key and related information can be found in "enccinfo".
+ */
+static SECStatus
+sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth,
+				 SEC_PKCS7RecipientInfo **recipientinfos,
+				 SEC_PKCS7EncryptedContentInfo *enccinfo,
+				 PK11SymKey **copy_key_for_signature)
+{
+    PK11SymKey *bulkkey = NULL;
+    sec_PKCS7CipherObject *decryptobj;
+
+    /*
+     * If a callback is supplied to retrieve the encryption key, 
+     * for instance, for Encrypted Content infos, then retrieve
+     * the bulkkey from the callback.  Otherwise, assume that
+     * we are processing Enveloped or SignedAndEnveloped data
+     * content infos.
+     *
+     * XXX Put an assert here?
+     */
+    if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) {
+	if (p7dcx->dkcb != NULL) {
+	    bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg, 
+				     &(enccinfo->contentEncAlg));
+	}
+	enccinfo->keysize = 0;
+    } else {
+	bulkkey = sec_pkcs7_decoder_get_recipient_key (p7dcx, recipientinfos, 
+						       enccinfo);
+	if (bulkkey == NULL) goto no_decryption;
+	enccinfo->keysize = PK11_GetKeyStrength(bulkkey, 
+						&(enccinfo->contentEncAlg));
+
+    }
+
+    /*
+     * XXX I think following should set error in p7dcx and clear set error
+     * (as used to be done here, or as is done in get_receipient_key above.
+     */
+    if(bulkkey == NULL) {
+	goto no_decryption;
+    }
+    
+    /* 
+     * We want to make sure decryption is allowed.  This is done via
+     * a callback specified in SEC_PKCS7DecoderStart().
+     */
+    if (p7dcx->decrypt_allowed_cb) {
+	if ((*p7dcx->decrypt_allowed_cb) (&(enccinfo->contentEncAlg), 
+					  bulkkey) == PR_FALSE) {
+	    p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
+	    goto no_decryption;
+	}
+    } else {
+	    p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
+	    goto no_decryption;
+    }
+
+    /*
+     * When decrypting a signedAndEnvelopedData, the signature also has
+     * to be decrypted with the bulk encryption key; to avoid having to
+     * get it all over again later (and do another potentially expensive
+     * RSA operation), copy it for later signature verification to use.
+     */
+    if (copy_key_for_signature != NULL)
+	*copy_key_for_signature = PK11_ReferenceSymKey (bulkkey);
+
+    /*
+     * Now we have the bulk encryption key (in bulkkey) and the
+     * the algorithm (in enccinfo->contentEncAlg).  Using those,
+     * create a decryption context.
+     */
+    decryptobj = sec_PKCS7CreateDecryptObject (bulkkey,
+					       &(enccinfo->contentEncAlg));
+
+    /*
+     * We are done with (this) bulkkey now.
+     */
+    PK11_FreeSymKey (bulkkey);
+
+    if (decryptobj == NULL) {
+	p7dcx->error = PORT_GetError();
+	PORT_SetError(0);
+	goto no_decryption;
+    }
+
+    SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
+				  sec_pkcs7_decoder_filter,
+				  p7dcx,
+				  (PRBool)(p7dcx->cb != NULL));
+
+    p7dcx->worker.depth = depth;
+    p7dcx->worker.decryptobj = decryptobj;
+
+    return SECSuccess;
+
+no_decryption:
+    /*
+     * For some reason (error set already, if appropriate), we cannot
+     * decrypt the content.  I am not sure what exactly is the right
+     * thing to do here; in some cases we want to just stop, and in
+     * others we want to let the decoding finish even though we cannot
+     * decrypt the content.  My current thinking is that if the caller
+     * set up a content callback, then they are really interested in
+     * getting (decrypted) content, and if they cannot they will want
+     * to know about it.  However, if no callback was specified, then
+     * maybe it is not important that the decryption failed.
+     */
+    if (p7dcx->cb != NULL)
+	return SECFailure;
+    else
+	return SECSuccess;	/* Let the decoding continue. */
+}
+
+
+static SECStatus
+sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx,
+				  PRArenaPool *poolp,
+				  SEC_PKCS7EncryptedContentInfo *enccinfo)
+{
+    struct sec_pkcs7_decoder_worker *worker;
+
+    /*
+     * XXX Handling nested contents would mean that there is a chain
+     * of workers -- one per each level of content.  The following
+     * would want to find the last worker in the chain.
+     */
+    worker = &(p7dcx->worker);
+
+    /*
+     * If no decryption context, then we have nothing to do.
+     */
+    if (worker->decryptobj == NULL)
+	return SECSuccess;
+
+    /*
+     * No matter what happens after this, we want to stop filtering.
+     * XXX If we handle nested contents, we only want to stop filtering
+     * if we are finishing off the *last* worker.
+     */
+    SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
+
+    /*
+     * Handle the last block.
+     */
+    sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE);
+
+    /*
+     * All done, destroy it.
+     */
+    sec_PKCS7DestroyDecryptObject (worker->decryptobj);
+    worker->decryptobj = NULL;
+
+    return SECSuccess;
+}
+
+
+static void
+sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth)
+{
+    SEC_PKCS7DecoderContext *p7dcx;
+    SEC_PKCS7ContentInfo *cinfo;
+    SEC_PKCS7SignedData *sigd;
+    SEC_PKCS7EnvelopedData *envd;
+    SEC_PKCS7SignedAndEnvelopedData *saed;
+    SEC_PKCS7EncryptedData *encd;
+    SEC_PKCS7DigestedData *digd;
+    PRBool after;
+    SECStatus rv;
+
+    /*
+     * Just to make the code easier to read, create an "after" variable
+     * that is equivalent to "not before".
+     * (This used to be just the statement "after = !before", but that
+     * causes a warning on the mac; to avoid that, we do it the long way.)
+     */
+    if (before)
+	after = PR_FALSE;
+    else
+	after = PR_TRUE;
+
+    p7dcx = (SEC_PKCS7DecoderContext*)arg;
+    cinfo = p7dcx->cinfo;
+
+    if (cinfo->contentTypeTag == NULL) {
+	if (after && dest == &(cinfo->contentType))
+	    cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
+	return;
+    }
+
+    switch (cinfo->contentTypeTag->offset) {
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	sigd = cinfo->content.signedData;
+	if (sigd == NULL)
+	    break;
+
+	if (sigd->contentInfo.contentTypeTag == NULL) {
+	    if (after && dest == &(sigd->contentInfo.contentType))
+		sigd->contentInfo.contentTypeTag =
+			SECOID_FindOID(&(sigd->contentInfo.contentType));
+	    break;
+	}
+
+	/*
+	 * We only set up a filtering digest if the content is
+	 * plain DATA; anything else needs more work because a
+	 * second pass is required to produce a DER encoding from
+	 * an input that can be BER encoded.  (This is a requirement
+	 * of PKCS7 that is unfortunate, but there you have it.)
+	 *
+	 * XXX Also, since we stop here if this is not DATA, the
+	 * inner content is not getting processed at all.  Someday
+	 * we may want to fix that.
+	 */
+	if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) {
+	    /* XXX Set an error in p7dcx->error */
+	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+	    break;
+	}
+
+	/*
+	 * Just before the content, we want to set up a digest context
+	 * for each digest algorithm listed, and start a filter which
+	 * will run all of the contents bytes through that digest.
+	 */
+	if (before && dest == &(sigd->contentInfo.content)) {
+	    rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
+						  sigd->digestAlgorithms);
+	    if (rv != SECSuccess)
+		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+
+	    break;
+	}
+
+	/*
+	 * XXX To handle nested types, here is where we would want
+	 * to check for inner boundaries that need handling.
+	 */
+
+	/*
+	 * Are we done?
+	 */
+	if (after && dest == &(sigd->contentInfo.content)) {
+	    /*
+	     * Close out the digest contexts.  We ignore any error
+	     * because we are stopping anyway; the error status left
+	     * behind in p7dcx will be seen by outer functions.
+	     */
+	    (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
+						     &(sigd->digests));
+
+	    /*
+	     * XXX To handle nested contents, we would need to remove
+	     * the worker from the chain (and free it).
+	     */
+
+	    /*
+	     * Stop notify.
+	     */
+	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+	}
+	break;
+
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	envd = cinfo->content.envelopedData;
+	if (envd == NULL)
+	    break;
+
+	if (envd->encContentInfo.contentTypeTag == NULL) {
+	    if (after && dest == &(envd->encContentInfo.contentType))
+		envd->encContentInfo.contentTypeTag =
+			SECOID_FindOID(&(envd->encContentInfo.contentType));
+	    break;
+	}
+
+	/*
+	 * Just before the content, we want to set up a decryption
+	 * context, and start a filter which will run all of the
+	 * contents bytes through it to determine the plain content.
+	 */
+	if (before && dest == &(envd->encContentInfo.encContent)) {
+	    rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
+						  envd->recipientInfos,
+						  &(envd->encContentInfo),
+						  NULL);
+	    if (rv != SECSuccess)
+		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+
+	    break;
+	}
+
+	/*
+	 * Are we done?
+	 */
+	if (after && dest == &(envd->encContentInfo.encContent)) {
+	    /*
+	     * Close out the decryption context.  We ignore any error
+	     * because we are stopping anyway; the error status left
+	     * behind in p7dcx will be seen by outer functions.
+	     */
+	    (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
+						     &(envd->encContentInfo));
+
+	    /*
+	     * XXX To handle nested contents, we would need to remove
+	     * the worker from the chain (and free it).
+	     */
+
+	    /*
+	     * Stop notify.
+	     */
+	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+	}
+	break;
+
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	saed = cinfo->content.signedAndEnvelopedData;
+	if (saed == NULL)
+	    break;
+
+	if (saed->encContentInfo.contentTypeTag == NULL) {
+	    if (after && dest == &(saed->encContentInfo.contentType))
+		saed->encContentInfo.contentTypeTag =
+			SECOID_FindOID(&(saed->encContentInfo.contentType));
+	    break;
+	}
+
+	/*
+	 * Just before the content, we want to set up a decryption
+	 * context *and* digest contexts, and start a filter which
+	 * will run all of the contents bytes through both.
+	 */
+	if (before && dest == &(saed->encContentInfo.encContent)) {
+	    rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
+						  saed->recipientInfos,
+						  &(saed->encContentInfo),
+						  &(saed->sigKey));
+	    if (rv == SECSuccess)
+		rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
+						      saed->digestAlgorithms);
+	    if (rv != SECSuccess)
+		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+
+	    break;
+	}
+
+	/*
+	 * Are we done?
+	 */
+	if (after && dest == &(saed->encContentInfo.encContent)) {
+	    /*
+	     * Close out the decryption and digests contexts.
+	     * We ignore any errors because we are stopping anyway;
+	     * the error status left behind in p7dcx will be seen by
+	     * outer functions.
+	     *
+	     * Note that the decrypt stuff must be called first;
+	     * it may have a last buffer to do which in turn has
+	     * to be added to the digest.
+	     */
+	    (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
+						     &(saed->encContentInfo));
+	    (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
+						     &(saed->digests));
+
+	    /*
+	     * XXX To handle nested contents, we would need to remove
+	     * the worker from the chain (and free it).
+	     */
+
+	    /*
+	     * Stop notify.
+	     */
+	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+	}
+	break;
+
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+	digd = cinfo->content.digestedData;
+	
+	/* 
+	 * XXX Want to do the digest or not?  Maybe future enhancement...
+	 */
+	if (before && dest == &(digd->contentInfo.content.data)) {
+	    SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, sec_pkcs7_decoder_filter,
+					  p7dcx,
+					  (PRBool)(p7dcx->cb != NULL));
+	    break;
+	}
+
+	/*
+	 * Are we done?
+	 */
+	if (after && dest == &(digd->contentInfo.content.data)) {
+	    SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
+	}
+	break;
+
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	encd = cinfo->content.encryptedData;
+
+	/*
+	 * XXX If the decryption key callback is set, we want to start
+	 * the decryption.  If the callback is not set, we will treat the
+	 * content as plain data, since we do not have the key.
+	 *
+	 * Is this the proper thing to do?
+	 */
+	if (before && dest == &(encd->encContentInfo.encContent)) {
+	    /*
+	     * Start the encryption process if the decryption key callback
+	     * is present.  Otherwise, treat the content like plain data.
+	     */
+	    rv = SECSuccess;
+	    if (p7dcx->dkcb != NULL) {
+		rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, NULL,
+						      &(encd->encContentInfo),
+						      NULL);
+	    }
+
+	    if (rv != SECSuccess)
+		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+		
+	    break;
+	}
+
+	/*
+	 * Are we done?
+	 */
+	if (after && dest == &(encd->encContentInfo.encContent)) {
+	    /*
+	     * Close out the decryption context.  We ignore any error
+	     * because we are stopping anyway; the error status left
+	     * behind in p7dcx will be seen by outer functions.
+	     */
+	    (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
+						     &(encd->encContentInfo));
+
+	    /*
+	     * Stop notify.
+	     */
+	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+	}
+	break;
+
+      case SEC_OID_PKCS7_DATA:
+	/*
+	 * If a output callback has been specified, we want to set the filter
+	 * to call the callback.  This is taken care of in 
+	 * sec_pkcs7_decoder_start_decrypt() or 
+	 * sec_pkcs7_decoder_start_digests() for the other content types.
+	 */ 
+	
+	if (before && dest == &(cinfo->content.data)) {
+
+	    /* 
+	     * Set the filter proc up.
+	     */
+	    SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
+					  sec_pkcs7_decoder_filter,
+					  p7dcx,
+					  (PRBool)(p7dcx->cb != NULL));
+	    break;
+	}
+
+	if (after && dest == &(cinfo->content.data)) {
+	    /*
+	     * Time to clean up after ourself, stop the Notify and Filter
+	     * procedures.
+	     */
+	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+	    SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
+	}
+	break;
+
+      default:
+	SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
+	break;
+    }
+}
+
+
+SEC_PKCS7DecoderContext *
+SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
+		      SECKEYGetPasswordKey pwfn, void *pwfn_arg,
+		      SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, 
+		      void *decrypt_key_cb_arg,
+		      SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
+{
+    SEC_PKCS7DecoderContext *p7dcx;
+    SEC_ASN1DecoderContext *dcx;
+    SEC_PKCS7ContentInfo *cinfo;
+    PRArenaPool *poolp;
+
+    poolp = PORT_NewArena (1024);		/* XXX what is right value? */
+    if (poolp == NULL)
+	return NULL;
+
+    cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
+    if (cinfo == NULL) {
+	PORT_FreeArena (poolp, PR_FALSE);
+	return NULL;
+    }
+
+    cinfo->poolp = poolp;
+    cinfo->pwfn = pwfn;
+    cinfo->pwfn_arg = pwfn_arg;
+    cinfo->created = PR_FALSE;
+    cinfo->refCount = 1;
+
+    p7dcx = 
+      (SEC_PKCS7DecoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7DecoderContext));
+    if (p7dcx == NULL) {
+	PORT_FreeArena (poolp, PR_FALSE);
+	return NULL;
+    }
+
+    p7dcx->tmp_poolp = PORT_NewArena (1024);	/* XXX what is right value? */
+    if (p7dcx->tmp_poolp == NULL) {
+	PORT_Free (p7dcx);
+	PORT_FreeArena (poolp, PR_FALSE);
+	return NULL;
+    }
+
+    dcx = SEC_ASN1DecoderStart (poolp, cinfo, sec_PKCS7ContentInfoTemplate);
+    if (dcx == NULL) {
+	PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
+	PORT_Free (p7dcx);
+	PORT_FreeArena (poolp, PR_FALSE);
+	return NULL;
+    }
+
+    SEC_ASN1DecoderSetNotifyProc (dcx, sec_pkcs7_decoder_notify, p7dcx);
+
+    p7dcx->dcx = dcx;
+    p7dcx->cinfo = cinfo;
+    p7dcx->cb = cb;
+    p7dcx->cb_arg = cb_arg;
+    p7dcx->pwfn = pwfn;
+    p7dcx->pwfn_arg = pwfn_arg;
+    p7dcx->dkcb = decrypt_key_cb;
+    p7dcx->dkcb_arg = decrypt_key_cb_arg;
+    p7dcx->decrypt_allowed_cb = decrypt_allowed_cb;
+
+    return p7dcx;
+}
+
+
+/*
+ * Do the next chunk of PKCS7 decoding.  If there is a problem, set
+ * an error and return a failure status.  Note that in the case of
+ * an error, this routine is still prepared to be called again and
+ * again in case that is the easiest route for our caller to take.
+ * We simply detect it and do not do anything except keep setting
+ * that error in case our caller has not noticed it yet...
+ */
+SECStatus
+SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
+		       const char *buf, unsigned long len)
+{
+    if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) { 
+	PORT_Assert (p7dcx->error == 0);
+	if (p7dcx->error == 0) {
+	    if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) {
+		p7dcx->error = PORT_GetError();
+		PORT_Assert (p7dcx->error);
+		if (p7dcx->error == 0)
+		    p7dcx->error = -1;
+	    }
+	}
+    }
+
+    if (p7dcx->error) {
+	if (p7dcx->dcx != NULL) {
+	    (void) SEC_ASN1DecoderFinish (p7dcx->dcx);
+	    p7dcx->dcx = NULL;
+	}
+	if (p7dcx->cinfo != NULL) {
+	    SEC_PKCS7DestroyContentInfo (p7dcx->cinfo);
+	    p7dcx->cinfo = NULL;
+	}
+	PORT_SetError (p7dcx->error);
+	return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+
+SEC_PKCS7ContentInfo *
+SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+
+    cinfo = p7dcx->cinfo;
+    if (p7dcx->dcx != NULL) {
+	if (SEC_ASN1DecoderFinish (p7dcx->dcx) != SECSuccess) {
+	    SEC_PKCS7DestroyContentInfo (cinfo);
+	    cinfo = NULL;
+	}
+    }
+    /* free any NSS data structures */
+    if (p7dcx->worker.decryptobj) {
+        sec_PKCS7DestroyDecryptObject (p7dcx->worker.decryptobj);
+    }
+    PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
+    PORT_Free (p7dcx);
+    return cinfo;
+}
+
+
+SEC_PKCS7ContentInfo *
+SEC_PKCS7DecodeItem(SECItem *p7item,
+		    SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
+		    SECKEYGetPasswordKey pwfn, void *pwfn_arg,
+		    SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, 
+		    void *decrypt_key_cb_arg,
+		    SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
+{
+    SEC_PKCS7DecoderContext *p7dcx;
+
+    p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb,
+				  decrypt_key_cb_arg, decrypt_allowed_cb);
+    if (!p7dcx) {
+        /* error code is set */
+        return NULL;
+    }
+    (void) SEC_PKCS7DecoderUpdate(p7dcx, (char *) p7item->data, p7item->len);
+    return SEC_PKCS7DecoderFinish(p7dcx);
+}
+
+/*
+ * Abort the ASN.1 stream. Used by pkcs 12
+ */
+void
+SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error)
+{
+    PORT_Assert(p7dcx);
+    SEC_ASN1DecoderAbort(p7dcx->dcx, error);
+}
+
+
+/*
+ * If the thing contains any certs or crls return true; false otherwise.
+ */
+PRBool
+SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo)
+{
+    SECOidTag kind;
+    SECItem **certs;
+    CERTSignedCrl **crls;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	return PR_FALSE;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	certs = cinfo->content.signedData->rawCerts;
+	crls = cinfo->content.signedData->crls;
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	certs = cinfo->content.signedAndEnvelopedData->rawCerts;
+	crls = cinfo->content.signedAndEnvelopedData->crls;
+	break;
+    }
+
+    /*
+     * I know this could be collapsed, but I was in a mood to be explicit.
+     */
+    if (certs != NULL && certs[0] != NULL)
+	return PR_TRUE;
+    else if (crls != NULL && crls[0] != NULL)
+	return PR_TRUE;
+    else
+	return PR_FALSE;
+}
+
+/* return the content length...could use GetContent, however we
+ * need the encrypted content length 
+ */
+PRBool
+SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen)
+{
+    SECItem *item = NULL;
+
+    if(cinfo == NULL) {
+	return PR_TRUE;
+    }
+
+    switch(SEC_PKCS7ContentType(cinfo)) 
+    {
+	case SEC_OID_PKCS7_DATA:
+	    item = cinfo->content.data;
+	    break;
+	case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	    item = &cinfo->content.encryptedData->encContentInfo.encContent;
+	    break;
+	default:
+	    /* add other types */
+	    return PR_FALSE;
+    }
+
+    if(!item) {
+	return PR_TRUE;
+    } else if(item->len <= minLen) {
+	return PR_TRUE;
+    }
+
+    return PR_FALSE;
+}
+
+
+PRBool
+SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo)
+{
+    SECOidTag kind;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	return PR_FALSE;
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	return PR_TRUE;
+    }
+}
+
+
+/*
+ * If the PKCS7 content has a signature (not just *could* have a signature)
+ * return true; false otherwise.  This can/should be called before calling
+ * VerifySignature, which will always indicate failure if no signature is
+ * present, but that does not mean there even was a signature!
+ * Note that the content itself can be empty (detached content was sent
+ * another way); it is the presence of the signature that matters.
+ */
+PRBool
+SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo)
+{
+    SECOidTag kind;
+    SEC_PKCS7SignerInfo **signerinfos;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	return PR_FALSE;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	signerinfos = cinfo->content.signedData->signerInfos;
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
+	break;
+    }
+
+    /*
+     * I know this could be collapsed; but I kind of think it will get
+     * more complicated before I am finished, so...
+     */
+    if (signerinfos != NULL && signerinfos[0] != NULL)
+	return PR_TRUE;
+    else
+	return PR_FALSE;
+}
+
+
+/*
+ * SEC_PKCS7ContentVerifySignature
+ *	Look at a PKCS7 contentInfo and check if the signature is good.
+ *	The digest was either calculated earlier (and is stored in the
+ *	contentInfo itself) or is passed in via "detached_digest".
+ *
+ *	The verification checks that the signing cert is valid and trusted
+ *	for the purpose specified by "certusage".
+ *
+ *	In addition, if "keepcerts" is true, add any new certificates found
+ *	into our local database.
+ *
+ * XXX Each place which returns PR_FALSE should be sure to have a good
+ * error set for inspection by the caller.  Alternatively, we could create
+ * an enumeration of success and each type of failure and return that
+ * instead of a boolean.  For now, the default in a bad situation is to
+ * set the error to SEC_ERROR_PKCS7_BAD_SIGNATURE.  But this should be
+ * reviewed; better (more specific) errors should be possible (to distinguish
+ * a signature failure from a badly-formed pkcs7 signedData, for example).
+ * Some of the errors should probably just be SEC_ERROR_BAD_SIGNATURE,
+ * but that has a less helpful error string associated with it right now;
+ * if/when that changes, review and change these as needed.
+ *
+ * XXX This is broken wrt signedAndEnvelopedData.  In that case, the
+ * message digest is doubly encrypted -- first encrypted with the signer
+ * private key but then again encrypted with the bulk encryption key used
+ * to encrypt the content.  So before we can pass the digest to VerifyDigest,
+ * we need to decrypt it with the bulk encryption key.  Also, in this case,
+ * there should be NO authenticatedAttributes (signerinfo->authAttr should
+ * be NULL).
+ */
+static PRBool
+sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo,
+			   SECCertUsage certusage,
+			   SECItem *detached_digest,
+			   HASH_HashType digest_type,
+			   PRBool keepcerts)
+{
+    SECAlgorithmID **digestalgs, *bulkid;
+    SECItem *digest;
+    SECItem **digests;
+    SECItem **rawcerts;
+    CERTSignedCrl **crls;
+    SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
+    CERTCertificate *cert, **certs;
+    PRBool goodsig;
+    CERTCertDBHandle *certdb, *defaultdb; 
+    SECOidTag encTag,digestTag;
+    HASH_HashType found_type;
+    int i, certcount;
+    SECKEYPublicKey *publickey;
+    SECItem *content_type;
+    PK11SymKey *sigkey;
+    SECItem *encoded_stime;
+    int64 stime;
+    SECStatus rv;
+
+    /*
+     * Everything needed in order to "goto done" safely.
+     */
+    goodsig = PR_FALSE;
+    certcount = 0;
+    cert = NULL;
+    certs = NULL;
+    certdb = NULL;
+    defaultdb = CERT_GetDefaultCertDB();
+    publickey = NULL;
+
+    if (! SEC_PKCS7ContentIsSigned(cinfo)) {
+	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	goto done;
+    }
+
+    PORT_Assert (cinfo->contentTypeTag != NULL);
+
+    switch (cinfo->contentTypeTag->offset) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	/* Could only get here if SEC_PKCS7ContentIsSigned is broken. */
+	PORT_Assert (0);
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    digestalgs = sdp->digestAlgorithms;
+	    digests = sdp->digests;
+	    rawcerts = sdp->rawCerts;
+	    crls = sdp->crls;
+	    signerinfos = sdp->signerInfos;
+	    content_type = &(sdp->contentInfo.contentType);
+	    sigkey = NULL;
+	    bulkid = NULL;
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    digestalgs = saedp->digestAlgorithms;
+	    digests = saedp->digests;
+	    rawcerts = saedp->rawCerts;
+	    crls = saedp->crls;
+	    signerinfos = saedp->signerInfos;
+	    content_type = &(saedp->encContentInfo.contentType);
+	    sigkey = saedp->sigKey;
+	    bulkid = &(saedp->encContentInfo.contentEncAlg);
+	}
+	break;
+    }
+
+    if ((signerinfos == NULL) || (signerinfos[0] == NULL)) {
+	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	goto done;
+    }
+
+    /*
+     * XXX Need to handle multiple signatures; checking them is easy,
+     * but what should be the semantics here (like, return value)?
+     */
+    if (signerinfos[1] != NULL) {
+	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	goto done;
+    }
+
+    signerinfo = signerinfos[0];
+
+    /*
+     * XXX I would like to just pass the issuerAndSN, along with the rawcerts
+     * and crls, to some function that did all of this certificate stuff
+     * (open/close the database if necessary, verifying the certs, etc.)
+     * and gave me back a cert pointer if all was good.
+     */
+    certdb = defaultdb;
+    if (certdb == NULL) {
+	goto done;
+    }
+
+    certcount = 0;
+    if (rawcerts != NULL) {
+	for (; rawcerts[certcount] != NULL; certcount++) {
+	    /* just counting */
+	}
+    }
+
+    /*
+     * Note that the result of this is that each cert in "certs"
+     * needs to be destroyed.
+     */
+    rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs,
+			  keepcerts, PR_FALSE, NULL);
+    if ( rv != SECSuccess ) {
+	goto done;
+    }
+
+    /*
+     * This cert will also need to be freed, but since we save it
+     * in signerinfo for later, we do not want to destroy it when
+     * we leave this function -- we let the clean-up of the entire
+     * cinfo structure later do the destroy of this cert.
+     */
+    cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN);
+    if (cert == NULL) {
+	goto done;
+    }
+
+    signerinfo->cert = cert;
+
+    /*
+     * Get and convert the signing time; if available, it will be used
+     * both on the cert verification and for importing the sender
+     * email profile.
+     */
+    encoded_stime = SEC_PKCS7GetSigningTime (cinfo);
+    if (encoded_stime != NULL) {
+	if (DER_DecodeTimeChoice (&stime, encoded_stime) != SECSuccess)
+	    encoded_stime = NULL;	/* conversion failed, so pretend none */
+    }
+
+    /*
+     * XXX  This uses the signing time, if available.  Additionally, we
+     * might want to, if there is no signing time, get the message time
+     * from the mail header itself, and use that.  That would require
+     * a change to our interface though, and for S/MIME callers to pass
+     * in a time (and for non-S/MIME callers to pass in nothing, or
+     * maybe make them pass in the current time, always?).
+     */
+    if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage,
+			 encoded_stime != NULL ? stime : PR_Now(),
+			 cinfo->pwfn_arg, NULL) != SECSuccess)
+	{
+	/*
+	 * XXX Give the user an option to check the signature anyway?
+	 * If we want to do this, need to give a way to leave and display
+	 * some dialog and get the answer and come back through (or do
+	 * the rest of what we do below elsewhere, maybe by putting it
+	 * in a function that we call below and could call from a dialog
+	 * finish handler).
+	 */
+	goto savecert;
+    }
+
+    publickey = CERT_ExtractPublicKey (cert);
+    if (publickey == NULL)
+	goto done;
+
+    /*
+     * XXX No!  If digests is empty, see if we can create it now by
+     * digesting the contents.  This is necessary if we want to allow
+     * somebody to do a simple decode (without filtering, etc.) and
+     * then later call us here to do the verification.
+     * OR, we can just specify that the interface to this routine
+     * *requires* that the digest(s) be done before calling and either
+     * stashed in the struct itself or passed in explicitly (as would
+     * be done for detached contents).
+     */
+    if ((digests == NULL || digests[0] == NULL)
+	&& (detached_digest == NULL || detached_digest->data == NULL))
+	goto done;
+
+    /*
+     * Find and confirm digest algorithm.
+     */
+    digestTag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm));
+
+    /* make sure we understand the digest type first */
+    found_type = HASH_GetHashTypeByOidTag(digestTag);
+    if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) {
+	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	goto done;
+    }
+
+    if (detached_digest != NULL) {
+	unsigned int hashLen     = HASH_ResultLen(found_type);
+
+	if (digest_type != found_type || 
+	    detached_digest->len != hashLen) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+	digest = detached_digest;
+    } else {
+	PORT_Assert (digestalgs != NULL && digestalgs[0] != NULL);
+	if (digestalgs == NULL || digestalgs[0] == NULL) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+
+	/*
+	 * pick digest matching signerinfo->digestAlg from digests
+	 */
+	for (i = 0; digestalgs[i] != NULL; i++) {
+	    if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag)
+		break;
+	}
+	if (digestalgs[i] == NULL) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+
+	digest = digests[i];
+    }
+
+    encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm));
+    if (encTag == SEC_OID_UNKNOWN) {
+	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	goto done;
+    }
+
+#ifndef NSS_ECC_MORE_THAN_SUITE_B
+    if (encTag == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
+	PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	goto done;
+    }
+#endif
+
+
+    if (signerinfo->authAttr != NULL) {
+	SEC_PKCS7Attribute *attr;
+	SECItem *value;
+	SECItem encoded_attrs;
+
+	/*
+	 * We have a sigkey only for signedAndEnvelopedData, which is
+	 * not supposed to have any authenticated attributes.
+	 */
+	if (sigkey != NULL) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+
+	/*
+	 * PKCS #7 says that if there are any authenticated attributes,
+	 * then there must be one for content type which matches the
+	 * content type of the content being signed, and there must
+	 * be one for message digest which matches our message digest.
+	 * So check these things first.
+	 * XXX Might be nice to have a compare-attribute-value function
+	 * which could collapse the following nicely.
+	 */
+	attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
+				       SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
+	value = sec_PKCS7AttributeValue (attr);
+	if (value == NULL || value->len != content_type->len) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+	if (PORT_Memcmp (value->data, content_type->data, value->len) != 0) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+
+	attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
+				       SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
+	value = sec_PKCS7AttributeValue (attr);
+	if (value == NULL || value->len != digest->len) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+	if (PORT_Memcmp (value->data, digest->data, value->len) != 0) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+
+	/*
+	 * Okay, we met the constraints of the basic attributes.
+	 * Now check the signature, which is based on a digest of
+	 * the DER-encoded authenticated attributes.  So, first we
+	 * encode and then we digest/verify.
+	 */
+	encoded_attrs.data = NULL;
+	encoded_attrs.len = 0;
+	if (sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
+				       &(signerinfo->authAttr)) == NULL)
+	    goto done;
+
+	if (encoded_attrs.data == NULL || encoded_attrs.len == 0) {
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+
+
+	goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data, 
+				   encoded_attrs.len,
+				   publickey, &(signerinfo->encDigest),
+				   encTag, digestTag, NULL,
+				   cinfo->pwfn_arg) == SECSuccess);
+	PORT_Free (encoded_attrs.data);
+    } else {
+	SECItem *sig;
+	SECItem holder;
+	SECStatus rv;
+
+	/*
+	 * No authenticated attributes.
+	 * The signature is based on the plain message digest.
+	 */
+
+	sig = &(signerinfo->encDigest);
+	if (sig->len == 0) {		/* bad signature */
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+	    goto done;
+	}
+
+	if (sigkey != NULL) {
+	    sec_PKCS7CipherObject *decryptobj;
+	    unsigned int buflen;
+
+	    /*
+	     * For signedAndEnvelopedData, we first must decrypt the encrypted
+	     * digest with the bulk encryption key.  The result is the normal
+	     * encrypted digest (aka the signature).
+	     */
+	    decryptobj = sec_PKCS7CreateDecryptObject (sigkey, bulkid);
+	    if (decryptobj == NULL)
+		goto done;
+
+	    buflen = sec_PKCS7DecryptLength (decryptobj, sig->len, PR_TRUE);
+	    PORT_Assert (buflen);
+	    if (buflen == 0) {		/* something is wrong */
+		sec_PKCS7DestroyDecryptObject (decryptobj);
+		goto done;
+	    }
+
+	    holder.data = (unsigned char*)PORT_Alloc (buflen);
+	    if (holder.data == NULL) {
+		sec_PKCS7DestroyDecryptObject (decryptobj);
+		goto done;
+	    }
+
+	    rv = sec_PKCS7Decrypt (decryptobj, holder.data, &holder.len, buflen,
+				   sig->data, sig->len, PR_TRUE);
+	    sec_PKCS7DestroyDecryptObject (decryptobj);
+	    if (rv != SECSuccess) {
+		goto done;
+	    }
+
+	    sig = &holder;
+	}
+
+	goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig,
+				     encTag, digestTag, cinfo->pwfn_arg)
+                            == SECSuccess);
+
+	if (sigkey != NULL) {
+	    PORT_Assert (sig == &holder);
+	    PORT_ZFree (holder.data, holder.len);
+	}
+    }
+
+    if (! goodsig) {
+	/*
+	 * XXX Change the generic error into our specific one, because
+	 * in that case we get a better explanation out of the Security
+	 * Advisor.  This is really a bug in our error strings (the
+	 * "generic" error has a lousy/wrong message associated with it
+	 * which assumes the signature verification was done for the
+	 * purposes of checking the issuer signature on a certificate)
+	 * but this is at least an easy workaround and/or in the
+	 * Security Advisor, which specifically checks for the error
+	 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
+	 * in that case but does not similarly check for
+	 * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would
+	 * probably say the wrong thing in the case that it *was* the
+	 * certificate signature check that failed during the cert
+	 * verification done above.  Our error handling is really a mess.
+	 */
+	if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
+	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
+    }
+
+savecert:
+    /*
+     * Only save the smime profile if we are checking an email message and
+     * the cert has an email address in it.
+     */
+    if ( cert->emailAddr && cert->emailAddr[0] &&
+	( ( certusage == certUsageEmailSigner ) ||
+	 ( certusage == certUsageEmailRecipient ) ) ) {
+	SECItem *profile = NULL;
+	int save_error;
+
+	/*
+	 * Remember the current error set because we do not care about
+	 * anything set by the functions we are about to call.
+	 */
+	save_error = PORT_GetError();
+
+	if (goodsig && (signerinfo->authAttr != NULL)) {
+	    /*
+	     * If the signature is good, then we can save the S/MIME profile,
+	     * if we have one.
+	     */
+	    SEC_PKCS7Attribute *attr;
+
+	    attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
+					   SEC_OID_PKCS9_SMIME_CAPABILITIES,
+					   PR_TRUE);
+	    profile = sec_PKCS7AttributeValue (attr);
+	}
+
+	rv = CERT_SaveSMimeProfile (cert, profile, encoded_stime);
+
+	/*
+	 * Restore the saved error in case the calls above set a new
+	 * one that we do not actually care about.
+	 */
+	PORT_SetError (save_error);
+
+	/*
+	 * XXX Failure is not indicated anywhere -- the signature
+	 * verification itself is unaffected by whether or not the
+	 * profile was successfully saved.
+	 */
+    }
+	
+
+done:
+
+    /*
+     * See comment above about why we do not want to destroy cert
+     * itself here.
+     */
+
+    if (certs != NULL)
+	CERT_DestroyCertArray (certs, certcount);
+
+    if (publickey != NULL)
+	SECKEY_DestroyPublicKey (publickey);
+
+    return goodsig;
+}
+
+/*
+ * SEC_PKCS7VerifySignature
+ *	Look at a PKCS7 contentInfo and check if the signature is good.
+ *	The verification checks that the signing cert is valid and trusted
+ *	for the purpose specified by "certusage".
+ *
+ *	In addition, if "keepcerts" is true, add any new certificates found
+ *	into our local database.
+ */
+PRBool
+SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
+			 SECCertUsage certusage,
+			 PRBool keepcerts)
+{
+    return sec_pkcs7_verify_signature (cinfo, certusage,
+				       NULL, HASH_AlgNULL, keepcerts);
+}
+
+/*
+ * SEC_PKCS7VerifyDetachedSignature
+ *	Look at a PKCS7 contentInfo and check if the signature matches
+ *	a passed-in digest (calculated, supposedly, from detached contents).
+ *	The verification checks that the signing cert is valid and trusted
+ *	for the purpose specified by "certusage".
+ *
+ *	In addition, if "keepcerts" is true, add any new certificates found
+ *	into our local database.
+ */
+PRBool
+SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
+				 SECCertUsage certusage,
+				 SECItem *detached_digest,
+				 HASH_HashType digest_type,
+				 PRBool keepcerts)
+{
+    return sec_pkcs7_verify_signature (cinfo, certusage,
+				       detached_digest, digest_type,
+				       keepcerts);
+}
+
+
+/*
+ * Return the asked-for portion of the name of the signer of a PKCS7
+ * signed object.
+ *
+ * Returns a pointer to allocated memory, which must be freed.
+ * A NULL return value is an error.
+ */
+
+#define sec_common_name 1
+#define sec_email_address 2
+
+static char *
+sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
+{
+    SECOidTag kind;
+    SEC_PKCS7SignerInfo **signerinfos;
+    CERTCertificate *signercert;
+    char *container;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	PORT_Assert (0);
+	return NULL;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    signerinfos = sdp->signerInfos;
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    signerinfos = saedp->signerInfos;
+	}
+	break;
+    }
+
+    if (signerinfos == NULL || signerinfos[0] == NULL)
+	return NULL;
+
+    signercert = signerinfos[0]->cert;
+
+    /*
+     * No cert there; see if we can find one by calling verify ourselves.
+     */
+    if (signercert == NULL) {
+	/*
+	 * The cert usage does not matter in this case, because we do not
+	 * actually care about the verification itself, but we have to pick
+	 * some valid usage to pass in.
+	 */
+	(void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner,
+					   NULL, HASH_AlgNULL, PR_FALSE);
+	signercert = signerinfos[0]->cert;
+	if (signercert == NULL)
+	    return NULL;
+    }
+
+    switch (selector) {
+      case sec_common_name:
+	container = CERT_GetCommonName (&signercert->subject);
+	break;
+      case sec_email_address:
+	if(signercert->emailAddr && signercert->emailAddr[0]) {
+	    container = PORT_Strdup(signercert->emailAddr);
+	} else {
+	    container = NULL;
+	}
+	break;
+      default:
+	PORT_Assert (0);
+	container = NULL;
+	break;
+    }
+
+    return container;
+}
+
+char *
+SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
+{
+    return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name);
+}
+
+char *
+SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
+{
+    return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address);
+}
+
+
+/*
+ * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
+ */
+SECItem *
+SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
+{
+    SEC_PKCS7SignerInfo **signerinfos;
+    SEC_PKCS7Attribute *attr;
+
+    if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
+	return NULL;
+
+    signerinfos = cinfo->content.signedData->signerInfos;
+
+    /*
+     * No signature, or more than one, means no deal.
+     */
+    if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
+	return NULL;
+
+    attr = sec_PKCS7FindAttribute (signerinfos[0]->authAttr,
+				   SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
+    return sec_PKCS7AttributeValue (attr);
+}
diff --git a/mozilla/security/nss/lib/pkcs7/p7encode.c b/mozilla/security/nss/lib/pkcs7/p7encode.c
new file mode 100644
index 0000000..5e11c63
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/p7encode.c
@@ -0,0 +1,1297 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+/*
+ * PKCS7 encoding.
+ *
+ * $Id: p7encode.c,v 1.13 2008/03/10 00:01:26 wtc%google.com Exp $
+ */
+
+#include "p7local.h"
+
+#include "cert.h"
+#include "cryptohi.h"
+#include "keyhi.h"
+#include "secasn1.h"
+#include "secoid.h"
+#include "secitem.h"
+#include "pk11func.h"
+#include "secerr.h"
+#include "sechash.h"	/* for HASH_GetHashObject() */
+
+struct sec_pkcs7_encoder_output {
+    SEC_PKCS7EncoderOutputCallback outputfn;
+    void *outputarg;
+};
+
+struct SEC_PKCS7EncoderContextStr {
+    SEC_ASN1EncoderContext *ecx;
+    SEC_PKCS7ContentInfo *cinfo;
+    struct sec_pkcs7_encoder_output output;
+    sec_PKCS7CipherObject *encryptobj;
+    const SECHashObject *digestobj;
+    void *digestcx;
+};
+
+
+/*
+ * The little output function that the ASN.1 encoder calls to hand
+ * us bytes which we in turn hand back to our caller (via the callback
+ * they gave us).
+ */
+static void
+sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len,
+		      int depth, SEC_ASN1EncodingPart data_kind)
+{
+    struct sec_pkcs7_encoder_output *output;
+
+    output = (struct sec_pkcs7_encoder_output*)arg;
+    output->outputfn (output->outputarg, buf, len);
+}
+
+static sec_PKCS7CipherObject *
+sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo,
+						 PK11SymKey *orig_bulkkey)
+{
+    SECOidTag kind;
+    sec_PKCS7CipherObject *encryptobj;
+    SEC_PKCS7RecipientInfo **recipientinfos, *ri;
+    SEC_PKCS7EncryptedContentInfo *enccinfo;
+    SEC_PKCS7SMIMEKEAParameters   keaParams;
+    SECKEYPublicKey *publickey = NULL;
+    SECKEYPrivateKey *ourPrivKey = NULL;
+    PK11SymKey  *bulkkey;
+    void *mark, *wincx;
+    int i;
+    PRArenaPool *arena = NULL;
+
+    /* Get the context in case we need it below. */
+    wincx = cinfo->pwfn_arg;
+
+    /* Clear keaParams, since cleanup code checks the lengths */
+    (void) memset(&keaParams, 0, sizeof(keaParams));
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	recipientinfos = NULL;
+	enccinfo = NULL;
+	break;
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	{
+	    SEC_PKCS7EncryptedData *encdp;
+
+	    /* To do EncryptedData we *must* be given a bulk key. */
+	    PORT_Assert (orig_bulkkey != NULL);
+	    if (orig_bulkkey == NULL) {
+		/* XXX error? */
+		return NULL;
+	    }
+
+	    encdp = cinfo->content.encryptedData;
+	    recipientinfos = NULL;
+	    enccinfo = &(encdp->encContentInfo);
+	}
+	break;
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7EnvelopedData *envdp;
+
+	    envdp = cinfo->content.envelopedData;
+	    recipientinfos = envdp->recipientInfos;
+	    enccinfo = &(envdp->encContentInfo);
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    recipientinfos = saedp->recipientInfos;
+	    enccinfo = &(saedp->encContentInfo);
+	}
+	break;
+    }
+
+    if (enccinfo == NULL)
+	return NULL;
+
+    bulkkey = orig_bulkkey;
+    if (bulkkey == NULL) {
+	CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
+	PK11SlotInfo *slot;
+
+
+	slot = PK11_GetBestSlot(type,cinfo->pwfn_arg);
+	if (slot == NULL) {
+	    return NULL;
+	}
+	bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8,
+			      cinfo->pwfn_arg);
+	PK11_FreeSlot(slot);
+	if (bulkkey == NULL) {
+	    return NULL;
+	}
+    }
+
+    encryptobj = NULL;
+    mark = PORT_ArenaMark (cinfo->poolp);
+
+    /*
+     * Encrypt the bulk key with the public key of each recipient.
+     */
+    for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
+	CERTCertificate *cert;
+	SECOidTag certalgtag, encalgtag;
+	SECStatus rv;
+	int data_len;
+	SECItem *params = NULL;
+
+	cert = ri->cert;
+	PORT_Assert (cert != NULL);
+	if (cert == NULL)
+	    continue;
+
+	/*
+	 * XXX Want an interface that takes a cert and some data and
+	 * fills in an algorithmID and encrypts the data with the public
+	 * key from the cert.  Or, give me two interfaces -- one which
+	 * gets the algorithm tag from a cert (I should not have to go
+	 * down into the subjectPublicKeyInfo myself) and another which
+	 * takes a public key and algorithm tag and data and encrypts
+	 * the data.  Or something like that.  The point is that all
+	 * of the following hardwired RSA and KEA stuff should be done
+	 * elsewhere.
+	 */
+
+	certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
+
+	switch (certalgtag) {
+	case SEC_OID_PKCS1_RSA_ENCRYPTION:
+	    encalgtag = certalgtag;
+	    publickey = CERT_ExtractPublicKey (cert);
+	    if (publickey == NULL) goto loser;
+		
+	    data_len = SECKEY_PublicKeyStrength(publickey);
+	    ri->encKey.data = 
+	        (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len);
+	    ri->encKey.len = data_len;
+	    if (ri->encKey.data == NULL) goto loser;
+
+	    rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey,
+				bulkkey,&ri->encKey);
+
+	    SECKEY_DestroyPublicKey(publickey);
+	    publickey = NULL;
+	    if (rv != SECSuccess) goto loser;
+	    params = NULL; /* paranoia */
+	    break;
+	/* ### mwelch -- KEA */ 
+      case SEC_OID_MISSI_KEA_DSS_OLD:
+      case SEC_OID_MISSI_KEA_DSS:
+      case SEC_OID_MISSI_KEA:
+	    {
+#define SMIME_FORTEZZA_RA_LENGTH 128
+#define SMIME_FORTEZZA_IV_LENGTH 24
+#define SMIME_FORTEZZA_MAX_KEY_SIZE 256
+		SECStatus err;
+		PK11SymKey *tek;
+		CERTCertificate *ourCert;
+		SECKEYPublicKey *ourPubKey;
+		SECKEATemplateSelector whichKEA = SECKEAInvalid;
+
+		/* We really want to show our KEA tag as the
+		   key exchange algorithm tag. */
+		encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
+
+		/* Get the public key of the recipient. */
+		publickey = CERT_ExtractPublicKey(cert);
+		if (publickey == NULL) goto loser;
+
+		/* Find our own cert, and extract its keys. */
+		ourCert = PK11_FindBestKEAMatch(cert,wincx);
+		if (ourCert == NULL) goto loser;
+
+		arena = PORT_NewArena(1024);
+		if (arena == NULL) goto loser;
+
+		ourPubKey = CERT_ExtractPublicKey(ourCert);
+		if (ourPubKey == NULL)
+		{
+		    CERT_DestroyCertificate(ourCert);
+		    goto loser;
+		}
+
+		/* While we're here, copy the public key into the outgoing
+		 * KEA parameters. */
+		SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey),
+				 &(ourPubKey->u.fortezza.KEAKey));
+		SECKEY_DestroyPublicKey(ourPubKey);
+		ourPubKey = NULL;
+
+		/* Extract our private key in order to derive the 
+		 * KEA key. */
+		ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
+		CERT_DestroyCertificate(ourCert); /* we're done with this */
+		if (!ourPrivKey) goto loser;
+
+		/* Prepare raItem with 128 bytes (filled with zeros). */
+		keaParams.originatorRA.data = 
+		  (unsigned char*)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
+		keaParams.originatorRA.len = SMIME_FORTEZZA_RA_LENGTH;
+
+
+		/* Generate the TEK (token exchange key) which we use
+		 * to wrap the bulk encryption key. (raItem) will be
+		 * filled with a random seed which we need to send to
+		 * the recipient. */
+		tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
+				     &keaParams.originatorRA, NULL,
+				     CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
+				     CKA_WRAP, 0, wincx);
+
+		    SECKEY_DestroyPublicKey(publickey);
+		    SECKEY_DestroyPrivateKey(ourPrivKey);
+		    publickey = NULL;
+		    ourPrivKey = NULL;
+		
+		if (!tek)
+		    goto loser;
+
+		ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp,
+						  SMIME_FORTEZZA_MAX_KEY_SIZE);
+		ri->encKey.len = SMIME_FORTEZZA_MAX_KEY_SIZE;
+
+		if (ri->encKey.data == NULL)
+		{
+		    PK11_FreeSymKey(tek);
+		    goto loser;
+		}
+
+		/* Wrap the bulk key. What we do with the resulting data
+		   depends on whether we're using Skipjack to wrap the key. */
+		switch(PK11_AlgtagToMechanism(enccinfo->encalg))
+		{
+		case CKM_SKIPJACK_CBC64:
+		case CKM_SKIPJACK_ECB64:
+		case CKM_SKIPJACK_OFB64:
+		case CKM_SKIPJACK_CFB64:
+		case CKM_SKIPJACK_CFB32:
+		case CKM_SKIPJACK_CFB16:
+		case CKM_SKIPJACK_CFB8:
+		    /* do SKIPJACK, we use the wrap mechanism */
+		    err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, 
+				      tek, bulkkey, &ri->encKey);
+		    whichKEA = SECKEAUsesSkipjack;
+		    break;
+		default:
+		    /* Not SKIPJACK, we encrypt the raw key data */
+		    keaParams.nonSkipjackIV .data = 
+		      (unsigned char*)PORT_ArenaAlloc(arena,
+						     SMIME_FORTEZZA_IV_LENGTH);
+		    keaParams.nonSkipjackIV.len = SMIME_FORTEZZA_IV_LENGTH;
+		    err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64,
+					  &keaParams.nonSkipjackIV, 
+				          tek, bulkkey, &ri->encKey);
+		    if (err != SECSuccess)
+			goto loser;
+
+		    if (ri->encKey.len != PK11_GetKeyLength(bulkkey))
+		    {
+			/* The size of the encrypted key is not the same as
+			   that of the original bulk key, presumably due to
+			   padding. Encode and store the real size of the
+			   bulk key. */
+			if (SEC_ASN1EncodeInteger(arena, 
+						  &keaParams.bulkKeySize,
+						  PK11_GetKeyLength(bulkkey))
+			    == NULL)
+			    err = (SECStatus)PORT_GetError();
+			else
+			    /* use full template for encoding */
+			    whichKEA = SECKEAUsesNonSkipjackWithPaddedEncKey;
+		    }
+		    else
+			/* enc key length == bulk key length */
+			whichKEA = SECKEAUsesNonSkipjack; 
+		    break;
+		}
+
+		PK11_FreeSymKey(tek);
+		if (err != SECSuccess)
+		    goto loser;
+
+		PORT_Assert( whichKEA != SECKEAInvalid);
+
+		/* Encode the KEA parameters into the recipient info. */
+		params = SEC_ASN1EncodeItem(arena,NULL, &keaParams, 
+				      sec_pkcs7_get_kea_template(whichKEA));
+		if (params == NULL) goto loser;
+		break;
+	    }
+	default:
+	    PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
+	    goto loser;
+	}
+
+	rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, 
+			params);
+	if (rv != SECSuccess)
+	    goto loser;
+	if (arena) PORT_FreeArena(arena,PR_FALSE);
+	arena = NULL;
+    }
+
+    encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey,
+					       enccinfo->encalg,
+					       &(enccinfo->contentEncAlg));
+    if (encryptobj != NULL) {
+	PORT_ArenaUnmark (cinfo->poolp, mark);
+	mark = NULL;		/* good one; do not want to release */
+    }
+    /* fallthru */
+
+loser:
+    if (arena) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    if (publickey) {
+        SECKEY_DestroyPublicKey(publickey);
+    }
+    if (ourPrivKey) {
+        SECKEY_DestroyPrivateKey(ourPrivKey);
+    }
+    if (mark != NULL) {
+	PORT_ArenaRelease (cinfo->poolp, mark);
+    }
+    if (orig_bulkkey == NULL) {
+	if (bulkkey) PK11_FreeSymKey(bulkkey);
+    }
+
+    return encryptobj;
+}
+
+
+static void
+sec_pkcs7_encoder_notify (void *arg, PRBool before, void *dest, int depth)
+{
+    SEC_PKCS7EncoderContext *p7ecx;
+    SEC_PKCS7ContentInfo *cinfo;
+    SECOidTag kind;
+    PRBool before_content;
+
+    /*
+     * We want to notice just before the content field.  After fields are
+     * not interesting to us.
+     */
+    if (!before)
+	return;
+
+    p7ecx = (SEC_PKCS7EncoderContext*)arg;
+    cinfo = p7ecx->cinfo;
+
+    before_content = PR_FALSE;
+
+    /*
+     * Watch for the content field, at which point we want to instruct
+     * the ASN.1 encoder to start taking bytes from the buffer.
+     *
+     * XXX The following assumes the inner content type is data;
+     * if/when we want to handle fully nested types, this will have
+     * to recurse until reaching the innermost data content.
+     */
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+	if (dest == &(cinfo->content.data))
+	    before_content = PR_TRUE;
+	break;
+
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+	{
+	    SEC_PKCS7DigestedData *digd;
+
+	    digd = cinfo->content.digestedData;
+	    if (digd == NULL)
+		break;
+
+	    if (dest == &(digd->contentInfo.content))
+		before_content = PR_TRUE;
+	}
+	break;
+
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	{
+	    SEC_PKCS7EncryptedData *encd;
+
+	    encd = cinfo->content.encryptedData;
+	    if (encd == NULL)
+		break;
+
+	    if (dest == &(encd->encContentInfo.encContent))
+		before_content = PR_TRUE;
+	}
+	break;
+
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7EnvelopedData *envd;
+
+	    envd = cinfo->content.envelopedData;
+	    if (envd == NULL)
+		break;
+
+	    if (dest == &(envd->encContentInfo.encContent))
+		before_content = PR_TRUE;
+	}
+	break;
+
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sigd;
+
+	    sigd = cinfo->content.signedData;
+	    if (sigd == NULL)
+		break;
+
+	    if (dest == &(sigd->contentInfo.content))
+		before_content = PR_TRUE;
+	}
+	break;
+
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saed;
+
+	    saed = cinfo->content.signedAndEnvelopedData;
+	    if (saed == NULL)
+		break;
+
+	    if (dest == &(saed->encContentInfo.encContent))
+		before_content = PR_TRUE;
+	}
+	break;
+    }
+
+    if (before_content) {
+	/*
+	 * This will cause the next SEC_ASN1EncoderUpdate to take the
+	 * contents bytes from the passed-in buffer.
+	 */
+	SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx);
+	/*
+	 * And that is all we needed this notify function for.
+	 */
+	SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx);
+    }
+}
+
+
+static SEC_PKCS7EncoderContext *
+sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo,
+				  PK11SymKey *bulkkey)
+{
+    SEC_PKCS7EncoderContext *p7ecx;
+    SECOidTag kind;
+    PRBool encrypt;
+    SECItem **digests;
+    SECAlgorithmID *digestalg, **digestalgs;
+
+    p7ecx = 
+      (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext));
+    if (p7ecx == NULL)
+	return NULL;
+
+    digests = NULL;
+    digestalg = NULL;
+    digestalgs = NULL;
+    encrypt = PR_FALSE;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+	break;
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+	digestalg = &(cinfo->content.digestedData->digestAlg);
+	break;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	digests = cinfo->content.signedData->digests;
+	digestalgs = cinfo->content.signedData->digestAlgorithms;
+	break;
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	encrypt = PR_TRUE;
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	digests = cinfo->content.signedAndEnvelopedData->digests;
+	digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
+	encrypt = PR_TRUE;
+	break;
+    }
+
+    if (encrypt) {
+	p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey);
+	if (p7ecx->encryptobj == NULL) {
+	    PORT_Free (p7ecx);
+	    return NULL;
+	}
+    }
+
+    if (digestalgs != NULL) {
+	if (digests != NULL) {
+	    /* digests already created (probably for detached data) */
+	    digestalg = NULL;
+	} else {
+	    /*
+	     * XXX Some day we should handle multiple digests; for now,
+	     * assume only one will be done.
+	     */
+	    PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL);
+	    digestalg = digestalgs[0];
+	}
+    }
+
+    if (digestalg != NULL) {
+	SECOidTag  oidTag = SECOID_FindOIDTag(&(digestalg->algorithm));
+
+	p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag);
+	if (p7ecx->digestobj != NULL) {
+	    p7ecx->digestcx = (* p7ecx->digestobj->create) ();
+	    if (p7ecx->digestcx == NULL)
+		p7ecx->digestobj = NULL;
+	    else
+		(* p7ecx->digestobj->begin) (p7ecx->digestcx);
+	}
+	if (p7ecx->digestobj == NULL) {
+	    if (p7ecx->encryptobj != NULL)
+		sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
+	    PORT_Free (p7ecx);
+	    return NULL;
+	}
+    }
+
+    p7ecx->cinfo = cinfo;
+    return p7ecx;
+}
+
+
+SEC_PKCS7EncoderContext *
+SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo,
+		       SEC_PKCS7EncoderOutputCallback outputfn,
+		       void *outputarg,
+		       PK11SymKey *bulkkey)
+{
+    SEC_PKCS7EncoderContext *p7ecx;
+    SECStatus rv;
+
+    p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
+    if (p7ecx == NULL)
+	return NULL;
+
+    p7ecx->output.outputfn = outputfn;
+    p7ecx->output.outputarg = outputarg;
+
+    /*
+     * Initialize the BER encoder.
+     */
+    p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate,
+				       sec_pkcs7_encoder_out, &(p7ecx->output));
+    if (p7ecx->ecx == NULL) {
+	PORT_Free (p7ecx);
+	return NULL;
+    }
+
+    /*
+     * Indicate that we are streaming.  We will be streaming until we
+     * get past the contents bytes.
+     */
+    SEC_ASN1EncoderSetStreaming (p7ecx->ecx);
+
+    /*
+     * The notify function will watch for the contents field.
+     */
+    SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);
+
+    /*
+     * This will encode everything up to the content bytes.  (The notify
+     * function will then cause the encoding to stop there.)  Then our
+     * caller can start passing contents bytes to our Update, which we
+     * will pass along.
+     */
+    rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
+    if (rv != SECSuccess) {
+	PORT_Free (p7ecx);
+	return NULL;
+    }
+
+    return p7ecx;
+}
+
+
+/*
+ * XXX If/when we support nested contents, this needs to be revised.
+ */
+static SECStatus
+sec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest,
+			     const unsigned char *data, unsigned long len,
+			     PRBool final)
+{
+    unsigned char *buf = NULL;
+    SECStatus rv;
+
+
+    rv = SECSuccess;		/* may as well be optimistic */
+
+    /*
+     * We should really have data to process, or we should be trying
+     * to finish/flush the last block.  (This is an overly paranoid
+     * check since all callers are in this file and simple inspection
+     * proves they do it right.  But it could find a bug in future
+     * modifications/development, that is why it is here.)
+     */
+    PORT_Assert ((data != NULL && len) || final);
+
+    /*
+     * Update the running digest.
+     * XXX This needs modification if/when we handle multiple digests.
+     */
+    if (len && p7ecx->digestobj != NULL) {
+	(* p7ecx->digestobj->update) (p7ecx->digestcx, data, len);
+    }
+
+    /*
+     * Encrypt this chunk.
+     */
+    if (p7ecx->encryptobj != NULL) {
+	/* XXX the following lengths should all be longs? */
+	unsigned int inlen;	/* length of data being encrypted */
+	unsigned int outlen;	/* length of encrypted data */
+	unsigned int buflen;	/* length available for encrypted data */
+
+	inlen = len;
+	buflen = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final);
+	if (buflen == 0) {
+	    /*
+	     * No output is expected, but the input data may be buffered
+	     * so we still have to call Encrypt.
+	     */
+	    rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0,
+				   data, inlen, final);
+	    if (final) {
+		len = 0;
+		goto done;
+	    }
+	    return rv;
+	}
+
+	if (dest != NULL)
+	    buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen);
+	else
+	    buf = (unsigned char*)PORT_Alloc (buflen);
+
+	if (buf == NULL) {
+	    rv = SECFailure;
+	} else {
+	    rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen,
+				   data, inlen, final);
+	    data = buf;
+	    len = outlen;
+	}
+	if (rv != SECSuccess) {
+	    if (final)
+		goto done;
+	    return rv;
+	}
+    }
+
+    if (p7ecx->ecx != NULL) {
+	/*
+	 * Encode the contents bytes.
+	 */
+	if(len) {
+	    rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len);
+	}
+    }
+
+done:
+    if (p7ecx->encryptobj != NULL) {
+	if (final)
+	    sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
+	if (dest != NULL) {
+	    dest->data = buf;
+	    dest->len = len;
+	} else if (buf != NULL) {
+	    PORT_Free (buf);
+	}
+    }
+
+    if (final && p7ecx->digestobj != NULL) {
+	SECItem *digest, **digests, ***digestsp;
+	unsigned char *digdata;
+	SECOidTag kind;
+
+	kind = SEC_PKCS7ContentType (p7ecx->cinfo);
+	switch (kind) {
+	  default:
+	    PORT_Assert (0);
+	    return SECFailure;
+	  case SEC_OID_PKCS7_DIGESTED_DATA:
+	    digest = &(p7ecx->cinfo->content.digestedData->digest);
+	    digestsp = NULL;
+	    break;
+	  case SEC_OID_PKCS7_SIGNED_DATA:
+	    digest = NULL;
+	    digestsp = &(p7ecx->cinfo->content.signedData->digests);
+	    break;
+	  case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	    digest = NULL;
+	    digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
+	    break;
+	}
+
+	digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
+				   p7ecx->digestobj->length);
+	if (digdata == NULL)
+	    return SECFailure;
+
+	if (digestsp != NULL) {
+	    PORT_Assert (digest == NULL);
+
+	    digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, 
+						sizeof(SECItem));
+	    digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
+				       2 * sizeof(SECItem *));
+	    if (digests == NULL || digest == NULL)
+		return SECFailure;
+
+	    digests[0] = digest;
+	    digests[1] = NULL;
+
+	    *digestsp = digests;
+	}
+
+	PORT_Assert (digest != NULL);
+
+	digest->data = digdata;
+	digest->len = p7ecx->digestobj->length;
+
+	(* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data,
+				   &(digest->len), digest->len);
+	(* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE);
+    }
+
+    return rv;
+}
+
+
+SECStatus
+SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx,
+			const char *data, unsigned long len)
+{
+    /* XXX Error handling needs help.  Return what?  Do "Finish" on failure? */
+    return sec_pkcs7_encoder_work_data (p7ecx, NULL,
+					(const unsigned char *)data, len,
+					PR_FALSE);
+}
+
+static SECStatus
+sec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo,
+				 SECKEYGetPasswordKey pwfn, void *pwfnarg)
+{
+    SECOidTag kind;
+    CERTCertificate **certs;
+    CERTCertificateList **certlists;
+    SECAlgorithmID **digestalgs;
+    SECItem **digests;
+    SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
+    SECItem **rawcerts, ***rawcertsp;
+    PRArenaPool *poolp;
+    int certcount;
+    int ci, cli, rci, si;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+      case SEC_OID_PKCS7_DATA:
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	certs = NULL;
+	certlists = NULL;
+	digestalgs = NULL;
+	digests = NULL;
+	signerinfos = NULL;
+	rawcertsp = NULL;
+	break;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    certs = sdp->certs;
+	    certlists = sdp->certLists;
+	    digestalgs = sdp->digestAlgorithms;
+	    digests = sdp->digests;
+	    signerinfos = sdp->signerInfos;
+	    rawcertsp = &(sdp->rawCerts);
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    certs = saedp->certs;
+	    certlists = saedp->certLists;
+	    digestalgs = saedp->digestAlgorithms;
+	    digests = saedp->digests;
+	    signerinfos = saedp->signerInfos;
+	    rawcertsp = &(saedp->rawCerts);
+	}
+	break;
+    }
+
+    if (certs == NULL && certlists == NULL && signerinfos == NULL)
+	return SECSuccess;		/* nothing for us to do! */
+
+    poolp = cinfo->poolp;
+    certcount = 0;
+
+    if (signerinfos != NULL) {
+	SECOidTag digestalgtag;
+	int di;
+	SECStatus rv;
+	CERTCertificate *cert;
+	SECKEYPrivateKey *privkey;
+	SECItem signature;
+	SECOidTag signalgtag;
+
+	PORT_Assert (digestalgs != NULL && digests != NULL);
+
+	/*
+	 * If one fails, we bail right then.  If we want to continue and
+	 * try to do subsequent signatures, this loop, and the departures
+	 * from it, will need to be reworked.
+	 */
+	for (si = 0; signerinfos[si] != NULL; si++) {
+
+	    signerinfo = signerinfos[si];
+
+	    /* find right digest */
+	    digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg));
+	    for (di = 0; digestalgs[di] != NULL; di++) {
+		/* XXX Should I be comparing more than the tag? */
+		if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di]))
+		    break;
+	    }
+	    if (digestalgs[di] == NULL) {
+		/* XXX oops; do what? set an error? */
+		return SECFailure;
+	    }
+	    PORT_Assert (digests[di] != NULL);
+
+	    cert = signerinfo->cert;
+	    privkey = PK11_FindKeyByAnyCert (cert, pwfnarg);
+	    if (privkey == NULL)
+		return SECFailure;
+
+	    /*
+	     * XXX I think there should be a cert-level interface for this,
+	     * so that I do not have to know about subjectPublicKeyInfo...
+	     */
+	    signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.algorithm));
+
+	    /* Fortezza MISSI have weird signature formats.  Map them
+	     * to standard DSA formats */
+	    signalgtag = PK11_FortezzaMapSig(signalgtag);
+
+	    if (signerinfo->authAttr != NULL) {
+		SEC_PKCS7Attribute *attr;
+		SECItem encoded_attrs;
+		SECItem *dummy;
+		SECOidTag algid;
+
+		/*
+		 * First, find and fill in the message digest attribute.
+		 */
+		attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
+					       SEC_OID_PKCS9_MESSAGE_DIGEST,
+					       PR_TRUE);
+		PORT_Assert (attr != NULL);
+		if (attr == NULL) {
+		    SECKEY_DestroyPrivateKey (privkey);
+		    return SECFailure;
+		}
+
+		/*
+		 * XXX The second half of the following assertion prevents
+		 * the encoder from being called twice on the same content.
+		 * Either just remove the second half the assertion, or
+		 * change the code to check if the value already there is
+		 * the same as digests[di], whichever seems more right.
+		 */
+		PORT_Assert (attr->values != NULL && attr->values[0] == NULL);
+		attr->values[0] = digests[di];
+
+		/*
+		 * Before encoding, reorder the attributes so that when they
+		 * are encoded, they will be conforming DER, which is required
+		 * to have a specific order and that is what must be used for
+		 * the hash/signature.  We do this here, rather than building
+		 * it into EncodeAttributes, because we do not want to do
+		 * such reordering on incoming messages (which also uses
+		 * EncodeAttributes) or our old signatures (and other "broken"
+		 * implementations) will not verify.  So, we want to guarantee
+		 * that we send out good DER encodings of attributes, but not
+		 * to expect to receive them.
+		 */
+		rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr);
+		if (rv != SECSuccess) {
+		    SECKEY_DestroyPrivateKey (privkey);
+		    return SECFailure;
+		}
+
+		encoded_attrs.data = NULL;
+		encoded_attrs.len = 0;
+		dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
+						   &(signerinfo->authAttr));
+		if (dummy == NULL) {
+		    SECKEY_DestroyPrivateKey (privkey);
+		    return SECFailure;
+		}
+
+	        algid = SEC_GetSignatureAlgorithmOidTag(privkey->keyType,
+ 							digestalgtag);
+		if (algid == SEC_OID_UNKNOWN) {
+		    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+		    SECKEY_DestroyPrivateKey (privkey);
+		    return SECFailure;
+		}
+		rv = SEC_SignData (&signature,
+				   encoded_attrs.data, encoded_attrs.len,
+				   privkey,
+				   algid);
+		SECITEM_FreeItem (&encoded_attrs, PR_FALSE);
+	    } else {
+		rv = SGN_Digest (privkey, digestalgtag, &signature,
+				 digests[di]);
+	    }
+
+	    SECKEY_DestroyPrivateKey (privkey);
+
+	    if (rv != SECSuccess)
+		return rv;
+
+	    rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature);
+	    if (rv != SECSuccess)
+		return rv;
+
+	    SECITEM_FreeItem (&signature, PR_FALSE);
+
+	    rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg),
+					signalgtag, NULL);
+	    if (rv != SECSuccess)
+		return SECFailure;
+
+	    /*
+	     * Count the cert chain for this signer.
+	     */
+	    if (signerinfo->certList != NULL)
+		certcount += signerinfo->certList->len;
+	}
+    }
+
+    if (certs != NULL) {
+	for (ci = 0; certs[ci] != NULL; ci++)
+	    certcount++;
+    }
+
+    if (certlists != NULL) {
+	for (cli = 0; certlists[cli] != NULL; cli++)
+	    certcount += certlists[cli]->len;
+    }
+
+    if (certcount == 0)
+	return SECSuccess;		/* signing done; no certs */
+
+    /*
+     * Combine all of the certs and cert chains into rawcerts.
+     * Note: certcount is an upper bound; we may not need that many slots
+     * but we will allocate anyway to avoid having to do another pass.
+     * (The temporary space saving is not worth it.)
+     */
+    rawcerts = (SECItem**)PORT_ArenaAlloc (poolp, 
+					(certcount + 1) * sizeof(SECItem *));
+    if (rawcerts == NULL)
+	return SECFailure;
+
+    /*
+     * XXX Want to check for duplicates and not add *any* cert that is
+     * already in the set.  This will be more important when we start
+     * dealing with larger sets of certs, dual-key certs (signing and
+     * encryption), etc.  For the time being we can slide by...
+     */
+    rci = 0;
+    if (signerinfos != NULL) {
+	for (si = 0; signerinfos[si] != NULL; si++) {
+	    signerinfo = signerinfos[si];
+	    for (ci = 0; ci < signerinfo->certList->len; ci++)
+		rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
+	}
+
+    }
+
+    if (certs != NULL) {
+	for (ci = 0; certs[ci] != NULL; ci++)
+	    rawcerts[rci++] = &(certs[ci]->derCert);
+    }
+
+    if (certlists != NULL) {
+	for (cli = 0; certlists[cli] != NULL; cli++) {
+	    for (ci = 0; ci < certlists[cli]->len; ci++)
+		rawcerts[rci++] = &(certlists[cli]->certs[ci]);
+	}
+    }
+
+    rawcerts[rci] = NULL;
+    *rawcertsp = rawcerts;
+
+    return SECSuccess;
+}
+
+
+SECStatus
+SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,
+			SECKEYGetPasswordKey pwfn, void *pwfnarg)
+{
+    SECStatus rv;
+
+    /*
+     * Flush out any remaining data.
+     */
+    rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE);
+
+    /*
+     * Turn off streaming stuff.
+     */
+    SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx);
+    SEC_ASN1EncoderClearStreaming (p7ecx->ecx);
+
+    if (rv != SECSuccess)
+	goto loser;
+
+    rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg);
+    if (rv != SECSuccess)
+	goto loser;
+
+    rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
+
+loser:
+    SEC_ASN1EncoderFinish (p7ecx->ecx);
+    PORT_Free (p7ecx);
+    return rv;
+}
+
+/*
+ * Abort the ASN.1 stream. Used by pkcs 12
+ */
+void
+SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7ecx, int error)
+{
+    PORT_Assert(p7ecx);
+    SEC_ASN1EncoderAbort(p7ecx->ecx, error);
+}
+
+/*
+ * After this routine is called, the entire PKCS7 contentInfo is ready
+ * to be encoded.  This is used internally, but can also be called from
+ * elsewhere for those who want to be able to just have pointers to
+ * the ASN1 template for pkcs7 contentInfo built into their own encodings.
+ */
+SECStatus
+SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,
+			   PK11SymKey *bulkkey,
+			   SECKEYGetPasswordKey pwfn,
+			   void *pwfnarg)
+{
+    SEC_PKCS7EncoderContext *p7ecx;
+    SECItem *content, *enc_content;
+    SECStatus rv;
+
+    p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
+    if (p7ecx == NULL)
+	return SECFailure;
+
+    content = SEC_PKCS7GetContent (cinfo);
+
+    if (p7ecx->encryptobj != NULL) {
+	SECOidTag kind;
+	SEC_PKCS7EncryptedContentInfo *enccinfo;
+
+	kind = SEC_PKCS7ContentType (p7ecx->cinfo);
+	switch (kind) {
+	  default:
+	    PORT_Assert (0);
+	    rv = SECFailure;
+	    goto loser;
+	  case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	    enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
+	    break;
+	  case SEC_OID_PKCS7_ENVELOPED_DATA:
+	    enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
+	    break;
+	  case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	    enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);
+	    break;
+	}
+	enc_content = &(enccinfo->encContent);
+    } else {
+	enc_content = NULL;
+    }
+
+    if (content != NULL && content->data != NULL && content->len) {
+	rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content,
+					  content->data, content->len, PR_TRUE);
+	if (rv != SECSuccess)
+	    goto loser;
+    }
+
+    rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg);
+
+loser:
+    PORT_Free (p7ecx);
+    return rv;
+}
+
+
+/*
+ * Encode a PKCS7 object, in one shot.  All necessary components
+ * of the object must already be specified.  Either the data has
+ * already been included (via SetContent), or the data is detached,
+ * or there is no data at all (certs-only).
+ *
+ * "cinfo" specifies the object to be encoded.
+ *
+ * "outputfn" is where the encoded bytes will be passed.
+ *
+ * "outputarg" is an opaque argument to the above callback.
+ *
+ * "bulkkey" specifies the bulk encryption key to use.   This argument
+ * can be NULL if no encryption is being done, or if the bulk key should
+ * be generated internally (usually the case for EnvelopedData but never
+ * for EncryptedData, which *must* provide a bulk encryption key).
+ *
+ * "pwfn" is a callback for getting the password which protects the
+ * private key of the signer.  This argument can be NULL if it is known
+ * that no signing is going to be done.
+ *
+ * "pwfnarg" is an opaque argument to the above callback.
+ */
+SECStatus
+SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,
+		 SEC_PKCS7EncoderOutputCallback outputfn,
+		 void *outputarg,
+		 PK11SymKey *bulkkey,
+		 SECKEYGetPasswordKey pwfn,
+		 void *pwfnarg)
+{
+    SECStatus rv;
+
+    rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
+    if (rv == SECSuccess) {
+	struct sec_pkcs7_encoder_output outputcx;
+
+	outputcx.outputfn = outputfn;
+	outputcx.outputarg = outputarg;
+
+	rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate,
+			     sec_pkcs7_encoder_out, &outputcx);
+    }
+
+    return rv;
+}
+
+
+/*
+ * Encode a PKCS7 object, in one shot.  All necessary components
+ * of the object must already be specified.  Either the data has
+ * already been included (via SetContent), or the data is detached,
+ * or there is no data at all (certs-only).  The output, rather than
+ * being passed to an output function as is done above, is all put
+ * into a SECItem.
+ *
+ * "pool" specifies a pool from which to allocate the result.
+ * It can be NULL, in which case memory is allocated generically.
+ *
+ * "dest" specifies a SECItem in which to put the result data.
+ * It can be NULL, in which case the entire item is allocated, too.
+ *
+ * "cinfo" specifies the object to be encoded.
+ *
+ * "bulkkey" specifies the bulk encryption key to use.   This argument
+ * can be NULL if no encryption is being done, or if the bulk key should
+ * be generated internally (usually the case for EnvelopedData but never
+ * for EncryptedData, which *must* provide a bulk encryption key).
+ *
+ * "pwfn" is a callback for getting the password which protects the
+ * private key of the signer.  This argument can be NULL if it is known
+ * that no signing is going to be done.
+ *
+ * "pwfnarg" is an opaque argument to the above callback.
+ */
+SECItem *
+SEC_PKCS7EncodeItem (PRArenaPool *pool,
+		     SECItem *dest,
+		     SEC_PKCS7ContentInfo *cinfo,
+		     PK11SymKey *bulkkey,
+		     SECKEYGetPasswordKey pwfn,
+		     void *pwfnarg)
+{
+    SECStatus rv;
+
+    rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
+    if (rv != SECSuccess)
+	return NULL;
+
+    return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
+}
+
diff --git a/mozilla/security/nss/lib/pkcs7/p7local.c b/mozilla/security/nss/lib/pkcs7/p7local.c
new file mode 100644
index 0000000..1c084fc
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/p7local.c
@@ -0,0 +1,1408 @@
+/* ***** 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 ***** */
+
+/*
+ * Support routines for PKCS7 implementation, none of which are exported.
+ * This file should only contain things that are needed by both the
+ * encoding/creation side *and* the decoding/decryption side.  Anything
+ * else should be static routines in the appropriate file.
+ *
+ * $Id: p7local.c,v 1.13 2008/05/30 03:39:46 nelson%bolyard.com Exp $
+ */
+
+#include "p7local.h"
+
+#include "cryptohi.h" 
+#include "secasn1.h"
+#include "secoid.h"
+#include "secitem.h"
+#include "pk11func.h"
+#include "secpkcs5.h"
+#include "secerr.h"
+
+/*
+ * -------------------------------------------------------------------
+ * Cipher stuff.
+ */
+
+typedef SECStatus (*sec_pkcs7_cipher_function) (void *,
+						unsigned char *,
+						unsigned *,
+						unsigned int,
+						const unsigned char *,
+						unsigned int);
+typedef SECStatus (*sec_pkcs7_cipher_destroy) (void *, PRBool);
+
+#define BLOCK_SIZE 4096
+
+struct sec_pkcs7_cipher_object {
+    void *cx;
+    sec_pkcs7_cipher_function doit;
+    sec_pkcs7_cipher_destroy destroy;
+    PRBool encrypt;
+    int block_size;
+    int pad_size;
+    int pending_count;
+    unsigned char pending_buf[BLOCK_SIZE];
+};
+
+SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
+SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate)
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
+
+/*
+ * Create a cipher object to do decryption,  based on the given bulk
+ * encryption key and algorithm identifier (which may include an iv).
+ *
+ * XXX This interface, or one similar, would be really nice available
+ * in general...  I tried to keep the pkcs7-specific stuff (mostly
+ * having to do with padding) out of here.
+ *
+ * XXX Once both are working, it might be nice to combine this and the
+ * function below (for starting up encryption) into one routine, and just
+ * have two simple cover functions which call it. 
+ */
+sec_PKCS7CipherObject *
+sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid)
+{
+    sec_PKCS7CipherObject *result;
+    SECOidTag algtag;
+    void *ciphercx;
+    CK_MECHANISM_TYPE cryptoMechType;
+    SECItem *param;
+    PK11SlotInfo *slot;
+
+    result = (struct sec_pkcs7_cipher_object*)
+      PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
+    if (result == NULL)
+	return NULL;
+
+    ciphercx = NULL;
+    algtag = SECOID_GetAlgorithmTag (algid);
+
+    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
+	SECItem *pwitem;
+
+	pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
+	if (!pwitem) {
+	    PORT_Free(result);
+	    return NULL;
+	}
+
+	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
+	if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	    PORT_Free(result);
+	    return NULL;
+	}
+    } else {
+	cryptoMechType = PK11_AlgtagToMechanism(algtag);
+	param = PK11_ParamFromAlgid(algid);
+	if (param == NULL) {
+	    PORT_Free(result);
+	    return NULL;
+	}
+    }
+
+    result->pad_size = PK11_GetBlockSize(cryptoMechType, param);
+    slot = PK11_GetSlotFromKey(key);
+    result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
+    PK11_FreeSlot(slot);
+    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, 
+					  key, param);
+    SECITEM_FreeItem(param,PR_TRUE);
+    if (ciphercx == NULL) {
+	PORT_Free (result);
+	return NULL;
+    }
+
+    result->cx = ciphercx;
+    result->doit =  (sec_pkcs7_cipher_function) PK11_CipherOp;
+    result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
+    result->encrypt = PR_FALSE;
+    result->pending_count = 0;
+
+    return result;
+}
+
+/*
+ * Create a cipher object to do encryption, based on the given bulk
+ * encryption key and algorithm tag.  Fill in the algorithm identifier
+ * (which may include an iv) appropriately.
+ *
+ * XXX This interface, or one similar, would be really nice available
+ * in general...  I tried to keep the pkcs7-specific stuff (mostly
+ * having to do with padding) out of here.
+ *
+ * XXX Once both are working, it might be nice to combine this and the
+ * function above (for starting up decryption) into one routine, and just
+ * have two simple cover functions which call it. 
+ */
+sec_PKCS7CipherObject *
+sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key,
+			      SECOidTag algtag, SECAlgorithmID *algid)
+{
+    sec_PKCS7CipherObject *result;
+    void *ciphercx;
+    SECItem *param;
+    SECStatus rv;
+    CK_MECHANISM_TYPE cryptoMechType;
+    PRBool needToEncodeAlgid = PR_FALSE;
+    PK11SlotInfo *slot;
+
+    result = (struct sec_pkcs7_cipher_object*)
+	      PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
+    if (result == NULL)
+	return NULL;
+
+    ciphercx = NULL;
+    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
+	SECItem *pwitem;
+
+	pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
+	if (!pwitem) {
+	    PORT_Free(result);
+	    return NULL;
+	}
+
+	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
+	if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	    PORT_Free(result);
+	    return NULL;
+	}
+    } else {
+	cryptoMechType = PK11_AlgtagToMechanism(algtag);
+	param = PK11_GenerateNewParam(cryptoMechType, key);
+	if (param == NULL) {
+	    PORT_Free(result);
+	    return NULL;
+	}
+	needToEncodeAlgid = PR_TRUE;
+    }
+
+    result->pad_size = PK11_GetBlockSize(cryptoMechType,param);
+    slot = PK11_GetSlotFromKey(key);
+    result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
+    PK11_FreeSlot(slot);
+    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, 
+    					  key, param);
+    if (ciphercx == NULL) {
+	PORT_Free (result);
+        SECITEM_FreeItem(param,PR_TRUE);
+	return NULL;
+    }
+
+    /*
+     * These are placed after the CreateContextBySymKey() because some
+     * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
+     * Don't move it from here.
+     */
+    if (needToEncodeAlgid) {
+	rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
+	if(rv != SECSuccess) {
+	    PORT_Free (result);
+            SECITEM_FreeItem(param,PR_TRUE);
+	    return NULL;
+	}
+    }
+    SECITEM_FreeItem(param,PR_TRUE);
+
+    result->cx = ciphercx;
+    result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
+    result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
+    result->encrypt = PR_TRUE;
+    result->pending_count = 0;
+
+    return result;
+}
+
+
+/*
+ * Destroy the cipher object.
+ */
+static void
+sec_pkcs7_destroy_cipher (sec_PKCS7CipherObject *obj)
+{
+    (* obj->destroy) (obj->cx, PR_TRUE);
+    PORT_Free (obj);
+}
+
+void
+sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj)
+{
+    PORT_Assert (obj != NULL);
+    if (obj == NULL)
+	return;
+    PORT_Assert (! obj->encrypt);
+    sec_pkcs7_destroy_cipher (obj);
+}
+
+void
+sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj)
+{
+    PORT_Assert (obj != NULL);
+    if (obj == NULL)
+	return;
+    PORT_Assert (obj->encrypt);
+    sec_pkcs7_destroy_cipher (obj);
+}
+
+
+/*
+ * XXX I think all of the following lengths should be longs instead
+ * of ints, but our current crypto interface uses ints, so I did too.
+ */
+
+
+/*
+ * What will be the output length of the next call to decrypt?
+ * Result can be used to perform memory allocations.  Note that the amount
+ * is exactly accurate only when not doing a block cipher or when final
+ * is false, otherwise it is an upper bound on the amount because until
+ * we see the data we do not know how many padding bytes there are
+ * (always between 1 and bsize).
+ *
+ * Note that this can return zero, which does not mean that the decrypt
+ * operation can be skipped!  (It simply means that there are not enough
+ * bytes to make up an entire block; the bytes will be reserved until
+ * there are enough to encrypt/decrypt at least one block.)  However,
+ * if zero is returned it *does* mean that no output buffer need be
+ * passed in to the subsequent decrypt operation, as no output bytes
+ * will be stored.
+ */
+unsigned int
+sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
+			PRBool final)
+{
+    int blocks, block_size;
+
+    PORT_Assert (! obj->encrypt);
+
+    block_size = obj->block_size;
+
+    /*
+     * If this is not a block cipher, then we always have the same
+     * number of output bytes as we had input bytes.
+     */
+    if (block_size == 0)
+	return input_len;
+
+    /*
+     * On the final call, we will always use up all of the pending
+     * bytes plus all of the input bytes, *but*, there will be padding
+     * at the end and we cannot predict how many bytes of padding we
+     * will end up removing.  The amount given here is actually known
+     * to be at least 1 byte too long (because we know we will have
+     * at least 1 byte of padding), but seemed clearer/better to me.
+     */
+    if (final)
+	return obj->pending_count + input_len;
+
+    /*
+     * Okay, this amount is exactly what we will output on the
+     * next cipher operation.  We will always hang onto the last
+     * 1 - block_size bytes for non-final operations.  That is,
+     * we will do as many complete blocks as we can *except* the
+     * last block (complete or partial).  (This is because until
+     * we know we are at the end, we cannot know when to interpret
+     * and removing the padding byte(s), which are guaranteed to
+     * be there.)
+     */
+    blocks = (obj->pending_count + input_len - 1) / block_size;
+    return blocks * block_size;
+}
+
+/*
+ * What will be the output length of the next call to encrypt?
+ * Result can be used to perform memory allocations.
+ *
+ * Note that this can return zero, which does not mean that the encrypt
+ * operation can be skipped!  (It simply means that there are not enough
+ * bytes to make up an entire block; the bytes will be reserved until
+ * there are enough to encrypt/decrypt at least one block.)  However,
+ * if zero is returned it *does* mean that no output buffer need be
+ * passed in to the subsequent encrypt operation, as no output bytes
+ * will be stored.
+ */
+unsigned int
+sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
+			PRBool final)
+{
+    int blocks, block_size;
+    int pad_size;
+
+    PORT_Assert (obj->encrypt);
+
+    block_size = obj->block_size;
+    pad_size = obj->pad_size;
+
+    /*
+     * If this is not a block cipher, then we always have the same
+     * number of output bytes as we had input bytes.
+     */
+    if (block_size == 0)
+	return input_len;
+
+    /*
+     * On the final call, we only send out what we need for
+     * remaining bytes plus the padding.  (There is always padding,
+     * so even if we have an exact number of blocks as input, we
+     * will add another full block that is just padding.)
+     */
+    if (final) {
+	if (pad_size == 0) {
+    	    return obj->pending_count + input_len;
+	} else {
+    	    blocks = (obj->pending_count + input_len) / pad_size;
+	    blocks++;
+	    return blocks*pad_size;
+	}
+    }
+
+    /*
+     * Now, count the number of complete blocks of data we have.
+     */
+    blocks = (obj->pending_count + input_len) / block_size;
+
+
+    return blocks * block_size;
+}
+
+
+/*
+ * Decrypt a given length of input buffer (starting at "input" and
+ * containing "input_len" bytes), placing the decrypted bytes in
+ * "output" and storing the output length in "*output_len_p".
+ * "obj" is the return value from sec_PKCS7CreateDecryptObject.
+ * When "final" is true, this is the last of the data to be decrypted.
+ *
+ * This is much more complicated than it sounds when the cipher is
+ * a block-type, meaning that the decryption function will only
+ * operate on whole blocks.  But our caller is operating stream-wise,
+ * and can pass in any number of bytes.  So we need to keep track
+ * of block boundaries.  We save excess bytes between calls in "obj".
+ * We also need to determine which bytes are padding, and remove
+ * them from the output.  We can only do this step when we know we
+ * have the final block of data.  PKCS #7 specifies that the padding
+ * used for a block cipher is a string of bytes, each of whose value is
+ * the same as the length of the padding, and that all data is padded.
+ * (Even data that starts out with an exact multiple of blocks gets
+ * added to it another block, all of which is padding.)
+ */ 
+SECStatus
+sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
+		  unsigned int *output_len_p, unsigned int max_output_len,
+		  const unsigned char *input, unsigned int input_len,
+		  PRBool final)
+{
+    int blocks, bsize, pcount, padsize;
+    unsigned int max_needed, ifraglen, ofraglen, output_len;
+    unsigned char *pbuf;
+    SECStatus rv;
+
+    PORT_Assert (! obj->encrypt);
+
+    /*
+     * Check that we have enough room for the output.  Our caller should
+     * already handle this; failure is really an internal error (i.e. bug).
+     */
+    max_needed = sec_PKCS7DecryptLength (obj, input_len, final);
+    PORT_Assert (max_output_len >= max_needed);
+    if (max_output_len < max_needed) {
+	/* PORT_SetError (XXX); */
+	return SECFailure;
+    }
+
+    /*
+     * hardware encryption does not like small decryption sizes here, so we
+     * allow both blocking and padding.
+     */
+    bsize = obj->block_size;
+    padsize = obj->pad_size;
+
+    /*
+     * When no blocking or padding work to do, we can simply call the
+     * cipher function and we are done.
+     */
+    if (bsize == 0) {
+	return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
+			      input, input_len);
+    }
+
+    pcount = obj->pending_count;
+    pbuf = obj->pending_buf;
+
+    output_len = 0;
+
+    if (pcount) {
+	/*
+	 * Try to fill in an entire block, starting with the bytes
+	 * we already have saved away.
+	 */
+	while (input_len && pcount < bsize) {
+	    pbuf[pcount++] = *input++;
+	    input_len--;
+	}
+	/*
+	 * If we have at most a whole block and this is not our last call,
+	 * then we are done for now.  (We do not try to decrypt a lone
+	 * single block because we cannot interpret the padding bytes
+	 * until we know we are handling the very last block of all input.)
+	 */
+	if (input_len == 0 && !final) {
+	    obj->pending_count = pcount;
+	    if (output_len_p)
+		*output_len_p = 0;
+	    return SECSuccess;
+	}
+	/*
+	 * Given the logic above, we expect to have a full block by now.
+	 * If we do not, there is something wrong, either with our own
+	 * logic or with (length of) the data given to us.
+	 */
+	PORT_Assert ((padsize == 0) || (pcount % padsize) == 0);
+	if ((padsize != 0) && (pcount % padsize) != 0) {
+	    PORT_Assert (final);	
+	    PORT_SetError (SEC_ERROR_BAD_DATA);
+	    return SECFailure;
+	}
+	/*
+	 * Decrypt the block.
+	 */
+	rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
+			    pbuf, pcount);
+	if (rv != SECSuccess)
+	    return rv;
+
+	/*
+	 * For now anyway, all of our ciphers have the same number of
+	 * bytes of output as they do input.  If this ever becomes untrue,
+	 * then sec_PKCS7DecryptLength needs to be made smarter!
+	 */
+	PORT_Assert (ofraglen == pcount);
+
+	/*
+	 * Account for the bytes now in output.
+	 */
+	max_output_len -= ofraglen;
+	output_len += ofraglen;
+	output += ofraglen;
+    }
+
+    /*
+     * If this is our last call, we expect to have an exact number of
+     * blocks left to be decrypted; we will decrypt them all.
+     * 
+     * If not our last call, we always save between 1 and bsize bytes
+     * until next time.  (We must do this because we cannot be sure
+     * that none of the decrypted bytes are padding bytes until we
+     * have at least another whole block of data.  You cannot tell by
+     * looking -- the data could be anything -- you can only tell by
+     * context, knowing you are looking at the last block.)  We could
+     * decrypt a whole block now but it is easier if we just treat it
+     * the same way we treat partial block bytes.
+     */
+    if (final) {
+	if (padsize) {
+	    blocks = input_len / padsize;
+	    ifraglen = blocks * padsize;
+	} else ifraglen = input_len;
+	PORT_Assert (ifraglen == input_len);
+
+	if (ifraglen != input_len) {
+	    PORT_SetError (SEC_ERROR_BAD_DATA);
+	    return SECFailure;
+	}
+    } else {
+	blocks = (input_len - 1) / bsize;
+	ifraglen = blocks * bsize;
+	PORT_Assert (ifraglen < input_len);
+
+	pcount = input_len - ifraglen;
+	PORT_Memcpy (pbuf, input + ifraglen, pcount);
+	obj->pending_count = pcount;
+    }
+
+    if (ifraglen) {
+	rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
+			    input, ifraglen);
+	if (rv != SECSuccess)
+	    return rv;
+
+	/*
+	 * For now anyway, all of our ciphers have the same number of
+	 * bytes of output as they do input.  If this ever becomes untrue,
+	 * then sec_PKCS7DecryptLength needs to be made smarter!
+	 */
+	PORT_Assert (ifraglen == ofraglen);
+	if (ifraglen != ofraglen) {
+	    PORT_SetError (SEC_ERROR_BAD_DATA);
+	    return SECFailure;
+	}
+
+	output_len += ofraglen;
+    } else {
+	ofraglen = 0;
+    }
+
+    /*
+     * If we just did our very last block, "remove" the padding by
+     * adjusting the output length.
+     */
+    if (final && (padsize != 0)) {
+	unsigned int padlen = *(output + ofraglen - 1);
+	if (padlen == 0 || padlen > padsize) {
+	    PORT_SetError (SEC_ERROR_BAD_DATA);
+	    return SECFailure;
+	}
+	output_len -= padlen;
+    }
+
+    PORT_Assert (output_len_p != NULL || output_len == 0);
+    if (output_len_p != NULL)
+	*output_len_p = output_len;
+
+    return SECSuccess;
+}
+
+/*
+ * Encrypt a given length of input buffer (starting at "input" and
+ * containing "input_len" bytes), placing the encrypted bytes in
+ * "output" and storing the output length in "*output_len_p".
+ * "obj" is the return value from sec_PKCS7CreateEncryptObject.
+ * When "final" is true, this is the last of the data to be encrypted.
+ *
+ * This is much more complicated than it sounds when the cipher is
+ * a block-type, meaning that the encryption function will only
+ * operate on whole blocks.  But our caller is operating stream-wise,
+ * and can pass in any number of bytes.  So we need to keep track
+ * of block boundaries.  We save excess bytes between calls in "obj".
+ * We also need to add padding bytes at the end.  PKCS #7 specifies
+ * that the padding used for a block cipher is a string of bytes,
+ * each of whose value is the same as the length of the padding,
+ * and that all data is padded.  (Even data that starts out with
+ * an exact multiple of blocks gets added to it another block,
+ * all of which is padding.)
+ *
+ * XXX I would kind of like to combine this with the function above
+ * which does decryption, since they have a lot in common.  But the
+ * tricky parts about padding and filling blocks would be much
+ * harder to read that way, so I left them separate.  At least for
+ * now until it is clear that they are right.
+ */ 
+SECStatus
+sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
+		  unsigned int *output_len_p, unsigned int max_output_len,
+		  const unsigned char *input, unsigned int input_len,
+		  PRBool final)
+{
+    int blocks, bsize, padlen, pcount, padsize;
+    unsigned int max_needed, ifraglen, ofraglen, output_len;
+    unsigned char *pbuf;
+    SECStatus rv;
+
+    PORT_Assert (obj->encrypt);
+
+    /*
+     * Check that we have enough room for the output.  Our caller should
+     * already handle this; failure is really an internal error (i.e. bug).
+     */
+    max_needed = sec_PKCS7EncryptLength (obj, input_len, final);
+    PORT_Assert (max_output_len >= max_needed);
+    if (max_output_len < max_needed) {
+	/* PORT_SetError (XXX); */
+	return SECFailure;
+    }
+
+    bsize = obj->block_size;
+    padsize = obj->pad_size;
+
+    /*
+     * When no blocking and padding work to do, we can simply call the
+     * cipher function and we are done.
+     */
+    if (bsize == 0) {
+	return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
+			      input, input_len);
+    }
+
+    pcount = obj->pending_count;
+    pbuf = obj->pending_buf;
+
+    output_len = 0;
+
+    if (pcount) {
+	/*
+	 * Try to fill in an entire block, starting with the bytes
+	 * we already have saved away.
+	 */
+	while (input_len && pcount < bsize) {
+	    pbuf[pcount++] = *input++;
+	    input_len--;
+	}
+	/*
+	 * If we do not have a full block and we know we will be
+	 * called again, then we are done for now.
+	 */
+	if (pcount < bsize && !final) {
+	    obj->pending_count = pcount;
+	    if (output_len_p != NULL)
+		*output_len_p = 0;
+	    return SECSuccess;
+	}
+	/*
+	 * If we have a whole block available, encrypt it.
+	 */
+	if ((padsize == 0) || (pcount % padsize) == 0) {
+	    rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
+				pbuf, pcount);
+	    if (rv != SECSuccess)
+		return rv;
+
+	    /*
+	     * For now anyway, all of our ciphers have the same number of
+	     * bytes of output as they do input.  If this ever becomes untrue,
+	     * then sec_PKCS7EncryptLength needs to be made smarter!
+	     */
+	    PORT_Assert (ofraglen == pcount);
+
+	    /*
+	     * Account for the bytes now in output.
+	     */
+	    max_output_len -= ofraglen;
+	    output_len += ofraglen;
+	    output += ofraglen;
+
+	    pcount = 0;
+	}
+    }
+
+    if (input_len) {
+	PORT_Assert (pcount == 0);
+
+	blocks = input_len / bsize;
+	ifraglen = blocks * bsize;
+
+	if (ifraglen) {
+	    rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
+				input, ifraglen);
+	    if (rv != SECSuccess)
+		return rv;
+
+	    /*
+	     * For now anyway, all of our ciphers have the same number of
+	     * bytes of output as they do input.  If this ever becomes untrue,
+	     * then sec_PKCS7EncryptLength needs to be made smarter!
+	     */
+	    PORT_Assert (ifraglen == ofraglen);
+
+	    max_output_len -= ofraglen;
+	    output_len += ofraglen;
+	    output += ofraglen;
+	}
+
+	pcount = input_len - ifraglen;
+	PORT_Assert (pcount < bsize);
+	if (pcount)
+	    PORT_Memcpy (pbuf, input + ifraglen, pcount);
+    }
+
+    if (final) {
+	padlen = padsize - (pcount % padsize);
+	PORT_Memset (pbuf + pcount, padlen, padlen);
+	rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
+			    pbuf, pcount+padlen);
+	if (rv != SECSuccess)
+	    return rv;
+
+	/*
+	 * For now anyway, all of our ciphers have the same number of
+	 * bytes of output as they do input.  If this ever becomes untrue,
+	 * then sec_PKCS7EncryptLength needs to be made smarter!
+	 */
+	PORT_Assert (ofraglen == (pcount+padlen));
+	output_len += ofraglen;
+    } else {
+	obj->pending_count = pcount;
+    }
+
+    PORT_Assert (output_len_p != NULL || output_len == 0);
+    if (output_len_p != NULL)
+	*output_len_p = output_len;
+
+    return SECSuccess;
+}
+
+/*
+ * End of cipher stuff.
+ * -------------------------------------------------------------------
+ */
+
+
+/*
+ * -------------------------------------------------------------------
+ * XXX The following Attribute stuff really belongs elsewhere.
+ * The Attribute type is *not* part of pkcs7 but rather X.501.
+ * But for now, since PKCS7 is the only customer of attributes,
+ * we define them here.  Once there is a use outside of PKCS7,
+ * then change the attribute types and functions from internal
+ * to external naming convention, and move them elsewhere!
+ */
+
+/*
+ * Look through a set of attributes and find one that matches the
+ * specified object ID.  If "only" is true, then make sure that
+ * there is not more than one attribute of the same type.  Otherwise,
+ * just return the first one found. (XXX Does anybody really want
+ * that first-found behavior?  It was like that when I found it...)
+ */
+SEC_PKCS7Attribute *
+sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs, SECOidTag oidtag,
+			PRBool only)
+{
+    SECOidData *oid;
+    SEC_PKCS7Attribute *attr1, *attr2;
+
+    if (attrs == NULL)
+	return NULL;
+
+    oid = SECOID_FindOIDByTag(oidtag);
+    if (oid == NULL)
+	return NULL;
+
+    while ((attr1 = *attrs++) != NULL) {
+	if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
+							    oid->oid.data,
+							    oid->oid.len) == 0)
+	    break;
+    }
+
+    if (attr1 == NULL)
+	return NULL;
+
+    if (!only)
+	return attr1;
+
+    while ((attr2 = *attrs++) != NULL) {
+	if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
+							    oid->oid.data,
+							    oid->oid.len) == 0)
+	    break;
+    }
+
+    if (attr2 != NULL)
+	return NULL;
+
+    return attr1;
+}
+
+
+/*
+ * Return the single attribute value, doing some sanity checking first:
+ * - Multiple values are *not* expected.
+ * - Empty values are *not* expected.
+ */
+SECItem *
+sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr)
+{
+    SECItem *value;
+
+    if (attr == NULL)
+	return NULL;
+
+    value = attr->values[0];
+
+    if (value == NULL || value->data == NULL || value->len == 0)
+	return NULL;
+
+    if (attr->values[1] != NULL)
+	return NULL;
+
+    return value;
+}
+
+static const SEC_ASN1Template *
+sec_attr_choose_attr_value_template(void *src_or_dest, PRBool encoding)
+{
+    const SEC_ASN1Template *theTemplate;
+
+    SEC_PKCS7Attribute *attribute;
+    SECOidData *oiddata;
+    PRBool encoded;
+
+    PORT_Assert (src_or_dest != NULL);
+    if (src_or_dest == NULL)
+	return NULL;
+
+    attribute = (SEC_PKCS7Attribute*)src_or_dest;
+
+    if (encoding && attribute->encoded)
+	return SEC_ASN1_GET(SEC_AnyTemplate);
+
+    oiddata = attribute->typeTag;
+    if (oiddata == NULL) {
+	oiddata = SECOID_FindOID(&attribute->type);
+	attribute->typeTag = oiddata;
+    }
+
+    if (oiddata == NULL) {
+	encoded = PR_TRUE;
+	theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
+    } else {
+	switch (oiddata->offset) {
+	  default:
+	    encoded = PR_TRUE;
+	    theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
+	    break;
+	  case SEC_OID_PKCS9_EMAIL_ADDRESS:
+	  case SEC_OID_RFC1274_MAIL:
+	  case SEC_OID_PKCS9_UNSTRUCTURED_NAME:
+	    encoded = PR_FALSE;
+	    theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
+	    break;
+	  case SEC_OID_PKCS9_CONTENT_TYPE:
+	    encoded = PR_FALSE;
+	    theTemplate = SEC_ASN1_GET(SEC_ObjectIDTemplate);
+	    break;
+	  case SEC_OID_PKCS9_MESSAGE_DIGEST:
+	    encoded = PR_FALSE;
+	    theTemplate = SEC_ASN1_GET(SEC_OctetStringTemplate);
+	    break;
+	  case SEC_OID_PKCS9_SIGNING_TIME:
+	    encoded = PR_FALSE;
+            theTemplate = SEC_ASN1_GET(CERT_TimeChoiceTemplate);
+	    break;
+	  /* XXX Want other types here, too */
+	}
+    }
+
+    if (encoding) {
+	/*
+	 * If we are encoding and we think we have an already-encoded value,
+	 * then the code which initialized this attribute should have set
+	 * the "encoded" property to true (and we would have returned early,
+	 * up above).  No devastating error, but that code should be fixed.
+	 * (It could indicate that the resulting encoded bytes are wrong.)
+	 */
+	PORT_Assert (!encoded);
+    } else {
+	/*
+	 * We are decoding; record whether the resulting value is
+	 * still encoded or not.
+	 */
+	attribute->encoded = encoded;
+    }
+    return theTemplate;
+}
+
+static const SEC_ASN1TemplateChooserPtr sec_attr_chooser
+	= sec_attr_choose_attr_value_template;
+
+static const SEC_ASN1Template sec_pkcs7_attribute_template[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SEC_PKCS7Attribute) },
+    { SEC_ASN1_OBJECT_ID,
+	  offsetof(SEC_PKCS7Attribute,type) },
+    { SEC_ASN1_DYNAMIC | SEC_ASN1_SET_OF,
+	  offsetof(SEC_PKCS7Attribute,values),
+	  &sec_attr_chooser },
+    { 0 }
+};
+
+static const SEC_ASN1Template sec_pkcs7_set_of_attribute_template[] = {
+    { SEC_ASN1_SET_OF, 0, sec_pkcs7_attribute_template },
+};
+
+/*
+ * If you are wondering why this routine does not reorder the attributes
+ * first, and might be tempted to make it do so, see the comment by the
+ * call to ReorderAttributes in p7encode.c.  (Or, see who else calls this
+ * and think long and hard about the implications of making it always
+ * do the reordering.)
+ */
+SECItem *
+sec_PKCS7EncodeAttributes (PRArenaPool *poolp, SECItem *dest, void *src)
+{
+    return SEC_ASN1EncodeItem (poolp, dest, src,
+			       sec_pkcs7_set_of_attribute_template);
+}
+
+/*
+ * Make sure that the order of the attributes guarantees valid DER
+ * (which must be in lexigraphically ascending order for a SET OF);
+ * if reordering is necessary it will be done in place (in attrs).
+ */
+SECStatus
+sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs)
+{
+    PRArenaPool *poolp;
+    int num_attrs, i, pass, besti;
+    unsigned int j;
+    SECItem **enc_attrs;
+    SEC_PKCS7Attribute **new_attrs;
+
+    /*
+     * I think we should not be called with NULL.  But if we are,
+     * call it a success anyway, because the order *is* okay.
+     */
+    PORT_Assert (attrs != NULL);
+    if (attrs == NULL)
+	return SECSuccess;
+
+    /*
+     * Count how many attributes we are dealing with here.
+     */
+    num_attrs = 0;
+    while (attrs[num_attrs] != NULL)
+	num_attrs++;
+
+    /*
+     * Again, I think we should have some attributes here.
+     * But if we do not, or if there is only one, then call it
+     * a success because it also already has a fine order.
+     */
+    PORT_Assert (num_attrs);
+    if (num_attrs == 0 || num_attrs == 1)
+	return SECSuccess;
+
+    /*
+     * Allocate an arena for us to work with, so it is easy to
+     * clean up all of the memory (fairly small pieces, really).
+     */
+    poolp = PORT_NewArena (1024);	/* XXX what is right value? */
+    if (poolp == NULL)
+	return SECFailure;		/* no memory; nothing we can do... */
+
+    /*
+     * Allocate arrays to hold the individual encodings which we will use
+     * for comparisons and the reordered attributes as they are sorted.
+     */
+    enc_attrs=(SECItem**)PORT_ArenaZAlloc(poolp, num_attrs*sizeof(SECItem *));
+    new_attrs = (SEC_PKCS7Attribute**)PORT_ArenaZAlloc (poolp,
+				  num_attrs * sizeof(SEC_PKCS7Attribute *));
+    if (enc_attrs == NULL || new_attrs == NULL) {
+	PORT_FreeArena (poolp, PR_FALSE);
+	return SECFailure;
+    }
+
+    /*
+     * DER encode each individual attribute.
+     */
+    for (i = 0; i < num_attrs; i++) {
+	enc_attrs[i] = SEC_ASN1EncodeItem (poolp, NULL, attrs[i],
+					   sec_pkcs7_attribute_template);
+	if (enc_attrs[i] == NULL) {
+	    PORT_FreeArena (poolp, PR_FALSE);
+	    return SECFailure;
+	}
+    }
+
+    /*
+     * Now compare and sort them; this is not the most efficient sorting
+     * method, but it is just fine for the problem at hand, because the
+     * number of attributes is (always) going to be small.
+     */
+    for (pass = 0; pass < num_attrs; pass++) {
+	/*
+	 * Find the first not-yet-accepted attribute.  (Once one is
+	 * sorted into the other array, it is cleared from enc_attrs.)
+	 */
+	for (i = 0; i < num_attrs; i++) {
+	    if (enc_attrs[i] != NULL)
+		break;
+	}
+	PORT_Assert (i < num_attrs);
+	besti = i;
+
+	/*
+	 * Find the lowest (lexigraphically) encoding.  One that is
+	 * shorter than all the rest is known to be "less" because each
+	 * attribute is of the same type (a SEQUENCE) and so thus the
+	 * first octet of each is the same, and the second octet is
+	 * the length (or the length of the length with the high bit
+	 * set, followed by the length, which also works out to always
+	 * order the shorter first).  Two (or more) that have the
+	 * same length need to be compared byte by byte until a mismatch
+	 * is found.
+	 */
+	for (i = besti + 1; i < num_attrs; i++) {
+	    if (enc_attrs[i] == NULL)	/* slot already handled */
+		continue;
+
+	    if (enc_attrs[i]->len != enc_attrs[besti]->len) {
+		if (enc_attrs[i]->len < enc_attrs[besti]->len)
+		    besti = i;
+		continue;
+	    }
+
+	    for (j = 0; j < enc_attrs[i]->len; j++) {
+		if (enc_attrs[i]->data[j] < enc_attrs[besti]->data[j]) {
+		    besti = i;
+		    break;
+		}
+	    }
+
+	    /*
+	     * For this not to be true, we would have to have encountered	
+	     * two *identical* attributes, which I think we should not see.
+	     * So assert if it happens, but even if it does, let it go
+	     * through; the ordering of the two does not matter.
+	     */
+	    PORT_Assert (j < enc_attrs[i]->len);
+	}
+
+	/*
+	 * Now we have found the next-lowest one; copy it over and
+	 * remove it from enc_attrs.
+	 */
+	new_attrs[pass] = attrs[besti];
+	enc_attrs[besti] = NULL;
+    }
+
+    /*
+     * Now new_attrs has the attributes in the order we want;
+     * copy them back into the attrs array we started with.
+     */
+    for (i = 0; i < num_attrs; i++)
+	attrs[i] = new_attrs[i];
+
+    PORT_FreeArena (poolp, PR_FALSE);
+    return SECSuccess;
+}
+
+/*
+ * End of attribute stuff.
+ * -------------------------------------------------------------------
+ */
+
+
+/*
+ * Templates and stuff.  Keep these at the end of the file.
+ */
+
+/* forward declaration */
+static const SEC_ASN1Template *
+sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding);
+
+static const SEC_ASN1TemplateChooserPtr sec_pkcs7_chooser
+	= sec_pkcs7_choose_content_template;
+
+const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
+	  0, NULL, sizeof(SEC_PKCS7ContentInfo) },
+    { SEC_ASN1_OBJECT_ID,
+	  offsetof(SEC_PKCS7ContentInfo,contentType) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
+     | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+	  offsetof(SEC_PKCS7ContentInfo,content),
+	  &sec_pkcs7_chooser },
+    { 0 }
+};
+
+/* XXX These names should change from external to internal convention. */
+
+static const SEC_ASN1Template SEC_PKCS7SignerInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SEC_PKCS7SignerInfo) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(SEC_PKCS7SignerInfo,version) },
+    { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7SignerInfo,issuerAndSN),
+	  SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7SignerInfo,digestAlg),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+	  offsetof(SEC_PKCS7SignerInfo,authAttr),
+	  sec_pkcs7_set_of_attribute_template },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7SignerInfo,digestEncAlg),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OCTET_STRING,
+	  offsetof(SEC_PKCS7SignerInfo,encDigest) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+	  offsetof(SEC_PKCS7SignerInfo,unAuthAttr),
+	  sec_pkcs7_set_of_attribute_template },
+    { 0 }
+};
+
+static const SEC_ASN1Template SEC_PKCS7SignedDataTemplate[] = {
+    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
+	  0, NULL, sizeof(SEC_PKCS7SignedData) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(SEC_PKCS7SignedData,version) },
+    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7SignedData,digestAlgorithms),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_INLINE,
+	  offsetof(SEC_PKCS7SignedData,contentInfo),
+	  sec_PKCS7ContentInfoTemplate },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC  |
+      SEC_ASN1_XTRN | 0,
+	  offsetof(SEC_PKCS7SignedData,rawCerts),
+	  SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC  |
+      SEC_ASN1_XTRN | 1,
+	  offsetof(SEC_PKCS7SignedData,crls),
+	  SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
+    { SEC_ASN1_SET_OF,
+	  offsetof(SEC_PKCS7SignedData,signerInfos),
+	  SEC_PKCS7SignerInfoTemplate },
+    { 0 }
+};
+
+static const SEC_ASN1Template SEC_PointerToPKCS7SignedDataTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedDataTemplate }
+};
+
+static const SEC_ASN1Template SEC_PKCS7RecipientInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SEC_PKCS7RecipientInfo) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(SEC_PKCS7RecipientInfo,version) },
+    { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7RecipientInfo,issuerAndSN),
+	  SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7RecipientInfo,keyEncAlg),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OCTET_STRING,
+	  offsetof(SEC_PKCS7RecipientInfo,encKey) },
+    { 0 }
+};
+
+static const SEC_ASN1Template SEC_PKCS7EncryptedContentInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
+	  0, NULL, sizeof(SEC_PKCS7EncryptedContentInfo) },
+    { SEC_ASN1_OBJECT_ID,
+	  offsetof(SEC_PKCS7EncryptedContentInfo,contentType) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7EncryptedContentInfo,contentEncAlg),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_MAY_STREAM | SEC_ASN1_CONTEXT_SPECIFIC |
+      SEC_ASN1_XTRN | 0,
+	  offsetof(SEC_PKCS7EncryptedContentInfo,encContent),
+	  SEC_ASN1_SUB(SEC_OctetStringTemplate) },
+    { 0 }
+};
+
+static const SEC_ASN1Template SEC_PKCS7EnvelopedDataTemplate[] = {
+    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
+	  0, NULL, sizeof(SEC_PKCS7EnvelopedData) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(SEC_PKCS7EnvelopedData,version) },
+    { SEC_ASN1_SET_OF,
+	  offsetof(SEC_PKCS7EnvelopedData,recipientInfos),
+	  SEC_PKCS7RecipientInfoTemplate },
+    { SEC_ASN1_INLINE,
+	  offsetof(SEC_PKCS7EnvelopedData,encContentInfo),
+	  SEC_PKCS7EncryptedContentInfoTemplate },
+    { 0 }
+};
+
+static const SEC_ASN1Template SEC_PointerToPKCS7EnvelopedDataTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_PKCS7EnvelopedDataTemplate }
+};
+
+static const SEC_ASN1Template SEC_PKCS7SignedAndEnvelopedDataTemplate[] = {
+    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
+	  0, NULL, sizeof(SEC_PKCS7SignedAndEnvelopedData) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(SEC_PKCS7SignedAndEnvelopedData,version) },
+    { SEC_ASN1_SET_OF,
+	  offsetof(SEC_PKCS7SignedAndEnvelopedData,recipientInfos),
+	  SEC_PKCS7RecipientInfoTemplate },
+    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7SignedAndEnvelopedData,digestAlgorithms),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_INLINE,
+	  offsetof(SEC_PKCS7SignedAndEnvelopedData,encContentInfo),
+	  SEC_PKCS7EncryptedContentInfoTemplate },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+      SEC_ASN1_XTRN | 0,
+	  offsetof(SEC_PKCS7SignedAndEnvelopedData,rawCerts),
+	  SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+      SEC_ASN1_XTRN | 1,
+	  offsetof(SEC_PKCS7SignedAndEnvelopedData,crls),
+	  SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
+    { SEC_ASN1_SET_OF,
+	  offsetof(SEC_PKCS7SignedAndEnvelopedData,signerInfos),
+	  SEC_PKCS7SignerInfoTemplate },
+    { 0 }
+};
+
+static const SEC_ASN1Template
+SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedAndEnvelopedDataTemplate }
+};
+
+static const SEC_ASN1Template SEC_PKCS7DigestedDataTemplate[] = {
+    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
+	  0, NULL, sizeof(SEC_PKCS7DigestedData) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(SEC_PKCS7DigestedData,version) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	  offsetof(SEC_PKCS7DigestedData,digestAlg),
+	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_INLINE,
+	  offsetof(SEC_PKCS7DigestedData,contentInfo),
+	  sec_PKCS7ContentInfoTemplate },
+    { SEC_ASN1_OCTET_STRING,
+	  offsetof(SEC_PKCS7DigestedData,digest) },
+    { 0 }
+};
+
+static const SEC_ASN1Template SEC_PointerToPKCS7DigestedDataTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_PKCS7DigestedDataTemplate }
+};
+
+static const SEC_ASN1Template SEC_PKCS7EncryptedDataTemplate[] = {
+    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
+	  0, NULL, sizeof(SEC_PKCS7EncryptedData) },
+    { SEC_ASN1_INTEGER,
+	  offsetof(SEC_PKCS7EncryptedData,version) },
+    { SEC_ASN1_INLINE,
+	  offsetof(SEC_PKCS7EncryptedData,encContentInfo),
+	  SEC_PKCS7EncryptedContentInfoTemplate },
+    { 0 }
+};
+
+static const SEC_ASN1Template SEC_PointerToPKCS7EncryptedDataTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_PKCS7EncryptedDataTemplate }
+};
+
+const SEC_ASN1Template SEC_SMIMEKEAParamTemplateSkipjack[] = {
+	{ SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
+	{ SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
+	{ SEC_ASN1_OCTET_STRING,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
+	{ 0 }
+};
+
+const SEC_ASN1Template SEC_SMIMEKEAParamTemplateNoSkipjack[] = {
+	{ SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
+	{ SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
+	{ SEC_ASN1_OCTET_STRING,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
+	{ SEC_ASN1_OCTET_STRING  | SEC_ASN1_OPTIONAL ,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
+	{ 0 }
+};
+
+const SEC_ASN1Template SEC_SMIMEKEAParamTemplateAllParams[] = {
+	{ SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
+	{ SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
+	{ SEC_ASN1_OCTET_STRING,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
+	{ SEC_ASN1_OCTET_STRING  | SEC_ASN1_OPTIONAL ,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
+	{ SEC_ASN1_OCTET_STRING  | SEC_ASN1_OPTIONAL ,
+	  offsetof(SEC_PKCS7SMIMEKEAParameters,bulkKeySize) },
+	{ 0 }
+};
+
+const SEC_ASN1Template*
+sec_pkcs7_get_kea_template(SECKEATemplateSelector whichTemplate)
+{
+	const SEC_ASN1Template *returnVal = NULL;
+
+	switch(whichTemplate)
+	{
+	case SECKEAUsesNonSkipjack:
+		returnVal = SEC_SMIMEKEAParamTemplateNoSkipjack;
+		break;
+	case SECKEAUsesSkipjack:
+		returnVal = SEC_SMIMEKEAParamTemplateSkipjack;
+		break;
+	case SECKEAUsesNonSkipjackWithPaddedEncKey:
+	default:
+		returnVal = SEC_SMIMEKEAParamTemplateAllParams;
+		break;
+	}
+	return returnVal;
+}
+	
+static const SEC_ASN1Template *
+sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding)
+{
+    const SEC_ASN1Template *theTemplate;
+    SEC_PKCS7ContentInfo *cinfo;
+    SECOidTag kind;
+
+    PORT_Assert (src_or_dest != NULL);
+    if (src_or_dest == NULL)
+	return NULL;
+
+    cinfo = (SEC_PKCS7ContentInfo*)src_or_dest;
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      default:
+	theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate);
+	break;
+      case SEC_OID_PKCS7_DATA:
+	theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
+	break;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	theTemplate = SEC_PointerToPKCS7SignedDataTemplate;
+	break;
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	theTemplate = SEC_PointerToPKCS7EnvelopedDataTemplate;
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	theTemplate = SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate;
+	break;
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+	theTemplate = SEC_PointerToPKCS7DigestedDataTemplate;
+	break;
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	theTemplate = SEC_PointerToPKCS7EncryptedDataTemplate;
+	break;
+    }
+    return theTemplate;
+}
+
+/*
+ * End of templates.  Do not add stuff after this; put new code
+ * up above the start of the template definitions.
+ */
diff --git a/mozilla/security/nss/lib/pkcs7/p7local.h b/mozilla/security/nss/lib/pkcs7/p7local.h
new file mode 100644
index 0000000..f0cbdba
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/p7local.h
@@ -0,0 +1,179 @@
+/* ***** 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 ***** */
+
+/*
+ * Support routines for PKCS7 implementation, none of which are exported.
+ * This file should only contain things that are needed by both the
+ * encoding/creation side *and* the decoding/decryption side.  Anything
+ * else should just be static routines in the appropriate file.
+ *
+ * Do not export this file!  If something in here is really needed outside
+ * of pkcs7 code, first try to add a PKCS7 interface which will do it for
+ * you.  If that has a problem, then just move out what you need, changing
+ * its name as appropriate!
+ *
+ * $Id: p7local.h,v 1.2 2004/04/25 15:03:13 gerv%gerv.net Exp $
+ */
+
+#ifndef _P7LOCAL_H_
+#define _P7LOCAL_H_
+
+#include "secpkcs7.h"
+#include "secasn1t.h"
+
+extern const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[];
+
+/* opaque objects */
+typedef struct sec_pkcs7_cipher_object sec_PKCS7CipherObject;
+
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/*
+ * Look through a set of attributes and find one that matches the
+ * specified object ID.  If "only" is true, then make sure that
+ * there is not more than one attribute of the same type.  Otherwise,
+ * just return the first one found. (XXX Does anybody really want
+ * that first-found behavior?  It was like that when I found it...)
+ */
+extern SEC_PKCS7Attribute *sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs,
+						   SECOidTag oidtag,
+						   PRBool only);
+/*
+ * Return the single attribute value, doing some sanity checking first:
+ * - Multiple values are *not* expected.
+ * - Empty values are *not* expected.
+ */
+extern SECItem *sec_PKCS7AttributeValue (SEC_PKCS7Attribute *attr);
+
+/*
+ * Encode a set of attributes (found in "src").
+ */
+extern SECItem *sec_PKCS7EncodeAttributes (PRArenaPool *poolp,
+					   SECItem *dest, void *src);
+
+/*
+ * Make sure that the order of the attributes guarantees valid DER
+ * (which must be in lexigraphically ascending order for a SET OF);
+ * if reordering is necessary it will be done in place (in attrs).
+ */
+extern SECStatus sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs);
+
+
+/*
+ * Create a context for decrypting, based on the given key and algorithm.
+ */
+extern sec_PKCS7CipherObject *
+sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid);
+
+/*
+ * Create a context for encrypting, based on the given key and algorithm,
+ * and fill in the algorithm id.
+ */
+extern sec_PKCS7CipherObject *
+sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key,
+			      SECOidTag algtag, SECAlgorithmID *algid);
+
+/*
+ * Destroy the given decryption or encryption object.
+ */
+extern void sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj);
+extern void sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj);
+
+/*
+ * What will be the output length of the next call to encrypt/decrypt?
+ * Result can be used to perform memory allocations.  Note that the amount
+ * is exactly accurate only when not doing a block cipher or when final
+ * is false, otherwise it is an upper bound on the amount because until
+ * we see the data we do not know how many padding bytes there are
+ * (always between 1 and the cipher block size).
+ *
+ * Note that this can return zero, which does not mean that the cipher
+ * operation can be skipped!  (It simply means that there are not enough
+ * bytes to make up an entire block; the bytes will be reserved until
+ * there are enough to encrypt/decrypt at least one block.)  However,
+ * if zero is returned it *does* mean that no output buffer need be
+ * passed in to the subsequent cipher operation, as no output bytes
+ * will be stored.
+ */
+extern unsigned int sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj,
+					    unsigned int input_len,
+					    PRBool final);
+extern unsigned int sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj,
+					    unsigned int input_len,
+					    PRBool final);
+
+/*
+ * Decrypt a given length of input buffer (starting at "input" and
+ * containing "input_len" bytes), placing the decrypted bytes in
+ * "output" and storing the output length in "*output_len_p".
+ * "obj" is the return value from sec_PKCS7CreateDecryptObject.
+ * When "final" is true, this is the last of the data to be decrypted.
+ */ 
+extern SECStatus sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj,
+				   unsigned char *output,
+				   unsigned int *output_len_p,
+				   unsigned int max_output_len,
+				   const unsigned char *input,
+				   unsigned int input_len,
+				   PRBool final);
+
+/*
+ * Encrypt a given length of input buffer (starting at "input" and
+ * containing "input_len" bytes), placing the encrypted bytes in
+ * "output" and storing the output length in "*output_len_p".
+ * "obj" is the return value from sec_PKCS7CreateEncryptObject.
+ * When "final" is true, this is the last of the data to be encrypted.
+ */ 
+extern SECStatus sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj,
+				   unsigned char *output,
+				   unsigned int *output_len_p,
+				   unsigned int max_output_len,
+				   const unsigned char *input,
+				   unsigned int input_len,
+				   PRBool final);
+
+/* return the correct kea template based on the template selector. skipjack
+ * does not have the extra IV.
+ */
+const SEC_ASN1Template * 
+sec_pkcs7_get_kea_template(SECKEATemplateSelector whichTemplate);
+
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif /* _P7LOCAL_H_ */
diff --git a/mozilla/security/nss/lib/pkcs7/pkcs7t.h b/mozilla/security/nss/lib/pkcs7/pkcs7t.h
new file mode 100644
index 0000000..ba638bd
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/pkcs7t.h
@@ -0,0 +1,299 @@
+/* ***** 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 ***** */
+
+/*
+ * Header for pkcs7 types.
+ *
+ * $Id: pkcs7t.h,v 1.6 2008/06/14 14:20:24 wtc%google.com Exp $
+ */
+
+#ifndef _PKCS7T_H_
+#define _PKCS7T_H_
+
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secoidt.h"
+#include "certt.h"
+#include "secmodt.h"
+
+/* Opaque objects */
+typedef struct SEC_PKCS7DecoderContextStr SEC_PKCS7DecoderContext;
+typedef struct SEC_PKCS7EncoderContextStr SEC_PKCS7EncoderContext;
+
+/* legacy defines that haven't been active for years */
+typedef void *(*SECKEYGetPasswordKey)(void *arg, void *handle);
+
+
+/* Non-opaque objects.  NOTE, though: I want them to be treated as
+ * opaque as much as possible.  If I could hide them completely,
+ * I would.  (I tried, but ran into trouble that was taking me too
+ * much time to get out of.)  I still intend to try to do so.
+ * In fact, the only type that "outsiders" should even *name* is
+ * SEC_PKCS7ContentInfo, and they should not reference its fields.
+ */
+/* rjr: PKCS #11 cert handling (pk11cert.c) does use SEC_PKCS7RecipientInfo's.
+ * This is because when we search the recipient list for the cert and key we
+ * want, we need to invert the order of the loops we used to have. The old
+ * loops were:
+ *
+ *  For each recipient {
+ *       find_cert = PK11_Find_AllCert(recipient->issuerSN);
+ *       [which unrolls to... ]
+ *       For each slot {
+ *            Log into slot;
+ *            search slot for cert;
+ *      }
+ *  }
+ *
+ *  the new loop searchs all the recipients at once on a slot. this allows
+ *  PKCS #11 to order slots in such a way that logout slots don't get checked
+ *  if we can find the cert on a logged in slot. This eliminates lots of
+ *  spurious password prompts when smart cards are installed... so why this
+ *  comment? If you make SEC_PKCS7RecipientInfo completely opaque, you need
+ *  to provide a non-opaque list of issuerSN's (the only field PKCS#11 needs
+ *  and fix up pk11cert.c first. NOTE: Only S/MIME calls this special PKCS #11
+ *  function.
+ */
+typedef struct SEC_PKCS7ContentInfoStr SEC_PKCS7ContentInfo;
+typedef struct SEC_PKCS7SignedDataStr SEC_PKCS7SignedData;
+typedef struct SEC_PKCS7EncryptedContentInfoStr SEC_PKCS7EncryptedContentInfo;
+typedef struct SEC_PKCS7EnvelopedDataStr SEC_PKCS7EnvelopedData;
+typedef struct SEC_PKCS7SignedAndEnvelopedDataStr
+		SEC_PKCS7SignedAndEnvelopedData;
+typedef struct SEC_PKCS7SignerInfoStr SEC_PKCS7SignerInfo;
+typedef struct SEC_PKCS7RecipientInfoStr SEC_PKCS7RecipientInfo;
+typedef struct SEC_PKCS7DigestedDataStr SEC_PKCS7DigestedData;
+typedef struct SEC_PKCS7EncryptedDataStr SEC_PKCS7EncryptedData;
+typedef struct SEC_PKCS7SMIMEKEAParametersStr SEC_PKCS7SMIMEKEAParameters;
+/*
+ * The following is not actually a PKCS7 type, but for now it is only
+ * used by PKCS7, so we have adopted it.  If someone else *ever* needs
+ * it, its name should be changed and it should be moved out of here.
+ * Do not dare to use it without doing so!
+ */
+typedef struct SEC_PKCS7AttributeStr SEC_PKCS7Attribute;
+
+struct SEC_PKCS7ContentInfoStr {
+    PLArenaPool *poolp;			/* local; not part of encoding */
+    PRBool created;			/* local; not part of encoding */
+    int refCount;			/* local; not part of encoding */
+    SECOidData *contentTypeTag;		/* local; not part of encoding */
+    SECKEYGetPasswordKey pwfn;		/* local; not part of encoding */
+    void *pwfn_arg;			/* local; not part of encoding */
+    SECItem contentType;
+    union {
+	SECItem				*data;
+	SEC_PKCS7DigestedData		*digestedData;
+	SEC_PKCS7EncryptedData		*encryptedData;
+	SEC_PKCS7EnvelopedData		*envelopedData;
+	SEC_PKCS7SignedData		*signedData;
+	SEC_PKCS7SignedAndEnvelopedData	*signedAndEnvelopedData;
+    } content;
+};
+
+struct SEC_PKCS7SignedDataStr {
+    SECItem version;
+    SECAlgorithmID **digestAlgorithms;
+    SEC_PKCS7ContentInfo contentInfo;
+    SECItem **rawCerts;
+    CERTSignedCrl **crls;
+    SEC_PKCS7SignerInfo **signerInfos;
+    SECItem **digests;			/* local; not part of encoding */
+    CERTCertificate **certs;		/* local; not part of encoding */
+    CERTCertificateList **certLists;	/* local; not part of encoding */
+};
+#define SEC_PKCS7_SIGNED_DATA_VERSION		1	/* what we *create* */
+
+struct SEC_PKCS7EncryptedContentInfoStr {
+    SECOidData *contentTypeTag;		/* local; not part of encoding */
+    SECItem contentType;
+    SECAlgorithmID contentEncAlg;
+    SECItem encContent;
+    SECItem plainContent;		/* local; not part of encoding */
+					/* bytes not encrypted, but encoded */
+    int keysize;			/* local; not part of encoding */
+					/* size of bulk encryption key
+					 * (only used by creation code) */
+    SECOidTag encalg;			/* local; not part of encoding */
+					/* oid tag of encryption algorithm
+					 * (only used by creation code) */
+};
+
+struct SEC_PKCS7EnvelopedDataStr {
+    SECItem version;
+    SEC_PKCS7RecipientInfo **recipientInfos;
+    SEC_PKCS7EncryptedContentInfo encContentInfo;
+};
+#define SEC_PKCS7_ENVELOPED_DATA_VERSION	0	/* what we *create* */
+
+struct SEC_PKCS7SignedAndEnvelopedDataStr {
+    SECItem version;
+    SEC_PKCS7RecipientInfo **recipientInfos;
+    SECAlgorithmID **digestAlgorithms;
+    SEC_PKCS7EncryptedContentInfo encContentInfo;
+    SECItem **rawCerts;
+    CERTSignedCrl **crls;
+    SEC_PKCS7SignerInfo **signerInfos;
+    SECItem **digests;			/* local; not part of encoding */
+    CERTCertificate **certs;		/* local; not part of encoding */
+    CERTCertificateList **certLists;	/* local; not part of encoding */
+    PK11SymKey *sigKey;			/* local; not part of encoding */
+};
+#define SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION 1	/* what we *create* */
+
+struct SEC_PKCS7SignerInfoStr {
+    SECItem version;
+    CERTIssuerAndSN *issuerAndSN;
+    SECAlgorithmID digestAlg;
+    SEC_PKCS7Attribute **authAttr;
+    SECAlgorithmID digestEncAlg;
+    SECItem encDigest;
+    SEC_PKCS7Attribute **unAuthAttr;
+    CERTCertificate *cert;		/* local; not part of encoding */
+    CERTCertificateList *certList;	/* local; not part of encoding */
+};
+#define SEC_PKCS7_SIGNER_INFO_VERSION		1	/* what we *create* */
+
+struct SEC_PKCS7RecipientInfoStr {
+    SECItem version;
+    CERTIssuerAndSN *issuerAndSN;
+    SECAlgorithmID keyEncAlg;
+    SECItem encKey;
+    CERTCertificate *cert;		/* local; not part of encoding */
+};
+#define SEC_PKCS7_RECIPIENT_INFO_VERSION	0	/* what we *create* */
+
+struct SEC_PKCS7DigestedDataStr {
+    SECItem version;
+    SECAlgorithmID digestAlg;
+    SEC_PKCS7ContentInfo contentInfo;
+    SECItem digest;
+};
+#define SEC_PKCS7_DIGESTED_DATA_VERSION		0	/* what we *create* */
+
+struct SEC_PKCS7EncryptedDataStr {
+    SECItem version;
+    SEC_PKCS7EncryptedContentInfo encContentInfo;
+};
+#define SEC_PKCS7_ENCRYPTED_DATA_VERSION	0	/* what we *create* */
+
+/*
+ * See comment above about this type not really belonging to PKCS7.
+ */
+struct SEC_PKCS7AttributeStr {
+    /* The following fields make up an encoded Attribute: */
+    SECItem type;
+    SECItem **values;	/* data may or may not be encoded */
+    /* The following fields are not part of an encoded Attribute: */
+    SECOidData *typeTag;
+    PRBool encoded;	/* when true, values are encoded */
+};
+
+/* An enumerated type used to select templates based on the encryption
+   scenario and data specifics. */
+typedef enum
+{
+	SECKEAInvalid = -1,
+	SECKEAUsesSkipjack = 0,
+	SECKEAUsesNonSkipjack = 1,
+	SECKEAUsesNonSkipjackWithPaddedEncKey = 2
+} SECKEATemplateSelector;
+
+/* ### mwelch - S/MIME KEA parameters. These don't really fit here,
+                but I cannot think of a more appropriate place at this time. */
+struct SEC_PKCS7SMIMEKEAParametersStr {
+	SECItem originatorKEAKey;	/* sender KEA key (encrypted?) */
+	SECItem originatorRA;		/* random number generated by sender */
+	SECItem nonSkipjackIV;		/* init'n vector for SkipjackCBC64
+					   decryption of KEA key if Skipjack
+					   is not the bulk algorithm used on
+					   the message */
+	SECItem bulkKeySize;		/* if Skipjack is not the bulk
+					   algorithm used on the message,
+					   and the size of the bulk encryption
+					   key is not the same as that of
+					   originatorKEAKey (due to padding
+					   perhaps), this field will contain
+					   the real size of the bulk encryption
+					   key. */
+};
+
+/*
+ * Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart.
+ * If specified, this is where the content bytes (only) will be "sent"
+ * as they are recovered during the decoding.
+ *
+ * XXX Should just combine this with SEC_PKCS7EncoderContentCallback type
+ * and use a simpler, common name.
+ */
+typedef void (* SEC_PKCS7DecoderContentCallback)(void *arg,
+						 const char *buf,
+						 unsigned long len);
+
+/*
+ * Type of function passed to SEC_PKCS7Encode or SEC_PKCS7EncoderStart.
+ * This is where the encoded bytes will be "sent".
+ *
+ * XXX Should just combine this with SEC_PKCS7DecoderContentCallback type
+ * and use a simpler, common name.
+ */
+typedef void (* SEC_PKCS7EncoderOutputCallback)(void *arg,
+						const char *buf,
+						unsigned long len);
+
+
+/*
+ * Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart
+ * to retrieve the decryption key.  This function is inteded to be
+ * used for EncryptedData content info's which do not have a key available
+ * in a certificate, etc.
+ */
+typedef PK11SymKey * (* SEC_PKCS7GetDecryptKeyCallback)(void *arg, 
+							SECAlgorithmID *algid);
+
+/* 
+ * Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart.
+ * This function in intended to be used to verify that decrypting a
+ * particular crypto algorithm is allowed.  Content types which do not
+ * require decryption will not need the callback.  If the callback
+ * is not specified for content types which require decryption, the
+ * decryption will be disallowed.
+ */
+typedef PRBool (* SEC_PKCS7DecryptionAllowedCallback)(SECAlgorithmID *algid,  
+						      PK11SymKey *bulkkey);
+
+#endif /* _PKCS7T_H_ */
diff --git a/mozilla/security/nss/lib/pkcs7/secmime.c b/mozilla/security/nss/lib/pkcs7/secmime.c
new file mode 100644
index 0000000..f8ce400
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/secmime.c
@@ -0,0 +1,904 @@
+/* ***** 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 ***** */
+
+/*
+ * Stuff specific to S/MIME policy and interoperability.
+ * Depends on PKCS7, but there should be no dependency the other way around.
+ *
+ * $Id: secmime.c,v 1.4 2004/06/18 00:38:45 jpierre%netscape.com Exp $
+ */
+
+#include "secmime.h"
+#include "secoid.h"
+#include "pk11func.h"
+#include "ciferfam.h"	/* for CIPHER_FAMILY symbols */
+#include "secasn1.h"
+#include "secitem.h"
+#include "cert.h"
+#include "key.h"
+#include "secerr.h"
+
+typedef struct smime_cipher_map_struct {
+    unsigned long cipher;
+    SECOidTag algtag;
+    SECItem *parms;
+} smime_cipher_map;
+
+/*
+ * These are macros because I think some subsequent parameters,
+ * like those for RC5, will want to use them, too, separately.
+ */
+#define SMIME_DER_INTVAL_16	SEC_ASN1_INTEGER, 0x01, 0x10
+#define SMIME_DER_INTVAL_40	SEC_ASN1_INTEGER, 0x01, 0x28
+#define SMIME_DER_INTVAL_64	SEC_ASN1_INTEGER, 0x01, 0x40
+#define SMIME_DER_INTVAL_128	SEC_ASN1_INTEGER, 0x02, 0x00, 0x80
+
+#ifdef SMIME_DOES_RC5	/* will be needed; quiet unused warning for now */
+static unsigned char smime_int16[] = { SMIME_DER_INTVAL_16 };
+#endif
+static unsigned char smime_int40[] = { SMIME_DER_INTVAL_40 };
+static unsigned char smime_int64[] = { SMIME_DER_INTVAL_64 };
+static unsigned char smime_int128[] = { SMIME_DER_INTVAL_128 };
+
+static SECItem smime_rc2p40 = { siBuffer, smime_int40, sizeof(smime_int40) };
+static SECItem smime_rc2p64 = { siBuffer, smime_int64, sizeof(smime_int64) };
+static SECItem smime_rc2p128 = { siBuffer, smime_int128, sizeof(smime_int128) };
+
+static smime_cipher_map smime_cipher_maps[] = {
+    { SMIME_RC2_CBC_40,		SEC_OID_RC2_CBC,	&smime_rc2p40 },
+    { SMIME_RC2_CBC_64,		SEC_OID_RC2_CBC,	&smime_rc2p64 },
+    { SMIME_RC2_CBC_128,	SEC_OID_RC2_CBC,	&smime_rc2p128 },
+#ifdef SMIME_DOES_RC5
+    { SMIME_RC5PAD_64_16_40,	SEC_OID_RC5_CBC_PAD,	&smime_rc5p40 },
+    { SMIME_RC5PAD_64_16_64,	SEC_OID_RC5_CBC_PAD,	&smime_rc5p64 },
+    { SMIME_RC5PAD_64_16_128,	SEC_OID_RC5_CBC_PAD,	&smime_rc5p128 },
+#endif
+    { SMIME_DES_CBC_56,		SEC_OID_DES_CBC,	NULL },
+    { SMIME_DES_EDE3_168,	SEC_OID_DES_EDE3_CBC,	NULL },
+    { SMIME_FORTEZZA,		SEC_OID_FORTEZZA_SKIPJACK, NULL}
+};
+
+/*
+ * Note, the following value really just needs to be an upper bound
+ * on the ciphers.
+ */
+static const int smime_symmetric_count = sizeof(smime_cipher_maps)
+					 / sizeof(smime_cipher_map);
+
+static unsigned long *smime_prefs, *smime_newprefs;
+static int smime_current_pref_index = 0;
+static PRBool smime_prefs_complete = PR_FALSE;
+static PRBool smime_prefs_changed = PR_TRUE;
+
+static unsigned long smime_policy_bits = 0;
+
+
+static int
+smime_mapi_by_cipher (unsigned long cipher)
+{
+    int i;
+
+    for (i = 0; i < smime_symmetric_count; i++) {
+	if (smime_cipher_maps[i].cipher == cipher)
+	    break;
+    }
+
+    if (i == smime_symmetric_count)
+	return -1;
+
+    return i;
+}
+
+
+/*
+ * this function locally records the user's preference
+ */
+SECStatus 
+SECMIME_EnableCipher(long which, int on)
+{
+    unsigned long mask;
+
+    if (smime_newprefs == NULL || smime_prefs_complete) {
+	/*
+	 * This is either the very first time, or we are starting over.
+	 */
+	smime_newprefs = (unsigned long*)PORT_ZAlloc (smime_symmetric_count
+				      * sizeof(*smime_newprefs));
+	if (smime_newprefs == NULL)
+	    return SECFailure;
+	smime_current_pref_index = 0;
+	smime_prefs_complete = PR_FALSE;
+    }
+
+    mask = which & CIPHER_FAMILYID_MASK;
+    if (mask == CIPHER_FAMILYID_MASK) {
+    	/*
+	 * This call signifies that all preferences have been set.
+	 * Move "newprefs" over, after checking first whether or
+	 * not the new ones are different from the old ones.
+	 */
+	if (smime_prefs != NULL) {
+	    if (PORT_Memcmp (smime_prefs, smime_newprefs,
+			     smime_symmetric_count * sizeof(*smime_prefs)) == 0)
+		smime_prefs_changed = PR_FALSE;
+	    else
+		smime_prefs_changed = PR_TRUE;
+	    PORT_Free (smime_prefs);
+	}
+
+	smime_prefs = smime_newprefs;
+	smime_prefs_complete = PR_TRUE;
+	return SECSuccess;
+    }
+
+    PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
+    if (mask != CIPHER_FAMILYID_SMIME) {
+	/* XXX set an error! */
+    	return SECFailure;
+    }
+
+    if (on) {
+	PORT_Assert (smime_current_pref_index < smime_symmetric_count);
+	if (smime_current_pref_index >= smime_symmetric_count) {
+	    /* XXX set an error! */
+	    return SECFailure;
+	}
+
+	smime_newprefs[smime_current_pref_index++] = which;
+    }
+
+    return SECSuccess;
+}
+
+
+/*
+ * this function locally records the export policy
+ */
+SECStatus 
+SECMIME_SetPolicy(long which, int on)
+{
+    unsigned long mask;
+
+    PORT_Assert ((which & CIPHER_FAMILYID_MASK) == CIPHER_FAMILYID_SMIME);
+    if ((which & CIPHER_FAMILYID_MASK) != CIPHER_FAMILYID_SMIME) {
+	/* XXX set an error! */
+    	return SECFailure;
+    }
+
+    which &= ~CIPHER_FAMILYID_MASK;
+
+    PORT_Assert (which < 32);	/* bits in the long */
+    if (which >= 32) {
+	/* XXX set an error! */
+    	return SECFailure;
+    }
+
+    mask = 1UL << which;
+
+    if (on) {
+    	smime_policy_bits |= mask;
+    } else {
+    	smime_policy_bits &= ~mask;
+    }
+
+    return SECSuccess;
+}
+
+
+/*
+ * Based on the given algorithm (including its parameters, in some cases!)
+ * and the given key (may or may not be inspected, depending on the
+ * algorithm), find the appropriate policy algorithm specification
+ * and return it.  If no match can be made, -1 is returned.
+ */
+static long
+smime_policy_algorithm (SECAlgorithmID *algid, PK11SymKey *key)
+{
+    SECOidTag algtag;
+
+    algtag = SECOID_GetAlgorithmTag (algid);
+    switch (algtag) {
+      case SEC_OID_RC2_CBC:
+	{
+	    unsigned int keylen_bits;
+
+	    keylen_bits = PK11_GetKeyStrength (key, algid);
+	    switch (keylen_bits) {
+	      case 40:
+		return SMIME_RC2_CBC_40;
+	      case 64:
+		return SMIME_RC2_CBC_64;
+	      case 128:
+		return SMIME_RC2_CBC_128;
+	      default:
+		break;
+	    }
+	}
+	break;
+      case SEC_OID_DES_CBC:
+	return SMIME_DES_CBC_56;
+      case SEC_OID_DES_EDE3_CBC:
+	return SMIME_DES_EDE3_168;
+      case SEC_OID_FORTEZZA_SKIPJACK:
+	return SMIME_FORTEZZA;
+#ifdef SMIME_DOES_RC5
+      case SEC_OID_RC5_CBC_PAD:
+	PORT_Assert (0);	/* XXX need to pull out parameters and match */
+	break;
+#endif
+      default:
+	break;
+    }
+
+    return -1;
+}
+
+
+static PRBool
+smime_cipher_allowed (unsigned long which)
+{
+    unsigned long mask;
+
+    which &= ~CIPHER_FAMILYID_MASK;
+    PORT_Assert (which < 32);	/* bits per long (min) */
+    if (which >= 32)
+	return PR_FALSE;
+
+    mask = 1UL << which;
+    if ((mask & smime_policy_bits) == 0)
+	return PR_FALSE;
+
+    return PR_TRUE;
+}
+
+
+PRBool
+SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key)
+{
+    long which;
+
+    which = smime_policy_algorithm (algid, key);
+    if (which < 0)
+	return PR_FALSE;
+
+    return smime_cipher_allowed ((unsigned long)which);
+}
+
+
+/*
+ * Does the current policy allow *any* S/MIME encryption (or decryption)?
+ *
+ * This tells whether or not *any* S/MIME encryption can be done,
+ * according to policy.  Callers may use this to do nicer user interface
+ * (say, greying out a checkbox so a user does not even try to encrypt
+ * a message when they are not allowed to) or for any reason they want
+ * to check whether S/MIME encryption (or decryption, for that matter)
+ * may be done.
+ *
+ * It takes no arguments.  The return value is a simple boolean:
+ *   PR_TRUE means encryption (or decryption) is *possible*
+ *	(but may still fail due to other reasons, like because we cannot
+ *	find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
+ *   PR_FALSE means encryption (or decryption) is not permitted
+ *
+ * There are no errors from this routine.
+ */
+PRBool
+SECMIME_EncryptionPossible (void)
+{
+    if (smime_policy_bits != 0)
+	return PR_TRUE;
+
+    return PR_FALSE;
+}
+
+
+/*
+ * XXX Would like the "parameters" field to be a SECItem *, but the
+ * encoder is having trouble with optional pointers to an ANY.  Maybe
+ * once that is fixed, can change this back...
+ */
+typedef struct smime_capability_struct {
+    unsigned long cipher;	/* local; not part of encoding */
+    SECOidTag capIDTag;		/* local; not part of encoding */
+    SECItem capabilityID;
+    SECItem parameters;
+} smime_capability;
+
+static const SEC_ASN1Template smime_capability_template[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(smime_capability) },
+    { SEC_ASN1_OBJECT_ID,
+	  offsetof(smime_capability,capabilityID), },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+	  offsetof(smime_capability,parameters), },
+    { 0, }
+};
+
+static const SEC_ASN1Template smime_capabilities_template[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, smime_capability_template }
+};
+
+
+
+static void
+smime_fill_capability (smime_capability *cap)
+{
+    unsigned long cipher;
+    SECOidTag algtag;
+    int i;
+
+    algtag = SECOID_FindOIDTag (&(cap->capabilityID));
+
+    for (i = 0; i < smime_symmetric_count; i++) {
+	if (smime_cipher_maps[i].algtag != algtag)
+	    continue;
+	/*
+	 * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing
+	 * 2 NULLs as equal and NULL and non-NULL as not equal), we could
+	 * use that here instead of all of the following comparison code.
+	 */
+	if (cap->parameters.data != NULL) {
+	    if (smime_cipher_maps[i].parms == NULL)
+		continue;
+	    if (cap->parameters.len != smime_cipher_maps[i].parms->len)
+		continue;
+	    if (PORT_Memcmp (cap->parameters.data,
+			     smime_cipher_maps[i].parms->data,
+			     cap->parameters.len) == 0)
+		break;
+	} else if (smime_cipher_maps[i].parms == NULL) {
+	    break;
+	}
+    }
+
+    if (i == smime_symmetric_count)
+	cipher = 0;
+    else
+	cipher = smime_cipher_maps[i].cipher;
+
+    cap->cipher = cipher;
+    cap->capIDTag = algtag;
+}
+
+
+static long
+smime_choose_cipher (CERTCertificate *scert, CERTCertificate **rcerts)
+{
+    PRArenaPool *poolp;
+    long chosen_cipher;
+    int *cipher_abilities;
+    int *cipher_votes;
+    int strong_mapi;
+    int rcount, mapi, max, i;
+	PRBool isFortezza = PK11_FortezzaHasKEA(scert);
+
+    if (smime_policy_bits == 0) {
+	PORT_SetError (SEC_ERROR_BAD_EXPORT_ALGORITHM);
+	return -1;
+    }
+
+    chosen_cipher = SMIME_RC2_CBC_40;		/* the default, LCD */
+
+    poolp = PORT_NewArena (1024);		/* XXX what is right value? */
+    if (poolp == NULL)
+	goto done;
+
+    cipher_abilities = (int*)PORT_ArenaZAlloc (poolp,
+					 smime_symmetric_count * sizeof(int));
+    if (cipher_abilities == NULL)
+	goto done;
+
+    cipher_votes = (int*)PORT_ArenaZAlloc (poolp,
+				     smime_symmetric_count * sizeof(int));
+    if (cipher_votes == NULL)
+	goto done;
+
+    /*
+     * XXX Should have a #define somewhere which specifies default
+     * strong cipher.  (Or better, a way to configure, which would
+     * take Fortezza into account as well.)
+     */
+
+    /* If the user has the Fortezza preference turned on, make
+     *  that the strong cipher. Otherwise, use triple-DES. */
+    strong_mapi = -1;
+    if (isFortezza) {
+	for(i=0;i < smime_current_pref_index && strong_mapi < 0;i++)
+	{
+	    if (smime_prefs[i] == SMIME_FORTEZZA)
+		strong_mapi = smime_mapi_by_cipher(SMIME_FORTEZZA);
+	}
+    }
+
+    if (strong_mapi == -1)
+	strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
+
+    PORT_Assert (strong_mapi >= 0);
+
+    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
+	SECItem *profile;
+	smime_capability **caps;
+	int capi, pref;
+	SECStatus dstat;
+
+	pref = smime_symmetric_count;
+	profile = CERT_FindSMimeProfile (rcerts[rcount]);
+	if (profile != NULL && profile->data != NULL && profile->len > 0) {
+	    caps = NULL;
+	    dstat = SEC_QuickDERDecodeItem (poolp, &caps,
+					smime_capabilities_template,
+					profile);
+	    if (dstat == SECSuccess && caps != NULL) {
+		for (capi = 0; caps[capi] != NULL; capi++) {
+		    smime_fill_capability (caps[capi]);
+		    mapi = smime_mapi_by_cipher (caps[capi]->cipher);
+		    if (mapi >= 0) {
+			cipher_abilities[mapi]++;
+			cipher_votes[mapi] += pref;
+			--pref;
+		    }
+		}
+	    }
+	} else {
+	    SECKEYPublicKey *key;
+	    unsigned int pklen_bits;
+
+	    /*
+	     * XXX This is probably only good for RSA keys.  What I would
+	     * really like is a function to just say;  Is the public key in
+	     * this cert an export-length key?  Then I would not have to
+	     * know things like the value 512, or the kind of key, or what
+	     * a subjectPublicKeyInfo is, etc.
+	     */
+	    key = CERT_ExtractPublicKey (rcerts[rcount]);
+	    if (key != NULL) {
+		pklen_bits = SECKEY_PublicKeyStrength (key) * 8;
+		SECKEY_DestroyPublicKey (key);
+
+		if (pklen_bits > 512) {
+		    cipher_abilities[strong_mapi]++;
+		    cipher_votes[strong_mapi] += pref;
+		}
+	    }
+	}
+	if (profile != NULL)
+	    SECITEM_FreeItem (profile, PR_TRUE);
+    }
+
+    max = 0;
+    for (mapi = 0; mapi < smime_symmetric_count; mapi++) {
+	if (cipher_abilities[mapi] != rcount)
+	    continue;
+	if (! smime_cipher_allowed (smime_cipher_maps[mapi].cipher))
+	    continue;
+	if (!isFortezza  && (smime_cipher_maps[mapi].cipher == SMIME_FORTEZZA))
+		continue;
+	if (cipher_votes[mapi] > max) {
+	    chosen_cipher = smime_cipher_maps[mapi].cipher;
+	    max = cipher_votes[mapi];
+	} /* XXX else if a tie, let scert break it? */
+    }
+
+done:
+    if (poolp != NULL)
+	PORT_FreeArena (poolp, PR_FALSE);
+
+    return chosen_cipher;
+}
+
+
+/*
+ * XXX This is a hack for now to satisfy our current interface.
+ * Eventually, with more parameters needing to be specified, just
+ * looking up the keysize is not going to be sufficient.
+ */
+static int
+smime_keysize_by_cipher (unsigned long which)
+{
+    int keysize;
+
+    switch (which) {
+      case SMIME_RC2_CBC_40:
+	keysize = 40;
+	break;
+      case SMIME_RC2_CBC_64:
+	keysize = 64;
+	break;
+      case SMIME_RC2_CBC_128:
+	keysize = 128;
+	break;
+#ifdef SMIME_DOES_RC5
+      case SMIME_RC5PAD_64_16_40:
+      case SMIME_RC5PAD_64_16_64:
+      case SMIME_RC5PAD_64_16_128:
+	/* XXX See comment above; keysize is not enough... */
+	PORT_Assert (0);
+	PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
+	keysize = -1;
+	break;
+#endif
+      case SMIME_DES_CBC_56:
+      case SMIME_DES_EDE3_168:
+      case SMIME_FORTEZZA:
+	/*
+	 * These are special; since the key size is fixed, we actually
+	 * want to *avoid* specifying a key size.
+	 */
+	keysize = 0;
+	break;
+      default:
+	keysize = -1;
+	break;
+    }
+
+    return keysize;
+}
+
+
+/*
+ * Start an S/MIME encrypting context.
+ *
+ * "scert" is the cert for the sender.  It will be checked for validity.
+ * "rcerts" are the certs for the recipients.  They will also be checked.
+ *
+ * "certdb" is the cert database to use for verifying the certs.
+ * It can be NULL if a default database is available (like in the client).
+ *
+ * This function already does all of the stuff specific to S/MIME protocol
+ * and local policy; the return value just needs to be passed to
+ * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
+ * and finally to SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+SEC_PKCS7ContentInfo *
+SECMIME_CreateEncrypted(CERTCertificate *scert,
+			CERTCertificate **rcerts,
+			CERTCertDBHandle *certdb,
+			SECKEYGetPasswordKey pwfn,
+			void *pwfn_arg)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    long cipher;
+    SECOidTag encalg;
+    int keysize;
+    int mapi, rci;
+
+    cipher = smime_choose_cipher (scert, rcerts);
+    if (cipher < 0)
+	return NULL;
+
+    mapi = smime_mapi_by_cipher (cipher);
+    if (mapi < 0)
+	return NULL;
+
+    /*
+     * XXX This is stretching it -- CreateEnvelopedData should probably
+     * take a cipher itself of some sort, because we cannot know what the
+     * future will bring in terms of parameters for each type of algorithm.
+     * For example, just an algorithm and keysize is *not* sufficient to
+     * fully specify the usage of RC5 (which also needs to know rounds and
+     * block size).  Work this out into a better API!
+     */
+    encalg = smime_cipher_maps[mapi].algtag;
+    keysize = smime_keysize_by_cipher (cipher);
+    if (keysize < 0)
+	return NULL;
+
+    cinfo = SEC_PKCS7CreateEnvelopedData (scert, certUsageEmailRecipient,
+					  certdb, encalg, keysize,
+					  pwfn, pwfn_arg);
+    if (cinfo == NULL)
+	return NULL;
+
+    for (rci = 0; rcerts[rci] != NULL; rci++) {
+	if (rcerts[rci] == scert)
+	    continue;
+	if (SEC_PKCS7AddRecipient (cinfo, rcerts[rci], certUsageEmailRecipient,
+				   NULL) != SECSuccess) {
+	    SEC_PKCS7DestroyContentInfo (cinfo);
+	    return NULL;
+	}
+    }
+
+    return cinfo;
+}
+
+
+static smime_capability **smime_capabilities;
+static SECItem *smime_encoded_caps;
+static PRBool lastUsedFortezza;
+
+
+static SECStatus
+smime_init_caps (PRBool isFortezza)
+{
+    smime_capability *cap;
+    smime_cipher_map *map;
+    SECOidData *oiddata;
+    SECStatus rv;
+    int i, capIndex;
+
+    if (smime_encoded_caps != NULL 
+	&& (! smime_prefs_changed) 
+	&& lastUsedFortezza == isFortezza)
+	return SECSuccess;
+
+    if (smime_encoded_caps != NULL) {
+	SECITEM_FreeItem (smime_encoded_caps, PR_TRUE);
+	smime_encoded_caps = NULL;
+    }
+
+    if (smime_capabilities == NULL) {
+	smime_capabilities = (smime_capability**)PORT_ZAlloc (
+					  (smime_symmetric_count + 1)
+					  * sizeof(smime_capability *));
+	if (smime_capabilities == NULL)
+	    return SECFailure;
+    }
+
+    rv = SECFailure;
+
+    /* 
+       The process of creating the encoded PKCS7 cipher capability list
+       involves two basic steps: 
+
+       (a) Convert our internal representation of cipher preferences 
+           (smime_prefs) into an array containing cipher OIDs and 
+	   parameter data (smime_capabilities). This step is
+	   performed here.
+
+       (b) Encode, using ASN.1, the cipher information in 
+           smime_capabilities, leaving the encoded result in 
+	   smime_encoded_caps.
+
+       (In the process of performing (a), Lisa put in some optimizations
+       which allow us to avoid needlessly re-populating elements in 
+       smime_capabilities as we walk through smime_prefs.)
+
+       We want to use separate loop variables for smime_prefs and
+       smime_capabilities because in the case where the Skipjack cipher 
+       is turned on in the prefs, but where we don't want to include 
+       Skipjack in the encoded capabilities (presumably due to using a 
+       non-fortezza cert when sending a message), we want to avoid creating
+       an empty element in smime_capabilities. This would otherwise cause 
+       the encoding step to produce an empty set, since Skipjack happens 
+       to be the first cipher in smime_prefs, if it is turned on.
+    */
+    for (i = 0, capIndex = 0; i < smime_current_pref_index; i++, capIndex++) {
+	int mapi;
+
+	/* Get the next cipher preference in smime_prefs. */
+	mapi = smime_mapi_by_cipher (smime_prefs[i]);
+	if (mapi < 0)
+	    break;
+
+	/* Find the corresponding entry in the cipher map. */
+	PORT_Assert (mapi < smime_symmetric_count);
+	map = &(smime_cipher_maps[mapi]);
+
+	/* If we're using a non-Fortezza cert, only advertise non-Fortezza
+	   capabilities. (We advertise all capabilities if we have a 
+	   Fortezza cert.) */
+	if ((!isFortezza) && (map->cipher == SMIME_FORTEZZA))
+	{
+	    capIndex--; /* we want to visit the same caps index entry next time */
+	    continue;
+	}
+
+	/*
+	 * Convert the next preference found in smime_prefs into an
+	 * smime_capability.
+	 */
+
+	cap = smime_capabilities[capIndex];
+	if (cap == NULL) {
+	    cap = (smime_capability*)PORT_ZAlloc (sizeof(smime_capability));
+	    if (cap == NULL)
+		break;
+	    smime_capabilities[capIndex] = cap;
+	} else if (cap->cipher == smime_prefs[i]) {
+	    continue;		/* no change to this one */
+	}
+
+	cap->capIDTag = map->algtag;
+	oiddata = SECOID_FindOIDByTag (map->algtag);
+	if (oiddata == NULL)
+	    break;
+
+	if (cap->capabilityID.data != NULL) {
+	    SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
+	    cap->capabilityID.data = NULL;
+	    cap->capabilityID.len = 0;
+	}
+
+	rv = SECITEM_CopyItem (NULL, &(cap->capabilityID), &(oiddata->oid));
+	if (rv != SECSuccess)
+	    break;
+
+	if (map->parms == NULL) {
+	    cap->parameters.data = NULL;
+	    cap->parameters.len = 0;
+	} else {
+	    cap->parameters.data = map->parms->data;
+	    cap->parameters.len = map->parms->len;
+	}
+
+	cap->cipher = smime_prefs[i];
+    }
+
+    if (i != smime_current_pref_index)
+	return rv;
+
+    while (capIndex < smime_symmetric_count) {
+	cap = smime_capabilities[capIndex];
+	if (cap != NULL) {
+	    SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
+	    PORT_Free (cap);
+	}
+	smime_capabilities[capIndex] = NULL;
+	capIndex++;
+    }
+    smime_capabilities[capIndex] = NULL;
+
+    smime_encoded_caps = SEC_ASN1EncodeItem (NULL, NULL, &smime_capabilities,
+					     smime_capabilities_template);
+    if (smime_encoded_caps == NULL)
+	return SECFailure;
+
+    lastUsedFortezza = isFortezza;
+
+    return SECSuccess;
+}
+
+
+static SECStatus
+smime_add_profile (CERTCertificate *cert, SEC_PKCS7ContentInfo *cinfo)
+{
+    PRBool isFortezza = PR_FALSE;
+
+    PORT_Assert (smime_prefs_complete);
+    if (! smime_prefs_complete)
+	return SECFailure;
+
+    /* See if the sender's cert specifies Fortezza key exchange. */
+    if (cert != NULL)
+	isFortezza = PK11_FortezzaHasKEA(cert);
+
+    /* For that matter, if capabilities haven't been initialized yet,
+       do so now. */
+    if (isFortezza != lastUsedFortezza || smime_encoded_caps == NULL || smime_prefs_changed) {
+	SECStatus rv;
+
+	rv = smime_init_caps(isFortezza);
+	if (rv != SECSuccess)
+	    return rv;
+
+	PORT_Assert (smime_encoded_caps != NULL);
+    }
+
+    return SEC_PKCS7AddSignedAttribute (cinfo, SEC_OID_PKCS9_SMIME_CAPABILITIES,
+					smime_encoded_caps);
+}
+
+
+/*
+ * Start an S/MIME signing context.
+ *
+ * "scert" is the cert that will be used to sign the data.  It will be
+ * checked for validity.
+ *
+ * "ecert" is the signer's encryption cert.  If it is different from
+ * scert, then it will be included in the signed message so that the
+ * recipient can save it for future encryptions.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ * 
+ * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
+ * XXX There should be SECMIME functions for hashing, or the hashing should
+ * be built into this interface, which we would like because we would
+ * support more smartcards that way, and then this argument should go away.)
+ *
+ * "digest" is the actual digest of the data.  It must be provided in
+ * the case of detached data or NULL if the content will be included.
+ *
+ * This function already does all of the stuff specific to S/MIME protocol
+ * and local policy; the return value just needs to be passed to
+ * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
+ * and finally to SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+
+SEC_PKCS7ContentInfo *
+SECMIME_CreateSigned (CERTCertificate *scert,
+		      CERTCertificate *ecert,
+		      CERTCertDBHandle *certdb,
+		      SECOidTag digestalg,
+		      SECItem *digest,
+		      SECKEYGetPasswordKey pwfn,
+		      void *pwfn_arg)
+{
+    SEC_PKCS7ContentInfo *cinfo;
+    SECStatus rv;
+
+    /* See note in header comment above about digestalg. */
+    /* Doesn't explain this. PORT_Assert (digestalg == SEC_OID_SHA1); */
+
+    cinfo = SEC_PKCS7CreateSignedData (scert, certUsageEmailSigner,
+				       certdb, digestalg, digest,
+				       pwfn, pwfn_arg);
+    if (cinfo == NULL)
+	return NULL;
+
+    if (SEC_PKCS7IncludeCertChain (cinfo, NULL) != SECSuccess) {
+	SEC_PKCS7DestroyContentInfo (cinfo);
+	return NULL;
+    }
+
+    /* if the encryption cert and the signing cert differ, then include
+     * the encryption cert too.
+     */
+    /* it is ok to compare the pointers since we ref count, and the same
+     * cert will always have the same pointer
+     */
+    if ( ( ecert != NULL ) && ( ecert != scert ) ) {
+	rv = SEC_PKCS7AddCertificate(cinfo, ecert);
+	if ( rv != SECSuccess ) {
+	    SEC_PKCS7DestroyContentInfo (cinfo);
+	    return NULL;
+	}
+    }
+    /*
+     * Add the signing time.  But if it fails for some reason,
+     * may as well not give up altogether -- just assert.
+     */
+    rv = SEC_PKCS7AddSigningTime (cinfo);
+    PORT_Assert (rv == SECSuccess);
+
+    /*
+     * Add the email profile.  Again, if it fails for some reason,
+     * may as well not give up altogether -- just assert.
+     */
+    rv = smime_add_profile (ecert, cinfo);
+    PORT_Assert (rv == SECSuccess);
+
+    return cinfo;
+}
diff --git a/mozilla/security/nss/lib/pkcs7/secmime.h b/mozilla/security/nss/lib/pkcs7/secmime.h
new file mode 100644
index 0000000..0b0ba90
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/secmime.h
@@ -0,0 +1,195 @@
+/* ***** 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 ***** */
+
+/*
+ * Header file for routines specific to S/MIME.  Keep things that are pure
+ * pkcs7 out of here; this is for S/MIME policy, S/MIME interoperability, etc.
+ *
+ * $Id: secmime.h,v 1.2 2004/04/25 15:03:13 gerv%gerv.net Exp $
+ */
+
+#ifndef _SECMIME_H_
+#define _SECMIME_H_ 1
+
+#include "secpkcs7.h"
+
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/*
+ * Initialize the local recording of the user S/MIME cipher preferences.
+ * This function is called once for each cipher, the order being
+ * important (first call records greatest preference, and so on).
+ * When finished, it is called with a "which" of CIPHER_FAMILID_MASK.
+ * If the function is called again after that, it is assumed that
+ * the preferences are being reset, and the old preferences are
+ * discarded.
+ *
+ * XXX This is for a particular user, and right now the storage is
+ * XXX local, static.  The preference should be stored elsewhere to allow
+ * XXX for multiple uses of one library?  How does SSL handle this;
+ * XXX it has something similar?
+ *
+ *  - The "which" values are defined in ciferfam.h (the SMIME_* values,
+ *    for example SMIME_DES_CBC_56).
+ *  - If "on" is non-zero then the named cipher is enabled, otherwise
+ *    it is disabled.  (It is not necessary to call the function for
+ *    ciphers that are disabled, however, as that is the default.)
+ *
+ * If the cipher preference is successfully recorded, SECSuccess
+ * is returned.  Otherwise SECFailure is returned.  The only errors
+ * are due to failure allocating memory or bad parameters/calls:
+ *	SEC_ERROR_XXX ("which" is not in the S/MIME cipher family)
+ *	SEC_ERROR_XXX (function is being called more times than there
+ *		are known/expected ciphers)
+ */
+extern SECStatus SECMIME_EnableCipher(long which, int on);
+
+/*
+ * Initialize the local recording of the S/MIME policy.
+ * This function is called to enable/disable a particular cipher.
+ * (S/MIME encryption or decryption using a particular cipher is only
+ * allowed if that cipher is currently enabled.)  At startup, all S/MIME
+ * ciphers are disabled.  From that point, this function can be called
+ * to enable a cipher -- it is not necessary to call this to disable
+ * a cipher unless that cipher was previously, explicitly enabled via
+ * this function.
+ *
+ * XXX This is for a the current module, I think, so local, static storage
+ * XXX is okay.  Is that correct, or could multiple uses of the same
+ * XXX library expect to operate under different policies?
+ *
+ *  - The "which" values are defined in ciferfam.h (the SMIME_* values,
+ *    for example SMIME_DES_CBC_56).
+ *  - If "on" is non-zero then the named cipher is enabled, otherwise
+ *    it is disabled.
+ *
+ * If the cipher is successfully enabled/disabled, SECSuccess is
+ * returned.  Otherwise SECFailure is returned.  The only errors
+ * are due to bad parameters:
+ *	SEC_ERROR_XXX ("which" is not in the S/MIME cipher family)
+ *	SEC_ERROR_XXX ("which" exceeds expected maximum cipher; this is
+ *		really an internal error)
+ */
+extern SECStatus SECMIME_SetPolicy(long which, int on);
+
+/*
+ * Does the current policy allow S/MIME decryption of this particular
+ * algorithm and keysize?
+ */
+extern PRBool SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key);
+
+/*
+ * Does the current policy allow *any* S/MIME encryption (or decryption)?
+ *
+ * This tells whether or not *any* S/MIME encryption can be done,
+ * according to policy.  Callers may use this to do nicer user interface
+ * (say, greying out a checkbox so a user does not even try to encrypt
+ * a message when they are not allowed to) or for any reason they want
+ * to check whether S/MIME encryption (or decryption, for that matter)
+ * may be done.
+ *
+ * It takes no arguments.  The return value is a simple boolean:
+ *   PR_TRUE means encryption (or decryption) is *possible*
+ *	(but may still fail due to other reasons, like because we cannot
+ *	find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
+ *   PR_FALSE means encryption (or decryption) is not permitted
+ *
+ * There are no errors from this routine.
+ */
+extern PRBool SECMIME_EncryptionPossible(void);
+
+/*
+ * Start an S/MIME encrypting context.
+ *
+ * "scert" is the cert for the sender.  It will be checked for validity.
+ * "rcerts" are the certs for the recipients.  They will also be checked.
+ *
+ * "certdb" is the cert database to use for verifying the certs.
+ * It can be NULL if a default database is available (like in the client).
+ *
+ * This function already does all of the stuff specific to S/MIME protocol
+ * and local policy; the return value just needs to be passed to
+ * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
+ * and finally to SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *SECMIME_CreateEncrypted(CERTCertificate *scert,
+						     CERTCertificate **rcerts,
+						     CERTCertDBHandle *certdb,
+						     SECKEYGetPasswordKey pwfn,
+						     void *pwfn_arg);
+
+/*
+ * Start an S/MIME signing context.
+ *
+ * "scert" is the cert that will be used to sign the data.  It will be
+ * checked for validity.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ * 
+ * "digestalg" names the digest algorithm.  (It should be SEC_OID_SHA1;
+ * XXX There should be SECMIME functions for hashing, or the hashing should
+ * be built into this interface, which we would like because we would
+ * support more smartcards that way, and then this argument should go away.)
+ *
+ * "digest" is the actual digest of the data.  It must be provided in
+ * the case of detached data or NULL if the content will be included.
+ *
+ * This function already does all of the stuff specific to S/MIME protocol
+ * and local policy; the return value just needs to be passed to
+ * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
+ * and finally to SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *SECMIME_CreateSigned(CERTCertificate *scert,
+						  CERTCertificate *ecert,
+						  CERTCertDBHandle *certdb,
+						  SECOidTag digestalg,
+						  SECItem *digest,
+						  SECKEYGetPasswordKey pwfn,
+						  void *pwfn_arg);
+
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif /* _SECMIME_H_ */
diff --git a/mozilla/security/nss/lib/pkcs7/secpkcs7.h b/mozilla/security/nss/lib/pkcs7/secpkcs7.h
new file mode 100644
index 0000000..9b67d84
--- /dev/null
+++ b/mozilla/security/nss/lib/pkcs7/secpkcs7.h
@@ -0,0 +1,626 @@
+/* ***** 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 ***** */
+
+/*
+ * Interface to the PKCS7 implementation.
+ *
+ * $Id: secpkcs7.h,v 1.6 2008/06/14 14:20:25 wtc%google.com Exp $
+ */
+
+#ifndef _SECPKCS7_H_
+#define _SECPKCS7_H_
+
+#include "seccomon.h"
+
+#include "secoidt.h"
+#include "certt.h"
+#include "keyt.h"
+#include "hasht.h"
+#include "pkcs7t.h"
+
+extern const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[];
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/************************************************************************
+ *	Miscellaneous
+ ************************************************************************/
+
+/*
+ * Returns the content type of the given contentInfo.
+ */
+extern SECOidTag SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo);
+
+/*
+ * Destroy a PKCS7 contentInfo and all of its sub-pieces.
+ */
+extern void SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *contentInfo);
+
+/*
+ * Copy a PKCS7 contentInfo.  A Destroy is needed on *each* copy.
+ */
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *contentInfo);
+
+/*
+ * Return a pointer to the actual content.  In the case of those types
+ * which are encrypted, this returns the *plain* content.
+ */
+extern SECItem *SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo);
+
+/************************************************************************
+ *	PKCS7 Decoding, Verification, etc..
+ ************************************************************************/
+
+extern SEC_PKCS7DecoderContext *
+SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback callback,
+		      void *callback_arg,
+		      SECKEYGetPasswordKey pwfn, void *pwfn_arg,
+		      SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, 
+		      void *decrypt_key_cb_arg,
+		      SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb);
+
+extern SECStatus
+SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
+		       const char *buf, unsigned long len);
+
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx);
+
+
+/*  Abort the underlying ASN.1 stream & set an error  */
+void SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error);
+
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7DecodeItem(SECItem *p7item,
+		    SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
+		    SECKEYGetPasswordKey pwfn, void *pwfn_arg,
+		    SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, 
+		    void *decrypt_key_cb_arg,
+		    SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb);
+
+extern PRBool SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo);
+
+/* checks to see if the contents of the content info is
+ * empty.  it so, PR_TRUE is returned.  PR_FALSE, otherwise.
+ *
+ * minLen is used to specify a minimum size.  if content size <= minLen,
+ * content is assumed empty.
+ */
+extern PRBool 
+SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen); 
+
+extern PRBool SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo);
+
+/*
+ * If the PKCS7 content has a signature (not just *could* have a signature)
+ * return true; false otherwise.  This can/should be called before calling
+ * VerifySignature, which will always indicate failure if no signature is
+ * present, but that does not mean there even was a signature!
+ * Note that the content itself can be empty (detached content was sent
+ * another way); it is the presence of the signature that matters.
+ */
+extern PRBool SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo);
+
+/*
+ * SEC_PKCS7VerifySignature
+ *	Look at a PKCS7 contentInfo and check if the signature is good.
+ *	The verification checks that the signing cert is valid and trusted
+ *	for the purpose specified by "certusage".
+ *
+ *	In addition, if "keepcerts" is true, add any new certificates found
+ *	into our local database.
+ */
+extern PRBool SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
+				       SECCertUsage certusage,
+				       PRBool keepcerts);
+
+/*
+ * SEC_PKCS7VerifyDetachedSignature
+ *	Look at a PKCS7 contentInfo and check if the signature matches
+ *	a passed-in digest (calculated, supposedly, from detached contents).
+ *	The verification checks that the signing cert is valid and trusted
+ *	for the purpose specified by "certusage".
+ *
+ *	In addition, if "keepcerts" is true, add any new certificates found
+ *	into our local database.
+ */
+extern PRBool SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
+					       SECCertUsage certusage,
+					       SECItem *detached_digest,
+					       HASH_HashType digest_type,
+					       PRBool keepcerts);
+
+/*
+ * SEC_PKCS7GetSignerCommonName, SEC_PKCS7GetSignerEmailAddress
+ *      The passed-in contentInfo is espected to be Signed, and these
+ *      functions return the specified portion of the full signer name.
+ *
+ *      Returns a pointer to allocated memory, which must be freed.
+ *      A NULL return value is an error.
+ */
+extern char *SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo);
+extern char *SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo);
+
+/*
+ * Return the the signing time, in UTCTime format, of a PKCS7 contentInfo.
+ */
+extern SECItem *SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo);
+
+
+/************************************************************************
+ *	PKCS7 Creation and Encoding.
+ ************************************************************************/
+
+/*
+ * Start a PKCS7 signing context.
+ *
+ * "cert" is the cert that will be used to sign the data.  It will be
+ * checked for validity.
+ *
+ * "certusage" describes the signing usage (e.g. certUsageEmailSigner)
+ * XXX Maybe SECCertUsage should be split so that our caller just says
+ * "email" and *we* add the "signing" part -- otherwise our caller
+ * could be lying about the usage; we do not want to allow encryption
+ * certs for signing or vice versa.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ * 
+ * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
+ *
+ * "digest" is the actual digest of the data.  It must be provided in
+ * the case of detached data or NULL if the content will be included.
+ *
+ * The return value can be passed to functions which add things to
+ * it like attributes, then eventually to SEC_PKCS7Encode() or to
+ * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
+ * SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateSignedData (CERTCertificate *cert,
+			   SECCertUsage certusage,
+			   CERTCertDBHandle *certdb,
+			   SECOidTag digestalg,
+			   SECItem *digest,
+		           SECKEYGetPasswordKey pwfn, void *pwfn_arg);
+
+/*
+ * Create a PKCS7 certs-only container.
+ *
+ * "cert" is the (first) cert that will be included.
+ *
+ * "include_chain" specifies whether the entire chain for "cert" should
+ * be included.
+ *
+ * "certdb" is the cert database to use for finding the chain.
+ * It can be NULL in when "include_chain" is false, or when meaning
+ * use the default database.
+ *
+ * More certs and chains can be added via AddCertficate and AddCertChain.
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateCertsOnly (CERTCertificate *cert,
+			  PRBool include_chain,
+			  CERTCertDBHandle *certdb);
+
+/*
+ * Start a PKCS7 enveloping context.
+ *
+ * "cert" is the cert for the recipient.  It will be checked for validity.
+ *
+ * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
+ * XXX Maybe SECCertUsage should be split so that our caller just says
+ * "email" and *we* add the "recipient" part -- otherwise our caller
+ * could be lying about the usage; we do not want to allow encryption
+ * certs for signing or vice versa.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ *
+ * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
+ *
+ * "keysize" specifies the bulk encryption key size, in bits.
+ *
+ * The return value can be passed to functions which add things to
+ * it like more recipients, then eventually to SEC_PKCS7Encode() or to
+ * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
+ * SEC_PKCS7DestroyContentInfo().
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert,
+			      SECCertUsage certusage,
+			      CERTCertDBHandle *certdb,
+			      SECOidTag encalg,
+			      int keysize,
+		              SECKEYGetPasswordKey pwfn, void *pwfn_arg);
+
+/*
+ * XXX There will be a similar routine for creating signedAndEnvelopedData.
+ * But its parameters will be different and I have no plans to implement
+ * it any time soon because we have no current need for it.
+ */
+
+/*
+ * Create an empty PKCS7 data content info.
+ *
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *SEC_PKCS7CreateData (void);
+
+/*
+ * Create an empty PKCS7 encrypted content info.
+ *
+ * "algorithm" specifies the bulk encryption algorithm to use.
+ * 
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern SEC_PKCS7ContentInfo *
+SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize,
+			      SECKEYGetPasswordKey pwfn, void *pwfn_arg);
+
+/*
+ * All of the following things return SECStatus to signal success or failure.
+ * Failure should have a more specific error status available via
+ * PORT_GetError()/XP_GetError().
+ */
+
+/*
+ * Add the specified attribute to the authenticated (i.e. signed) attributes
+ * of "cinfo" -- "oidtag" describes the attribute and "value" is the
+ * value to be associated with it.  NOTE! "value" must already be encoded;
+ * no interpretation of "oidtag" is done.  Also, it is assumed that this
+ * signedData has only one signer -- if we ever need to add attributes
+ * when there is more than one signature, we need a way to specify *which*
+ * signature should get the attribute.
+ *
+ * XXX Technically, a signed attribute can have multiple values; if/when
+ * we ever need to support an attribute which takes multiple values, we
+ * either need to change this interface or create an AddSignedAttributeValue
+ * which can be called subsequently, and would then append a value.
+ *
+ * "cinfo" should be of type signedData (the only kind of pkcs7 data
+ * that is allowed authenticated attributes); SECFailure will be returned
+ * if it is not.
+ */
+extern SECStatus SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,
+					      SECOidTag oidtag,
+					      SECItem *value);
+
+/*
+ * Add "cert" and its entire chain to the set of certs included in "cinfo".
+ *
+ * "certdb" is the cert database to use for finding the chain.
+ * It can be NULL, meaning use the default database.
+ *
+ * "cinfo" should be of type signedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ */
+extern SECStatus SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo,
+					CERTCertificate *cert,
+					CERTCertDBHandle *certdb);
+
+/*
+ * Add "cert" to the set of certs included in "cinfo".
+ *
+ * "cinfo" should be of type signedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ */
+extern SECStatus SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo,
+					  CERTCertificate *cert);
+
+/*
+ * Add another recipient to an encrypted message.
+ *
+ * "cinfo" should be of type envelopedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ *
+ * "cert" is the cert for the recipient.  It will be checked for validity.
+ *
+ * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
+ * XXX Maybe SECCertUsage should be split so that our caller just says
+ * "email" and *we* add the "recipient" part -- otherwise our caller
+ * could be lying about the usage; we do not want to allow encryption
+ * certs for signing or vice versa.
+ *
+ * "certdb" is the cert database to use for verifying the cert.
+ * It can be NULL if a default database is available (like in the client).
+ */
+extern SECStatus SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo,
+					CERTCertificate *cert,
+					SECCertUsage certusage,
+					CERTCertDBHandle *certdb);
+
+/*
+ * Add the signing time to the authenticated (i.e. signed) attributes
+ * of "cinfo".  This is expected to be included in outgoing signed
+ * messages for email (S/MIME) but is likely useful in other situations.
+ *
+ * This should only be added once; a second call will either do
+ * nothing or replace an old signing time with a newer one.
+ *
+ * XXX This will probably just shove the current time into "cinfo"
+ * but it will not actually get signed until the entire item is
+ * processed for encoding.  Is this (expected to be small) delay okay?
+ *
+ * "cinfo" should be of type signedData (the only kind of pkcs7 data
+ * that is allowed authenticated attributes); SECFailure will be returned
+ * if it is not.
+ */
+extern SECStatus SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo);
+
+/*
+ * Add the signer's symmetric capabilities to the authenticated
+ * (i.e. signed) attributes of "cinfo".  This is expected to be
+ * included in outgoing signed messages for email (S/MIME).
+ *
+ * This can only be added once; a second call will return SECFailure.
+ *
+ * "cinfo" should be of type signedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ */
+extern SECStatus SEC_PKCS7AddSymmetricCapabilities(SEC_PKCS7ContentInfo *cinfo);
+
+/*
+ * Mark that the signer's certificate and its issuing chain should
+ * be included in the encoded data.  This is expected to be used
+ * in outgoing signed messages for email (S/MIME).
+ *
+ * "certdb" is the cert database to use for finding the chain.
+ * It can be NULL, meaning use the default database.
+ *
+ * "cinfo" should be of type signedData or signedAndEnvelopedData;
+ * SECFailure will be returned if it is not.
+ */
+extern SECStatus SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,
+					    CERTCertDBHandle *certdb);
+
+
+/*
+ * Set the content; it will be included and also hashed and/or encrypted
+ * as appropriate.  This is for in-memory content (expected to be "small")
+ * that will be included in the PKCS7 object.  All others should stream the
+ * content through when encoding (see SEC_PKCS7Encoder{Start,Update,Finish}).
+ *
+ * "buf" points to data of length "len"; it will be copied.
+ */
+extern SECStatus SEC_PKCS7SetContent (SEC_PKCS7ContentInfo *cinfo,
+				      const char *buf, unsigned long len);
+
+/*
+ * Encode a PKCS7 object, in one shot.  All necessary components
+ * of the object must already be specified.  Either the data has
+ * already been included (via SetContent), or the data is detached,
+ * or there is no data at all (certs-only).
+ *
+ * "cinfo" specifies the object to be encoded.
+ *
+ * "outputfn" is where the encoded bytes will be passed.
+ *
+ * "outputarg" is an opaque argument to the above callback.
+ *
+ * "bulkkey" specifies the bulk encryption key to use.   This argument
+ * can be NULL if no encryption is being done, or if the bulk key should
+ * be generated internally (usually the case for EnvelopedData but never
+ * for EncryptedData, which *must* provide a bulk encryption key).
+ *
+ * "pwfn" is a callback for getting the password which protects the
+ * private key of the signer.  This argument can be NULL if it is known
+ * that no signing is going to be done.
+ *
+ * "pwfnarg" is an opaque argument to the above callback.
+ */
+extern SECStatus SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,
+				  SEC_PKCS7EncoderOutputCallback outputfn,
+				  void *outputarg,
+				  PK11SymKey *bulkkey,
+				  SECKEYGetPasswordKey pwfn,
+				  void *pwfnarg);
+
+/*
+ * Encode a PKCS7 object, in one shot.  All necessary components
+ * of the object must already be specified.  Either the data has
+ * already been included (via SetContent), or the data is detached,
+ * or there is no data at all (certs-only).  The output, rather than
+ * being passed to an output function as is done above, is all put
+ * into a SECItem.
+ *
+ * "pool" specifies a pool from which to allocate the result.
+ * It can be NULL, in which case memory is allocated generically.
+ *
+ * "dest" specifies a SECItem in which to put the result data.
+ * It can be NULL, in which case the entire item is allocated, too.
+ *
+ * "cinfo" specifies the object to be encoded.
+ *
+ * "bulkkey" specifies the bulk encryption key to use.   This argument
+ * can be NULL if no encryption is being done, or if the bulk key should
+ * be generated internally (usually the case for EnvelopedData but never
+ * for EncryptedData, which *must* provide a bulk encryption key).
+ *
+ * "pwfn" is a callback for getting the password which protects the
+ * private key of the signer.  This argument can be NULL if it is known
+ * that no signing is going to be done.
+ *
+ * "pwfnarg" is an opaque argument to the above callback.
+ */
+extern SECItem *SEC_PKCS7EncodeItem (PLArenaPool *pool,
+				     SECItem *dest,
+				     SEC_PKCS7ContentInfo *cinfo,
+				     PK11SymKey *bulkkey,
+				     SECKEYGetPasswordKey pwfn,
+				     void *pwfnarg);
+
+/*
+ * For those who want to simply point to the pkcs7 contentInfo ASN.1
+ * template, and *not* call the encoding functions directly, the
+ * following function can be used -- after it is called, the entire
+ * PKCS7 contentInfo is ready to be encoded.
+ */
+extern SECStatus SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,
+					    PK11SymKey *bulkkey,
+					    SECKEYGetPasswordKey pwfn,
+					    void *pwfnarg);
+
+/*
+ * Start the process of encoding a PKCS7 object.  The first part of
+ * the encoded object will be passed to the output function right away;
+ * after that it is expected that SEC_PKCS7EncoderUpdate will be called,
+ * streaming in the actual content that is getting included as well as
+ * signed or encrypted (or both).
+ *
+ * "cinfo" specifies the object to be encoded.
+ *
+ * "outputfn" is where the encoded bytes will be passed.
+ *
+ * "outputarg" is an opaque argument to the above callback.
+ *
+ * "bulkkey" specifies the bulk encryption key to use.   This argument
+ * can be NULL if no encryption is being done, or if the bulk key should
+ * be generated internally (usually the case for EnvelopedData but never
+ * for EncryptedData, which *must* provide a bulk encryption key).
+ *
+ * Returns an object to be passed to EncoderUpdate and EncoderFinish.
+ */
+extern SEC_PKCS7EncoderContext *
+SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo,
+		       SEC_PKCS7EncoderOutputCallback outputfn,
+		       void *outputarg,
+		       PK11SymKey *bulkkey);
+
+/*
+ * Encode more contents, hashing and/or encrypting along the way.
+ */
+extern SECStatus SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx,
+					 const char *buf,
+					 unsigned long len);
+
+/*
+ * No more contents; finish the signature creation, if appropriate,
+ * and then the encoding.
+ *
+ * "pwfn" is a callback for getting the password which protects the
+ * signer's private key.  This argument can be NULL if it is known
+ * that no signing is going to be done.
+ *
+ * "pwfnarg" is an opaque argument to the above callback.
+ */
+extern SECStatus SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,
+					 SECKEYGetPasswordKey pwfn,
+					 void *pwfnarg);
+
+/*  Abort the underlying ASN.1 stream & set an error  */
+void SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7dcx, int error);
+
+/* retrieve the algorithm ID used to encrypt the content info
+ * for encrypted and enveloped data.  The SECAlgorithmID pointer
+ * returned needs to be freed as it is a copy of the algorithm
+ * id in the content info.
+ */ 
+extern SECAlgorithmID *
+SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo); 
+
+/* the content of an encrypted data content info is encrypted.
+ * it is assumed that for encrypted data, that the data has already
+ * been set and is in the "plainContent" field of the content info.
+ *
+ * cinfo is the content info to encrypt
+ *
+ * key is the key with which to perform the encryption.  if the
+ *     algorithm is a password based encryption algorithm, the
+ *     key is actually a password which will be processed per
+ *     PKCS #5.
+ * 
+ * in the event of an error, SECFailure is returned.  SECSuccess
+ * indicates a success.
+ */
+extern SECStatus 
+SEC_PKCS7EncryptContents(PLArenaPool *poolp,
+			 SEC_PKCS7ContentInfo *cinfo, 
+			 SECItem *key,
+			 void *wincx); 
+	
+/* the content of an encrypted data content info is decrypted.
+ * it is assumed that for encrypted data, that the data has already
+ * been set and is in the "encContent" field of the content info.
+ *
+ * cinfo is the content info to decrypt
+ *
+ * key is the key with which to perform the decryption.  if the
+ *     algorithm is a password based encryption algorithm, the
+ *     key is actually a password which will be processed per
+ *     PKCS #5.
+ * 
+ * in the event of an error, SECFailure is returned.  SECSuccess
+ * indicates a success.
+ */
+extern SECStatus 
+SEC_PKCS7DecryptContents(PLArenaPool *poolp,
+			 SEC_PKCS7ContentInfo *cinfo, 
+			 SECItem *key,
+			 void *wincx); 
+
+/* retrieve the certificate list from the content info.  the list
+ * is a pointer to the list in the content info.  this should not
+ * be deleted or freed in any way short of calling 
+ * SEC_PKCS7DestroyContentInfo
+ */
+extern SECItem **
+SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo);
+
+/* Returns the key length (in bits) of the algorithm used to encrypt
+   this object.  Returns 0 if it's not encrypted, or the key length is
+   irrelevant. */
+extern int 
+SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo);
+ 
+
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif /* _SECPKCS7_H_ */
diff --git a/mozilla/security/nss/lib/pki/asymmkey.c b/mozilla/security/nss/lib/pki/asymmkey.c
new file mode 100644
index 0000000..717c0df
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/asymmkey.c
@@ -0,0 +1,434 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: asymmkey.c,v $ $Revision: 1.6 $ $Date: 2005/01/20 02:25:48 $";
+#endif /* DEBUG */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+NSS_IMPLEMENT PRStatus
+NSSPrivateKey_Destroy (
+  NSSPrivateKey *vk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPrivateKey_DeleteStoredObject (
+  NSSPrivateKey *vk,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSPrivateKey_GetSignatureLength (
+  NSSPrivateKey *vk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return -1;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSPrivateKey_GetPrivateModulusLength (
+  NSSPrivateKey *vk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return -1;
+}
+
+NSS_IMPLEMENT PRBool
+NSSPrivateKey_IsStillPresent (
+  NSSPrivateKey *vk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FALSE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_Encode (
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *ap,
+  NSSItem *passwordOpt, /* NULL will cause a callback; "" for no password */
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSPrivateKey_GetTrustDomain (
+  NSSPrivateKey *vk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSPrivateKey_GetToken (
+  NSSPrivateKey *vk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSPrivateKey_GetSlot (
+  NSSPrivateKey *vk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSPrivateKey_GetModule (
+  NSSPrivateKey *vk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_Decrypt (
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *encryptedData,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_Sign (
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_SignRecover (
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSPrivateKey_UnwrapSymmetricKey (
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSPrivateKey_DeriveSymmetricKey (
+  NSSPrivateKey *vk,
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt, /* zero for best allowed */
+  NSSOperations operations,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSPublicKey *
+NSSPrivateKey_FindPublicKey (
+  NSSPrivateKey *vk
+  /* { don't need the callback here, right? } */
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSPrivateKey_CreateCryptoContext (
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSPrivateKey_FindCertificates (
+  NSSPrivateKey *vk,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSPrivateKey_FindBestCertificate (
+  NSSPrivateKey *vk,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPublicKey_Destroy (
+  NSSPublicKey *bk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPublicKey_DeleteStoredObject (
+  NSSPublicKey *bk,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_Encode (
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *ap,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSPublicKey_GetTrustDomain (
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSPublicKey_GetToken (
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSPublicKey_GetSlot (
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSPublicKey_GetModule (
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_Encrypt (
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPublicKey_Verify (
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_VerifyRecover (
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_WrapSymmetricKey (
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSPublicKey_CreateCryptoContext (
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSPublicKey_FindCertificates (
+  NSSPublicKey *bk,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSPublicKey_FindBestCertificate (
+  NSSPublicKey *bk,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSPublicKey_FindPrivateKey (
+  NSSPublicKey *bk,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
diff --git a/mozilla/security/nss/lib/pki/certdecode.c b/mozilla/security/nss/lib/pki/certdecode.c
new file mode 100644
index 0000000..816d705
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/certdecode.c
@@ -0,0 +1,101 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: certdecode.c,v $ $Revision: 1.17 $ $Date: 2007/11/16 05:29:27 $";
+#endif /* DEBUG */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+/* This is defined in pki3hack.c */
+NSS_EXTERN nssDecodedCert *
+nssDecodedPKIXCertificate_Create (
+  NSSArena *arenaOpt,
+  NSSDER *encoding
+);
+
+NSS_IMPLEMENT PRStatus
+nssDecodedPKIXCertificate_Destroy (
+  nssDecodedCert *dc
+);
+
+NSS_IMPLEMENT nssDecodedCert *
+nssDecodedCert_Create (
+  NSSArena *arenaOpt,
+  NSSDER *encoding,
+  NSSCertificateType type
+)
+{
+    nssDecodedCert *rvDC = NULL;
+    switch(type) {
+    case NSSCertificateType_PKIX:
+	rvDC = nssDecodedPKIXCertificate_Create(arenaOpt, encoding);
+	break;
+    default:
+#if 0
+	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+#endif
+	return (nssDecodedCert *)NULL;
+    }
+    return rvDC;
+}
+
+NSS_IMPLEMENT PRStatus
+nssDecodedCert_Destroy (
+  nssDecodedCert *dc
+)
+{
+    if (!dc) {
+	return PR_FAILURE;
+    }
+    switch(dc->type) {
+    case NSSCertificateType_PKIX:
+	return nssDecodedPKIXCertificate_Destroy(dc);
+    default:
+#if 0
+	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+#endif
+	break;
+    }
+    return PR_FAILURE;
+}
+
diff --git a/mozilla/security/nss/lib/pki/certificate.c b/mozilla/security/nss/lib/pki/certificate.c
new file mode 100644
index 0000000..760d7bb
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/certificate.c
@@ -0,0 +1,1157 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.66 $ $Date: 2009/02/09 07:51:27 $";
+#endif /* DEBUG */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#include "pkistore.h"
+
+#include "pki3hack.h"
+#include "pk11func.h"
+#include "hasht.h"
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+/* Creates a certificate from a base object */
+NSS_IMPLEMENT NSSCertificate *
+nssCertificate_Create (
+  nssPKIObject *object
+)
+{
+    PRStatus status;
+    NSSCertificate *rvCert;
+    nssArenaMark * mark;
+    NSSArena *arena = object->arena;
+    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
+    PR_ASSERT(object->lockType == nssPKIMonitor);
+    mark = nssArena_Mark(arena);
+    rvCert = nss_ZNEW(arena, NSSCertificate);
+    if (!rvCert) {
+	return (NSSCertificate *)NULL;
+    }
+    rvCert->object = *object;
+    /* XXX should choose instance based on some criteria */
+    status = nssCryptokiCertificate_GetAttributes(object->instances[0],
+                                                  NULL,  /* XXX sessionOpt */
+                                                  arena,
+                                                  &rvCert->type,
+                                                  &rvCert->id,
+                                                  &rvCert->encoding,
+                                                  &rvCert->issuer,
+                                                  &rvCert->serial,
+                                                  &rvCert->subject);
+    if (status != PR_SUCCESS ||
+	!rvCert->encoding.data ||
+	!rvCert->encoding.size ||
+	!rvCert->issuer.data ||
+	!rvCert->issuer.size ||
+	!rvCert->serial.data ||
+	!rvCert->serial.size) {
+	if (mark)
+	    nssArena_Release(arena, mark);
+	return (NSSCertificate *)NULL;
+    }
+    if (mark)
+	nssArena_Unmark(arena, mark);
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssCertificate_AddRef (
+  NSSCertificate *c
+)
+{
+    if (c) {
+	nssPKIObject_AddRef(&c->object);
+    }
+    return c;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCertificate_Destroy (
+  NSSCertificate *c
+)
+{
+    nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
+    nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
+
+    if (c) {
+	PRUint32 i;
+	nssDecodedCert *dc = c->decoding;
+	NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+	NSSCryptoContext *cc = c->object.cryptoContext;
+
+	PR_ASSERT(c->object.refCount > 0);
+
+	/* --- LOCK storage --- */
+	if (cc) {
+	    nssCertificateStore_Lock(cc->certStore, &lockTrace);
+	} else {
+	    nssTrustDomain_LockCertCache(td);
+	}
+	if (PR_AtomicDecrement(&c->object.refCount) == 0) {
+	    /* --- remove cert and UNLOCK storage --- */
+	    if (cc) {
+		nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
+		nssCertificateStore_Unlock(cc->certStore, &lockTrace,
+                                           &unlockTrace);
+	    } else {
+		nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
+		nssTrustDomain_UnlockCertCache(td);
+	    }
+	    /* free cert data */
+	    for (i=0; i<c->object.numInstances; i++) {
+		nssCryptokiObject_Destroy(c->object.instances[i]);
+	    }
+	    nssPKIObject_DestroyLock(&c->object);
+	    nssArena_Destroy(c->object.arena);
+	    nssDecodedCert_Destroy(dc);
+	} else {
+	    /* --- UNLOCK storage --- */
+	    if (cc) {
+		nssCertificateStore_Unlock(cc->certStore,
+					   &lockTrace,
+					   &unlockTrace);
+	    } else {
+		nssTrustDomain_UnlockCertCache(td);
+	    }
+	}
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_Destroy (
+  NSSCertificate *c
+)
+{
+    return nssCertificate_Destroy(c);
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetEncoding (
+  NSSCertificate *c
+)
+{
+    if (c->encoding.size > 0 && c->encoding.data) {
+	return &c->encoding;
+    } else {
+	return (NSSDER *)NULL;
+    }
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetIssuer (
+  NSSCertificate *c
+)
+{
+    if (c->issuer.size > 0 && c->issuer.data) {
+	return &c->issuer;
+    } else {
+	return (NSSDER *)NULL;
+    }
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetSerialNumber (
+  NSSCertificate *c
+)
+{
+    if (c->serial.size > 0 && c->serial.data) {
+	return &c->serial;
+    } else {
+	return (NSSDER *)NULL;
+    }
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetSubject (
+  NSSCertificate *c
+)
+{
+    if (c->subject.size > 0 && c->subject.data) {
+	return &c->subject;
+    } else {
+	return (NSSDER *)NULL;
+    }
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssCertificate_GetNickname (
+  NSSCertificate *c,
+  NSSToken *tokenOpt
+)
+{
+    return nssPKIObject_GetNicknameForToken(&c->object, tokenOpt);
+}
+
+NSS_IMPLEMENT NSSASCII7 *
+nssCertificate_GetEmailAddress (
+  NSSCertificate *c
+)
+{
+    return c->email;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_DeleteStoredObject (
+  NSSCertificate *c,
+  NSSCallback *uhh
+)
+{
+    return nssPKIObject_DeleteStoredObject(&c->object, uhh, PR_TRUE);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_Validate (
+  NSSCertificate *c,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt /* NULL for none */
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT void ** /* void *[] */
+NSSCertificate_ValidateCompletely (
+  NSSCertificate *c,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt, /* NULL for none */
+  void **rvOpt, /* NULL for allocate */
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt /* NULL for heap */
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_ValidateAndDiscoverUsagesAndPolicies (
+  NSSCertificate *c,
+  NSSTime **notBeforeOutOpt,
+  NSSTime **notAfterOutOpt,
+  void *allowedUsages,
+  void *disallowedUsages,
+  void *allowedPolicies,
+  void *disallowedPolicies,
+  /* more args.. work on this fgmr */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSDER *
+NSSCertificate_Encode (
+  NSSCertificate *c,
+  NSSDER *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    /* Item, DER, BER are all typedefs now... */
+    return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt);
+}
+
+NSS_IMPLEMENT nssDecodedCert *
+nssCertificate_GetDecoding (
+  NSSCertificate *c
+)
+{
+    nssDecodedCert* deco = NULL;
+    if (c->type == NSSCertificateType_PKIX) {
+        (void)STAN_GetCERTCertificate(c);
+    }
+    nssPKIObject_Lock(&c->object);
+    if (!c->decoding) {
+	deco = nssDecodedCert_Create(NULL, &c->encoding, c->type);
+    	PORT_Assert(!c->decoding); 
+        c->decoding = deco;
+    } else {
+        deco = c->decoding;
+    }
+    nssPKIObject_Unlock(&c->object);
+    return deco;
+}
+
+static NSSCertificate **
+filter_subject_certs_for_id (
+  NSSCertificate **subjectCerts, 
+  void *id
+)
+{
+    NSSCertificate **si;
+    nssDecodedCert *dcp;
+    int nextOpenSlot = 0;
+    int i;
+    nssCertIDMatch matchLevel = nssCertIDMatch_Unknown;
+    nssCertIDMatch match;
+
+    /* walk the subject certs */
+    for (si = subjectCerts; *si; si++) {
+	dcp = nssCertificate_GetDecoding(*si);
+	if (!dcp) {
+	    NSSCertificate_Destroy(*si);
+	    continue;
+	}
+	match = dcp->matchIdentifier(dcp, id);
+	switch (match) {
+	case nssCertIDMatch_Yes:
+	    if (matchLevel == nssCertIDMatch_Unknown) {
+		/* we have non-definitive matches, forget them */
+		for (i = 0; i < nextOpenSlot; i++) {
+		    NSSCertificate_Destroy(subjectCerts[i]);
+		    subjectCerts[i] = NULL;
+		}
+		nextOpenSlot = 0;
+		/* only keep definitive matches from now on */
+		matchLevel = nssCertIDMatch_Yes;
+	    }
+	    /* keep the cert */
+	    subjectCerts[nextOpenSlot++] = *si;
+	    break;
+	case nssCertIDMatch_Unknown:
+	    if (matchLevel == nssCertIDMatch_Unknown) {
+		/* only have non-definitive matches so far, keep it */
+		subjectCerts[nextOpenSlot++] = *si;
+		break;
+	    }
+	    /* else fall through, we have a definitive match already */
+	case nssCertIDMatch_No:
+	default:
+	    NSSCertificate_Destroy(*si);
+	    *si = NULL;
+	}
+    }
+    subjectCerts[nextOpenSlot] = NULL;
+    return subjectCerts;
+}
+
+static NSSCertificate **
+filter_certs_for_valid_issuers (
+  NSSCertificate **certs
+)
+{
+    NSSCertificate **cp;
+    nssDecodedCert *dcp;
+    int nextOpenSlot = 0;
+
+    for (cp = certs; *cp; cp++) {
+	dcp = nssCertificate_GetDecoding(*cp);
+	if (dcp && dcp->isValidIssuer(dcp)) {
+	    certs[nextOpenSlot++] = *cp;
+	} else {
+	    NSSCertificate_Destroy(*cp);
+	}
+    }
+    certs[nextOpenSlot] = NULL;
+    return certs;
+}
+
+static NSSCertificate *
+find_cert_issuer (
+  NSSCertificate *c,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSTrustDomain *td,
+  NSSCryptoContext *cc
+)
+{
+    NSSArena *arena;
+    NSSCertificate **certs = NULL;
+    NSSCertificate **ccIssuers = NULL;
+    NSSCertificate **tdIssuers = NULL;
+    NSSCertificate *issuer = NULL;
+
+    if (!cc)
+	cc = c->object.cryptoContext;
+    if (!td)
+	td = NSSCertificate_GetTrustDomain(c);
+    arena = nssArena_Create();
+    if (!arena) {
+	return (NSSCertificate *)NULL;
+    }
+    if (cc) {
+	ccIssuers = nssCryptoContext_FindCertificatesBySubject(cc,
+	                                                       &c->issuer,
+	                                                       NULL,
+	                                                       0,
+	                                                       arena);
+    }
+    if (td)
+	tdIssuers = nssTrustDomain_FindCertificatesBySubject(td,
+                                                         &c->issuer,
+                                                         NULL,
+                                                         0,
+                                                         arena);
+    certs = nssCertificateArray_Join(ccIssuers, tdIssuers);
+    if (certs) {
+	nssDecodedCert *dc = NULL;
+	void *issuerID = NULL;
+	dc = nssCertificate_GetDecoding(c);
+	if (dc) {
+	    issuerID = dc->getIssuerIdentifier(dc);
+	}
+	/* XXX review based on CERT_FindCertIssuer
+	 * this function is not using the authCertIssuer field as a fallback
+	 * if authority key id does not exist
+	 */
+	if (issuerID) {
+	    certs = filter_subject_certs_for_id(certs, issuerID);
+	}
+	certs = filter_certs_for_valid_issuers(certs);
+	issuer = nssCertificateArray_FindBestCertificate(certs,
+	                                                 timeOpt,
+	                                                 usage,
+	                                                 policiesOpt);
+	nssCertificateArray_Destroy(certs);
+    }
+    nssArena_Destroy(arena);
+    return issuer;
+}
+
+/* This function returns the built chain, as far as it gets,
+** even if/when it fails to find an issuer, and returns PR_FAILURE
+*/
+NSS_IMPLEMENT NSSCertificate **
+nssCertificate_BuildChain (
+  NSSCertificate *c,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit,
+  NSSArena *arenaOpt,
+  PRStatus *statusOpt,
+  NSSTrustDomain *td,
+  NSSCryptoContext *cc 
+)
+{
+    NSSCertificate **rvChain = NULL;
+    NSSUsage issuerUsage = *usage;
+    nssPKIObjectCollection *collection = NULL;
+    PRUint32  rvCount = 0;
+    PRStatus  st;
+    PRStatus  ret = PR_SUCCESS;
+
+    if (!c || !cc ||
+        (!td && (td = NSSCertificate_GetTrustDomain(c)) == NULL)) {
+	goto loser;
+    }
+    /* bump the usage up to CA level */
+    issuerUsage.nss3lookingForCA = PR_TRUE;
+    collection = nssCertificateCollection_Create(td, NULL);
+    if (!collection)
+	goto loser;
+    st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
+    if (st != PR_SUCCESS)
+    	goto loser;
+    for (rvCount = 1; (!rvLimit || rvCount < rvLimit); ++rvCount) {
+	CERTCertificate *cCert = STAN_GetCERTCertificate(c);
+	if (cCert->isRoot) {
+	    /* not including the issuer of the self-signed cert, which is,
+	     * of course, itself
+	     */
+	    break;
+	}
+	c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt, td, cc);
+	if (!c) {
+	    ret = PR_FAILURE;
+	    break;
+	}
+	st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
+	nssCertificate_Destroy(c); /* collection has it */
+	if (st != PR_SUCCESS)
+	    goto loser;
+    }
+    rvChain = nssPKIObjectCollection_GetCertificates(collection, 
+                                                     rvOpt, 
+                                                     rvLimit, 
+                                                     arenaOpt);
+    if (rvChain) {
+	nssPKIObjectCollection_Destroy(collection);
+	if (statusOpt) 
+	    *statusOpt = ret;
+	if (ret != PR_SUCCESS)
+	    nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
+	return rvChain;
+    }
+
+loser:
+    if (collection)
+	nssPKIObjectCollection_Destroy(collection);
+    if (statusOpt) 
+	*statusOpt = PR_FAILURE;
+    nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
+    return rvChain;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCertificate_BuildChain (
+  NSSCertificate *c,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt,
+  PRStatus *statusOpt,
+  NSSTrustDomain *td,
+  NSSCryptoContext *cc 
+)
+{
+    return nssCertificate_BuildChain(c, timeOpt, usage, policiesOpt,
+                                     rvOpt, rvLimit, arenaOpt, statusOpt,
+				     td, cc);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+nssCertificate_GetCryptoContext (
+  NSSCertificate *c
+)
+{
+    return c->object.cryptoContext;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+nssCertificate_GetTrustDomain (
+  NSSCertificate *c
+)
+{
+    return c->object.trustDomain;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSCertificate_GetTrustDomain (
+  NSSCertificate *c
+)
+{
+    return nssCertificate_GetTrustDomain(c);
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSCertificate_GetToken (
+  NSSCertificate *c,
+  PRStatus *statusOpt
+)
+{
+    return (NSSToken *)NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSCertificate_GetSlot (
+  NSSCertificate *c,
+  PRStatus *statusOpt
+)
+{
+    return (NSSSlot *)NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSCertificate_GetModule (
+  NSSCertificate *c,
+  PRStatus *statusOpt
+)
+{
+    return (NSSModule *)NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCertificate_Encrypt (
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_Verify (
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCertificate_VerifyRecover (
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCertificate_WrapSymmetricKey (
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSCertificate_CreateCryptoContext (
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh  
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSPublicKey *
+NSSCertificate_GetPublicKey (
+  NSSCertificate *c
+)
+{
+#if 0
+    CK_ATTRIBUTE pubktemplate[] = {
+	{ CKA_CLASS,   NULL, 0 },
+	{ CKA_ID,      NULL, 0 },
+	{ CKA_SUBJECT, NULL, 0 }
+    };
+    PRStatus nssrv;
+    CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]);
+    NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey);
+    if (c->id.size > 0) {
+	/* CKA_ID */
+	NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]);
+    } else {
+	/* failure, yes? */
+	return (NSSPublicKey *)NULL;
+    }
+    if (c->subject.size > 0) {
+	/* CKA_SUBJECT */
+	NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]);
+    } else {
+	/* failure, yes? */
+	return (NSSPublicKey *)NULL;
+    }
+    /* Try the cert's token first */
+    if (c->token) {
+	nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count);
+    }
+#endif
+    /* Try all other key tokens */
+    return (NSSPublicKey *)NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSCertificate_FindPrivateKey (
+  NSSCertificate *c,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRBool
+NSSCertificate_IsPrivateKeyAvailable (
+  NSSCertificate *c,
+  NSSCallback *uhh,
+  PRStatus *statusOpt
+)
+{
+    PRBool isUser = PR_FALSE;
+    nssCryptokiObject **ip;
+    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
+    if (!instances) {
+	return PR_FALSE;
+    }
+    for (ip = instances; *ip; ip++) {
+	nssCryptokiObject *instance = *ip;
+	if (nssToken_IsPrivateKeyAvailable(instance->token, c, instance)) {
+	    isUser = PR_TRUE;
+	}
+    }
+    nssCryptokiObjectArray_Destroy(instances);
+    return isUser;
+}
+
+/* sort the subject cert list from newest to oldest */
+PRIntn
+nssCertificate_SubjectListSort (
+  void *v1,
+  void *v2
+)
+{
+    NSSCertificate *c1 = (NSSCertificate *)v1;
+    NSSCertificate *c2 = (NSSCertificate *)v2;
+    nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1);
+    nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2);
+    if (!dc1) {
+	return dc2 ? 1 : 0;
+    } else if (!dc2) {
+	return -1;
+    } else {
+	return dc1->isNewerThan(dc1, dc2) ? -1 : 1;
+    }
+}
+
+NSS_IMPLEMENT PRBool
+NSSUserCertificate_IsStillPresent (
+  NSSUserCertificate *uc,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FALSE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSUserCertificate_Decrypt (
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSUserCertificate_Sign (
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSUserCertificate_SignRecover (
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSUserCertificate_UnwrapSymmetricKey (
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSUserCertificate_DeriveSymmetricKey (
+  NSSUserCertificate *uc, /* provides private key */
+  NSSCertificate *c, /* provides public key */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt, /* zero for best allowed */
+  NSSOperations operations,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT nssSMIMEProfile *
+nssSMIMEProfile_Create (
+  NSSCertificate *cert,
+  NSSItem *profileTime,
+  NSSItem *profileData
+)
+{
+    NSSArena *arena;
+    nssSMIMEProfile *rvProfile;
+    nssPKIObject *object;
+    NSSTrustDomain *td = nssCertificate_GetTrustDomain(cert);
+    NSSCryptoContext *cc = nssCertificate_GetCryptoContext(cert);
+    arena = nssArena_Create();
+    if (!arena) {
+	return NULL;
+    }
+    object = nssPKIObject_Create(arena, NULL, td, cc, nssPKILock);
+    if (!object) {
+	goto loser;
+    }
+    rvProfile = nss_ZNEW(arena, nssSMIMEProfile);
+    if (!rvProfile) {
+	goto loser;
+    }
+    rvProfile->object = *object;
+    rvProfile->certificate = cert;
+    rvProfile->email = nssUTF8_Duplicate(cert->email, arena);
+    rvProfile->subject = nssItem_Duplicate(&cert->subject, arena, NULL);
+    if (profileTime) {
+	rvProfile->profileTime = nssItem_Duplicate(profileTime, arena, NULL);
+    }
+    if (profileData) {
+	rvProfile->profileData = nssItem_Duplicate(profileData, arena, NULL);
+    }
+    return rvProfile;
+loser:
+    if (object) nssPKIObject_Destroy(object);
+    else if (arena)  nssArena_Destroy(arena);
+    return (nssSMIMEProfile *)NULL;
+}
+
+/* execute a callback function on all members of a cert list */
+NSS_EXTERN PRStatus
+nssCertificateList_DoCallback (
+  nssList *certList, 
+  PRStatus (* callback)(NSSCertificate *c, void *arg),
+  void *arg
+)
+{
+    nssListIterator *certs;
+    NSSCertificate *cert;
+    PRStatus nssrv;
+    certs = nssList_CreateIterator(certList);
+    if (!certs) {
+        return PR_FAILURE;
+    }
+    for (cert  = (NSSCertificate *)nssListIterator_Start(certs);
+         cert != (NSSCertificate *)NULL;
+         cert  = (NSSCertificate *)nssListIterator_Next(certs))
+    {
+	nssrv = (*callback)(cert, arg);
+    }
+    nssListIterator_Finish(certs);
+    nssListIterator_Destroy(certs);
+    return PR_SUCCESS;
+}
+
+static PRStatus add_ref_callback(NSSCertificate *c, void *a)
+{
+    nssCertificate_AddRef(c);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void
+nssCertificateList_AddReferences (
+  nssList *certList
+)
+{
+    (void)nssCertificateList_DoCallback(certList, add_ref_callback, NULL);
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssTrust_Create (
+  nssPKIObject *object,
+  NSSItem *certData
+)
+{
+    PRStatus status;
+    PRUint32 i;
+    PRUint32 lastTrustOrder, myTrustOrder;
+    unsigned char sha1_hashcmp[SHA1_LENGTH];
+    unsigned char sha1_hashin[SHA1_LENGTH];
+    NSSItem sha1_hash;
+    NSSTrust *rvt;
+    nssCryptokiObject *instance;
+    nssTrustLevel serverAuth, clientAuth, codeSigning, emailProtection;
+    SECStatus rv; /* Should be stan flavor */
+    PRBool stepUp;
+
+    lastTrustOrder = 1<<16; /* just make it big */
+    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
+    rvt = nss_ZNEW(object->arena, NSSTrust);
+    if (!rvt) {
+	return (NSSTrust *)NULL;
+    }
+    rvt->object = *object;
+
+    /* should be stan flavor of Hashbuf */
+    rv = PK11_HashBuf(SEC_OID_SHA1,sha1_hashcmp,certData->data,certData->size);
+    if (rv != SECSuccess) {
+	return (NSSTrust *)NULL;
+    }
+    sha1_hash.data = sha1_hashin;
+    sha1_hash.size = sizeof (sha1_hashin);
+    /* trust has to peek into the base object members */
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	instance = object->instances[i];
+	myTrustOrder = nssToken_GetTrustOrder(instance->token);
+	status = nssCryptokiTrust_GetAttributes(instance, NULL,
+						&sha1_hash,
+	                                        &serverAuth,
+	                                        &clientAuth,
+	                                        &codeSigning,
+	                                        &emailProtection,
+	                                        &stepUp);
+	if (status != PR_SUCCESS) {
+	    nssPKIObject_Unlock(object);
+	    return (NSSTrust *)NULL;
+	}
+	if (PORT_Memcmp(sha1_hashin,sha1_hashcmp,SHA1_LENGTH) != 0) {
+	    nssPKIObject_Unlock(object);
+	    return (NSSTrust *)NULL;
+	}
+	if (rvt->serverAuth == nssTrustLevel_Unknown ||
+	    myTrustOrder < lastTrustOrder) 
+	{
+	    rvt->serverAuth = serverAuth;
+	}
+	if (rvt->clientAuth == nssTrustLevel_Unknown ||
+	    myTrustOrder < lastTrustOrder) 
+	{
+	    rvt->clientAuth = clientAuth;
+	}
+	if (rvt->emailProtection == nssTrustLevel_Unknown ||
+	    myTrustOrder < lastTrustOrder) 
+	{
+	    rvt->emailProtection = emailProtection;
+	}
+	if (rvt->codeSigning == nssTrustLevel_Unknown ||
+	    myTrustOrder < lastTrustOrder) 
+	{
+	    rvt->codeSigning = codeSigning;
+	}
+	rvt->stepUpApproved = stepUp;
+	lastTrustOrder = myTrustOrder;
+    }
+    nssPKIObject_Unlock(object);
+    return rvt;
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssTrust_AddRef (
+  NSSTrust *trust
+)
+{
+    if (trust) {
+	nssPKIObject_AddRef(&trust->object);
+    }
+    return trust;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTrust_Destroy (
+  NSSTrust *trust
+)
+{
+    if (trust) {
+	(void)nssPKIObject_Destroy(&trust->object);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT nssSMIMEProfile *
+nssSMIMEProfile_AddRef (
+  nssSMIMEProfile *profile
+)
+{
+    if (profile) {
+	nssPKIObject_AddRef(&profile->object);
+    }
+    return profile;
+}
+
+NSS_IMPLEMENT PRStatus
+nssSMIMEProfile_Destroy (
+  nssSMIMEProfile *profile
+)
+{
+    if (profile) {
+	(void)nssPKIObject_Destroy(&profile->object);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT NSSCRL *
+nssCRL_Create (
+  nssPKIObject *object
+)
+{
+    PRStatus status;
+    NSSCRL *rvCRL;
+    NSSArena *arena = object->arena;
+    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
+    rvCRL = nss_ZNEW(arena, NSSCRL);
+    if (!rvCRL) {
+	return (NSSCRL *)NULL;
+    }
+    rvCRL->object = *object;
+    /* XXX should choose instance based on some criteria */
+    status = nssCryptokiCRL_GetAttributes(object->instances[0],
+                                          NULL,  /* XXX sessionOpt */
+                                          arena,
+                                          &rvCRL->encoding,
+                                          NULL, /* subject */
+                                          NULL, /* class */
+                                          &rvCRL->url,
+                                          &rvCRL->isKRL);
+    if (status != PR_SUCCESS) {
+	return (NSSCRL *)NULL;
+    }
+    return rvCRL;
+}
+
+NSS_IMPLEMENT NSSCRL *
+nssCRL_AddRef (
+  NSSCRL *crl
+)
+{
+    if (crl) {
+	nssPKIObject_AddRef(&crl->object);
+    }
+    return crl;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCRL_Destroy (
+  NSSCRL *crl
+)
+{
+    if (crl) {
+	(void)nssPKIObject_Destroy(&crl->object);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCRL_DeleteStoredObject (
+  NSSCRL *crl,
+  NSSCallback *uhh
+)
+{
+    return nssPKIObject_DeleteStoredObject(&crl->object, uhh, PR_TRUE);
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCRL_GetEncoding (
+  NSSCRL *crl
+)
+{
+    if (crl && crl->encoding.data != NULL && crl->encoding.size > 0) {
+	return &crl->encoding;
+    } else {
+	return (NSSDER *)NULL;
+    }
+}
diff --git a/mozilla/security/nss/lib/pki/cryptocontext.c b/mozilla/security/nss/lib/pki/cryptocontext.c
new file mode 100644
index 0000000..a21f7b7
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/cryptocontext.c
@@ -0,0 +1,1020 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: cryptocontext.c,v $ $Revision: 1.18 $ $Date: 2007/11/16 05:29:27 $";
+#endif /* DEBUG */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef PKISTORE_H
+#include "pkistore.h"
+#endif /* PKISTORE_H */
+
+#include "pki1t.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
+
+NSS_IMPLEMENT NSSCryptoContext *
+nssCryptoContext_Create (
+  NSSTrustDomain *td,
+  NSSCallback *uhhOpt
+)
+{
+    NSSArena *arena;
+    NSSCryptoContext *rvCC;
+    arena = NSSArena_Create();
+    if (!arena) {
+	return NULL;
+    }
+    rvCC = nss_ZNEW(arena, NSSCryptoContext);
+    if (!rvCC) {
+	return NULL;
+    }
+    rvCC->td = td;
+    rvCC->arena = arena;
+    rvCC->certStore = nssCertificateStore_Create(rvCC->arena);
+    if (!rvCC->certStore) {
+	nssArena_Destroy(arena);
+	return NULL;
+    }
+
+    return rvCC;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_Destroy (
+  NSSCryptoContext *cc
+)
+{
+    PRStatus status = PR_SUCCESS;
+    PORT_Assert(cc->certStore);
+    if (cc->certStore) {
+	status = nssCertificateStore_Destroy(cc->certStore);
+	if (status == PR_FAILURE) {
+	    return status;
+	}
+    } else {
+	status = PR_FAILURE;
+    }
+    nssArena_Destroy(cc->arena);
+    return status;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_SetDefaultCallback (
+  NSSCryptoContext *td,
+  NSSCallback *newCallback,
+  NSSCallback **oldCallbackOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSCallback *
+NSSCryptoContext_GetDefaultCallback (
+  NSSCryptoContext *td,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSCryptoContext_GetTrustDomain (
+  NSSCryptoContext *td
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindOrImportCertificate (
+  NSSCryptoContext *cc,
+  NSSCertificate *c
+)
+{
+    NSSCertificate *rvCert = NULL;
+
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+	return rvCert;
+    }
+    rvCert = nssCertificateStore_FindOrAdd(cc->certStore, c);
+    if (rvCert == c && c->object.cryptoContext != cc) {
+	PORT_Assert(!c->object.cryptoContext);
+	c->object.cryptoContext = cc;
+    } 
+    if (rvCert) {
+	/* an NSSCertificate cannot be part of two crypto contexts
+	** simultaneously.  If this assertion fails, then there is 
+	** a serious Stan design flaw.
+	*/
+	PORT_Assert(cc == c->object.cryptoContext);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_ImportPKIXCertificate (
+  NSSCryptoContext *cc,
+  struct NSSPKIXCertificateStr *pc
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_ImportEncodedCertificate (
+  NSSCryptoContext *cc,
+  NSSBER *ber
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ImportEncodedPKIXCertificateChain (
+  NSSCryptoContext *cc,
+  NSSBER *ber
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCryptoContext_ImportTrust (
+  NSSCryptoContext *cc,
+  NSSTrust *trust
+)
+{
+    PRStatus nssrv;
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return PR_FAILURE;
+    }
+    nssrv = nssCertificateStore_AddTrust(cc->certStore, trust);
+#if 0
+    if (nssrv == PR_SUCCESS) {
+	trust->object.cryptoContext = cc;
+    }
+#endif
+    return nssrv;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCryptoContext_ImportSMIMEProfile (
+  NSSCryptoContext *cc,
+  nssSMIMEProfile *profile
+)
+{
+    PRStatus nssrv;
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return PR_FAILURE;
+    }
+    nssrv = nssCertificateStore_AddSMIMEProfile(cc->certStore, profile);
+#if 0
+    if (nssrv == PR_SUCCESS) {
+	profile->object.cryptoContext = cc;
+    }
+#endif
+    return nssrv;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNickname (
+  NSSCryptoContext *cc,
+  const NSSUTF8 *name,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt /* NULL for none */
+)
+{
+    NSSCertificate **certs;
+    NSSCertificate *rvCert = NULL;
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    certs = nssCertificateStore_FindCertificatesByNickname(cc->certStore,
+                                                           name,
+                                                           NULL, 0, NULL);
+    if (certs) {
+	rvCert = nssCertificateArray_FindBestCertificate(certs,
+	                                                 timeOpt,
+	                                                 usage,
+	                                                 policiesOpt);
+	nssCertificateArray_Destroy(certs);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesByNickname (
+  NSSCryptoContext *cc,
+  NSSUTF8 *name,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    NSSCertificate **rvCerts;
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    rvCerts = nssCertificateStore_FindCertificatesByNickname(cc->certStore,
+                                                             name,
+                                                             rvOpt,
+                                                             maximumOpt,
+                                                             arenaOpt);
+    return rvCerts;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindCertificateByIssuerAndSerialNumber (
+  NSSCryptoContext *cc,
+  NSSDER *issuer,
+  NSSDER *serialNumber
+)
+{
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    return nssCertificateStore_FindCertificateByIssuerAndSerialNumber(
+                                                               cc->certStore,
+                                                               issuer,
+                                                               serialNumber);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateBySubject (
+  NSSCryptoContext *cc,
+  NSSDER *subject,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    NSSCertificate **certs;
+    NSSCertificate *rvCert = NULL;
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    certs = nssCertificateStore_FindCertificatesBySubject(cc->certStore,
+                                                          subject,
+                                                          NULL, 0, NULL);
+    if (certs) {
+	rvCert = nssCertificateArray_FindBestCertificate(certs,
+	                                                 timeOpt,
+	                                                 usage,
+	                                                 policiesOpt);
+	nssCertificateArray_Destroy(certs);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssCryptoContext_FindCertificatesBySubject (
+  NSSCryptoContext *cc,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    NSSCertificate **rvCerts;
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    rvCerts = nssCertificateStore_FindCertificatesBySubject(cc->certStore,
+                                                            subject,
+                                                            rvOpt,
+                                                            maximumOpt,
+                                                            arenaOpt);
+    return rvCerts;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesBySubject (
+  NSSCryptoContext *cc,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    return nssCryptoContext_FindCertificatesBySubject(cc, subject,
+                                                      rvOpt, maximumOpt,
+                                                      arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNameComponents (
+  NSSCryptoContext *cc,
+  NSSUTF8 *nameComponents,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesByNameComponents (
+  NSSCryptoContext *cc,
+  NSSUTF8 *nameComponents,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindCertificateByEncodedCertificate (
+  NSSCryptoContext *cc,
+  NSSBER *encodedCertificate
+)
+{
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    return nssCertificateStore_FindCertificateByEncodedCertificate(
+                                                           cc->certStore,
+                                                           encodedCertificate);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateByEmail (
+  NSSCryptoContext *cc,
+  NSSASCII7 *email,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    NSSCertificate **certs;
+    NSSCertificate *rvCert = NULL;
+
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    certs = nssCertificateStore_FindCertificatesByEmail(cc->certStore,
+                                                        email,
+                                                        NULL, 0, NULL);
+    if (certs) {
+	rvCert = nssCertificateArray_FindBestCertificate(certs,
+	                                                 timeOpt,
+	                                                 usage,
+	                                                 policiesOpt);
+	nssCertificateArray_Destroy(certs);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesByEmail (
+  NSSCryptoContext *cc,
+  NSSASCII7 *email,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    NSSCertificate **rvCerts;
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    rvCerts = nssCertificateStore_FindCertificatesByEmail(cc->certStore,
+                                                          email,
+                                                          rvOpt,
+                                                          maximumOpt,
+                                                          arenaOpt);
+    return rvCerts;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindCertificateByOCSPHash (
+  NSSCryptoContext *cc,
+  NSSItem *hash
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestUserCertificate (
+  NSSCryptoContext *cc,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindUserCertificates (
+  NSSCryptoContext *cc,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForSSLClientAuth (
+  NSSCryptoContext *cc,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindUserCertificatesForSSLClientAuth (
+  NSSCryptoContext *cc,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForEmailSigning (
+  NSSCryptoContext *cc,
+  NSSASCII7 *signerOpt,
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindUserCertificatesForEmailSigning (
+  NSSCryptoContext *cc,
+  NSSASCII7 *signerOpt, /* fgmr or a more general name? */
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssCryptoContext_FindTrustForCertificate (
+  NSSCryptoContext *cc,
+  NSSCertificate *cert
+)
+{
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    return nssCertificateStore_FindTrustForCertificate(cc->certStore, cert);
+}
+
+NSS_IMPLEMENT nssSMIMEProfile *
+nssCryptoContext_FindSMIMEProfileForCertificate (
+  NSSCryptoContext *cc,
+  NSSCertificate *cert
+)
+{
+    PORT_Assert(cc->certStore);
+    if (!cc->certStore) {
+	return NULL;
+    }
+    return nssCertificateStore_FindSMIMEProfileForCertificate(cc->certStore, 
+                                                              cert);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_GenerateKeyPair (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *ap,
+  NSSPrivateKey **pvkOpt,
+  NSSPublicKey **pbkOpt,
+  PRBool privateKeyIsSensitive,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKey (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *ap,
+  PRUint32 keysize,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKeyFromPassword (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *ap,
+  NSSUTF8 *passwordOpt, /* if null, prompt */
+  NSSToken *destinationOpt,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_FindSymmetricKeyByAlgorithmAndKeyID (
+  NSSCryptoContext *cc,
+  NSSOID *algorithm,
+  NSSItem *keyID,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+struct token_session_str {
+    NSSToken *token;
+    nssSession *session;
+};
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Decrypt (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *encryptedData,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginDecrypt (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueDecrypt (
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishDecrypt (
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Sign (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginSign (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ContinueSign (
+  NSSCryptoContext *cc,
+  NSSItem *data
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishSign (
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_SignRecover (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginSignRecover (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueSignRecover (
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishSignRecover (
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_UnwrapSymmetricKey (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_DeriveSymmetricKey (
+  NSSCryptoContext *cc,
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt, /* zero for best allowed */
+  NSSOperations operations,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Encrypt (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginEncrypt (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueEncrypt (
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishEncrypt (
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_Verify (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginVerify (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ContinueVerify (
+  NSSCryptoContext *cc,
+  NSSItem *data
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_FinishVerify (
+  NSSCryptoContext *cc
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_VerifyRecover (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginVerifyRecover (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueVerifyRecover (
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishVerifyRecover (
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_WrapSymmetricKey (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Digest (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    return nssToken_Digest(cc->token, cc->session, apOpt, 
+                           data, rvOpt, arenaOpt);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginDigest (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+)
+{
+    return nssToken_BeginDigest(cc->token, cc->session, apOpt);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ContinueDigest (
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *item
+)
+{
+	/*
+    NSSAlgorithmAndParameters *ap;
+    ap = (apOpt) ? apOpt : cc->ap;
+    */
+	/* why apOpt?  can't change it at this point... */
+    return nssToken_ContinueDigest(cc->token, cc->session, item);
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishDigest (
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    return nssToken_FinishDigest(cc->token, cc->session, rvOpt, arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSCryptoContext_Clone (
+  NSSCryptoContext *cc
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
diff --git a/mozilla/security/nss/lib/pki/nsspki.h b/mozilla/security/nss/lib/pki/nsspki.h
new file mode 100644
index 0000000..354a1ab
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/nsspki.h
@@ -0,0 +1,3204 @@
+/* ***** 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 ***** */
+
+#ifndef NSSPKI_H
+#define NSSPKI_H
+
+#ifdef DEBUG
+static const char NSSPKI_CVS_ID[] = "@(#) $RCSfile: nsspki.h,v $ $Revision: 1.12 $ $Date: 2007/07/11 04:47:42 $";
+#endif /* DEBUG */
+
+/*
+ * nsspki.h
+ *
+ * This file prototypes the methods of the top-level PKI objects.
+ */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#ifndef NSSPKI1_H
+#include "nsspki1.h"
+#endif /* NSSPKI1_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A note about interfaces
+ *
+ * Although these APIs are specified in C, a language which does
+ * not have fancy support for abstract interfaces, this library
+ * was designed from an object-oriented perspective.  It may be
+ * useful to consider the standard interfaces which went into
+ * the writing of these APIs.
+ *
+ * Basic operations on all objects:
+ *  Destroy -- free a pointer to an object
+ *  DeleteStoredObject -- delete an object permanently
+ *
+ * Public Key cryptographic operations:
+ *  Encrypt
+ *  Verify
+ *  VerifyRecover
+ *  Wrap
+ *  Derive
+ *
+ * Private Key cryptographic operations:
+ *  IsStillPresent
+ *  Decrypt
+ *  Sign
+ *  SignRecover
+ *  Unwrap
+ *  Derive
+ *
+ * Symmetric Key cryptographic operations:
+ *  IsStillPresent
+ *  Encrypt
+ *  Decrypt
+ *  Sign
+ *  SignRecover
+ *  Verify
+ *  VerifyRecover
+ *  Wrap
+ *  Unwrap
+ *  Derive
+ *
+ */
+
+/*
+ * NSSCertificate
+ *
+ * These things can do crypto ops like public keys, except that the trust, 
+ * usage, and other constraints are checked.  These objects are "high-level,"
+ * so trust, usages, etc. are in the form we throw around (client auth,
+ * email signing, etc.).  Remember that theoretically another implementation
+ * (think PGP) could be beneath this object.
+ */
+
+/*
+ * NSSCertificate_Destroy
+ *
+ * Free a pointer to a certificate object.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_Destroy
+(
+  NSSCertificate *c
+);
+
+/*
+ * NSSCertificate_DeleteStoredObject
+ *
+ * Permanently remove this certificate from storage.  If this is the
+ * only (remaining) certificate corresponding to a private key, 
+ * public key, and/or other object; then that object (those objects)
+ * are deleted too.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_DeleteStoredObject
+(
+  NSSCertificate *c,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSCertificate_Validate
+ *
+ * Verify that this certificate is trusted, for the specified usage(s), 
+ * at the specified time, {word word} the specified policies.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_Validate
+(
+  NSSCertificate *c,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/*
+ * NSSCertificate_ValidateCompletely
+ *
+ * Verify that this certificate is trusted.  The difference between
+ * this and the previous call is that NSSCertificate_Validate merely
+ * returns success or failure with an appropriate error stack.
+ * However, there may be (and often are) multiple problems with a
+ * certificate.  This routine returns an array of errors, specifying
+ * every problem.
+ */
+
+/* 
+ * Return value must be an array of objects, each of which has
+ * an NSSError, and any corresponding certificate (in the chain)
+ * and/or policy.
+ */
+
+NSS_EXTERN void ** /* void *[] */
+NSSCertificate_ValidateCompletely
+(
+  NSSCertificate *c,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt, /* NULL for none */
+  void **rvOpt, /* NULL for allocate */
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt /* NULL for heap */
+);
+
+/*
+ * NSSCertificate_ValidateAndDiscoverUsagesAndPolicies
+ *
+ * Returns PR_SUCCESS if the certificate is valid for at least something.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_ValidateAndDiscoverUsagesAndPolicies
+(
+  NSSCertificate *c,
+  NSSTime **notBeforeOutOpt,
+  NSSTime **notAfterOutOpt,
+  void *allowedUsages,
+  void *disallowedUsages,
+  void *allowedPolicies,
+  void *disallowedPolicies,
+  /* more args.. work on this fgmr */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCertificate_Encode
+ *
+ */
+
+NSS_EXTERN NSSDER *
+NSSCertificate_Encode
+(
+  NSSCertificate *c,
+  NSSDER *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCertificate_BuildChain
+ *
+ * This routine returns NSSCertificate *'s for each certificate
+ * in the "chain" starting from the specified one up to and
+ * including the root.  The zeroth element in the array is the
+ * specified ("leaf") certificate.
+ *
+ * If statusOpt is supplied, and is returned as PR_FAILURE, possible
+ * error values are:
+ *
+ * NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND - the chain is incomplete
+ *
+ */
+
+extern const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND;
+
+NSS_EXTERN NSSCertificate **
+NSSCertificate_BuildChain
+(
+  NSSCertificate *c,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt,
+  PRStatus *statusOpt,
+  NSSTrustDomain *td,
+  NSSCryptoContext *cc 
+);
+
+/*
+ * NSSCertificate_GetTrustDomain
+ *
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSCertificate_GetTrustDomain
+(
+  NSSCertificate *c
+);
+
+/*
+ * NSSCertificate_GetToken
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSToken *
+NSSCertificate_GetToken
+(
+  NSSCertificate *c,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSCertificate_GetSlot
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSSlot *
+NSSCertificate_GetSlot
+(
+  NSSCertificate *c,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSCertificate_GetModule
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSModule *
+NSSCertificate_GetModule
+(
+  NSSCertificate *c,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSCertificate_Encrypt
+ *
+ * Encrypt a single chunk of data with the public key corresponding to
+ * this certificate.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCertificate_Encrypt
+(
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCertificate_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_Verify
+(
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSCertificate_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCertificate_VerifyRecover
+(
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCertificate_WrapSymmetricKey
+ *
+ * This method tries very hard to to succeed, even in situations 
+ * involving sensitive keys and multiple modules.
+ * { relyea: want to add verbiage? }
+ */
+
+NSS_EXTERN NSSItem *
+NSSCertificate_WrapSymmetricKey
+(
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCertificate_CreateCryptoContext
+ *
+ * Create a crypto context, in this certificate's trust domain, with this
+ * as the distinguished certificate.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSCertificate_CreateCryptoContext
+(
+  NSSCertificate *c,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh  
+);
+
+/*
+ * NSSCertificate_GetPublicKey
+ *
+ * Returns the public key corresponding to this certificate.
+ */
+
+NSS_EXTERN NSSPublicKey *
+NSSCertificate_GetPublicKey
+(
+  NSSCertificate *c
+);
+
+/*
+ * NSSCertificate_FindPrivateKey
+ *
+ * Finds and returns the private key corresponding to this certificate,
+ * if it is available.
+ *
+ * { Should this hang off of NSSUserCertificate? }
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSCertificate_FindPrivateKey
+(
+  NSSCertificate *c,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSCertificate_IsPrivateKeyAvailable
+ *
+ * Returns success if the private key corresponding to this certificate
+ * is available to be used.
+ *
+ * { Should *this* hang off of NSSUserCertificate?? }
+ */
+
+NSS_EXTERN PRBool
+NSSCertificate_IsPrivateKeyAvailable
+(
+  NSSCertificate *c,
+  NSSCallback *uhh,
+  PRStatus *statusOpt
+);
+
+/*
+ * If we make NSSUserCertificate not a typedef of NSSCertificate, 
+ * then we'll need implementations of the following:
+ *
+ *  NSSUserCertificate_Destroy
+ *  NSSUserCertificate_DeleteStoredObject
+ *  NSSUserCertificate_Validate
+ *  NSSUserCertificate_ValidateCompletely
+ *  NSSUserCertificate_ValidateAndDiscoverUsagesAndPolicies
+ *  NSSUserCertificate_Encode
+ *  NSSUserCertificate_BuildChain
+ *  NSSUserCertificate_GetTrustDomain
+ *  NSSUserCertificate_GetToken
+ *  NSSUserCertificate_GetSlot
+ *  NSSUserCertificate_GetModule
+ *  NSSUserCertificate_GetCryptoContext
+ *  NSSUserCertificate_GetPublicKey
+ */
+
+/*
+ * NSSUserCertificate_IsStillPresent
+ *
+ * Verify that if this certificate lives on a token, that the token
+ * is still present and the certificate still exists.  This is a
+ * lightweight call which should be used whenever it should be
+ * verified that the user hasn't perhaps popped out his or her
+ * token and strolled away.
+ */
+
+NSS_EXTERN PRBool
+NSSUserCertificate_IsStillPresent
+(
+  NSSUserCertificate *uc,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSUserCertificate_Decrypt
+ *
+ * Decrypt a single chunk of data with the private key corresponding
+ * to this certificate.
+ */
+
+NSS_EXTERN NSSItem *
+NSSUserCertificate_Decrypt
+(
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSUserCertificate_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSUserCertificate_Sign
+(
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSUserCertificate_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSUserCertificate_SignRecover
+(
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSUserCertificate_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSUserCertificate_UnwrapSymmetricKey
+(
+  NSSUserCertificate *uc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSUserCertificate_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSUserCertificate_DeriveSymmetricKey
+(
+  NSSUserCertificate *uc, /* provides private key */
+  NSSCertificate *c, /* provides public key */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt, /* zero for best allowed */
+  NSSOperations operations,
+  NSSCallback *uhh
+);
+
+/* filter-certs function(s) */
+
+/**
+ ** fgmr -- trust objects
+ **/
+
+/*
+ * NSSPrivateKey
+ *
+ */
+
+/*
+ * NSSPrivateKey_Destroy
+ *
+ * Free a pointer to a private key object.
+ */
+
+NSS_EXTERN PRStatus
+NSSPrivateKey_Destroy
+(
+  NSSPrivateKey *vk
+);
+
+/*
+ * NSSPrivateKey_DeleteStoredObject
+ *
+ * Permanently remove this object, and any related objects (such as the
+ * certificates corresponding to this key).
+ */
+
+NSS_EXTERN PRStatus
+NSSPrivateKey_DeleteStoredObject
+(
+  NSSPrivateKey *vk,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSPrivateKey_GetSignatureLength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSPrivateKey_GetSignatureLength
+(
+  NSSPrivateKey *vk
+);
+
+/*
+ * NSSPrivateKey_GetPrivateModulusLength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSPrivateKey_GetPrivateModulusLength
+(
+  NSSPrivateKey *vk
+);
+
+/*
+ * NSSPrivateKey_IsStillPresent
+ *
+ */
+
+NSS_EXTERN PRBool
+NSSPrivateKey_IsStillPresent
+(
+  NSSPrivateKey *vk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSPrivateKey_Encode
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_Encode
+(
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *ap,
+  NSSItem *passwordOpt, /* NULL will cause a callback; "" for no password */
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPrivateKey_GetTrustDomain
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSPrivateKey_GetTrustDomain
+(
+  NSSPrivateKey *vk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSPrivateKey_GetToken
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSPrivateKey_GetToken
+(
+  NSSPrivateKey *vk
+);
+
+/*
+ * NSSPrivateKey_GetSlot
+ *
+ */
+
+NSS_EXTERN NSSSlot *
+NSSPrivateKey_GetSlot
+(
+  NSSPrivateKey *vk
+);
+
+/*
+ * NSSPrivateKey_GetModule
+ *
+ */
+
+NSS_EXTERN NSSModule *
+NSSPrivateKey_GetModule
+(
+  NSSPrivateKey *vk
+);
+
+/*
+ * NSSPrivateKey_Decrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_Decrypt
+(
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *encryptedData,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPrivateKey_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_Sign
+(
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPrivateKey_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_SignRecover
+(
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPrivateKey_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSPrivateKey_UnwrapSymmetricKey
+(
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSPrivateKey_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSPrivateKey_DeriveSymmetricKey
+(
+  NSSPrivateKey *vk,
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt, /* zero for best allowed */
+  NSSOperations operations,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSPrivateKey_FindPublicKey
+ *
+ */
+
+NSS_EXTERN NSSPublicKey *
+NSSPrivateKey_FindPublicKey
+(
+  NSSPrivateKey *vk
+  /* { don't need the callback here, right? } */
+);
+
+/*
+ * NSSPrivateKey_CreateCryptoContext
+ *
+ * Create a crypto context, in this key's trust domain,
+ * with this as the distinguished private key.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSPrivateKey_CreateCryptoContext
+(
+  NSSPrivateKey *vk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSPrivateKey_FindCertificates
+ *
+ * Note that there may be more than one certificate for this
+ * private key.  { FilterCertificates function to further
+ * reduce the list. }
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSPrivateKey_FindCertificates
+(
+  NSSPrivateKey *vk,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPrivateKey_FindBestCertificate
+ *
+ * The parameters for this function will depend on what the users
+ * need.  This is just a starting point.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSPrivateKey_FindBestCertificate
+(
+  NSSPrivateKey *vk,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSPublicKey
+ *
+ * Once you generate, find, or derive one of these, you can use it
+ * to perform (simple) cryptographic operations.  Though there may
+ * be certificates associated with these public keys, they are not
+ * verified.
+ */
+
+/*
+ * NSSPublicKey_Destroy
+ *
+ * Free a pointer to a public key object.
+ */
+
+NSS_EXTERN PRStatus
+NSSPublicKey_Destroy
+(
+  NSSPublicKey *bk
+);
+
+/*
+ * NSSPublicKey_DeleteStoredObject
+ *
+ * Permanently remove this object, and any related objects (such as the
+ * corresponding private keys and certificates).
+ */
+
+NSS_EXTERN PRStatus
+NSSPublicKey_DeleteStoredObject
+(
+  NSSPublicKey *bk,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSPublicKey_Encode
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_Encode
+(
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *ap,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPublicKey_GetTrustDomain
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSPublicKey_GetTrustDomain
+(
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSPublicKey_GetToken
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSToken *
+NSSPublicKey_GetToken
+(
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSPublicKey_GetSlot
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSSlot *
+NSSPublicKey_GetSlot
+(
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSPublicKey_GetModule
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSModule *
+NSSPublicKey_GetModule
+(
+  NSSPublicKey *bk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSPublicKey_Encrypt
+ *
+ * Encrypt a single chunk of data with the public key corresponding to
+ * this certificate.
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_Encrypt
+(
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPublicKey_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSPublicKey_Verify
+(
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSPublicKey_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_VerifyRecover
+(
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPublicKey_WrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_WrapSymmetricKey
+(
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPublicKey_CreateCryptoContext
+ *
+ * Create a crypto context, in this key's trust domain, with this
+ * as the distinguished public key.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSPublicKey_CreateCryptoContext
+(
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSPublicKey_FindCertificates
+ *
+ * Note that there may be more than one certificate for this
+ * public key.  The current implementation may not find every
+ * last certificate available for this public key: that would
+ * involve trolling e.g. huge ldap databases, which will be
+ * grossly inefficient and not generally useful.
+ * { FilterCertificates function to further reduce the list }
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSPublicKey_FindCertificates
+(
+  NSSPublicKey *bk,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSPrivateKey_FindBestCertificate
+ *
+ * The parameters for this function will depend on what the users
+ * need.  This is just a starting point.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSPublicKey_FindBestCertificate
+(
+  NSSPublicKey *bk,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSPublicKey_FindPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSPublicKey_FindPrivateKey
+(
+  NSSPublicKey *bk,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSSymmetricKey
+ *
+ */
+
+/*
+ * NSSSymmetricKey_Destroy
+ *
+ * Free a pointer to a symmetric key object.
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_Destroy
+(
+  NSSSymmetricKey *mk
+);
+
+/*
+ * NSSSymmetricKey_DeleteStoredObject
+ *
+ * Permanently remove this object.
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_DeleteStoredObject
+(
+  NSSSymmetricKey *mk,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSSymmetricKey_GetKeyLength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSSymmetricKey_GetKeyLength
+(
+  NSSSymmetricKey *mk
+);
+
+/*
+ * NSSSymmetricKey_GetKeyStrength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSSymmetricKey_GetKeyStrength
+(
+  NSSSymmetricKey *mk
+);
+
+/*
+ * NSSSymmetricKey_IsStillPresent
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_IsStillPresent
+(
+  NSSSymmetricKey *mk
+);
+
+/*
+ * NSSSymmetricKey_GetTrustDomain
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSSymmetricKey_GetTrustDomain
+(
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSSymmetricKey_GetToken
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSToken *
+NSSSymmetricKey_GetToken
+(
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSSymmetricKey_GetSlot
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSSlot *
+NSSSymmetricKey_GetSlot
+(
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSSymmetricKey_GetModule
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSModule *
+NSSSymmetricKey_GetModule
+(
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSSymmetricKey_Encrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_Encrypt
+(
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSSymmetricKey_Decrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_Decrypt
+(
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *encryptedData,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSSymmetricKey_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_Sign
+(
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSSymmetricKey_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_SignRecover
+(
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSSymmetricKey_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_Verify
+(
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSSymmetricKey_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_VerifyRecover
+(
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSSymmetricKey_WrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_WrapSymmetricKey
+(
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSSymmetricKey_WrapPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_WrapPrivateKey
+(
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPrivateKey *keyToWrap,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSSymmetricKey_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSSymmetricKey_UnwrapSymmetricKey
+(
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSOID *target,
+  PRUint32 keySizeOpt,
+  NSSOperations operations,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSSymmetricKey_UnwrapPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSSymmetricKey_UnwrapPrivateKey
+(
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSUTF8 *labelOpt,
+  NSSItem *keyIDOpt,
+  PRBool persistant,
+  PRBool sensitive,
+  NSSToken *destinationOpt,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSSymmetricKey_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSSymmetricKey_DeriveSymmetricKey
+(
+  NSSSymmetricKey *originalKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt,
+  NSSOperations operations,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSSymmetricKey_CreateCryptoContext
+ *
+ * Create a crypto context, in this key's trust domain,
+ * with this as the distinguished symmetric key.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSSymmetricKey_CreateCryptoContext
+(
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhh
+);
+
+/*
+ * NSSTrustDomain
+ *
+ */
+
+/*
+ * NSSTrustDomain_Create
+ *
+ * This creates a trust domain, optionally with an initial cryptoki
+ * module.  If the module name is not null, the module is loaded if
+ * needed (using the uriOpt argument), and initialized with the
+ * opaqueOpt argument.  If mumble mumble priority settings, then
+ * module-specification objects in the module can cause the loading
+ * and initialization of further modules.
+ *
+ * The uriOpt is defined to take a URI.  At present, we only
+ * support file: URLs pointing to platform-native shared libraries.
+ * However, by specifying this as a URI, this keeps open the 
+ * possibility of supporting other, possibly remote, resources.
+ *
+ * The "reserved" arguments is held for when we figure out the
+ * module priority stuff.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSTrustDomain_Create
+(
+  NSSUTF8 *moduleOpt,
+  NSSUTF8 *uriOpt,
+  NSSUTF8 *opaqueOpt,
+  void *reserved
+);
+
+/*
+ * NSSTrustDomain_Destroy
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_Destroy
+(
+  NSSTrustDomain *td
+);
+
+/*
+ * NSSTrustDomain_SetDefaultCallback
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_SetDefaultCallback
+(
+  NSSTrustDomain *td,
+  NSSCallback *newCallback,
+  NSSCallback **oldCallbackOpt
+);
+
+/*
+ * NSSTrustDomain_GetDefaultCallback
+ *
+ */
+
+NSS_EXTERN NSSCallback *
+NSSTrustDomain_GetDefaultCallback
+(
+  NSSTrustDomain *td,
+  PRStatus *statusOpt
+);
+
+/*
+ * Default policies?
+ * Default usage?
+ * Default time, for completeness?
+ */
+
+/*
+ * NSSTrustDomain_LoadModule
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_LoadModule
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *moduleOpt,
+  NSSUTF8 *uriOpt,
+  NSSUTF8 *opaqueOpt,
+  void *reserved
+);
+
+/*
+ * NSSTrustDomain_AddModule
+ * NSSTrustDomain_AddSlot
+ * NSSTrustDomain_UnloadModule
+ * Managing modules, slots, tokens; priorities;
+ * Traversing all of the above
+ * this needs more work
+ */
+
+/*
+ * NSSTrustDomain_DisableToken
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_DisableToken
+(
+  NSSTrustDomain *td,
+  NSSToken *token,
+  NSSError why
+);
+
+/*
+ * NSSTrustDomain_EnableToken
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_EnableToken
+(
+  NSSTrustDomain *td,
+  NSSToken *token
+);
+
+/*
+ * NSSTrustDomain_IsTokenEnabled
+ *
+ * If disabled, "why" is always on the error stack.
+ * The optional argument is just for convenience.
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_IsTokenEnabled
+(
+  NSSTrustDomain *td,
+  NSSToken *token,
+  NSSError *whyOpt
+);
+
+/*
+ * NSSTrustDomain_FindSlotByName
+ *
+ */
+
+NSS_EXTERN NSSSlot *
+NSSTrustDomain_FindSlotByName
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *slotName
+);
+
+/*
+ * NSSTrustDomain_FindTokenByName
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindTokenByName
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *tokenName
+);
+
+/*
+ * NSSTrustDomain_FindTokenBySlotName
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindTokenBySlotName
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *slotName
+);
+
+/*
+ * NSSTrustDomain_FindBestTokenForAlgorithm
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindTokenForAlgorithm
+(
+  NSSTrustDomain *td,
+  NSSOID *algorithm
+);
+
+/*
+ * NSSTrustDomain_FindBestTokenForAlgorithms
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindBestTokenForAlgorithms
+(
+  NSSTrustDomain *td,
+  NSSOID *algorithms[], /* may be null-terminated */
+  PRUint32 nAlgorithmsOpt /* limits the array if nonzero */
+);
+
+/*
+ * NSSTrustDomain_Login
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_Login
+(
+  NSSTrustDomain *td,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSTrustDomain_Logout
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_Logout
+(
+  NSSTrustDomain *td
+);
+
+/* Importing things */
+
+/*
+ * NSSTrustDomain_ImportCertificate
+ *
+ * The implementation will pull some data out of the certificate
+ * (e.g. e-mail address) for use in pkcs#11 object attributes.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_ImportCertificate
+(
+  NSSTrustDomain *td,
+  NSSCertificate *c
+);
+
+/*
+ * NSSTrustDomain_ImportPKIXCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_ImportPKIXCertificate
+(
+  NSSTrustDomain *td,
+  /* declared as a struct until these "data types" are defined */
+  struct NSSPKIXCertificateStr *pc
+);
+
+/*
+ * NSSTrustDomain_ImportEncodedCertificate
+ *
+ * Imports any type of certificate we support.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_ImportEncodedCertificate
+(
+  NSSTrustDomain *td,
+  NSSBER *ber
+);
+
+/*
+ * NSSTrustDomain_ImportEncodedCertificateChain
+ *
+ * If you just want the leaf, pass in a maximum of one.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_ImportEncodedCertificateChain
+(
+  NSSTrustDomain *td,
+  NSSBER *ber,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSTrustDomain_ImportEncodedPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSTrustDomain_ImportEncodedPrivateKey
+(
+  NSSTrustDomain *td,
+  NSSBER *ber,
+  NSSItem *passwordOpt, /* NULL will cause a callback */
+  NSSCallback *uhhOpt,
+  NSSToken *destination
+);
+
+/*
+ * NSSTrustDomain_ImportEncodedPublicKey
+ *
+ */
+
+NSS_EXTERN NSSPublicKey *
+NSSTrustDomain_ImportEncodedPublicKey
+(
+  NSSTrustDomain *td,
+  NSSBER *ber
+);
+
+/* Other importations: S/MIME capabilities */
+
+/*
+ * NSSTrustDomain_FindBestCertificateByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNickname
+(
+  NSSTrustDomain *td,
+  const NSSUTF8 *name,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/*
+ * NSSTrustDomain_FindCertificatesByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesByNickname
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *name,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSTrustDomain_FindCertificateByIssuerAndSerialNumber
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByIssuerAndSerialNumber
+(
+  NSSTrustDomain *td,
+  NSSDER *issuer,
+  NSSDER *serialNumber
+);
+
+/*
+ * NSSTrustDomain_FindCertificatesByIssuerAndSerialNumber
+ *
+ * Theoretically, this should never happen.  However, some companies
+ * we know have issued duplicate certificates with the same issuer
+ * and serial number.  Do we just ignore them?  I'm thinking yes.
+ */
+
+/*
+ * NSSTrustDomain_FindBestCertificateBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestCertificateBySubject
+(
+  NSSTrustDomain *td,
+  NSSDER /*NSSUTF8*/ *subject,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSTrustDomain_FindCertificatesBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesBySubject
+(
+  NSSTrustDomain *td,
+  NSSDER /*NSSUTF8*/ *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSTrustDomain_FindBestCertificateByNameComponents
+ *
+ * This call does try several tricks, including a pseudo pkcs#11 
+ * attribute for the ldap module to try as a query.  Eventually
+ * this call falls back to a traversal if that's what's required.
+ * It will search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNameComponents
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *nameComponents,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSTrustDomain_FindCertificatesByNameComponents
+ *
+ * This call, too, tries several tricks.  It will stop on the first
+ * attempt that generates results, so it won't e.g. traverse the
+ * entire ldap database.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesByNameComponents
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *nameComponents,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSTrustDomain_FindCertificateByEncodedCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByEncodedCertificate
+(
+  NSSTrustDomain *td,
+  NSSBER *encodedCertificate
+);
+
+/*
+ * NSSTrustDomain_FindBestCertificateByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByEmail
+(
+  NSSTrustDomain *td,
+  NSSASCII7 *email,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSTrustDomain_FindCertificatesByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesByEmail
+(
+  NSSTrustDomain *td,
+  NSSASCII7 *email,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSTrustDomain_FindCertificateByOCSPHash
+ *
+ * There can be only one.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByOCSPHash
+(
+  NSSTrustDomain *td,
+  NSSItem *hash
+);
+
+/*
+ * NSSTrustDomain_TraverseCertificates
+ *
+ * This function descends from one in older versions of NSS which
+ * traverses the certs in the permanent database.  That function
+ * was used to implement selection routines, but was directly
+ * available too.  Trust domains are going to contain a lot more
+ * certs now (e.g., an ldap server), so we'd really like to
+ * discourage traversal.  Thus for now, this is commented out.
+ * If it's needed, let's look at the situation more closely to
+ * find out what the actual requirements are.
+ */
+ 
+/* For now, adding this function.  This may only be for debugging
+ * purposes.
+ * Perhaps some equivalent function, on a specified token, will be
+ * needed in a "friend" header file?
+ */
+NSS_EXTERN PRStatus *
+NSSTrustDomain_TraverseCertificates
+(
+  NSSTrustDomain *td,
+  PRStatus (*callback)(NSSCertificate *c, void *arg),
+  void *arg
+);
+
+/*
+ * NSSTrustDomain_FindBestUserCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestUserCertificate
+(
+  NSSTrustDomain *td,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSTrustDomain_FindUserCertificates
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindUserCertificates
+(
+  NSSTrustDomain *td,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSTrustDomain_FindBestUserCertificateForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForSSLClientAuth
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSTrustDomain_FindUserCertificatesForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForSSLClientAuth
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSTrustDomain_FindBestUserCertificateForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForEmailSigning
+(
+  NSSTrustDomain *td,
+  NSSASCII7 *signerOpt,
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSTrustDomain_FindUserCertificatesForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForEmailSigning
+(
+  NSSTrustDomain *td,
+  NSSASCII7 *signerOpt,
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+);
+
+/*
+ * Here is where we'd add more Find[Best]UserCertificate[s]For<usage>
+ * routines.
+ */
+
+/* Private Keys */
+
+/*
+ * NSSTrustDomain_GenerateKeyPair
+ *
+ * Creates persistant objects.  If you want session objects, use
+ * NSSCryptoContext_GenerateKeyPair.  The destination token is where
+ * the keys are stored.  If that token can do the required math, then
+ * that's where the keys are generated too.  Otherwise, the keys are
+ * generated elsewhere and moved to that token.
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_GenerateKeyPair
+(
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap,
+  NSSPrivateKey **pvkOpt,
+  NSSPublicKey **pbkOpt,
+  PRBool privateKeyIsSensitive,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSTrustDomain_TraversePrivateKeys
+ *
+ * 
+ * NSS_EXTERN PRStatus *
+ * NSSTrustDomain_TraversePrivateKeys
+ * (
+ *   NSSTrustDomain *td,
+ *   PRStatus (*callback)(NSSPrivateKey *vk, void *arg),
+ *   void *arg
+ * );
+ */
+
+/* Symmetric Keys */
+
+/*
+ * NSSTrustDomain_GenerateSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKey
+(
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap,
+  PRUint32 keysize,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSTrustDomain_GenerateSymmetricKeyFromPassword
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKeyFromPassword
+(
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap,
+  NSSUTF8 *passwordOpt, /* if null, prompt */
+  NSSToken *destinationOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSTrustDomain_FindSymmetricKeyByAlgorithm
+ *
+ * Is this still needed?
+ * 
+ * NSS_EXTERN NSSSymmetricKey *
+ * NSSTrustDomain_FindSymmetricKeyByAlgorithm
+ * (
+ *   NSSTrustDomain *td,
+ *   NSSOID *algorithm,
+ *   NSSCallback *uhhOpt
+ * );
+ */
+
+/*
+ * NSSTrustDomain_FindSymmetricKeyByAlgorithmAndKeyID
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSTrustDomain_FindSymmetricKeyByAlgorithmAndKeyID
+(
+  NSSTrustDomain *td,
+  NSSOID *algorithm,
+  NSSItem *keyID,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSTrustDomain_TraverseSymmetricKeys
+ *
+ * 
+ * NSS_EXTERN PRStatus *
+ * NSSTrustDomain_TraverseSymmetricKeys
+ * (
+ *   NSSTrustDomain *td,
+ *   PRStatus (*callback)(NSSSymmetricKey *mk, void *arg),
+ *   void *arg
+ * );
+ */
+
+/*
+ * NSSTrustDomain_CreateCryptoContext
+ *
+ * If a callback object is specified, it becomes the for the crypto
+ * context; otherwise, this trust domain's default (if any) is
+ * inherited.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContext
+(
+  NSSTrustDomain *td,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSTrustDomain_CreateCryptoContextForAlgorithm
+ *
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithm
+(
+  NSSTrustDomain *td,
+  NSSOID *algorithm
+);
+
+/*
+ * NSSTrustDomain_CreateCryptoContextForAlgorithmAndParameters
+ *
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithmAndParameters
+(
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap
+);
+
+/* find/traverse other objects, e.g. s/mime profiles */
+
+/*
+ * NSSCryptoContext
+ *
+ * A crypto context is sort of a short-term snapshot of a trust domain,
+ * used for the life of "one crypto operation."  You can also think of
+ * it as a "temporary database."
+ * 
+ * Just about all of the things you can do with a trust domain -- importing
+ * or creating certs, keys, etc. -- can be done with a crypto context.
+ * The difference is that the objects will be temporary ("session") objects.
+ * 
+ * Also, if the context was created for a key, cert, and/or algorithm; or
+ * if such objects have been "associated" with the context, then the context
+ * can do everything the keys can, like crypto operations.
+ * 
+ * And finally, because it keeps the state of the crypto operations, it
+ * can do streaming crypto ops.
+ */
+
+/*
+ * NSSTrustDomain_Destroy
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_Destroy
+(
+  NSSCryptoContext *cc
+);
+
+/* establishing a default callback */
+
+/*
+ * NSSCryptoContext_SetDefaultCallback
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_SetDefaultCallback
+(
+  NSSCryptoContext *cc,
+  NSSCallback *newCallback,
+  NSSCallback **oldCallbackOpt
+);
+
+/*
+ * NSSCryptoContext_GetDefaultCallback
+ *
+ */
+
+NSS_EXTERN NSSCallback *
+NSSCryptoContext_GetDefaultCallback
+(
+  NSSCryptoContext *cc,
+  PRStatus *statusOpt
+);
+
+/*
+ * NSSCryptoContext_GetTrustDomain
+ *
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSCryptoContext_GetTrustDomain
+(
+  NSSCryptoContext *cc
+);
+
+/* AddModule, etc: should we allow "temporary" changes here? */
+/* DisableToken, etc: ditto */
+/* Ordering of tokens? */
+/* Finding slots+token etc. */
+/* login+logout */
+
+/* Importing things */
+
+/*
+ * NSSCryptoContext_FindOrImportCertificate
+ *
+ * If the certificate store already contains this DER cert, return the 
+ * address of the matching NSSCertificate that is already in the store,
+ * and bump its reference count.
+ *
+ * If this DER cert is NOT already in the store, then add the new
+ * NSSCertificate to the store and bump its reference count, 
+ * then return its address. 
+ *
+ * if this DER cert is not in the store and cannot be added to it, 
+ * return NULL;
+ *
+ * Record the associated crypto context in the certificate.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindOrImportCertificate (
+  NSSCryptoContext *cc,
+  NSSCertificate *c
+);
+
+/*
+ * NSSCryptoContext_ImportPKIXCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_ImportPKIXCertificate
+(
+  NSSCryptoContext *cc,
+  struct NSSPKIXCertificateStr *pc
+);
+
+/*
+ * NSSCryptoContext_ImportEncodedCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_ImportEncodedCertificate
+(
+  NSSCryptoContext *cc,
+  NSSBER *ber
+);
+
+/*
+ * NSSCryptoContext_ImportEncodedPKIXCertificateChain
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ImportEncodedPKIXCertificateChain
+(
+  NSSCryptoContext *cc,
+  NSSBER *ber
+);
+
+/* Other importations: S/MIME capabilities
+ */
+
+/*
+ * NSSCryptoContext_FindBestCertificateByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNickname
+(
+  NSSCryptoContext *cc,
+  const NSSUTF8 *name,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/*
+ * NSSCryptoContext_FindCertificatesByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesByNickname
+(
+  NSSCryptoContext *cc,
+  NSSUTF8 *name,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FindCertificateByIssuerAndSerialNumber
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindCertificateByIssuerAndSerialNumber
+(
+  NSSCryptoContext *cc,
+  NSSDER *issuer,
+  NSSDER *serialNumber
+);
+
+/*
+ * NSSCryptoContext_FindBestCertificateBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateBySubject
+(
+  NSSCryptoContext *cc,
+  NSSDER /*NSSUTF8*/ *subject,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSCryptoContext_FindCertificatesBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesBySubject
+(
+  NSSCryptoContext *cc,
+  NSSDER /*NSSUTF8*/ *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FindBestCertificateByNameComponents
+ *
+ * This call does try several tricks, including a pseudo pkcs#11 
+ * attribute for the ldap module to try as a query.  Eventually
+ * this call falls back to a traversal if that's what's required.
+ * It will search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNameComponents
+(
+  NSSCryptoContext *cc,
+  NSSUTF8 *nameComponents,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSCryptoContext_FindCertificatesByNameComponents
+ *
+ * This call, too, tries several tricks.  It will stop on the first
+ * attempt that generates results, so it won't e.g. traverse the
+ * entire ldap database.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesByNameComponents
+(
+  NSSCryptoContext *cc,
+  NSSUTF8 *nameComponents,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FindCertificateByEncodedCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindCertificateByEncodedCertificate
+(
+  NSSCryptoContext *cc,
+  NSSBER *encodedCertificate
+);
+
+/*
+ * NSSCryptoContext_FindBestCertificateByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateByEmail
+(
+  NSSCryptoContext *cc,
+  NSSASCII7 *email,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSCryptoContext_FindCertificatesByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesByEmail
+(
+  NSSCryptoContext *cc,
+  NSSASCII7 *email,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FindCertificateByOCSPHash
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindCertificateByOCSPHash
+(
+  NSSCryptoContext *cc,
+  NSSItem *hash
+);
+
+/*
+ * NSSCryptoContext_TraverseCertificates
+ *
+ * 
+ * NSS_EXTERN PRStatus *
+ * NSSCryptoContext_TraverseCertificates
+ * (
+ *   NSSCryptoContext *cc,
+ *   PRStatus (*callback)(NSSCertificate *c, void *arg),
+ *   void *arg
+ * );
+ */
+
+/*
+ * NSSCryptoContext_FindBestUserCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestUserCertificate
+(
+  NSSCryptoContext *cc,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSCryptoContext_FindUserCertificates
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindUserCertificates
+(
+  NSSCryptoContext *cc,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FindBestUserCertificateForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForSSLClientAuth
+(
+  NSSCryptoContext *cc,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSCryptoContext_FindUserCertificatesForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindUserCertificatesForSSLClientAuth
+(
+  NSSCryptoContext *cc,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FindBestUserCertificateForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForEmailSigning
+(
+  NSSCryptoContext *cc,
+  NSSASCII7 *signerOpt,
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+);
+
+/*
+ * NSSCryptoContext_FindUserCertificatesForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindUserCertificatesForEmailSigning
+(
+  NSSCryptoContext *cc,
+  NSSASCII7 *signerOpt, /* fgmr or a more general name? */
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+);
+
+/* Private Keys */
+
+/*
+ * NSSCryptoContext_GenerateKeyPair
+ *
+ * Creates session objects.  If you want persistant objects, use
+ * NSSTrustDomain_GenerateKeyPair.  The destination token is where
+ * the keys are stored.  If that token can do the required math, then
+ * that's where the keys are generated too.  Otherwise, the keys are
+ * generated elsewhere and moved to that token.
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_GenerateKeyPair
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *ap,
+  NSSPrivateKey **pvkOpt,
+  NSSPublicKey **pbkOpt,
+  PRBool privateKeyIsSensitive,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_TraversePrivateKeys
+ *
+ * 
+ * NSS_EXTERN PRStatus *
+ * NSSCryptoContext_TraversePrivateKeys
+ * (
+ *   NSSCryptoContext *cc,
+ *   PRStatus (*callback)(NSSPrivateKey *vk, void *arg),
+ *   void *arg
+ * );
+ */
+
+/* Symmetric Keys */
+
+/*
+ * NSSCryptoContext_GenerateSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKey
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *ap,
+  PRUint32 keysize,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_GenerateSymmetricKeyFromPassword
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKeyFromPassword
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *ap,
+  NSSUTF8 *passwordOpt, /* if null, prompt */
+  NSSToken *destinationOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_FindSymmetricKeyByAlgorithm
+ *
+ * 
+ * NSS_EXTERN NSSSymmetricKey *
+ * NSSCryptoContext_FindSymmetricKeyByType
+ * (
+ *   NSSCryptoContext *cc,
+ *   NSSOID *type,
+ *   NSSCallback *uhhOpt
+ * );
+ */
+
+/*
+ * NSSCryptoContext_FindSymmetricKeyByAlgorithmAndKeyID
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_FindSymmetricKeyByAlgorithmAndKeyID
+(
+  NSSCryptoContext *cc,
+  NSSOID *algorithm,
+  NSSItem *keyID,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_TraverseSymmetricKeys
+ *
+ * 
+ * NSS_EXTERN PRStatus *
+ * NSSCryptoContext_TraverseSymmetricKeys
+ * (
+ *   NSSCryptoContext *cc,
+ *   PRStatus (*callback)(NSSSymmetricKey *mk, void *arg),
+ *   void *arg
+ * );
+ */
+
+/* Crypto ops on distinguished keys */
+
+/*
+ * NSSCryptoContext_Decrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Decrypt
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *encryptedData,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_BeginDecrypt
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginDecrypt
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_ContinueDecrypt
+ *
+ */
+
+/*
+ * NSSItem semantics:
+ *
+ *   If rvOpt is NULL, a new NSSItem and buffer are allocated.
+ *   If rvOpt is not null, but the buffer pointer is null,
+ *     then rvOpt is returned but a new buffer is allocated.
+ *     In this case, if the length value is not zero, then
+ *     no more than that much space will be allocated.
+ *   If rvOpt is not null and the buffer pointer is not null,
+ *     then that buffer is re-used.  No more than the buffer
+ *     length value will be used; if it's not enough, an
+ *     error is returned.  If less is used, the number is
+ *     adjusted downwards.
+ *
+ *  Note that although this is short of some ideal "Item"
+ *  definition, we can usually tell how big these buffers
+ *  have to be.
+ *
+ *  Feedback is requested; and earlier is better than later.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueDecrypt
+(
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FinishDecrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishDecrypt
+(
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Sign
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_BeginSign
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginSign
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_ContinueSign
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ContinueSign
+(
+  NSSCryptoContext *cc,
+  NSSItem *data
+);
+
+/*
+ * NSSCryptoContext_FinishSign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishSign
+(
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_SignRecover
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_BeginSignRecover
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginSignRecover
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_ContinueSignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueSignRecover
+(
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FinishSignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishSignRecover
+(
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_UnwrapSymmetricKey
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_DeriveSymmetricKey
+(
+  NSSCryptoContext *cc,
+  NSSPublicKey *bk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt, /* zero for best allowed */
+  NSSOperations operations,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_Encrypt
+ *
+ * Encrypt a single chunk of data with the distinguished public key
+ * of this crypto context.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Encrypt
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_BeginEncrypt
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginEncrypt
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_ContinueEncrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueEncrypt
+(
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FinishEncrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishEncrypt
+(
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_Verify
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_BeginVerify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginVerify
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_ContinueVerify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ContinueVerify
+(
+  NSSCryptoContext *cc,
+  NSSItem *data
+);
+
+/*
+ * NSSCryptoContext_FinishVerify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_FinishVerify
+(
+  NSSCryptoContext *cc
+);
+
+/*
+ * NSSCryptoContext_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_VerifyRecover
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_BeginVerifyRecover
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginVerifyRecover
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_ContinueVerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueVerifyRecover
+(
+  NSSCryptoContext *cc,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_FinishVerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishVerifyRecover
+(
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_WrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_WrapSymmetricKey
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_Digest
+ *
+ * Digest a single chunk of data with the distinguished digest key
+ * of this crypto context.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Digest
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhhOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSCryptoContext_BeginDigest
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginDigest
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhhOpt
+);
+
+/*
+ * NSSCryptoContext_ContinueDigest
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ContinueDigest
+(
+  NSSCryptoContext *cc,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *item
+);
+
+/*
+ * NSSCryptoContext_FinishDigest
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishDigest
+(
+  NSSCryptoContext *cc,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * tbd: Combination ops
+ */
+
+/*
+ * NSSCryptoContext_Clone
+ *
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSCryptoContext_Clone
+(
+  NSSCryptoContext *cc
+);
+
+/*
+ * NSSCryptoContext_Save
+ * NSSCryptoContext_Restore
+ *
+ * We need to be able to save and restore the state of contexts.
+ * Perhaps a mark-and-release mechanism would be better?
+ */
+
+/*
+ * ..._SignTBSCertificate
+ *
+ * This requires feedback from the cert server team.
+ */
+
+/*
+ * PRBool NSSCertificate_GetIsTrustedFor{xxx}(NSSCertificate *c);
+ * PRStatus NSSCertificate_SetIsTrustedFor{xxx}(NSSCertificate *c, PRBool trusted);
+ *
+ * These will be helper functions which get the trust object for a cert,
+ * and then call the corresponding function(s) on it.
+ *
+ * PKIX trust objects will have methods to manipulate the low-level trust
+ * bits (which are based on key usage and extended key usage), and also the
+ * conceptual high-level usages (e.g. ssl client auth, email encryption, etc.)
+ *
+ * Other types of trust objects (if any) might have different low-level
+ * representations, but hopefully high-level concepts would map.
+ *
+ * Only these high-level general routines would be promoted to the
+ * general certificate level here.  Hence the {xxx} above would be things
+ * like "EmailSigning."
+ *
+ *
+ * NSSPKIXTrust *NSSCertificate_GetPKIXTrustObject(NSSCertificate *c);
+ * PRStatus NSSCertificate_SetPKIXTrustObject(NSSCertificate *c, NSPKIXTrust *t);
+ *
+ * I want to hold off on any general trust object until we've investigated
+ * other models more thoroughly.
+ */
+
+PR_END_EXTERN_C
+
+#endif /* NSSPKI_H */
diff --git a/mozilla/security/nss/lib/pki/nsspkit.h b/mozilla/security/nss/lib/pki/nsspkit.h
new file mode 100644
index 0000000..0d42c35
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/nsspkit.h
@@ -0,0 +1,274 @@
+/* ***** 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 ***** */
+
+#ifndef NSSPKIT_H
+#define NSSPKIT_H
+
+#ifdef DEBUG
+static const char NSSPKIT_CVS_ID[] = "@(#) $RCSfile: nsspkit.h,v $ $Revision: 1.6 $ $Date: 2005/01/20 02:25:49 $";
+#endif /* DEBUG */
+
+/*
+ * nsspkit.h
+ *
+ * This file defines the types of the top-level PKI objects.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSCertificate
+ *
+ * This is the public representation of a Certificate.  The certificate
+ * may be one found on a smartcard or other token, one decoded from data
+ * received as part of a protocol, one constructed from constituent
+ * parts, etc.  Usually it is associated with ("in") a trust domain; as
+ * it can be verified only within a trust domain.  The underlying type
+ * of certificate may be of any supported standard, e.g. PKIX, PGP, etc.
+ *
+ * People speak of "verifying (with) the server's, or correspondant's, 
+ * certificate"; for simple operations we support that simplification
+ * by implementing public-key crypto operations as methods on this type.
+ */
+
+struct NSSCertificateStr;
+typedef struct NSSCertificateStr NSSCertificate;
+
+/*
+ * NSSUserCertificate
+ *
+ * A ``User'' certificate is one for which the private key is available.
+ * People speak of "using my certificate to sign my email" and "using
+ * my certificate to authenticate to (or login to) the server"; for
+ * simple operations, we support that simplification by implementing
+ * private-key crypto operations as methods on this type.
+ *
+ * The current design only weakly distinguishes between certificates
+ * and user certificates: as far as the compiler goes they're 
+ * interchangable; debug libraries only have one common pointer-tracker;
+ * etc.  However, attempts to do private-key operations on a certificate
+ * for which the private key is not available will fail.
+ *
+ * Open design question: should these types be more firmly separated?
+ */
+
+typedef NSSCertificate NSSUserCertificate;
+
+/*
+ * NSSPrivateKey
+ *
+ * This is the public representation of a Private Key.  In general,
+ * the actual value of the key is not available, but operations may
+ * be performed with it.
+ */
+
+struct NSSPrivateKeyStr;
+typedef struct NSSPrivateKeyStr NSSPrivateKey;
+
+/*
+ * NSSPublicKey
+ *
+ */
+
+struct NSSPublicKeyStr;
+typedef struct NSSPublicKeyStr NSSPublicKey;
+
+/*
+ * NSSSymmetricKey
+ *
+ */
+
+struct NSSSymmetricKeyStr;
+typedef struct NSSSymmetricKeyStr NSSSymmetricKey;
+
+/*
+ * NSSTrustDomain
+ *
+ * A Trust Domain is the field in which certificates may be validated.
+ * A trust domain will generally have one or more cryptographic modules
+ * open; these modules perform the cryptographic operations, and 
+ * provide the basic "root" trust information from which the trust in
+ * a specific certificate or key depends.
+ *
+ * A client program, or a simple server, would typically have one
+ * trust domain.  A server supporting multiple "virtual servers" might
+ * have a separate trust domain for each virtual server.  The separate
+ * trust domains might share some modules (e.g., a hardware crypto
+ * accelerator) but not others (e.g., the tokens storing the different
+ * servers' private keys, or the databases with each server's trusted
+ * root certificates).
+ *
+ * This object descends from the "permananet database" in the old code.
+ */
+
+struct NSSTrustDomainStr;
+typedef struct NSSTrustDomainStr NSSTrustDomain;
+
+/*
+ * NSSCryptoContext
+ *
+ * A Crypto Context is a short-term, "helper" object which is used
+ * for the lifetime of one ongoing "crypto operation."  Such an
+ * operation may be the creation of a signed message, the use of an
+ * TLS socket connection, etc.  Each crypto context is "in" a
+ * specific trust domain, and it may have associated with it a
+ * distinguished certificate, public key, private key, and/or
+ * symmetric key.  It can also temporarily hold and use temporary
+ * data (e.g. intermediate certificates) which is not stored
+ * permanently in the trust domain.
+ *
+ * In OO terms, this interface inherits interfaces from the trust
+ * domain, the certificates, and the keys.  It also provides
+ * streaming crypto operations.
+ *
+ * This object descends from the "temporary database" concept in the
+ * old code, but it has changed a lot as a result of what we've 
+ * learned.
+ */
+
+typedef struct NSSCryptoContextStr NSSCryptoContext;
+
+/*
+ * fgmr others
+ */
+
+/* 
+ * NSSTime
+ *
+ * Unfortunately, we need an "exceptional" value to indicate
+ * an error upon return, or "no value" on input.  Note that zero
+ * is a perfectly valid value for both time_t and PRTime.
+ *
+ * If we were to create a "range" object, with two times for
+ * Not Before and Not After, we would have an obvious place for
+ * the somewhat arbitrary logic involved in comparing them.
+ *
+ * Failing that, let's have an NSSTime_CompareRanges function.
+ */
+
+struct NSSTimeStr;
+typedef struct NSSTimeStr NSSTime;
+
+struct NSSTrustStr;
+typedef struct NSSTrustStr NSSTrust;
+
+/*
+ * NSSUsage
+ *
+ * This is trickier than originally planned; I'll write up a
+ * doc on it.
+ *
+ * We'd still like nsspki.h to have a list of common usages,
+ * e.g.:
+ *
+ *  extern const NSSUsage *NSSUsage_ClientAuth;
+ *  extern const NSSUsage *NSSUsage_ServerAuth;
+ *  extern const NSSUsage *NSSUsage_SignEmail;
+ *  extern const NSSUsage *NSSUsage_EncryptEmail;
+ *  etc.
+ */
+
+struct NSSUsageStr;
+typedef struct NSSUsageStr NSSUsage;
+
+/*
+ * NSSPolicies
+ *
+ * Placeholder, for now.
+ */
+
+struct NSSPoliciesStr;
+typedef struct NSSPoliciesStr NSSPolicies;
+
+/*
+ * NSSAlgorithmAndParameters
+ *
+ * Algorithm is an OID
+ * Parameters depend on the algorithm
+ */
+
+struct NSSAlgorithmAndParametersStr;
+typedef struct NSSAlgorithmAndParametersStr NSSAlgorithmAndParameters;
+
+/*
+ * NSSCallback
+ *
+ * At minimum, a "challenge" method and a closure argument.
+ * Usually the challenge will just be prompting for a password.
+ * How OO do we want to make it?
+ */
+
+typedef struct NSSCallbackStr NSSCallback;
+
+struct NSSCallbackStr {
+    /* Prompt for a password to initialize a slot.  */
+    PRStatus (* getInitPW)(NSSUTF8 *slotName, void *arg, 
+                           NSSUTF8 **ssoPW, NSSUTF8 **userPW); 
+    /* Prompt for oldPW and newPW in order to change the 
+     * password on a slot.  
+     */
+    PRStatus (* getNewPW)(NSSUTF8 *slotName, PRUint32 *retries, void *arg,
+                          NSSUTF8 **oldPW, NSSUTF8 **newPW); 
+    /* Prompt for slot password.  */
+    PRStatus (* getPW)(NSSUTF8 *slotName, PRUint32 *retries, void *arg,
+                       NSSUTF8 **password); 
+    void *arg;
+};
+
+/* set errors - user cancelled, ... */
+
+typedef PRUint32 NSSOperations;
+/* 1) Do we want these to be preprocessor definitions or constants? */
+/* 2) What is the correct and complete list? */
+
+#define NSSOperations_ENCRYPT           0x0001
+#define NSSOperations_DECRYPT           0x0002
+#define NSSOperations_WRAP              0x0004
+#define NSSOperations_UNWRAP            0x0008
+#define NSSOperations_SIGN              0x0010
+#define NSSOperations_SIGN_RECOVER      0x0020
+#define NSSOperations_VERIFY            0x0040
+#define NSSOperations_VERIFY_RECOVER    0x0080
+
+struct NSSPKIXCertificateStr;
+
+PR_END_EXTERN_C
+
+#endif /* NSSPKIT_H */
diff --git a/mozilla/security/nss/lib/pki/pki.h b/mozilla/security/nss/lib/pki/pki.h
new file mode 100644
index 0000000..0ae5de9
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pki.h
@@ -0,0 +1,248 @@
+/* ***** 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 ***** */
+
+#ifndef PKI_H
+#define PKI_H
+
+#ifdef DEBUG
+static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.13 $ $Date: 2005/01/20 02:25:49 $";
+#endif /* DEBUG */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+PR_BEGIN_EXTERN_C
+
+NSS_EXTERN NSSCallback *
+nssTrustDomain_GetDefaultCallback
+(
+  NSSTrustDomain *td,
+  PRStatus *statusOpt
+);
+
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_FindCertificatesBySubject
+(
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSTrust *
+nssTrustDomain_FindTrustForCertificate
+(
+  NSSTrustDomain *td,
+  NSSCertificate *c
+);
+
+NSS_EXTERN NSSCertificate *
+nssCertificate_AddRef
+(
+  NSSCertificate *c
+);
+
+NSS_EXTERN PRStatus
+nssCertificate_Destroy
+(
+  NSSCertificate *c
+);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetEncoding
+(
+  NSSCertificate *c
+);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetIssuer
+(
+  NSSCertificate *c
+);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetSerialNumber
+(
+  NSSCertificate *c
+);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetSubject
+(
+  NSSCertificate *c
+);
+
+NSS_EXTERN NSSUTF8 *
+nssCertificate_GetNickname
+(
+  NSSCertificate *c,
+  NSSToken *tokenOpt
+);
+
+NSS_EXTERN NSSASCII7 *
+nssCertificate_GetEmailAddress
+(
+  NSSCertificate *c
+);
+
+NSS_EXTERN PRBool
+nssCertificate_IssuerAndSerialEqual
+(
+  NSSCertificate *c1,
+  NSSCertificate *c2
+);
+
+NSS_EXTERN NSSPrivateKey *
+nssPrivateKey_AddRef
+(
+  NSSPrivateKey *vk
+);
+
+NSS_EXTERN PRStatus
+nssPrivateKey_Destroy
+(
+  NSSPrivateKey *vk
+);
+
+NSS_EXTERN NSSItem *
+nssPrivateKey_GetID
+(
+  NSSPrivateKey *vk
+);
+
+NSS_EXTERN NSSUTF8 *
+nssPrivateKey_GetNickname
+(
+  NSSPrivateKey *vk,
+  NSSToken *tokenOpt
+);
+
+NSS_EXTERN PRStatus
+nssPublicKey_Destroy
+(
+  NSSPublicKey *bk
+);
+
+NSS_EXTERN NSSItem *
+nssPublicKey_GetID
+(
+  NSSPublicKey *vk
+);
+
+NSS_EXTERN NSSCertificate **
+nssCryptoContext_FindCertificatesBySubject
+(
+  NSSCryptoContext *cc,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/* putting here for now, needs more thought */
+NSS_EXTERN PRStatus
+nssCryptoContext_ImportTrust
+(
+  NSSCryptoContext *cc,
+  NSSTrust *trust
+);
+
+NSS_EXTERN NSSTrust *
+nssCryptoContext_FindTrustForCertificate
+(
+  NSSCryptoContext *cc,
+  NSSCertificate *cert
+);
+
+NSS_EXTERN PRStatus
+nssCryptoContext_ImportSMIMEProfile
+(
+  NSSCryptoContext *cc,
+  nssSMIMEProfile *profile
+);
+
+NSS_EXTERN nssSMIMEProfile *
+nssCryptoContext_FindSMIMEProfileForCertificate
+(
+  NSSCryptoContext *cc,
+  NSSCertificate *cert
+);
+
+NSS_EXTERN NSSTrust *
+nssTrust_AddRef
+(
+  NSSTrust *trust
+);
+
+NSS_EXTERN PRStatus
+nssTrust_Destroy
+(
+  NSSTrust *trust
+);
+
+NSS_EXTERN nssSMIMEProfile *
+nssSMIMEProfile_AddRef
+(
+  nssSMIMEProfile *profile
+);
+
+NSS_EXTERN PRStatus
+nssSMIMEProfile_Destroy
+(
+  nssSMIMEProfile *profile
+);
+
+NSS_EXTERN nssSMIMEProfile *
+nssSMIMEProfile_Create
+(
+  NSSCertificate *cert,
+  NSSItem *profileTime,
+  NSSItem *profileData
+);
+
+PR_END_EXTERN_C
+
+#endif /* PKI_H */
diff --git a/mozilla/security/nss/lib/pki/pki3hack.c b/mozilla/security/nss/lib/pki/pki3hack.c
new file mode 100644
index 0000000..d5c8dcc
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pki3hack.c
@@ -0,0 +1,1299 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.98 $ $Date: 2009/10/01 17:14:02 $";
+#endif /* DEBUG */
+
+/*
+ * Hacks to integrate NSS 3.4 and NSS 4.0 certificates.
+ */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef PKI_H
+#include "pki.h"
+#endif /* PKI_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef DEVNSS3HACK_H
+#include "dev3hack.h"
+#endif /* DEVNSS3HACK_H */
+
+#ifndef PKINSS3HACK_H
+#include "pki3hack.h"
+#endif /* PKINSS3HACK_H */
+
+#include "secitem.h"
+#include "certdb.h"
+#include "certt.h"
+#include "cert.h"
+#include "certi.h"
+#include "pk11func.h"
+#include "pkistore.h"
+#include "secmod.h"
+#include "nssrwlk.h"
+
+NSSTrustDomain *g_default_trust_domain = NULL;
+
+NSSCryptoContext *g_default_crypto_context = NULL;
+
+NSSTrustDomain *
+STAN_GetDefaultTrustDomain()
+{
+    return g_default_trust_domain;
+}
+
+NSSCryptoContext *
+STAN_GetDefaultCryptoContext()
+{
+    return g_default_crypto_context;
+}
+
+extern const NSSError NSS_ERROR_ALREADY_INITIALIZED;
+extern const NSSError NSS_ERROR_INTERNAL_ERROR;
+
+NSS_IMPLEMENT PRStatus
+STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot)
+{
+    NSSToken *token;
+    if (!td) {
+	td = g_default_trust_domain;
+	if (!td) {
+	    /* we're called while still initting. slot will get added
+	     * appropriately through normal init processes */
+	    return PR_SUCCESS;
+	}
+    }
+    token = nssToken_CreateFromPK11SlotInfo(td, slot);
+    PK11Slot_SetNSSToken(slot, token);
+    /* Don't add non-existent token to TD's token list */
+    if (token) {
+	NSSRWLock_LockWrite(td->tokensLock);
+	nssList_Add(td->tokenList, token);
+	NSSRWLock_UnlockWrite(td->tokensLock);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+STAN_ResetTokenInterator(NSSTrustDomain *td)
+{
+    if (!td) {
+	td = g_default_trust_domain;
+	if (!td) {
+	    /* we're called while still initting. slot will get added
+	     * appropriately through normal init processes */
+	    return PR_SUCCESS;
+	}
+    }
+    NSSRWLock_LockWrite(td->tokensLock);
+    nssListIterator_Destroy(td->tokens);
+    td->tokens = nssList_CreateIterator(td->tokenList);
+    NSSRWLock_UnlockWrite(td->tokensLock);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+STAN_LoadDefaultNSS3TrustDomain (
+  void
+)
+{
+    NSSTrustDomain *td;
+    SECMODModuleList *mlp;
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+    int i;
+
+    if (g_default_trust_domain || g_default_crypto_context) {
+	/* Stan is already initialized or a previous shutdown failed. */
+	nss_SetError(NSS_ERROR_ALREADY_INITIALIZED);
+	return PR_FAILURE;
+    }
+    td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL);
+    if (!td) {
+	return PR_FAILURE;
+    }
+    /*
+     * Deadlock warning: we should never acquire the moduleLock while
+     * we hold the tokensLock. We can use the NSSRWLock Rank feature to
+     * guarrentee this. tokensLock have a higher rank than module lock.
+     */
+    td->tokenList = nssList_Create(td->arena, PR_TRUE);
+    if (!td->tokenList) {
+	goto loser;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    NSSRWLock_LockWrite(td->tokensLock);
+    for (mlp = SECMOD_GetDefaultModuleList(); mlp != NULL; mlp=mlp->next) {
+	for (i=0; i < mlp->module->slotCount; i++) {
+	    STAN_InitTokenForSlotInfo(td, mlp->module->slots[i]);
+	}
+    }
+    td->tokens = nssList_CreateIterator(td->tokenList);
+    NSSRWLock_UnlockWrite(td->tokensLock);
+    SECMOD_ReleaseReadLock(moduleLock);
+    if (!td->tokens) {
+	goto loser;
+    }
+    g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL);
+    if (!g_default_crypto_context) {
+	goto loser;
+    }
+    g_default_trust_domain = td;
+    return PR_SUCCESS;
+
+  loser:
+    NSSTrustDomain_Destroy(td);
+    return PR_FAILURE;
+}
+
+/*
+ * must be called holding the ModuleListLock (either read or write).
+ */
+NSS_IMPLEMENT SECStatus
+STAN_AddModuleToDefaultTrustDomain (
+  SECMODModule *module
+)
+{
+    NSSTrustDomain *td;
+    int i;
+    td = STAN_GetDefaultTrustDomain();
+    for (i=0; i<module->slotCount; i++) {
+	STAN_InitTokenForSlotInfo(td, module->slots[i]);
+    }
+    STAN_ResetTokenInterator(td);
+    return SECSuccess;
+}
+
+/*
+ * must be called holding the ModuleListLock (either read or write).
+ */
+NSS_IMPLEMENT SECStatus
+STAN_RemoveModuleFromDefaultTrustDomain (
+  SECMODModule *module
+)
+{
+    NSSToken *token;
+    NSSTrustDomain *td;
+    int i;
+    td = STAN_GetDefaultTrustDomain();
+    NSSRWLock_LockWrite(td->tokensLock);
+    for (i=0; i<module->slotCount; i++) {
+	token = PK11Slot_GetNSSToken(module->slots[i]);
+	if (token) {
+	    nssToken_NotifyCertsNotVisible(token);
+	    nssList_Remove(td->tokenList, token);
+	    PK11Slot_SetNSSToken(module->slots[i], NULL);
+	    nssToken_Destroy(token);
+ 	}
+    }
+    nssListIterator_Destroy(td->tokens);
+    td->tokens = nssList_CreateIterator(td->tokenList);
+    NSSRWLock_UnlockWrite(td->tokensLock);
+    return SECSuccess;
+}
+
+NSS_IMPLEMENT PRStatus
+STAN_Shutdown()
+{
+    PRStatus status = PR_SUCCESS;
+    if (g_default_trust_domain) {
+	if (NSSTrustDomain_Destroy(g_default_trust_domain) == PR_SUCCESS) {
+	    g_default_trust_domain = NULL;
+	} else {
+	    status = PR_FAILURE;
+	}
+    }
+    if (g_default_crypto_context) {
+	if (NSSCryptoContext_Destroy(g_default_crypto_context) == PR_SUCCESS) {
+	    g_default_crypto_context = NULL;
+	} else {
+	    status = PR_FAILURE;
+	}
+    }
+    return status;
+}
+
+/* this function should not be a hack; it will be needed in 4.0 (rename) */
+NSS_IMPLEMENT NSSItem *
+STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der)
+{
+    NSSItem *rvKey;
+    SECItem secDER;
+    SECItem secKey = { 0 };
+    SECStatus secrv;
+    PRArenaPool *arena;
+
+    SECITEM_FROM_NSSITEM(&secDER, der);
+
+    /* nss3 call uses nss3 arena's */
+    arena = PORT_NewArena(256);
+    if (!arena) {
+	return NULL;
+    }
+    secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey);
+    if (secrv != SECSuccess) {
+	return NULL;
+    }
+    rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data);
+    PORT_FreeArena(arena,PR_FALSE);
+    return rvKey;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der, NSSArena *arena, 
+                                     NSSDER *issuer, NSSDER *serial)
+{
+    SECStatus secrv;
+    SECItem derCert;
+    SECItem derIssuer = { 0 };
+    SECItem derSerial = { 0 };
+    SECITEM_FROM_NSSITEM(&derCert, der);
+    secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
+    if (secrv != SECSuccess) {
+	return PR_FAILURE;
+    }
+    (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data);
+    secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
+    if (secrv != SECSuccess) {
+	PORT_Free(derSerial.data);
+	return PR_FAILURE;
+    }
+    (void)nssItem_Create(arena, issuer, derIssuer.len, derIssuer.data);
+    PORT_Free(derSerial.data);
+    PORT_Free(derIssuer.data);
+    return PR_SUCCESS;
+}
+
+static NSSItem *
+nss3certificate_getIdentifier(nssDecodedCert *dc)
+{
+    NSSItem *rvID;
+    CERTCertificate *c = (CERTCertificate *)dc->data;
+    rvID = nssItem_Create(NULL, NULL, c->certKey.len, c->certKey.data);
+    return rvID;
+}
+
+static void *
+nss3certificate_getIssuerIdentifier(nssDecodedCert *dc)
+{
+    CERTCertificate *c = (CERTCertificate *)dc->data;
+    return (void *)c->authKeyID;
+}
+
+static nssCertIDMatch
+nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id)
+{
+    CERTCertificate *c = (CERTCertificate *)dc->data;
+    CERTAuthKeyID *authKeyID = (CERTAuthKeyID *)id;
+    SECItem skid;
+    nssCertIDMatch match = nssCertIDMatch_Unknown;
+
+    /* keyIdentifier */
+    if (authKeyID->keyID.len > 0 &&
+	CERT_FindSubjectKeyIDExtension(c, &skid) == SECSuccess) {
+	PRBool skiEqual;
+	skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid);
+	PORT_Free(skid.data);
+	if (skiEqual) {
+	    /* change the state to positive match, but keep going */
+	    match = nssCertIDMatch_Yes;
+	} else {
+	    /* exit immediately on failure */
+	    return nssCertIDMatch_No;
+	}
+    }
+
+    /* issuer/serial (treated as pair) */
+    if (authKeyID->authCertIssuer) {
+	SECItem *caName = NULL;
+	SECItem *caSN = &authKeyID->authCertSerialNumber;
+
+	caName = (SECItem *)CERT_GetGeneralNameByType(
+	                                        authKeyID->authCertIssuer,
+						certDirectoryName, PR_TRUE);
+	if (caName != NULL &&
+	    SECITEM_ItemsAreEqual(&c->derIssuer, caName) &&
+	    SECITEM_ItemsAreEqual(&c->serialNumber, caSN)) 
+	{
+	    match = nssCertIDMatch_Yes;
+	} else {
+	    match = nssCertIDMatch_Unknown;
+	}
+    }
+    return match;
+}
+
+static PRBool
+nss3certificate_isValidIssuer(nssDecodedCert *dc)
+{
+    CERTCertificate *c = (CERTCertificate *)dc->data;
+    unsigned int ignore;
+    return CERT_IsCACert(c, &ignore);
+}
+
+static NSSUsage *
+nss3certificate_getUsage(nssDecodedCert *dc)
+{
+    /* CERTCertificate *c = (CERTCertificate *)dc->data; */
+    return NULL;
+}
+
+static PRBool 
+nss3certificate_isValidAtTime(nssDecodedCert *dc, NSSTime *time)
+{
+    SECCertTimeValidity validity;
+    CERTCertificate *c = (CERTCertificate *)dc->data;
+    validity = CERT_CheckCertValidTimes(c, NSSTime_GetPRTime(time), PR_TRUE);
+    if (validity == secCertTimeValid) {
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+static PRBool 
+nss3certificate_isNewerThan(nssDecodedCert *dc, nssDecodedCert *cmpdc)
+{
+    /* I know this isn't right, but this is glue code anyway */
+    if (cmpdc->type == dc->type) {
+	CERTCertificate *certa = (CERTCertificate *)dc->data;
+	CERTCertificate *certb = (CERTCertificate *)cmpdc->data;
+	return CERT_IsNewer(certa, certb);
+    }
+    return PR_FALSE;
+}
+
+/* CERT_FilterCertListByUsage */
+static PRBool
+nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage)
+{
+    CERTCertificate *cc;
+    unsigned int requiredKeyUsage = 0;
+    unsigned int requiredCertType = 0;
+    SECStatus secrv;
+    PRBool match;
+    PRBool ca;
+
+    /* This is for NSS 3.3 functions that do not specify a usage */
+    if (usage->anyUsage) {
+	return PR_TRUE;
+    }
+    ca = usage->nss3lookingForCA;
+    secrv = CERT_KeyUsageAndTypeForCertUsage(usage->nss3usage, ca,
+                                             &requiredKeyUsage,
+                                             &requiredCertType);
+    if (secrv != SECSuccess) {
+	return PR_FALSE;
+    }
+    cc = (CERTCertificate *)dc->data;
+    secrv = CERT_CheckKeyUsage(cc, requiredKeyUsage);
+    match = (PRBool)(secrv == SECSuccess);
+    if (match) {
+	unsigned int certType = 0;
+	if (ca) {
+	    (void)CERT_IsCACert(cc, &certType);
+	} else {
+	    certType = cc->nsCertType;
+	}
+	if (!(certType & requiredCertType)) {
+	    match = PR_FALSE;
+	}
+    }
+    return match;
+}
+
+static NSSASCII7 *
+nss3certificate_getEmailAddress(nssDecodedCert *dc)
+{
+    CERTCertificate *cc = (CERTCertificate *)dc->data;
+    return (cc && cc->emailAddr && cc->emailAddr[0])
+	    ? (NSSASCII7 *)cc->emailAddr : NULL;
+}
+
+static PRStatus
+nss3certificate_getDERSerialNumber(nssDecodedCert *dc, 
+                                   NSSDER *serial, NSSArena *arena)
+{
+    CERTCertificate *cc = (CERTCertificate *)dc->data;
+    SECItem derSerial = { 0 };
+    SECStatus secrv;
+    secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
+    if (secrv == SECSuccess) {
+	(void)nssItem_Create(arena, serial, derSerial.len, derSerial.data);
+	PORT_Free(derSerial.data);
+	return PR_SUCCESS;
+    }
+    return PR_FAILURE;
+}
+
+/* Returns NULL if "encoding" cannot be decoded. */
+NSS_IMPLEMENT nssDecodedCert *
+nssDecodedPKIXCertificate_Create (
+  NSSArena *arenaOpt,
+  NSSDER *encoding
+)
+{
+    nssDecodedCert  *rvDC = NULL;
+    CERTCertificate *cert;
+    SECItem          secDER;
+
+    SECITEM_FROM_NSSITEM(&secDER, encoding);
+    cert = CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL);
+    if (cert) {
+	rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
+	if (rvDC) {
+	    rvDC->type                = NSSCertificateType_PKIX;
+	    rvDC->data                = (void *)cert;
+	    rvDC->getIdentifier       = nss3certificate_getIdentifier;
+	    rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
+	    rvDC->matchIdentifier     = nss3certificate_matchIdentifier;
+	    rvDC->isValidIssuer       = nss3certificate_isValidIssuer;
+	    rvDC->getUsage            = nss3certificate_getUsage;
+	    rvDC->isValidAtTime       = nss3certificate_isValidAtTime;
+	    rvDC->isNewerThan         = nss3certificate_isNewerThan;
+	    rvDC->matchUsage          = nss3certificate_matchUsage;
+	    rvDC->getEmailAddress     = nss3certificate_getEmailAddress;
+	    rvDC->getDERSerialNumber  = nss3certificate_getDERSerialNumber;
+	} else {
+	    CERT_DestroyCertificate(cert);
+	}
+    }
+    return rvDC;
+}
+
+static nssDecodedCert *
+create_decoded_pkix_cert_from_nss3cert (
+  NSSArena *arenaOpt,
+  CERTCertificate *cc
+)
+{
+    nssDecodedCert *rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
+    if (rvDC) {
+	rvDC->type                = NSSCertificateType_PKIX;
+	rvDC->data                = (void *)cc;
+	rvDC->getIdentifier       = nss3certificate_getIdentifier;
+	rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
+	rvDC->matchIdentifier     = nss3certificate_matchIdentifier;
+	rvDC->isValidIssuer       = nss3certificate_isValidIssuer;
+	rvDC->getUsage            = nss3certificate_getUsage;
+	rvDC->isValidAtTime       = nss3certificate_isValidAtTime;
+	rvDC->isNewerThan         = nss3certificate_isNewerThan;
+	rvDC->matchUsage          = nss3certificate_matchUsage;
+	rvDC->getEmailAddress     = nss3certificate_getEmailAddress;
+    }
+    return rvDC;
+}
+
+NSS_IMPLEMENT PRStatus
+nssDecodedPKIXCertificate_Destroy (
+  nssDecodedCert *dc
+)
+{
+    CERTCertificate *cert = (CERTCertificate *)dc->data;
+
+    /* The decoder may only be half initialized (the case where we find we 
+     * could not decode the certificate). In this case, there is not cert to
+     * free, just free the dc structure. */
+    if (cert) {
+	PRBool freeSlot = cert->ownSlot;
+	PK11SlotInfo *slot = cert->slot;
+	PRArenaPool *arena  = cert->arena;
+	/* zero cert before freeing. Any stale references to this cert
+	 * after this point will probably cause an exception.  */
+	PORT_Memset(cert, 0, sizeof *cert);
+	/* free the arena that contains the cert. */
+	PORT_FreeArena(arena, PR_FALSE);
+	if (slot && freeSlot) {
+	    PK11_FreeSlot(slot);
+	}
+    }
+    nss_ZFreeIf(dc);
+    return PR_SUCCESS;
+}
+
+/* see pk11cert.c:pk11_HandleTrustObject */
+static unsigned int
+get_nss3trust_from_nss4trust(CK_TRUST t)
+{
+    unsigned int rt = 0;
+    if (t == nssTrustLevel_Trusted) {
+	rt |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+    }
+    if (t == nssTrustLevel_TrustedDelegator) {
+	rt |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA /*| CERTDB_NS_TRUSTED_CA*/;
+    }
+    if (t == nssTrustLevel_Valid) {
+	rt |= CERTDB_VALID_PEER;
+    }
+    if (t == nssTrustLevel_ValidDelegator) {
+	rt |= CERTDB_VALID_CA;
+    }
+    return rt;
+}
+
+static CERTCertTrust *
+cert_trust_from_stan_trust(NSSTrust *t, PRArenaPool *arena)
+{
+    CERTCertTrust *rvTrust;
+    unsigned int client;
+    if (!t) {
+	return NULL;
+    }
+    rvTrust = PORT_ArenaAlloc(arena, sizeof(CERTCertTrust));
+    if (!rvTrust) return NULL;
+    rvTrust->sslFlags = get_nss3trust_from_nss4trust(t->serverAuth);
+    client = get_nss3trust_from_nss4trust(t->clientAuth);
+    if (client & (CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA)) {
+	client &= ~(CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA);
+	rvTrust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA;
+    }
+    rvTrust->sslFlags |= client;
+    rvTrust->emailFlags = get_nss3trust_from_nss4trust(t->emailProtection);
+    rvTrust->objectSigningFlags = get_nss3trust_from_nss4trust(t->codeSigning);
+    /* The cert is a valid step-up cert (in addition to/lieu of trust above */
+    if (t->stepUpApproved) {
+	rvTrust->sslFlags |= CERTDB_GOVT_APPROVED_CA;
+    }
+    return rvTrust;
+}
+
+CERTCertTrust * 
+nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc)
+{
+    CERTCertTrust *rvTrust = NULL;
+    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+    NSSTrust *t;
+    t = nssTrustDomain_FindTrustForCertificate(td, c);
+    if (t) {
+	rvTrust = cert_trust_from_stan_trust(t, cc->arena);
+	if (!rvTrust) {
+	    nssTrust_Destroy(t);
+	    return NULL;
+	}
+	nssTrust_Destroy(t);
+    } else {
+	rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
+	if (!rvTrust) {
+	    return NULL;
+	}
+	memset(rvTrust, 0, sizeof(*rvTrust));
+    }
+    if (NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
+	rvTrust->sslFlags |= CERTDB_USER;
+	rvTrust->emailFlags |= CERTDB_USER;
+	rvTrust->objectSigningFlags |= CERTDB_USER;
+    }
+    return rvTrust;
+}
+
+static nssCryptokiInstance *
+get_cert_instance(NSSCertificate *c)
+{
+    nssCryptokiObject *instance, **ci;
+    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
+    if (!instances) {
+	return NULL;
+    }
+    instance = NULL;
+    for (ci = instances; *ci; ci++) {
+	if (!instance) {
+	    instance = nssCryptokiObject_Clone(*ci);
+	} else {
+	    /* This only really works for two instances...  But 3.4 can't
+	     * handle more anyway.  The logic is, if there are multiple
+	     * instances, prefer the one that is not internal (e.g., on
+	     * a hardware device.
+	     */
+	    if (PK11_IsInternal(instance->token->pk11slot)) {
+		nssCryptokiObject_Destroy(instance);
+		instance = nssCryptokiObject_Clone(*ci);
+	    }
+	}
+    }
+    nssCryptokiObjectArray_Destroy(instances);
+    return instance;
+}
+
+char * 
+STAN_GetCERTCertificateNameForInstance (
+  PLArenaPool *arenaOpt,
+  NSSCertificate *c,
+  nssCryptokiInstance *instance
+)
+{
+    NSSCryptoContext *context = c->object.cryptoContext;
+    PRStatus nssrv;
+    int nicklen, tokenlen, len;
+    NSSUTF8 *tokenName = NULL;
+    NSSUTF8 *stanNick = NULL;
+    char *nickname = NULL;
+    char *nick;
+
+    if (instance) {
+	stanNick = instance->label;
+    } else if (context) {
+	stanNick = c->object.tempName;
+    }
+    if (stanNick) {
+	/* fill other fields needed by NSS3 functions using CERTCertificate */
+	if (instance && (!PK11_IsInternalKeySlot(instance->token->pk11slot) || 
+	                 PORT_Strchr(stanNick, ':') != NULL) ) {
+	    tokenName = nssToken_GetName(instance->token);
+	    tokenlen = nssUTF8_Size(tokenName, &nssrv);
+	} else {
+	/* don't use token name for internal slot; 3.3 didn't */
+	    tokenlen = 0;
+	}
+	nicklen = nssUTF8_Size(stanNick, &nssrv);
+	len = tokenlen + nicklen;
+	if (arenaOpt) {
+	    nickname = PORT_ArenaAlloc(arenaOpt, len);
+	} else {
+	    nickname = PORT_Alloc(len);
+	}
+	nick = nickname;
+	if (tokenName) {
+	    memcpy(nick, tokenName, tokenlen-1);
+	    nick += tokenlen-1;
+	    *nick++ = ':';
+	}
+	memcpy(nick, stanNick, nicklen-1);
+	nickname[len-1] = '\0';
+    }
+    return nickname;
+}
+
+char * 
+STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c)
+{
+    char * result;
+    nssCryptokiInstance *instance = get_cert_instance(c);
+    /* It's OK to call this function, even if instance is NULL */
+    result = STAN_GetCERTCertificateNameForInstance(arenaOpt, c, instance);
+    if (instance)
+	nssCryptokiObject_Destroy(instance);
+    return result;
+}
+
+static void
+fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced)
+{
+    CERTCertTrust* trust = NULL;
+    NSSTrust *nssTrust;
+    NSSCryptoContext *context = c->object.cryptoContext;
+    nssCryptokiInstance *instance;
+    NSSUTF8 *stanNick = NULL;
+
+    /* We are holding the base class object's lock on entry of this function
+     * This lock protects writes to fields of the CERTCertificate .
+     * It is also needed by some functions to compute values such as trust.
+     */
+    instance = get_cert_instance(c);
+
+    if (instance) {
+	stanNick = instance->label;
+    } else if (context) {
+	stanNick = c->object.tempName;
+    }
+    /* fill other fields needed by NSS3 functions using CERTCertificate */
+    if ((!cc->nickname && stanNick) || forced) {
+	PRStatus nssrv;
+	int nicklen, tokenlen, len;
+	NSSUTF8 *tokenName = NULL;
+	char *nick;
+	if (instance && 
+	     (!PK11_IsInternalKeySlot(instance->token->pk11slot) || 
+	      (stanNick && PORT_Strchr(stanNick, ':') != NULL))) {
+	    tokenName = nssToken_GetName(instance->token);
+	    tokenlen = nssUTF8_Size(tokenName, &nssrv);
+	} else {
+	    /* don't use token name for internal slot; 3.3 didn't */
+	    tokenlen = 0;
+	}
+	if (stanNick) {
+	    nicklen = nssUTF8_Size(stanNick, &nssrv);
+	    len = tokenlen + nicklen;
+	    nick = PORT_ArenaAlloc(cc->arena, len);
+	    if (tokenName) {
+		memcpy(nick, tokenName, tokenlen-1);
+		nick[tokenlen-1] = ':';
+		memcpy(nick+tokenlen, stanNick, nicklen-1);
+	    } else {
+		memcpy(nick, stanNick, nicklen-1);
+	    }
+	    nick[len-1] = '\0';
+            cc->nickname = nick;
+	} else {
+	    cc->nickname = NULL;
+	}
+    }
+    if (context) {
+	/* trust */
+	nssTrust = nssCryptoContext_FindTrustForCertificate(context, c);
+	if (nssTrust) {
+            trust = cert_trust_from_stan_trust(nssTrust, cc->arena);
+            if (trust) {
+                /* we should destroy cc->trust before replacing it, but it's
+                   allocated in cc->arena, so memory growth will occur on each
+                   refresh */
+                cc->trust = trust;
+            }
+	    nssTrust_Destroy(nssTrust);
+	}
+    } else if (instance) {
+	/* slot */
+	if (cc->slot != instance->token->pk11slot) {
+	    if (cc->slot) {
+		PK11_FreeSlot(cc->slot);
+	    }
+	    cc->slot = PK11_ReferenceSlot(instance->token->pk11slot);
+	}
+	cc->ownSlot = PR_TRUE;
+	/* pkcs11ID */
+	cc->pkcs11ID = instance->handle;
+	/* trust */
+	trust = nssTrust_GetCERTCertTrustForCert(c, cc);
+        if (trust) {
+            /* we should destroy cc->trust before replacing it, but it's
+               allocated in cc->arena, so memory growth will occur on each
+               refresh */
+            cc->trust = trust;
+        }
+	nssCryptokiObject_Destroy(instance);
+    } 
+    /* database handle is now the trust domain */
+    cc->dbhandle = c->object.trustDomain;
+    /* subjectList ? */
+    /* istemp and isperm are supported in NSS 3.4 */
+    cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */
+    cc->isperm = PR_TRUE;  /* by default */
+    /* pointer back */
+    cc->nssCertificate = c;
+    if (trust) {
+	/* force the cert type to be recomputed to include trust info */
+	PRUint32 nsCertType = cert_ComputeCertType(cc);
+
+	/* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */
+	PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32));
+	PR_AtomicSet((PRInt32 *)&cc->nsCertType, nsCertType);
+    }
+}
+
+static CERTCertificate *
+stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate)
+{
+    nssDecodedCert *dc = NULL;
+    CERTCertificate *cc = NULL;
+
+    nssPKIObject_Lock(&c->object);
+
+    dc = c->decoding;
+    if (!dc) {
+	dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding);
+	if (!dc) {
+            goto loser;
+        }
+	cc = (CERTCertificate *)dc->data;
+	PORT_Assert(cc); /* software error */
+	if (!cc) {
+	    nssDecodedPKIXCertificate_Destroy(dc);
+	    nss_SetError(NSS_ERROR_INTERNAL_ERROR);
+	    goto loser;
+	}
+    	PORT_Assert(!c->decoding); 
+	if (!c->decoding) {
+	    c->decoding = dc;
+	} else { 
+            /* this should never happen. Fail. */
+	    nssDecodedPKIXCertificate_Destroy(dc);
+	    nss_SetError(NSS_ERROR_INTERNAL_ERROR);
+            goto loser;
+	}
+    }
+    cc = (CERTCertificate *)dc->data;
+    PORT_Assert(cc);
+    if (!cc) {
+        nss_SetError(NSS_ERROR_INTERNAL_ERROR);
+        goto loser;
+    }
+    if (!cc->nssCertificate || forceUpdate) {
+        fill_CERTCertificateFields(c, cc, forceUpdate);
+    } else if (!cc->trust && !c->object.cryptoContext) {
+        /* if it's a perm cert, it might have been stored before the
+         * trust, so look for the trust again.  But a temp cert can be
+         * ignored.
+         */
+        CERTCertTrust* trust = NULL;
+        trust = nssTrust_GetCERTCertTrustForCert(c, cc);
+        cc->trust = trust;
+    }
+
+  loser:
+    nssPKIObject_Unlock(&c->object);
+    return cc;
+}
+
+NSS_IMPLEMENT CERTCertificate *
+STAN_ForceCERTCertificateUpdate(NSSCertificate *c)
+{
+    if (c->decoding) {
+	return stan_GetCERTCertificate(c, PR_TRUE);
+    }
+    return NULL;
+}
+
+NSS_IMPLEMENT CERTCertificate *
+STAN_GetCERTCertificate(NSSCertificate *c)
+{
+    return stan_GetCERTCertificate(c, PR_FALSE);
+}
+/*
+ * many callers of STAN_GetCERTCertificate() intend that
+ * the CERTCertificate returned inherits the reference to the 
+ * NSSCertificate. For these callers it's convenient to have 
+ * this function 'own' the reference and either return a valid 
+ * CERTCertificate structure which inherits the reference or 
+ * destroy the reference to NSSCertificate and returns NULL.
+ */
+NSS_IMPLEMENT CERTCertificate *
+STAN_GetCERTCertificateOrRelease(NSSCertificate *c)
+{
+    CERTCertificate *nss3cert = stan_GetCERTCertificate(c, PR_FALSE);
+    if (!nss3cert) {
+	nssCertificate_Destroy(c);
+    }
+    return nss3cert;
+}
+
+static nssTrustLevel
+get_stan_trust(unsigned int t, PRBool isClientAuth) 
+{
+    if (isClientAuth) {
+	if (t & CERTDB_TRUSTED_CLIENT_CA) {
+	    return nssTrustLevel_TrustedDelegator;
+	}
+    } else {
+	if (t & CERTDB_TRUSTED_CA || t & CERTDB_NS_TRUSTED_CA) {
+	    return nssTrustLevel_TrustedDelegator;
+	}
+    }
+    if (t & CERTDB_TRUSTED) {
+	return nssTrustLevel_Trusted;
+    }
+    if (t & CERTDB_VALID_CA) {
+	return nssTrustLevel_ValidDelegator;
+    }
+    if (t & CERTDB_VALID_PEER) {
+	return nssTrustLevel_Valid;
+    }
+    return nssTrustLevel_NotTrusted;
+}
+
+NSS_EXTERN NSSCertificate *
+STAN_GetNSSCertificate(CERTCertificate *cc)
+{
+    NSSCertificate *c;
+    nssCryptokiInstance *instance;
+    nssPKIObject *pkiob;
+    NSSArena *arena;
+    c = cc->nssCertificate;
+    if (c) {
+    	return c;
+    }
+    /* i don't think this should happen.  but if it can, need to create
+     * NSSCertificate from CERTCertificate values here.  */
+    /* Yup, it can happen. */
+    arena = NSSArena_Create();
+    if (!arena) {
+	return NULL;
+    }
+    c = nss_ZNEW(arena, NSSCertificate);
+    if (!c) {
+	nssArena_Destroy(arena);
+	return NULL;
+    }
+    NSSITEM_FROM_SECITEM(&c->encoding, &cc->derCert);
+    c->type = NSSCertificateType_PKIX;
+    pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKIMonitor);
+    if (!pkiob) {
+	nssArena_Destroy(arena);
+	return NULL;
+    }
+    c->object = *pkiob;
+    nssItem_Create(arena,
+                   &c->issuer, cc->derIssuer.len, cc->derIssuer.data);
+    nssItem_Create(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;
+	SECStatus secrv;
+	secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
+	if (secrv == SECFailure) {
+	    nssArena_Destroy(arena);
+	    return NULL;
+	}
+	nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data);
+	PORT_Free(derSerial.data);
+    }
+    if (cc->emailAddr && cc->emailAddr[0]) {
+        c->email = nssUTF8_Create(arena,
+                                  nssStringType_PrintableString,
+                                  (NSSUTF8 *)cc->emailAddr,
+                                  PORT_Strlen(cc->emailAddr));
+    }
+    if (cc->slot) {
+	instance = nss_ZNEW(arena, nssCryptokiInstance);
+	if (!instance) {
+	    nssArena_Destroy(arena);
+	    return NULL;
+	}
+	instance->token = nssToken_AddRef(PK11Slot_GetNSSToken(cc->slot));
+	instance->handle = cc->pkcs11ID;
+	instance->isTokenObject = PR_TRUE;
+	if (cc->nickname) {
+	    instance->label = nssUTF8_Create(arena,
+	                                     nssStringType_UTF8String,
+	                                     (NSSUTF8 *)cc->nickname,
+	                                     PORT_Strlen(cc->nickname));
+	}
+	nssPKIObject_AddInstance(&c->object, instance);
+    }
+    c->decoding = create_decoded_pkix_cert_from_nss3cert(NULL, cc);
+    cc->nssCertificate = c;
+    return c;
+}
+
+static NSSToken*
+stan_GetTrustToken (
+  NSSCertificate *c
+)
+{
+    NSSToken *ttok = NULL;
+    NSSToken *rtok = NULL;
+    NSSToken *tok = NULL;
+    nssCryptokiObject **ip;
+    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
+    if (!instances) {
+	return PR_FALSE;
+    }
+    for (ip = instances; *ip; ip++) {
+	nssCryptokiObject *instance = *ip;
+        nssCryptokiObject *to = 
+		nssToken_FindTrustForCertificate(instance->token, NULL,
+		&c->encoding, &c->issuer, &c->serial, 
+		nssTokenSearchType_TokenOnly);
+	NSSToken *ctok = instance->token;
+	PRBool ro = PK11_IsReadOnly(ctok->pk11slot);
+
+	if (to) {
+	    nssCryptokiObject_Destroy(to);
+	    ttok = ctok;
+ 	    if (!ro) {
+		break;
+	    }
+	} else {
+	    if (!rtok && ro) {
+		rtok = ctok;
+	    } 
+	    if (!tok && !ro) {
+		tok = ctok;
+	    }
+	}
+    }
+    nssCryptokiObjectArray_Destroy(instances);
+    return ttok ? ttok : (tok ? tok : rtok);
+}
+
+NSS_EXTERN PRStatus
+STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust)
+{
+    PRStatus nssrv;
+    NSSCertificate *c = STAN_GetNSSCertificate(cc);
+    NSSToken *tok;
+    NSSTrustDomain *td;
+    NSSTrust *nssTrust;
+    NSSArena *arena;
+    CERTCertTrust *oldTrust;
+    nssListIterator *tokens;
+    PRBool moving_object;
+    nssCryptokiObject *newInstance;
+    nssPKIObject *pkiob;
+
+    if (c == NULL) {
+        return SECFailure;
+    }
+    oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc);
+    if (oldTrust) {
+	if (memcmp(oldTrust, trust, sizeof (CERTCertTrust)) == 0) {
+	    /* ... and the new trust is no different, done) */
+	    return PR_SUCCESS;
+	} else {
+	    /* take over memory already allocated in cc's arena */
+	    cc->trust = oldTrust;
+	}
+    } else {
+	cc->trust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
+    }
+    memcpy(cc->trust, trust, sizeof(CERTCertTrust));
+    /* Set the NSSCerticate's trust */
+    arena = nssArena_Create();
+    if (!arena) return PR_FAILURE;
+    nssTrust = nss_ZNEW(arena, NSSTrust);
+    if (!nssTrust) {
+	nssArena_Destroy(arena);
+	return PR_FAILURE;
+    }
+    pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock);
+    if (!pkiob) {
+	nssArena_Destroy(arena);
+	return PR_FAILURE;
+    }
+    nssTrust->object = *pkiob;
+    nssTrust->certificate = c;
+    nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE);
+    nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE);
+    nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE);
+    nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE);
+    nssTrust->stepUpApproved = 
+                    (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA);
+    if (c->object.cryptoContext != NULL) {
+	/* The cert is in a context, set the trust there */
+	NSSCryptoContext *cc = c->object.cryptoContext;
+	nssrv = nssCryptoContext_ImportTrust(cc, nssTrust);
+	if (nssrv != PR_SUCCESS) {
+	    goto done;
+	}
+	if (c->object.numInstances == 0) {
+	    /* The context is the only instance, finished */
+	    goto done;
+	}
+    }
+    td = STAN_GetDefaultTrustDomain();
+    tok = stan_GetTrustToken(c);
+    moving_object = PR_FALSE;
+    if (tok && PK11_IsReadOnly(tok->pk11slot))  {
+	NSSRWLock_LockRead(td->tokensLock);
+	tokens = nssList_CreateIterator(td->tokenList);
+	if (!tokens) {
+	    nssrv = PR_FAILURE;
+	    NSSRWLock_UnlockRead(td->tokensLock);
+	    goto done;
+	}
+	for (tok  = (NSSToken *)nssListIterator_Start(tokens);
+	     tok != (NSSToken *)NULL;
+	     tok  = (NSSToken *)nssListIterator_Next(tokens))
+	{
+	    if (!PK11_IsReadOnly(tok->pk11slot)) break;
+	}
+	nssListIterator_Finish(tokens);
+	nssListIterator_Destroy(tokens);
+	NSSRWLock_UnlockRead(td->tokensLock);
+	moving_object = PR_TRUE;
+    } 
+    if (tok) {
+	if (moving_object) {
+	    /* this is kind of hacky.  the softoken needs the cert
+	     * object in order to store trust.  forcing it to be perm
+	     */
+	    NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
+	    NSSASCII7 *email = NULL;
+
+	    if (PK11_IsInternal(tok->pk11slot)) {
+		email = c->email;
+	    }
+	    newInstance = nssToken_ImportCertificate(tok, NULL,
+	                                             NSSCertificateType_PKIX,
+	                                             &c->id,
+	                                             nickname,
+	                                             &c->encoding,
+	                                             &c->issuer,
+	                                             &c->subject,
+	                                             &c->serial,
+						     email,
+	                                             PR_TRUE);
+	    if (!newInstance) {
+		nssrv = PR_FAILURE;
+		goto done;
+	    }
+	    nssPKIObject_AddInstance(&c->object, newInstance);
+	}
+	newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
+	                                   &c->issuer, &c->serial,
+	                                   nssTrust->serverAuth,
+	                                   nssTrust->clientAuth,
+	                                   nssTrust->codeSigning,
+	                                   nssTrust->emailProtection,
+	                                   nssTrust->stepUpApproved, PR_TRUE);
+	/* If the selected token can't handle trust, dump the trust on 
+	 * the internal token */
+	if (!newInstance && !PK11_IsInternalKeySlot(tok->pk11slot)) {
+	    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
+	    NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
+	    NSSASCII7 *email = c->email;
+	    tok = PK11Slot_GetNSSToken(slot);
+	    PK11_FreeSlot(slot);
+	
+	    newInstance = nssToken_ImportCertificate(tok, NULL,
+	                                             NSSCertificateType_PKIX,
+	                                             &c->id,
+	                                             nickname,
+	                                             &c->encoding,
+	                                             &c->issuer,
+	                                             &c->subject,
+	                                             &c->serial,
+						     email,
+	                                             PR_TRUE);
+	    if (!newInstance) {
+		nssrv = PR_FAILURE;
+		goto done;
+	    }
+	    nssPKIObject_AddInstance(&c->object, newInstance);
+	    newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
+	                                   &c->issuer, &c->serial,
+	                                   nssTrust->serverAuth,
+	                                   nssTrust->clientAuth,
+	                                   nssTrust->codeSigning,
+	                                   nssTrust->emailProtection,
+	                                   nssTrust->stepUpApproved, PR_TRUE);
+	}
+	if (newInstance) {
+	    nssCryptokiObject_Destroy(newInstance);
+	    nssrv = PR_SUCCESS;
+	} else {
+	    nssrv = PR_FAILURE;
+	}
+    } else {
+	nssrv = PR_FAILURE;
+    }
+done:
+    (void)nssTrust_Destroy(nssTrust);
+    return nssrv;
+}
+
+/* CERT_TraversePermCertsForSubject */
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_TraverseCertificatesBySubject (
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  PRStatus (*callback)(NSSCertificate *c, void *arg),
+  void *arg
+)
+{
+    PRStatus nssrv = PR_SUCCESS;
+    NSSArena *tmpArena;
+    NSSCertificate **subjectCerts;
+    NSSCertificate *c;
+    PRIntn i;
+    tmpArena = NSSArena_Create();
+    if (!tmpArena) {
+        return PR_FAILURE;
+    }
+    subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, subject, NULL,
+                                                            0, tmpArena);
+    if (subjectCerts) {
+	for (i=0, c = subjectCerts[i]; c; i++) {
+	    nssrv = callback(c, arg);
+	    if (nssrv != PR_SUCCESS) break;
+	}
+    }
+    nssArena_Destroy(tmpArena);
+    return nssrv;
+}
+
+/* CERT_TraversePermCertsForNickname */
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_TraverseCertificatesByNickname (
+  NSSTrustDomain *td,
+  NSSUTF8 *nickname,
+  PRStatus (*callback)(NSSCertificate *c, void *arg),
+  void *arg
+)
+{
+    PRStatus nssrv = PR_SUCCESS;
+    NSSArena *tmpArena;
+    NSSCertificate **nickCerts;
+    NSSCertificate *c;
+    PRIntn i;
+    tmpArena = NSSArena_Create();
+    if (!tmpArena) {
+        return PR_FAILURE;
+    }
+    nickCerts = NSSTrustDomain_FindCertificatesByNickname(td, nickname, NULL,
+                                                          0, tmpArena);
+    if (nickCerts) {
+	for (i=0, c = nickCerts[i]; c; i++) {
+	    nssrv = callback(c, arg);
+	    if (nssrv != PR_SUCCESS) break;
+	}
+    }
+    nssArena_Destroy(tmpArena);
+    return nssrv;
+}
+
+static void cert_dump_iter(const void *k, void *v, void *a)
+{
+    NSSCertificate *c = (NSSCertificate *)k;
+    CERTCertificate *cert = STAN_GetCERTCertificate(c);
+    printf("[%2d] \"%s\"\n", c->object.refCount, cert->subjectName);
+}
+
+void
+nss_DumpCertificateCacheInfo()
+{
+    NSSTrustDomain *td;
+    NSSCryptoContext *cc;
+    td = STAN_GetDefaultTrustDomain();
+    cc = STAN_GetDefaultCryptoContext();
+    printf("\n\nCertificates in the cache:\n");
+    nssTrustDomain_DumpCacheInfo(td, cert_dump_iter, NULL);
+    printf("\n\nCertificates in the temporary store:\n");
+    if (cc->certStore) {
+	nssCertificateStore_DumpStoreInfo(cc->certStore, cert_dump_iter, NULL);
+    }
+}
+
diff --git a/mozilla/security/nss/lib/pki/pki3hack.h b/mozilla/security/nss/lib/pki/pki3hack.h
new file mode 100644
index 0000000..3920f79
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pki3hack.h
@@ -0,0 +1,197 @@
+/* ***** 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 ***** */
+
+#ifndef PKINSS3HACK_H
+#define PKINSS3HACK_H
+
+#ifdef DEBUG
+static const char PKINSS3HACK_CVS_ID[] = "@(#) $RCSfile: pki3hack.h,v $ $Revision: 1.19 $ $Date: 2005/01/20 02:25:49 $";
+#endif /* DEBUG */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef DEVT_H
+#include "devt.h"
+#endif /* DEVT_H */
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#include "base.h"
+
+#include "cert.h"
+
+PR_BEGIN_EXTERN_C
+
+#define NSSITEM_FROM_SECITEM(nssit, secit)  \
+    (nssit)->data = (void *)(secit)->data;  \
+    (nssit)->size = (PRUint32)(secit)->len;
+
+#define SECITEM_FROM_NSSITEM(secit, nssit)          \
+    (secit)->data = (unsigned char *)(nssit)->data; \
+    (secit)->len  = (unsigned int)(nssit)->size;
+
+NSS_EXTERN NSSTrustDomain *
+STAN_GetDefaultTrustDomain();
+
+NSS_EXTERN NSSCryptoContext *
+STAN_GetDefaultCryptoContext();
+
+NSS_EXTERN PRStatus
+STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot);
+
+NSS_EXTERN PRStatus
+STAN_ResetTokenInterator(NSSTrustDomain *td);
+
+NSS_EXTERN PRStatus
+STAN_LoadDefaultNSS3TrustDomain(void);
+
+NSS_EXTERN PRStatus
+STAN_Shutdown();
+
+NSS_EXTERN SECStatus
+STAN_AddModuleToDefaultTrustDomain(SECMODModule *module);
+
+NSS_EXTERN SECStatus
+STAN_RemoveModuleFromDefaultTrustDomain(SECMODModule *module);
+
+NSS_EXTERN CERTCertificate *
+STAN_ForceCERTCertificateUpdate(NSSCertificate *c);
+
+NSS_EXTERN CERTCertificate *
+STAN_GetCERTCertificate(NSSCertificate *c);
+
+NSS_EXTERN CERTCertificate *
+STAN_GetCERTCertificateOrRelease(NSSCertificate *c);
+
+NSS_EXTERN NSSCertificate *
+STAN_GetNSSCertificate(CERTCertificate *c);
+
+NSS_EXTERN CERTCertTrust * 
+nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc);
+
+NSS_EXTERN PRStatus
+STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust);
+
+NSS_EXTERN PRStatus
+nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der, NSSArena *arena, 
+                                     NSSDER *issuer, NSSDER *serial);
+
+NSS_EXTERN char *
+STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c);
+
+NSS_EXTERN char *
+STAN_GetCERTCertificateNameForInstance(PLArenaPool *arenaOpt,
+                                       NSSCertificate *c,
+                                       nssCryptokiInstance *instance);
+
+/* exposing this */
+NSS_EXTERN NSSCertificate *
+NSSCertificate_Create
+(
+  NSSArena *arenaOpt
+);
+
+/* This function is being put here because it is a hack for 
+ * PK11_FindCertFromNickname.
+ */
+NSS_EXTERN NSSCertificate *
+nssTrustDomain_FindBestCertificateByNicknameForToken
+(
+  NSSTrustDomain *td,
+  NSSToken *token,
+  NSSUTF8 *name,
+  NSSTime *timeOpt, /* NULL for "now" */
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/* This function is being put here because it is a hack for 
+ * PK11_FindCertsFromNickname.
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_FindCertificatesByNicknameForToken
+(
+  NSSTrustDomain *td,
+  NSSToken *token,
+  NSSUTF8 *name,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+);
+
+/* CERT_TraversePermCertsForSubject */
+NSS_EXTERN PRStatus
+nssTrustDomain_TraverseCertificatesBySubject
+(
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  PRStatus (*callback)(NSSCertificate *c, void *arg),
+  void *arg
+);
+
+/* CERT_TraversePermCertsForNickname */
+NSS_EXTERN PRStatus
+nssTrustDomain_TraverseCertificatesByNickname
+(
+  NSSTrustDomain *td,
+  NSSUTF8 *nickname,
+  PRStatus (*callback)(NSSCertificate *c, void *arg),
+  void *arg
+);
+
+/* SEC_TraversePermCerts */
+NSS_EXTERN PRStatus
+nssTrustDomain_TraverseCertificates
+(
+  NSSTrustDomain *td,
+  PRStatus (*callback)(NSSCertificate *c, void *arg),
+  void *arg
+);
+
+/* CERT_AddTempCertToPerm */
+NSS_EXTERN PRStatus
+nssTrustDomain_AddTempCertToPerm
+(
+  NSSCertificate *c
+);
+
+PR_END_EXTERN_C
+
+#endif /* PKINSS3HACK_H */
diff --git a/mozilla/security/nss/lib/pki/pkibase.c b/mozilla/security/nss/lib/pki/pkibase.c
new file mode 100644
index 0000000..48d2976
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pkibase.c
@@ -0,0 +1,1261 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.31 $ $Date: 2009/04/17 19:28:07 $";
+#endif /* DEBUG */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#include "pki3hack.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+NSS_IMPLEMENT void
+nssPKIObject_Lock(nssPKIObject * object)
+{
+    switch (object->lockType) {
+    case nssPKIMonitor:
+        PZ_EnterMonitor(object->sync.mlock);
+        break;
+    case nssPKILock:
+        PZ_Lock(object->sync.lock);
+        break;
+    default:
+        PORT_Assert(0);
+    }
+}
+
+NSS_IMPLEMENT void
+nssPKIObject_Unlock(nssPKIObject * object)
+{
+    switch (object->lockType) {
+    case nssPKIMonitor:
+        PZ_ExitMonitor(object->sync.mlock);
+        break;
+    case nssPKILock:
+        PZ_Unlock(object->sync.lock);
+        break;
+    default:
+        PORT_Assert(0);
+    }
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_NewLock(nssPKIObject * object, nssPKILockType lockType)
+{
+    object->lockType = lockType;
+    switch (lockType) {
+    case nssPKIMonitor:
+        object->sync.mlock = PZ_NewMonitor(nssILockSSL);
+        return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
+    case nssPKILock:
+        object->sync.lock = PZ_NewLock(nssILockSSL);
+        return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
+    default:
+        PORT_Assert(0);
+        return PR_FAILURE;
+    }
+}
+
+NSS_IMPLEMENT void
+nssPKIObject_DestroyLock(nssPKIObject * object)
+{
+    switch (object->lockType) {
+    case nssPKIMonitor:
+        PZ_DestroyMonitor(object->sync.mlock);
+        object->sync.mlock = NULL;
+        break;
+    case nssPKILock:
+        PZ_DestroyLock(object->sync.lock);
+        object->sync.lock = NULL;
+        break;
+    default:
+        PORT_Assert(0);
+    }
+}
+
+
+
+NSS_IMPLEMENT nssPKIObject *
+nssPKIObject_Create (
+  NSSArena *arenaOpt,
+  nssCryptokiObject *instanceOpt,
+  NSSTrustDomain *td,
+  NSSCryptoContext *cc,
+  nssPKILockType lockType
+)
+{
+    NSSArena *arena;
+    nssArenaMark *mark = NULL;
+    nssPKIObject *object;
+    if (arenaOpt) {
+	arena = arenaOpt;
+	mark = nssArena_Mark(arena);
+    } else {
+	arena = nssArena_Create();
+	if (!arena) {
+	    return (nssPKIObject *)NULL;
+	}
+    }
+    object = nss_ZNEW(arena, nssPKIObject);
+    if (!object) {
+	goto loser;
+    }
+    object->arena = arena;
+    object->trustDomain = td; /* XXX */
+    object->cryptoContext = cc;
+    if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
+	goto loser;
+    }
+    if (instanceOpt) {
+	if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
+	    goto loser;
+	}
+    }
+    PR_AtomicIncrement(&object->refCount);
+    if (mark) {
+	nssArena_Unmark(arena, mark);
+    }
+    return object;
+loser:
+    if (mark) {
+	nssArena_Release(arena, mark);
+    } else {
+	nssArena_Destroy(arena);
+    }
+    return (nssPKIObject *)NULL;
+}
+
+NSS_IMPLEMENT PRBool
+nssPKIObject_Destroy (
+  nssPKIObject *object
+)
+{
+    PRUint32 i;
+    PR_ASSERT(object->refCount > 0);
+    if (PR_AtomicDecrement(&object->refCount) == 0) {
+	for (i=0; i<object->numInstances; i++) {
+	    nssCryptokiObject_Destroy(object->instances[i]);
+	}
+	nssPKIObject_DestroyLock(object);
+	nssArena_Destroy(object->arena);
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+NSS_IMPLEMENT nssPKIObject *
+nssPKIObject_AddRef (
+  nssPKIObject *object
+)
+{
+    PR_AtomicIncrement(&object->refCount);
+    return object;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_AddInstance (
+  nssPKIObject *object,
+  nssCryptokiObject *instance
+)
+{
+    nssCryptokiObject **newInstances = NULL;
+
+    nssPKIObject_Lock(object);
+    if (object->numInstances == 0) {
+	newInstances = nss_ZNEWARRAY(object->arena,
+				     nssCryptokiObject *,
+				     object->numInstances + 1);
+    } else {
+	PRBool found = PR_FALSE;
+	PRUint32 i;
+	for (i=0; i<object->numInstances; i++) {
+	    if (nssCryptokiObject_Equal(object->instances[i], instance)) {
+		found = PR_TRUE;
+		break;
+	    }
+	}
+	if (found) {
+	    /* The new instance is identical to one in the array, except
+	     * perhaps that the label may be different.  So replace 
+	     * the label in the array instance with the label from the 
+	     * new instance, and discard the new instance.
+	     */
+	    nss_ZFreeIf(object->instances[i]->label);
+	    object->instances[i]->label = instance->label;
+	    nssPKIObject_Unlock(object);
+	    instance->label = NULL;
+	    nssCryptokiObject_Destroy(instance);
+	    return PR_SUCCESS;
+	}
+	newInstances = nss_ZREALLOCARRAY(object->instances,
+					 nssCryptokiObject *,
+					 object->numInstances + 1);
+    }
+    if (newInstances) {
+	object->instances = newInstances;
+	newInstances[object->numInstances++] = instance;
+    }
+    nssPKIObject_Unlock(object);
+    return (newInstances ? PR_SUCCESS : PR_FAILURE);
+}
+
+NSS_IMPLEMENT PRBool
+nssPKIObject_HasInstance (
+  nssPKIObject *object,
+  nssCryptokiObject *instance
+)
+{
+    PRUint32 i;
+    PRBool hasIt = PR_FALSE;;
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	if (nssCryptokiObject_Equal(object->instances[i], instance)) {
+	    hasIt = PR_TRUE;
+	    break;
+	}
+    }
+    nssPKIObject_Unlock(object);
+    return hasIt;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_RemoveInstanceForToken (
+  nssPKIObject *object,
+  NSSToken *token
+)
+{
+    PRUint32 i;
+    nssCryptokiObject *instanceToRemove = NULL;
+    nssPKIObject_Lock(object);
+    if (object->numInstances == 0) {
+	nssPKIObject_Unlock(object);
+	return PR_SUCCESS;
+    }
+    for (i=0; i<object->numInstances; i++) {
+	if (object->instances[i]->token == token) {
+	    instanceToRemove = object->instances[i];
+	    object->instances[i] = object->instances[object->numInstances-1];
+	    object->instances[object->numInstances-1] = NULL;
+	    break;
+	}
+    }
+    if (--object->numInstances > 0) {
+	nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
+	                                      nssCryptokiObject *,
+	                                      object->numInstances);
+	if (instances) {
+	    object->instances = instances;
+	}
+    } else {
+	nss_ZFreeIf(object->instances);
+    }
+    nssCryptokiObject_Destroy(instanceToRemove);
+    nssPKIObject_Unlock(object);
+    return PR_SUCCESS;
+}
+
+/* this needs more thought on what will happen when there are multiple
+ * instances
+ */
+NSS_IMPLEMENT PRStatus
+nssPKIObject_DeleteStoredObject (
+  nssPKIObject *object,
+  NSSCallback *uhh,
+  PRBool isFriendly
+)
+{
+    PRUint32 i, numNotDestroyed;
+    PRStatus status = PR_SUCCESS;
+    numNotDestroyed = 0;
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	nssCryptokiObject *instance = object->instances[i];
+	status = nssToken_DeleteStoredObject(instance);
+	object->instances[i] = NULL;
+	if (status == PR_SUCCESS) {
+	    nssCryptokiObject_Destroy(instance);
+	} else {
+	    object->instances[numNotDestroyed++] = instance;
+	}
+    }
+    if (numNotDestroyed == 0) {
+	nss_ZFreeIf(object->instances);
+	object->numInstances = 0;
+    } else {
+	object->numInstances = numNotDestroyed;
+    }
+    nssPKIObject_Unlock(object);
+    return status;
+}
+
+NSS_IMPLEMENT NSSToken **
+nssPKIObject_GetTokens (
+  nssPKIObject *object,
+  PRStatus *statusOpt
+)
+{
+    NSSToken **tokens = NULL;
+    nssPKIObject_Lock(object);
+    if (object->numInstances > 0) {
+	tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
+	if (tokens) {
+	    PRUint32 i;
+	    for (i=0; i<object->numInstances; i++) {
+		tokens[i] = nssToken_AddRef(object->instances[i]->token);
+	    }
+	}
+    }
+    nssPKIObject_Unlock(object);
+    if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */
+    return tokens;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssPKIObject_GetNicknameForToken (
+  nssPKIObject *object,
+  NSSToken *tokenOpt
+)
+{
+    PRUint32 i;
+    NSSUTF8 *nickname = NULL;
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	if ((!tokenOpt && object->instances[i]->label) ||
+	    (object->instances[i]->token == tokenOpt)) 
+	{
+            /* XXX should be copy? safe as long as caller has reference */
+	    nickname = object->instances[i]->label; 
+	    break;
+	}
+    }
+    nssPKIObject_Unlock(object);
+    return nickname;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssPKIObject_GetInstances (
+  nssPKIObject *object
+)
+{
+    nssCryptokiObject **instances = NULL;
+    PRUint32 i;
+    if (object->numInstances == 0) {
+	return (nssCryptokiObject **)NULL;
+    }
+    nssPKIObject_Lock(object);
+    instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, 
+                              object->numInstances + 1);
+    if (instances) {
+	for (i=0; i<object->numInstances; i++) {
+	    instances[i] = nssCryptokiObject_Clone(object->instances[i]);
+	}
+    }
+    nssPKIObject_Unlock(object);
+    return instances;
+}
+
+NSS_IMPLEMENT void
+nssCertificateArray_Destroy (
+  NSSCertificate **certs
+)
+{
+    if (certs) {
+	NSSCertificate **certp;
+	for (certp = certs; *certp; certp++) {
+	    if ((*certp)->decoding) {
+		CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
+		if (cc) {
+		    CERT_DestroyCertificate(cc);
+		}
+		continue;
+	    }
+	    nssCertificate_Destroy(*certp);
+	}
+	nss_ZFreeIf(certs);
+    }
+}
+
+NSS_IMPLEMENT void
+NSSCertificateArray_Destroy (
+  NSSCertificate **certs
+)
+{
+    nssCertificateArray_Destroy(certs);
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssCertificateArray_Join (
+  NSSCertificate **certs1,
+  NSSCertificate **certs2
+)
+{
+    if (certs1 && certs2) {
+	NSSCertificate **certs, **cp;
+	PRUint32 count = 0;
+	PRUint32 count1 = 0;
+	cp = certs1;
+	while (*cp++) count1++;
+	count = count1;
+	cp = certs2;
+	while (*cp++) count++;
+	certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
+	if (!certs) {
+	    nss_ZFreeIf(certs1);
+	    nss_ZFreeIf(certs2);
+	    return (NSSCertificate **)NULL;
+	}
+	for (cp = certs2; *cp; cp++, count1++) {
+	    certs[count1] = *cp;
+	}
+	nss_ZFreeIf(certs2);
+	return certs;
+    } else if (certs1) {
+	return certs1;
+    } else {
+	return certs2;
+    }
+}
+
+NSS_IMPLEMENT NSSCertificate * 
+nssCertificateArray_FindBestCertificate (
+  NSSCertificate **certs, 
+  NSSTime *timeOpt,
+  const NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    NSSCertificate *bestCert = NULL;
+    NSSTime *time, sTime;
+    PRBool haveUsageMatch = PR_FALSE;
+    PRBool thisCertMatches;
+
+    if (timeOpt) {
+	time = timeOpt;
+    } else {
+	NSSTime_Now(&sTime);
+	time = &sTime;
+    }
+    if (!certs) {
+	return (NSSCertificate *)NULL;
+    }
+    for (; *certs; certs++) {
+	nssDecodedCert *dc, *bestdc;
+	NSSCertificate *c = *certs;
+	dc = nssCertificate_GetDecoding(c);
+	if (!dc) continue;
+	thisCertMatches = dc->matchUsage(dc, usage);
+	if (!bestCert) {
+	    /* always take the first cert, but remember whether or not
+	     * the usage matched 
+	     */
+	    bestCert = nssCertificate_AddRef(c);
+	    haveUsageMatch = thisCertMatches;
+	    continue;
+	} else {
+	    if (haveUsageMatch && !thisCertMatches) {
+		/* if already have a cert for this usage, and if this cert 
+		 * doesn't have the correct usage, continue
+		 */
+		continue;
+	    } else if (!haveUsageMatch && thisCertMatches) {
+		/* this one does match usage, replace the other */
+		nssCertificate_Destroy(bestCert);
+		bestCert = nssCertificate_AddRef(c);
+		haveUsageMatch = PR_TRUE;
+		continue;
+	    }
+	    /* this cert match as well as any cert we've found so far, 
+	     * defer to time/policies 
+	     * */
+	}
+	bestdc = nssCertificate_GetDecoding(bestCert);
+	/* time */
+	if (bestdc->isValidAtTime(bestdc, time)) {
+	    /* The current best cert is valid at time */
+	    if (!dc->isValidAtTime(dc, time)) {
+		/* If the new cert isn't valid at time, it's not better */
+		continue;
+	    }
+	} else {
+	    /* The current best cert is not valid at time */
+	    if (dc->isValidAtTime(dc, time)) {
+		/* If the new cert is valid at time, it's better */
+		nssCertificate_Destroy(bestCert);
+		bestCert = nssCertificate_AddRef(c);
+	    }
+	}
+	/* either they are both valid at time, or neither valid; 
+	 * take the newer one
+	 */
+	if (!bestdc->isNewerThan(bestdc, dc)) {
+	    nssCertificate_Destroy(bestCert);
+	    bestCert = nssCertificate_AddRef(c);
+	}
+	/* policies */
+	/* XXX later -- defer to policies */
+    }
+    return bestCert;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCertificateArray_Traverse (
+  NSSCertificate **certs,
+  PRStatus (* callback)(NSSCertificate *c, void *arg),
+  void *arg
+)
+{
+    PRStatus status = PR_SUCCESS;
+    if (certs) {
+	NSSCertificate **certp;
+	for (certp = certs; *certp; certp++) {
+	    status = (*callback)(*certp, arg);
+	    if (status != PR_SUCCESS) {
+		break;
+	    }
+	}
+    }
+    return status;
+}
+
+
+NSS_IMPLEMENT void
+nssCRLArray_Destroy (
+  NSSCRL **crls
+)
+{
+    if (crls) {
+	NSSCRL **crlp;
+	for (crlp = crls; *crlp; crlp++) {
+	    nssCRL_Destroy(*crlp);
+	}
+	nss_ZFreeIf(crls);
+    }
+}
+
+/*
+ * Object collections
+ */
+
+typedef enum
+{
+  pkiObjectType_Certificate = 0,
+  pkiObjectType_CRL = 1,
+  pkiObjectType_PrivateKey = 2,
+  pkiObjectType_PublicKey = 3
+} pkiObjectType;
+
+/* Each object is defined by a set of items that uniquely identify it.
+ * Here are the uid sets:
+ *
+ * NSSCertificate ==>  { issuer, serial }
+ * NSSPrivateKey
+ *         (RSA) ==> { modulus, public exponent }
+ *
+ */
+#define MAX_ITEMS_FOR_UID 2
+
+/* pkiObjectCollectionNode
+ *
+ * A node in the collection is the set of unique identifiers for a single
+ * object, along with either the actual object or a proto-object.
+ */
+typedef struct
+{
+  PRCList link;
+  PRBool haveObject;
+  nssPKIObject *object;
+  NSSItem uid[MAX_ITEMS_FOR_UID];
+} 
+pkiObjectCollectionNode;
+
+/* nssPKIObjectCollection
+ *
+ * The collection is the set of all objects, plus the interfaces needed
+ * to manage the objects.
+ *
+ */
+struct nssPKIObjectCollectionStr
+{
+  NSSArena *arena;
+  NSSTrustDomain *td;
+  NSSCryptoContext *cc;
+  PRCList head; /* list of pkiObjectCollectionNode's */
+  PRUint32 size;
+  pkiObjectType objectType;
+  void           (*      destroyObject)(nssPKIObject *o);
+  PRStatus       (*   getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
+  PRStatus       (* getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, 
+                                        NSSArena *arena);
+  nssPKIObject * (*       createObject)(nssPKIObject *o);
+  nssPKILockType lockType; /* type of lock to use for new proto-objects */
+};
+
+static nssPKIObjectCollection *
+nssPKIObjectCollection_Create (
+  NSSTrustDomain *td,
+  NSSCryptoContext *ccOpt,
+  nssPKILockType lockType
+)
+{
+    NSSArena *arena;
+    nssPKIObjectCollection *rvCollection = NULL;
+    arena = nssArena_Create();
+    if (!arena) {
+	return (nssPKIObjectCollection *)NULL;
+    }
+    rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
+    if (!rvCollection) {
+	goto loser;
+    }
+    PR_INIT_CLIST(&rvCollection->head);
+    rvCollection->arena = arena;
+    rvCollection->td = td; /* XXX */
+    rvCollection->cc = ccOpt;
+    rvCollection->lockType = lockType;
+    return rvCollection;
+loser:
+    nssArena_Destroy(arena);
+    return (nssPKIObjectCollection *)NULL;
+}
+
+NSS_IMPLEMENT void
+nssPKIObjectCollection_Destroy (
+  nssPKIObjectCollection *collection
+)
+{
+    if (collection) {
+	PRCList *link;
+	pkiObjectCollectionNode *node;
+	/* first destroy any objects in the collection */
+	link = PR_NEXT_LINK(&collection->head);
+	while (link != &collection->head) {
+	    node = (pkiObjectCollectionNode *)link;
+	    if (node->haveObject) {
+		(*collection->destroyObject)(node->object);
+	    } else {
+		nssPKIObject_Destroy(node->object);
+	    }
+	    link = PR_NEXT_LINK(link);
+	}
+	/* then destroy it */
+	nssArena_Destroy(collection->arena);
+    }
+}
+
+NSS_IMPLEMENT PRUint32
+nssPKIObjectCollection_Count (
+  nssPKIObjectCollection *collection
+)
+{
+    return collection->size;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddObject (
+  nssPKIObjectCollection *collection,
+  nssPKIObject *object
+)
+{
+    pkiObjectCollectionNode *node;
+    node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
+    if (!node) {
+	return PR_FAILURE;
+    }
+    node->haveObject = PR_TRUE;
+    node->object = nssPKIObject_AddRef(object);
+    (*collection->getUIDFromObject)(object, node->uid);
+    PR_INIT_CLIST(&node->link);
+    PR_INSERT_BEFORE(&node->link, &collection->head);
+    collection->size++;
+    return PR_SUCCESS;
+}
+
+static pkiObjectCollectionNode *
+find_instance_in_collection (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject *instance
+)
+{
+    PRCList *link;
+    pkiObjectCollectionNode *node;
+    link = PR_NEXT_LINK(&collection->head);
+    while (link != &collection->head) {
+	node = (pkiObjectCollectionNode *)link;
+	if (nssPKIObject_HasInstance(node->object, instance)) {
+	    return node;
+	}
+	link = PR_NEXT_LINK(link);
+    }
+    return (pkiObjectCollectionNode *)NULL;
+}
+
+static pkiObjectCollectionNode *
+find_object_in_collection (
+  nssPKIObjectCollection *collection,
+  NSSItem *uid
+)
+{
+    PRUint32 i;
+    PRStatus status;
+    PRCList *link;
+    pkiObjectCollectionNode *node;
+    link = PR_NEXT_LINK(&collection->head);
+    while (link != &collection->head) {
+	node = (pkiObjectCollectionNode *)link;
+	for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
+	    if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
+		break;
+	    }
+	}
+	if (i == MAX_ITEMS_FOR_UID) {
+	    return node;
+	}
+	link = PR_NEXT_LINK(link);
+    }
+    return (pkiObjectCollectionNode *)NULL;
+}
+
+static pkiObjectCollectionNode *
+add_object_instance (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject *instance,
+  PRBool *foundIt
+)
+{
+    PRUint32 i;
+    PRStatus status;
+    pkiObjectCollectionNode *node;
+    nssArenaMark *mark = NULL;
+    NSSItem uid[MAX_ITEMS_FOR_UID];
+    nsslibc_memset(uid, 0, sizeof uid);
+    /* The list is traversed twice, first (here) looking to match the
+     * { token, handle } tuple, and if that is not found, below a search
+     * for unique identifier is done.  Here, a match means this exact object
+     * instance is already in the collection, and we have nothing to do.
+     */
+    *foundIt = PR_FALSE;
+    node = find_instance_in_collection(collection, instance);
+    if (node) {
+	/* The collection is assumed to take over the instance.  Since we
+	 * are not using it, it must be destroyed.
+	 */
+	nssCryptokiObject_Destroy(instance);
+	*foundIt = PR_TRUE;
+	return node;
+    }
+    mark = nssArena_Mark(collection->arena);
+    if (!mark) {
+	goto loser;
+    }
+    status = (*collection->getUIDFromInstance)(instance, uid, 
+                                               collection->arena);
+    if (status != PR_SUCCESS) {
+	goto loser;
+    }
+    /* Search for unique identifier.  A match here means the object exists 
+     * in the collection, but does not have this instance, so the instance 
+     * needs to be added.
+     */
+    node = find_object_in_collection(collection, uid);
+    if (node) {
+	/* This is an object with multiple instances */
+	status = nssPKIObject_AddInstance(node->object, instance);
+    } else {
+	/* This is a completely new object.  Create a node for it. */
+	node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
+	if (!node) {
+	    goto loser;
+	}
+	node->object = nssPKIObject_Create(NULL, instance, 
+	                                   collection->td, collection->cc,
+                                           collection->lockType);
+	if (!node->object) {
+	    goto loser;
+	}
+	for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
+	    node->uid[i] = uid[i];
+	}
+	node->haveObject = PR_FALSE;
+	PR_INIT_CLIST(&node->link);
+	PR_INSERT_BEFORE(&node->link, &collection->head);
+	collection->size++;
+	status = PR_SUCCESS;
+    }
+    nssArena_Unmark(collection->arena, mark);
+    return node;
+loser:
+    if (mark) {
+	nssArena_Release(collection->arena, mark);
+    }
+    nssCryptokiObject_Destroy(instance);
+    return (pkiObjectCollectionNode *)NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddInstances (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject **instances,
+  PRUint32 numInstances
+)
+{
+    PRStatus status = PR_SUCCESS;
+    PRUint32 i = 0;
+    PRBool foundIt;
+    pkiObjectCollectionNode *node;
+    if (instances) {
+	while ((!numInstances || i < numInstances) && *instances) {
+	    if (status == PR_SUCCESS) {
+		node = add_object_instance(collection, *instances, &foundIt);
+		if (node == NULL) {
+		    /* add_object_instance freed the current instance */
+		    /* free the remaining instances */
+		    status = PR_FAILURE;
+		}
+	    } else {
+		nssCryptokiObject_Destroy(*instances);
+	    }
+	    instances++;
+	    i++;
+	}
+    }
+    return status;
+}
+
+static void
+nssPKIObjectCollection_RemoveNode (
+   nssPKIObjectCollection *collection,
+   pkiObjectCollectionNode *node
+)
+{
+    PR_REMOVE_LINK(&node->link); 
+    collection->size--;
+}
+
+static PRStatus
+nssPKIObjectCollection_GetObjects (
+  nssPKIObjectCollection *collection,
+  nssPKIObject **rvObjects,
+  PRUint32 rvSize
+)
+{
+    PRUint32 i = 0;
+    PRCList *link = PR_NEXT_LINK(&collection->head);
+    pkiObjectCollectionNode *node;
+    int error=0;
+    while ((i < rvSize) && (link != &collection->head)) {
+	node = (pkiObjectCollectionNode *)link;
+	if (!node->haveObject) {
+	    /* Convert the proto-object to an object */
+	    node->object = (*collection->createObject)(node->object);
+	    if (!node->object) {
+		link = PR_NEXT_LINK(link);
+		/*remove bogus object from list*/
+		nssPKIObjectCollection_RemoveNode(collection,node);
+		error++;
+		continue;
+	    }
+	    node->haveObject = PR_TRUE;
+	}
+	rvObjects[i++] = nssPKIObject_AddRef(node->object);
+	link = PR_NEXT_LINK(link);
+    }
+    if (!error && *rvObjects == NULL) {
+	nss_SetError(NSS_ERROR_NOT_FOUND);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_Traverse (
+  nssPKIObjectCollection *collection,
+  nssPKIObjectCallback *callback
+)
+{
+    PRStatus status;
+    PRCList *link = PR_NEXT_LINK(&collection->head);
+    pkiObjectCollectionNode *node;
+    while (link != &collection->head) {
+	node = (pkiObjectCollectionNode *)link;
+	if (!node->haveObject) {
+	    node->object = (*collection->createObject)(node->object);
+	    if (!node->object) {
+		link = PR_NEXT_LINK(link);
+		/*remove bogus object from list*/
+		nssPKIObjectCollection_RemoveNode(collection,node);
+		continue;
+	    }
+	    node->haveObject = PR_TRUE;
+	}
+	switch (collection->objectType) {
+	case pkiObjectType_Certificate: 
+	    status = (*callback->func.cert)((NSSCertificate *)node->object, 
+	                                    callback->arg);
+	    break;
+	case pkiObjectType_CRL: 
+	    status = (*callback->func.crl)((NSSCRL *)node->object, 
+	                                   callback->arg);
+	    break;
+	case pkiObjectType_PrivateKey: 
+	    status = (*callback->func.pvkey)((NSSPrivateKey *)node->object, 
+	                                     callback->arg);
+	    break;
+	case pkiObjectType_PublicKey: 
+	    status = (*callback->func.pbkey)((NSSPublicKey *)node->object, 
+	                                     callback->arg);
+	    break;
+	}
+	link = PR_NEXT_LINK(link);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddInstanceAsObject (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject *instance
+)
+{
+    pkiObjectCollectionNode *node;
+    PRBool foundIt;
+    node = add_object_instance(collection, instance, &foundIt);
+    if (node == NULL) {
+	return PR_FAILURE;
+    }
+    if (!node->haveObject) {
+	node->object = (*collection->createObject)(node->object);
+	if (!node->object) {
+	    /*remove bogus object from list*/
+	    nssPKIObjectCollection_RemoveNode(collection,node);
+	    return PR_FAILURE;
+	}
+	node->haveObject = PR_TRUE;
+    } else if (!foundIt) {
+	/* The instance was added to a pre-existing node.  This
+	 * function is *only* being used for certificates, and having
+	 * multiple instances of certs in 3.X requires updating the
+	 * CERTCertificate.
+	 * But only do it if it was a new instance!!!  If the same instance
+	 * is encountered, we set *foundIt to true.  Detect that here and
+	 * ignore it.
+	 */
+	STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
+    }
+    return PR_SUCCESS;
+}
+
+/*
+ * Certificate collections
+ */
+
+static void
+cert_destroyObject(nssPKIObject *o)
+{
+    NSSCertificate *c = (NSSCertificate *)o;
+    if (c->decoding) {
+	CERTCertificate *cc = STAN_GetCERTCertificate(c);
+	if (cc) {
+	    CERT_DestroyCertificate(cc);
+	    return;
+	} /* else destroy it as NSSCertificate below */
+    }
+    nssCertificate_Destroy(c);
+}
+
+static PRStatus
+cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
+{
+    NSSCertificate *c = (NSSCertificate *)o;
+    /* The builtins are still returning decoded serial numbers.  Until
+     * this compatibility issue is resolved, use the full DER of the
+     * cert to uniquely identify it.
+     */
+    NSSDER *derCert;
+    derCert = nssCertificate_GetEncoding(c);
+    uid[0].data = NULL; uid[0].size = 0;
+    uid[1].data = NULL; uid[1].size = 0;
+    if (derCert != NULL) {
+	uid[0] = *derCert;
+    }
+    return PR_SUCCESS;
+}
+
+static PRStatus
+cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
+                        NSSArena *arena)
+{
+    /* The builtins are still returning decoded serial numbers.  Until
+     * this compatibility issue is resolved, use the full DER of the
+     * cert to uniquely identify it.
+     */
+    uid[1].data = NULL; uid[1].size = 0;
+    return nssCryptokiCertificate_GetAttributes(instance,
+                                                NULL,  /* XXX sessionOpt */
+                                                arena, /* arena    */
+                                                NULL,  /* type     */
+                                                NULL,  /* id       */
+                                                &uid[0], /* encoding */
+                                                NULL,  /* issuer   */
+                                                NULL,  /* serial   */
+                                                NULL);  /* subject  */
+}
+
+static nssPKIObject *
+cert_createObject(nssPKIObject *o)
+{
+    NSSCertificate *cert;
+    cert = nssCertificate_Create(o);
+/*    if (STAN_GetCERTCertificate(cert) == NULL) {
+	nssCertificate_Destroy(cert);
+	return (nssPKIObject *)NULL;
+    } */
+    /* In 3.4, have to maintain uniqueness of cert pointers by caching all
+     * certs.  Cache the cert here, before returning.  If it is already
+     * cached, take the cached entry.
+     */
+    {
+	NSSTrustDomain *td = o->trustDomain;
+	nssTrustDomain_AddCertsToCache(td, &cert, 1);
+    }
+    return (nssPKIObject *)cert;
+}
+
+NSS_IMPLEMENT nssPKIObjectCollection *
+nssCertificateCollection_Create (
+  NSSTrustDomain *td,
+  NSSCertificate **certsOpt
+)
+{
+    PRStatus status;
+    nssPKIObjectCollection *collection;
+    collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
+    collection->objectType = pkiObjectType_Certificate;
+    collection->destroyObject = cert_destroyObject;
+    collection->getUIDFromObject = cert_getUIDFromObject;
+    collection->getUIDFromInstance = cert_getUIDFromInstance;
+    collection->createObject = cert_createObject;
+    if (certsOpt) {
+	for (; *certsOpt; certsOpt++) {
+	    nssPKIObject *object = (nssPKIObject *)(*certsOpt);
+	    status = nssPKIObjectCollection_AddObject(collection, object);
+	}
+    }
+    return collection;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssPKIObjectCollection_GetCertificates (
+  nssPKIObjectCollection *collection,
+  NSSCertificate **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    PRStatus status;
+    PRUint32 rvSize;
+    PRBool allocated = PR_FALSE;
+    if (collection->size == 0) {
+	return (NSSCertificate **)NULL;
+    }
+    if (maximumOpt == 0) {
+	rvSize = collection->size;
+    } else {
+	rvSize = PR_MIN(collection->size, maximumOpt);
+    }
+    if (!rvOpt) {
+	rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
+	if (!rvOpt) {
+	    return (NSSCertificate **)NULL;
+	}
+	allocated = PR_TRUE;
+    }
+    status = nssPKIObjectCollection_GetObjects(collection, 
+                                               (nssPKIObject **)rvOpt, 
+                                               rvSize);
+    if (status != PR_SUCCESS) {
+	if (allocated) {
+	    nss_ZFreeIf(rvOpt);
+	}
+	return (NSSCertificate **)NULL;
+    }
+    return rvOpt;
+}
+
+/*
+ * CRL/KRL collections
+ */
+
+static void
+crl_destroyObject(nssPKIObject *o)
+{
+    NSSCRL *crl = (NSSCRL *)o;
+    nssCRL_Destroy(crl);
+}
+
+static PRStatus
+crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
+{
+    NSSCRL *crl = (NSSCRL *)o;
+    NSSDER *encoding;
+    encoding = nssCRL_GetEncoding(crl);
+    if (!encoding) {
+        nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+        return PR_FALSE;
+    }
+    uid[0] = *encoding;
+    uid[1].data = NULL; uid[1].size = 0;
+    return PR_SUCCESS;
+}
+
+static PRStatus
+crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
+                       NSSArena *arena)
+{
+    return nssCryptokiCRL_GetAttributes(instance,
+                                        NULL,    /* XXX sessionOpt */
+                                        arena,   /* arena    */
+                                        &uid[0], /* encoding */
+                                        NULL,    /* subject  */
+                                        NULL,    /* class    */
+                                        NULL,    /* url      */
+                                        NULL);   /* isKRL    */
+}
+
+static nssPKIObject *
+crl_createObject(nssPKIObject *o)
+{
+    return (nssPKIObject *)nssCRL_Create(o);
+}
+
+NSS_IMPLEMENT nssPKIObjectCollection *
+nssCRLCollection_Create (
+  NSSTrustDomain *td,
+  NSSCRL **crlsOpt
+)
+{
+    PRStatus status;
+    nssPKIObjectCollection *collection;
+    collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
+    collection->objectType = pkiObjectType_CRL;
+    collection->destroyObject = crl_destroyObject;
+    collection->getUIDFromObject = crl_getUIDFromObject;
+    collection->getUIDFromInstance = crl_getUIDFromInstance;
+    collection->createObject = crl_createObject;
+    if (crlsOpt) {
+	for (; *crlsOpt; crlsOpt++) {
+	    nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
+	    status = nssPKIObjectCollection_AddObject(collection, object);
+	}
+    }
+    return collection;
+}
+
+NSS_IMPLEMENT NSSCRL **
+nssPKIObjectCollection_GetCRLs (
+  nssPKIObjectCollection *collection,
+  NSSCRL **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    PRStatus status;
+    PRUint32 rvSize;
+    PRBool allocated = PR_FALSE;
+    if (collection->size == 0) {
+	return (NSSCRL **)NULL;
+    }
+    if (maximumOpt == 0) {
+	rvSize = collection->size;
+    } else {
+	rvSize = PR_MIN(collection->size, maximumOpt);
+    }
+    if (!rvOpt) {
+	rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
+	if (!rvOpt) {
+	    return (NSSCRL **)NULL;
+	}
+	allocated = PR_TRUE;
+    }
+    status = nssPKIObjectCollection_GetObjects(collection, 
+                                               (nssPKIObject **)rvOpt, 
+                                               rvSize);
+    if (status != PR_SUCCESS) {
+	if (allocated) {
+	    nss_ZFreeIf(rvOpt);
+	}
+	return (NSSCRL **)NULL;
+    }
+    return rvOpt;
+}
+
+/* how bad would it be to have a static now sitting around, updated whenever
+ * this was called?  would avoid repeated allocs...
+ */
+NSS_IMPLEMENT NSSTime *
+NSSTime_Now (
+  NSSTime *timeOpt
+)
+{
+    return NSSTime_SetPRTime(timeOpt, PR_Now());
+}
+
+NSS_IMPLEMENT NSSTime *
+NSSTime_SetPRTime (
+  NSSTime *timeOpt,
+  PRTime prTime
+)
+{
+    NSSTime *rvTime;
+    rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
+    rvTime->prTime = prTime;
+    return rvTime;
+}
+
+NSS_IMPLEMENT PRTime
+NSSTime_GetPRTime (
+  NSSTime *time
+)
+{
+  return time->prTime;
+}
+
diff --git a/mozilla/security/nss/lib/pki/pkim.h b/mozilla/security/nss/lib/pki/pkim.h
new file mode 100644
index 0000000..419d36a
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pkim.h
@@ -0,0 +1,731 @@
+/* ***** 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 ***** */
+
+#ifndef PKIM_H
+#define PKIM_H
+
+#ifdef DEBUG
+static const char PKIM_CVS_ID[] = "@(#) $RCSfile: pkim.h,v $ $Revision: 1.30 $ $Date: 2007/11/16 05:29:27 $";
+#endif /* DEBUG */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#ifndef PKI_H
+#include "pki.h"
+#endif /* PKI_H */
+
+#ifndef PKITM_H
+#include "pkitm.h"
+#endif /* PKITM_H */
+
+PR_BEGIN_EXTERN_C
+
+/* nssPKIObject
+ *
+ * This is the base object class, common to all PKI objects defined in
+ * in this module.  Each object can be safely 'casted' to an nssPKIObject,
+ * then passed to these methods.
+ *
+ * nssPKIObject_Create
+ * nssPKIObject_Destroy
+ * nssPKIObject_AddRef
+ * nssPKIObject_AddInstance
+ * nssPKIObject_HasInstance
+ * nssPKIObject_GetTokens
+ * nssPKIObject_GetNicknameForToken
+ * nssPKIObject_RemoveInstanceForToken
+ * nssPKIObject_DeleteStoredObject
+ */
+
+NSS_EXTERN void     nssPKIObject_Lock       (nssPKIObject * object);
+NSS_EXTERN void     nssPKIObject_Unlock     (nssPKIObject * object);
+NSS_EXTERN PRStatus nssPKIObject_NewLock    (nssPKIObject * object,
+                                             nssPKILockType lockType);
+NSS_EXTERN void     nssPKIObject_DestroyLock(nssPKIObject * object);
+
+/* nssPKIObject_Create
+ *
+ * A generic PKI object.  It must live in a trust domain.  It may be
+ * initialized with a token instance, or alternatively in a crypto context.
+ */
+NSS_EXTERN nssPKIObject *
+nssPKIObject_Create
+(
+  NSSArena *arenaOpt,
+  nssCryptokiObject *instanceOpt,
+  NSSTrustDomain *td,
+  NSSCryptoContext *ccOpt,
+  nssPKILockType lockType
+);
+
+/* nssPKIObject_AddRef
+ */
+NSS_EXTERN nssPKIObject *
+nssPKIObject_AddRef
+(
+  nssPKIObject *object
+);
+
+/* nssPKIObject_Destroy
+ *
+ * Returns true if object was destroyed.  This notifies the subclass that
+ * all references are gone and it should delete any members it owns.
+ */
+NSS_EXTERN PRBool
+nssPKIObject_Destroy
+(
+  nssPKIObject *object
+);
+
+/* nssPKIObject_AddInstance
+ *
+ * Add a token instance to the object, if it does not have it already.
+ */
+NSS_EXTERN PRStatus
+nssPKIObject_AddInstance
+(
+  nssPKIObject *object,
+  nssCryptokiObject *instance
+);
+
+/* nssPKIObject_HasInstance
+ *
+ * Query the object for a token instance.
+ */
+NSS_EXTERN PRBool
+nssPKIObject_HasInstance
+(
+  nssPKIObject *object,
+  nssCryptokiObject *instance
+);
+
+/* nssPKIObject_GetTokens
+ *
+ * Get all tokens which have an instance of the object.
+ */
+NSS_EXTERN NSSToken **
+nssPKIObject_GetTokens
+(
+  nssPKIObject *object,
+  PRStatus *statusOpt
+);
+
+/* nssPKIObject_GetNicknameForToken
+ *
+ * tokenOpt == NULL means take the first available, otherwise return the
+ * nickname for the specified token.
+ */
+NSS_EXTERN NSSUTF8 *
+nssPKIObject_GetNicknameForToken
+(
+  nssPKIObject *object,
+  NSSToken *tokenOpt
+);
+
+/* nssPKIObject_RemoveInstanceForToken
+ *
+ * Remove the instance of the object on the specified token.
+ */
+NSS_EXTERN PRStatus
+nssPKIObject_RemoveInstanceForToken
+(
+  nssPKIObject *object,
+  NSSToken *token
+);
+
+/* nssPKIObject_DeleteStoredObject
+ *
+ * Delete all token instances of the object, as well as any crypto context
+ * instances (TODO).  If any of the instances are read-only, or if the
+ * removal fails, the object will keep those instances.  'isFriendly' refers
+ * to the object -- can this object be removed from a friendly token without
+ * login?  For example, certificates are friendly, private keys are not.
+ * Note that if the token is not friendly, authentication will be required
+ * regardless of the value of 'isFriendly'.
+ */
+NSS_EXTERN PRStatus
+nssPKIObject_DeleteStoredObject
+(
+  nssPKIObject *object,
+  NSSCallback *uhh,
+  PRBool isFriendly
+);
+
+NSS_EXTERN nssCryptokiObject **
+nssPKIObject_GetInstances
+(
+  nssPKIObject *object
+);
+
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_FindCertificatesByID
+(
+  NSSTrustDomain *td,
+  NSSItem *id,
+  NSSCertificate **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSCRL **
+nssTrustDomain_FindCRLsBySubject
+(
+  NSSTrustDomain *td,
+  NSSDER *subject
+);
+
+/* module-private nsspki methods */
+
+NSS_EXTERN NSSCryptoContext *
+nssCryptoContext_Create
+(
+  NSSTrustDomain *td,
+  NSSCallback *uhhOpt
+);
+
+/* XXX for the collection */
+NSS_EXTERN NSSCertificate *
+nssCertificate_Create
+(
+  nssPKIObject *object
+);
+
+NSS_EXTERN PRStatus
+nssCertificate_SetCertTrust
+(
+  NSSCertificate *c,
+  NSSTrust *trust
+);
+
+NSS_EXTERN nssDecodedCert *
+nssCertificate_GetDecoding
+(
+  NSSCertificate *c
+);
+
+extern PRIntn
+nssCertificate_SubjectListSort
+(
+  void *v1,
+  void *v2
+);
+
+NSS_EXTERN nssDecodedCert *
+nssDecodedCert_Create
+(
+  NSSArena *arenaOpt,
+  NSSDER *encoding,
+  NSSCertificateType type
+);
+
+NSS_EXTERN PRStatus
+nssDecodedCert_Destroy
+(
+  nssDecodedCert *dc
+);
+
+NSS_EXTERN NSSTrust *
+nssTrust_Create
+(
+  nssPKIObject *object,
+  NSSItem *certData
+);
+
+NSS_EXTERN NSSCRL *
+nssCRL_Create
+(
+  nssPKIObject *object
+);
+
+NSS_EXTERN NSSCRL *
+nssCRL_AddRef
+(
+  NSSCRL *crl
+);
+
+NSS_EXTERN PRStatus
+nssCRL_Destroy
+(
+  NSSCRL *crl
+);
+
+NSS_EXTERN PRStatus
+nssCRL_DeleteStoredObject
+(
+  NSSCRL *crl,
+  NSSCallback *uhh
+);
+
+NSS_EXTERN NSSPrivateKey *
+nssPrivateKey_Create
+(
+  nssPKIObject *o
+);
+
+NSS_EXTERN NSSDER *
+nssCRL_GetEncoding
+(
+  NSSCRL *crl
+);
+
+NSS_EXTERN NSSPublicKey *
+nssPublicKey_Create
+(
+  nssPKIObject *object
+);
+
+/* nssCertificateArray
+ *
+ * These are being thrown around a lot, might as well group together some
+ * functionality.
+ *
+ * nssCertificateArray_Destroy
+ * nssCertificateArray_Join
+ * nssCertificateArray_FindBestCertificate
+ * nssCertificateArray_Traverse
+ */
+
+/* nssCertificateArray_Destroy
+ *
+ * Will destroy the array and the certs within it.  If the array was created
+ * in an arena, will *not* (of course) destroy the arena.  However, is safe
+ * to call this method on an arena-allocated array.
+ */
+NSS_EXTERN void
+nssCertificateArray_Destroy
+(
+  NSSCertificate **certs
+);
+
+/* nssCertificateArray_Join
+ *
+ * Join two arrays into one.  The two arrays, certs1 and certs2, should
+ * be considered invalid after a call to this function (they may be destroyed
+ * as part of the join).  certs1 and/or certs2 may be NULL.  Safe to
+ * call with arrays allocated in an arena, the result will also be in the
+ * arena.
+ */
+NSS_EXTERN NSSCertificate **
+nssCertificateArray_Join
+(
+  NSSCertificate **certs1,
+  NSSCertificate **certs2
+);
+
+/* nssCertificateArray_FindBestCertificate
+ *
+ * Use the usual { time, usage, policies } to find the best cert in the
+ * array.
+ */
+NSS_EXTERN NSSCertificate * 
+nssCertificateArray_FindBestCertificate
+(
+  NSSCertificate **certs, 
+  NSSTime *timeOpt,
+  const NSSUsage *usage,
+  NSSPolicies *policiesOpt
+);
+
+/* nssCertificateArray_Traverse
+ *
+ * Do the callback for each cert, terminate the traversal if the callback
+ * fails.
+ */
+NSS_EXTERN PRStatus
+nssCertificateArray_Traverse
+(
+  NSSCertificate **certs,
+  PRStatus (* callback)(NSSCertificate *c, void *arg),
+  void *arg
+);
+
+NSS_EXTERN void
+nssCRLArray_Destroy
+(
+  NSSCRL **crls
+);
+
+/* nssPKIObjectCollection
+ *
+ * This is a handy way to group objects together and perform operations
+ * on them.  It can also handle "proto-objects"-- references to
+ * objects instances on tokens, where the actual object hasn't 
+ * been formed yet.
+ *
+ * nssCertificateCollection_Create
+ * nssPrivateKeyCollection_Create
+ * nssPublicKeyCollection_Create
+ *
+ * If this was a language that provided for inheritance, each type would
+ * inherit all of the following methods.  Instead, there is only one
+ * type (nssPKIObjectCollection), shared among all.  This may cause
+ * confusion; an alternative would be to define all of the methods
+ * for each subtype (nssCertificateCollection_Destroy, ...), but that doesn't
+ * seem worth the code bloat..  It is left up to the caller to remember 
+ * what type of collection he/she is dealing with.
+ *
+ * nssPKIObjectCollection_Destroy
+ * nssPKIObjectCollection_Count
+ * nssPKIObjectCollection_AddObject
+ * nssPKIObjectCollection_AddInstances
+ * nssPKIObjectCollection_Traverse
+ *
+ * Back to type-specific methods.
+ *
+ * nssPKIObjectCollection_GetCertificates
+ * nssPKIObjectCollection_GetCRLs
+ * nssPKIObjectCollection_GetPrivateKeys
+ * nssPKIObjectCollection_GetPublicKeys
+ */
+
+/* nssCertificateCollection_Create
+ *
+ * Create a collection of certificates in the specified trust domain.
+ * Optionally provide a starting set of certs.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssCertificateCollection_Create
+(
+  NSSTrustDomain *td,
+  NSSCertificate **certsOpt
+);
+
+/* nssCRLCollection_Create
+ *
+ * Create a collection of CRLs/KRLs in the specified trust domain.
+ * Optionally provide a starting set of CRLs.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssCRLCollection_Create
+(
+  NSSTrustDomain *td,
+  NSSCRL **crlsOpt
+);
+
+/* nssPrivateKeyCollection_Create
+ *
+ * Create a collection of private keys in the specified trust domain.
+ * Optionally provide a starting set of keys.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssPrivateKeyCollection_Create
+(
+  NSSTrustDomain *td,
+  NSSPrivateKey **pvkOpt
+);
+
+/* nssPublicKeyCollection_Create
+ *
+ * Create a collection of public keys in the specified trust domain.
+ * Optionally provide a starting set of keys.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssPublicKeyCollection_Create
+(
+  NSSTrustDomain *td,
+  NSSPublicKey **pvkOpt
+);
+
+/* nssPKIObjectCollection_Destroy
+ */
+NSS_EXTERN void
+nssPKIObjectCollection_Destroy
+(
+  nssPKIObjectCollection *collection
+);
+
+/* nssPKIObjectCollection_Count
+ */
+NSS_EXTERN PRUint32
+nssPKIObjectCollection_Count
+(
+  nssPKIObjectCollection *collection
+);
+
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_AddObject
+(
+  nssPKIObjectCollection *collection,
+  nssPKIObject *object
+);
+
+/* nssPKIObjectCollection_AddInstances
+ *
+ * Add a set of object instances to the collection.  The instances
+ * will be sorted into any existing certs/proto-certs that may be in
+ * the collection.  The instances will be absorbed by the collection,
+ * the array should not be used after this call (except to free it).
+ *
+ * Failure means the collection is in an invalid state.
+ *
+ * numInstances = 0 means the array is NULL-terminated
+ */
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_AddInstances
+(
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject **instances,
+  PRUint32 numInstances
+);
+
+/* nssPKIObjectCollection_Traverse
+ */
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_Traverse
+(
+  nssPKIObjectCollection *collection,
+  nssPKIObjectCallback *callback
+);
+
+/* This function is being added for NSS 3.5.  It corresponds to the function
+ * nssToken_TraverseCertificates.  The idea is to use the collection during
+ * a traversal, creating certs each time a new instance is added for which
+ * a cert does not already exist.
+ */
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_AddInstanceAsObject
+(
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject *instance
+);
+
+/* nssPKIObjectCollection_GetCertificates
+ *
+ * Get all of the certificates in the collection. 
+ */
+NSS_EXTERN NSSCertificate **
+nssPKIObjectCollection_GetCertificates
+(
+  nssPKIObjectCollection *collection,
+  NSSCertificate **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSCRL **
+nssPKIObjectCollection_GetCRLs
+(
+  nssPKIObjectCollection *collection,
+  NSSCRL **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSPrivateKey **
+nssPKIObjectCollection_GetPrivateKeys
+(
+  nssPKIObjectCollection *collection,
+  NSSPrivateKey **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSPublicKey **
+nssPKIObjectCollection_GetPublicKeys
+(
+  nssPKIObjectCollection *collection,
+  NSSPublicKey **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSTime *
+NSSTime_Now
+(
+  NSSTime *timeOpt
+);
+
+NSS_EXTERN NSSTime *
+NSSTime_SetPRTime
+(
+  NSSTime *timeOpt,
+  PRTime prTime
+);
+
+NSS_EXTERN PRTime
+NSSTime_GetPRTime
+(
+  NSSTime *time
+);
+
+NSS_EXTERN nssHash *
+nssHash_CreateCertificate
+(
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+);
+
+/* 3.4 Certificate cache routines */
+
+NSS_EXTERN PRStatus
+nssTrustDomain_InitializeCache
+(
+  NSSTrustDomain *td,
+  PRUint32 cacheSize
+);
+
+NSS_EXTERN PRStatus
+nssTrustDomain_AddCertsToCache
+(
+  NSSTrustDomain *td,
+  NSSCertificate **certs,
+  PRUint32 numCerts
+);
+
+NSS_EXTERN void
+nssTrustDomain_RemoveCertFromCacheLOCKED (
+  NSSTrustDomain *td,
+  NSSCertificate *cert
+);
+
+NSS_EXTERN void
+nssTrustDomain_LockCertCache (
+  NSSTrustDomain *td
+);
+
+NSS_EXTERN void
+nssTrustDomain_UnlockCertCache (
+  NSSTrustDomain *td
+);
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_DestroyCache
+(
+  NSSTrustDomain *td
+);
+
+/* 
+ * Remove all certs for the given token from the cache.  This is
+ * needed if the token is removed.
+ */
+NSS_EXTERN PRStatus
+nssTrustDomain_RemoveTokenCertsFromCache
+(
+  NSSTrustDomain *td,
+  NSSToken *token
+);
+
+NSS_EXTERN PRStatus
+nssTrustDomain_UpdateCachedTokenCerts
+(
+  NSSTrustDomain *td,
+  NSSToken *token
+);
+
+/*
+ * Find all cached certs with this nickname (label).
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsForNicknameFromCache
+(
+  NSSTrustDomain *td,
+  const NSSUTF8 *nickname,
+  nssList *certListOpt
+);
+
+/*
+ * Find all cached certs with this email address.
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsForEmailAddressFromCache
+(
+  NSSTrustDomain *td,
+  NSSASCII7 *email,
+  nssList *certListOpt
+);
+
+/*
+ * Find all cached certs with this subject.
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsForSubjectFromCache
+(
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  nssList *certListOpt
+);
+
+/*
+ * Look for a specific cert in the cache.
+ */
+NSS_EXTERN NSSCertificate *
+nssTrustDomain_GetCertForIssuerAndSNFromCache
+(
+  NSSTrustDomain *td,
+  NSSDER *issuer,
+  NSSDER *serialNum
+);
+
+/*
+ * Look for a specific cert in the cache.
+ */
+NSS_EXTERN NSSCertificate *
+nssTrustDomain_GetCertByDERFromCache
+(
+  NSSTrustDomain *td,
+  NSSDER *der
+);
+
+/* Get all certs from the cache */
+/* XXX this is being included to make some old-style calls word, not to
+ *     say we should keep it
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsFromCache
+(
+  NSSTrustDomain *td,
+  nssList *certListOpt
+);
+
+NSS_EXTERN void
+nssTrustDomain_DumpCacheInfo
+(
+  NSSTrustDomain *td,
+  void (* cert_dump_iter)(const void *, void *, void *),
+  void *arg
+);
+
+NSS_EXTERN void
+nssCertificateList_AddReferences
+(
+  nssList *certList
+);
+
+PR_END_EXTERN_C
+
+#endif /* PKIM_H */
diff --git a/mozilla/security/nss/lib/pki/pkistore.c b/mozilla/security/nss/lib/pki/pkistore.c
new file mode 100644
index 0000000..90840e4
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pkistore.c
@@ -0,0 +1,766 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: pkistore.c,v $ $Revision: 1.33 $ $Date: 2008/06/06 01:19:30 $";
+#endif /* DEBUG */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef PKI_H
+#include "pki.h"
+#endif /* PKI_H */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#ifndef PKISTORE_H
+#include "pkistore.h"
+#endif /* PKISTORE_H */
+
+#include "cert.h"
+
+#include "prbit.h"
+
+/* 
+ * Certificate Store
+ *
+ * This differs from the cache in that it is a true storage facility.  Items
+ * stay in until they are explicitly removed.  It is only used by crypto
+ * contexts at this time, but may be more generally useful...
+ *
+ */
+
+struct nssCertificateStoreStr 
+{
+    PRBool i_alloced_arena;
+    NSSArena *arena;
+    PZLock *lock;
+    nssHash *subject;
+    nssHash *issuer_and_serial;
+};
+
+typedef struct certificate_hash_entry_str certificate_hash_entry;
+
+struct certificate_hash_entry_str
+{
+    NSSCertificate *cert;
+    NSSTrust *trust;
+    nssSMIMEProfile *profile;
+};
+
+/* forward static declarations */
+static NSSCertificate *
+nssCertStore_FindCertByIssuerAndSerialNumberLocked (
+  nssCertificateStore *store,
+  NSSDER *issuer,
+  NSSDER *serial
+);
+
+NSS_IMPLEMENT nssCertificateStore *
+nssCertificateStore_Create (
+  NSSArena *arenaOpt
+)
+{
+    NSSArena *arena;
+    nssCertificateStore *store;
+    PRBool i_alloced_arena;
+    if (arenaOpt) {
+	arena = arenaOpt;
+	i_alloced_arena = PR_FALSE;
+    } else {
+	arena = nssArena_Create();
+	if (!arena) {
+	    return NULL;
+	}
+	i_alloced_arena = PR_TRUE;
+    }
+    store = nss_ZNEW(arena, nssCertificateStore);
+    if (!store) {
+	goto loser;
+    }
+    store->lock = PZ_NewLock(nssILockOther);
+    if (!store->lock) {
+	goto loser;
+    }
+    /* Create the issuer/serial --> {cert, trust, S/MIME profile } hash */
+    store->issuer_and_serial = nssHash_CreateCertificate(arena, 0);
+    if (!store->issuer_and_serial) {
+	goto loser;
+    }
+    /* Create the subject DER --> subject list hash */
+    store->subject = nssHash_CreateItem(arena, 0);
+    if (!store->subject) {
+	goto loser;
+    }
+    store->arena = arena;
+    store->i_alloced_arena = i_alloced_arena;
+    return store;
+loser:
+    if (store) {
+	if (store->lock) {
+	    PZ_DestroyLock(store->lock);
+	}
+	if (store->issuer_and_serial) {
+	    nssHash_Destroy(store->issuer_and_serial);
+	}
+	if (store->subject) {
+	    nssHash_Destroy(store->subject);
+	}
+    }
+    if (i_alloced_arena) {
+	nssArena_Destroy(arena);
+    }
+    return NULL;
+}
+
+extern const NSSError NSS_ERROR_BUSY;
+
+NSS_IMPLEMENT PRStatus
+nssCertificateStore_Destroy (
+  nssCertificateStore *store
+)
+{
+    if (nssHash_Count(store->issuer_and_serial) > 0) {
+	nss_SetError(NSS_ERROR_BUSY);
+	return PR_FAILURE;
+    }
+    PZ_DestroyLock(store->lock);
+    nssHash_Destroy(store->issuer_and_serial);
+    nssHash_Destroy(store->subject);
+    if (store->i_alloced_arena) {
+	nssArena_Destroy(store->arena);
+    } else {
+	nss_ZFreeIf(store);
+    }
+    return PR_SUCCESS;
+}
+
+static PRStatus
+add_certificate_entry (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    PRStatus nssrv;
+    certificate_hash_entry *entry;
+    entry = nss_ZNEW(cert->object.arena, certificate_hash_entry);
+    if (!entry) {
+	return PR_FAILURE;
+    }
+    entry->cert = cert;
+    nssrv = nssHash_Add(store->issuer_and_serial, cert, entry);
+    if (nssrv != PR_SUCCESS) {
+	nss_ZFreeIf(entry);
+    }
+    return nssrv;
+}
+
+static PRStatus
+add_subject_entry (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    PRStatus nssrv;
+    nssList *subjectList;
+    subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
+    if (subjectList) {
+	/* The subject is already in, add this cert to the list */
+	nssrv = nssList_AddUnique(subjectList, cert);
+    } else {
+	/* Create a new subject list for the subject */
+	subjectList = nssList_Create(NULL, PR_FALSE);
+	if (!subjectList) {
+	    return PR_FAILURE;
+	}
+	nssList_SetSortFunction(subjectList, nssCertificate_SubjectListSort);
+	/* Add the cert entry to this list of subjects */
+	nssrv = nssList_Add(subjectList, cert);
+	if (nssrv != PR_SUCCESS) {
+	    return nssrv;
+	}
+	/* Add the subject list to the cache */
+	nssrv = nssHash_Add(store->subject, &cert->subject, subjectList);
+    }
+    return nssrv;
+}
+
+/* declared below */
+static void
+remove_certificate_entry (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+);
+
+/* Caller must hold store->lock */
+static PRStatus
+nssCertificateStore_AddLocked (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    PRStatus nssrv = add_certificate_entry(store, cert);
+    if (nssrv == PR_SUCCESS) {
+	nssrv = add_subject_entry(store, cert);
+	if (nssrv == PR_FAILURE) {
+	    remove_certificate_entry(store, cert);
+	}
+    }
+    return nssrv;
+}
+
+
+NSS_IMPLEMENT NSSCertificate *
+nssCertificateStore_FindOrAdd (
+  nssCertificateStore *store,
+  NSSCertificate *c
+)
+{
+    PRStatus nssrv;
+    NSSCertificate *rvCert = NULL;
+
+    PZ_Lock(store->lock);
+    rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked(
+					   store, &c->issuer, &c->serial);
+    if (!rvCert) {
+	nssrv = nssCertificateStore_AddLocked(store, c);
+	if (PR_SUCCESS == nssrv) {
+	    rvCert = nssCertificate_AddRef(c);
+	}
+    }
+    PZ_Unlock(store->lock);
+    return rvCert;
+}
+
+static void
+remove_certificate_entry (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    certificate_hash_entry *entry;
+    entry = (certificate_hash_entry *)
+                             nssHash_Lookup(store->issuer_and_serial, cert);
+    if (entry) {
+	nssHash_Remove(store->issuer_and_serial, cert);
+	if (entry->trust) {
+	    nssTrust_Destroy(entry->trust);
+	}
+	if (entry->profile) {
+	    nssSMIMEProfile_Destroy(entry->profile);
+	}
+	nss_ZFreeIf(entry);
+    }
+}
+
+static void
+remove_subject_entry (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    nssList *subjectList;
+    /* Get the subject list for the cert's subject */
+    subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
+    if (subjectList) {
+	/* Remove the cert from the subject hash */
+	nssList_Remove(subjectList, cert);
+	nssHash_Remove(store->subject, &cert->subject);
+	if (nssList_Count(subjectList) == 0) {
+	    nssList_Destroy(subjectList);
+	} else {
+	    /* The cert being released may have keyed the subject entry.
+	     * Since there are still subject certs around, get another and
+	     * rekey the entry just in case.
+	     */
+	    NSSCertificate *subjectCert;
+	    (void)nssList_GetArray(subjectList, (void **)&subjectCert, 1);
+	    nssHash_Add(store->subject, &subjectCert->subject, subjectList);
+	}
+    }
+}
+
+NSS_IMPLEMENT void
+nssCertificateStore_RemoveCertLOCKED (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    certificate_hash_entry *entry;
+    entry = (certificate_hash_entry *)
+                              nssHash_Lookup(store->issuer_and_serial, cert);
+    if (entry && entry->cert == cert) {
+	remove_certificate_entry(store, cert);
+	remove_subject_entry(store, cert);
+    }
+}
+
+NSS_IMPLEMENT void
+nssCertificateStore_Lock (
+  nssCertificateStore *store, nssCertificateStoreTrace* out
+)
+{
+#ifdef DEBUG
+    PORT_Assert(out);
+    out->store = store;
+    out->lock = store->lock;
+    out->locked = PR_TRUE;
+    PZ_Lock(out->lock);
+#else
+    PZ_Lock(store->lock);
+#endif
+}
+
+NSS_IMPLEMENT void
+nssCertificateStore_Unlock (
+  nssCertificateStore *store, const nssCertificateStoreTrace* in,
+  nssCertificateStoreTrace* out
+)
+{
+#ifdef DEBUG
+    PORT_Assert(in);
+    PORT_Assert(out);
+    out->store = store;
+    out->lock = store->lock;
+    PORT_Assert(!out->locked);
+    out->unlocked = PR_TRUE;
+
+    PORT_Assert(in->store == out->store);
+    PORT_Assert(in->lock == out->lock);
+    PORT_Assert(in->locked);
+    PORT_Assert(!in->unlocked);
+
+    PZ_Unlock(out->lock);
+#else
+    PZ_Unlock(store->lock);
+#endif
+}
+
+static NSSCertificate **
+get_array_from_list (
+  nssList *certList,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    PRUint32 count;
+    NSSCertificate **rvArray = NULL;
+    count = nssList_Count(certList);
+    if (count == 0) {
+	return NULL;
+    }
+    if (maximumOpt > 0) {
+	count = PR_MIN(maximumOpt, count);
+    }
+    if (rvOpt) {
+	nssList_GetArray(certList, (void **)rvOpt, count);
+    } else {
+	rvArray = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1);
+	if (rvArray) {
+	    nssList_GetArray(certList, (void **)rvArray, count);
+	}
+    }
+    return rvArray;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssCertificateStore_FindCertificatesBySubject (
+  nssCertificateStore *store,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    NSSCertificate **rvArray = NULL;
+    nssList *subjectList;
+    PZ_Lock(store->lock);
+    subjectList = (nssList *)nssHash_Lookup(store->subject, subject);
+    if (subjectList) {
+	nssCertificateList_AddReferences(subjectList);
+	rvArray = get_array_from_list(subjectList, 
+	                              rvOpt, maximumOpt, arenaOpt);
+    }
+    PZ_Unlock(store->lock);
+    return rvArray;
+}
+
+/* Because only subject indexing is implemented, all other lookups require
+ * full traversal (unfortunately, PLHashTable doesn't allow you to exit
+ * early from the enumeration).  The assumptions are that 1) lookups by 
+ * fields other than subject will be rare, and 2) the hash will not have
+ * a large number of entries.  These assumptions will be tested.
+ *
+ * XXX
+ * For NSS 3.4, it is worth consideration to do all forms of indexing,
+ * because the only crypto context is global and persistent.
+ */
+
+struct nickname_template_str
+{
+    NSSUTF8 *nickname;
+    nssList *subjectList;
+};
+
+static void match_nickname(const void *k, void *v, void *a)
+{
+    PRStatus nssrv;
+    NSSCertificate *c;
+    NSSUTF8 *nickname;
+    nssList *subjectList = (nssList *)v;
+    struct nickname_template_str *nt = (struct nickname_template_str *)a;
+    nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
+    nickname = nssCertificate_GetNickname(c, NULL);
+    if (nssrv == PR_SUCCESS && nickname &&
+         nssUTF8_Equal(nickname, nt->nickname, &nssrv)) 
+    {
+	nt->subjectList = subjectList;
+    }
+}
+
+/*
+ * Find all cached certs with this label.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssCertificateStore_FindCertificatesByNickname (
+  nssCertificateStore *store,
+  const NSSUTF8 *nickname,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    NSSCertificate **rvArray = NULL;
+    struct nickname_template_str nt;
+    nt.nickname = (char*) nickname;
+    nt.subjectList = NULL;
+    PZ_Lock(store->lock);
+    nssHash_Iterate(store->subject, match_nickname, &nt);
+    if (nt.subjectList) {
+	nssCertificateList_AddReferences(nt.subjectList);
+	rvArray = get_array_from_list(nt.subjectList, 
+	                              rvOpt, maximumOpt, arenaOpt);
+    }
+    PZ_Unlock(store->lock);
+    return rvArray;
+}
+
+struct email_template_str
+{
+    NSSASCII7 *email;
+    nssList *emailList;
+};
+
+static void match_email(const void *k, void *v, void *a)
+{
+    PRStatus nssrv;
+    NSSCertificate *c;
+    nssList *subjectList = (nssList *)v;
+    struct email_template_str *et = (struct email_template_str *)a;
+    nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
+    if (nssrv == PR_SUCCESS && 
+         nssUTF8_Equal(c->email, et->email, &nssrv)) 
+    {
+	nssListIterator *iter = nssList_CreateIterator(subjectList);
+	if (iter) {
+	    for (c  = (NSSCertificate *)nssListIterator_Start(iter);
+	         c != (NSSCertificate *)NULL;
+	         c  = (NSSCertificate *)nssListIterator_Next(iter))
+	    {
+		nssList_Add(et->emailList, c);
+	    }
+	    nssListIterator_Finish(iter);
+	    nssListIterator_Destroy(iter);
+	}
+    }
+}
+
+/*
+ * Find all cached certs with this email address.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssCertificateStore_FindCertificatesByEmail (
+  nssCertificateStore *store,
+  NSSASCII7 *email,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    NSSCertificate **rvArray = NULL;
+    struct email_template_str et;
+    et.email = email;
+    et.emailList = nssList_Create(NULL, PR_FALSE);
+    if (!et.emailList) {
+	return NULL;
+    }
+    PZ_Lock(store->lock);
+    nssHash_Iterate(store->subject, match_email, &et);
+    if (et.emailList) {
+	/* get references before leaving the store's lock protection */
+	nssCertificateList_AddReferences(et.emailList);
+    }
+    PZ_Unlock(store->lock);
+    if (et.emailList) {
+	rvArray = get_array_from_list(et.emailList, 
+	                              rvOpt, maximumOpt, arenaOpt);
+	nssList_Destroy(et.emailList);
+    }
+    return rvArray;
+}
+
+/* Caller holds store->lock */
+static NSSCertificate *
+nssCertStore_FindCertByIssuerAndSerialNumberLocked (
+  nssCertificateStore *store,
+  NSSDER *issuer,
+  NSSDER *serial
+)
+{
+    certificate_hash_entry *entry;
+    NSSCertificate *rvCert = NULL;
+    NSSCertificate index;
+
+    index.issuer = *issuer;
+    index.serial = *serial;
+    entry = (certificate_hash_entry *)
+                           nssHash_Lookup(store->issuer_and_serial, &index);
+    if (entry) {
+	rvCert = nssCertificate_AddRef(entry->cert);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssCertificateStore_FindCertificateByIssuerAndSerialNumber (
+  nssCertificateStore *store,
+  NSSDER *issuer,
+  NSSDER *serial
+)
+{
+    NSSCertificate *rvCert = NULL;
+
+    PZ_Lock(store->lock);
+    rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked (
+                           store, issuer, serial);
+    PZ_Unlock(store->lock);
+    return rvCert;
+}
+
+static PRStatus
+issuer_and_serial_from_encoding (
+  NSSBER *encoding, 
+  NSSDER *issuer, 
+  NSSDER *serial
+)
+{
+    SECItem derCert, derIssuer, derSerial;
+    SECStatus secrv;
+    derCert.data = (unsigned char *)encoding->data;
+    derCert.len = encoding->size;
+    secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
+    if (secrv != SECSuccess) {
+	return PR_FAILURE;
+    }
+    secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
+    if (secrv != SECSuccess) {
+	PORT_Free(derIssuer.data);
+	return PR_FAILURE;
+    }
+    issuer->data = derIssuer.data;
+    issuer->size = derIssuer.len;
+    serial->data = derSerial.data;
+    serial->size = derSerial.len;
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssCertificateStore_FindCertificateByEncodedCertificate (
+  nssCertificateStore *store,
+  NSSDER *encoding
+)
+{
+    PRStatus nssrv = PR_FAILURE;
+    NSSDER issuer, serial;
+    NSSCertificate *rvCert = NULL;
+    nssrv = issuer_and_serial_from_encoding(encoding, &issuer, &serial);
+    if (nssrv != PR_SUCCESS) {
+	return NULL;
+    }
+    rvCert = nssCertificateStore_FindCertificateByIssuerAndSerialNumber(store, 
+                                                                     &issuer, 
+                                                                     &serial);
+    PORT_Free(issuer.data);
+    PORT_Free(serial.data);
+    return rvCert;
+}
+
+NSS_EXTERN PRStatus
+nssCertificateStore_AddTrust (
+  nssCertificateStore *store,
+  NSSTrust *trust
+)
+{
+    NSSCertificate *cert;
+    certificate_hash_entry *entry;
+    cert = trust->certificate;
+    PZ_Lock(store->lock);
+    entry = (certificate_hash_entry *)
+                              nssHash_Lookup(store->issuer_and_serial, cert);
+    if (entry) {
+	entry->trust = nssTrust_AddRef(trust);
+    }
+    PZ_Unlock(store->lock);
+    return (entry) ? PR_SUCCESS : PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssCertificateStore_FindTrustForCertificate (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    certificate_hash_entry *entry;
+    NSSTrust *rvTrust = NULL;
+    PZ_Lock(store->lock);
+    entry = (certificate_hash_entry *)
+                              nssHash_Lookup(store->issuer_and_serial, cert);
+    if (entry && entry->trust) {
+	rvTrust = nssTrust_AddRef(entry->trust);
+    }
+    PZ_Unlock(store->lock);
+    return rvTrust;
+}
+
+NSS_EXTERN PRStatus
+nssCertificateStore_AddSMIMEProfile (
+  nssCertificateStore *store,
+  nssSMIMEProfile *profile
+)
+{
+    NSSCertificate *cert;
+    certificate_hash_entry *entry;
+    cert = profile->certificate;
+    PZ_Lock(store->lock);
+    entry = (certificate_hash_entry *)
+                              nssHash_Lookup(store->issuer_and_serial, cert);
+    if (entry) {
+	entry->profile = nssSMIMEProfile_AddRef(profile);
+    }
+    PZ_Unlock(store->lock);
+    return (entry) ? PR_SUCCESS : PR_FAILURE;
+}
+
+NSS_IMPLEMENT nssSMIMEProfile *
+nssCertificateStore_FindSMIMEProfileForCertificate (
+  nssCertificateStore *store,
+  NSSCertificate *cert
+)
+{
+    certificate_hash_entry *entry;
+    nssSMIMEProfile *rvProfile = NULL;
+    PZ_Lock(store->lock);
+    entry = (certificate_hash_entry *)
+                              nssHash_Lookup(store->issuer_and_serial, cert);
+    if (entry && entry->profile) {
+	rvProfile = nssSMIMEProfile_AddRef(entry->profile);
+    }
+    PZ_Unlock(store->lock);
+    return rvProfile;
+}
+
+/* XXX this is also used by cache and should be somewhere else */
+
+static PLHashNumber
+nss_certificate_hash (
+  const void *key
+)
+{
+    unsigned int i;
+    PLHashNumber h;
+    NSSCertificate *c = (NSSCertificate *)key;
+    h = 0;
+    for (i=0; i<c->issuer.size; i++)
+	h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->issuer.data)[i];
+    for (i=0; i<c->serial.size; i++)
+	h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->serial.data)[i];
+    return h;
+}
+
+static int
+nss_compare_certs(const void *v1, const void *v2)
+{
+    PRStatus ignore;
+    NSSCertificate *c1 = (NSSCertificate *)v1;
+    NSSCertificate *c2 = (NSSCertificate *)v2;
+    return (int)(nssItem_Equal(&c1->issuer, &c2->issuer, &ignore) &&
+                 nssItem_Equal(&c1->serial, &c2->serial, &ignore));
+}
+
+NSS_IMPLEMENT nssHash *
+nssHash_CreateCertificate (
+  NSSArena *arenaOpt,
+  PRUint32 numBuckets
+)
+{
+    return nssHash_Create(arenaOpt, 
+                          numBuckets, 
+                          nss_certificate_hash, 
+                          nss_compare_certs, 
+                          PL_CompareValues);
+}
+
+NSS_IMPLEMENT void
+nssCertificateStore_DumpStoreInfo (
+  nssCertificateStore *store,
+  void (* cert_dump_iter)(const void *, void *, void *),
+  void *arg
+)
+{
+    PZ_Lock(store->lock);
+    nssHash_Iterate(store->issuer_and_serial, cert_dump_iter, arg);
+    PZ_Unlock(store->lock);
+}
+
diff --git a/mozilla/security/nss/lib/pki/pkistore.h b/mozilla/security/nss/lib/pki/pkistore.h
new file mode 100644
index 0000000..a45f414
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pkistore.h
@@ -0,0 +1,204 @@
+/* ***** 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 ***** */
+
+#ifndef PKISTORE_H
+#define PKISTORE_H
+
+#ifdef DEBUG
+static const char PKISTORE_CVS_ID[] = "@(#) $RCSfile: pkistore.h,v $ $Revision: 1.12 $ $Date: 2008/06/06 01:19:31 $";
+#endif /* DEBUG */
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+PR_BEGIN_EXTERN_C
+
+/* 
+ * PKI Stores
+ *
+ * This is a set of routines for managing local stores of PKI objects.
+ * Currently, the only application is in crypto contexts, where the
+ * certificate store is used.  In the future, methods should be added
+ * here for storing local references to keys.
+ */
+
+/* 
+ * nssCertificateStore
+ *
+ * Manages local store of certificate, trust, and S/MIME profile objects.
+ * Within a crypto context, mappings of cert to trust and cert to S/MIME
+ * profile are always 1-1.  Therefore, it is reasonable to store all objects
+ * in a single collection, indexed by the certificate.
+ */
+
+NSS_EXTERN nssCertificateStore *
+nssCertificateStore_Create
+(
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN PRStatus
+nssCertificateStore_Destroy
+(
+  nssCertificateStore *store
+);
+
+/* Atomic Find cert in store, or add this cert to the store.
+** Ref counts properly maintained.
+*/
+NSS_EXTERN NSSCertificate *
+nssCertificateStore_FindOrAdd 
+(
+  nssCertificateStore *store,
+  NSSCertificate *c
+);
+
+NSS_EXTERN void
+nssCertificateStore_RemoveCertLOCKED
+(
+  nssCertificateStore *store,
+  NSSCertificate *cert
+);
+
+struct nssCertificateStoreTraceStr {
+    nssCertificateStore* store;
+    PZLock* lock;
+    PRBool locked;
+    PRBool unlocked;
+};
+
+typedef struct nssCertificateStoreTraceStr nssCertificateStoreTrace;
+
+NSS_EXTERN void
+nssCertificateStore_Lock (
+  nssCertificateStore *store, nssCertificateStoreTrace* out
+);
+
+NSS_EXTERN void
+nssCertificateStore_Unlock (
+  nssCertificateStore *store, const nssCertificateStoreTrace* in,
+  nssCertificateStoreTrace* out
+);
+
+NSS_EXTERN NSSCertificate **
+nssCertificateStore_FindCertificatesBySubject
+(
+  nssCertificateStore *store,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSCertificate **
+nssCertificateStore_FindCertificatesByNickname
+(
+  nssCertificateStore *store,
+  const NSSUTF8 *nickname,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSCertificate **
+nssCertificateStore_FindCertificatesByEmail
+(
+  nssCertificateStore *store,
+  NSSASCII7 *email,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+);
+
+NSS_EXTERN NSSCertificate *
+nssCertificateStore_FindCertificateByIssuerAndSerialNumber
+(
+  nssCertificateStore *store,
+  NSSDER *issuer,
+  NSSDER *serial
+);
+
+NSS_EXTERN NSSCertificate *
+nssCertificateStore_FindCertificateByEncodedCertificate
+(
+  nssCertificateStore *store,
+  NSSDER *encoding
+);
+
+NSS_EXTERN PRStatus
+nssCertificateStore_AddTrust
+(
+  nssCertificateStore *store,
+  NSSTrust *trust
+);
+
+NSS_EXTERN NSSTrust *
+nssCertificateStore_FindTrustForCertificate
+(
+  nssCertificateStore *store,
+  NSSCertificate *cert
+);
+
+NSS_EXTERN PRStatus
+nssCertificateStore_AddSMIMEProfile
+(
+  nssCertificateStore *store,
+  nssSMIMEProfile *profile
+);
+
+NSS_EXTERN nssSMIMEProfile *
+nssCertificateStore_FindSMIMEProfileForCertificate
+(
+  nssCertificateStore *store,
+  NSSCertificate *cert
+);
+
+NSS_EXTERN void
+nssCertificateStore_DumpStoreInfo
+(
+  nssCertificateStore *store,
+  void (* cert_dump_iter)(const void *, void *, void *),
+  void *arg
+);
+
+PR_END_EXTERN_C
+
+#endif /* PKISTORE_H */
diff --git a/mozilla/security/nss/lib/pki/pkit.h b/mozilla/security/nss/lib/pki/pkit.h
new file mode 100644
index 0000000..15d6c16
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pkit.h
@@ -0,0 +1,224 @@
+/* ***** 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 ***** */
+
+#ifndef PKIT_H
+#define PKIT_H
+
+#ifdef DEBUG
+static const char PKIT_CVS_ID[] = "@(#) $RCSfile: pkit.h,v $ $Revision: 1.19 $ $Date: 2007/11/16 05:29:27 $";
+#endif /* DEBUG */
+
+/*
+ * pkit.h
+ *
+ * This file contains definitions for the types of the top-level PKI objects.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+#ifndef BASET_H
+#include "baset.h"
+#endif /* BASET_H */
+
+#include "certt.h"
+#include "pkcs11t.h"
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef DEVT_H
+#include "devt.h"
+#endif /* DEVT_H */
+
+#ifndef nssrwlkt_h__
+#include "nssrwlkt.h"
+#endif /* nssrwlkt_h__ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A note on ephemeral certs
+ *
+ * The key objects defined here can only be created on tokens, and can only
+ * exist on tokens.  Therefore, any instance of a key object must have
+ * a corresponding cryptoki instance.  OTOH, certificates created in 
+ * crypto contexts need not be stored as session objects on the token.
+ * There are good performance reasons for not doing so.  The certificate
+ * and trust objects have been defined with a cryptoContext field to
+ * allow for ephemeral certs, which may have a single instance in a crypto
+ * context along with any number (including zero) of cryptoki instances.
+ * Since contexts may not share objects, there can be only one context
+ * for each object.
+ */
+
+typedef enum {
+    nssPKILock = 1,
+    nssPKIMonitor = 2
+} nssPKILockType;
+
+/* nssPKIObject
+ *
+ * This is the base object class, common to all PKI objects defined in
+ * nsspkit.h
+ */
+struct nssPKIObjectStr 
+{
+    /* The arena for all object memory */
+    NSSArena *arena;
+    /* Atomically incremented/decremented reference counting */
+    PRInt32 refCount;
+    /* lock protects the array of nssCryptokiInstance's of the object */
+    union {
+        PZLock* lock;
+        PZMonitor *mlock;
+    } sync;
+    nssPKILockType lockType;
+    /* XXX with LRU cache, this cannot be guaranteed up-to-date.  It cannot
+     * be compared against the update level of the trust domain, since it is
+     * also affected by import/export.  Where is this array needed?
+     */
+    nssCryptokiObject **instances;
+    PRUint32 numInstances;
+    /* The object must live in a trust domain */
+    NSSTrustDomain *trustDomain;
+    /* The object may live in a crypto context */
+    NSSCryptoContext *cryptoContext;
+    /* XXX added so temp certs can have nickname, think more ... */
+    NSSUTF8 *tempName;
+};
+
+typedef struct nssDecodedCertStr nssDecodedCert;
+
+typedef struct nssCertificateStoreStr nssCertificateStore;
+
+/* How wide is the scope of this? */
+typedef struct nssSMIMEProfileStr nssSMIMEProfile;
+
+typedef struct nssPKIObjectStr nssPKIObject;
+
+struct NSSTrustStr 
+{
+    nssPKIObject object;
+    NSSCertificate *certificate;
+    nssTrustLevel serverAuth;
+    nssTrustLevel clientAuth;
+    nssTrustLevel emailProtection;
+    nssTrustLevel codeSigning;
+    PRBool stepUpApproved;
+};
+
+struct nssSMIMEProfileStr
+{
+    nssPKIObject object;
+    NSSCertificate *certificate;
+    NSSASCII7 *email;
+    NSSDER *subject;
+    NSSItem *profileTime;
+    NSSItem *profileData;
+};
+
+struct NSSCertificateStr
+{
+    nssPKIObject object;
+    NSSCertificateType type;
+    NSSItem id;
+    NSSBER encoding;
+    NSSDER issuer;
+    NSSDER subject;
+    NSSDER serial;
+    NSSASCII7 *email;
+    nssDecodedCert *decoding;
+};
+
+struct NSSPrivateKeyStr;
+
+struct NSSPublicKeyStr;
+
+struct NSSSymmetricKeyStr;
+
+typedef struct nssTDCertificateCacheStr nssTDCertificateCache;
+
+struct NSSTrustDomainStr {
+    PRInt32 refCount;
+    NSSArena *arena;
+    NSSCallback *defaultCallback;
+    nssList *tokenList;
+    nssListIterator *tokens;
+    nssTDCertificateCache *cache;
+    NSSRWLock *tokensLock;
+    void *spkDigestInfo;
+    CERTStatusConfig *statusConfig;
+};
+
+struct NSSCryptoContextStr
+{
+    PRInt32 refCount;
+    NSSArena *arena;
+    NSSTrustDomain *td;
+    NSSToken *token;
+    nssSession *session;
+    nssCertificateStore *certStore;
+};
+
+struct NSSTimeStr {
+    PRTime prTime;
+};
+
+struct NSSCRLStr {
+  nssPKIObject object;
+  NSSDER encoding;
+  NSSUTF8 *url;
+  PRBool isKRL;
+};
+
+typedef struct NSSCRLStr NSSCRL;
+
+struct NSSPoliciesStr;
+
+struct NSSAlgorithmAndParametersStr;
+
+struct NSSPKIXCertificateStr;
+
+PR_END_EXTERN_C
+
+#endif /* PKIT_H */
diff --git a/mozilla/security/nss/lib/pki/pkitm.h b/mozilla/security/nss/lib/pki/pkitm.h
new file mode 100644
index 0000000..a0ebba9
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/pkitm.h
@@ -0,0 +1,121 @@
+/* ***** 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 ***** */
+
+#ifndef PKITM_H
+#define PKITM_H
+
+#ifdef DEBUG
+static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.15 $ $Date: 2007/11/16 05:29:27 $";
+#endif /* DEBUG */
+
+/*
+ * pkitm.h
+ *
+ * This file contains PKI-module specific types.
+ */
+
+#ifndef BASET_H
+#include "baset.h"
+#endif /* BASET_H */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+PR_BEGIN_EXTERN_C
+
+typedef enum nssCertIDMatchEnum {
+  nssCertIDMatch_Yes = 0,
+  nssCertIDMatch_No = 1,
+  nssCertIDMatch_Unknown = 2
+} nssCertIDMatch;
+
+/*
+ * nssDecodedCert
+ *
+ * This is an interface to allow the PKI module access to certificate
+ * information that can only be found by decoding.  The interface is
+ * generic, allowing each certificate type its own way of providing
+ * the information
+ */
+struct nssDecodedCertStr {
+    NSSCertificateType type;
+    void *data;
+    /* returns the unique identifier for the cert */
+    NSSItem *  (*getIdentifier)(nssDecodedCert *dc);
+    /* returns the unique identifier for this cert's issuer */
+    void *     (*getIssuerIdentifier)(nssDecodedCert *dc);
+    /* is id the identifier for this cert? */
+    nssCertIDMatch (*matchIdentifier)(nssDecodedCert *dc, void *id);
+    /* is this cert a valid CA cert? */
+    PRBool     (*isValidIssuer)(nssDecodedCert *dc);
+    /* returns the cert usage */
+    NSSUsage * (*getUsage)(nssDecodedCert *dc);
+    /* is time within the validity period of the cert? */
+    PRBool     (*isValidAtTime)(nssDecodedCert *dc, NSSTime *time);
+    /* is the validity period of this cert newer than cmpdc? */
+    PRBool     (*isNewerThan)(nssDecodedCert *dc, nssDecodedCert *cmpdc);
+    /* does the usage for this cert match the requested usage? */
+    PRBool     (*matchUsage)(nssDecodedCert *dc, const NSSUsage *usage);
+    /* extract the email address */
+    NSSASCII7 *(*getEmailAddress)(nssDecodedCert *dc);
+    /* extract the DER-encoded serial number */
+    PRStatus   (*getDERSerialNumber)(nssDecodedCert *dc,
+                                     NSSDER *derSerial, NSSArena *arena);
+};
+
+struct NSSUsageStr {
+    PRBool anyUsage;
+    SECCertUsage nss3usage;
+    PRBool nss3lookingForCA;
+};
+
+typedef struct nssPKIObjectCollectionStr nssPKIObjectCollection;
+
+typedef struct
+{
+  union {
+    PRStatus (*  cert)(NSSCertificate *c, void *arg);
+    PRStatus (*   crl)(NSSCRL       *crl, void *arg);
+    PRStatus (* pvkey)(NSSPrivateKey *vk, void *arg);
+    PRStatus (* pbkey)(NSSPublicKey *bk, void *arg);
+  } func;
+  void *arg;
+} nssPKIObjectCallback;
+
+PR_END_EXTERN_C
+
+#endif /* PKITM_H */
diff --git a/mozilla/security/nss/lib/pki/symmkey.c b/mozilla/security/nss/lib/pki/symmkey.c
new file mode 100644
index 0000000..036a9bd
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/symmkey.c
@@ -0,0 +1,300 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: symmkey.c,v $ $Revision: 1.6 $ $Date: 2005/01/20 02:25:49 $";
+#endif /* DEBUG */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_Destroy (
+  NSSSymmetricKey *mk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_DeleteStoredObject (
+  NSSSymmetricKey *mk,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSSymmetricKey_GetKeyLength (
+  NSSSymmetricKey *mk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return -1;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSSymmetricKey_GetKeyStrength (
+  NSSSymmetricKey *mk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return -1;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_IsStillPresent (
+  NSSSymmetricKey *mk
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSSymmetricKey_GetTrustDomain (
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSSymmetricKey_GetToken (
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSSymmetricKey_GetSlot (
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSSymmetricKey_GetModule (
+  NSSSymmetricKey *mk,
+  PRStatus *statusOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_Encrypt (
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_Decrypt (
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *encryptedData,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_Sign (
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_SignRecover (
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_Verify (
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *data,
+  NSSItem *signature,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_VerifyRecover (
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *signature,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_WrapSymmetricKey (
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSSymmetricKey *keyToWrap,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_WrapPrivateKey (
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPrivateKey *keyToWrap,
+  NSSCallback *uhh,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSSymmetricKey_UnwrapSymmetricKey (
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSOID *target,
+  PRUint32 keySizeOpt,
+  NSSOperations operations,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSSymmetricKey_UnwrapPrivateKey (
+  NSSSymmetricKey *wrappingKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSItem *wrappedKey,
+  NSSUTF8 *labelOpt,
+  NSSItem *keyIDOpt,
+  PRBool persistant,
+  PRBool sensitive,
+  NSSToken *destinationOpt,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSSymmetricKey_DeriveSymmetricKey (
+  NSSSymmetricKey *originalKey,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSOID *target,
+  PRUint32 keySizeOpt,
+  NSSOperations operations,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSSymmetricKey_CreateCryptoContext (
+  NSSSymmetricKey *mk,
+  NSSAlgorithmAndParameters *apOpt,
+  NSSCallback *uhh
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
diff --git a/mozilla/security/nss/lib/pki/tdcache.c b/mozilla/security/nss/lib/pki/tdcache.c
new file mode 100644
index 0000000..fb1adef
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/tdcache.c
@@ -0,0 +1,1178 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.48 $ $Date: 2008/11/19 16:08:05 $";
+#endif /* DEBUG */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef PKI_H
+#include "pki.h"
+#endif /* PKI_H */
+
+#ifndef NSSBASE_H
+#include "nssbase.h"
+#endif /* NSSBASE_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#include "cert.h"
+#include "dev.h"
+#include "pki3hack.h"
+
+#ifdef DEBUG_CACHE
+static PRLogModuleInfo *s_log = NULL;
+#endif
+
+#ifdef DEBUG_CACHE
+static void log_item_dump(const char *msg, NSSItem *it)
+{
+    char buf[33];
+    int i, j;
+    for (i=0; i<10 && i<it->size; i++) {
+	sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[i]);
+    }
+    if (it->size>10) {
+	sprintf(&buf[2*i], "..");
+	i += 1;
+	for (j=it->size-1; i<=16 && j>10; i++, j--) {
+	    sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[j]);
+	}
+    }
+    PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, buf));
+}
+#endif
+
+#ifdef DEBUG_CACHE
+static void log_cert_ref(const char *msg, NSSCertificate *c)
+{
+    PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg,
+                           (c->nickname) ? c->nickname : c->email));
+    log_item_dump("\tserial", &c->serial);
+    log_item_dump("\tsubject", &c->subject);
+}
+#endif
+
+/* Certificate cache routines */
+
+/* XXX
+ * Locking is not handled well at all.  A single, global lock with sub-locks
+ * in the collection types.  Cleanup needed.
+ */
+
+/* should it live in its own arena? */
+struct nssTDCertificateCacheStr 
+{
+    PZLock *lock;
+    NSSArena *arena;
+    nssHash *issuerAndSN;
+    nssHash *subject;
+    nssHash *nickname;
+    nssHash *email;
+};
+
+struct cache_entry_str 
+{
+    union {
+	NSSCertificate *cert;
+	nssList *list;
+	void *value;
+    } entry;
+    PRUint32 hits;
+    PRTime lastHit;
+    NSSArena *arena;
+    NSSUTF8 *nickname;
+};
+
+typedef struct cache_entry_str cache_entry;
+
+static cache_entry *
+new_cache_entry(NSSArena *arena, void *value, PRBool ownArena)
+{
+    cache_entry *ce = nss_ZNEW(arena, cache_entry);
+    if (ce) {
+	ce->entry.value = value;
+	ce->hits = 1;
+	ce->lastHit = PR_Now();
+	if (ownArena) {
+	    ce->arena = arena;
+	}
+	ce->nickname = NULL;
+    }
+    return ce;
+}
+
+/* this should not be exposed in a header, but is here to keep the above
+ * types/functions static
+ */
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_InitializeCache (
+  NSSTrustDomain *td,
+  PRUint32 cacheSize
+)
+{
+    NSSArena *arena;
+    nssTDCertificateCache *cache = td->cache;
+#ifdef DEBUG_CACHE
+    s_log = PR_NewLogModule("nss_cache");
+    PR_ASSERT(s_log);
+#endif
+    PR_ASSERT(!cache);
+    arena = nssArena_Create();
+    if (!arena) {
+	return PR_FAILURE;
+    }
+    cache = nss_ZNEW(arena, nssTDCertificateCache);
+    if (!cache) {
+	nssArena_Destroy(arena);
+	return PR_FAILURE;
+    }
+    cache->lock = PZ_NewLock(nssILockCache);
+    if (!cache->lock) {
+	nssArena_Destroy(arena);
+	return PR_FAILURE;
+    }
+    /* Create the issuer and serial DER --> certificate hash */
+    cache->issuerAndSN = nssHash_CreateCertificate(arena, cacheSize);
+    if (!cache->issuerAndSN) {
+	goto loser;
+    }
+    /* Create the subject DER --> subject list hash */
+    cache->subject = nssHash_CreateItem(arena, cacheSize);
+    if (!cache->subject) {
+	goto loser;
+    }
+    /* Create the nickname --> subject list hash */
+    cache->nickname = nssHash_CreateString(arena, cacheSize);
+    if (!cache->nickname) {
+	goto loser;
+    }
+    /* Create the email --> list of subject lists hash */
+    cache->email = nssHash_CreateString(arena, cacheSize);
+    if (!cache->email) {
+	goto loser;
+    }
+    cache->arena = arena;
+    td->cache = cache;
+#ifdef DEBUG_CACHE
+    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialized."));
+#endif
+    return PR_SUCCESS;
+loser:
+    PZ_DestroyLock(cache->lock);
+    nssArena_Destroy(arena);
+    td->cache = NULL;
+#ifdef DEBUG_CACHE
+    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialization failed."));
+#endif
+    return PR_FAILURE;
+}
+
+/* The entries of the hashtable are currently dependent on the certificate(s)
+ * that produced them.  That is, the entries will be freed when the cert is
+ * released from the cache.  If there are certs in the cache at any time,
+ * including shutdown, the hash table entries will hold memory.  In order for
+ * clean shutdown, it is necessary for there to be no certs in the cache.
+ */
+
+extern const NSSError NSS_ERROR_INTERNAL_ERROR;
+extern const NSSError NSS_ERROR_BUSY;
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_DestroyCache (
+  NSSTrustDomain *td
+)
+{
+    if (!td->cache) {
+	nss_SetError(NSS_ERROR_INTERNAL_ERROR);
+	return PR_FAILURE;
+    }
+    if (nssHash_Count(td->cache->issuerAndSN) > 0) {
+	nss_SetError(NSS_ERROR_BUSY);
+	return PR_FAILURE;
+    }
+    PZ_DestroyLock(td->cache->lock);
+    nssHash_Destroy(td->cache->issuerAndSN);
+    nssHash_Destroy(td->cache->subject);
+    nssHash_Destroy(td->cache->nickname);
+    nssHash_Destroy(td->cache->email);
+    nssArena_Destroy(td->cache->arena);
+    td->cache = NULL;
+#ifdef DEBUG_CACHE
+    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache destroyed."));
+#endif
+    return PR_SUCCESS;
+}
+
+static PRStatus
+remove_issuer_and_serial_entry (
+  nssTDCertificateCache *cache,
+  NSSCertificate *cert
+)
+{
+    /* Remove the cert from the issuer/serial hash */
+    nssHash_Remove(cache->issuerAndSN, cert);
+#ifdef DEBUG_CACHE
+    log_cert_ref("removed issuer/sn", cert);
+#endif
+    return PR_SUCCESS;
+}
+
+static PRStatus
+remove_subject_entry (
+  nssTDCertificateCache *cache,
+  NSSCertificate *cert,
+  nssList **subjectList,
+  NSSUTF8 **nickname,
+  NSSArena **arena
+)
+{
+    PRStatus nssrv;
+    cache_entry *ce;
+    *subjectList = NULL;
+    *arena = NULL;
+    /* Get the subject list for the cert's subject */
+    ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
+    if (ce) {
+	/* Remove the cert from the subject hash */
+	nssList_Remove(ce->entry.list, cert);
+	*subjectList = ce->entry.list;
+	*nickname = ce->nickname;
+	*arena = ce->arena;
+	nssrv = PR_SUCCESS;
+#ifdef DEBUG_CACHE
+	log_cert_ref("removed cert", cert);
+	log_item_dump("from subject list", &cert->subject);
+#endif
+    } else {
+	nssrv = PR_FAILURE;
+    }
+    return nssrv;
+}
+
+static PRStatus
+remove_nickname_entry (
+  nssTDCertificateCache *cache,
+  NSSUTF8 *nickname,
+  nssList *subjectList
+)
+{
+    PRStatus nssrv;
+    if (nickname) {
+	nssHash_Remove(cache->nickname, nickname);
+	nssrv = PR_SUCCESS;
+#ifdef DEBUG_CACHE
+	PR_LOG(s_log, PR_LOG_DEBUG, ("removed nickname %s", nickname));
+#endif
+    } else {
+	nssrv = PR_FAILURE;
+    }
+    return nssrv;
+}
+
+static PRStatus
+remove_email_entry (
+  nssTDCertificateCache *cache,
+  NSSCertificate *cert,
+  nssList *subjectList
+)
+{
+    PRStatus nssrv = PR_FAILURE;
+    cache_entry *ce;
+    /* Find the subject list in the email hash */
+    if (cert->email) {
+	ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
+	if (ce) {
+	    nssList *subjects = ce->entry.list;
+	    /* Remove the subject list from the email hash */
+	    nssList_Remove(subjects, subjectList);
+#ifdef DEBUG_CACHE
+	    log_item_dump("removed subject list", &cert->subject);
+	    PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
+#endif
+	    if (nssList_Count(subjects) == 0) {
+		/* No more subject lists for email, delete list and
+		* remove hash entry
+		*/
+		(void)nssList_Destroy(subjects);
+		nssHash_Remove(cache->email, cert->email);
+		/* there are no entries left for this address, free space
+		 * used for email entries
+		 */
+		nssArena_Destroy(ce->arena);
+#ifdef DEBUG_CACHE
+		PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
+#endif
+	    }
+	    nssrv = PR_SUCCESS;
+	}
+    }
+    return nssrv;
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_RemoveCertFromCacheLOCKED (
+  NSSTrustDomain *td,
+  NSSCertificate *cert
+)
+{
+    nssList *subjectList;
+    cache_entry *ce;
+    NSSArena *arena;
+    NSSUTF8 *nickname;
+
+#ifdef DEBUG_CACHE
+    log_cert_ref("attempt to remove cert", cert);
+#endif
+    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
+    if (!ce || ce->entry.cert != cert) {
+	/* If it's not in the cache, or a different cert is (this is really
+	 * for safety reasons, though it shouldn't happen), do nothing 
+	 */
+#ifdef DEBUG_CACHE
+	PR_LOG(s_log, PR_LOG_DEBUG, ("but it wasn't in the cache"));
+#endif
+	return;
+    }
+    (void)remove_issuer_and_serial_entry(td->cache, cert);
+    (void)remove_subject_entry(td->cache, cert, &subjectList, 
+                               &nickname, &arena);
+    if (nssList_Count(subjectList) == 0) {
+	(void)remove_nickname_entry(td->cache, nickname, subjectList);
+	(void)remove_email_entry(td->cache, cert, subjectList);
+	(void)nssList_Destroy(subjectList);
+	nssHash_Remove(td->cache->subject, &cert->subject);
+	/* there are no entries left for this subject, free the space used
+	 * for both the nickname and subject entries
+	 */
+	if (arena) {
+	    nssArena_Destroy(arena);
+	}
+    }
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_LockCertCache (
+  NSSTrustDomain *td
+)
+{
+    PZ_Lock(td->cache->lock);
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_UnlockCertCache (
+  NSSTrustDomain *td
+)
+{
+    PZ_Unlock(td->cache->lock);
+}
+
+struct token_cert_dtor {
+    NSSToken *token;
+    nssTDCertificateCache *cache;
+    NSSCertificate **certs;
+    PRUint32 numCerts, arrSize;
+};
+
+static void 
+remove_token_certs(const void *k, void *v, void *a)
+{
+    NSSCertificate *c = (NSSCertificate *)k;
+    nssPKIObject *object = &c->object;
+    struct token_cert_dtor *dtor = a;
+    PRUint32 i;
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	if (object->instances[i]->token == dtor->token) {
+	    nssCryptokiObject_Destroy(object->instances[i]);
+	    object->instances[i] = object->instances[object->numInstances-1];
+	    object->instances[object->numInstances-1] = NULL;
+	    object->numInstances--;
+	    dtor->certs[dtor->numCerts++] = c;
+	    if (dtor->numCerts == dtor->arrSize) {
+		dtor->arrSize *= 2;
+		dtor->certs = nss_ZREALLOCARRAY(dtor->certs, 
+		                                NSSCertificate *,
+		                                dtor->arrSize);
+	    }
+	    break;
+	}
+    }
+    nssPKIObject_Unlock(object);
+    return;
+}
+
+/* 
+ * Remove all certs for the given token from the cache.  This is
+ * needed if the token is removed. 
+ */
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_RemoveTokenCertsFromCache (
+  NSSTrustDomain *td,
+  NSSToken *token
+)
+{
+    NSSCertificate **certs;
+    PRUint32 i, arrSize = 10;
+    struct token_cert_dtor dtor;
+    certs = nss_ZNEWARRAY(NULL, NSSCertificate *, arrSize);
+    if (!certs) {
+	return PR_FAILURE;
+    }
+    dtor.cache = td->cache;
+    dtor.token = token;
+    dtor.certs = certs;
+    dtor.numCerts = 0;
+    dtor.arrSize = arrSize;
+    PZ_Lock(td->cache->lock);
+    nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, (void *)&dtor);
+    for (i=0; i<dtor.numCerts; i++) {
+	if (dtor.certs[i]->object.numInstances == 0) {
+	    nssTrustDomain_RemoveCertFromCacheLOCKED(td, dtor.certs[i]);
+	    dtor.certs[i] = NULL;  /* skip this cert in the second for loop */
+	}
+    }
+    PZ_Unlock(td->cache->lock);
+    for (i=0; i<dtor.numCerts; i++) {
+	if (dtor.certs[i]) {
+	    STAN_ForceCERTCertificateUpdate(dtor.certs[i]);
+	}
+    }
+    nss_ZFreeIf(dtor.certs);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_UpdateCachedTokenCerts (
+  NSSTrustDomain *td,
+  NSSToken *token
+)
+{
+    NSSCertificate **cp, **cached = NULL;
+    nssList *certList;
+    PRUint32 count;
+    certList = nssList_Create(NULL, PR_FALSE);
+    if (!certList) return PR_FAILURE;
+    (void *)nssTrustDomain_GetCertsFromCache(td, certList);
+    count = nssList_Count(certList);
+    if (count > 0) {
+	cached = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
+	if (!cached) {
+	    return PR_FAILURE;
+	}
+	nssList_GetArray(certList, (void **)cached, count);
+	nssList_Destroy(certList);
+	for (cp = cached; *cp; cp++) {
+	    nssCryptokiObject *instance;
+	    NSSCertificate *c = *cp;
+	    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+	    instance = nssToken_FindCertificateByIssuerAndSerialNumber(
+	                                                       token,
+                                                               NULL,
+                                                               &c->issuer,
+                                                               &c->serial,
+                                                               tokenOnly,
+                                                               NULL);
+	    if (instance) {
+		nssPKIObject_AddInstance(&c->object, instance);
+		STAN_ForceCERTCertificateUpdate(c);
+	    }
+	}
+	nssCertificateArray_Destroy(cached);
+    }
+    return PR_SUCCESS;
+}
+
+static PRStatus
+add_issuer_and_serial_entry (
+  NSSArena *arena,
+  nssTDCertificateCache *cache, 
+  NSSCertificate *cert
+)
+{
+    cache_entry *ce;
+    ce = new_cache_entry(arena, (void *)cert, PR_FALSE);
+#ifdef DEBUG_CACHE
+    log_cert_ref("added to issuer/sn", cert);
+#endif
+    return nssHash_Add(cache->issuerAndSN, cert, (void *)ce);
+}
+
+static PRStatus
+add_subject_entry (
+  NSSArena *arena,
+  nssTDCertificateCache *cache, 
+  NSSCertificate *cert,
+  NSSUTF8 *nickname,
+  nssList **subjectList
+)
+{
+    PRStatus nssrv;
+    nssList *list;
+    cache_entry *ce;
+    *subjectList = NULL;  /* this is only set if a new one is created */
+    ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
+    if (ce) {
+	ce->hits++;
+	ce->lastHit = PR_Now();
+	/* The subject is already in, add this cert to the list */
+	nssrv = nssList_AddUnique(ce->entry.list, cert);
+#ifdef DEBUG_CACHE
+	log_cert_ref("added to existing subject list", cert);
+#endif
+    } else {
+	NSSDER *subject;
+	/* Create a new subject list for the subject */
+	list = nssList_Create(arena, PR_FALSE);
+	if (!list) {
+	    return PR_FAILURE;
+	}
+	ce = new_cache_entry(arena, (void *)list, PR_TRUE);
+	if (!ce) {
+	    return PR_FAILURE;
+	}
+	if (nickname) {
+	    ce->nickname = nssUTF8_Duplicate(nickname, arena);
+	}
+	nssList_SetSortFunction(list, nssCertificate_SubjectListSort);
+	/* Add the cert entry to this list of subjects */
+	nssrv = nssList_AddUnique(list, cert);
+	if (nssrv != PR_SUCCESS) {
+	    return nssrv;
+	}
+	/* Add the subject list to the cache */
+	subject = nssItem_Duplicate(&cert->subject, arena, NULL);
+	if (!subject) {
+	    return PR_FAILURE;
+	}
+	nssrv = nssHash_Add(cache->subject, subject, ce);
+	if (nssrv != PR_SUCCESS) {
+	    return nssrv;
+	}
+	*subjectList = list;
+#ifdef DEBUG_CACHE
+	log_cert_ref("created subject list", cert);
+#endif
+    }
+    return nssrv;
+}
+
+static PRStatus
+add_nickname_entry (
+  NSSArena *arena,
+  nssTDCertificateCache *cache, 
+  NSSUTF8 *certNickname,
+  nssList *subjectList
+)
+{
+    PRStatus nssrv = PR_SUCCESS;
+    cache_entry *ce;
+    ce = (cache_entry *)nssHash_Lookup(cache->nickname, certNickname);
+    if (ce) {
+	/* This is a collision.  A nickname entry already exists for this
+	 * subject, but a subject entry didn't.  This would imply there are
+	 * two subjects using the same nickname, which is not allowed.
+	 */
+	return PR_FAILURE;
+    } else {
+	NSSUTF8 *nickname;
+	ce = new_cache_entry(arena, subjectList, PR_FALSE);
+	if (!ce) {
+	    return PR_FAILURE;
+	}
+	nickname = nssUTF8_Duplicate(certNickname, arena);
+	if (!nickname) {
+	    return PR_FAILURE;
+	}
+	nssrv = nssHash_Add(cache->nickname, nickname, ce);
+#ifdef DEBUG_CACHE
+	log_cert_ref("created nickname for", cert);
+#endif
+    }
+    return nssrv;
+}
+
+static PRStatus
+add_email_entry (
+  nssTDCertificateCache *cache, 
+  NSSCertificate *cert,
+  nssList *subjectList
+)
+{
+    PRStatus nssrv = PR_SUCCESS;
+    nssList *subjects;
+    cache_entry *ce;
+    ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
+    if (ce) {
+	/* Already have an entry for this email address, but not subject */
+	subjects = ce->entry.list;
+	nssrv = nssList_AddUnique(subjects, subjectList);
+	ce->hits++;
+	ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+	log_cert_ref("added subject to email for", cert);
+#endif
+    } else {
+	NSSASCII7 *email;
+	NSSArena *arena;
+	arena = nssArena_Create();
+	if (!arena) {
+	    return PR_FAILURE;
+	}
+	/* Create a new list of subject lists, add this subject */
+	subjects = nssList_Create(arena, PR_TRUE);
+	if (!subjects) {
+	    nssArena_Destroy(arena);
+	    return PR_FAILURE;
+	}
+	/* Add the new subject to the list */
+	nssrv = nssList_AddUnique(subjects, subjectList);
+	if (nssrv != PR_SUCCESS) {
+	    nssArena_Destroy(arena);
+	    return nssrv;
+	}
+	/* Add the new entry to the cache */
+	ce = new_cache_entry(arena, (void *)subjects, PR_TRUE);
+	if (!ce) {
+	    nssArena_Destroy(arena);
+	    return PR_FAILURE;
+	}
+	email = nssUTF8_Duplicate(cert->email, arena);
+	if (!email) {
+	    nssArena_Destroy(arena);
+	    return PR_FAILURE;
+	}
+	nssrv = nssHash_Add(cache->email, email, ce);
+	if (nssrv != PR_SUCCESS) {
+	    nssArena_Destroy(arena);
+	    return nssrv;
+	}
+#ifdef DEBUG_CACHE
+	log_cert_ref("created email for", cert);
+#endif
+    }
+    return nssrv;
+}
+
+extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
+
+static void
+remove_object_instances (
+  nssPKIObject *object,
+  nssCryptokiObject **instances,
+  int numInstances
+)
+{
+    int i;
+
+    for (i = 0; i < numInstances; i++) {
+	nssPKIObject_RemoveInstanceForToken(object, instances[i]->token);
+    }
+}
+
+static SECStatus
+merge_object_instances (
+  nssPKIObject *to,
+  nssPKIObject *from
+)
+{
+    nssCryptokiObject **instances, **ci;
+    int i;
+    SECStatus rv = SECSuccess;
+
+    instances = nssPKIObject_GetInstances(from);
+    if (instances == NULL) {
+	return SECFailure;
+    }
+    for (ci = instances, i = 0; *ci; ci++, i++) {
+	nssCryptokiObject *instance = nssCryptokiObject_Clone(*ci);
+	if (instance) {
+	    if (nssPKIObject_AddInstance(to, instance) == SECSuccess) {
+		continue;
+	    }
+	    nssCryptokiObject_Destroy(instance);
+	}
+	remove_object_instances(to, instances, i);
+	rv = SECFailure;
+	break;
+    }
+    nssCryptokiObjectArray_Destroy(instances);
+    return rv;
+}
+
+static NSSCertificate *
+add_cert_to_cache (
+  NSSTrustDomain *td, 
+  NSSCertificate *cert
+)
+{
+    NSSArena *arena = NULL;
+    nssList *subjectList = NULL;
+    PRStatus nssrv;
+    PRUint32 added = 0;
+    cache_entry *ce;
+    NSSCertificate *rvCert = NULL;
+    NSSUTF8 *certNickname = nssCertificate_GetNickname(cert, NULL);
+
+    PZ_Lock(td->cache->lock);
+    /* If it exists in the issuer/serial hash, it's already in all */
+    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
+    if (ce) {
+	ce->hits++;
+	ce->lastHit = PR_Now();
+	rvCert = nssCertificate_AddRef(ce->entry.cert);
+#ifdef DEBUG_CACHE
+	log_cert_ref("attempted to add cert already in cache", cert);
+#endif
+	PZ_Unlock(td->cache->lock);
+	/* collision - somebody else already added the cert
+	 * to the cache before this thread got around to it.
+	 */
+	/* merge the instances of the cert */
+	if (merge_object_instances(&rvCert->object, &cert->object)
+							!= SECSuccess) {
+	    nssCertificate_Destroy(rvCert);
+	    return NULL;
+	}
+	STAN_ForceCERTCertificateUpdate(rvCert);
+	nssCertificate_Destroy(cert);
+	return rvCert;
+    }
+    /* create a new cache entry for this cert within the cert's arena*/
+    nssrv = add_issuer_and_serial_entry(cert->object.arena, td->cache, cert);
+    if (nssrv != PR_SUCCESS) {
+	goto loser;
+    }
+    added++;
+    /* create an arena for the nickname and subject entries */
+    arena = nssArena_Create();
+    if (!arena) {
+	goto loser;
+    }
+    /* create a new subject list for this cert, or add to existing */
+    nssrv = add_subject_entry(arena, td->cache, cert, 
+						certNickname, &subjectList);
+    if (nssrv != PR_SUCCESS) {
+	goto loser;
+    }
+    added++;
+    /* If a new subject entry was created, also need nickname and/or email */
+    if (subjectList != NULL) {
+	PRBool handle = PR_FALSE;
+	if (certNickname) {
+	    nssrv = add_nickname_entry(arena, td->cache, 
+						certNickname, subjectList);
+	    if (nssrv != PR_SUCCESS) {
+		goto loser;
+	    }
+	    handle = PR_TRUE;
+	    added++;
+	}
+	if (cert->email) {
+	    nssrv = add_email_entry(td->cache, cert, subjectList);
+	    if (nssrv != PR_SUCCESS) {
+		goto loser;
+	    }
+	    handle = PR_TRUE;
+	    added += 2;
+	}
+#ifdef nodef
+	/* I think either a nickname or email address must be associated
+	 * with the cert.  However, certs are passed to NewTemp without
+	 * either.  This worked in the old code, so it must work now.
+	 */
+	if (!handle) {
+	    /* Require either nickname or email handle */
+	    nssrv = PR_FAILURE;
+	    goto loser;
+	}
+#endif
+    } else {
+    	/* A new subject entry was not created.  arena is unused. */
+	nssArena_Destroy(arena);
+    }
+    rvCert = cert;
+    PZ_Unlock(td->cache->lock);
+    return rvCert;
+loser:
+    /* Remove any handles that have been created */
+    subjectList = NULL;
+    if (added >= 1) {
+	(void)remove_issuer_and_serial_entry(td->cache, cert);
+    }
+    if (added >= 2) {
+	(void)remove_subject_entry(td->cache, cert, &subjectList, 
+						&certNickname, &arena);
+    }
+    if (added == 3 || added == 5) {
+	(void)remove_nickname_entry(td->cache, certNickname, subjectList);
+    }
+    if (added >= 4) {
+	(void)remove_email_entry(td->cache, cert, subjectList);
+    }
+    if (subjectList) {
+	nssHash_Remove(td->cache->subject, &cert->subject);
+	nssList_Destroy(subjectList);
+    }
+    if (arena) {
+	nssArena_Destroy(arena);
+    }
+    PZ_Unlock(td->cache->lock);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_AddCertsToCache (
+  NSSTrustDomain *td,
+  NSSCertificate **certs,
+  PRUint32 numCerts
+)
+{
+    PRUint32 i;
+    NSSCertificate *c;
+    for (i=0; i<numCerts && certs[i]; i++) {
+	c = add_cert_to_cache(td, certs[i]);
+	if (c == NULL) {
+	    return PR_FAILURE;
+	} else {
+	    certs[i] = c;
+	}
+    }
+    return PR_SUCCESS;
+}
+
+static NSSCertificate **
+collect_subject_certs (
+  nssList *subjectList,
+  nssList *rvCertListOpt
+)
+{
+    NSSCertificate *c;
+    NSSCertificate **rvArray = NULL;
+    PRUint32 count;
+    nssCertificateList_AddReferences(subjectList);
+    if (rvCertListOpt) {
+	nssListIterator *iter = nssList_CreateIterator(subjectList);
+	if (!iter) {
+	    return (NSSCertificate **)NULL;
+	}
+	for (c  = (NSSCertificate *)nssListIterator_Start(iter);
+	     c != (NSSCertificate *)NULL;
+	     c  = (NSSCertificate *)nssListIterator_Next(iter)) {
+	    nssList_Add(rvCertListOpt, c);
+	}
+	nssListIterator_Finish(iter);
+	nssListIterator_Destroy(iter);
+    } else {
+	count = nssList_Count(subjectList);
+	rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
+	if (!rvArray) {
+	    return (NSSCertificate **)NULL;
+	}
+	nssList_GetArray(subjectList, (void **)rvArray, count);
+    }
+    return rvArray;
+}
+
+/*
+ * Find all cached certs with this subject.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_GetCertsForSubjectFromCache (
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  nssList *certListOpt
+)
+{
+    NSSCertificate **rvArray = NULL;
+    cache_entry *ce;
+#ifdef DEBUG_CACHE
+    log_item_dump("looking for cert by subject", subject);
+#endif
+    PZ_Lock(td->cache->lock);
+    ce = (cache_entry *)nssHash_Lookup(td->cache->subject, subject);
+    if (ce) {
+	ce->hits++;
+	ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+	rvArray = collect_subject_certs(ce->entry.list, certListOpt);
+    }
+    PZ_Unlock(td->cache->lock);
+    return rvArray;
+}
+
+/*
+ * Find all cached certs with this label.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_GetCertsForNicknameFromCache (
+  NSSTrustDomain *td,
+  const NSSUTF8 *nickname,
+  nssList *certListOpt
+)
+{
+    NSSCertificate **rvArray = NULL;
+    cache_entry *ce;
+#ifdef DEBUG_CACHE
+    PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by nick %s", nickname));
+#endif
+    PZ_Lock(td->cache->lock);
+    ce = (cache_entry *)nssHash_Lookup(td->cache->nickname, nickname);
+    if (ce) {
+	ce->hits++;
+	ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+	rvArray = collect_subject_certs(ce->entry.list, certListOpt);
+    }
+    PZ_Unlock(td->cache->lock);
+    return rvArray;
+}
+
+/*
+ * Find all cached certs with this email address.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_GetCertsForEmailAddressFromCache (
+  NSSTrustDomain *td,
+  NSSASCII7 *email,
+  nssList *certListOpt
+)
+{
+    NSSCertificate **rvArray = NULL;
+    cache_entry *ce;
+    nssList *collectList = NULL;
+    nssListIterator *iter = NULL;
+    nssList *subjectList;
+#ifdef DEBUG_CACHE
+    PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by email %s", email));
+#endif
+    PZ_Lock(td->cache->lock);
+    ce = (cache_entry *)nssHash_Lookup(td->cache->email, email);
+    if (ce) {
+	ce->hits++;
+	ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+	/* loop over subject lists and get refs for certs */
+	if (certListOpt) {
+	    collectList = certListOpt;
+	} else {
+	    collectList = nssList_Create(NULL, PR_FALSE);
+	    if (!collectList) {
+		PZ_Unlock(td->cache->lock);
+		return NULL;
+	    }
+	}
+	iter = nssList_CreateIterator(ce->entry.list);
+	if (!iter) {
+	    PZ_Unlock(td->cache->lock);
+	    if (!certListOpt) {
+		nssList_Destroy(collectList);
+	    }
+	    return NULL;
+	}
+	for (subjectList  = (nssList *)nssListIterator_Start(iter);
+	     subjectList != (nssList *)NULL;
+	     subjectList  = (nssList *)nssListIterator_Next(iter)) {
+	    (void)collect_subject_certs(subjectList, collectList);
+	}
+	nssListIterator_Finish(iter);
+	nssListIterator_Destroy(iter);
+    }
+    PZ_Unlock(td->cache->lock);
+    if (!certListOpt && collectList) {
+	PRUint32 count = nssList_Count(collectList);
+	rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
+	if (rvArray) {
+	    nssList_GetArray(collectList, (void **)rvArray, count);
+	}
+	nssList_Destroy(collectList);
+    }
+    return rvArray;
+}
+
+/*
+ * Look for a specific cert in the cache
+ */
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_GetCertForIssuerAndSNFromCache (
+  NSSTrustDomain *td,
+  NSSDER *issuer,
+  NSSDER *serial
+)
+{
+    NSSCertificate certkey;
+    NSSCertificate *rvCert = NULL;
+    cache_entry *ce;
+    certkey.issuer.data = issuer->data;
+    certkey.issuer.size = issuer->size;
+    certkey.serial.data = serial->data;
+    certkey.serial.size = serial->size;
+#ifdef DEBUG_CACHE
+    log_item_dump("looking for cert by issuer/sn, issuer", issuer);
+    log_item_dump("                               serial", serial);
+#endif
+    PZ_Lock(td->cache->lock);
+    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, &certkey);
+    if (ce) {
+	ce->hits++;
+	ce->lastHit = PR_Now();
+	rvCert = nssCertificate_AddRef(ce->entry.cert);
+#ifdef DEBUG_CACHE
+	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+    }
+    PZ_Unlock(td->cache->lock);
+    return rvCert;
+}
+
+static PRStatus
+issuer_and_serial_from_encoding (
+  NSSBER *encoding, 
+  NSSDER *issuer, 
+  NSSDER *serial
+)
+{
+    SECItem derCert, derIssuer, derSerial;
+    SECStatus secrv;
+    derCert.data = (unsigned char *)encoding->data;
+    derCert.len = encoding->size;
+    secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
+    if (secrv != SECSuccess) {
+	return PR_FAILURE;
+    }
+    secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
+    if (secrv != SECSuccess) {
+	return PR_FAILURE;
+    }
+    issuer->data = derIssuer.data;
+    issuer->size = derIssuer.len;
+    serial->data = derSerial.data;
+    serial->size = derSerial.len;
+    return PR_SUCCESS;
+}
+
+/*
+ * Look for a specific cert in the cache
+ */
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_GetCertByDERFromCache (
+  NSSTrustDomain *td,
+  NSSDER *der
+)
+{
+    PRStatus nssrv = PR_FAILURE;
+    NSSDER issuer, serial;
+    NSSCertificate *rvCert;
+    nssrv = issuer_and_serial_from_encoding(der, &issuer, &serial);
+    if (nssrv != PR_SUCCESS) {
+	return NULL;
+    }
+#ifdef DEBUG_CACHE
+    log_item_dump("looking for cert by DER", der);
+#endif
+    rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td, 
+                                                           &issuer, &serial);
+    PORT_Free(issuer.data);
+    PORT_Free(serial.data);
+    return rvCert;
+}
+
+static void cert_iter(const void *k, void *v, void *a)
+{
+    nssList *certList = (nssList *)a;
+    NSSCertificate *c = (NSSCertificate *)k;
+    nssList_Add(certList, nssCertificate_AddRef(c));
+}
+
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsFromCache (
+  NSSTrustDomain *td,
+  nssList *certListOpt
+)
+{
+    NSSCertificate **rvArray = NULL;
+    nssList *certList;
+    if (certListOpt) {
+	certList = certListOpt;
+    } else {
+	certList = nssList_Create(NULL, PR_FALSE);
+	if (!certList) {
+	    return NULL;
+	}
+    }
+    PZ_Lock(td->cache->lock);
+    nssHash_Iterate(td->cache->issuerAndSN, cert_iter, (void *)certList);
+    PZ_Unlock(td->cache->lock);
+    if (!certListOpt) {
+	PRUint32 count = nssList_Count(certList);
+	rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
+	nssList_GetArray(certList, (void **)rvArray, count);
+	/* array takes the references */
+	nssList_Destroy(certList);
+    }
+    return rvArray;
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_DumpCacheInfo (
+  NSSTrustDomain *td,
+  void (* cert_dump_iter)(const void *, void *, void *),
+  void *arg
+)
+{
+    PZ_Lock(td->cache->lock);
+    nssHash_Iterate(td->cache->issuerAndSN, cert_dump_iter, arg);
+    PZ_Unlock(td->cache->lock);
+}
diff --git a/mozilla/security/nss/lib/pki/trustdomain.c b/mozilla/security/nss/lib/pki/trustdomain.c
new file mode 100644
index 0000000..c9797bc
--- /dev/null
+++ b/mozilla/security/nss/lib/pki/trustdomain.c
@@ -0,0 +1,1294 @@
+/* ***** 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.60 $ $Date: 2008/10/06 02:56:00 $";
+#endif /* DEBUG */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef PKI1T_H
+#include "pki1t.h"
+#endif /* PKI1T_H */
+
+#include "cert.h"
+#include "pki3hack.h"
+#include "pk11pub.h"
+#include "nssrwlk.h"
+
+#define NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE 32
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+typedef PRUint32 nssUpdateLevel;
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSTrustDomain_Create (
+  NSSUTF8 *moduleOpt,
+  NSSUTF8 *uriOpt,
+  NSSUTF8 *opaqueOpt,
+  void *reserved
+)
+{
+    NSSArena *arena;
+    NSSTrustDomain *rvTD;
+    arena = NSSArena_Create();
+    if(!arena) {
+	return (NSSTrustDomain *)NULL;
+    }
+    rvTD = nss_ZNEW(arena, NSSTrustDomain);
+    if (!rvTD) {
+	goto loser;
+    }
+    /* protect the token list and the token iterator */
+    rvTD->tokensLock = NSSRWLock_New(100, "tokens");
+    if (!rvTD->tokensLock) {
+	goto loser;
+    }
+    nssTrustDomain_InitializeCache(rvTD, NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE);
+    rvTD->arena = arena;
+    rvTD->refCount = 1;
+    rvTD->statusConfig = NULL;
+    return rvTD;
+loser:
+    if (rvTD && rvTD->tokensLock) {
+	NSSRWLock_Destroy(rvTD->tokensLock);
+    }
+    nssArena_Destroy(arena);
+    return (NSSTrustDomain *)NULL;
+}
+
+static void
+token_destructor(void *t)
+{
+    NSSToken *tok = (NSSToken *)t;
+    /* The token holds the first/last reference to the slot.
+     * When the token is actually destroyed (ref count == 0), 
+     * the slot will also be destroyed.
+     */
+    nssToken_Destroy(tok);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_Destroy (
+  NSSTrustDomain *td
+)
+{
+    PRStatus status = PR_SUCCESS;
+    if (--td->refCount == 0) {
+	/* Destroy each token in the list of tokens */
+	if (td->tokens) {
+	    nssListIterator_Destroy(td->tokens);
+	    td->tokens = NULL;
+	}
+	if (td->tokenList) {
+	    nssList_Clear(td->tokenList, token_destructor);
+	    nssList_Destroy(td->tokenList);
+	    td->tokenList = NULL;
+	}
+	NSSRWLock_Destroy(td->tokensLock);
+	td->tokensLock = NULL;
+	status = nssTrustDomain_DestroyCache(td);
+	if (status == PR_FAILURE) {
+	    return status;
+	}
+	if (td->statusConfig) {
+	    td->statusConfig->statusDestroy(td->statusConfig);
+	    td->statusConfig = NULL;
+	}
+	/* Destroy the trust domain */
+	nssArena_Destroy(td->arena);
+    }
+    return status;
+}
+
+/* XXX uses tokens until slot list is in place */
+static NSSSlot **
+nssTrustDomain_GetActiveSlots (
+  NSSTrustDomain *td,
+  nssUpdateLevel *updateLevel
+)
+{
+    PRUint32 count;
+    NSSSlot **slots = NULL;
+    NSSToken **tp, **tokens;
+    *updateLevel = 1;
+    NSSRWLock_LockRead(td->tokensLock);
+    count = nssList_Count(td->tokenList);
+    tokens = nss_ZNEWARRAY(NULL, NSSToken *, count + 1);
+    if (!tokens) {
+	NSSRWLock_UnlockRead(td->tokensLock);
+	return NULL;
+    }
+    slots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
+    if (!slots) {
+	NSSRWLock_UnlockRead(td->tokensLock);
+	nss_ZFreeIf(tokens);
+	return NULL;
+    }
+    nssList_GetArray(td->tokenList, (void **)tokens, count);
+    NSSRWLock_UnlockRead(td->tokensLock);
+    count = 0;
+    for (tp = tokens; *tp; tp++) {
+        NSSSlot * slot = nssToken_GetSlot(*tp);
+        if (!PK11_IsDisabled(slot->pk11slot)) {
+            slots[count++] = slot;
+        } else {
+	    nssSlot_Destroy(slot);
+	}
+    }
+    nss_ZFreeIf(tokens);
+    if (!count) {
+	nss_ZFreeIf(slots);
+    	slots = NULL;
+    }
+    return slots;
+}
+
+/* XXX */
+static nssSession *
+nssTrustDomain_GetSessionForToken (
+  NSSTrustDomain *td,
+  NSSToken *token
+)
+{
+    return nssToken_GetDefaultSession(token);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_SetDefaultCallback (
+  NSSTrustDomain *td,
+  NSSCallback *newCallback,
+  NSSCallback **oldCallbackOpt
+)
+{
+    if (oldCallbackOpt) {
+	*oldCallbackOpt = td->defaultCallback;
+    }
+    td->defaultCallback = newCallback;
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT NSSCallback *
+nssTrustDomain_GetDefaultCallback (
+  NSSTrustDomain *td,
+  PRStatus *statusOpt
+)
+{
+    if (statusOpt) {
+	*statusOpt = PR_SUCCESS;
+    }
+    return td->defaultCallback;
+}
+
+NSS_IMPLEMENT NSSCallback *
+NSSTrustDomain_GetDefaultCallback (
+  NSSTrustDomain *td,
+  PRStatus *statusOpt
+)
+{
+    return nssTrustDomain_GetDefaultCallback(td, statusOpt);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_LoadModule (
+  NSSTrustDomain *td,
+  NSSUTF8 *moduleOpt,
+  NSSUTF8 *uriOpt,
+  NSSUTF8 *opaqueOpt,
+  void *reserved
+)
+{
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_DisableToken (
+  NSSTrustDomain *td,
+  NSSToken *token,
+  NSSError why
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_EnableToken (
+  NSSTrustDomain *td,
+  NSSToken *token
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_IsTokenEnabled (
+  NSSTrustDomain *td,
+  NSSToken *token,
+  NSSError *whyOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSTrustDomain_FindSlotByName (
+  NSSTrustDomain *td,
+  NSSUTF8 *slotName
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindTokenByName (
+  NSSTrustDomain *td,
+  NSSUTF8 *tokenName
+)
+{
+    PRStatus nssrv;
+    NSSUTF8 *myName;
+    NSSToken *tok = NULL;
+    NSSRWLock_LockRead(td->tokensLock);
+    for (tok  = (NSSToken *)nssListIterator_Start(td->tokens);
+         tok != (NSSToken *)NULL;
+         tok  = (NSSToken *)nssListIterator_Next(td->tokens))
+    {
+	if (nssToken_IsPresent(tok)) {
+	    myName = nssToken_GetName(tok);
+	    if (nssUTF8_Equal(tokenName, myName, &nssrv)) break;
+	}
+    }
+    nssListIterator_Finish(td->tokens);
+    NSSRWLock_UnlockRead(td->tokensLock);
+    return tok;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindTokenBySlotName (
+  NSSTrustDomain *td,
+  NSSUTF8 *slotName
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindTokenForAlgorithm (
+  NSSTrustDomain *td,
+  NSSOID *algorithm
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindBestTokenForAlgorithms (
+  NSSTrustDomain *td,
+  NSSOID *algorithms[], /* may be null-terminated */
+  PRUint32 nAlgorithmsOpt /* limits the array if nonzero */
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_Login (
+  NSSTrustDomain *td,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_Logout (
+  NSSTrustDomain *td
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_ImportCertificate (
+  NSSTrustDomain *td,
+  NSSCertificate *c
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_ImportPKIXCertificate (
+  NSSTrustDomain *td,
+  /* declared as a struct until these "data types" are defined */
+  struct NSSPKIXCertificateStr *pc
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_ImportEncodedCertificate (
+  NSSTrustDomain *td,
+  NSSBER *ber
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_ImportEncodedCertificateChain (
+  NSSTrustDomain *td,
+  NSSBER *ber,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSTrustDomain_ImportEncodedPrivateKey (
+  NSSTrustDomain *td,
+  NSSBER *ber,
+  NSSItem *passwordOpt, /* NULL will cause a callback */
+  NSSCallback *uhhOpt,
+  NSSToken *destination
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSPublicKey *
+NSSTrustDomain_ImportEncodedPublicKey (
+  NSSTrustDomain *td,
+  NSSBER *ber
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+static NSSCertificate **
+get_certs_from_list(nssList *list)
+{
+    PRUint32 count = nssList_Count(list);
+    NSSCertificate **certs = NULL;
+    if (count > 0) {
+	certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
+	if (certs) {
+	    nssList_GetArray(list, (void **)certs, count);
+	}
+    }
+    return certs;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_FindCertificatesByNickname (
+  NSSTrustDomain *td,
+  const NSSUTF8 *name,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    NSSToken *token = NULL;
+    NSSSlot **slots = NULL;
+    NSSSlot **slotp;
+    NSSCertificate **rvCerts = NULL;
+    nssPKIObjectCollection *collection = NULL;
+    nssUpdateLevel updateLevel;
+    nssList *nameList;
+    PRUint32 numRemaining = maximumOpt;
+    PRUint32 collectionCount = 0;
+    PRUint32 errors = 0;
+
+    /* First, grab from the cache */
+    nameList = nssList_Create(NULL, PR_FALSE);
+    if (!nameList) {
+	return NULL;
+    }
+    (void)nssTrustDomain_GetCertsForNicknameFromCache(td, name, nameList);
+    rvCerts = get_certs_from_list(nameList);
+    /* initialize the collection of token certificates with the set of
+     * cached certs (if any).
+     */
+    collection = nssCertificateCollection_Create(td, rvCerts);
+    nssCertificateArray_Destroy(rvCerts);
+    nssList_Destroy(nameList);
+    if (!collection) {
+	return (NSSCertificate **)NULL;
+    }
+    /* obtain the current set of active slots in the trust domain */
+    slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+    if (!slots) {
+	goto loser;
+    }
+    /* iterate over the slots */
+    for (slotp = slots; *slotp; slotp++) {
+	token = nssSlot_GetToken(*slotp);
+	if (token) {
+	    nssSession *session;
+	    nssCryptokiObject **instances = NULL;
+	    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+	    PRStatus status = PR_FAILURE;
+
+	    session = nssTrustDomain_GetSessionForToken(td, token);
+	    if (session) {
+		instances = nssToken_FindCertificatesByNickname(token,
+								session,
+								name,
+								tokenOnly,
+								numRemaining,
+								&status);
+	    }
+	    nssToken_Destroy(token);
+	    if (status != PR_SUCCESS) {
+		errors++;
+		continue;
+	    }
+	    if (instances) {
+		status = nssPKIObjectCollection_AddInstances(collection, 
+		                                             instances, 0);
+		nss_ZFreeIf(instances);
+		if (status != PR_SUCCESS) {
+		    errors++;
+		    continue;
+		}
+		collectionCount = nssPKIObjectCollection_Count(collection);
+		if (maximumOpt > 0) {
+		    if (collectionCount >= maximumOpt)
+		    	break;
+		    numRemaining = maximumOpt - collectionCount;
+		}
+	    }
+	}
+    }
+    if (!collectionCount && errors)
+    	goto loser;
+    /* Grab the certs collected in the search. */
+    rvCerts = nssPKIObjectCollection_GetCertificates(collection,
+                                                     rvOpt, maximumOpt,
+                                                     arenaOpt);
+    /* clean up */
+    nssPKIObjectCollection_Destroy(collection);
+    nssSlotArray_Destroy(slots);
+    return rvCerts;
+loser:
+    if (slots) {
+	nssSlotArray_Destroy(slots);
+    }
+    if (collection) {
+	nssPKIObjectCollection_Destroy(collection);
+    }
+    return (NSSCertificate **)NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesByNickname (
+  NSSTrustDomain *td,
+  NSSUTF8 *name,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    return nssTrustDomain_FindCertificatesByNickname(td,
+                                                     name,
+                                                     rvOpt,
+                                                     maximumOpt,
+                                                     arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindBestCertificateByNickname (
+  NSSTrustDomain *td,
+  const NSSUTF8 *name,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    NSSCertificate **nicknameCerts;
+    NSSCertificate *rvCert = NULL;
+    nicknameCerts = nssTrustDomain_FindCertificatesByNickname(td, name,
+                                                              NULL,
+                                                              0,
+                                                              NULL);
+    if (nicknameCerts) {
+	rvCert = nssCertificateArray_FindBestCertificate(nicknameCerts,
+                                                         timeOpt,
+                                                         usage,
+                                                         policiesOpt);
+	nssCertificateArray_Destroy(nicknameCerts);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNickname (
+  NSSTrustDomain *td,
+  const NSSUTF8 *name,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    return nssTrustDomain_FindBestCertificateByNickname(td,
+                                                        name,
+                                                        timeOpt,
+                                                        usage,
+                                                        policiesOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_FindCertificatesBySubject (
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    NSSToken *token = NULL;
+    NSSSlot **slots = NULL;
+    NSSSlot **slotp;
+    NSSCertificate **rvCerts = NULL;
+    nssPKIObjectCollection *collection = NULL;
+    nssUpdateLevel updateLevel;
+    nssList *subjectList;
+    PRUint32 numRemaining = maximumOpt;
+    PRUint32 collectionCount = 0;
+    PRUint32 errors = 0;
+
+    /* look in cache */
+    subjectList = nssList_Create(NULL, PR_FALSE);
+    if (!subjectList) {
+	return NULL;
+    }
+    (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList);
+    rvCerts = get_certs_from_list(subjectList);
+    collection = nssCertificateCollection_Create(td, rvCerts);
+    nssCertificateArray_Destroy(rvCerts);
+    nssList_Destroy(subjectList);
+    if (!collection) {
+	return (NSSCertificate **)NULL;
+    }
+    slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+    if (!slots) {
+	goto loser;
+    }
+    for (slotp = slots; *slotp; slotp++) {
+	token = nssSlot_GetToken(*slotp);
+	if (token) {
+	    nssSession *session;
+	    nssCryptokiObject **instances = NULL;
+	    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+	    PRStatus status = PR_FAILURE;
+
+	    session = nssTrustDomain_GetSessionForToken(td, token);
+	    if (session) {
+		instances = nssToken_FindCertificatesBySubject(token,
+							       session,
+							       subject,
+							       tokenOnly,
+							       numRemaining,
+							       &status);
+	    }
+	    nssToken_Destroy(token);
+	    if (status != PR_SUCCESS) {
+		errors++;
+		continue;
+	    }
+	    if (instances) {
+		status = nssPKIObjectCollection_AddInstances(collection, 
+		                                             instances, 0);
+		nss_ZFreeIf(instances);
+		if (status != PR_SUCCESS) {
+		    errors++;
+		    continue;
+		}
+		collectionCount = nssPKIObjectCollection_Count(collection);
+		if (maximumOpt > 0) {
+		    if (collectionCount >= maximumOpt)
+		    	break;
+		    numRemaining = maximumOpt - collectionCount;
+		}
+	    }
+	}
+    }
+    if (!collectionCount && errors)
+    	goto loser;
+    rvCerts = nssPKIObjectCollection_GetCertificates(collection,
+                                                     rvOpt, maximumOpt,
+                                                     arenaOpt);
+    nssPKIObjectCollection_Destroy(collection);
+    nssSlotArray_Destroy(slots);
+    return rvCerts;
+loser:
+    if (slots) {
+	nssSlotArray_Destroy(slots);
+    }
+    if (collection) {
+	nssPKIObjectCollection_Destroy(collection);
+    }
+    return (NSSCertificate **)NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesBySubject (
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    return nssTrustDomain_FindCertificatesBySubject(td, 
+                                                    subject,
+                                                    rvOpt,
+                                                    maximumOpt,
+                                                    arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindBestCertificateBySubject (
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    NSSCertificate **subjectCerts;
+    NSSCertificate *rvCert = NULL;
+    subjectCerts = nssTrustDomain_FindCertificatesBySubject(td, subject,
+                                                            NULL,
+                                                            0,
+                                                            NULL);
+    if (subjectCerts) {
+	rvCert = nssCertificateArray_FindBestCertificate(subjectCerts,
+                                                         timeOpt,
+                                                         usage,
+                                                         policiesOpt);
+	nssCertificateArray_Destroy(subjectCerts);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateBySubject (
+  NSSTrustDomain *td,
+  NSSDER *subject,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    return nssTrustDomain_FindBestCertificateBySubject(td,
+                                                       subject,
+                                                       timeOpt,
+                                                       usage,
+                                                       policiesOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNameComponents (
+  NSSTrustDomain *td,
+  NSSUTF8 *nameComponents,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesByNameComponents (
+  NSSTrustDomain *td,
+  NSSUTF8 *nameComponents,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+/* This returns at most a single certificate, so it can stop the loop
+ * when one is found.
+ */
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindCertificateByIssuerAndSerialNumber (
+  NSSTrustDomain *td,
+  NSSDER *issuer,
+  NSSDER *serial
+)
+{
+    NSSSlot **slots = NULL;
+    NSSSlot **slotp;
+    NSSCertificate *rvCert = NULL;
+    nssPKIObjectCollection *collection = NULL;
+    nssUpdateLevel updateLevel;
+
+    /* see if this search is already cached */
+    rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td,
+                                                           issuer, 
+                                                           serial);
+    if (rvCert) {
+	return rvCert;
+    }
+    slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+    if (slots) {
+	for (slotp = slots; *slotp; slotp++) {
+	    NSSToken *token = nssSlot_GetToken(*slotp);
+	    nssSession *session;
+	    nssCryptokiObject *instance;
+	    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+	    PRStatus status = PR_FAILURE;
+
+	    if (!token) 
+		continue;
+	    session = nssTrustDomain_GetSessionForToken(td, token);
+	    if (session) {
+		instance = nssToken_FindCertificateByIssuerAndSerialNumber(
+								    token,
+								    session,
+								    issuer,
+								    serial,
+								    tokenOnly,
+								    &status);
+	    }
+	    nssToken_Destroy(token);
+	    if (status != PR_SUCCESS) {
+		continue;
+	    }
+	    if (instance) {
+		if (!collection) {
+		    collection = nssCertificateCollection_Create(td, NULL);
+		    if (!collection) {
+			break;  /* don't keep looping if out if memory */
+		    }
+		}
+		status = nssPKIObjectCollection_AddInstances(collection, 
+							     &instance, 1);
+		if (status == PR_SUCCESS) {
+		    (void)nssPKIObjectCollection_GetCertificates(
+					     collection, &rvCert, 1, NULL);
+		}
+		if (rvCert) {
+		    break; /* found one cert, all done */
+		}
+	    }
+	}
+    }
+    if (collection) {
+	nssPKIObjectCollection_Destroy(collection);
+    }
+    if (slots) {
+	nssSlotArray_Destroy(slots);
+    }
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindCertificateByIssuerAndSerialNumber (
+  NSSTrustDomain *td,
+  NSSDER *issuer,
+  NSSDER *serial
+)
+{
+    return nssTrustDomain_FindCertificateByIssuerAndSerialNumber(td,
+                                                                 issuer,
+                                                                 serial);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindCertificateByEncodedCertificate (
+  NSSTrustDomain *td,
+  NSSBER *ber
+)
+{
+    PRStatus status;
+    NSSCertificate *rvCert = NULL;
+    NSSDER issuer = { 0 };
+    NSSDER serial = { 0 };
+    NSSArena *arena = nssArena_Create();
+    if (!arena) {
+	return (NSSCertificate *)NULL;
+    }
+    /* XXX this is not generic...  will any cert crack into issuer/serial? */
+    status = nssPKIX509_GetIssuerAndSerialFromDER(ber, arena, &issuer, &serial);
+    if (status != PR_SUCCESS) {
+	goto finish;
+    }
+    rvCert = nssTrustDomain_FindCertificateByIssuerAndSerialNumber(td,
+                                                                   &issuer,
+                                                                   &serial);
+finish:
+    nssArena_Destroy(arena);
+    return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindCertificateByEncodedCertificate (
+  NSSTrustDomain *td,
+  NSSBER *ber
+)
+{
+    return nssTrustDomain_FindCertificateByEncodedCertificate(td, ber);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateByEmail (
+  NSSTrustDomain *td,
+  NSSASCII7 *email,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    return 0;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesByEmail (
+  NSSTrustDomain *td,
+  NSSASCII7 *email,
+  NSSCertificate *rvOpt[],
+  PRUint32 maximumOpt, /* 0 for no max */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindCertificateByOCSPHash (
+  NSSTrustDomain *td,
+  NSSItem *hash
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestUserCertificate (
+  NSSTrustDomain *td,
+  NSSTime *timeOpt,
+  NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindUserCertificates (
+  NSSTrustDomain *td,
+  NSSTime *timeOpt,
+  NSSUsage *usageOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForSSLClientAuth (
+  NSSTrustDomain *td,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForSSLClientAuth (
+  NSSTrustDomain *td,
+  NSSUTF8 *sslHostOpt,
+  NSSDER *rootCAsOpt[], /* null pointer for none */
+  PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForEmailSigning (
+  NSSTrustDomain *td,
+  NSSASCII7 *signerOpt,
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForEmailSigning (
+  NSSTrustDomain *td,
+  NSSASCII7 *signerOpt,
+  NSSASCII7 *recipientOpt,
+  /* anything more here? */
+  NSSAlgorithmAndParameters *apOpt,
+  NSSPolicies *policiesOpt,
+  NSSCertificate **rvOpt,
+  PRUint32 rvLimit, /* zero for no limit */
+  NSSArena *arenaOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+static PRStatus
+collector(nssCryptokiObject *instance, void *arg)
+{
+    nssPKIObjectCollection *collection = (nssPKIObjectCollection *)arg;
+    return nssPKIObjectCollection_AddInstanceAsObject(collection, instance);
+}
+
+NSS_IMPLEMENT PRStatus *
+NSSTrustDomain_TraverseCertificates (
+  NSSTrustDomain *td,
+  PRStatus (*callback)(NSSCertificate *c, void *arg),
+  void *arg
+)
+{
+    PRStatus status = PR_FAILURE;
+    NSSToken *token = NULL;
+    NSSSlot **slots = NULL;
+    NSSSlot **slotp;
+    nssPKIObjectCollection *collection = NULL;
+    nssPKIObjectCallback pkiCallback;
+    nssUpdateLevel updateLevel;
+    NSSCertificate **cached = NULL;
+    nssList *certList;
+
+    certList = nssList_Create(NULL, PR_FALSE);
+    if (!certList) 
+    	return NULL;
+    (void *)nssTrustDomain_GetCertsFromCache(td, certList);
+    cached = get_certs_from_list(certList);
+    collection = nssCertificateCollection_Create(td, cached);
+    nssCertificateArray_Destroy(cached);
+    nssList_Destroy(certList);
+    if (!collection) {
+	return (PRStatus *)NULL;
+    }
+    /* obtain the current set of active slots in the trust domain */
+    slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+    if (!slots) {
+	goto loser;
+    }
+    /* iterate over the slots */
+    for (slotp = slots; *slotp; slotp++) {
+	/* get the token for the slot, if present */
+	token = nssSlot_GetToken(*slotp);
+	if (token) {
+	    nssSession *session;
+	    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+	    /* get a session for the token */
+	    session = nssTrustDomain_GetSessionForToken(td, token);
+	    if (session) {
+		/* perform the traversal */
+		status = nssToken_TraverseCertificates(token,
+						       session,
+						       tokenOnly,
+						       collector,
+						       collection);
+	    }
+	    nssToken_Destroy(token);
+	}
+    }
+
+    /* Traverse the collection */
+    pkiCallback.func.cert = callback;
+    pkiCallback.arg = arg;
+    status = nssPKIObjectCollection_Traverse(collection, &pkiCallback);
+loser:
+    if (slots) {
+	nssSlotArray_Destroy(slots);
+    }
+    if (collection) {
+	nssPKIObjectCollection_Destroy(collection);
+    }
+    return NULL;
+}
+
+
+NSS_IMPLEMENT NSSTrust *
+nssTrustDomain_FindTrustForCertificate (
+  NSSTrustDomain *td,
+  NSSCertificate *c
+)
+{
+    NSSSlot **slots;
+    NSSSlot **slotp;
+    nssCryptokiObject *to = NULL;
+    nssPKIObject *pkio = NULL;
+    NSSTrust *rvt = NULL;
+    nssUpdateLevel updateLevel;
+    slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+    if (!slots) {
+	return (NSSTrust *)NULL;
+    }
+    for (slotp = slots; *slotp; slotp++) {
+	NSSToken *token = nssSlot_GetToken(*slotp);
+
+	if (token) {
+	    to = nssToken_FindTrustForCertificate(token, NULL, 
+	                                          &c->encoding,
+	                                          &c->issuer,
+	                                          &c->serial,
+	                                      nssTokenSearchType_TokenOnly);
+	    if (to) {
+		PRStatus status;
+		if (!pkio) {
+		    pkio = nssPKIObject_Create(NULL, to, td, NULL, nssPKILock);
+		    status = pkio ? PR_SUCCESS : PR_FAILURE;
+		} else {
+		    status = nssPKIObject_AddInstance(pkio, to);
+		}
+		if (status != PR_SUCCESS) {
+		    nssCryptokiObject_Destroy(to);
+		}
+	    }
+	    nssToken_Destroy(token);
+	}
+    }
+    if (pkio) {
+	rvt = nssTrust_Create(pkio, &c->encoding);
+	if (rvt) {
+	    pkio = NULL;  /* rvt object now owns the pkio reference */
+	}
+    }
+    nssSlotArray_Destroy(slots);
+    if (pkio) {
+	nssPKIObject_Destroy(pkio);
+    }
+    return rvt;
+}
+
+NSS_IMPLEMENT NSSCRL **
+nssTrustDomain_FindCRLsBySubject (
+  NSSTrustDomain *td,
+  NSSDER *subject
+)
+{
+    NSSSlot **slots;
+    NSSSlot **slotp;
+    NSSToken *token;
+    nssUpdateLevel updateLevel;
+    nssPKIObjectCollection *collection;
+    NSSCRL **rvCRLs = NULL;
+    collection = nssCRLCollection_Create(td, NULL);
+    if (!collection) {
+	return (NSSCRL **)NULL;
+    }
+    slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+    if (!slots) {
+	goto loser;
+    }
+    for (slotp = slots; *slotp; slotp++) {
+	token = nssSlot_GetToken(*slotp);
+	if (token) {
+	    PRStatus status = PR_FAILURE;
+	    nssSession *session;
+	    nssCryptokiObject **instances = NULL;
+	    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+
+	    /* get a session for the token */
+	    session = nssTrustDomain_GetSessionForToken(td, token);
+	    if (session) {
+		/* perform the traversal */
+		instances = nssToken_FindCRLsBySubject(token, session, subject,
+	                                               tokenOnly, 0, &status);
+	    }
+	    nssToken_Destroy(token);
+	    if (status == PR_SUCCESS) {
+		/* add the found CRL's to the collection */
+		status = nssPKIObjectCollection_AddInstances(collection, 
+							     instances, 0);
+	    }
+	    nss_ZFreeIf(instances);
+	}
+    }
+    rvCRLs = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
+loser:
+    nssPKIObjectCollection_Destroy(collection);
+    nssSlotArray_Destroy(slots);
+    return rvCRLs;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_GenerateKeyPair (
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap,
+  NSSPrivateKey **pvkOpt,
+  NSSPublicKey **pbkOpt,
+  PRBool privateKeyIsSensitive,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKey (
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap,
+  PRUint32 keysize,
+  NSSToken *destination,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKeyFromPassword (
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap,
+  NSSUTF8 *passwordOpt, /* if null, prompt */
+  NSSToken *destinationOpt,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSTrustDomain_FindSymmetricKeyByAlgorithmAndKeyID (
+  NSSTrustDomain *td,
+  NSSOID *algorithm,
+  NSSItem *keyID,
+  NSSCallback *uhhOpt
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+nssTrustDomain_CreateCryptoContext (
+  NSSTrustDomain *td,
+  NSSCallback *uhhOpt
+)
+{
+    return nssCryptoContext_Create(td, uhhOpt);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContext (
+  NSSTrustDomain *td,
+  NSSCallback *uhhOpt
+)
+{
+    return nssTrustDomain_CreateCryptoContext(td, uhhOpt);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithm (
+  NSSTrustDomain *td,
+  NSSOID *algorithm
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithmAndParameters (
+  NSSTrustDomain *td,
+  NSSAlgorithmAndParameters *ap
+)
+{
+    nss_SetError(NSS_ERROR_NOT_FOUND);
+    return NULL;
+}
+
diff --git a/mozilla/security/nss/lib/pki1/nsspki1.h b/mozilla/security/nss/lib/pki1/nsspki1.h
new file mode 100644
index 0000000..ceafd4a
--- /dev/null
+++ b/mozilla/security/nss/lib/pki1/nsspki1.h
@@ -0,0 +1,2872 @@
+/* ***** 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 ***** */
+
+#ifndef NSSPKI1_H
+#define NSSPKI1_H
+
+#ifdef DEBUG
+static const char NSSPKI1_CVS_ID[] = "@(#) $RCSfile: nsspki1.h,v $ $Revision: 1.3 $ $Date: 2005/01/20 02:25:49 $";
+#endif /* DEBUG */
+
+/*
+ * nsspki1.h
+ *
+ * This file contains the prototypes of the public NSS routines 
+ * dealing with the PKIX part-1 definitions.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+#ifndef NSSPKI1T_H
+#include "nsspki1t.h"
+#endif /* NSSPKI1T_H */
+
+#ifndef OIDDATA_H
+#include "oiddata.h"
+#endif /* OIDDATA_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSOID
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ *  NSSOID_CreateFromBER   -- constructor
+ *  NSSOID_CreateFromUTF8  -- constructor
+ *  (there is no explicit destructor)
+ * 
+ *  NSSOID_GetDEREncoding
+ *  NSSOID_GetUTF8Encoding
+ */
+
+extern const NSSOID *NSS_OID_UNKNOWN;
+
+/*
+ * NSSOID_CreateFromBER
+ *
+ * This routine creates an NSSOID by decoding a BER- or DER-encoded
+ * OID.  It may return NSS_OID_UNKNOWN upon error, in which case it 
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NSS_OID_UNKNOWN upon error
+ *  An NSSOID upon success
+ */
+
+NSS_EXTERN NSSOID *
+NSSOID_CreateFromBER
+(
+  NSSBER *berOid
+);
+
+extern const NSSError NSS_ERROR_INVALID_BER;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSOID_CreateFromUTF8
+ *
+ * This routine creates an NSSOID by decoding a UTF8 string 
+ * representation of an OID in dotted-number format.  The string may 
+ * optionally begin with an octothorpe.  It may return NSS_OID_UNKNOWN
+ * upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_STRING
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NSS_OID_UNKNOWN upon error
+ *  An NSSOID upon success
+ */
+
+NSS_EXTERN NSSOID *
+NSSOID_CreateFromUTF8
+(
+  NSSUTF8 *stringOid
+);
+
+extern const NSSError NSS_ERROR_INVALID_STRING;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSOID_GetDEREncoding
+ *
+ * This routine returns the DER encoding of the specified NSSOID.
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return return null upon error, in 
+ * which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NSSOID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSOID
+ */
+
+NSS_EXTERN NSSDER *
+NSSOID_GetDEREncoding
+(
+  const NSSOID *oid,
+  NSSDER *rvOpt,
+  NSSArena *arenaOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_NSSOID;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSOID_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing the dotted-number 
+ * encoding of the specified NSSOID.  If the optional arena argument 
+ * is non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return null upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NSSOID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string containing the dotted-digit encoding of 
+ *      this NSSOID
+ */
+
+NSS_EXTERN NSSUTF8 *
+NSSOID_GetUTF8Encoding
+(
+  const NSSOID *oid,
+  NSSArena *arenaOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_NSSOID;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSATAV
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ *  NSSATAV_CreateFromBER   -- constructor
+ *  NSSATAV_CreateFromUTF8  -- constructor
+ *  NSSATAV_Create          -- constructor
+ *
+ *  NSSATAV_Destroy
+ *  NSSATAV_GetDEREncoding
+ *  NSSATAV_GetUTF8Encoding
+ *  NSSATAV_GetType
+ *  NSSATAV_GetValue
+ *  NSSATAV_Compare
+ *  NSSATAV_Duplicate
+ */
+
+/*
+ * NSSATAV_CreateFromBER
+ * 
+ * This routine creates an NSSATAV by decoding a BER- or DER-encoded
+ * ATAV.  If the optional arena argument is non-null, the memory used 
+ * will be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error, 
+ * in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSATAV upon success
+ */
+
+NSS_EXTERN NSSATAV *
+NSSATAV_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *derATAV
+);
+
+extern const NSSError NSS_ERROR_INVALID_BER;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSATAV_CreateFromUTF8
+ *
+ * This routine creates an NSSATAV by decoding a UTF8 string in the
+ * "equals" format, e.g., "c=US."  If the optional arena argument is 
+ * non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_UNKNOWN_ATTRIBUTE
+ *  NSS_ERROR_INVALID_STRING
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSATAV upon success
+ */
+
+NSS_EXTERN NSSATAV *
+NSSATAV_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringATAV
+);
+
+extern const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE;
+extern const NSSError NSS_ERROR_INVALID_STRING;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSATAV_Create
+ *
+ * This routine creates an NSSATAV from the specified NSSOID and the
+ * specified data. If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory
+ * will be obtained from the heap.If the specified data length is zero, 
+ * the data is assumed to be terminated by first zero byte; this allows 
+ * UTF8 strings to be easily specified.  This routine may return NULL 
+ * upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_INVALID_NSSOID
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSATAV upon success
+ */
+
+NSS_EXTERN NSSATAV *
+NSSATAV_Create
+(
+  NSSArena *arenaOpt,
+  const NSSOID *oid,
+  const void *data,
+  PRUint32 length
+);
+
+extern const NSSError NSS_ERROR_INVALID_ARENA;
+extern const NSSError NSS_ERROR_INVALID_NSSOID;
+extern const NSSError NSS_ERROR_INVALID_POINTER;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSATAV_Destroy
+ *
+ * This routine will destroy an ATAV object.  It should eventually be
+ * called on all ATAVs created without an arena.  While it is not 
+ * necessary to call it on ATAVs created within an arena, it is not an
+ * error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+NSSATAV_Destroy
+(
+  NSSATAV *atav
+);
+
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+
+/*
+ * NSSATAV_GetDEREncoding
+ *
+ * This routine will DER-encode an ATAV object. If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSATAV
+ */
+
+NSS_EXTERN NSSDER *
+NSSATAV_GetDEREncoding
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSATAV_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the ATAV in "equals" notation (e.g., "o=Acme").  
+ * If the optional arena argument is non-null, the memory used will be
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return null upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string containing the "equals" encoding of the 
+ *      ATAV
+ */
+
+NSS_EXTERN NSSUTF8 *
+NSSATAV_GetUTF8Encoding
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSATAV_GetType
+ *
+ * This routine returns the NSSOID corresponding to the attribute type
+ * in the specified ATAV.  This routine may return NSS_OID_UNKNOWN 
+ * upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *
+ * Return value:
+ *  NSS_OID_UNKNOWN upon error
+ *  An element of enum NSSOIDenum upon success
+ */
+
+NSS_EXTERN const NSSOID *
+NSSATAV_GetType
+(
+  NSSATAV *atav
+);
+
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+
+/*
+ * NSSATAV_GetValue
+ *
+ * This routine returns an NSSItem containing the attribute value
+ * in the specified ATAV.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  This routine may return
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSItem containing the attribute value.
+ */
+
+NSS_EXTERN NSSUTF8 *
+NSSATAV_GetValue
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSATAV_Compare
+ *
+ * This routine compares two ATAVs for equality.  For two ATAVs to be
+ * equal, the attribute types must be the same, and the attribute 
+ * values must have equal length and contents.  The result of the 
+ * comparison will be stored at the location pointed to by the "equalp"
+ * variable, which must point to a valid PRBool.  This routine may 
+ * return PR_FAILURE upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+NSSATAV_Compare
+(
+  NSSATAV *atav1,
+  NSSATAV *atav2,
+  PRBool *equalp
+);
+
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
+
+/*
+ * NSSATAV_Duplicate
+ *
+ * This routine duplicates the specified ATAV.  If the optional arena 
+ * argument is non-null, the memory required will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL on error
+ *  A pointer to a new ATAV
+ */
+
+NSS_EXTERN NSSATAV *
+NSSATAV_Duplicate
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_ATAV;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * NSSRDN
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ *  NSSRDN_CreateFromBER   -- constructor
+ *  NSSRDN_CreateFromUTF8  -- constructor
+ *  NSSRDN_Create          -- constructor
+ *  NSSRDN_CreateSimple    -- constructor
+ *
+ *  NSSRDN_Destroy
+ *  NSSRDN_GetDEREncoding
+ *  NSSRDN_GetUTF8Encoding
+ *  NSSRDN_AddATAV
+ *  NSSRDN_GetATAVCount
+ *  NSSRDN_GetATAV
+ *  NSSRDN_GetSimpleATAV
+ *  NSSRDN_Compare
+ *  NSSRDN_Duplicate
+ */
+
+/*
+ * NSSRDN_CreateFromBER
+ *
+ * This routine creates an NSSRDN by decoding a BER- or DER-encoded 
+ * RDN.  If the optional arena argument is non-null, the memory used 
+ * will be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error, 
+ * in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+NSSRDN_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berRDN
+);
+
+/*
+ * NSSRDN_CreateFromUTF8
+ *
+ * This routine creates an NSSRDN by decoding an UTF8 string 
+ * consisting of either a single ATAV in the "equals" format, e.g., 
+ * "uid=smith," or one or more such ATAVs in parentheses, e.g., 
+ * "(sn=Smith,ou=Sales)."  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  This routine may return
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_UNKNOWN_ATTRIBUTE
+ *  NSS_ERROR_INVALID_STRING
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+NSSRDN_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringRDN
+);
+
+/*
+ * NSSRDN_Create
+ *
+ * This routine creates an NSSRDN from one or more NSSATAVs.  The
+ * final argument to this routine must be NULL.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_ATAV
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+NSSRDN_Create
+(
+  NSSArena *arenaOpt,
+  NSSATAV *atav1,
+  ...
+);
+
+/*
+ * NSSRDN_CreateSimple
+ *
+ * This routine creates a simple NSSRDN from a single NSSATAV.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_ATAV
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+NSSRDN_CreateSimple
+(
+  NSSArena *arenaOpt,
+  NSSATAV *atav
+);
+
+/*
+ * NSSRDN_Destroy
+ *
+ * This routine will destroy an RDN object.  It should eventually be
+ * called on all RDNs created without an arena.  While it is not 
+ * necessary to call it on RDNs created within an arena, it is not an
+ * error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will 
+ * create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *
+ * Return value:
+ *  PR_FAILURE upon failure
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+NSSRDN_Destroy
+(
+  NSSRDN *rdn
+);
+
+/*
+ * NSSRDN_GetDEREncoding
+ *
+ * This routine will DER-encode an RDN object.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSRDN
+ */
+
+NSS_EXTERN NSSDER *
+NSSRDN_GetDEREncoding
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSRDN_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the RDN.  A simple (one-ATAV) RDN will be simply
+ * the string representation of that ATAV; a non-simple RDN will be in
+ * parenthesised form.  If the optional arena argument is non-null, 
+ * the memory used will be obtained from that arena; otherwise, the 
+ * memory will be obtained from the heap.  This routine may return 
+ * null upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+NSSRDN_GetUTF8Encoding
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSRDN_AddATAV
+ *
+ * This routine adds an ATAV to the set of ATAVs in the specified RDN.
+ * Remember that RDNs consist of an unordered set of ATAVs.  If the
+ * RDN was created with a non-null arena argument, that same arena
+ * will be used for any additional required memory.  If the RDN was 
+ * created with a NULL arena argument, any additional memory will
+ * be obtained from the heap.  This routine returns a PRStatus value;
+ * it will return PR_SUCCESS upon success, and upon failure it will
+ * create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure
+ */
+
+NSS_EXTERN PRStatus
+NSSRDN_AddATAV
+(
+  NSSRDN *rdn,
+  NSSATAV *atav
+);
+
+/*
+ * NSSRDN_GetATAVCount
+ *
+ * This routine returns the cardinality of the set of ATAVs within
+ * the specified RDN.  This routine may return 0 upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *
+ * Return value:
+ *  0 upon error
+ *  A positive number upon success
+ */
+
+NSS_EXTERN PRUint32
+NSSRDN_GetATAVCount
+(
+  NSSRDN *rdn
+);
+
+/*
+ * NSSRDN_GetATAV
+ *
+ * This routine returns a pointer to an ATAV that is a member of
+ * the set of ATAVs within the specified RDN.  While the set of
+ * ATAVs within an RDN is unordered, this routine will return
+ * distinct values for distinct values of 'i' as long as the RDN
+ * is not changed in any way.  The RDN may be changed by calling
+ * NSSRDN_AddATAV.  The value of the variable 'i' is on the range
+ * [0,c) where c is the cardinality returned from NSSRDN_GetATAVCount.
+ * The caller owns the ATAV the pointer to which is returned.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_VALUE_OUT_OF_RANGE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSATAV
+ */
+
+NSS_EXTERN NSSATAV *
+NSSRDN_GetATAV
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt,
+  PRUint32 i
+);
+
+/*
+ * NSSRDN_GetSimpleATAV
+ *
+ * Most RDNs are actually very simple, with a single ATAV.  This 
+ * routine will return the single ATAV from such an RDN.  The caller
+ * owns the ATAV the pointer to which is returned.  If the optional
+ * arena argument is non-null, the memory used will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.
+ * This routine may return NULL upon error, including the case where
+ * the set of ATAVs in the RDN is nonsingular.  Upon error, this
+ * routine will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_RDN_NOT_SIMPLE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSATAV
+ */
+
+NSS_EXTERN NSSATAV *
+NSSRDN_GetSimpleATAV
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSRDN_Compare
+ *
+ * This routine compares two RDNs for equality.  For two RDNs to be
+ * equal, they must have the same number of ATAVs, and every ATAV in
+ * one must be equal to an ATAV in the other.  (Note that the sets
+ * of ATAVs are unordered.)  The result of the comparison will be
+ * stored at the location pointed to by the "equalp" variable, which
+ * must point to a valid PRBool.  This routine may return PR_FAILURE
+ * upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+NSSRDN_Compare
+(
+  NSSRDN *rdn1,
+  NSSRDN *rdn2,
+  PRBool *equalp
+);
+
+/*
+ * NSSRDN_Duplicate
+ *
+ * This routine duplicates the specified RDN.  If the optional arena
+ * argument is non-null, the memory required will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.
+ * This routine may return NULL upon error, in which case it will have
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL on error
+ *  A pointer to a new RDN
+ */
+
+NSS_EXTERN NSSRDN *
+NSSRDN_Duplicate
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSRDNSeq
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ *  NSSRDNSeq_CreateFromBER   -- constructor
+ *  NSSRDNSeq_CreateFromUTF8  -- constructor
+ *  NSSRDNSeq_Create          -- constructor
+ *
+ *  NSSRDNSeq_Destroy
+ *  NSSRDNSeq_GetDEREncoding
+ *  NSSRDNSeq_GetUTF8Encoding
+ *  NSSRDNSeq_AppendRDN
+ *  NSSRDNSeq_GetRDNCount
+ *  NSSRDNSeq_GetRDN
+ *  NSSRDNSeq_Compare
+ *  NSSRDNSeq_Duplicate
+ */
+
+/*
+ * NSSRDNSeq_CreateFromBER
+ *
+ * This routine creates an NSSRDNSeq by decoding a BER- or DER-encoded 
+ * sequence of RDNs.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  This routine may return 
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDNSeq upon success
+ */
+
+NSS_EXTERN NSSRDNSeq *
+NSSRDNSeq_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berRDNSeq
+);
+
+/*
+ * NSSRDNSeq_CreateFromUTF8
+ *
+ * This routine creates an NSSRDNSeq by decoding a UTF8 string
+ * consisting of a comma-separated sequence of RDNs, such as
+ * "(sn=Smith,ou=Sales),o=Acme,c=US."  If the optional arena argument
+ * is non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_UNKNOWN_ATTRIBUTE
+ *  NSS_ERROR_INVALID_STRING
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDNSeq upon success
+ */
+
+NSS_EXTERN NSSRDNSeq *
+NSSRDNSeq_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringRDNSeq
+);
+
+/*
+ * NSSRDNSeq_Create
+ *
+ * This routine creates an NSSRDNSeq from one or more NSSRDNs.  The
+ * final argument to this routine must be NULL.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_RDN
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointero to an NSSRDNSeq upon success
+ */
+
+NSS_EXTERN NSSRDNSeq *
+NSSRDNSeq_Create
+(
+  NSSArena *arenaOpt,
+  NSSRDN *rdn1,
+  ...
+);
+
+/*
+ * NSSRDNSeq_Destroy
+ *
+ * This routine will destroy an RDNSeq object.  It should eventually 
+ * be called on all RDNSeqs created without an arena.  While it is not
+ * necessary to call it on RDNSeqs created within an arena, it is not
+ * an error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+NSSRDNSeq_Destroy
+(
+  NSSRDNSeq *rdnseq
+);
+
+/*
+ * NSSRDNSeq_GetDEREncoding
+ *
+ * This routine will DER-encode an RDNSeq object.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.
+ * This routine may return null upon error, in which case it will have
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSRDNSeq
+ */
+
+NSS_EXTERN NSSDER *
+NSSRDNSeq_GetDEREncoding
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSRDNSeq_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the RDNSeq as a comma-separated sequence of RDNs.  
+ * If the optional arena argument is non-null, the memory used will be
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return null upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+NSSRDNSeq_GetUTF8Encoding
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSRDNSeq_AppendRDN
+ *
+ * This routine appends an RDN to the end of the existing RDN 
+ * sequence.  If the RDNSeq was created with a non-null arena 
+ * argument, that same arena will be used for any additional required
+ * memory.  If the RDNSeq was created with a NULL arena argument, any
+ * additional memory will be obtained from the heap.  This routine
+ * returns a PRStatus value; it will return PR_SUCCESS upon success,
+ * and upon failure it will create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure
+ */
+
+NSS_EXTERN PRStatus
+NSSRDNSeq_AppendRDN
+(
+  NSSRDNSeq *rdnseq,
+  NSSRDN *rdn
+);
+
+/*
+ * NSSRDNSeq_GetRDNCount
+ *
+ * This routine returns the cardinality of the sequence of RDNs within
+ * the specified RDNSeq.  This routine may return 0 upon error, in 
+ * which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *
+ * Return value:
+ *  0 upon error
+ *  A positive number upon success
+ */
+
+NSS_EXTERN PRUint32
+NSSRDNSeq_GetRDNCount
+(
+  NSSRDNSeq *rdnseq
+);
+
+/*
+ * NSSRDNSeq_GetRDN
+ *
+ * This routine returns a pointer to the i'th RDN in the sequence of
+ * RDNs that make up the specified RDNSeq.  The sequence begins with
+ * the top-level (e.g., "c=US") RDN.  The value of the variable 'i'
+ * is on the range [0,c) where c is the cardinality returned from
+ * NSSRDNSeq_GetRDNCount.  The caller owns the RDN the pointer to which
+ * is returned.  If the optional arena argument is non-null, the memory
+ * used will be obtained from that areana; otherwise, the memory will 
+ * be obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have created an error stack.  Note that the 
+ * usual string representation of RDN Sequences is from last to first.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_VALUE_OUT_OF_RANGE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRDN
+ */
+
+NSS_EXTERN NSSRDN *
+NSSRDNSeq_GetRDN
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt,
+  PRUint32 i
+);
+
+/*
+ * NSSRDNSeq_Compare
+ *
+ * This routine compares two RDNSeqs for equality.  For two RDNSeqs to 
+ * be equal, they must have the same number of RDNs, and each RDN in
+ * one sequence must be equal to the corresponding RDN in the other
+ * sequence.  The result of the comparison will be stored at the
+ * location pointed to by the "equalp" variable, which must point to a
+ * valid PRBool.  This routine may return PR_FAILURE upon error, in
+ * which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+NSSRDNSeq_Compare
+(
+  NSSRDNSeq *rdnseq1,
+  NSSRDNSeq *rdnseq2,
+  PRBool *equalp
+);
+
+/*
+ * NSSRDNSeq_Duplicate
+ *
+ * This routine duplicates the specified RDNSeq.  If the optional arena
+ * argument is non-null, the memory required will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This 
+ * routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new RDNSeq
+ */
+
+NSS_EXTERN NSSRDNSeq *
+NSSRDNSeq_Duplicate
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ * NSSName_CreateFromBER   -- constructor
+ * NSSName_CreateFromUTF8  -- constructor
+ * NSSName_Create          -- constructor
+ *
+ * NSSName_Destroy
+ * NSSName_GetDEREncoding
+ * NSSName_GetUTF8Encoding
+ * NSSName_GetChoice
+ * NSSName_GetRDNSequence
+ * NSSName_GetSpecifiedChoice
+ * NSSName_Compare
+ * NSSName_Duplicate
+ *
+ * NSSName_GetUID
+ * NSSName_GetEmail
+ * NSSName_GetCommonName
+ * NSSName_GetOrganization
+ * NSSName_GetOrganizationalUnits
+ * NSSName_GetStateOrProvince
+ * NSSName_GetLocality
+ * NSSName_GetCountry
+ * NSSName_GetAttribute
+ */
+
+/*
+ * NSSName_CreateFromBER
+ *
+ * This routine creates an NSSName by decoding a BER- or DER-encoded 
+ * (directory) Name.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, 
+ * the memory will be obtained from the heap.  This routine may
+ * return NULL upon error, in which case it will have created an error
+ * stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSName upon success
+ */
+
+NSS_EXTERN NSSName *
+NSSName_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berName
+);
+
+/*
+ * NSSName_CreateFromUTF8
+ *
+ * This routine creates an NSSName by decoding a UTF8 string 
+ * consisting of the string representation of one of the choices of 
+ * (directory) names.  Currently the only choice is an RDNSeq.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  The routine may return NULL upon error, in which
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_STRING
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSName upon success
+ */
+
+NSS_EXTERN NSSName *
+NSSName_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringName
+);
+
+/*
+ * NSSName_Create
+ *
+ * This routine creates an NSSName with the specified choice of
+ * underlying name types.  The value of the choice variable must be
+ * one of the values of the NSSNameChoice enumeration, and the type
+ * of the arg variable must be as specified in the following table:
+ *
+ *   Choice                     Type
+ *   ========================   ===========
+ *   NSSNameChoiceRdnSequence   NSSRDNSeq *
+ *
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_CHOICE
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSName upon success
+ */
+
+NSS_EXTERN NSSName *
+NSSName_Create
+(
+  NSSArena *arenaOpt,
+  NSSNameChoice choice,
+  void *arg
+);
+
+/*
+ * NSSName_Destroy
+ *
+ * This routine will destroy a Name object.  It should eventually be
+ * called on all Names created without an arena.  While it is not
+ * necessary to call it on Names created within an arena, it is not
+ * an error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+NSSName_Destroy
+(
+  NSSName *name
+);
+
+/*
+ * NSSName_GetDEREncoding
+ *
+ * This routine will DER-encode a name object.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSName
+ */
+
+NSS_EXTERN NSSDER *
+NSSName_GetDEREncoding
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the Name in the format specified by the 
+ * underlying name choice.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the 
+ * memory will be obtained from the heap.  This routine may return
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+NSSName_GetUTF8Encoding
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetChoice
+ *
+ * This routine returns the type of the choice underlying the specified
+ * name.  The return value will be a member of the NSSNameChoice 
+ * enumeration.  This routine may return NSSNameChoiceInvalid upon 
+ * error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *
+ * Return value:
+ *  NSSNameChoiceInvalid upon error
+ *  An other member of the NSSNameChoice enumeration upon success
+ */
+
+NSS_EXTERN NSSNameChoice
+NSSName_GetChoice
+(
+  NSSName *name
+);
+
+/*
+ * NSSName_GetRDNSequence
+ *
+ * If the choice underlying the specified NSSName is that of an 
+ * RDNSequence, this routine will return a pointer to that RDN
+ * sequence.  Otherwise, this routine will place an error on the
+ * error stack, and return NULL.  If the optional arena argument is
+ * non-null, the memory required will be obtained from that arena;
+ * otherwise, the memory will be obtained from the heap.  The
+ * caller owns the returned pointer.  This routine may return NULL
+ * upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRDNSeq
+ */
+
+NSS_EXTERN NSSRDNSeq *
+NSSName_GetRDNSequence
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetSpecifiedChoice
+ *
+ * If the choice underlying the specified NSSName matches the specified
+ * choice, a caller-owned pointer to that underlying object will be
+ * returned.  Otherwise, an error will be placed on the error stack and
+ * NULL will be returned.  If the optional arena argument is non-null, 
+ * the memory required will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  The caller owns the returned
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer, which must be typecast
+ */
+
+NSS_EXTERN void *
+NSSName_GetSpecifiedChoice
+(
+  NSSName *name,
+  NSSNameChoice choice,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_Compare
+ *
+ * This routine compares two Names for equality.  For two Names to be
+ * equal, they must have the same choice of underlying types, and the
+ * underlying values must be equal.  The result of the comparison will
+ * be stored at the location pointed to by the "equalp" variable, which
+ * must point to a valid PRBool. This routine may return PR_FAILURE
+ * upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+NSSName_Compare
+(
+  NSSName *name1,
+  NSSName *name2,
+  PRBool *equalp
+);
+
+/*
+ * NSSName_Duplicate
+ *
+ * This routine duplicates the specified nssname.  If the optional
+ * arena argument is non-null, the memory required will be obtained
+ * from that arena; otherwise, the memory will be obtained from the
+ * heap.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new NSSName
+ */
+
+NSS_EXTERN NSSName *
+NSSName_Duplicate
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetUID
+ *
+ * This routine will attempt to derive a user identifier from the
+ * specified name, if the choices and content of the name permit.
+ * If the Name consists of a Sequence of Relative Distinguished 
+ * Names containing a UID attribute, the UID will be the value of 
+ * that attribute.  Note that no UID attribute is defined in either 
+ * PKIX or PKCS#9; rather, this seems to derive from RFC 1274, which 
+ * defines the type as a caseIgnoreString.  We'll return a Directory 
+ * String.  If the optional arena argument is non-null, the memory 
+ * used will be obtained from that arena; otherwise, the memory will 
+ * be obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_UID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String.
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSName_GetUID
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetEmail
+ *
+ * This routine will attempt to derive an email address from the
+ * specified name, if the choices and content of the name permit.  
+ * If the Name consists of a Sequence of Relative Distinguished 
+ * Names containing either a PKIX email address or a PKCS#9 email
+ * address, the result will be the value of that attribute.  If the
+ * optional arena argument is non-null, the memory used will be
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_EMAIL
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr IA5 String */
+NSSName_GetEmail
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetCommonName
+ *
+ * This routine will attempt to derive a common name from the
+ * specified name, if the choices and content of the name permit.  
+ * If the Name consists of a Sequence of Relative Distinguished Names
+ * containing a PKIX Common Name, the result will be that name.  If 
+ * the optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_COMMON_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSName_GetCommonName
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetOrganization
+ *
+ * This routine will attempt to derive an organisation name from the
+ * specified name, if the choices and content of the name permit.  
+ * If Name consists of a Sequence of Relative Distinguished names 
+ * containing a PKIX Organization, the result will be the value of 
+ * that attribute.  If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  This routine may return NULL upon 
+ * error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_ORGANIZATION
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSName_GetOrganization
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetOrganizationalUnits
+ *
+ * This routine will attempt to derive a sequence of organisational 
+ * unit names from the specified name, if the choices and content of 
+ * the name permit.  If the Name consists of a Sequence of Relative 
+ * Distinguished Names containing one or more organisational units,
+ * the result will be the values of those attributes.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from 
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_ORGANIZATIONAL_UNITS
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a null-terminated array of UTF8 Strings
+ */
+
+NSS_EXTERN NSSUTF8 ** /* XXX fgmr DirectoryString */
+NSSName_GetOrganizationalUnits
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetStateOrProvince
+ *
+ * This routine will attempt to derive a state or province name from 
+ * the specified name, if the choices and content of the name permit.
+ * If the Name consists of a Sequence of Relative Distinguished Names
+ * containing a state or province, the result will be the value of 
+ * that attribute.  If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  This routine may return NULL upon 
+ * error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_STATE_OR_PROVINCE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSName_GetStateOrProvince
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetLocality
+ *
+ * This routine will attempt to derive a locality name from the 
+ * specified name, if the choices and content of the name permit.  If
+ * the Name consists of a Sequence of Relative Distinguished names
+ * containing a Locality, the result will be the value of that 
+ * attribute.  If the optional arena argument is non-null, the memory 
+ * used will be obtained from that arena; otherwise, the memory will 
+ * be obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_LOCALITY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSName_GetLocality
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetCountry
+ *
+ * This routine will attempt to derive a country name from the 
+ * specified name, if the choices and content of the name permit.
+ * If the Name consists of a Sequence of Relative Distinguished 
+ * Names containing a Country, the result will be the value of
+ * that attribute..  If the optional arena argument is non-null, 
+ * the memory used will be obtained from that arena; otherwise, 
+ * the memory will be obtained from the heap.  This routine may 
+ * return NULL upon error, in which case it will have created an 
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_COUNTRY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr PrintableString */
+NSSName_GetCountry
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSName_GetAttribute
+ *
+ * If the specified name consists of a Sequence of Relative 
+ * Distinguished Names containing an attribute with the specified 
+ * type, and the actual value of that attribute may be expressed 
+ * with a Directory String, then the value of that attribute will 
+ * be returned as a Directory String.  If the optional arena argument 
+ * is non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine 
+ * may return NULL upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_ATTRIBUTE
+ *  NSS_ERROR_ATTRIBUTE_VALUE_NOT_STRING
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSName_GetAttribute
+(
+  NSSName *name,
+  NSSOID *attribute,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ * NSSGeneralName_CreateFromBER   -- constructor
+ * NSSGeneralName_CreateFromUTF8  -- constructor
+ * NSSGeneralName_Create          -- constructor
+ *
+ * NSSGeneralName_Destroy
+ * NSSGeneralName_GetDEREncoding
+ * NSSGeneralName_GetUTF8Encoding
+ * NSSGeneralName_GetChoice
+ * NSSGeneralName_GetOtherName
+ * NSSGeneralName_GetRfc822Name
+ * NSSGeneralName_GetDNSName
+ * NSSGeneralName_GetX400Address
+ * NSSGeneralName_GetDirectoryName
+ * NSSGeneralName_GetEdiPartyName
+ * NSSGeneralName_GetUniformResourceIdentifier
+ * NSSGeneralName_GetIPAddress
+ * NSSGeneralName_GetRegisteredID
+ * NSSGeneralName_GetSpecifiedChoice
+ * NSSGeneralName_Compare
+ * NSSGeneralName_Duplicate
+ *
+ * NSSGeneralName_GetUID
+ * NSSGeneralName_GetEmail
+ * NSSGeneralName_GetCommonName
+ * NSSGeneralName_GetOrganization
+ * NSSGeneralName_GetOrganizationalUnits
+ * NSSGeneralName_GetStateOrProvince
+ * NSSGeneralName_GetLocality
+ * NSSGeneralName_GetCountry
+ * NSSGeneralName_GetAttribute
+ */
+
+/*
+ * NSSGeneralName_CreateFromBER
+ *
+ * This routine creates an NSSGeneralName by decoding a BER- or DER-
+ * encoded general name.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the 
+ * memory will be obtained from the heap.  This routine may return 
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralName upon success
+ */
+
+NSS_EXTERN NSSGeneralName *
+NSSGeneralName_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berGeneralName
+);
+
+/*
+ * NSSGeneralName_CreateFromUTF8
+ *
+ * This routine creates an NSSGeneralName by decoding a UTF8 string
+ * consisting of the string representation of one of the choices of
+ * general names.  If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory
+ * will be obtained from the heap.  The routine may return NULL upon
+ * error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_STRING
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralName upon success
+ */
+
+NSS_EXTERN NSSGeneralName *
+NSSGeneralName_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringGeneralName
+);
+
+/*
+ * NSSGeneralName_Create
+ *
+ * This routine creates an NSSGeneralName with the specified choice of
+ * underlying name types.  The value of the choice variable must be one
+ * of the values of the NSSGeneralNameChoice enumeration, and the type
+ * of the arg variable must be as specified in the following table:
+ *
+ *   Choice                                         Type
+ *   ============================================   =========
+ *   NSSGeneralNameChoiceOtherName
+ *   NSSGeneralNameChoiceRfc822Name
+ *   NSSGeneralNameChoiceDNSName
+ *   NSSGeneralNameChoiceX400Address
+ *   NSSGeneralNameChoiceDirectoryName              NSSName *
+ *   NSSGeneralNameChoiceEdiPartyName
+ *   NSSGeneralNameChoiceUniformResourceIdentifier
+ *   NSSGeneralNameChoiceIPAddress
+ *   NSSGeneralNameChoiceRegisteredID
+ *
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have created an error stack.
+ *
+ * The error may be one fo the following values:
+ *  NSS_ERROR_INVALID_CHOICE
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralName upon success
+ */
+
+NSS_EXTERN NSSGeneralName *
+NSSGeneralName_Create
+(
+  NSSGeneralNameChoice choice,
+  void *arg
+);
+
+/*
+ * NSSGeneralName_Destroy
+ * 
+ * This routine will destroy a General Name object.  It should 
+ * eventually be called on all General Names created without an arena.
+ * While it is not necessary to call it on General Names created within
+ * an arena, it is not an error to do so.  This routine returns a
+ * PRStatus value; if successful, it will return PR_SUCCESS. If 
+ * usuccessful, it will create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *
+ * Return value:
+ *  PR_FAILURE upon failure
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+NSSGeneralName_Destroy
+(
+  NSSGeneralName *generalName
+);
+
+/*
+ * NSSGeneralName_GetDEREncoding
+ *
+ * This routine will DER-encode a name object.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSGeneralName
+ */
+
+NSS_EXTERN NSSDER *
+NSSGeneralName_GetDEREncoding
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the General Name in the format specified by the
+ * underlying name choice.  If the optional arena argument is 
+ * non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+NSSGeneralName_GetUTF8Encoding
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetChoice
+ *
+ * This routine returns the type of choice underlying the specified 
+ * general name.  The return value will be a member of the 
+ * NSSGeneralNameChoice enumeration.  This routine may return 
+ * NSSGeneralNameChoiceInvalid upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *
+ * Return value:
+ *  NSSGeneralNameChoiceInvalid upon error
+ *  An other member of the NSSGeneralNameChoice enumeration 
+ */
+
+NSS_EXTERN NSSGeneralNameChoice
+NSSGeneralName_GetChoice
+(
+  NSSGeneralName *generalName
+);
+
+/*
+ * NSSGeneralName_GetOtherName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * Other Name, this routine will return a pointer to that Other name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSOtherName
+ */
+
+NSS_EXTERN NSSOtherName *
+NSSGeneralName_GetOtherName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetRfc822Name
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * RFC 822 Name, this routine will return a pointer to that name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRFC822Name
+ */
+
+NSS_EXTERN NSSRFC822Name *
+NSSGeneralName_GetRfc822Name
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetDNSName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a 
+ * DNS Name, this routine will return a pointer to that DNS name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSDNSName
+ */
+
+NSS_EXTERN NSSDNSName *
+NSSGeneralName_GetDNSName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetX400Address
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * X.400 Address, this routine will return a pointer to that Address.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSX400Address
+ */
+
+NSS_EXTERN NSSX400Address *
+NSSGeneralName_GetX400Address
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetDirectoryName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a
+ * (directory) Name, this routine will return a pointer to that name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSName
+ */
+
+NSS_EXTERN NSSName *
+NSSGeneralName_GetName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetEdiPartyName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * EDI Party Name, this routine will return a pointer to that name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSEdiPartyName
+ */
+
+NSS_EXTERN NSSEdiPartyName *
+NSSGeneralName_GetEdiPartyName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetUniformResourceIdentifier
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a
+ * URI, this routine will return a pointer to that URI.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSURI
+ */
+
+NSS_EXTERN NSSURI *
+NSSGeneralName_GetUniformResourceIdentifier
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetIPAddress
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * IP Address , this routine will return a pointer to that address.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSIPAddress
+ */
+
+NSS_EXTERN NSSIPAddress *
+NSSGeneralName_GetIPAddress
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetRegisteredID
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a
+ * Registered ID, this routine will return a pointer to that ID.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRegisteredID
+ */
+
+NSS_EXTERN NSSRegisteredID *
+NSSGeneralName_GetRegisteredID
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetSpecifiedChoice
+ *
+ * If the choice underlying the specified NSSGeneralName matches the
+ * specified choice, a caller-owned pointer to that underlying object
+ * will be returned.  Otherwise, an error will be placed on the error
+ * stack and NULL will be returned.  If the optional arena argument
+ * is non-null, the memory required will be obtained from that arena;
+ * otherwise, the memory will be obtained from the heap.  The caller
+ * owns the returned pointer.  This routine may return NULL upon 
+ * error, in which caes it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer, which must be typecast
+ */
+
+NSS_EXTERN void *
+NSSGeneralName_GetSpecifiedChoice
+(
+  NSSGeneralName *generalName,
+  NSSGeneralNameChoice choice,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_Compare
+ * 
+ * This routine compares two General Names for equality.  For two 
+ * General Names to be equal, they must have the same choice of
+ * underlying types, and the underlying values must be equal.  The
+ * result of the comparison will be stored at the location pointed
+ * to by the "equalp" variable, which must point to a valid PRBool.
+ * This routine may return PR_FAILURE upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following value:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+NSSGeneralName_Compare
+(
+  NSSGeneralName *generalName1,
+  NSSGeneralName *generalName2,
+  PRBool *equalp
+);
+
+/*
+ * NSSGeneralName_Duplicate
+ *
+ * This routine duplicates the specified General Name.  If the optional
+ * arena argument is non-null, the memory required will be obtained
+ * from that arena; otherwise, the memory will be obtained from the
+ * heap.  This routine may return NULL upon error, in which case it 
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new NSSGeneralName
+ */
+
+NSS_EXTERN NSSGeneralName *
+NSSGeneralName_Duplicate
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetUID
+ *
+ * This routine will attempt to derive a user identifier from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished Names containing a UID
+ * attribute, the UID will be the value of that attribute.  Note
+ * that no UID attribute is defined in either PKIX or PKCS#9; 
+ * rather, this seems to derive from RFC 1274, which defines the
+ * type as a caseIgnoreString.  We'll return a Directory String.
+ * If the optional arena argument is non-null, the memory used
+ * will be obtained from that arena; otherwise, the memory will be
+ * obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_UID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String.
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSGeneralName_GetUID
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetEmail
+ *
+ * This routine will attempt to derive an email address from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing either
+ * a PKIX email address or a PKCS#9 email address, the result will
+ * be the value of that attribute.  If the General Name is an RFC 822
+ * Name, the result will be the string form of that name.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_EMAIL
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr IA5String */
+NSSGeneralName_GetEmail
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetCommonName
+ *
+ * This routine will attempt to derive a common name from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing a PKIX
+ * Common Name, the result will be that name.  If the optional arena 
+ * argument is non-null, the memory used will be obtained from that 
+ * arena; otherwise, the memory will be obtained from the heap.  This 
+ * routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_COMMON_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSGeneralName_GetCommonName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetOrganization
+ *
+ * This routine will attempt to derive an organisation name from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing an
+ * Organization, the result will be the value of that attribute.  
+ * If the optional arena argument is non-null, the memory used will 
+ * be obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_ORGANIZATION
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSGeneralName_GetOrganization
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetOrganizationalUnits
+ *
+ * This routine will attempt to derive a sequence of organisational 
+ * unit names from the specified general name, if the choices and 
+ * content of the name permit.  If the General Name is a (directory) 
+ * Name consisting of a Sequence of Relative Distinguished names 
+ * containing one or more organisational units, the result will 
+ * consist of those units.  If the optional arena  argument is non-
+ * null, the memory used will be obtained from that arena; otherwise, 
+ * the memory will be obtained from the heap.  This routine may return 
+ * NULL upon error, in which case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_ORGANIZATIONAL_UNITS
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a null-terminated array of UTF8 Strings
+ */
+
+NSS_EXTERN NSSUTF8 ** /* XXX fgmr DirectoryString */
+NSSGeneralName_GetOrganizationalUnits
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetStateOrProvince
+ *
+ * This routine will attempt to derive a state or province name from 
+ * the specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing a state or 
+ * province, the result will be the value of that attribute.  If the 
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_STATE_OR_PROVINCE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSGeneralName_GetStateOrProvince
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetLocality
+ *
+ * This routine will attempt to derive a locality name from 
+ * the specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing a Locality, 
+ * the result will be the value of that attribute.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from 
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_LOCALITY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSGeneralName_GetLocality
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetCountry
+ *
+ * This routine will attempt to derive a country name from the 
+ * specified general name, if the choices and content of the name 
+ * permit.  If the General Name is a (directory) Name consisting of a
+ * Sequence of Relative Distinguished names containing a Country, the 
+ * result will be the value of that attribute.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from 
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_COUNTRY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr PrintableString */
+NSSGeneralName_GetCountry
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralName_GetAttribute
+ *
+ * If the specified general name is a (directory) name consisting
+ * of a Sequence of Relative Distinguished Names containing an 
+ * attribute with the specified type, and the actual value of that
+ * attribute may be expressed with a Directory String, then the
+ * value of that attribute will be returned as a Directory String.
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_ATTRIBUTE
+ *  NSS_ERROR_ATTRIBUTE_VALUE_NOT_STRING
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+NSSGeneralName_GetAttribute
+(
+  NSSGeneralName *generalName,
+  NSSOID *attribute,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralNameSeq
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ *  NSSGeneralNameSeq_CreateFromBER   -- constructor
+ *  NSSGeneralNameSeq_Create          -- constructor
+ *
+ *  NSSGeneralNameSeq_Destroy
+ *  NSSGeneralNameSeq_GetDEREncoding
+ *  NSSGeneralNameSeq_AppendGeneralName
+ *  NSSGeneralNameSeq_GetGeneralNameCount
+ *  NSSGeneralNameSeq_GetGeneralName
+ *  NSSGeneralNameSeq_Compare
+ *  NSSGeneralnameSeq_Duplicate
+ */
+
+/*
+ * NSSGeneralNameSeq_CreateFromBER
+ *
+ * This routine creates a general name sequence by decoding a BER-
+ * or DER-encoded GeneralNames.  If the optional arena argument is
+ * non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralNameSeq upon success
+ */
+
+NSS_EXTERN NSSGeneralNameSeq *
+NSSGeneralNameSeq_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berGeneralNameSeq
+);
+
+/*
+ * NSSGeneralNameSeq_Create
+ *
+ * This routine creates an NSSGeneralNameSeq from one or more General
+ * Names.  The final argument to this routine must be NULL.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralNameSeq upon success
+ */
+
+NSS_EXTERN NSSGeneralNameSeq *
+NSSGeneralNameSeq_Create
+(
+  NSSArena *arenaOpt,
+  NSSGeneralName *generalName1,
+  ...
+);
+
+/*
+ * NSSGeneralNameSeq_Destroy
+ *
+ * This routine will destroy an NSSGeneralNameSeq object.  It should
+ * eventually be called on all NSSGeneralNameSeqs created without an
+ * arena.  While it is not necessary to call it on NSSGeneralNameSeq's
+ * created within an arena, it is not an error to do so.  This routine
+ * returns a PRStatus value; if successful, it will return PR_SUCCESS.
+ * If unsuccessful, it will create an error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+NSSGeneralNameSeq_Destroy
+(
+  NSSGeneralNameSeq *generalNameSeq
+);
+
+/*
+ * NSSGeneralNameSeq_GetDEREncoding
+ *
+ * This routine will DER-encode an NSSGeneralNameSeq object.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return null upon error, in which
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSGeneralNameSeq
+ */
+
+NSS_EXTERN NSSDER *
+NSSGeneralNameSeq_GetDEREncoding
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralNameSeq_AppendGeneralName
+ *
+ * This routine appends a General Name to the end of the existing
+ * General Name Sequence.  If the sequence was created with a non-null
+ * arena argument, that same arena will be used for any additional
+ * required memory.  If the sequence was created with a NULL arena
+ * argument, any additional memory will be obtained from the heap.
+ * This routine returns a PRStatus value; it will return PR_SUCCESS
+ * upon success, and upon failure it will create an error stack and 
+ * return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ * 
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure.
+ */
+
+NSS_EXTERN PRStatus
+NSSGeneralNameSeq_AppendGeneralName
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSGeneralName *generalName
+);
+
+/*
+ * NSSGeneralNameSeq_GetGeneralNameCount
+ *
+ * This routine returns the cardinality of the specified General name
+ * Sequence.  This routine may return 0 upon error, in which case it
+ * will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *
+ * Return value;
+ *  0 upon error
+ *  A positive number upon success
+ */
+
+NSS_EXTERN PRUint32
+NSSGeneralNameSeq_GetGeneralNameCount
+(
+  NSSGeneralNameSeq *generalNameSeq
+);
+
+/*
+ * NSSGeneralNameSeq_GetGeneralName
+ *
+ * This routine returns a pointer to the i'th General Name in the 
+ * specified General Name Sequence.  The value of the variable 'i' is
+ * on the range [0,c) where c is the cardinality returned from 
+ * NSSGeneralNameSeq_GetGeneralNameCount.  The caller owns the General
+ * Name the pointer to which is returned.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have 
+ * created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_VALUE_OUT_OF_RANGE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to a General Name.
+ */
+
+NSS_EXTERN NSSGeneralName *
+NSSGeneralNameSeq_GetGeneralName
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSArena *arenaOpt,
+  PRUint32 i
+);
+
+/*
+ * NSSGeneralNameSeq_Compare
+ *
+ * This routine compares two General Name Sequences for equality.  For
+ * two General Name Sequences to be equal, they must have the same
+ * cardinality, and each General Name in one sequence must be equal to
+ * the corresponding General Name in the other.  The result of the
+ * comparison will be stored at the location pointed to by the "equalp"
+ * variable, which must point to a valid PRBool.  This routine may 
+ * return PR_FAILURE upon error, in which case it will have created an
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+NSSGeneralNameSeq_Compare
+(
+  NSSGeneralNameSeq *generalNameSeq1,
+  NSSGeneralNameSeq *generalNameSeq2,
+  PRBool *equalp
+);
+
+/*
+ * NSSGeneralNameSeq_Duplicate
+ *
+ * This routine duplicates the specified sequence of general names.  If
+ * the optional arena argument is non-null, the memory required will be
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have created an error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new General Name Sequence.
+ */
+
+NSS_EXTERN NSSGeneralNameSeq *
+NSSGeneralNameSeq_Duplicate
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSArena *arenaOpt
+);
+
+PR_END_EXTERN_C
+
+#endif /* NSSPT1M_H */
diff --git a/mozilla/security/nss/lib/pki1/nsspki1t.h b/mozilla/security/nss/lib/pki1/nsspki1t.h
new file mode 100644
index 0000000..ab47ccd
--- /dev/null
+++ b/mozilla/security/nss/lib/pki1/nsspki1t.h
@@ -0,0 +1,205 @@
+/* ***** 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 ***** */
+
+#ifndef NSSPKI1T_H
+#define NSSPKI1T_H
+
+#ifdef DEBUG
+static const char NSSPKI1T_CVS_ID[] = "@(#) $RCSfile: nsspki1t.h,v $ $Revision: 1.3 $ $Date: 2005/01/20 02:25:49 $";
+#endif /* DEBUG */
+
+/*
+ * nsspki1t.h
+ *
+ * This file contains the public type definitions for the PKIX part-1
+ * objects.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * OBJECT IDENTIFIER
+ *
+ * This is the basic OID that crops up everywhere.
+ */
+
+struct NSSOIDStr;
+typedef struct NSSOIDStr NSSOID;
+
+/*
+ * AttributeTypeAndValue
+ *
+ * This structure contains an attribute type (indicated by an OID), 
+ * and the type-specific value.  RelativeDistinguishedNamess consist
+ * of a set of these.  These are distinct from Attributes (which have
+ * SET of values), from AttributeDescriptions (which have qualifiers
+ * on the types), and from AttributeValueAssertions (which assert a
+ * a value comparison under some matching rule).
+ */
+
+struct NSSATAVStr;
+typedef struct NSSATAVStr NSSATAV;
+
+/*
+ * RelativeDistinguishedName
+ *
+ * This structure contains an unordered set of AttributeTypeAndValue 
+ * objects.  RDNs are used to distinguish a set of objects underneath 
+ * a common object.
+ *
+ * Often, a single ATAV is sufficient to make a unique distinction.
+ * For example, if a company assigns its people unique uid values,
+ * then in the Name "uid=smith,ou=People,o=Acme,c=US" the "uid=smith"
+ * ATAV by itself forms an RDN.  However, sometimes a set of ATAVs is
+ * needed.  For example, if a company needed to distinguish between
+ * two Smiths by specifying their corporate divisions, then in the
+ * Name "(cn=Smith,ou=Sales),ou=People,o=Acme,c=US" the parenthesised
+ * set of ATAVs forms the RDN.
+ */
+
+struct NSSRDNStr;
+typedef struct NSSRDNStr NSSRDN;
+
+/*
+ * RDNSequence
+ *
+ * This structure contains a sequence of RelativeDistinguishedName
+ * objects.
+ */
+
+struct NSSRDNSeqStr;
+typedef struct NSSRDNSeqStr NSSRDNSeq;
+
+/*
+ * Name
+ *
+ * This structure contains a union of the possible name formats,
+ * which at the moment is limited to an RDNSequence.
+ */
+
+struct NSSNameStr;
+typedef struct NSSNameStr NSSName;
+
+/*
+ * NameChoice
+ *
+ * This enumeration is used to specify choice within a name.
+ */
+
+enum NSSNameChoiceEnum {
+  NSSNameChoiceInvalid = -1,
+  NSSNameChoiceRdnSequence
+};
+typedef enum NSSNameChoiceEnum NSSNameChoice;
+
+/*
+ * GeneralName
+ *
+ * This structure contains a union of the possible general names,
+ * of which there are several.
+ */
+
+struct NSSGeneralNameStr;
+typedef struct NSSGeneralNameStr NSSGeneralName;
+
+/*
+ * GeneralNameChoice
+ *
+ * This enumerates the possible general name types.
+ */
+
+enum NSSGeneralNameChoiceEnum {
+  NSSGeneralNameChoiceInvalid = -1,
+  NSSGeneralNameChoiceOtherName = 0,
+  NSSGeneralNameChoiceRfc822Name = 1,
+  NSSGeneralNameChoiceDNSName = 2,
+  NSSGeneralNameChoiceX400Address = 3,
+  NSSGeneralNameChoiceDirectoryName = 4,
+  NSSGeneralNameChoiceEdiPartyName = 5,
+  NSSGeneralNameChoiceUniformResourceIdentifier = 6,
+  NSSGeneralNameChoiceIPAddress = 7,
+  NSSGeneralNameChoiceRegisteredID = 8
+};
+typedef enum NSSGeneralNameChoiceEnum NSSGeneralNameChoice;
+
+/*
+ * The "other" types of general names.
+ */
+
+struct NSSOtherNameStr;
+typedef struct NSSOtherNameStr NSSOtherName;
+
+struct NSSRFC822NameStr;
+typedef struct NSSRFC822NameStr NSSRFC822Name;
+
+struct NSSDNSNameStr;
+typedef struct NSSDNSNameStr NSSDNSName;
+
+struct NSSX400AddressStr;
+typedef struct NSSX400AddressStr NSSX400Address;
+
+struct NSSEdiPartyNameStr;
+typedef struct NSSEdiPartyNameStr NSSEdiPartyName;
+
+struct NSSURIStr;
+typedef struct NSSURIStr NSSURI;
+
+struct NSSIPAddressStr;
+typedef struct NSSIPAddressStr NSSIPAddress;
+
+struct NSSRegisteredIDStr;
+typedef struct NSSRegisteredIDStr NSSRegisteredID;
+
+/*
+ * GeneralNameSeq
+ *
+ * This structure contains a sequence of GeneralName objects.
+ * Note that the PKIX documents refer to this as "GeneralNames,"
+ * which differs from "GeneralName" by only one letter.  To
+ * try to reduce confusion, we expand the name slightly to
+ * "GeneralNameSeq."
+ */
+
+struct NSSGeneralNameSeqStr;
+typedef struct NSSGeneralNameSeqStr NSSGeneralNameSeq;
+
+PR_END_EXTERN_C
+
+#endif /* NSSPKI1T_H */
diff --git a/mozilla/security/nss/lib/pki1/oiddata.h b/mozilla/security/nss/lib/pki1/oiddata.h
new file mode 100644
index 0000000..22e5c98
--- /dev/null
+++ b/mozilla/security/nss/lib/pki1/oiddata.h
@@ -0,0 +1,214 @@
+/* THIS IS A GENERATED FILE */
+/* ***** 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 ***** */
+
+#ifndef OIDDATA_H
+#define OIDDATA_H
+
+#ifdef DEBUG
+static const char OIDDATA_CVS_ID[] = "@(#) $RCSfile: oiddata.h,v $ $Revision: 1.4 $ $Date: 2005/03/14 18:02:00 $ ; @(#) $RCSfile: oiddata.h,v $ $Revision: 1.4 $ $Date: 2005/03/14 18:02:00 $";
+#endif /* DEBUG */
+
+#ifndef NSSPKI1T_H
+#include "nsspki1t.h"
+#endif /* NSSPKI1T_H */
+
+extern const NSSOID *NSS_OID_RFC1274_UID;
+extern const NSSOID *NSS_OID_RFC1274_EMAIL;
+extern const NSSOID *NSS_OID_RFC2247_DC;
+extern const NSSOID *NSS_OID_ANSIX9_DSA_SIGNATURE;
+extern const NSSOID *NSS_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
+extern const NSSOID *NSS_OID_X942_DIFFIE_HELMAN_KEY;
+extern const NSSOID *NSS_OID_PKCS1_RSA_ENCRYPTION;
+extern const NSSOID *NSS_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
+extern const NSSOID *NSS_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION;
+extern const NSSOID *NSS_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
+extern const NSSOID *NSS_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+extern const NSSOID *NSS_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC;
+extern const NSSOID *NSS_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC;
+extern const NSSOID *NSS_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC;
+extern const NSSOID *NSS_OID_PKCS7;
+extern const NSSOID *NSS_OID_PKCS7_DATA;
+extern const NSSOID *NSS_OID_PKCS7_SIGNED_DATA;
+extern const NSSOID *NSS_OID_PKCS7_ENVELOPED_DATA;
+extern const NSSOID *NSS_OID_PKCS7_SIGNED_ENVELOPED_DATA;
+extern const NSSOID *NSS_OID_PKCS7_DIGESTED_DATA;
+extern const NSSOID *NSS_OID_PKCS7_ENCRYPTED_DATA;
+extern const NSSOID *NSS_OID_PKCS9_EMAIL_ADDRESS;
+extern const NSSOID *NSS_OID_PKCS9_UNSTRUCTURED_NAME;
+extern const NSSOID *NSS_OID_PKCS9_CONTENT_TYPE;
+extern const NSSOID *NSS_OID_PKCS9_MESSAGE_DIGEST;
+extern const NSSOID *NSS_OID_PKCS9_SIGNING_TIME;
+extern const NSSOID *NSS_OID_PKCS9_COUNTER_SIGNATURE;
+extern const NSSOID *NSS_OID_PKCS9_CHALLENGE_PASSWORD;
+extern const NSSOID *NSS_OID_PKCS9_UNSTRUCTURED_ADDRESS;
+extern const NSSOID *NSS_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES;
+extern const NSSOID *NSS_OID_PKCS9_SMIME_CAPABILITIES;
+extern const NSSOID *NSS_OID_PKCS9_FRIENDLY_NAME;
+extern const NSSOID *NSS_OID_PKCS9_LOCAL_KEY_ID;
+extern const NSSOID *NSS_OID_PKCS9_X509_CERT;
+extern const NSSOID *NSS_OID_PKCS9_SDSI_CERT;
+extern const NSSOID *NSS_OID_PKCS9_X509_CRL;
+extern const NSSOID *NSS_OID_PKCS12;
+extern const NSSOID *NSS_OID_PKCS12_PBE_IDS;
+extern const NSSOID *NSS_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4;
+extern const NSSOID *NSS_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4;
+extern const NSSOID *NSS_OID_PKCS12_PBE_WITH_SHA1_AND_3_KEY_TRIPLE_DES_CBC;
+extern const NSSOID *NSS_OID_PKCS12_PBE_WITH_SHA1_AND_2_KEY_TRIPLE_DES_CBC;
+extern const NSSOID *NSS_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC;
+extern const NSSOID *NSS_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
+extern const NSSOID *NSS_OID_PKCS12_KEY_BAG;
+extern const NSSOID *NSS_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG;
+extern const NSSOID *NSS_OID_PKCS12_CERT_BAG;
+extern const NSSOID *NSS_OID_PKCS12_CRL_BAG;
+extern const NSSOID *NSS_OID_PKCS12_SECRET_BAG;
+extern const NSSOID *NSS_OID_PKCS12_SAFE_CONTENTS_BAG;
+extern const NSSOID *NSS_OID_MD2;
+extern const NSSOID *NSS_OID_MD4;
+extern const NSSOID *NSS_OID_MD5;
+extern const NSSOID *NSS_OID_RC2_CBC;
+extern const NSSOID *NSS_OID_RC4;
+extern const NSSOID *NSS_OID_DES_EDE3_CBC;
+extern const NSSOID *NSS_OID_RC5_CBC_PAD;
+extern const NSSOID *NSS_OID_X509_AUTH_INFO_ACCESS;
+extern const NSSOID *NSS_OID_PKIX_CPS_POINTER_QUALIFIER;
+extern const NSSOID *NSS_OID_PKIX_USER_NOTICE_QUALIFIER;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_SERVER_AUTH;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_CLIENT_AUTH;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_CODE_SIGN;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_EMAIL_PROTECTION;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_IPSEC_END_SYSTEM;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_IPSEC_TUNNEL;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_IPSEC_USER;
+extern const NSSOID *NSS_OID_EXT_KEY_USAGE_TIME_STAMP;
+extern const NSSOID *NSS_OID_OCSP_RESPONDER;
+extern const NSSOID *NSS_OID_PKIX_REGCTRL_REGTOKEN;
+extern const NSSOID *NSS_OID_PKIX_REGCTRL_AUTHENTICATOR;
+extern const NSSOID *NSS_OID_PKIX_REGCTRL_PKIPUBINFO;
+extern const NSSOID *NSS_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS;
+extern const NSSOID *NSS_OID_PKIX_REGCTRL_OLD_CERT_ID;
+extern const NSSOID *NSS_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY;
+extern const NSSOID *NSS_OID_PKIX_REGINFO_UTF8_PAIRS;
+extern const NSSOID *NSS_OID_PKIX_REGINFO_CERT_REQUEST;
+extern const NSSOID *NSS_OID_OID_PKIX_OCSP;
+extern const NSSOID *NSS_OID_PKIX_OCSP_BASIC_RESPONSE;
+extern const NSSOID *NSS_OID_PKIX_OCSP_NONCE;
+extern const NSSOID *NSS_OID_PKIX_OCSP_RESPONSE;
+extern const NSSOID *NSS_OID_PKIX_OCSP_CRL;
+extern const NSSOID *NSS_OID_X509_OCSP_NO_CHECK;
+extern const NSSOID *NSS_OID_PKIX_OCSP_ARCHIVE_CUTOFF;
+extern const NSSOID *NSS_OID_PKIX_OCSP_SERVICE_LOCATOR;
+extern const NSSOID *NSS_OID_DES_ECB;
+extern const NSSOID *NSS_OID_DES_CBC;
+extern const NSSOID *NSS_OID_DES_OFB;
+extern const NSSOID *NSS_OID_DES_CFB;
+extern const NSSOID *NSS_OID_DES_MAC;
+extern const NSSOID *NSS_OID_ISO_SHA_WITH_RSA_SIGNATURE;
+extern const NSSOID *NSS_OID_DES_EDE;
+extern const NSSOID *NSS_OID_SHA1;
+extern const NSSOID *NSS_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST;
+extern const NSSOID *NSS_OID_X520_COMMON_NAME;
+extern const NSSOID *NSS_OID_X520_SURNAME;
+extern const NSSOID *NSS_OID_X520_COUNTRY_NAME;
+extern const NSSOID *NSS_OID_X520_LOCALITY_NAME;
+extern const NSSOID *NSS_OID_X520_STATE_OR_PROVINCE_NAME;
+extern const NSSOID *NSS_OID_X520_ORGANIZATION_NAME;
+extern const NSSOID *NSS_OID_X520_ORGANIZATIONAL_UNIT_NAME;
+extern const NSSOID *NSS_OID_X520_TITLE;
+extern const NSSOID *NSS_OID_X520_NAME;
+extern const NSSOID *NSS_OID_X520_GIVEN_NAME;
+extern const NSSOID *NSS_OID_X520_INITIALS;
+extern const NSSOID *NSS_OID_X520_GENERATION_QUALIFIER;
+extern const NSSOID *NSS_OID_X520_DN_QUALIFIER;
+extern const NSSOID *NSS_OID_X500_RSA_ENCRYPTION;
+extern const NSSOID *NSS_OID_X509_SUBJECT_DIRECTORY_ATTR;
+extern const NSSOID *NSS_OID_X509_SUBJECT_DIRECTORY_ATTRIBUTES;
+extern const NSSOID *NSS_OID_X509_SUBJECT_KEY_ID;
+extern const NSSOID *NSS_OID_X509_KEY_USAGE;
+extern const NSSOID *NSS_OID_X509_PRIVATE_KEY_USAGE_PERIOD;
+extern const NSSOID *NSS_OID_X509_SUBJECT_ALT_NAME;
+extern const NSSOID *NSS_OID_X509_ISSUER_ALT_NAME;
+extern const NSSOID *NSS_OID_X509_BASIC_CONSTRAINTS;
+extern const NSSOID *NSS_OID_X509_CRL_NUMBER;
+extern const NSSOID *NSS_OID_X509_REASON_CODE;
+extern const NSSOID *NSS_OID_X509_HOLD_INSTRUCTION_CODE;
+extern const NSSOID *NSS_OID_X509_INVALID_DATE;
+extern const NSSOID *NSS_OID_X509_DELTA_CRL_INDICATOR;
+extern const NSSOID *NSS_OID_X509_ISSUING_DISTRIBUTION_POINT;
+extern const NSSOID *NSS_OID_X509_CERTIFICATE_ISSUER;
+extern const NSSOID *NSS_OID_X509_NAME_CONSTRAINTS;
+extern const NSSOID *NSS_OID_X509_CRL_DIST_POINTS;
+extern const NSSOID *NSS_OID_X509_CERTIFICATE_POLICIES;
+extern const NSSOID *NSS_OID_X509_POLICY_MAPPINGS;
+extern const NSSOID *NSS_OID_X509_AUTH_KEY_ID;
+extern const NSSOID *NSS_OID_X509_POLICY_CONSTRAINTS;
+extern const NSSOID *NSS_OID_X509_EXT_KEY_USAGE;
+extern const NSSOID *NSS_OID_MISSI_DSS_OLD;
+extern const NSSOID *NSS_OID_FORTEZZA_SKIPJACK;
+extern const NSSOID *NSS_OID_MISSI_KEA;
+extern const NSSOID *NSS_OID_MISSI_KEA_DSS_OLD;
+extern const NSSOID *NSS_OID_MISSI_DSS;
+extern const NSSOID *NSS_OID_MISSI_KEA_DSS;
+extern const NSSOID *NSS_OID_MISSI_ALT_KEY;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_CERT_TYPE;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_BASE_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_REVOCATION_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_CA_REVOCATION_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_CA_CRL_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_CA_CERT_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_CERT_RENEWAL_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_CA_POLICY_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_HOMEPAGE_URL;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_ENTITY_LOGO;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_USER_PICTURE;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_SSL_SERVER_NAME;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_COMMENT;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_THAYES;
+extern const NSSOID *NSS_OID_NS_TYPE_GIF;
+extern const NSSOID *NSS_OID_NS_TYPE_JPEG;
+extern const NSSOID *NSS_OID_NS_TYPE_URL;
+extern const NSSOID *NSS_OID_NS_TYPE_HTML;
+extern const NSSOID *NSS_OID_NS_TYPE_CERT_SEQUENCE;
+extern const NSSOID *NSS_OID_NS_KEY_USAGE_GOVT_APPROVED;
+extern const NSSOID *NSS_OID_NETSCAPE_RECOVERY_REQUEST;
+extern const NSSOID *NSS_OID_NETSCAPE_SMIME_KEA;
+extern const NSSOID *NSS_OID_NETSCAPE_NICKNAME;
+extern const NSSOID *NSS_OID_VERISIGN_USER_NOTICES;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_NETSCAPE_OK;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_ISSUER_LOGO;
+extern const NSSOID *NSS_OID_NS_CERT_EXT_SUBJECT_LOGO;
+
+#endif /* OIDDATA_H */
diff --git a/mozilla/security/nss/lib/pki1/pki1.h b/mozilla/security/nss/lib/pki1/pki1.h
new file mode 100644
index 0000000..953feab
--- /dev/null
+++ b/mozilla/security/nss/lib/pki1/pki1.h
@@ -0,0 +1,3037 @@
+/* ***** 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 ***** */
+
+#ifndef PKI1_H
+#define PKI1_H
+
+#ifdef DEBUG
+static const char PKI1_CVS_ID[] = "@(#) $RCSfile: pki1.h,v $ $Revision: 1.5 $ $Date: 2005/03/14 18:02:00 $";
+#endif /* DEBUG */
+
+/*
+ * pki1.h
+ *
+ * This file contains the prototypes to the non-public NSS routines
+ * relating to the PKIX part-1 objects.
+ */
+
+#ifndef PKI1T_H
+#include "pki1t.h"
+#endif /* PKI1T_H */
+
+#ifndef NSSPKI1_H
+#include "nsspki1.h"
+#endif /* NSSPKI1_H */
+
+PR_BEGIN_EXTERN_C
+
+extern const NSSOID nss_builtin_oids[];
+extern const PRUint32 nss_builtin_oid_count;
+
+extern const nssAttributeTypeAliasTable nss_attribute_type_aliases[];
+extern const PRUint32 nss_attribute_type_alias_count;
+
+/*
+ * NSSOID
+ *
+ * The non-public "methods" regarding this "object" are:
+ *
+ *  nssOID_CreateFromBER   -- constructor
+ *  nssOID_CreateFromUTF8  -- constructor
+ *  (there is no explicit destructor)
+ * 
+ *  nssOID_GetDEREncoding
+ *  nssOID_GetUTF8Encoding
+ *
+ * In debug builds, the following non-public calls are also available:
+ *
+ *  nssOID_verifyPointer
+ *  nssOID_getExplanation
+ *  nssOID_getTaggedUTF8
+ */
+
+/*
+ * nssOID_CreateFromBER
+ *
+ * This routine creates an NSSOID by decoding a BER- or DER-encoded
+ * OID.  It may return NSS_OID_UNKNOWN upon error, in which case it 
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NSS_OID_UNKNOWN upon error
+ *  An NSSOID upon success
+ */
+
+NSS_EXTERN NSSOID *
+nssOID_CreateFromBER
+(
+  NSSBER *berOid
+);
+
+extern const NSSError NSS_ERROR_INVALID_BER;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * nssOID_CreateFromUTF8
+ *
+ * This routine creates an NSSOID by decoding a UTF8 string 
+ * representation of an OID in dotted-number format.  The string may 
+ * optionally begin with an octothorpe.  It may return NSS_OID_UNKNOWN
+ * upon error, in which case it will have set an error on the error 
+ * stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_UTF8
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NSS_OID_UNKNOWN upon error
+ *  An NSSOID upon success
+ */
+
+NSS_EXTERN NSSOID *
+nssOID_CreateFromUTF8
+(
+  NSSUTF8 *stringOid
+);
+
+extern const NSSError NSS_ERROR_INVALID_UTF8;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+
+/*
+ * nssOID_GetDEREncoding
+ *
+ * This routine returns the DER encoding of the specified NSSOID.
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return return null upon error, in 
+ * which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NSSOID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSOID
+ */
+
+NSS_EXTERN NSSDER *
+nssOID_GetDEREncoding
+(
+  const NSSOID *oid,
+  NSSDER *rvOpt,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssOID_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing the dotted-number 
+ * encoding of the specified NSSOID.  If the optional arena argument 
+ * is non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return null upon error, in which case it will have set an error
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NSSOID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string containing the dotted-digit encoding of 
+ *      this NSSOID
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssOID_GetUTF8Encoding
+(
+  const NSSOID *oid,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssOID_verifyPointer
+ *
+ * This method is only present in debug builds.
+ *
+ * If the specified pointer is a valid poitner to an NSSOID object, 
+ * this routine will return PR_SUCCESS.  Otherwise, it will put an 
+ * error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NSSOID
+ *
+ * Return value:
+ *  PR_SUCCESS if the pointer is valid
+ *  PR_FAILURE if it isn't
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssOID_verifyPointer
+(
+  const NSSOID *oid
+);
+
+extern const NSSError NSS_ERROR_INVALID_NSSOID;
+#endif /* DEBUG */
+
+/*
+ * nssOID_getExplanation
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine will return a static pointer to a UTF8-encoded string
+ * describing (in English) the specified OID.  The memory pointed to
+ * by the return value is not owned by the caller, and should not be
+ * freed or modified.  Note that explanations are only provided for
+ * the OIDs built into the NSS library; there is no way to specify an
+ * explanation for dynamically created OIDs.  This routine is intended
+ * only for use in debugging tools such as "derdump."  This routine
+ * may return null upon error, in which case it will have placed an
+ * error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NSSOID
+ *
+ * Return value:
+ *  NULL upon error
+ *  A static pointer to a readonly, non-caller-owned UTF8-encoded
+ *    string explaining the specified OID.
+ */
+
+#ifdef DEBUG
+NSS_EXTERN const NSSUTF8 *
+nssOID_getExplanation
+(
+  NSSOID *oid
+);
+
+extern const NSSError NSS_ERROR_INVALID_NSSOID;
+#endif /* DEBUG */
+
+/*
+ * nssOID_getTaggedUTF8
+ *
+ * This method is only present in debug builds.
+ *
+ * This routine will return a pointer to a caller-owned UTF8-encoded
+ * string containing a tagged encoding of the specified OID.  Note
+ * that OID (component) tags are only provided for the OIDs built 
+ * into the NSS library; there is no way to specify tags for 
+ * dynamically created OIDs.  This routine is intended for use in
+ * debugging tools such as "derdump."   If the optional arena argument
+ * is non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine 
+ * may return return null upon error, in which case it will have set 
+ * an error on the error stack.
+ *
+ * The error may be one of the following values
+ *  NSS_ERROR_INVALID_NSSOID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string containing the tagged encoding of
+ *      this NSSOID
+ */
+
+#ifdef DEBUG
+NSS_EXTERN NSSUTF8 *
+nssOID_getTaggedUTF8
+(
+  NSSOID *oid,
+  NSSArena *arenaOpt
+);
+
+extern const NSSError NSS_ERROR_INVALID_NSSOID;
+extern const NSSError NSS_ERROR_NO_MEMORY;
+#endif /* DEBUG */
+
+/*
+ * NSSATAV
+ *
+ * The non-public "methods" regarding this "object" are:
+ *
+ *  nssATAV_CreateFromBER   -- constructor
+ *  nssATAV_CreateFromUTF8  -- constructor
+ *  nssATAV_Create          -- constructor
+ *
+ *  nssATAV_Destroy
+ *  nssATAV_GetDEREncoding
+ *  nssATAV_GetUTF8Encoding
+ *  nssATAV_GetType
+ *  nssATAV_GetValue
+ *  nssATAV_Compare
+ *  nssATAV_Duplicate
+ *
+ * In debug builds, the following non-public call is also available:
+ *
+ *  nssATAV_verifyPointer
+ */
+
+/*
+ * nssATAV_CreateFromBER
+ * 
+ * This routine creates an NSSATAV by decoding a BER- or DER-encoded
+ * ATAV.  If the optional arena argument is non-null, the memory used 
+ * will be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error, 
+ * in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSATAV upon success
+ */
+
+NSS_EXTERN NSSATAV *
+nssATAV_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  const NSSBER *berATAV
+);
+
+/*
+ * nssATAV_CreateFromUTF8
+ *
+ * This routine creates an NSSATAV by decoding a UTF8 string in the
+ * "equals" format, e.g., "c=US."  If the optional arena argument is 
+ * non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have set an error 
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_UNKNOWN_ATTRIBUTE
+ *  NSS_ERROR_INVALID_UTF8
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSATAV upon success
+ */
+
+NSS_EXTERN NSSATAV *
+nssATAV_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  const NSSUTF8 *stringATAV
+);
+
+/*
+ * nssATAV_Create
+ *
+ * This routine creates an NSSATAV from the specified NSSOID and the
+ * specified data. If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory
+ * will be obtained from the heap.If the specified data length is zero, 
+ * the data is assumed to be terminated by first zero byte; this allows 
+ * UTF8 strings to be easily specified.  This routine may return NULL 
+ * upon error, in which case it will have set an error on the error 
+ * stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ARENA
+ *  NSS_ERROR_INVALID_NSSOID
+ *  NSS_ERROR_INVALID_POINTER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSATAV upon success
+ */
+
+NSS_EXTERN NSSATAV *
+nssATAV_Create
+(
+  NSSArena *arenaOpt,
+  const NSSOID *oid,
+  const void *data,
+  PRUint32 length
+);
+
+/*
+ * nssATAV_Destroy
+ *
+ * This routine will destroy an ATAV object.  It should eventually be
+ * called on all ATAVs created without an arena.  While it is not 
+ * necessary to call it on ATAVs created within an arena, it is not an
+ * error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * set an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+nssATAV_Destroy
+(
+  NSSATAV *atav
+);
+
+/*
+ * nssATAV_GetDEREncoding
+ *
+ * This routine will DER-encode an ATAV object. If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have set
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSATAV
+ */
+
+NSS_EXTERN NSSDER *
+nssATAV_GetDEREncoding
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssATAV_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the ATAV in "equals" notation (e.g., "o=Acme").  
+ * If the optional arena argument is non-null, the memory used will be
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return null upon error, in which 
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string containing the "equals" encoding of the 
+ *      ATAV
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssATAV_GetUTF8Encoding
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssATAV_GetType
+ *
+ * This routine returns the NSSOID corresponding to the attribute type
+ * in the specified ATAV.  This routine may return NSS_OID_UNKNOWN 
+ * upon error, in which case it will have set an error on the error
+ * stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *
+ * Return value:
+ *  NSS_OID_UNKNOWN upon error
+ *  An element of enum NSSOIDenum upon success
+ */
+
+NSS_EXTERN const NSSOID *
+nssATAV_GetType
+(
+  NSSATAV *atav
+);
+
+/*
+ * nssATAV_GetValue
+ *
+ * This routine returns a string containing the attribute value
+ * in the specified ATAV.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  This routine may return
+ * NULL upon error, in which case it will have set an error upon the
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSItem containing the attribute value.
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssATAV_GetValue
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssATAV_Compare
+ *
+ * This routine compares two ATAVs for equality.  For two ATAVs to be
+ * equal, the attribute types must be the same, and the attribute 
+ * values must have equal length and contents.  The result of the 
+ * comparison will be stored at the location pointed to by the "equalp"
+ * variable, which must point to a valid PRBool.  This routine may 
+ * return PR_FAILURE upon error, in which case it will have set an 
+ * error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+nssATAV_Compare
+(
+  NSSATAV *atav1,
+  NSSATAV *atav2,
+  PRBool *equalp
+);
+
+/*
+ * nssATAV_Duplicate
+ *
+ * This routine duplicates the specified ATAV.  If the optional arena 
+ * argument is non-null, the memory required will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * placed an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL on error
+ *  A pointer to a new ATAV
+ */
+
+NSS_EXTERN NSSATAV *
+nssATAV_Duplicate
+(
+  NSSATAV *atav,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssATAV_verifyPointer
+ *
+ * This method is only present in debug builds.
+ *
+ * If the specified pointer is a valid pointer to an NSSATAV object,
+ * this routine will return PR_SUCCESS.  Otherwise, it will put an
+ * error on the error stack and return PR_FAILRUE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NSSATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS if the pointer is valid
+ *  PR_FAILURE if it isn't
+ */
+
+#ifdef DEBUG
+NSS_EXTERN PRStatus
+nssATAV_verifyPointer
+(
+  NSSATAV *atav
+);
+#endif /* DEBUG */
+
+/*
+ * NSSRDN
+ *
+ * The non-public "methods" regarding this "object" are:
+ *
+ *  nssRDN_CreateFromBER   -- constructor
+ *  nssRDN_CreateFromUTF8  -- constructor
+ *  nssRDN_Create          -- constructor
+ *  nssRDN_CreateSimple    -- constructor
+ *
+ *  nssRDN_Destroy
+ *  nssRDN_GetDEREncoding
+ *  nssRDN_GetUTF8Encoding
+ *  nssRDN_AddATAV
+ *  nssRDN_GetATAVCount
+ *  nssRDN_GetATAV
+ *  nssRDN_GetSimpleATAV
+ *  nssRDN_Compare
+ *  nssRDN_Duplicate
+ */
+
+/*
+ * nssRDN_CreateFromBER
+ *
+ * This routine creates an NSSRDN by decoding a BER- or DER-encoded 
+ * RDN.  If the optional arena argument is non-null, the memory used 
+ * will be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error, 
+ * in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+nssRDN_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berRDN
+);
+
+/*
+ * nssRDN_CreateFromUTF8
+ *
+ * This routine creates an NSSRDN by decoding an UTF8 string 
+ * consisting of either a single ATAV in the "equals" format, e.g., 
+ * "uid=smith," or one or more such ATAVs in parentheses, e.g., 
+ * "(sn=Smith,ou=Sales)."  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  This routine may return
+ * NULL upon error, in which case it will have set an error on the
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_UNKNOWN_ATTRIBUTE
+ *  NSS_ERROR_INVALID_UTF8
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+nssRDN_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringRDN
+);
+
+/*
+ * nssRDN_Create
+ *
+ * This routine creates an NSSRDN from one or more NSSATAVs.  The
+ * final argument to this routine must be NULL.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have set
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_ATAV
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+nssRDN_Create
+(
+  NSSArena *arenaOpt,
+  NSSATAV *atav1,
+  ...
+);
+
+/*
+ * nssRDN_CreateSimple
+ *
+ * This routine creates a simple NSSRDN from a single NSSATAV.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_ATAV
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDN upon success
+ */
+
+NSS_EXTERN NSSRDN *
+nssRDN_CreateSimple
+(
+  NSSArena *arenaOpt,
+  NSSATAV *atav
+);
+
+/*
+ * nssRDN_Destroy
+ *
+ * This routine will destroy an RDN object.  It should eventually be
+ * called on all RDNs created without an arena.  While it is not 
+ * necessary to call it on RDNs created within an arena, it is not an
+ * error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will 
+ * set an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *
+ * Return value:
+ *  PR_FAILURE upon failure
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+nssRDN_Destroy
+(
+  NSSRDN *rdn
+);
+
+/*
+ * nssRDN_GetDEREncoding
+ *
+ * This routine will DER-encode an RDN object.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have set
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSRDN
+ */
+
+NSS_EXTERN NSSDER *
+nssRDN_GetDEREncoding
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssRDN_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the RDN.  A simple (one-ATAV) RDN will be simply
+ * the string representation of that ATAV; a non-simple RDN will be in
+ * parenthesised form.  If the optional arena argument is non-null, 
+ * the memory used will be obtained from that arena; otherwise, the 
+ * memory will be obtained from the heap.  This routine may return 
+ * null upon error, in which case it will have set an error on the 
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssRDN_GetUTF8Encoding
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssRDN_AddATAV
+ *
+ * This routine adds an ATAV to the set of ATAVs in the specified RDN.
+ * Remember that RDNs consist of an unordered set of ATAVs.  If the
+ * RDN was created with a non-null arena argument, that same arena
+ * will be used for any additional required memory.  If the RDN was 
+ * created with a NULL arena argument, any additional memory will
+ * be obtained from the heap.  This routine returns a PRStatus value;
+ * it will return PR_SUCCESS upon success, and upon failure it will
+ * set an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_INVALID_ATAV
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure
+ */
+
+NSS_EXTERN PRStatus
+nssRDN_AddATAV
+(
+  NSSRDN *rdn,
+  NSSATAV *atav
+);
+
+/*
+ * nssRDN_GetATAVCount
+ *
+ * This routine returns the cardinality of the set of ATAVs within
+ * the specified RDN.  This routine may return 0 upon error, in which 
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *
+ * Return value:
+ *  0 upon error
+ *  A positive number upon success
+ */
+
+NSS_EXTERN PRUint32
+nssRDN_GetATAVCount
+(
+  NSSRDN *rdn
+);
+
+/*
+ * nssRDN_GetATAV
+ *
+ * This routine returns a pointer to an ATAV that is a member of
+ * the set of ATAVs within the specified RDN.  While the set of
+ * ATAVs within an RDN is unordered, this routine will return
+ * distinct values for distinct values of 'i' as long as the RDN
+ * is not changed in any way.  The RDN may be changed by calling
+ * NSSRDN_AddATAV.  The value of the variable 'i' is on the range
+ * [0,c) where c is the cardinality returned from NSSRDN_GetATAVCount.
+ * The caller owns the ATAV the pointer to which is returned.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have set an error upon the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_VALUE_OUT_OF_RANGE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSATAV
+ */
+
+NSS_EXTERN NSSATAV *
+nssRDN_GetATAV
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt,
+  PRUint32 i
+);
+
+/*
+ * nssRDN_GetSimpleATAV
+ *
+ * Most RDNs are actually very simple, with a single ATAV.  This 
+ * routine will return the single ATAV from such an RDN.  The caller
+ * owns the ATAV the pointer to which is returned.  If the optional
+ * arena argument is non-null, the memory used will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.
+ * This routine may return NULL upon error, including the case where
+ * the set of ATAVs in the RDN is nonsingular.  Upon error, this
+ * routine will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_RDN_NOT_SIMPLE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSATAV
+ */
+
+NSS_EXTERN NSSATAV *
+nssRDN_GetSimpleATAV
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssRDN_Compare
+ *
+ * This routine compares two RDNs for equality.  For two RDNs to be
+ * equal, they must have the same number of ATAVs, and every ATAV in
+ * one must be equal to an ATAV in the other.  (Note that the sets
+ * of ATAVs are unordered.)  The result of the comparison will be
+ * stored at the location pointed to by the "equalp" variable, which
+ * must point to a valid PRBool.  This routine may return PR_FAILURE
+ * upon error, in which case it will have set an error on the error
+ * stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+nssRDN_Compare
+(
+  NSSRDN *rdn1,
+  NSSRDN *rdn2,
+  PRBool *equalp
+);
+
+/*
+ * nssRDN_Duplicate
+ *
+ * This routine duplicates the specified RDN.  If the optional arena
+ * argument is non-null, the memory required will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.
+ * This routine may return NULL upon error, in which case it will have
+ * placed an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL on error
+ *  A pointer to a new RDN
+ */
+
+NSS_EXTERN NSSRDN *
+nssRDN_Duplicate
+(
+  NSSRDN *rdn,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSRDNSeq
+ *
+ * The non-public "methods" regarding this "object" are:
+ *
+ *  nssRDNSeq_CreateFromBER   -- constructor
+ *  nssRDNSeq_CreateFromUTF8  -- constructor
+ *  nssRDNSeq_Create          -- constructor
+ *
+ *  nssRDNSeq_Destroy
+ *  nssRDNSeq_GetDEREncoding
+ *  nssRDNSeq_GetUTF8Encoding
+ *  nssRDNSeq_AppendRDN
+ *  nssRDNSeq_GetRDNCount
+ *  nssRDNSeq_GetRDN
+ *  nssRDNSeq_Compare
+ *  nssRDNSeq_Duplicate
+ *
+ *  nssRDNSeq_EvaluateUTF8 -- not an object method
+ */
+
+/*
+ * nssRDNSeq_CreateFromBER
+ *
+ * This routine creates an NSSRDNSeq by decoding a BER- or DER-encoded 
+ * sequence of RDNs.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  This routine may return 
+ * NULL upon error, in which case it will have set an error on the
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDNSeq upon success
+ */
+
+NSS_EXTERN NSSRDNSeq *
+nssRDNSeq_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berRDNSeq
+);
+
+/*
+ * nssRDNSeq_CreateFromUTF8
+ *
+ * This routine creates an NSSRDNSeq by decoding a UTF8 string
+ * consisting of a comma-separated sequence of RDNs, such as
+ * "(sn=Smith,ou=Sales),o=Acme,c=US."  If the optional arena argument
+ * is non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have set an error
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_UNKNOWN_ATTRIBUTE
+ *  NSS_ERROR_INVALID_UTF8
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSRDNSeq upon success
+ */
+
+NSS_EXTERN NSSRDNSeq *
+nssRDNSeq_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringRDNSeq
+);
+
+/*
+ * nssRDNSeq_Create
+ *
+ * This routine creates an NSSRDNSeq from one or more NSSRDNs.  The
+ * final argument to this routine must be NULL.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have set
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_RDN
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointero to an NSSRDNSeq upon success
+ */
+
+NSS_EXTERN NSSRDNSeq *
+nssRDNSeq_Create
+(
+  NSSArena *arenaOpt,
+  NSSRDN *rdn1,
+  ...
+);
+
+/*
+ * nssRDNSeq_Destroy
+ *
+ * This routine will destroy an RDNSeq object.  It should eventually 
+ * be called on all RDNSeqs created without an arena.  While it is not
+ * necessary to call it on RDNSeqs created within an arena, it is not
+ * an error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * set an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+nssRDNSeq_Destroy
+(
+  NSSRDNSeq *rdnseq
+);
+
+/*
+ * nssRDNSeq_GetDEREncoding
+ *
+ * This routine will DER-encode an RDNSeq object.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from
+ * that arena; otherwise, the memory will be obtained from the heap.
+ * This routine may return null upon error, in which case it will have
+ * set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSRDNSeq
+ */
+
+NSS_EXTERN NSSDER *
+nssRDNSeq_GetDEREncoding
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssRDNSeq_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the RDNSeq as a comma-separated sequence of RDNs.  
+ * If the optional arena argument is non-null, the memory used will be
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return null upon error, in which 
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssRDNSeq_GetUTF8Encoding
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssRDNSeq_AppendRDN
+ *
+ * This routine appends an RDN to the end of the existing RDN 
+ * sequence.  If the RDNSeq was created with a non-null arena 
+ * argument, that same arena will be used for any additional required
+ * memory.  If the RDNSeq was created with a NULL arena argument, any
+ * additional memory will be obtained from the heap.  This routine
+ * returns a PRStatus value; it will return PR_SUCCESS upon success,
+ * and upon failure it will set an error on the error stack and return
+ * PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_INVALID_RDN
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure
+ */
+
+NSS_EXTERN PRStatus
+nssRDNSeq_AppendRDN
+(
+  NSSRDNSeq *rdnseq,
+  NSSRDN *rdn
+);
+
+/*
+ * nssRDNSeq_GetRDNCount
+ *
+ * This routine returns the cardinality of the sequence of RDNs within
+ * the specified RDNSeq.  This routine may return 0 upon error, in 
+ * which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *
+ * Return value:
+ *  0 upon error
+ *  A positive number upon success
+ */
+
+NSS_EXTERN PRUint32
+nssRDNSeq_GetRDNCount
+(
+  NSSRDNSeq *rdnseq
+);
+
+/*
+ * nssRDNSeq_GetRDN
+ *
+ * This routine returns a pointer to the i'th RDN in the sequence of
+ * RDNs that make up the specified RDNSeq.  The sequence begins with
+ * the top-level (e.g., "c=US") RDN.  The value of the variable 'i'
+ * is on the range [0,c) where c is the cardinality returned from
+ * NSSRDNSeq_GetRDNCount.  The caller owns the RDN the pointer to which
+ * is returned.  If the optional arena argument is non-null, the memory
+ * used will be obtained from that areana; otherwise, the memory will 
+ * be obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have set an error upon the error stack.  Note
+ * that the usual UTF8 representation of RDN Sequences is from last
+ * to first.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_VALUE_OUT_OF_RANGE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRDN
+ */
+
+NSS_EXTERN NSSRDN *
+nssRDNSeq_GetRDN
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt,
+  PRUint32 i
+);
+
+/*
+ * nssRDNSeq_Compare
+ *
+ * This routine compares two RDNSeqs for equality.  For two RDNSeqs to 
+ * be equal, they must have the same number of RDNs, and each RDN in
+ * one sequence must be equal to the corresponding RDN in the other
+ * sequence.  The result of the comparison will be stored at the
+ * location pointed to by the "equalp" variable, which must point to a
+ * valid PRBool.  This routine may return PR_FAILURE upon error, in
+ * which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+nssRDNSeq_Compare
+(
+  NSSRDNSeq *rdnseq1,
+  NSSRDNSeq *rdnseq2,
+  PRBool *equalp
+);
+
+/*
+ * nssRDNSeq_Duplicate
+ *
+ * This routine duplicates the specified RDNSeq.  If the optional arena
+ * argument is non-null, the memory required will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This 
+ * routine may return NULL upon error, in which case it will have 
+ * placed an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_RDNSEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new RDNSeq
+ */
+
+NSS_EXTERN NSSRDNSeq *
+nssRDNSeq_Duplicate
+(
+  NSSRDNSeq *rdnseq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssRDNSeq_EvaluateUTF8
+ *
+ * This routine evaluates a UTF8 string, and returns PR_TRUE if the 
+ * string contains the string representation of an RDNSeq.  This 
+ * routine is used by the (directory) Name routines 
+ * nssName_CreateFromUTF8 and nssName_EvaluateUTF8 to determine which
+ * choice of directory name the string may encode.  This routine may 
+ * return PR_FALSE upon error, but it subsumes that condition under the
+ * general "string does not evaluate as an RDNSeq" state, and does not
+ * set an error on the error stack.
+ *
+ * Return value:
+ *  PR_TRUE if the string represents an RDNSeq
+ *  PR_FALSE if otherwise
+ */
+
+NSS_EXTERN PRBool
+nssRDNSeq_EvaluateUTF8
+(
+  NSSUTF8 *str
+);
+
+/*
+ * NSSName
+ *
+ * The non-public "methods" regarding this "object" are:
+ *
+ * nssName_CreateFromBER   -- constructor
+ * nssName_CreateFromUTF8  -- constructor
+ * nssName_Create          -- constructor
+ *
+ * nssName_Destroy
+ * nssName_GetDEREncoding
+ * nssName_GetUTF8Encoding
+ * nssName_GetChoice
+ * nssName_GetRDNSequence
+ * nssName_GetSpecifiedChoice
+ * nssName_Compare
+ * nssName_Duplicate
+ *
+ * nssName_GetUID
+ * nssName_GetEmail
+ * nssName_GetCommonName
+ * nssName_GetOrganization
+ * nssName_GetOrganizationalUnits
+ * nssName_GetStateOrProvince
+ * nssName_GetLocality
+ * nssName_GetCountry
+ * nssName_GetAttribute
+ *
+ * nssName_EvaluateUTF8 -- not an object method
+ */
+
+/*
+ * nssName_CreateFromBER
+ *
+ * This routine creates an NSSName by decoding a BER- or DER-encoded 
+ * (directory) Name.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, 
+ * the memory will be obtained from the heap.  This routine may
+ * return NULL upon error, in which case it will have set an error
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSName upon success
+ */
+
+NSS_EXTERN NSSName *
+nssName_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berName
+);
+
+/*
+ * nssName_CreateFromUTF8
+ *
+ * This routine creates an NSSName by decoding a UTF8 string 
+ * consisting of the string representation of one of the choices of 
+ * (directory) names.  Currently the only choice is an RDNSeq.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  The routine may return NULL upon error, in which
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_UTF8
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSName upon success
+ */
+
+NSS_EXTERN NSSName *
+nssName_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringName
+);
+
+/*
+ * nssName_Create
+ *
+ * This routine creates an NSSName with the specified choice of
+ * underlying name types.  The value of the choice variable must be
+ * one of the values of the NSSNameChoice enumeration, and the type
+ * of the arg variable must be as specified in the following table:
+ *
+ *   Choice                     Type
+ *   ========================   ===========
+ *   NSSNameChoiceRdnSequence   NSSRDNSeq *
+ *
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_CHOICE
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSName upon success
+ */
+
+NSS_EXTERN NSSName *
+nssName_Create
+(
+  NSSArena *arenaOpt,
+  NSSNameChoice choice,
+  void *arg
+);
+
+/*
+ * nssName_Destroy
+ *
+ * This routine will destroy a Name object.  It should eventually be
+ * called on all Names created without an arena.  While it is not
+ * necessary to call it on Names created within an arena, it is not
+ * an error to do so.  This routine returns a PRStatus value; if
+ * successful, it will return PR_SUCCESS.  If unsuccessful, it will
+ * set an error on the error stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+nssName_Destroy
+(
+  NSSName *name
+);
+
+/*
+ * nssName_GetDEREncoding
+ *
+ * This routine will DER-encode a name object.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have set
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSName
+ */
+
+NSS_EXTERN NSSDER *
+nssName_GetDEREncoding
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the Name in the format specified by the 
+ * underlying name choice.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the 
+ * memory will be obtained from the heap.  This routine may return
+ * NULL upon error, in which case it will have set an error on the 
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to the UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssName_GetUTF8Encoding
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetChoice
+ *
+ * This routine returns the type of the choice underlying the specified
+ * name.  The return value will be a member of the NSSNameChoice 
+ * enumeration.  This routine may return NSSNameChoiceInvalid upon 
+ * error, in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *
+ * Return value:
+ *  NSSNameChoiceInvalid upon error
+ *  An other member of the NSSNameChoice enumeration upon success
+ */
+
+NSS_EXTERN NSSNameChoice
+nssName_GetChoice
+(
+  NSSName *name
+);
+
+/*
+ * nssName_GetRDNSequence
+ *
+ * If the choice underlying the specified NSSName is that of an 
+ * RDNSequence, this routine will return a pointer to that RDN
+ * sequence.  Otherwise, this routine will place an error on the
+ * error stack, and return NULL.  If the optional arena argument is
+ * non-null, the memory required will be obtained from that arena;
+ * otherwise, the memory will be obtained from the heap.  The
+ * caller owns the returned pointer.  This routine may return NULL
+ * upon error, in which case it will have set an error on the error
+ * stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRDNSeq
+ */
+
+NSS_EXTERN NSSRDNSeq *
+nssName_GetRDNSequence
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetSpecifiedChoice
+ *
+ * If the choice underlying the specified NSSName matches the specified
+ * choice, a caller-owned pointer to that underlying object will be
+ * returned.  Otherwise, an error will be placed on the error stack and
+ * NULL will be returned.  If the optional arena argument is non-null, 
+ * the memory required will be obtained from that arena; otherwise, the
+ * memory will be obtained from the heap.  The caller owns the returned
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer, which must be typecast
+ */
+
+NSS_EXTERN void *
+nssName_GetSpecifiedChoice
+(
+  NSSName *name,
+  NSSNameChoice choice,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_Compare
+ *
+ * This routine compares two Names for equality.  For two Names to be
+ * equal, they must have the same choice of underlying types, and the
+ * underlying values must be equal.  The result of the comparison will
+ * be stored at the location pointed to by the "equalp" variable, which
+ * must point to a valid PRBool. This routine may return PR_FAILURE
+ * upon error, in which case it will have set an error on the error
+ * stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE on error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+nssName_Compare
+(
+  NSSName *name1,
+  NSSName *name2,
+  PRBool *equalp
+);
+
+/*
+ * nssName_Duplicate
+ *
+ * This routine duplicates the specified nssname.  If the optional
+ * arena argument is non-null, the memory required will be obtained
+ * from that arena; otherwise, the memory will be obtained from the
+ * heap.  This routine may return NULL upon error, in which case it
+ * will have placed an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new NSSName
+ */
+
+NSS_EXTERN NSSName *
+nssName_Duplicate
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetUID
+ *
+ * This routine will attempt to derive a user identifier from the
+ * specified name, if the choices and content of the name permit.
+ * If the Name consists of a Sequence of Relative Distinguished 
+ * Names containing a UID attribute, the UID will be the value of 
+ * that attribute.  Note that no UID attribute is defined in either 
+ * PKIX or PKCS#9; rather, this seems to derive from RFC 1274, which 
+ * defines the type as a caseIgnoreString.  We'll return a Directory 
+ * String.  If the optional arena argument is non-null, the memory 
+ * used will be obtained from that arena; otherwise, the memory will 
+ * be obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_UID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String.
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssName_GetUID
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetEmail
+ *
+ * This routine will attempt to derive an email address from the
+ * specified name, if the choices and content of the name permit.  
+ * If the Name consists of a Sequence of Relative Distinguished 
+ * Names containing either a PKIX email address or a PKCS#9 email
+ * address, the result will be the value of that attribute.  If the
+ * optional arena argument is non-null, the memory used will be
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_EMAIL
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr IA5 String */
+nssName_GetEmail
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetCommonName
+ *
+ * This routine will attempt to derive a common name from the
+ * specified name, if the choices and content of the name permit.  
+ * If the Name consists of a Sequence of Relative Distinguished Names
+ * containing a PKIX Common Name, the result will be that name.  If 
+ * the optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_COMMON_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssName_GetCommonName
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetOrganization
+ *
+ * This routine will attempt to derive an organisation name from the
+ * specified name, if the choices and content of the name permit.  
+ * If Name consists of a Sequence of Relative Distinguished names 
+ * containing a PKIX Organization, the result will be the value of 
+ * that attribute.  If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  This routine may return NULL upon 
+ * error, in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_ORGANIZATION
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssName_GetOrganization
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetOrganizationalUnits
+ *
+ * This routine will attempt to derive a sequence of organisational 
+ * unit names from the specified name, if the choices and content of 
+ * the name permit.  If the Name consists of a Sequence of Relative 
+ * Distinguished Names containing one or more organisational units,
+ * the result will be the values of those attributes.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from 
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_ORGANIZATIONAL_UNITS
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a null-terminated array of UTF8 Strings
+ */
+
+NSS_EXTERN NSSUTF8 ** /* XXX fgmr DirectoryString */
+nssName_GetOrganizationalUnits
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetStateOrProvince
+ *
+ * This routine will attempt to derive a state or province name from 
+ * the specified name, if the choices and content of the name permit.
+ * If the Name consists of a Sequence of Relative Distinguished Names
+ * containing a state or province, the result will be the value of 
+ * that attribute.  If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  This routine may return NULL upon 
+ * error, in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_STATE_OR_PROVINCE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssName_GetStateOrProvince
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetLocality
+ *
+ * This routine will attempt to derive a locality name from the 
+ * specified name, if the choices and content of the name permit.  If
+ * the Name consists of a Sequence of Relative Distinguished names
+ * containing a Locality, the result will be the value of that 
+ * attribute.  If the optional arena argument is non-null, the memory 
+ * used will be obtained from that arena; otherwise, the memory will 
+ * be obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_LOCALITY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssName_GetLocality
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetCountry
+ *
+ * This routine will attempt to derive a country name from the 
+ * specified name, if the choices and content of the name permit.
+ * If the Name consists of a Sequence of Relative Distinguished 
+ * Names containing a Country, the result will be the value of
+ * that attribute..  If the optional arena argument is non-null, 
+ * the memory used will be obtained from that arena; otherwise, 
+ * the memory will be obtained from the heap.  This routine may 
+ * return NULL upon error, in which case it will have set an error 
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_COUNTRY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr PrintableString */
+nssName_GetCountry
+(
+  NSSName *name,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_GetAttribute
+ *
+ * If the specified name consists of a Sequence of Relative 
+ * Distinguished Names containing an attribute with the specified 
+ * type, and the actual value of that attribute may be expressed 
+ * with a Directory String, then the value of that attribute will 
+ * be returned as a Directory String.  If the optional arena argument 
+ * is non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine 
+ * may return NULL upon error, in which case it will have set an error 
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_NAME
+ *  NSS_ERROR_NO_ATTRIBUTE
+ *  NSS_ERROR_ATTRIBUTE_VALUE_NOT_STRING
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssName_GetAttribute
+(
+  NSSName *name,
+  NSSOID *attribute,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssName_EvaluateUTF8
+ *
+ * This routine evaluates a UTF8 string, and returns PR_TRUE if the 
+ * string contains the string representation of an NSSName.  This 
+ * routine is used by the GeneralName routine 
+ * nssGeneralName_CreateFromUTF8 to determine which choice of
+ * general name the string may encode.  This routine may return 
+ * PR_FALSE upon error, but it subsumes that condition under the 
+ * general "string does not evaluate as a Name" state, and does not
+ * set an error on the error stack.
+ * 
+ * Return value:
+ *  PR_TRUE if the string represents a Name
+ *  PR_FALSE otherwise
+ */
+
+NSS_EXTERN PRBool
+nssName_EvaluateUTF8
+(
+  NSSUTF8 *str
+);
+
+/*
+ * NSSGeneralName
+ *
+ * The non-public "methods" regarding this "object" are:
+ *
+ * nssGeneralName_CreateFromBER   -- constructor
+ * nssGeneralName_CreateFromUTF8  -- constructor
+ * nssGeneralName_Create          -- constructor
+ *
+ * nssGeneralName_Destroy
+ * nssGeneralName_GetDEREncoding
+ * nssGeneralName_GetUTF8Encoding
+ * nssGeneralName_GetChoice
+ * nssGeneralName_GetOtherName
+ * nssGeneralName_GetRfc822Name
+ * nssGeneralName_GetDNSName
+ * nssGeneralName_GetX400Address
+ * nssGeneralName_GetDirectoryName
+ * nssGeneralName_GetEdiPartyName
+ * nssGeneralName_GetUniformResourceIdentifier
+ * nssGeneralName_GetIPAddress
+ * nssGeneralName_GetRegisteredID
+ * nssGeneralName_GetSpecifiedChoice
+ * nssGeneralName_Compare
+ * nssGeneralName_Duplicate
+ *
+ * nssGeneralName_GetUID
+ * nssGeneralName_GetEmail
+ * nssGeneralName_GetCommonName
+ * nssGeneralName_GetOrganization
+ * nssGeneralName_GetOrganizationalUnits
+ * nssGeneralName_GetStateOrProvince
+ * nssGeneralName_GetLocality
+ * nssGeneralName_GetCountry
+ * nssGeneralName_GetAttribute
+ */
+
+/*
+ * nssGeneralName_CreateFromBER
+ *
+ * This routine creates an NSSGeneralName by decoding a BER- or DER-
+ * encoded general name.  If the optional arena argument is non-null,
+ * the memory used will be obtained from that arena; otherwise, the 
+ * memory will be obtained from the heap.  This routine may return 
+ * NULL upon error, in which case it will have set an error on the 
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralName upon success
+ */
+
+NSS_EXTERN NSSGeneralName *
+nssGeneralName_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berGeneralName
+);
+
+/*
+ * nssGeneralName_CreateFromUTF8
+ *
+ * This routine creates an NSSGeneralName by decoding a UTF8 string
+ * consisting of the string representation of one of the choices of
+ * general names.  If the optional arena argument is non-null, the 
+ * memory used will be obtained from that arena; otherwise, the memory
+ * will be obtained from the heap.  The routine may return NULL upon
+ * error, in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_UTF8
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralName upon success
+ */
+
+NSS_EXTERN NSSGeneralName *
+nssGeneralName_CreateFromUTF8
+(
+  NSSArena *arenaOpt,
+  NSSUTF8 *stringGeneralName
+);
+
+/*
+ * nssGeneralName_Create
+ *
+ * This routine creates an NSSGeneralName with the specified choice of
+ * underlying name types.  The value of the choice variable must be one
+ * of the values of the NSSGeneralNameChoice enumeration, and the type
+ * of the arg variable must be as specified in the following table:
+ *
+ *   Choice                                         Type
+ *   ============================================   =========
+ *   NSSGeneralNameChoiceOtherName
+ *   NSSGeneralNameChoiceRfc822Name
+ *   NSSGeneralNameChoiceDNSName
+ *   NSSGeneralNameChoiceX400Address
+ *   NSSGeneralNameChoiceDirectoryName              NSSName *
+ *   NSSGeneralNameChoiceEdiPartyName
+ *   NSSGeneralNameChoiceUniformResourceIdentifier
+ *   NSSGeneralNameChoiceIPAddress
+ *   NSSGeneralNameChoiceRegisteredID
+ *
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be 
+ * obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have set an error on the error stack.
+ *
+ * The error may be one fo the following values:
+ *  NSS_ERROR_INVALID_CHOICE
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralName upon success
+ */
+
+NSS_EXTERN NSSGeneralName *
+nssGeneralName_Create
+(
+  NSSGeneralNameChoice choice,
+  void *arg
+);
+
+/*
+ * nssGeneralName_Destroy
+ * 
+ * This routine will destroy a General Name object.  It should 
+ * eventually be called on all General Names created without an arena.
+ * While it is not necessary to call it on General Names created within
+ * an arena, it is not an error to do so.  This routine returns a
+ * PRStatus value; if successful, it will return PR_SUCCESS. If 
+ * usuccessful, it will set an error on the error stack and return 
+ * PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *
+ * Return value:
+ *  PR_FAILURE upon failure
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+nssGeneralName_Destroy
+(
+  NSSGeneralName *generalName
+);
+
+/*
+ * nssGeneralName_GetDEREncoding
+ *
+ * This routine will DER-encode a name object.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return null upon error, in which case it will have set
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSGeneralName
+ */
+
+NSS_EXTERN NSSDER *
+nssGeneralName_GetDEREncoding
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetUTF8Encoding
+ *
+ * This routine returns a UTF8 string containing a string 
+ * representation of the General Name in the format specified by the
+ * underlying name choice.  If the optional arena argument is 
+ * non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have set an error
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 string
+ */
+
+NSS_EXTERN NSSUTF8 *
+nssGeneralName_GetUTF8Encoding
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetChoice
+ *
+ * This routine returns the type of choice underlying the specified 
+ * general name.  The return value will be a member of the 
+ * NSSGeneralNameChoice enumeration.  This routine may return 
+ * NSSGeneralNameChoiceInvalid upon error, in which case it will have 
+ * set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *
+ * Return value:
+ *  NSSGeneralNameChoiceInvalid upon error
+ *  An other member of the NSSGeneralNameChoice enumeration 
+ */
+
+NSS_EXTERN NSSGeneralNameChoice
+nssGeneralName_GetChoice
+(
+  NSSGeneralName *generalName
+);
+
+/*
+ * nssGeneralName_GetOtherName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * Other Name, this routine will return a pointer to that Other name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSOtherName
+ */
+
+NSS_EXTERN NSSOtherName *
+nssGeneralName_GetOtherName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetRfc822Name
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * RFC 822 Name, this routine will return a pointer to that name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRFC822Name
+ */
+
+NSS_EXTERN NSSRFC822Name *
+nssGeneralName_GetRfc822Name
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetDNSName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a 
+ * DNS Name, this routine will return a pointer to that DNS name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSDNSName
+ */
+
+NSS_EXTERN NSSDNSName *
+nssGeneralName_GetDNSName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetX400Address
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * X.400 Address, this routine will return a pointer to that Address.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSX400Address
+ */
+
+NSS_EXTERN NSSX400Address *
+nssGeneralName_GetX400Address
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetDirectoryName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a
+ * (directory) Name, this routine will return a pointer to that name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSName
+ */
+
+NSS_EXTERN NSSName *
+nssGeneralName_GetName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetEdiPartyName
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * EDI Party Name, this routine will return a pointer to that name.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSEdiPartyName
+ */
+
+NSS_EXTERN NSSEdiPartyName *
+nssGeneralName_GetEdiPartyName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetUniformResourceIdentifier
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a
+ * URI, this routine will return a pointer to that URI.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSURI
+ */
+
+NSS_EXTERN NSSURI *
+nssGeneralName_GetUniformResourceIdentifier
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetIPAddress
+ *
+ * If the choice underlying the specified NSSGeneralName is that of an
+ * IP Address , this routine will return a pointer to that address.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSIPAddress
+ */
+
+NSS_EXTERN NSSIPAddress *
+nssGeneralName_GetIPAddress
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetRegisteredID
+ *
+ * If the choice underlying the specified NSSGeneralName is that of a
+ * Registered ID, this routine will return a pointer to that ID.
+ * Otherwise, this routine will place an error on the error stack, and
+ * return NULL.  If the optional arena argument is non-null, the memory
+ * required will be obtained from that arena; otherwise, the memory 
+ * will be obtained from the heap.  The caller owns the returned 
+ * pointer.  This routine may return NULL upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to an NSSRegisteredID
+ */
+
+NSS_EXTERN NSSRegisteredID *
+nssGeneralName_GetRegisteredID
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetSpecifiedChoice
+ *
+ * If the choice underlying the specified NSSGeneralName matches the
+ * specified choice, a caller-owned pointer to that underlying object
+ * will be returned.  Otherwise, an error will be placed on the error
+ * stack and NULL will be returned.  If the optional arena argument
+ * is non-null, the memory required will be obtained from that arena;
+ * otherwise, the memory will be obtained from the heap.  The caller
+ * owns the returned pointer.  This routine may return NULL upon 
+ * error, in which caes it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_WRONG_CHOICE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer, which must be typecast
+ */
+
+NSS_EXTERN void *
+nssGeneralName_GetSpecifiedChoice
+(
+  NSSGeneralName *generalName,
+  NSSGeneralNameChoice choice,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_Compare
+ * 
+ * This routine compares two General Names for equality.  For two 
+ * General Names to be equal, they must have the same choice of
+ * underlying types, and the underlying values must be equal.  The
+ * result of the comparison will be stored at the location pointed
+ * to by the "equalp" variable, which must point to a valid PRBool.
+ * This routine may return PR_FAILURE upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following value:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+nssGeneralName_Compare
+(
+  NSSGeneralName *generalName1,
+  NSSGeneralName *generalName2,
+  PRBool *equalp
+);
+
+/*
+ * nssGeneralName_Duplicate
+ *
+ * This routine duplicates the specified General Name.  If the optional
+ * arena argument is non-null, the memory required will be obtained
+ * from that arena; otherwise, the memory will be obtained from the
+ * heap.  This routine may return NULL upon error, in which case it 
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new NSSGeneralName
+ */
+
+NSS_EXTERN NSSGeneralName *
+nssGeneralName_Duplicate
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetUID
+ *
+ * This routine will attempt to derive a user identifier from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished Names containing a UID
+ * attribute, the UID will be the value of that attribute.  Note
+ * that no UID attribute is defined in either PKIX or PKCS#9; 
+ * rather, this seems to derive from RFC 1274, which defines the
+ * type as a caseIgnoreString.  We'll return a Directory String.
+ * If the optional arena argument is non-null, the memory used
+ * will be obtained from that arena; otherwise, the memory will be
+ * obtained from the heap.  This routine may return NULL upon error,
+ * in which case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_UID
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String.
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssGeneralName_GetUID
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetEmail
+ *
+ * This routine will attempt to derive an email address from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing either
+ * a PKIX email address or a PKCS#9 email address, the result will
+ * be the value of that attribute.  If the General Name is an RFC 822
+ * Name, the result will be the string form of that name.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_EMAIL
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr IA5String */
+nssGeneralName_GetEmail
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetCommonName
+ *
+ * This routine will attempt to derive a common name from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing a PKIX
+ * Common Name, the result will be that name.  If the optional arena 
+ * argument is non-null, the memory used will be obtained from that 
+ * arena; otherwise, the memory will be obtained from the heap.  This 
+ * routine may return NULL upon error, in which case it will have set 
+ * an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_COMMON_NAME
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssGeneralName_GetCommonName
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetOrganization
+ *
+ * This routine will attempt to derive an organisation name from the
+ * specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing an
+ * Organization, the result will be the value of that attribute.  
+ * If the optional arena argument is non-null, the memory used will 
+ * be obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_ORGANIZATION
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssGeneralName_GetOrganization
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetOrganizationalUnits
+ *
+ * This routine will attempt to derive a sequence of organisational 
+ * unit names from the specified general name, if the choices and 
+ * content of the name permit.  If the General Name is a (directory) 
+ * Name consisting of a Sequence of Relative Distinguished names 
+ * containing one or more organisational units, the result will 
+ * consist of those units.  If the optional arena  argument is non-
+ * null, the memory used will be obtained from that arena; otherwise, 
+ * the memory will be obtained from the heap.  This routine may return 
+ * NULL upon error, in which case it will have set an error on the 
+ * error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_ORGANIZATIONAL_UNITS
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a null-terminated array of UTF8 Strings
+ */
+
+NSS_EXTERN NSSUTF8 ** /* XXX fgmr DirectoryString */
+nssGeneralName_GetOrganizationalUnits
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetStateOrProvince
+ *
+ * This routine will attempt to derive a state or province name from 
+ * the specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing a state or 
+ * province, the result will be the value of that attribute.  If the 
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_STATE_OR_PROVINCE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssGeneralName_GetStateOrProvince
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetLocality
+ *
+ * This routine will attempt to derive a locality name from 
+ * the specified general name, if the choices and content of the name
+ * permit.  If the General Name is a (directory) Name consisting
+ * of a Sequence of Relative Distinguished names containing a Locality, 
+ * the result will be the value of that attribute.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from 
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_LOCALITY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssGeneralName_GetLocality
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetCountry
+ *
+ * This routine will attempt to derive a country name from the 
+ * specified general name, if the choices and content of the name 
+ * permit.  If the General Name is a (directory) Name consisting of a
+ * Sequence of Relative Distinguished names containing a Country, the 
+ * result will be the value of that attribute.  If the optional 
+ * arena argument is non-null, the memory used will be obtained from 
+ * that arena; otherwise, the memory will be obtained from the heap.  
+ * This routine may return NULL upon error, in which case it will have 
+ * set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_COUNTRY
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr PrintableString */
+nssGeneralName_GetCountry
+(
+  NSSGeneralName *generalName,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralName_GetAttribute
+ *
+ * If the specified general name is a (directory) name consisting
+ * of a Sequence of Relative Distinguished Names containing an 
+ * attribute with the specified type, and the actual value of that
+ * attribute may be expressed with a Directory String, then the
+ * value of that attribute will be returned as a Directory String.
+ * If the optional arena argument is non-null, the memory used will
+ * be obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_ATTRIBUTE
+ *  NSS_ERROR_ATTRIBUTE_VALUE_NOT_STRING
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a UTF8 String
+ */
+
+NSS_EXTERN NSSUTF8 * /* XXX fgmr DirectoryString */
+nssGeneralName_GetAttribute
+(
+  NSSGeneralName *generalName,
+  NSSOID *attribute,
+  NSSArena *arenaOpt
+);
+
+/*
+ * NSSGeneralNameSeq
+ *
+ * The public "methods" regarding this "object" are:
+ *
+ *  nssGeneralNameSeq_CreateFromBER   -- constructor
+ *  nssGeneralNameSeq_Create          -- constructor
+ *
+ *  nssGeneralNameSeq_Destroy
+ *  nssGeneralNameSeq_GetDEREncoding
+ *  nssGeneralNameSeq_AppendGeneralName
+ *  nssGeneralNameSeq_GetGeneralNameCount
+ *  nssGeneralNameSeq_GetGeneralName
+ *  nssGeneralNameSeq_Compare
+ *  nssGeneralnameSeq_Duplicate
+ */
+
+/*
+ * nssGeneralNameSeq_CreateFromBER
+ *
+ * This routine creates a general name sequence by decoding a BER-
+ * or DER-encoded GeneralNames.  If the optional arena argument is
+ * non-null, the memory used will be obtained from that arena; 
+ * otherwise, the memory will be obtained from the heap.  This routine
+ * may return NULL upon error, in which case it will have set an error
+ * on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_BER
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralNameSeq upon success
+ */
+
+NSS_EXTERN NSSGeneralNameSeq *
+nssGeneralNameSeq_CreateFromBER
+(
+  NSSArena *arenaOpt,
+  NSSBER *berGeneralNameSeq
+);
+
+/*
+ * nssGeneralNameSeq_Create
+ *
+ * This routine creates an NSSGeneralNameSeq from one or more General
+ * Names.  The final argument to this routine must be NULL.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_NO_MEMORY
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to an NSSGeneralNameSeq upon success
+ */
+
+NSS_EXTERN NSSGeneralNameSeq *
+nssGeneralNameSeq_Create
+(
+  NSSArena *arenaOpt,
+  NSSGeneralName *generalName1,
+  ...
+);
+
+/*
+ * nssGeneralNameSeq_Destroy
+ *
+ * This routine will destroy an NSSGeneralNameSeq object.  It should
+ * eventually be called on all NSSGeneralNameSeqs created without an
+ * arena.  While it is not necessary to call it on NSSGeneralNameSeq's
+ * created within an arena, it is not an error to do so.  This routine
+ * returns a PRStatus value; if successful, it will return PR_SUCCESS.
+ * If unsuccessful, it will set an error on the error stack and return
+ * PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon success
+ */
+
+NSS_EXTERN PRStatus
+nssGeneralNameSeq_Destroy
+(
+  NSSGeneralNameSeq *generalNameSeq
+);
+
+/*
+ * nssGeneralNameSeq_GetDEREncoding
+ *
+ * This routine will DER-encode an NSSGeneralNameSeq object.  If the
+ * optional arena argument is non-null, the memory used will be 
+ * obtained from that arena; otherwise, the memory will be obtained
+ * from the heap.  This routine may return null upon error, in which
+ * case it will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  The DER encoding of this NSSGeneralNameSeq
+ */
+
+NSS_EXTERN NSSDER *
+nssGeneralNameSeq_GetDEREncoding
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSArena *arenaOpt
+);
+
+/*
+ * nssGeneralNameSeq_AppendGeneralName
+ *
+ * This routine appends a General Name to the end of the existing
+ * General Name Sequence.  If the sequence was created with a non-null
+ * arena argument, that same arena will be used for any additional
+ * required memory.  If the sequence was created with a NULL arena
+ * argument, any additional memory will be obtained from the heap.
+ * This routine returns a PRStatus value; it will return PR_SUCCESS
+ * upon success, and upon failure it will set an error on the error
+ * stack and return PR_FAILURE.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_INVALID_GENERAL_NAME
+ *  NSS_ERROR_NO_MEMORY
+ * 
+ * Return value:
+ *  PR_SUCCESS upon success
+ *  PR_FAILURE upon failure.
+ */
+
+NSS_EXTERN PRStatus
+nssGeneralNameSeq_AppendGeneralName
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSGeneralName *generalName
+);
+
+/*
+ * nssGeneralNameSeq_GetGeneralNameCount
+ *
+ * This routine returns the cardinality of the specified General name
+ * Sequence.  This routine may return 0 upon error, in which case it
+ * will have set an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *
+ * Return value;
+ *  0 upon error
+ *  A positive number upon success
+ */
+
+NSS_EXTERN PRUint32
+nssGeneralNameSeq_GetGeneralNameCount
+(
+  NSSGeneralNameSeq *generalNameSeq
+);
+
+/*
+ * nssGeneralNameSeq_GetGeneralName
+ *
+ * This routine returns a pointer to the i'th General Name in the 
+ * specified General Name Sequence.  The value of the variable 'i' is
+ * on the range [0,c) where c is the cardinality returned from 
+ * NSSGeneralNameSeq_GetGeneralNameCount.  The caller owns the General
+ * Name the pointer to which is returned.  If the optional arena
+ * argument is non-null, the memory used will be obtained from that
+ * arena; otherwise, the memory will be obtained from the heap.  This
+ * routine may return NULL upon error, in which case it will have set
+ * an error upon the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_VALUE_OUT_OF_RANGE
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A caller-owned pointer to a General Name.
+ */
+
+NSS_EXTERN NSSGeneralName *
+nssGeneralNameSeq_GetGeneralName
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSArena *arenaOpt,
+  PRUint32 i
+);
+
+/*
+ * nssGeneralNameSeq_Compare
+ *
+ * This routine compares two General Name Sequences for equality.  For
+ * two General Name Sequences to be equal, they must have the same
+ * cardinality, and each General Name in one sequence must be equal to
+ * the corresponding General Name in the other.  The result of the
+ * comparison will be stored at the location pointed to by the "equalp"
+ * variable, which must point to a valid PRBool.  This routine may 
+ * return PR_FAILURE upon error, in which case it will have set an 
+ * error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_INVALID_ARGUMENT
+ *
+ * Return value:
+ *  PR_FAILURE upon error
+ *  PR_SUCCESS upon a successful comparison (equal or not)
+ */
+
+NSS_EXTERN PRStatus
+nssGeneralNameSeq_Compare
+(
+  NSSGeneralNameSeq *generalNameSeq1,
+  NSSGeneralNameSeq *generalNameSeq2,
+  PRBool *equalp
+);
+
+/*
+ * nssGeneralNameSeq_Duplicate
+ *
+ * This routine duplicates the specified sequence of general names.  If
+ * the optional arena argument is non-null, the memory required will be
+ * obtained from that arena; otherwise, the memory will be obtained 
+ * from the heap.  This routine may return NULL upon error, in which 
+ * case it will have placed an error on the error stack.
+ *
+ * The error may be one of the following values:
+ *  NSS_ERROR_INVALID_GENERAL_NAME_SEQ
+ *  NSS_ERROR_NO_MEMORY
+ *
+ * Return value:
+ *  NULL upon error
+ *  A pointer to a new General Name Sequence.
+ */
+
+NSS_EXTERN NSSGeneralNameSeq *
+nssGeneralNameSeq_Duplicate
+(
+  NSSGeneralNameSeq *generalNameSeq,
+  NSSArena *arenaOpt
+);
+
+PR_END_EXTERN_C
+
+#endif /* PKI1_H */
diff --git a/mozilla/security/nss/lib/pki1/pki1t.h b/mozilla/security/nss/lib/pki1/pki1t.h
new file mode 100644
index 0000000..99c18d3
--- /dev/null
+++ b/mozilla/security/nss/lib/pki1/pki1t.h
@@ -0,0 +1,107 @@
+/* ***** 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 ***** */
+
+#ifndef PKI1T_H
+#define PKI1T_H
+
+#ifdef DEBUG
+static const char PKI1T_CVS_ID[] = "@(#) $RCSfile: pki1t.h,v $ $Revision: 1.3 $ $Date: 2005/01/20 02:25:49 $";
+#endif /* DEBUG */
+
+/*
+ * pki1t.h
+ *
+ * This file contains definitions for the types used in the PKIX part-1
+ * code, but not available publicly.
+ */
+
+#ifndef BASET_H
+#include "baset.h"
+#endif /* BASET_H */
+
+#ifndef NSSPKI1T_H
+#include "nsspki1t.h"
+#endif /* NSSPKI1T_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSOID
+ *
+ * This structure is used to hold our internal table of built-in OID
+ * data.  The fields are as follows:
+ *
+ *  NSSItem     data -- this is the actual DER-encoded multinumber oid
+ *  const char *expl -- this explains the derivation, and is checked
+ *                      in a unit test.  While the field always exists,
+ *                      it is only populated or used in debug builds.
+ *
+ */
+
+struct NSSOIDStr {
+#ifdef DEBUG
+  const NSSUTF8 *tag;
+  const NSSUTF8 *expl;
+#endif /* DEBUG */
+  NSSItem data;
+};
+
+/*
+ * nssAttributeTypeAliasTable
+ *
+ * Attribute types are passed around as oids (at least in the X.500
+ * and PKI worlds, as opposed to ldap).  However, when written as 
+ * strings they usually have well-known aliases, e.g., "ou" or "c."
+ *
+ * This type defines a table, populated in the generated oiddata.c
+ * file, of the aliases we recognize.
+ *
+ * The fields are as follows:
+ *
+ *  NSSUTF8 *alias -- a well-known string alias for an oid
+ *  NSSOID  *oid   -- the oid to which the alias corresponds
+ *
+ */
+
+struct nssAttributeTypeAliasTableStr {
+  const NSSUTF8 *alias;
+  const NSSOID **oid;
+};
+typedef struct nssAttributeTypeAliasTableStr nssAttributeTypeAliasTable;
+
+PR_END_EXTERN_C
+
+#endif /* PKI1T_H */
diff --git a/mozilla/security/nss/lib/smime/cms.h b/mozilla/security/nss/lib/smime/cms.h
new file mode 100644
index 0000000..d3c22f0
--- /dev/null
+++ b/mozilla/security/nss/lib/smime/cms.h
@@ -0,0 +1,1134 @@
+/* ***** 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 ***** */
+
+/*
+ * Interfaces of the CMS implementation.
+ *
+ * $Id: cms.h,v 1.22 2008/06/14 14:20:31 wtc%google.com Exp $
+ */
+
+#ifndef _CMS_H_
+#define _CMS_H_
+
+#include "seccomon.h"
+
+#include "secoidt.h"
+#include "certt.h"
+#include "keyt.h"
+#include "hasht.h"
+#include "cmst.h"
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/************************************************************************
+ * cmsdecode.c - CMS decoding
+ ************************************************************************/
+
+/*
+ * NSS_CMSDecoder_Start - set up decoding of a DER-encoded CMS message
+ *
+ * "poolp" - pointer to arena for message, or NULL if new pool should be created
+ * "cb", "cb_arg" - callback function and argument for delivery of inner content
+ *                  inner content will be stored in the message if cb is NULL.
+ * "pwfn", pwfn_arg" - callback function for getting token password
+ * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
+ */
+extern NSSCMSDecoderContext *
+NSS_CMSDecoder_Start(PLArenaPool *poolp,
+		      NSSCMSContentCallback cb, void *cb_arg,
+		      PK11PasswordFunc pwfn, void *pwfn_arg,
+		      NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg);
+
+/*
+ * NSS_CMSDecoder_Update - feed DER-encoded data to decoder
+ */
+extern SECStatus
+NSS_CMSDecoder_Update(NSSCMSDecoderContext *p7dcx, const char *buf, unsigned long len);
+
+/*
+ * NSS_CMSDecoder_Cancel - cancel a decoding process
+ */
+extern void
+NSS_CMSDecoder_Cancel(NSSCMSDecoderContext *p7dcx);
+
+/*
+ * NSS_CMSDecoder_Finish - mark the end of inner content and finish decoding
+ */
+extern NSSCMSMessage *
+NSS_CMSDecoder_Finish(NSSCMSDecoderContext *p7dcx);
+
+/*
+ * NSS_CMSMessage_CreateFromDER - decode a CMS message from DER encoded data
+ */
+extern NSSCMSMessage *
+NSS_CMSMessage_CreateFromDER(SECItem *DERmessage,
+		    NSSCMSContentCallback cb, void *cb_arg,
+		    PK11PasswordFunc pwfn, void *pwfn_arg,
+		    NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg);
+
+/************************************************************************
+ * cmsencode.c - CMS encoding
+ ************************************************************************/
+
+/*
+ * NSS_CMSEncoder_Start - set up encoding of a CMS message
+ *
+ * "cmsg" - message to encode
+ * "outputfn", "outputarg" - callback function for delivery of DER-encoded output
+ *                           will not be called if NULL.
+ * "dest" - if non-NULL, pointer to SECItem that will hold the DER-encoded output
+ * "destpoolp" - pool to allocate DER-encoded output in
+ * "pwfn", pwfn_arg" - callback function for getting token password
+ * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
+ * "detached_digestalgs", "detached_digests" - digests from detached content
+ */
+extern NSSCMSEncoderContext *
+NSS_CMSEncoder_Start(NSSCMSMessage *cmsg,
+			NSSCMSContentCallback outputfn, void *outputarg,
+			SECItem *dest, PLArenaPool *destpoolp,
+			PK11PasswordFunc pwfn, void *pwfn_arg,
+			NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
+			SECAlgorithmID **detached_digestalgs, SECItem **detached_digests);
+
+/*
+ * NSS_CMSEncoder_Update - take content data delivery from the user
+ *
+ * "p7ecx" - encoder context
+ * "data" - content data
+ * "len" - length of content data
+ */
+extern SECStatus
+NSS_CMSEncoder_Update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned long len);
+
+/*
+ * NSS_CMSEncoder_Cancel - stop all encoding
+ */
+extern SECStatus
+NSS_CMSEncoder_Cancel(NSSCMSEncoderContext *p7ecx);
+
+/*
+ * NSS_CMSEncoder_Finish - signal the end of data
+ *
+ * we need to walk down the chain of encoders and the finish them from the innermost out
+ */
+extern SECStatus
+NSS_CMSEncoder_Finish(NSSCMSEncoderContext *p7ecx);
+
+/************************************************************************
+ * cmsmessage.c - CMS message object
+ ************************************************************************/
+
+/*
+ * NSS_CMSMessage_Create - create a CMS message object
+ *
+ * "poolp" - arena to allocate memory from, or NULL if new arena should be created
+ */
+extern NSSCMSMessage *
+NSS_CMSMessage_Create(PLArenaPool *poolp);
+
+/*
+ * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
+ *
+ * "cmsg" - message object
+ * "pwfn", pwfn_arg" - callback function for getting token password
+ * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
+ * "detached_digestalgs", "detached_digests" - digests from detached content
+ *
+ * used internally.
+ */
+extern void
+NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
+			PK11PasswordFunc pwfn, void *pwfn_arg,
+			NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
+			SECAlgorithmID **detached_digestalgs, SECItem **detached_digests);
+
+/*
+ * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
+ */
+extern void
+NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_Copy - return a copy of the given message. 
+ *
+ * The copy may be virtual or may be real -- either way, the result needs
+ * to be passed to NSS_CMSMessage_Destroy later (as does the original).
+ */
+extern NSSCMSMessage *
+NSS_CMSMessage_Copy(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
+ */
+extern PLArenaPool *
+NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
+ */
+extern NSSCMSContentInfo *
+NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg);
+
+/*
+ * Return a pointer to the actual content. 
+ * In the case of those types which are encrypted, this returns the *plain* content.
+ * In case of nested contentInfos, this descends and retrieves the innermost content.
+ */
+extern SECItem *
+NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
+ *
+ * CMS data content objects do not count.
+ */
+extern int
+NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_ContentLevel - find content level #n
+ *
+ * CMS data content objects do not count.
+ */
+extern NSSCMSContentInfo *
+NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n);
+
+/*
+ * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
+ */
+extern PRBool
+NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
+ */
+extern PRBool
+NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
+ *
+ * If the CMS message has a SignedData with a signature (not just a SignedData)
+ * return true; false otherwise.  This can/should be called before calling
+ * VerifySignature, which will always indicate failure if no signature is
+ * present, but that does not mean there even was a signature!
+ * Note that the content itself can be empty (detached content was sent
+ * another way); it is the presence of the signature that matters.
+ */
+extern PRBool
+NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg);
+
+/*
+ * NSS_CMSMessage_IsContentEmpty - see if content is empty
+ *
+ * returns PR_TRUE is innermost content length is < minLen
+ * XXX need the encrypted content length (why?)
+ */
+extern PRBool
+NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen);
+
+/************************************************************************
+ * cmscinfo.c - CMS contentInfo methods
+ ************************************************************************/
+
+/*
+ * NSS_CMSContentInfo_Destroy - destroy a CMS contentInfo and all of its sub-pieces.
+ */
+extern void
+NSS_CMSContentInfo_Destroy(NSSCMSContentInfo *cinfo);
+
+/*
+ * NSS_CMSContentInfo_GetChildContentInfo - get content's contentInfo (if it exists)
+ */
+extern NSSCMSContentInfo *
+NSS_CMSContentInfo_GetChildContentInfo(NSSCMSContentInfo *cinfo);
+
+/*
+ * NSS_CMSContentInfo_SetContent - set cinfo's content type & content to CMS object
+ */
+extern SECStatus
+NSS_CMSContentInfo_SetContent(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, SECOidTag type, void *ptr);
+
+/*
+ * NSS_CMSContentInfo_SetContent_XXXX - typesafe wrappers for NSS_CMSContentInfo_SetType
+ *   set cinfo's content type & content to CMS object
+ */
+extern SECStatus
+NSS_CMSContentInfo_SetContent_Data(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, SECItem *data, PRBool detached);
+
+extern SECStatus
+NSS_CMSContentInfo_SetContent_SignedData(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, NSSCMSSignedData *sigd);
+
+extern SECStatus
+NSS_CMSContentInfo_SetContent_EnvelopedData(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, NSSCMSEnvelopedData *envd);
+
+extern SECStatus
+NSS_CMSContentInfo_SetContent_DigestedData(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, NSSCMSDigestedData *digd);
+
+extern SECStatus
+NSS_CMSContentInfo_SetContent_EncryptedData(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSContentInfo_GetContent - get pointer to inner content
+ *
+ * needs to be casted...
+ */
+extern void *
+NSS_CMSContentInfo_GetContent(NSSCMSContentInfo *cinfo);
+
+/* 
+ * NSS_CMSContentInfo_GetInnerContent - get pointer to innermost content
+ *
+ * this is typically only called by NSS_CMSMessage_GetContent()
+ */
+extern SECItem *
+NSS_CMSContentInfo_GetInnerContent(NSSCMSContentInfo *cinfo);
+
+/*
+ * NSS_CMSContentInfo_GetContentType{Tag,OID} - find out (saving pointer to lookup result
+ * for future reference) and return the inner content type.
+ */
+extern SECOidTag
+NSS_CMSContentInfo_GetContentTypeTag(NSSCMSContentInfo *cinfo);
+
+extern SECItem *
+NSS_CMSContentInfo_GetContentTypeOID(NSSCMSContentInfo *cinfo);
+
+/*
+ * NSS_CMSContentInfo_GetContentEncAlgTag - find out (saving pointer to lookup result
+ * for future reference) and return the content encryption algorithm tag.
+ */
+extern SECOidTag
+NSS_CMSContentInfo_GetContentEncAlgTag(NSSCMSContentInfo *cinfo);
+
+/*
+ * NSS_CMSContentInfo_GetContentEncAlg - find out and return the content encryption algorithm tag.
+ */
+extern SECAlgorithmID *
+NSS_CMSContentInfo_GetContentEncAlg(NSSCMSContentInfo *cinfo);
+
+extern SECStatus
+NSS_CMSContentInfo_SetContentEncAlg(PLArenaPool *poolp, NSSCMSContentInfo *cinfo,
+				    SECOidTag bulkalgtag, SECItem *parameters, int keysize);
+
+extern SECStatus
+NSS_CMSContentInfo_SetContentEncAlgID(PLArenaPool *poolp, NSSCMSContentInfo *cinfo,
+				    SECAlgorithmID *algid, int keysize);
+
+extern void
+NSS_CMSContentInfo_SetBulkKey(NSSCMSContentInfo *cinfo, PK11SymKey *bulkkey);
+
+extern PK11SymKey *
+NSS_CMSContentInfo_GetBulkKey(NSSCMSContentInfo *cinfo);
+
+extern int
+NSS_CMSContentInfo_GetBulkKeySize(NSSCMSContentInfo *cinfo);
+
+/************************************************************************
+ * cmsutil.c - CMS misc utility functions
+ ************************************************************************/
+
+/*
+ * NSS_CMSArray_SortByDER - sort array of objects by objects' DER encoding
+ *
+ * make sure that the order of the objects guarantees valid DER (which must be
+ * in lexigraphically ascending order for a SET OF); if reordering is necessary it
+ * will be done in place (in objs).
+ */
+extern SECStatus
+NSS_CMSArray_SortByDER(void **objs, const SEC_ASN1Template *objtemplate, void **objs2);
+
+/*
+ * NSS_CMSUtil_DERCompare - for use with NSS_CMSArray_Sort to
+ *  sort arrays of SECItems containing DER
+ */
+extern int
+NSS_CMSUtil_DERCompare(void *a, void *b);
+
+/*
+ * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of 
+ * algorithms.
+ *
+ * algorithmArray - array of algorithm IDs
+ * algid - algorithmid of algorithm to pick
+ *
+ * Returns:
+ *  An integer containing the index of the algorithm in the array or -1 if 
+ *  algorithm was not found.
+ */
+extern int
+NSS_CMSAlgArray_GetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid);
+
+/*
+ * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of 
+ * algorithms.
+ *
+ * algorithmArray - array of algorithm IDs
+ * algiddata - id of algorithm to pick
+ *
+ * Returns:
+ *  An integer containing the index of the algorithm in the array or -1 if 
+ *  algorithm was not found.
+ */
+extern int
+NSS_CMSAlgArray_GetIndexByAlgTag(SECAlgorithmID **algorithmArray, SECOidTag algtag);
+
+extern const SECHashObject *
+NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid);
+
+extern const SEC_ASN1Template *
+NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type);
+
+extern size_t
+NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type);
+
+extern NSSCMSContentInfo *
+NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type);
+
+extern const char *
+NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs);
+
+/************************************************************************
+ * cmssigdata.c - CMS signedData methods
+ ************************************************************************/
+
+extern NSSCMSSignedData *
+NSS_CMSSignedData_Create(NSSCMSMessage *cmsg);
+
+extern void
+NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd);
+
+/*
+ * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData
+ *     before start of encoding.
+ *
+ * In detail:
+ *  - find out about the right value to put into sigd->version
+ *  - come up with a list of digestAlgorithms (which should be the union of the algorithms
+ *         in the signerinfos).
+ *         If we happen to have a pre-set list of algorithms (and digest values!), we
+ *         check if we have all the signerinfos' algorithms. If not, this is an error.
+ */
+extern SECStatus
+NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData *sigd);
+
+extern SECStatus
+NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData *sigd);
+
+/*
+ * NSS_CMSSignedData_Encode_AfterData - do all the necessary things to a SignedData
+ *     after all the encapsulated data was passed through the encoder.
+ *
+ * In detail:
+ *  - create the signatures in all the SignerInfos
+ *
+ * Please note that nothing is done to the Certificates and CRLs in the message - this
+ * is entirely the responsibility of our callers.
+ */
+extern SECStatus
+NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData *sigd);
+
+extern SECStatus
+NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd);
+
+/*
+ * NSS_CMSSignedData_Decode_AfterData - do all the necessary things to a SignedData
+ *     after all the encapsulated data was passed through the decoder.
+ */
+extern SECStatus
+NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData *sigd);
+
+/*
+ * NSS_CMSSignedData_Decode_AfterEnd - do all the necessary things to a SignedData
+ *     after all decoding is finished.
+ */
+extern SECStatus
+NSS_CMSSignedData_Decode_AfterEnd(NSSCMSSignedData *sigd);
+
+/* 
+ * NSS_CMSSignedData_GetSignerInfos - retrieve the SignedData's signer list
+ */
+extern NSSCMSSignerInfo **
+NSS_CMSSignedData_GetSignerInfos(NSSCMSSignedData *sigd);
+
+extern int
+NSS_CMSSignedData_SignerInfoCount(NSSCMSSignedData *sigd);
+
+extern NSSCMSSignerInfo *
+NSS_CMSSignedData_GetSignerInfo(NSSCMSSignedData *sigd, int i);
+
+/* 
+ * NSS_CMSSignedData_GetDigestAlgs - retrieve the SignedData's digest algorithm list
+ */
+extern SECAlgorithmID **
+NSS_CMSSignedData_GetDigestAlgs(NSSCMSSignedData *sigd);
+
+/*
+ * NSS_CMSSignedData_GetContentInfo - return pointer to this signedData's contentinfo
+ */
+extern NSSCMSContentInfo *
+NSS_CMSSignedData_GetContentInfo(NSSCMSSignedData *sigd);
+
+/* 
+ * NSS_CMSSignedData_GetCertificateList - retrieve the SignedData's certificate list
+ */
+extern SECItem **
+NSS_CMSSignedData_GetCertificateList(NSSCMSSignedData *sigd);
+
+extern SECStatus
+NSS_CMSSignedData_ImportCerts(NSSCMSSignedData *sigd, CERTCertDBHandle *certdb,
+				SECCertUsage certusage, PRBool keepcerts);
+
+/*
+ * NSS_CMSSignedData_HasDigests - see if we have digests in place
+ */
+extern PRBool
+NSS_CMSSignedData_HasDigests(NSSCMSSignedData *sigd);
+
+/*
+ * NSS_CMSSignedData_VerifySignerInfo - check a signature.
+ *
+ * The digests were either calculated during decoding (and are stored in the
+ * signedData itself) or set after decoding using NSS_CMSSignedData_SetDigests.
+ *
+ * The verification checks if the signing cert is valid and has a trusted chain
+ * for the purpose specified by "certusage".
+ */
+extern SECStatus
+NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedData *sigd, int i, CERTCertDBHandle *certdb,
+				    SECCertUsage certusage);
+
+/*
+ * NSS_CMSSignedData_VerifyCertsOnly - verify the certs in a certs-only message
+*/
+extern SECStatus
+NSS_CMSSignedData_VerifyCertsOnly(NSSCMSSignedData *sigd, 
+                                  CERTCertDBHandle *certdb, 
+                                  SECCertUsage usage);
+
+extern SECStatus
+NSS_CMSSignedData_AddCertList(NSSCMSSignedData *sigd, CERTCertificateList *certlist);
+
+/*
+ * NSS_CMSSignedData_AddCertChain - add cert and its entire chain to the set of certs 
+ */
+extern SECStatus
+NSS_CMSSignedData_AddCertChain(NSSCMSSignedData *sigd, CERTCertificate *cert);
+
+extern SECStatus
+NSS_CMSSignedData_AddCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert);
+
+extern PRBool
+NSS_CMSSignedData_ContainsCertsOrCrls(NSSCMSSignedData *sigd);
+
+extern SECStatus
+NSS_CMSSignedData_AddSignerInfo(NSSCMSSignedData *sigd,
+				NSSCMSSignerInfo *signerinfo);
+
+extern SECStatus
+NSS_CMSSignedData_SetDigests(NSSCMSSignedData *sigd,
+				SECAlgorithmID **digestalgs,
+				SECItem **digests);
+
+extern SECStatus
+NSS_CMSSignedData_SetDigestValue(NSSCMSSignedData *sigd,
+				SECOidTag digestalgtag,
+				SECItem *digestdata);
+
+extern SECStatus
+NSS_CMSSignedData_AddDigest(PLArenaPool *poolp,
+				NSSCMSSignedData *sigd,
+				SECOidTag digestalgtag,
+				SECItem *digest);
+
+extern SECItem *
+NSS_CMSSignedData_GetDigestValue(NSSCMSSignedData *sigd, SECOidTag digestalgtag);
+
+/*
+ * NSS_CMSSignedData_CreateCertsOnly - create a certs-only SignedData.
+ *
+ * cert          - base certificates that will be included
+ * include_chain - if true, include the complete cert chain for cert
+ *
+ * More certs and chains can be added via AddCertificate and AddCertChain.
+ *
+ * An error results in a return value of NULL and an error set.
+ */
+extern NSSCMSSignedData *
+NSS_CMSSignedData_CreateCertsOnly(NSSCMSMessage *cmsg, CERTCertificate *cert, PRBool include_chain);
+
+/************************************************************************
+ * cmssiginfo.c - signerinfo methods
+ ************************************************************************/
+
+extern NSSCMSSignerInfo *
+NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag);
+extern NSSCMSSignerInfo *
+NSS_CMSSignerInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID, SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag);
+
+/*
+ * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure
+ */
+extern void
+NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si);
+
+/*
+ * NSS_CMSSignerInfo_Sign - sign something
+ *
+ */
+extern SECStatus
+NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest, SECItem *contentType);
+
+extern SECStatus
+NSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,
+			    SECCertUsage certusage);
+
+/*
+ * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo
+ *
+ * Just verifies the signature. The assumption is that verification of the certificate
+ * is done already.
+ */
+extern SECStatus
+NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo, SECItem *digest, SECItem *contentType);
+
+extern NSSCMSVerificationStatus
+NSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo);
+
+extern SECOidData *
+NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo);
+
+extern SECOidTag
+NSS_CMSSignerInfo_GetDigestAlgTag(NSSCMSSignerInfo *signerinfo);
+
+extern int
+NSS_CMSSignerInfo_GetVersion(NSSCMSSignerInfo *signerinfo);
+
+extern CERTCertificateList *
+NSS_CMSSignerInfo_GetCertList(NSSCMSSignerInfo *signerinfo);
+
+/*
+ * NSS_CMSSignerInfo_GetSigningTime - return the signing time,
+ *				      in UTCTime format, of a CMS signerInfo.
+ *
+ * sinfo - signerInfo data for this signer
+ *
+ * Returns a pointer to XXXX (what?)
+ * A return value of NULL is an error.
+ */
+extern SECStatus
+NSS_CMSSignerInfo_GetSigningTime(NSSCMSSignerInfo *sinfo, PRTime *stime);
+
+/*
+ * Return the signing cert of a CMS signerInfo.
+ *
+ * the certs in the enclosing SignedData must have been imported already
+ */
+extern CERTCertificate *
+NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb);
+
+/*
+ * NSS_CMSSignerInfo_GetSignerCommonName - return the common name of the signer
+ *
+ * sinfo - signerInfo data for this signer
+ *
+ * Returns a pointer to allocated memory, which must be freed with PORT_Free.
+ * A return value of NULL is an error.
+ */
+extern char *
+NSS_CMSSignerInfo_GetSignerCommonName(NSSCMSSignerInfo *sinfo);
+
+/*
+ * NSS_CMSSignerInfo_GetSignerEmailAddress - return the common name of the signer
+ *
+ * sinfo - signerInfo data for this signer
+ *
+ * Returns a pointer to allocated memory, which must be freed.
+ * A return value of NULL is an error.
+ */
+extern char *
+NSS_CMSSignerInfo_GetSignerEmailAddress(NSSCMSSignerInfo *sinfo);
+
+/*
+ * NSS_CMSSignerInfo_AddAuthAttr - add an attribute to the
+ * authenticated (i.e. signed) attributes of "signerinfo". 
+ */
+extern SECStatus
+NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr);
+
+/*
+ * NSS_CMSSignerInfo_AddUnauthAttr - add an attribute to the
+ * unauthenticated attributes of "signerinfo". 
+ */
+extern SECStatus
+NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr);
+
+/* 
+ * NSS_CMSSignerInfo_AddSigningTime - add the signing time to the
+ * authenticated (i.e. signed) attributes of "signerinfo". 
+ *
+ * This is expected to be included in outgoing signed
+ * messages for email (S/MIME) but is likely useful in other situations.
+ *
+ * This should only be added once; a second call will do nothing.
+ *
+ * XXX This will probably just shove the current time into "signerinfo"
+ * but it will not actually get signed until the entire item is
+ * processed for encoding.  Is this (expected to be small) delay okay?
+ */
+extern SECStatus
+NSS_CMSSignerInfo_AddSigningTime(NSSCMSSignerInfo *signerinfo, PRTime t);
+
+/*
+ * NSS_CMSSignerInfo_AddSMIMECaps - add a SMIMECapabilities attribute to the
+ * authenticated (i.e. signed) attributes of "signerinfo".
+ *
+ * This is expected to be included in outgoing signed
+ * messages for email (S/MIME).
+ */
+extern SECStatus
+NSS_CMSSignerInfo_AddSMIMECaps(NSSCMSSignerInfo *signerinfo);
+
+/*
+ * NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
+ * authenticated (i.e. signed) attributes of "signerinfo".
+ *
+ * This is expected to be included in outgoing signed messages for email (S/MIME).
+ */
+SECStatus
+NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb);
+
+/*
+ * NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
+ * authenticated (i.e. signed) attributes of "signerinfo", using the OID prefered by Microsoft.
+ *
+ * This is expected to be included in outgoing signed messages for email (S/MIME),
+ * if compatibility with Microsoft mail clients is wanted.
+ */
+SECStatus
+NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb);
+
+/* 
+ * NSS_CMSSignerInfo_AddCounterSignature - countersign a signerinfo
+ */
+extern SECStatus
+NSS_CMSSignerInfo_AddCounterSignature(NSSCMSSignerInfo *signerinfo,
+				    SECOidTag digestalg, CERTCertificate signingcert);
+
+/*
+ * XXXX the following needs to be done in the S/MIME layer code
+ * after signature of a signerinfo is verified
+ */
+extern SECStatus
+NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo);
+
+/*
+ * NSS_CMSSignerInfo_IncludeCerts - set cert chain inclusion mode for this signer
+ */
+extern SECStatus
+NSS_CMSSignerInfo_IncludeCerts(NSSCMSSignerInfo *signerinfo, NSSCMSCertChainMode cm, SECCertUsage usage);
+
+/************************************************************************
+ * cmsenvdata.c - CMS envelopedData methods
+ ************************************************************************/
+
+/*
+ * NSS_CMSEnvelopedData_Create - create an enveloped data message
+ */
+extern NSSCMSEnvelopedData *
+NSS_CMSEnvelopedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm, int keysize);
+
+/*
+ * NSS_CMSEnvelopedData_Destroy - destroy an enveloped data message
+ */
+extern void
+NSS_CMSEnvelopedData_Destroy(NSSCMSEnvelopedData *edp);
+
+/*
+ * NSS_CMSEnvelopedData_GetContentInfo - return pointer to this envelopedData's contentinfo
+ */
+extern NSSCMSContentInfo *
+NSS_CMSEnvelopedData_GetContentInfo(NSSCMSEnvelopedData *envd);
+
+/*
+ * NSS_CMSEnvelopedData_AddRecipient - add a recipientinfo to the enveloped data msg
+ *
+ * rip must be created on the same pool as edp - this is not enforced, though.
+ */
+extern SECStatus
+NSS_CMSEnvelopedData_AddRecipient(NSSCMSEnvelopedData *edp, NSSCMSRecipientInfo *rip);
+
+/*
+ * NSS_CMSEnvelopedData_Encode_BeforeStart - prepare this envelopedData for encoding
+ *
+ * at this point, we need
+ * - recipientinfos set up with recipient's certificates
+ * - a content encryption algorithm (if none, 3DES will be used)
+ *
+ * this function will generate a random content encryption key (aka bulk key),
+ * initialize the recipientinfos with certificate identification and wrap the bulk key
+ * using the proper algorithm for every certificiate.
+ * it will finally set the bulk algorithm and key so that the encode step can find it.
+ */
+extern SECStatus
+NSS_CMSEnvelopedData_Encode_BeforeStart(NSSCMSEnvelopedData *envd);
+
+/*
+ * NSS_CMSEnvelopedData_Encode_BeforeData - set up encryption
+ */
+extern SECStatus
+NSS_CMSEnvelopedData_Encode_BeforeData(NSSCMSEnvelopedData *envd);
+
+/*
+ * NSS_CMSEnvelopedData_Encode_AfterData - finalize this envelopedData for encoding
+ */
+extern SECStatus
+NSS_CMSEnvelopedData_Encode_AfterData(NSSCMSEnvelopedData *envd);
+
+/*
+ * NSS_CMSEnvelopedData_Decode_BeforeData - find our recipientinfo, 
+ * derive bulk key & set up our contentinfo
+ */
+extern SECStatus
+NSS_CMSEnvelopedData_Decode_BeforeData(NSSCMSEnvelopedData *envd);
+
+/*
+ * NSS_CMSEnvelopedData_Decode_AfterData - finish decrypting this envelopedData's content
+ */
+extern SECStatus
+NSS_CMSEnvelopedData_Decode_AfterData(NSSCMSEnvelopedData *envd);
+
+/*
+ * NSS_CMSEnvelopedData_Decode_AfterEnd - finish decoding this envelopedData
+ */
+extern SECStatus
+NSS_CMSEnvelopedData_Decode_AfterEnd(NSSCMSEnvelopedData *envd);
+
+
+/************************************************************************
+ * cmsrecinfo.c - CMS recipientInfo methods
+ ************************************************************************/
+
+/*
+ * NSS_CMSRecipientInfo_Create - create a recipientinfo
+ *
+ * we currently do not create KeyAgreement recipientinfos with multiple recipientEncryptedKeys
+ * the certificate is supposed to have been verified by the caller
+ */
+extern NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert);
+
+extern NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage   *cmsg, 
+                                         SECItem         *subjKeyID,
+                                         SECKEYPublicKey *pubKey);
+
+extern NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg, 
+                                                 CERTCertificate *cert);
+
+/*
+ * NSS_CMSRecipientInfo_CreateNew - create a blank recipientinfo for 
+ * applications which want to encode their own CMS structures and
+ * key exchange types.
+ */
+extern NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg);
+
+/*
+ * NSS_CMSRecipientInfo_CreateFromDER - create a recipientinfo  from partially
+ * decoded DER data for applications which want to encode their own CMS 
+ * structures and key exchange types.
+ */
+extern NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg);
+
+extern void
+NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri);
+
+/*
+ * NSS_CMSRecipientInfo_GetCertAndKey - retrieve the cert and key from the
+ * recipientInfo struct. If retcert or retkey are NULL, the cert or 
+ * key (respectively) would not be returned). This function is a no-op if both 
+ * retcert and retkey are NULL. Caller inherits ownership of the cert and key
+ * he requested (and is responsible to free them).
+ */
+SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri,
+   CERTCertificate** retcert, SECKEYPrivateKey** retkey);
+
+extern int
+NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri);
+
+extern SECItem *
+NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex);
+
+/*
+ * NSS_CMSRecipientInfo_Encode - encode an NSS_CMSRecipientInfo as ASN.1
+ */
+SECStatus NSS_CMSRecipientInfo_Encode(PLArenaPool* poolp,
+                                      const NSSCMSRecipientInfo *src,
+                                      SECItem* returned);
+
+extern SECOidTag
+NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri);
+
+extern SECStatus
+NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, SECOidTag bulkalgtag);
+
+extern PK11SymKey *
+NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
+		CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag);
+
+/************************************************************************
+ * cmsencdata.c - CMS encryptedData methods
+ ************************************************************************/
+/*
+ * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
+ *
+ * "algorithm" specifies the bulk encryption algorithm to use.
+ * "keysize" is the key size.
+ * 
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+extern NSSCMSEncryptedData *
+NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm, int keysize);
+
+/*
+ * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
+ */
+extern void
+NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
+ */
+extern NSSCMSContentInfo *
+NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
+ *     before encoding begins.
+ *
+ * In particular:
+ *  - set the correct version value.
+ *  - get the encryption key
+ */
+extern SECStatus
+NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
+ */
+extern SECStatus
+NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
+ */
+extern SECStatus
+NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
+ */
+extern SECStatus
+NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
+ */
+extern SECStatus
+NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd);
+
+/*
+ * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
+ */
+extern SECStatus
+NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd);
+
+/************************************************************************
+ * cmsdigdata.c - CMS encryptedData methods
+ ************************************************************************/
+/*
+ * NSS_CMSDigestedData_Create - create a digestedData object (presumably for encoding)
+ *
+ * version will be set by NSS_CMSDigestedData_Encode_BeforeStart
+ * digestAlg is passed as parameter
+ * contentInfo must be filled by the user
+ * digest will be calculated while encoding
+ */
+extern NSSCMSDigestedData *
+NSS_CMSDigestedData_Create(NSSCMSMessage *cmsg, SECAlgorithmID *digestalg);
+
+/*
+ * NSS_CMSDigestedData_Destroy - destroy a digestedData object
+ */
+extern void
+NSS_CMSDigestedData_Destroy(NSSCMSDigestedData *digd);
+
+/*
+ * NSS_CMSDigestedData_GetContentInfo - return pointer to digestedData object's contentInfo
+ */
+extern NSSCMSContentInfo *
+NSS_CMSDigestedData_GetContentInfo(NSSCMSDigestedData *digd);
+
+/*
+ * NSS_CMSDigestedData_Encode_BeforeStart - do all the necessary things to a DigestedData
+ *     before encoding begins.
+ *
+ * In particular:
+ *  - set the right version number. The contentInfo's content type must be set up already.
+ */
+extern SECStatus
+NSS_CMSDigestedData_Encode_BeforeStart(NSSCMSDigestedData *digd);
+
+/*
+ * NSS_CMSDigestedData_Encode_BeforeData - do all the necessary things to a DigestedData
+ *     before the encapsulated data is passed through the encoder.
+ *
+ * In detail:
+ *  - set up the digests if necessary
+ */
+extern SECStatus
+NSS_CMSDigestedData_Encode_BeforeData(NSSCMSDigestedData *digd);
+
+/*
+ * NSS_CMSDigestedData_Encode_AfterData - do all the necessary things to a DigestedData
+ *     after all the encapsulated data was passed through the encoder.
+ *
+ * In detail:
+ *  - finish the digests
+ */
+extern SECStatus
+NSS_CMSDigestedData_Encode_AfterData(NSSCMSDigestedData *digd);
+
+/*
+ * NSS_CMSDigestedData_Decode_BeforeData - do all the necessary things to a DigestedData
+ *     before the encapsulated data is passed through the encoder.
+ *
+ * In detail:
+ *  - set up the digests if necessary
+ */
+extern SECStatus
+NSS_CMSDigestedData_Decode_BeforeData(NSSCMSDigestedData *digd);
+
+/*
+ * NSS_CMSDigestedData_Decode_AfterData - do all the necessary things to a DigestedData
+ *     after all the encapsulated data was passed through the encoder.
+ *
+ * In detail:
+ *  - finish the digests
+ */
+extern SECStatus
+NSS_CMSDigestedData_Decode_AfterData(NSSCMSDigestedData *digd);
+
+/*
+ * NSS_CMSDigestedData_Decode_AfterEnd - finalize a digestedData.
+ *
+ * In detail:
+ *  - check the digests for equality
+ */
+extern SECStatus
+NSS_CMSDigestedData_Decode_AfterEnd(NSSCMSDigestedData *digd);
+
+/************************************************************************
+ * cmsdigest.c - digestion routines
+ ************************************************************************/
+
+/*
+ * NSS_CMSDigestContext_StartMultiple - start digest calculation using all the
+ *  digest algorithms in "digestalgs" in parallel.
+ */
+extern NSSCMSDigestContext *
+NSS_CMSDigestContext_StartMultiple(SECAlgorithmID **digestalgs);
+
+/*
+ * NSS_CMSDigestContext_StartSingle - same as NSS_CMSDigestContext_StartMultiple, but
+ *  only one algorithm.
+ */
+extern NSSCMSDigestContext *
+NSS_CMSDigestContext_StartSingle(SECAlgorithmID *digestalg);
+
+/*
+ * NSS_CMSDigestContext_Update - feed more data into the digest machine
+ */
+extern void
+NSS_CMSDigestContext_Update(NSSCMSDigestContext *cmsdigcx, const unsigned char *data, int len);
+
+/*
+ * NSS_CMSDigestContext_Cancel - cancel digesting operation
+ */
+extern void
+NSS_CMSDigestContext_Cancel(NSSCMSDigestContext *cmsdigcx);
+
+/*
+ * NSS_CMSDigestContext_FinishMultiple - finish the digests and put them
+ *  into an array of SECItems (allocated on poolp)
+ */
+extern SECStatus
+NSS_CMSDigestContext_FinishMultiple(NSSCMSDigestContext *cmsdigcx, PLArenaPool *poolp,
+			    SECItem ***digestsp);
+
+/*
+ * NSS_CMSDigestContext_FinishSingle - same as NSS_CMSDigestContext_FinishMultiple,
+ *  but for one digest.
+ */
+extern SECStatus
+NSS_CMSDigestContext_FinishSingle(NSSCMSDigestContext *cmsdigcx, PLArenaPool *poolp,
+			    SECItem *digest);
+
+/************************************************************************
+ * 
+ ************************************************************************/
+
+/* shortcuts for basic use */
+
+/*
+ * NSS_CMSDEREncode - DER Encode a CMS message, with input being
+ *                    the plaintext message and derOut being the output,
+ *                    stored in arena's pool.
+ */
+extern SECStatus
+NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut, 
+                 PLArenaPool *arena);
+
+
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif /* _CMS_H_ */
diff --git a/mozilla/security/nss/lib/smime/cmslocal.h b/mozilla/security/nss/lib/smime/cmslocal.h
new file mode 100644
index 0000000..0e1c092
--- /dev/null
+++ b/mozilla/security/nss/lib/smime/cmslocal.h
@@ -0,0 +1,346 @@
+/* ***** 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 ***** */
+
+/*
+ * Support routines for CMS implementation, none of which are exported.
+ *
+ * Do not export this file!  If something in here is really needed outside
+ * of smime code, first try to add a CMS interface which will do it for
+ * you.  If that has a problem, then just move out what you need, changing
+ * its name as appropriate!
+ *
+ * $Id: cmslocal.h,v 1.5 2005/06/27 22:21:18 julien.pierre.bugs%sun.com Exp $
+ */
+
+#ifndef _CMSLOCAL_H_
+#define _CMSLOCAL_H_
+
+#include "cms.h"
+#include "cmsreclist.h"
+#include "secasn1t.h"
+
+extern const SEC_ASN1Template NSSCMSContentInfoTemplate[];
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/***********************************************************************
+ * cmscipher.c - en/decryption routines
+ ***********************************************************************/
+
+/*
+ * NSS_CMSCipherContext_StartDecrypt - create a cipher context to do decryption
+ * based on the given bulk * encryption key and algorithm identifier (which may include an iv).
+ */
+extern NSSCMSCipherContext *
+NSS_CMSCipherContext_StartDecrypt(PK11SymKey *key, SECAlgorithmID *algid);
+
+/*
+ * NSS_CMSCipherContext_StartEncrypt - create a cipher object to do encryption,
+ * based on the given bulk encryption key and algorithm tag.  Fill in the algorithm
+ * identifier (which may include an iv) appropriately.
+ */
+extern NSSCMSCipherContext *
+NSS_CMSCipherContext_StartEncrypt(PRArenaPool *poolp, PK11SymKey *key, SECAlgorithmID *algid);
+
+extern void
+NSS_CMSCipherContext_Destroy(NSSCMSCipherContext *cc);
+
+/*
+ * NSS_CMSCipherContext_DecryptLength - find the output length of the next call to decrypt.
+ *
+ * cc - the cipher context
+ * input_len - number of bytes used as input
+ * final - true if this is the final chunk of data
+ *
+ * Result can be used to perform memory allocations.  Note that the amount
+ * is exactly accurate only when not doing a block cipher or when final
+ * is false, otherwise it is an upper bound on the amount because until
+ * we see the data we do not know how many padding bytes there are
+ * (always between 1 and bsize).
+ */
+extern unsigned int
+NSS_CMSCipherContext_DecryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final);
+
+/*
+ * NSS_CMSCipherContext_EncryptLength - find the output length of the next call to encrypt.
+ *
+ * cc - the cipher context
+ * input_len - number of bytes used as input
+ * final - true if this is the final chunk of data
+ *
+ * Result can be used to perform memory allocations.
+ */
+extern unsigned int
+NSS_CMSCipherContext_EncryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final);
+
+/*
+ * NSS_CMSCipherContext_Decrypt - do the decryption
+ *
+ * cc - the cipher context
+ * output - buffer for decrypted result bytes
+ * output_len_p - number of bytes in output
+ * max_output_len - upper bound on bytes to put into output
+ * input - pointer to input bytes
+ * input_len - number of input bytes
+ * final - true if this is the final chunk of data
+ *
+ * Decrypts a given length of input buffer (starting at "input" and
+ * containing "input_len" bytes), placing the decrypted bytes in
+ * "output" and storing the output length in "*output_len_p".
+ * "cc" is the return value from NSS_CMSCipher_StartDecrypt.
+ * When "final" is true, this is the last of the data to be decrypted.
+ */ 
+extern SECStatus
+NSS_CMSCipherContext_Decrypt(NSSCMSCipherContext *cc, unsigned char *output,
+		  unsigned int *output_len_p, unsigned int max_output_len,
+		  const unsigned char *input, unsigned int input_len,
+		  PRBool final);
+
+/*
+ * NSS_CMSCipherContext_Encrypt - do the encryption
+ *
+ * cc - the cipher context
+ * output - buffer for decrypted result bytes
+ * output_len_p - number of bytes in output
+ * max_output_len - upper bound on bytes to put into output
+ * input - pointer to input bytes
+ * input_len - number of input bytes
+ * final - true if this is the final chunk of data
+ *
+ * Encrypts a given length of input buffer (starting at "input" and
+ * containing "input_len" bytes), placing the encrypted bytes in
+ * "output" and storing the output length in "*output_len_p".
+ * "cc" is the return value from NSS_CMSCipher_StartEncrypt.
+ * When "final" is true, this is the last of the data to be encrypted.
+ */ 
+extern SECStatus
+NSS_CMSCipherContext_Encrypt(NSSCMSCipherContext *cc, unsigned char *output,
+		  unsigned int *output_len_p, unsigned int max_output_len,
+		  const unsigned char *input, unsigned int input_len,
+		  PRBool final);
+
+/************************************************************************
+ * cmspubkey.c - public key operations
+ ************************************************************************/
+
+/*
+ * NSS_CMSUtil_EncryptSymKey_RSA - wrap a symmetric key with RSA
+ *
+ * this function takes a symmetric key and encrypts it using an RSA public key
+ * according to PKCS#1 and RFC2633 (S/MIME)
+ */
+extern SECStatus
+NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert,
+                              PK11SymKey *key,
+                              SECItem *encKey);
+
+extern SECStatus
+NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp,
+                                    SECKEYPublicKey *publickey,
+                                    PK11SymKey *bulkkey, SECItem *encKey);
+
+/*
+ * NSS_CMSUtil_DecryptSymKey_RSA - unwrap a RSA-wrapped symmetric key
+ *
+ * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
+ * key handle. Please note that the actual unwrapped key data may not be allowed to leave
+ * a hardware token...
+ */
+extern PK11SymKey *
+NSS_CMSUtil_DecryptSymKey_RSA(SECKEYPrivateKey *privkey, SECItem *encKey, SECOidTag bulkalgtag);
+
+extern SECStatus
+NSS_CMSUtil_EncryptSymKey_MISSI(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
+			SECOidTag symalgtag, SECItem *encKey, SECItem **pparams, void *pwfn_arg);
+
+extern PK11SymKey *
+NSS_CMSUtil_DecryptSymKey_MISSI(SECKEYPrivateKey *privkey, SECItem *encKey,
+			SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg);
+
+extern SECStatus
+NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
+			SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
+			SECItem *originatorPubKey);
+
+extern PK11SymKey *
+NSS_CMSUtil_DecryptSymKey_ESDH(SECKEYPrivateKey *privkey, SECItem *encKey,
+			SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg);
+
+/************************************************************************
+ * cmsreclist.c - recipient list stuff
+ ************************************************************************/
+extern NSSCMSRecipient **nss_cms_recipient_list_create(NSSCMSRecipientInfo **recipientinfos);
+extern void nss_cms_recipient_list_destroy(NSSCMSRecipient **recipient_list);
+extern NSSCMSRecipientEncryptedKey *NSS_CMSRecipientEncryptedKey_Create(PLArenaPool *poolp);
+
+/************************************************************************
+ * cmsarray.c - misc array functions
+ ************************************************************************/
+/*
+ * NSS_CMSArray_Alloc - allocate an array in an arena
+ */
+extern void **
+NSS_CMSArray_Alloc(PRArenaPool *poolp, int n);
+
+/*
+ * NSS_CMSArray_Add - add an element to the end of an array
+ */
+extern SECStatus
+NSS_CMSArray_Add(PRArenaPool *poolp, void ***array, void *obj);
+
+/*
+ * NSS_CMSArray_IsEmpty - check if array is empty
+ */
+extern PRBool
+NSS_CMSArray_IsEmpty(void **array);
+
+/*
+ * NSS_CMSArray_Count - count number of elements in array
+ */
+extern int
+NSS_CMSArray_Count(void **array);
+
+/*
+ * NSS_CMSArray_Sort - sort an array ascending, in place
+ *
+ * If "secondary" is not NULL, the same reordering gets applied to it.
+ * If "tertiary" is not NULL, the same reordering gets applied to it.
+ * "compare" is a function that returns 
+ *  < 0 when the first element is less than the second
+ *  = 0 when the first element is equal to the second
+ *  > 0 when the first element is greater than the second
+ */
+extern void
+NSS_CMSArray_Sort(void **primary, int (*compare)(void *,void *), void **secondary, void **tertiary);
+
+/************************************************************************
+ * cmsattr.c - misc attribute functions
+ ************************************************************************/
+/*
+ * NSS_CMSAttribute_Create - create an attribute
+ *
+ * if value is NULL, the attribute won't have a value. It can be added later
+ * with NSS_CMSAttribute_AddValue.
+ */
+extern NSSCMSAttribute *
+NSS_CMSAttribute_Create(PRArenaPool *poolp, SECOidTag oidtag, SECItem *value, PRBool encoded);
+
+/*
+ * NSS_CMSAttribute_AddValue - add another value to an attribute
+ */
+extern SECStatus
+NSS_CMSAttribute_AddValue(PLArenaPool *poolp, NSSCMSAttribute *attr, SECItem *value);
+
+/*
+ * NSS_CMSAttribute_GetType - return the OID tag
+ */
+extern SECOidTag
+NSS_CMSAttribute_GetType(NSSCMSAttribute *attr);
+
+/*
+ * NSS_CMSAttribute_GetValue - return the first attribute value
+ *
+ * We do some sanity checking first:
+ * - Multiple values are *not* expected.
+ * - Empty values are *not* expected.
+ */
+extern SECItem *
+NSS_CMSAttribute_GetValue(NSSCMSAttribute *attr);
+
+/*
+ * NSS_CMSAttribute_CompareValue - compare the attribute's first value against data
+ */
+extern PRBool
+NSS_CMSAttribute_CompareValue(NSSCMSAttribute *attr, SECItem *av);
+
+/*
+ * NSS_CMSAttributeArray_Encode - encode an Attribute array as SET OF Attributes
+ *
+ * If you are wondering why this routine does not reorder the attributes
+ * first, and might be tempted to make it do so, see the comment by the
+ * call to ReorderAttributes in cmsencode.c.  (Or, see who else calls this
+ * and think long and hard about the implications of making it always
+ * do the reordering.)
+ */
+extern SECItem *
+NSS_CMSAttributeArray_Encode(PRArenaPool *poolp, NSSCMSAttribute ***attrs, SECItem *dest);
+
+/*
+ * NSS_CMSAttributeArray_Reorder - sort attribute array by attribute's DER encoding
+ *
+ * make sure that the order of the attributes guarantees valid DER (which must be
+ * in lexigraphically ascending order for a SET OF); if reordering is necessary it
+ * will be done in place (in attrs).
+ */
+extern SECStatus
+NSS_CMSAttributeArray_Reorder(NSSCMSAttribute **attrs);
+
+/*
+ * NSS_CMSAttributeArray_FindAttrByOidTag - look through a set of attributes and
+ * find one that matches the specified object ID.
+ *
+ * If "only" is true, then make sure that there is not more than one attribute
+ * of the same type.  Otherwise, just return the first one found. (XXX Does
+ * anybody really want that first-found behavior?  It was like that when I found it...)
+ */
+extern NSSCMSAttribute *
+NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only);
+
+/*
+ * NSS_CMSAttributeArray_AddAttr - add an attribute to an
+ * array of attributes. 
+ */
+extern SECStatus
+NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr);
+
+/*
+ * NSS_CMSAttributeArray_SetAttr - set an attribute's value in a set of attributes
+ */
+extern SECStatus
+NSS_CMSAttributeArray_SetAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, SECOidTag type, SECItem *value, PRBool encoded);
+
+/*
+ * NSS_CMSSignedData_AddTempCertificate - add temporary certificate references.
+ * They may be needed for signature verification on the data, for example.
+ */
+extern SECStatus
+NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert);
+
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif /* _CMSLOCAL_H_ */
diff --git a/mozilla/security/nss/lib/smime/cmsreclist.h b/mozilla/security/nss/lib/smime/cmsreclist.h
new file mode 100644
index 0000000..00e89b5
--- /dev/null
+++ b/mozilla/security/nss/lib/smime/cmsreclist.h
@@ -0,0 +1,62 @@
+/* ***** 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 ***** */
+
+/*
+ * $Id: cmsreclist.h,v 1.4 2004/04/25 15:03:16 gerv%gerv.net Exp $
+ */
+
+#ifndef _CMSRECLIST_H
+#define _CMSRECLIST_H
+
+struct NSSCMSRecipientStr {
+    int				riIndex;	/* this recipient's index in recipientInfo array */
+    int				subIndex;	/* index into recipientEncryptedKeys */
+						/* (only in NSSCMSKeyAgreeRecipientInfoStr) */
+    enum {RLIssuerSN=0, RLSubjKeyID=1} kind;	/* for conversion recipientinfos -> recipientlist */
+    union {
+	CERTIssuerAndSN *	issuerAndSN;
+	SECItem *		subjectKeyID;
+    } id;
+
+    /* result data (filled out for each recipient that's us) */
+    CERTCertificate *		cert;
+    SECKEYPrivateKey *		privkey;
+    PK11SlotInfo *		slot;
+};
+
+typedef struct NSSCMSRecipientStr NSSCMSRecipient;
+
+#endif /* _CMSRECLIST_H */
diff --git a/mozilla/security/nss/lib/smime/cmst.h b/mozilla/security/nss/lib/smime/cmst.h
new file mode 100644
index 0000000..b5de52b
--- /dev/null
+++ b/mozilla/security/nss/lib/smime/cmst.h
@@ -0,0 +1,534 @@
+/* ***** 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 ***** */
+
+/*
+ * Header for CMS types.
+ *
+ * $Id: cmst.h,v 1.10 2005/06/27 22:21:19 julien.pierre.bugs%sun.com Exp $
+ */
+
+#ifndef _CMST_H_
+#define _CMST_H_
+
+#include "seccomon.h"
+#include "secoidt.h"
+#include "certt.h"
+#include "secmodt.h"
+#include "secmodt.h"
+
+#include "plarena.h"
+
+/* Non-opaque objects.  NOTE, though: I want them to be treated as
+ * opaque as much as possible.  If I could hide them completely,
+ * I would.  (I tried, but ran into trouble that was taking me too
+ * much time to get out of.)  I still intend to try to do so.
+ * In fact, the only type that "outsiders" should even *name* is
+ * NSSCMSMessage, and they should not reference its fields.
+ */
+/* rjr: PKCS #11 cert handling (pk11cert.c) does use NSSCMSRecipientInfo's.
+ * This is because when we search the recipient list for the cert and key we
+ * want, we need to invert the order of the loops we used to have. The old
+ * loops were:
+ *
+ *  For each recipient {
+ *       find_cert = PK11_Find_AllCert(recipient->issuerSN);
+ *       [which unrolls to... ]
+ *       For each slot {
+ *            Log into slot;
+ *            search slot for cert;
+ *      }
+ *  }
+ *
+ *  the new loop searchs all the recipients at once on a slot. this allows
+ *  PKCS #11 to order slots in such a way that logout slots don't get checked
+ *  if we can find the cert on a logged in slot. This eliminates lots of
+ *  spurious password prompts when smart cards are installed... so why this
+ *  comment? If you make NSSCMSRecipientInfo completely opaque, you need
+ *  to provide a non-opaque list of issuerSN's (the only field PKCS#11 needs
+ *  and fix up pk11cert.c first. NOTE: Only S/MIME calls this special PKCS #11
+ *  function.
+ */
+
+typedef struct NSSCMSMessageStr NSSCMSMessage;
+
+typedef union NSSCMSContentUnion NSSCMSContent;
+typedef struct NSSCMSContentInfoStr NSSCMSContentInfo;
+
+typedef struct NSSCMSSignedDataStr NSSCMSSignedData;
+typedef struct NSSCMSSignerInfoStr NSSCMSSignerInfo;
+typedef struct NSSCMSSignerIdentifierStr NSSCMSSignerIdentifier;
+
+typedef struct NSSCMSEnvelopedDataStr NSSCMSEnvelopedData;
+typedef struct NSSCMSOriginatorInfoStr NSSCMSOriginatorInfo;
+typedef struct NSSCMSRecipientInfoStr NSSCMSRecipientInfo;
+
+typedef struct NSSCMSDigestedDataStr NSSCMSDigestedData;
+typedef struct NSSCMSEncryptedDataStr NSSCMSEncryptedData;
+
+typedef struct NSSCMSSMIMEKEAParametersStr NSSCMSSMIMEKEAParameters;
+
+typedef struct NSSCMSAttributeStr NSSCMSAttribute;
+
+typedef struct NSSCMSDecoderContextStr NSSCMSDecoderContext;
+typedef struct NSSCMSEncoderContextStr NSSCMSEncoderContext;
+
+typedef struct NSSCMSCipherContextStr NSSCMSCipherContext;
+typedef struct NSSCMSDigestContextStr NSSCMSDigestContext;
+
+/*
+ * Type of function passed to NSSCMSDecode or NSSCMSDecoderStart.
+ * If specified, this is where the content bytes (only) will be "sent"
+ * as they are recovered during the decoding.
+ * And:
+ * Type of function passed to NSSCMSEncode or NSSCMSEncoderStart.
+ * This is where the DER-encoded bytes will be "sent".
+ *
+ * XXX Should just combine this with NSSCMSEncoderContentCallback type
+ * and use a simpler, common name.
+ */
+typedef void (*NSSCMSContentCallback)(void *arg, const char *buf, unsigned long len);
+
+/*
+ * Type of function passed to NSSCMSDecode or NSSCMSDecoderStart
+ * to retrieve the decryption key.  This function is intended to be
+ * used for EncryptedData content info's which do not have a key available
+ * in a certificate, etc.
+ */
+typedef PK11SymKey *(*NSSCMSGetDecryptKeyCallback)(void *arg, SECAlgorithmID *algid);
+
+
+/* =============================================================================
+ * ENCAPSULATED CONTENTINFO & CONTENTINFO
+ */
+
+union NSSCMSContentUnion {
+    /* either unstructured */
+    SECItem *			data;
+    /* or structured data */
+    NSSCMSDigestedData *	digestedData;
+    NSSCMSEncryptedData	*	encryptedData;
+    NSSCMSEnvelopedData	*	envelopedData;
+    NSSCMSSignedData *		signedData;
+    /* or anonymous pointer to something */
+    void *			pointer;
+};
+
+struct NSSCMSContentInfoStr {
+    SECItem			contentType;
+    NSSCMSContent		content;
+    /* --------- local; not part of encoding --------- */
+    SECOidData *		contentTypeTag;	
+
+    /* additional info for encryptedData and envelopedData */
+    /* we waste this space for signedData and digestedData. sue me. */
+
+    SECAlgorithmID		contentEncAlg;
+    SECItem *			rawContent;		/* encrypted DER, optional */
+							/* XXXX bytes not encrypted, but encoded? */
+    /* --------- local; not part of encoding --------- */
+    PK11SymKey *		bulkkey;		/* bulk encryption key */
+    int				keysize;		/* size of bulk encryption key
+							 * (only used by creation code) */
+    SECOidTag			contentEncAlgTag;	/* oid tag of encryption algorithm
+							 * (only used by creation code) */
+    NSSCMSCipherContext		*ciphcx;		/* context for en/decryption going on */
+    NSSCMSDigestContext		*digcx;			/* context for digesting going on */
+};
+
+/* =============================================================================
+ * MESSAGE
+ */
+
+struct NSSCMSMessageStr {
+    NSSCMSContentInfo	contentInfo;		/* "outer" cinfo */
+    /* --------- local; not part of encoding --------- */
+    PLArenaPool *	poolp;
+    PRBool		poolp_is_ours;
+    int			refCount;
+    /* properties of the "inner" data */
+    SECAlgorithmID **	detached_digestalgs;
+    SECItem **		detached_digests;
+    void *		pwfn_arg;
+    NSSCMSGetDecryptKeyCallback decrypt_key_cb;
+    void *		decrypt_key_cb_arg;
+};
+
+/* =============================================================================
+ * SIGNEDDATA
+ */
+
+struct NSSCMSSignedDataStr {
+    SECItem			version;
+    SECAlgorithmID **		digestAlgorithms;
+    NSSCMSContentInfo		contentInfo;
+    SECItem **			rawCerts;
+    CERTSignedCrl **		crls;
+    NSSCMSSignerInfo **		signerInfos;
+    /* --------- local; not part of encoding --------- */
+    NSSCMSMessage *		cmsg;			/* back pointer to message */
+    SECItem **			digests;
+    CERTCertificate **		certs;
+    CERTCertificateList **	certLists;
+    CERTCertificate **          tempCerts;              /* temporary certs, needed
+                                                         * for example for signature
+                                                         * verification */
+};
+#define NSS_CMS_SIGNED_DATA_VERSION_BASIC	1	/* what we *create* */
+#define NSS_CMS_SIGNED_DATA_VERSION_EXT		3	/* what we *create* */
+
+typedef enum {
+    NSSCMSVS_Unverified = 0,
+    NSSCMSVS_GoodSignature = 1,
+    NSSCMSVS_BadSignature = 2,
+    NSSCMSVS_DigestMismatch = 3,
+    NSSCMSVS_SigningCertNotFound = 4,
+    NSSCMSVS_SigningCertNotTrusted = 5,
+    NSSCMSVS_SignatureAlgorithmUnknown = 6,
+    NSSCMSVS_SignatureAlgorithmUnsupported = 7,
+    NSSCMSVS_MalformedSignature = 8,
+    NSSCMSVS_ProcessingError = 9
+} NSSCMSVerificationStatus;
+
+typedef enum {
+    NSSCMSSignerID_IssuerSN = 0,
+    NSSCMSSignerID_SubjectKeyID = 1
+} NSSCMSSignerIDSelector;
+
+struct NSSCMSSignerIdentifierStr {
+    NSSCMSSignerIDSelector identifierType;
+    union {
+	CERTIssuerAndSN *issuerAndSN;
+	SECItem *subjectKeyID;
+    } id;
+};
+
+struct NSSCMSSignerInfoStr {
+    SECItem			version;
+    NSSCMSSignerIdentifier	signerIdentifier;
+    SECAlgorithmID		digestAlg;
+    NSSCMSAttribute **		authAttr;
+    SECAlgorithmID		digestEncAlg;
+    SECItem			encDigest;
+    NSSCMSAttribute **		unAuthAttr;
+    /* --------- local; not part of encoding --------- */
+    NSSCMSMessage *		cmsg;			/* back pointer to message */
+    CERTCertificate *		cert;
+    CERTCertificateList *	certList;
+    PRTime			signingTime;
+    NSSCMSVerificationStatus	verificationStatus;
+    SECKEYPrivateKey *          signingKey; /* Used if we're using subjKeyID*/
+    SECKEYPublicKey *           pubKey;
+};
+#define NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN	1	/* what we *create* */
+#define NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY	3	/* what we *create* */
+
+typedef enum {
+    NSSCMSCM_None = 0,
+    NSSCMSCM_CertOnly = 1,
+    NSSCMSCM_CertChain = 2,
+    NSSCMSCM_CertChainWithRoot = 3
+} NSSCMSCertChainMode;
+
+/* =============================================================================
+ * ENVELOPED DATA
+ */
+struct NSSCMSEnvelopedDataStr {
+    SECItem			version;
+    NSSCMSOriginatorInfo *	originatorInfo;		/* optional */
+    NSSCMSRecipientInfo **	recipientInfos;
+    NSSCMSContentInfo		contentInfo;
+    NSSCMSAttribute **		unprotectedAttr;
+    /* --------- local; not part of encoding --------- */
+    NSSCMSMessage *		cmsg;			/* back pointer to message */
+};
+#define NSS_CMS_ENVELOPED_DATA_VERSION_REG	0	/* what we *create* */
+#define NSS_CMS_ENVELOPED_DATA_VERSION_ADV	2	/* what we *create* */
+
+struct NSSCMSOriginatorInfoStr {
+    SECItem **			rawCerts;
+    CERTSignedCrl **		crls;
+    /* --------- local; not part of encoding --------- */
+    CERTCertificate **		certs;
+};
+
+/* -----------------------------------------------------------------------------
+ * key transport recipient info
+ */
+typedef enum {
+    NSSCMSRecipientID_IssuerSN = 0,
+    NSSCMSRecipientID_SubjectKeyID = 1,
+    NSSCMSRecipientID_BrandNew = 2
+} NSSCMSRecipientIDSelector;
+
+struct NSSCMSRecipientIdentifierStr {
+    NSSCMSRecipientIDSelector	identifierType;
+    union {
+	CERTIssuerAndSN		*issuerAndSN;
+	SECItem 		*subjectKeyID;
+    } id;
+};
+typedef struct NSSCMSRecipientIdentifierStr NSSCMSRecipientIdentifier;
+
+struct NSSCMSKeyTransRecipientInfoStr {
+    SECItem			version;
+    NSSCMSRecipientIdentifier	recipientIdentifier;
+    SECAlgorithmID		keyEncAlg;
+    SECItem			encKey;
+};
+typedef struct NSSCMSKeyTransRecipientInfoStr NSSCMSKeyTransRecipientInfo;
+
+/*
+ * View comments before NSSCMSRecipientInfoStr for purpose of this
+ * structure.
+ */
+struct NSSCMSKeyTransRecipientInfoExStr {
+    NSSCMSKeyTransRecipientInfo recipientInfo;
+    int version;  /* version of this structure (0) */
+    SECKEYPublicKey *pubKey;
+};
+
+typedef struct NSSCMSKeyTransRecipientInfoExStr NSSCMSKeyTransRecipientInfoEx;
+
+#define NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN	0	/* what we *create* */
+#define NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY		2	/* what we *create* */
+
+/* -----------------------------------------------------------------------------
+ * key agreement recipient info
+ */
+struct NSSCMSOriginatorPublicKeyStr {
+    SECAlgorithmID			algorithmIdentifier;
+    SECItem				publicKey;			/* bit string! */
+};
+typedef struct NSSCMSOriginatorPublicKeyStr NSSCMSOriginatorPublicKey;
+
+typedef enum {
+    NSSCMSOriginatorIDOrKey_IssuerSN = 0,
+    NSSCMSOriginatorIDOrKey_SubjectKeyID = 1,
+    NSSCMSOriginatorIDOrKey_OriginatorPublicKey = 2
+} NSSCMSOriginatorIDOrKeySelector;
+
+struct NSSCMSOriginatorIdentifierOrKeyStr {
+    NSSCMSOriginatorIDOrKeySelector identifierType;
+    union {
+	CERTIssuerAndSN			*issuerAndSN;		/* static-static */
+	SECItem				*subjectKeyID;		/* static-static */
+	NSSCMSOriginatorPublicKey	originatorPublicKey;	/* ephemeral-static */
+    } id;
+};
+typedef struct NSSCMSOriginatorIdentifierOrKeyStr NSSCMSOriginatorIdentifierOrKey;
+
+struct NSSCMSRecipientKeyIdentifierStr {
+    SECItem *				subjectKeyIdentifier;
+    SECItem *				date;			/* optional */
+    SECItem *				other;			/* optional */
+};
+typedef struct NSSCMSRecipientKeyIdentifierStr NSSCMSRecipientKeyIdentifier;
+
+typedef enum {
+    NSSCMSKeyAgreeRecipientID_IssuerSN = 0,
+    NSSCMSKeyAgreeRecipientID_RKeyID = 1
+} NSSCMSKeyAgreeRecipientIDSelector;
+
+struct NSSCMSKeyAgreeRecipientIdentifierStr {
+    NSSCMSKeyAgreeRecipientIDSelector	identifierType;
+    union {
+	CERTIssuerAndSN			*issuerAndSN;
+	NSSCMSRecipientKeyIdentifier	recipientKeyIdentifier;
+    } id;
+};
+typedef struct NSSCMSKeyAgreeRecipientIdentifierStr NSSCMSKeyAgreeRecipientIdentifier;
+
+struct NSSCMSRecipientEncryptedKeyStr {
+    NSSCMSKeyAgreeRecipientIdentifier	recipientIdentifier;
+    SECItem				encKey;
+};
+typedef struct NSSCMSRecipientEncryptedKeyStr NSSCMSRecipientEncryptedKey;
+
+struct NSSCMSKeyAgreeRecipientInfoStr {
+    SECItem				version;
+    NSSCMSOriginatorIdentifierOrKey	originatorIdentifierOrKey;
+    SECItem *				ukm;				/* optional */
+    SECAlgorithmID			keyEncAlg;
+    NSSCMSRecipientEncryptedKey **	recipientEncryptedKeys;
+};
+typedef struct NSSCMSKeyAgreeRecipientInfoStr NSSCMSKeyAgreeRecipientInfo;
+
+#define NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION	3	/* what we *create* */
+
+/* -----------------------------------------------------------------------------
+ * KEK recipient info
+ */
+struct NSSCMSKEKIdentifierStr {
+    SECItem			keyIdentifier;
+    SECItem *			date;			/* optional */
+    SECItem *			other;			/* optional */
+};
+typedef struct NSSCMSKEKIdentifierStr NSSCMSKEKIdentifier;
+
+struct NSSCMSKEKRecipientInfoStr {
+    SECItem			version;
+    NSSCMSKEKIdentifier		kekIdentifier;
+    SECAlgorithmID		keyEncAlg;
+    SECItem			encKey;
+};
+typedef struct NSSCMSKEKRecipientInfoStr NSSCMSKEKRecipientInfo;
+
+#define NSS_CMS_KEK_RECIPIENT_INFO_VERSION	4	/* what we *create* */
+
+/* -----------------------------------------------------------------------------
+ * recipient info
+ */
+
+typedef enum {
+    NSSCMSRecipientInfoID_KeyTrans = 0,
+    NSSCMSRecipientInfoID_KeyAgree = 1,
+    NSSCMSRecipientInfoID_KEK = 2
+} NSSCMSRecipientInfoIDSelector;
+
+/*
+ * In order to preserve backwards binary compatibility when implementing
+ * creation of Recipient Info's that uses subjectKeyID in the 
+ * keyTransRecipientInfo we need to stash a public key pointer in this
+ * structure somewhere.  We figured out that NSSCMSKeyTransRecipientInfo
+ * is the smallest member of the ri union.  We're in luck since that's
+ * the very structure that would need to use the public key. So we created
+ * a new structure NSSCMSKeyTransRecipientInfoEx which has a member 
+ * NSSCMSKeyTransRecipientInfo as the first member followed by a version
+ * and a public key pointer.  This way we can keep backwards compatibility
+ * without changing the size of this structure.
+ *
+ * BTW, size of structure:
+ * NSSCMSKeyTransRecipientInfo:  9 ints, 4 pointers
+ * NSSCMSKeyAgreeRecipientInfo: 12 ints, 8 pointers
+ * NSSCMSKEKRecipientInfo:      10 ints, 7 pointers
+ *
+ * The new structure:
+ * NSSCMSKeyTransRecipientInfoEx: sizeof(NSSCMSKeyTransRecipientInfo) +
+ *                                1 int, 1 pointer
+ */
+
+struct NSSCMSRecipientInfoStr {
+    NSSCMSRecipientInfoIDSelector recipientInfoType;
+    union {
+	NSSCMSKeyTransRecipientInfo keyTransRecipientInfo;
+	NSSCMSKeyAgreeRecipientInfo keyAgreeRecipientInfo;
+	NSSCMSKEKRecipientInfo kekRecipientInfo;
+	NSSCMSKeyTransRecipientInfoEx keyTransRecipientInfoEx;
+    } ri;
+    /* --------- local; not part of encoding --------- */
+    NSSCMSMessage *		cmsg;			/* back pointer to message */
+    CERTCertificate *		cert;			/* recipient's certificate */
+};
+
+/* =============================================================================
+ * DIGESTED DATA
+ */
+struct NSSCMSDigestedDataStr {
+    SECItem			version;
+    SECAlgorithmID		digestAlg;
+    NSSCMSContentInfo		contentInfo;
+    SECItem			digest;
+    /* --------- local; not part of encoding --------- */
+    NSSCMSMessage *		cmsg;		/* back pointer */
+    SECItem			cdigest;	/* calculated digest */
+};
+#define NSS_CMS_DIGESTED_DATA_VERSION_DATA	0	/* what we *create* */
+#define NSS_CMS_DIGESTED_DATA_VERSION_ENCAP	2	/* what we *create* */
+
+/* =============================================================================
+ * ENCRYPTED DATA
+ */
+struct NSSCMSEncryptedDataStr {
+    SECItem			version;
+    NSSCMSContentInfo		contentInfo;
+    NSSCMSAttribute **		unprotectedAttr;	/* optional */
+    /* --------- local; not part of encoding --------- */
+    NSSCMSMessage *		cmsg;		/* back pointer */
+};
+#define NSS_CMS_ENCRYPTED_DATA_VERSION		0	/* what we *create* */
+#define NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR	2	/* what we *create* */
+
+/* =============================================================================
+ * FORTEZZA KEA
+ */
+
+/* An enumerated type used to select templates based on the encryption
+   scenario and data specifics. */
+typedef enum {
+    NSSCMSKEAInvalid = -1,
+    NSSCMSKEAUsesSkipjack = 0,
+    NSSCMSKEAUsesNonSkipjack = 1,
+    NSSCMSKEAUsesNonSkipjackWithPaddedEncKey = 2
+} NSSCMSKEATemplateSelector;
+
+/* ### mwelch - S/MIME KEA parameters. These don't really fit here,
+                but I cannot think of a more appropriate place at this time. */
+struct NSSCMSSMIMEKEAParametersStr {
+    SECItem originatorKEAKey;	/* sender KEA key (encrypted?) */
+    SECItem originatorRA;	/* random number generated by sender */
+    SECItem nonSkipjackIV;	/* init'n vector for SkipjackCBC64
+			           decryption of KEA key if Skipjack
+				   is not the bulk algorithm used on
+				   the message */
+    SECItem bulkKeySize;	/* if Skipjack is not the bulk
+			           algorithm used on the message,
+				   and the size of the bulk encryption
+				   key is not the same as that of
+				   originatorKEAKey (due to padding
+				   perhaps), this field will contain
+				   the real size of the bulk encryption
+				   key. */
+};
+
+/*
+ * *****************************************************************************
+ * *****************************************************************************
+ * *****************************************************************************
+ */
+
+/*
+ * See comment above about this type not really belonging to CMS.
+ */
+struct NSSCMSAttributeStr {
+    /* The following fields make up an encoded Attribute: */
+    SECItem			type;
+    SECItem **			values;	/* data may or may not be encoded */
+    /* The following fields are not part of an encoded Attribute: */
+    SECOidData *		typeTag;
+    PRBool			encoded;	/* when true, values are encoded */
+};
+
+#endif /* _CMST_H_ */
diff --git a/mozilla/security/nss/lib/smime/smime.h b/mozilla/security/nss/lib/smime/smime.h
new file mode 100644
index 0000000..d7fbc8c
--- /dev/null
+++ b/mozilla/security/nss/lib/smime/smime.h
@@ -0,0 +1,156 @@
+/* ***** 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 ***** */
+
+/*
+ * Header file for routines specific to S/MIME.  Keep things that are pure
+ * pkcs7 out of here; this is for S/MIME policy, S/MIME interoperability, etc.
+ *
+ * $Id: smime.h,v 1.8 2004/04/25 15:03:16 gerv%gerv.net Exp $
+ */
+
+#ifndef _SECMIME_H_
+#define _SECMIME_H_ 1
+
+#include "cms.h"
+
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/*
+ * Initialize the local recording of the user S/MIME cipher preferences.
+ * This function is called once for each cipher, the order being
+ * important (first call records greatest preference, and so on).
+ * When finished, it is called with a "which" of CIPHER_FAMILID_MASK.
+ * If the function is called again after that, it is assumed that
+ * the preferences are being reset, and the old preferences are
+ * discarded.
+ *
+ * XXX This is for a particular user, and right now the storage is
+ * XXX local, static.  The preference should be stored elsewhere to allow
+ * XXX for multiple uses of one library?  How does SSL handle this;
+ * XXX it has something similar?
+ *
+ *  - The "which" values are defined in ciferfam.h (the SMIME_* values,
+ *    for example SMIME_DES_CBC_56).
+ *  - If "on" is non-zero then the named cipher is enabled, otherwise
+ *    it is disabled.  (It is not necessary to call the function for
+ *    ciphers that are disabled, however, as that is the default.)
+ *
+ * If the cipher preference is successfully recorded, SECSuccess
+ * is returned.  Otherwise SECFailure is returned.  The only errors
+ * are due to failure allocating memory or bad parameters/calls:
+ *	SEC_ERROR_XXX ("which" is not in the S/MIME cipher family)
+ *	SEC_ERROR_XXX (function is being called more times than there
+ *		are known/expected ciphers)
+ */
+extern SECStatus NSS_SMIMEUtil_EnableCipher(long which, int on);
+
+/*
+ * Initialize the local recording of the S/MIME policy.
+ * This function is called to allow/disallow a particular cipher.
+ *
+ * XXX This is for a the current module, I think, so local, static storage
+ * XXX is okay.  Is that correct, or could multiple uses of the same
+ * XXX library expect to operate under different policies?
+ *
+ *  - The "which" values are defined in ciferfam.h (the SMIME_* values,
+ *    for example SMIME_DES_CBC_56).
+ *  - If "on" is non-zero then the named cipher is enabled, otherwise
+ *    it is disabled.
+ */
+extern SECStatus NSS_SMIMEUtils_AllowCipher(long which, int on);
+
+/*
+ * Does the current policy allow S/MIME decryption of this particular
+ * algorithm and keysize?
+ */
+extern PRBool NSS_SMIMEUtil_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key);
+
+/*
+ * Does the current policy allow *any* S/MIME encryption (or decryption)?
+ *
+ * This tells whether or not *any* S/MIME encryption can be done,
+ * according to policy.  Callers may use this to do nicer user interface
+ * (say, greying out a checkbox so a user does not even try to encrypt
+ * a message when they are not allowed to) or for any reason they want
+ * to check whether S/MIME encryption (or decryption, for that matter)
+ * may be done.
+ *
+ * It takes no arguments.  The return value is a simple boolean:
+ *   PR_TRUE means encryption (or decryption) is *possible*
+ *	(but may still fail due to other reasons, like because we cannot
+ *	find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
+ *   PR_FALSE means encryption (or decryption) is not permitted
+ *
+ * There are no errors from this routine.
+ */
+extern PRBool NSS_SMIMEUtil_EncryptionPossible(void);
+
+/*
+ * NSS_SMIMEUtil_CreateSMIMECapabilities - get S/MIME capabilities attr value
+ *
+ * scans the list of allowed and enabled ciphers and construct a PKCS9-compliant
+ * S/MIME capabilities attribute value.
+ */
+extern SECStatus NSS_SMIMEUtil_CreateSMIMECapabilities(PLArenaPool *poolp, SECItem *dest, PRBool includeFortezzaCiphers);
+
+/*
+ * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferences attr value
+ */
+extern SECStatus NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCertificate *cert);
+
+/*
+ * NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs - create S/MIME encryption key preferences attr value using MS oid
+ */
+extern SECStatus NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCertificate *cert);
+
+/*
+ * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference - find cert marked by EncryptionKeyPreference
+ *          attribute
+ */
+extern CERTCertificate *NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(CERTCertDBHandle *certdb, SECItem *DERekp);
+
+/*
+ * NSS_SMIMEUtil_FindBulkAlgForRecipients - find bulk algorithm suitable for all recipients
+ */
+extern SECStatus
+NSS_SMIMEUtil_FindBulkAlgForRecipients(CERTCertificate **rcerts, SECOidTag *bulkalgtag, int *keysize);
+
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif /* _SECMIME_H_ */
diff --git a/mozilla/security/nss/lib/softoken/ecdecode.c b/mozilla/security/nss/lib/softoken/ecdecode.c
new file mode 100644
index 0000000..c037dc5
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/ecdecode.c
@@ -0,0 +1,641 @@
+/*
+ * ***** 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 Elliptic Curve Cryptography library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifdef NSS_ENABLE_ECC
+
+#include "blapi.h"
+#include "secoid.h"
+#include "secitem.h"
+#include "secerr.h"
+#include "ec.h"
+#include "ecl-curve.h"
+
+#define CHECK_OK(func) if (func == NULL) goto cleanup
+#define CHECK_SEC_OK(func) if (SECSuccess != (rv = func)) goto cleanup
+
+/*
+ * Initializes a SECItem from a hexadecimal string
+ *
+ * Warning: This function ignores leading 00's, so any leading 00's
+ * in the hexadecimal string must be optional.
+ */
+static SECItem *
+hexString2SECItem(PRArenaPool *arena, SECItem *item, const char *str)
+{
+    int i = 0;
+    int byteval = 0;
+    int tmp = PORT_Strlen(str);
+
+    if ((tmp % 2) != 0) return NULL;
+    
+    /* skip leading 00's unless the hex string is "00" */
+    while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) {
+        str += 2;
+        tmp -= 2;
+    }
+
+    item->data = (unsigned char *) PORT_ArenaAlloc(arena, tmp/2);
+    if (item->data == NULL) return NULL;
+    item->len = tmp/2;
+
+    while (str[i]) {
+        if ((str[i] >= '0') && (str[i] <= '9'))
+	    tmp = str[i] - '0';
+	else if ((str[i] >= 'a') && (str[i] <= 'f'))
+	    tmp = str[i] - 'a' + 10;
+	else if ((str[i] >= 'A') && (str[i] <= 'F'))
+	    tmp = str[i] - 'A' + 10;
+	else
+	    return NULL;
+
+	byteval = byteval * 16 + tmp;
+	if ((i % 2) != 0) {
+	    item->data[i/2] = byteval;
+	    byteval = 0;
+	}
+	i++;
+    }
+
+    return item;
+}
+
+/* Copy all of the fields from srcParams into dstParams
+ */
+SECStatus
+EC_CopyParams(PRArenaPool *arena, ECParams *dstParams,
+	      const ECParams *srcParams)
+{
+    SECStatus rv = SECFailure;
+
+    dstParams->arena = arena;
+    dstParams->type = srcParams->type;
+    dstParams->fieldID.size = srcParams->fieldID.size;
+    dstParams->fieldID.type = srcParams->fieldID.type;
+    if (srcParams->fieldID.type == ec_field_GFp) {
+	CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.prime,
+	    &srcParams->fieldID.u.prime));
+    } else {
+	CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.poly,
+	    &srcParams->fieldID.u.poly));
+    }
+    dstParams->fieldID.k1 = srcParams->fieldID.k1;
+    dstParams->fieldID.k2 = srcParams->fieldID.k2;
+    dstParams->fieldID.k3 = srcParams->fieldID.k3;
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.a,
+	&srcParams->curve.a));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.b,
+	&srcParams->curve.b));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.seed,
+	&srcParams->curve.seed));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->base,
+	&srcParams->base));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->order,
+	&srcParams->order));
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->DEREncoding,
+	&srcParams->DEREncoding));
+	dstParams->name = srcParams->name;
+    CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curveOID,
+ 	&srcParams->curveOID));
+    dstParams->cofactor = srcParams->cofactor;
+
+    return SECSuccess;
+
+cleanup:
+    return SECFailure;
+}
+
+static SECStatus
+gf_populate_params(ECCurveName name, ECFieldType field_type, ECParams *params)
+{
+    SECStatus rv = SECFailure;
+    const ECCurveParams *curveParams;
+    /* 2 ['0'+'4'] + MAX_ECKEY_LEN * 2 [x,y] * 2 [hex string] + 1 ['\0'] */
+    char genenc[3 + 2 * 2 * MAX_ECKEY_LEN];
+
+    if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve)) goto cleanup;
+    params->name = name;
+    curveParams = ecCurve_map[params->name];
+    CHECK_OK(curveParams);
+    params->fieldID.size = curveParams->size;
+    params->fieldID.type = field_type;
+    if (field_type == ec_field_GFp) {
+	CHECK_OK(hexString2SECItem(params->arena, &params->fieldID.u.prime, 
+	    curveParams->irr));
+    } else {
+	CHECK_OK(hexString2SECItem(params->arena, &params->fieldID.u.poly, 
+	    curveParams->irr));
+    }
+    CHECK_OK(hexString2SECItem(params->arena, &params->curve.a, 
+	curveParams->curvea));
+    CHECK_OK(hexString2SECItem(params->arena, &params->curve.b, 
+	curveParams->curveb));
+    genenc[0] = '0';
+    genenc[1] = '4';
+    genenc[2] = '\0';
+    strcat(genenc, curveParams->genx);
+    strcat(genenc, curveParams->geny);
+    CHECK_OK(hexString2SECItem(params->arena, &params->base, genenc));
+    CHECK_OK(hexString2SECItem(params->arena, &params->order, 
+    	curveParams->order));
+    params->cofactor = curveParams->cofactor;
+
+    rv = SECSuccess;
+
+cleanup:
+    return rv;
+}
+
+SECStatus
+EC_FillParams(PRArenaPool *arena, const SECItem *encodedParams, 
+    ECParams *params)
+{
+    SECStatus rv = SECFailure;
+    SECOidTag tag;
+    SECItem oid = { siBuffer, NULL, 0};
+
+#if EC_DEBUG
+    int i;
+
+    printf("Encoded params in EC_DecodeParams: ");
+    for (i = 0; i < encodedParams->len; i++) {
+	    printf("%02x:", encodedParams->data[i]);
+    }
+    printf("\n");
+#endif
+
+    if ((encodedParams->len != ANSI_X962_CURVE_OID_TOTAL_LEN) &&
+	(encodedParams->len != SECG_CURVE_OID_TOTAL_LEN)) {
+	    PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+	    return SECFailure;
+    };
+
+    oid.len = encodedParams->len - 2;
+    oid.data = encodedParams->data + 2;
+    if ((encodedParams->data[0] != SEC_ASN1_OBJECT_ID) ||
+	((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)) { 
+	    PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+	    return SECFailure;
+    }
+
+    params->arena = arena;
+    params->cofactor = 0;
+    params->type = ec_params_named;
+    params->name = ECCurve_noName;
+
+    /* For named curves, fill out curveOID */
+    params->curveOID.len = oid.len;
+    params->curveOID.data = (unsigned char *) PORT_ArenaAlloc(arena, oid.len);
+    if (params->curveOID.data == NULL) goto cleanup;
+    memcpy(params->curveOID.data, oid.data, oid.len);
+
+#if EC_DEBUG
+    printf("Curve: %s\n", SECOID_FindOIDTagDescription(tag));
+#endif
+
+    switch (tag) {
+
+    /* Binary curves */
+
+    case SEC_OID_ANSIX962_EC_C2PNB163V1:
+	/* Populate params for c2pnb163v1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2PNB163V2:
+	/* Populate params for c2pnb163v2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V2, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2PNB163V3:
+	/* Populate params for c2pnb163v3 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V3, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2PNB176V1:
+	/* Populate params for c2pnb176v1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB176V1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB191V1:
+	/* Populate params for c2tnb191v1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB191V2:
+	/* Populate params for c2tnb191v2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V2, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB191V3:
+	/* Populate params for c2tnb191v3 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V3, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2PNB208W1:
+	/* Populate params for c2pnb208w1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB208W1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB239V1:
+	/* Populate params for c2tnb239v1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB239V2:
+	/* Populate params for c2tnb239v2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V2, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB239V3:
+	/* Populate params for c2tnb239v3 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V3, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2PNB272W1:
+	/* Populate params for c2pnb272w1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB272W1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2PNB304W1:
+	/* Populate params for c2pnb304w1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB304W1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB359V1:
+	/* Populate params for c2tnb359v1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB359V1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2PNB368W1:
+	/* Populate params for c2pnb368w1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB368W1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_C2TNB431R1:
+	/* Populate params for c2tnb431r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB431R1, ec_field_GF2m,
+	    params) );
+	break;
+	
+    case SEC_OID_SECG_EC_SECT113R1:
+	/* Populate params for sect113r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_113R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT113R2:
+	/* Populate params for sect113r2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_113R2, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT131R1:
+	/* Populate params for sect131r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_131R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT131R2:
+	/* Populate params for sect131r2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_131R2, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT163K1:
+	/* Populate params for sect163k1
+	 * (the NIST K-163 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163K1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT163R1:
+	/* Populate params for sect163r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT163R2:
+	/* Populate params for sect163r2
+	 * (the NIST B-163 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163R2, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT193R1:
+	/* Populate params for sect193r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_193R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT193R2:
+	/* Populate params for sect193r2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_193R2, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT233K1:
+	/* Populate params for sect233k1
+	 * (the NIST K-233 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_233K1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT233R1:
+	/* Populate params for sect233r1
+	 * (the NIST B-233 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_233R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT239K1:
+	/* Populate params for sect239k1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_239K1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT283K1:
+        /* Populate params for sect283k1
+	 * (the NIST K-283 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_283K1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT283R1:
+	/* Populate params for sect283r1
+	 * (the NIST B-283 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_283R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT409K1:
+	/* Populate params for sect409k1
+	 * (the NIST K-409 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_409K1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT409R1:
+	/* Populate params for sect409r1
+	 * (the NIST B-409 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_409R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT571K1:
+	/* Populate params for sect571k1
+	 * (the NIST K-571 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_571K1, ec_field_GF2m,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECT571R1:
+	/* Populate params for sect571r1
+	 * (the NIST B-571 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_571R1, ec_field_GF2m,
+	    params) );
+	break;
+
+    /* Prime curves */
+
+    case SEC_OID_ANSIX962_EC_PRIME192V1:
+	/* Populate params for prime192v1 aka secp192r1 
+	 * (the NIST P-192 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_PRIME192V2:
+	/* Populate params for prime192v2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V2, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_PRIME192V3:
+	/* Populate params for prime192v3 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V3, ec_field_GFp,
+	    params) );
+	break;
+	
+    case SEC_OID_ANSIX962_EC_PRIME239V1:
+	/* Populate params for prime239v1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_PRIME239V2:
+	/* Populate params for prime239v2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V2, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_PRIME239V3:
+	/* Populate params for prime239v3 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V3, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_ANSIX962_EC_PRIME256V1:
+	/* Populate params for prime256v1 aka secp256r1
+	 * (the NIST P-256 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_256V1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP112R1:
+        /* Populate params for secp112r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_112R1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP112R2:
+        /* Populate params for secp112r2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_112R2, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP128R1:
+        /* Populate params for secp128r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_128R1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP128R2:
+        /* Populate params for secp128r2 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_128R2, ec_field_GFp,
+	    params) );
+	break;
+	
+    case SEC_OID_SECG_EC_SECP160K1:
+        /* Populate params for secp160k1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160K1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP160R1:
+        /* Populate params for secp160r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160R1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP160R2:
+	/* Populate params for secp160r1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160R2, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP192K1:
+	/* Populate params for secp192k1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_192K1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP224K1:
+	/* Populate params for secp224k1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_224K1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP224R1:
+	/* Populate params for secp224r1 
+	 * (the NIST P-224 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_224R1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP256K1:
+	/* Populate params for secp256k1 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_256K1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP384R1:
+	/* Populate params for secp384r1
+	 * (the NIST P-384 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_384R1, ec_field_GFp,
+	    params) );
+	break;
+
+    case SEC_OID_SECG_EC_SECP521R1:
+	/* Populate params for secp521r1 
+	 * (the NIST P-521 curve)
+	 */
+	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_521R1, ec_field_GFp,
+	    params) );
+	break;
+
+    default:
+	break;
+    };
+
+cleanup:
+    if (!params->cofactor) {
+	PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+#if EC_DEBUG
+	printf("Unrecognized curve, returning NULL params\n");
+#endif
+    }
+
+    return rv;
+}
+
+SECStatus
+EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams)
+{
+    PRArenaPool *arena;
+    ECParams *params;
+    SECStatus rv = SECFailure;
+
+    /* Initialize an arena for the ECParams structure */
+    if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
+	return SECFailure;
+
+    params = (ECParams *)PORT_ArenaZAlloc(arena, sizeof(ECParams));
+    if (!params) {
+	PORT_FreeArena(arena, PR_TRUE);
+	return SECFailure;
+    }
+
+    /* Copy the encoded params */
+    SECITEM_AllocItem(arena, &(params->DEREncoding),
+	encodedParams->len);
+    memcpy(params->DEREncoding.data, encodedParams->data, encodedParams->len);
+
+    /* Fill out the rest of the ECParams structure based on 
+     * the encoded params 
+     */
+    rv = EC_FillParams(arena, encodedParams, params);
+    if (rv == SECFailure) {
+	PORT_FreeArena(arena, PR_TRUE);	
+	return SECFailure;
+    } else {
+	*ecparams = params;;
+	return SECSuccess;
+    }
+}
+
+#endif /* NSS_ENABLE_ECC */
diff --git a/mozilla/security/nss/lib/softoken/fipsaudt.c b/mozilla/security/nss/lib/softoken/fipsaudt.c
new file mode 100644
index 0000000..573a17c
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/fipsaudt.c
@@ -0,0 +1,351 @@
+/* ***** 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 Network Security Services (NSS).
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * 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 ***** */
+
+/*
+ * This file implements audit logging required by FIPS 140-2 Security
+ * Level 2.
+ */
+
+#include "prprf.h"
+#include "softoken.h"
+
+/*
+ * Print the value of the returned object handle in the output buffer
+ * on a successful return of the PKCS #11 function.  If the PKCS #11
+ * function failed or the pointer to object handle is NULL (which is
+ * the case for C_DeriveKey with CKM_TLS_KEY_AND_MAC_DERIVE), an empty
+ * string is stored in the output buffer.
+ *
+ * out: the output buffer
+ * outlen: the length of the output buffer
+ * argName: the name of the "pointer to object handle" argument
+ * phObject: the pointer to object handle
+ * rv: the return value of the PKCS #11 function
+ */
+static void sftk_PrintReturnedObjectHandle(char *out, PRUint32 outlen,
+    const char *argName, CK_OBJECT_HANDLE_PTR phObject, CK_RV rv)
+{
+    if ((rv == CKR_OK) && phObject) {
+	PR_snprintf(out, outlen,
+	    " *%s=0x%08lX", argName, (PRUint32)*phObject);
+    } else {
+	PORT_Assert(outlen != 0);
+	out[0] = '\0';
+    }
+}
+
+/*
+ * MECHANISM_BUFSIZE needs to be large enough for sftk_PrintMechanism,
+ * which uses <= 49 bytes.
+ */
+#define MECHANISM_BUFSIZE 64
+
+static void sftk_PrintMechanism(char *out, PRUint32 outlen,
+    CK_MECHANISM_PTR pMechanism)
+{
+    if (pMechanism) {
+	/*
+	 * If we change the format string, we need to make sure
+	 * MECHANISM_BUFSIZE is still large enough.  We allow
+	 * 20 bytes for %p on a 64-bit platform.
+	 */
+	PR_snprintf(out, outlen, "%p {mechanism=0x%08lX, ...}",
+	    pMechanism, (PRUint32)pMechanism->mechanism);
+    } else {
+	PR_snprintf(out, outlen, "%p", pMechanism);
+    }
+}
+
+void sftk_AuditCreateObject(CK_SESSION_HANDLE hSession,
+    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+    CK_OBJECT_HANDLE_PTR phObject, CK_RV rv)
+{
+    char msg[256];
+    char shObject[32];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintReturnedObjectHandle(shObject, sizeof shObject,
+	"phObject", phObject, rv);
+    PR_snprintf(msg, sizeof msg,
+	"C_CreateObject(hSession=0x%08lX, pTemplate=%p, ulCount=%lu, "
+	"phObject=%p)=0x%08lX%s",
+	(PRUint32)hSession, pTemplate, (PRUint32)ulCount,
+	phObject, (PRUint32)rv, shObject);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_LOAD_KEY, msg);
+}
+
+void sftk_AuditCopyObject(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+    CK_OBJECT_HANDLE_PTR phNewObject, CK_RV rv)
+{
+    char msg[256];
+    char shNewObject[32];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintReturnedObjectHandle(shNewObject, sizeof shNewObject,
+	"phNewObject", phNewObject, rv);
+    PR_snprintf(msg, sizeof msg,
+	"C_CopyObject(hSession=0x%08lX, hObject=0x%08lX, "
+	"pTemplate=%p, ulCount=%lu, phNewObject=%p)=0x%08lX%s",
+	(PRUint32)hSession, (PRUint32)hObject,
+	pTemplate, (PRUint32)ulCount, phNewObject, (PRUint32)rv, shNewObject);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_COPY_KEY, msg);
+}
+
+/* WARNING: hObject has been destroyed and can only be printed. */
+void sftk_AuditDestroyObject(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hObject, CK_RV rv)
+{
+    char msg[256];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    PR_snprintf(msg, sizeof msg,
+	"C_DestroyObject(hSession=0x%08lX, hObject=0x%08lX)=0x%08lX",
+	(PRUint32)hSession, (PRUint32)hObject, (PRUint32)rv);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_DESTROY_KEY, msg);
+}
+
+void sftk_AuditGetObjectSize(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize, CK_RV rv)
+{
+    char msg[256];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    PR_snprintf(msg, sizeof msg,
+	"C_GetObjectSize(hSession=0x%08lX, hObject=0x%08lX, "
+	"pulSize=%p)=0x%08lX",
+	(PRUint32)hSession, (PRUint32)hObject,
+	pulSize, (PRUint32)rv);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_ACCESS_KEY, msg);
+}
+
+void sftk_AuditGetAttributeValue(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate,
+    CK_ULONG ulCount, CK_RV rv)
+{
+    char msg[256];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    PR_snprintf(msg, sizeof msg,
+	"C_GetAttributeValue(hSession=0x%08lX, hObject=0x%08lX, "
+	"pTemplate=%p, ulCount=%lu)=0x%08lX",
+	(PRUint32)hSession, (PRUint32)hObject,
+	pTemplate, (PRUint32)ulCount, (PRUint32)rv);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_ACCESS_KEY, msg);
+}
+
+void sftk_AuditSetAttributeValue(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate,
+    CK_ULONG ulCount, CK_RV rv)
+{
+    char msg[256];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    PR_snprintf(msg, sizeof msg,
+	"C_SetAttributeValue(hSession=0x%08lX, hObject=0x%08lX, "
+	"pTemplate=%p, ulCount=%lu)=0x%08lX",
+	(PRUint32)hSession, (PRUint32)hObject,
+	pTemplate, (PRUint32)ulCount, (PRUint32)rv);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_CHANGE_KEY, msg);
+}
+
+void sftk_AuditCryptInit(const char *opName, CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_RV rv)
+{
+    char msg[256];
+    char mech[MECHANISM_BUFSIZE];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintMechanism(mech, sizeof mech, pMechanism);
+    PR_snprintf(msg, sizeof msg,
+	"C_%sInit(hSession=0x%08lX, pMechanism=%s, "
+	"hKey=0x%08lX)=0x%08lX",
+	opName, (PRUint32)hSession, mech,
+	(PRUint32)hKey, (PRUint32)rv);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_CRYPT, msg);
+}
+
+void sftk_AuditGenerateKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
+    CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey, CK_RV rv)
+{
+    char msg[256];
+    char mech[MECHANISM_BUFSIZE];
+    char shKey[32];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintMechanism(mech, sizeof mech, pMechanism);
+    sftk_PrintReturnedObjectHandle(shKey, sizeof shKey, "phKey", phKey, rv);
+    PR_snprintf(msg, sizeof msg,
+	"C_GenerateKey(hSession=0x%08lX, pMechanism=%s, "
+	"pTemplate=%p, ulCount=%lu, phKey=%p)=0x%08lX%s",
+	(PRUint32)hSession, mech,
+	pTemplate, (PRUint32)ulCount, phKey, (PRUint32)rv, shKey);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_GENERATE_KEY, msg);
+}
+
+void sftk_AuditGenerateKeyPair(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+    CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+    CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey,
+    CK_OBJECT_HANDLE_PTR phPrivateKey, CK_RV rv)
+{
+    char msg[512];
+    char mech[MECHANISM_BUFSIZE];
+    char shPublicKey[32];
+    char shPrivateKey[32];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintMechanism(mech, sizeof mech, pMechanism);
+    sftk_PrintReturnedObjectHandle(shPublicKey, sizeof shPublicKey,
+	"phPublicKey", phPublicKey, rv);
+    sftk_PrintReturnedObjectHandle(shPrivateKey, sizeof shPrivateKey,
+	"phPrivateKey", phPrivateKey, rv);
+    PR_snprintf(msg, sizeof msg,
+	"C_GenerateKeyPair(hSession=0x%08lX, pMechanism=%s, "
+	"pPublicKeyTemplate=%p, ulPublicKeyAttributeCount=%lu, "
+	"pPrivateKeyTemplate=%p, ulPrivateKeyAttributeCount=%lu, "
+	"phPublicKey=%p, phPrivateKey=%p)=0x%08lX%s%s",
+	(PRUint32)hSession, mech,
+	pPublicKeyTemplate, (PRUint32)ulPublicKeyAttributeCount,
+	pPrivateKeyTemplate, (PRUint32)ulPrivateKeyAttributeCount,
+	phPublicKey, phPrivateKey, (PRUint32)rv, shPublicKey, shPrivateKey);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_GENERATE_KEY, msg);
+}
+
+void sftk_AuditWrapKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey,
+    CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey,
+    CK_ULONG_PTR pulWrappedKeyLen, CK_RV rv)
+{
+    char msg[256];
+    char mech[MECHANISM_BUFSIZE];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintMechanism(mech, sizeof mech, pMechanism);
+    PR_snprintf(msg, sizeof msg,
+	"C_WrapKey(hSession=0x%08lX, pMechanism=%s, hWrappingKey=0x%08lX, "
+	"hKey=0x%08lX, pWrappedKey=%p, pulWrappedKeyLen=%p)=0x%08lX",
+	(PRUint32)hSession, mech, (PRUint32)hWrappingKey,
+	(PRUint32)hKey, pWrappedKey, pulWrappedKeyLen, (PRUint32)rv);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_WRAP_KEY, msg);
+}
+
+void sftk_AuditUnwrapKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,
+    CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,
+    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
+    CK_OBJECT_HANDLE_PTR phKey, CK_RV rv)
+{
+    char msg[256];
+    char mech[MECHANISM_BUFSIZE];
+    char shKey[32];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintMechanism(mech, sizeof mech, pMechanism);
+    sftk_PrintReturnedObjectHandle(shKey, sizeof shKey, "phKey", phKey, rv);
+    PR_snprintf(msg, sizeof msg,
+	"C_UnwrapKey(hSession=0x%08lX, pMechanism=%s, "
+	"hUnwrappingKey=0x%08lX, pWrappedKey=%p, ulWrappedKeyLen=%lu, "
+	"pTemplate=%p, ulAttributeCount=%lu, phKey=%p)=0x%08lX%s",
+	(PRUint32)hSession, mech,
+	(PRUint32)hUnwrappingKey, pWrappedKey, (PRUint32)ulWrappedKeyLen,
+	pTemplate, (PRUint32)ulAttributeCount, phKey, (PRUint32)rv, shKey);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_UNWRAP_KEY, msg);
+}
+
+void sftk_AuditDeriveKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey,
+    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
+    CK_OBJECT_HANDLE_PTR phKey, CK_RV rv)
+{
+    char msg[512];
+    char mech[MECHANISM_BUFSIZE];
+    char shKey[32];
+    char sTlsKeys[128];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    sftk_PrintMechanism(mech, sizeof mech, pMechanism);
+    sftk_PrintReturnedObjectHandle(shKey, sizeof shKey, "phKey", phKey, rv);
+    if ((rv == CKR_OK) &&
+	(pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE)) {
+	CK_SSL3_KEY_MAT_PARAMS *param =
+	    (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;
+	CK_SSL3_KEY_MAT_OUT *keymat = param->pReturnedKeyMaterial;
+	PR_snprintf(sTlsKeys, sizeof sTlsKeys,
+	    " hClientMacSecret=0x%08lX hServerMacSecret=0x%08lX"
+	    " hClientKey=0x%08lX hServerKey=0x%08lX",
+	    (PRUint32)keymat->hClientMacSecret,
+	    (PRUint32)keymat->hServerMacSecret,
+	    (PRUint32)keymat->hClientKey,
+	    (PRUint32)keymat->hServerKey);
+    } else {
+	sTlsKeys[0] = '\0';
+    }
+    PR_snprintf(msg, sizeof msg,
+	"C_DeriveKey(hSession=0x%08lX, pMechanism=%s, "
+	"hBaseKey=0x%08lX, pTemplate=%p, ulAttributeCount=%lu, "
+	"phKey=%p)=0x%08lX%s%s",
+	(PRUint32)hSession, mech,
+	(PRUint32)hBaseKey, pTemplate,(PRUint32)ulAttributeCount,
+	phKey, (PRUint32)rv, shKey, sTlsKeys);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_DERIVE_KEY, msg);
+}
+
+void sftk_AuditDigestKey(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hKey, CK_RV rv)
+{
+    char msg[256];
+    NSSAuditSeverity severity = (rv == CKR_OK) ?
+	NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+
+    PR_snprintf(msg, sizeof msg,
+	"C_DigestKey(hSession=0x%08lX, hKey=0x%08lX)=0x%08lX",
+	(PRUint32)hSession, (PRUint32)hKey, (PRUint32)rv);
+    sftk_LogAuditMessage(severity, NSS_AUDIT_DIGEST_KEY, msg);
+}
diff --git a/mozilla/security/nss/lib/softoken/fipstest.c b/mozilla/security/nss/lib/softoken/fipstest.c
new file mode 100644
index 0000000..a9ca120
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/fipstest.c
@@ -0,0 +1,2155 @@
+/*
+ * PKCS #11 FIPS Power-Up Self Test.
+ *
+ * ***** 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 ***** */
+/* $Id: fipstest.c,v 1.27 2009/06/19 23:05:48 rrelyea%redhat.com Exp $ */
+
+#include "softoken.h"   /* Required for RC2-ECB, RC2-CBC, RC4, DES-ECB,  */
+                        /*              DES-CBC, DES3-ECB, DES3-CBC, RSA */
+                        /*              and DSA.                         */
+#include "seccomon.h"   /* Required for RSA and DSA. */
+#include "lowkeyi.h"    /* Required for RSA and DSA. */
+#include "pkcs11.h"     /* Required for PKCS #11. */
+#include "secerr.h"
+
+#ifdef NSS_ENABLE_ECC
+#include "ec.h"         /* Required for ECDSA */
+#endif
+
+
+/* FIPS preprocessor directives for RC2-ECB and RC2-CBC.        */
+#define FIPS_RC2_KEY_LENGTH                      5  /*  40-bits */
+#define FIPS_RC2_ENCRYPT_LENGTH                  8  /*  64-bits */
+#define FIPS_RC2_DECRYPT_LENGTH                  8  /*  64-bits */
+
+
+/* FIPS preprocessor directives for RC4.                        */
+#define FIPS_RC4_KEY_LENGTH                      5  /*  40-bits */
+#define FIPS_RC4_ENCRYPT_LENGTH                  8  /*  64-bits */
+#define FIPS_RC4_DECRYPT_LENGTH                  8  /*  64-bits */
+
+
+/* FIPS preprocessor directives for DES-ECB and DES-CBC.        */
+#define FIPS_DES_ENCRYPT_LENGTH                  8  /*  64-bits */
+#define FIPS_DES_DECRYPT_LENGTH                  8  /*  64-bits */
+
+
+/* FIPS preprocessor directives for DES3-CBC and DES3-ECB.      */
+#define FIPS_DES3_ENCRYPT_LENGTH                 8  /*  64-bits */
+#define FIPS_DES3_DECRYPT_LENGTH                 8  /*  64-bits */
+
+
+/* FIPS preprocessor directives for AES-ECB and AES-CBC.        */
+#define FIPS_AES_BLOCK_SIZE                     16  /* 128-bits */
+#define FIPS_AES_ENCRYPT_LENGTH                 16  /* 128-bits */
+#define FIPS_AES_DECRYPT_LENGTH                 16  /* 128-bits */
+#define FIPS_AES_128_KEY_SIZE                   16  /* 128-bits */
+#define FIPS_AES_192_KEY_SIZE                   24  /* 192-bits */
+#define FIPS_AES_256_KEY_SIZE                   32  /* 256-bits */
+
+
+/* FIPS preprocessor directives for message digests             */
+#define FIPS_KNOWN_HASH_MESSAGE_LENGTH          64  /* 512-bits */
+
+
+/* FIPS preprocessor directives for RSA.                         */
+#define FIPS_RSA_TYPE                           siBuffer
+#define FIPS_RSA_PUBLIC_EXPONENT_LENGTH           3 /*   24-bits */
+#define FIPS_RSA_PRIVATE_VERSION_LENGTH           1 /*    8-bits */
+#define FIPS_RSA_MESSAGE_LENGTH                 256 /* 2048-bits */
+#define FIPS_RSA_COEFFICIENT_LENGTH             128 /* 1024-bits */
+#define FIPS_RSA_PRIME0_LENGTH                  128 /* 1024-bits */
+#define FIPS_RSA_PRIME1_LENGTH                  128 /* 1024-bits */
+#define FIPS_RSA_EXPONENT0_LENGTH               128 /* 1024-bits */
+#define FIPS_RSA_EXPONENT1_LENGTH               128 /* 1024-bits */
+#define FIPS_RSA_PRIVATE_EXPONENT_LENGTH        256 /* 2048-bits */
+#define FIPS_RSA_ENCRYPT_LENGTH                 256 /* 2048-bits */
+#define FIPS_RSA_DECRYPT_LENGTH                 256 /* 2048-bits */
+#define FIPS_RSA_SIGNATURE_LENGTH               256 /* 2048-bits */
+#define FIPS_RSA_MODULUS_LENGTH                 256 /* 2048-bits */
+
+
+/* FIPS preprocessor directives for DSA.                        */
+#define FIPS_DSA_TYPE                           siBuffer
+#define FIPS_DSA_DIGEST_LENGTH                  20 /*  160-bits */
+#define FIPS_DSA_SUBPRIME_LENGTH                20 /*  160-bits */
+#define FIPS_DSA_SIGNATURE_LENGTH               40 /*  320-bits */
+#define FIPS_DSA_PRIME_LENGTH                  128 /* 1024-bits */
+#define FIPS_DSA_BASE_LENGTH                   128 /* 1024-bits */
+
+/* FIPS preprocessor directives for RNG.                        */
+#define FIPS_RNG_XKEY_LENGTH                    32  /* 256-bits */
+
+static CK_RV
+sftk_fips_RC2_PowerUpSelfTest( void )
+{
+    /* RC2 Known Key (40-bits). */
+    static const PRUint8 rc2_known_key[] = { "RSARC" };
+
+    /* RC2-CBC Known Initialization Vector (64-bits). */
+    static const PRUint8 rc2_cbc_known_initialization_vector[] = {"Security"};
+
+    /* RC2 Known Plaintext (64-bits). */
+    static const PRUint8 rc2_ecb_known_plaintext[] = {"Netscape"};
+    static const PRUint8 rc2_cbc_known_plaintext[] = {"Netscape"};
+
+    /* RC2 Known Ciphertext (64-bits). */
+    static const PRUint8 rc2_ecb_known_ciphertext[] = {
+				  0x1a,0x71,0x33,0x54,0x8d,0x5c,0xd2,0x30};
+    static const PRUint8 rc2_cbc_known_ciphertext[] = {
+				  0xff,0x41,0xdb,0x94,0x8a,0x4c,0x33,0xb3};
+
+    /* RC2 variables. */
+    PRUint8        rc2_computed_ciphertext[FIPS_RC2_ENCRYPT_LENGTH];
+    PRUint8        rc2_computed_plaintext[FIPS_RC2_DECRYPT_LENGTH];
+    RC2Context *   rc2_context;
+    unsigned int   rc2_bytes_encrypted;
+    unsigned int   rc2_bytes_decrypted;
+    SECStatus      rc2_status;
+
+
+    /******************************************************/
+    /* RC2-ECB Single-Round Known Answer Encryption Test: */
+    /******************************************************/
+
+    rc2_context = RC2_CreateContext( rc2_known_key, FIPS_RC2_KEY_LENGTH,
+                                     NULL, NSS_RC2,
+                                     FIPS_RC2_KEY_LENGTH );
+
+    if( rc2_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    rc2_status = RC2_Encrypt( rc2_context, rc2_computed_ciphertext,
+                              &rc2_bytes_encrypted, FIPS_RC2_ENCRYPT_LENGTH,
+                              rc2_ecb_known_plaintext,
+                              FIPS_RC2_DECRYPT_LENGTH );
+
+    RC2_DestroyContext( rc2_context, PR_TRUE );
+
+    if( ( rc2_status != SECSuccess ) ||
+        ( rc2_bytes_encrypted != FIPS_RC2_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( rc2_computed_ciphertext, rc2_ecb_known_ciphertext,
+                       FIPS_RC2_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* RC2-ECB Single-Round Known Answer Decryption Test: */
+    /******************************************************/
+
+    rc2_context = RC2_CreateContext( rc2_known_key, FIPS_RC2_KEY_LENGTH,
+                                     NULL, NSS_RC2,
+                                     FIPS_RC2_KEY_LENGTH );
+
+    if( rc2_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    rc2_status = RC2_Decrypt( rc2_context, rc2_computed_plaintext,
+                              &rc2_bytes_decrypted, FIPS_RC2_DECRYPT_LENGTH,
+                              rc2_ecb_known_ciphertext,
+                              FIPS_RC2_ENCRYPT_LENGTH );
+
+    RC2_DestroyContext( rc2_context, PR_TRUE );
+
+    if( ( rc2_status != SECSuccess ) ||
+        ( rc2_bytes_decrypted != FIPS_RC2_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( rc2_computed_plaintext, rc2_ecb_known_plaintext,
+                       FIPS_RC2_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* RC2-CBC Single-Round Known Answer Encryption Test: */
+    /******************************************************/
+
+    rc2_context = RC2_CreateContext( rc2_known_key, FIPS_RC2_KEY_LENGTH,
+                                     rc2_cbc_known_initialization_vector,
+                                     NSS_RC2_CBC, FIPS_RC2_KEY_LENGTH );
+
+    if( rc2_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    rc2_status = RC2_Encrypt( rc2_context, rc2_computed_ciphertext,
+                              &rc2_bytes_encrypted, FIPS_RC2_ENCRYPT_LENGTH,
+                              rc2_cbc_known_plaintext,
+                              FIPS_RC2_DECRYPT_LENGTH );
+
+    RC2_DestroyContext( rc2_context, PR_TRUE );
+
+    if( ( rc2_status != SECSuccess ) ||
+        ( rc2_bytes_encrypted != FIPS_RC2_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( rc2_computed_ciphertext, rc2_cbc_known_ciphertext,
+                       FIPS_RC2_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* RC2-CBC Single-Round Known Answer Decryption Test: */
+    /******************************************************/
+
+    rc2_context = RC2_CreateContext( rc2_known_key, FIPS_RC2_KEY_LENGTH,
+                                     rc2_cbc_known_initialization_vector,
+                                     NSS_RC2_CBC, FIPS_RC2_KEY_LENGTH );
+
+    if( rc2_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    rc2_status = RC2_Decrypt( rc2_context, rc2_computed_plaintext,
+                              &rc2_bytes_decrypted, FIPS_RC2_DECRYPT_LENGTH,
+                              rc2_cbc_known_ciphertext,
+                              FIPS_RC2_ENCRYPT_LENGTH );
+
+    RC2_DestroyContext( rc2_context, PR_TRUE );
+
+    if( ( rc2_status != SECSuccess ) ||
+        ( rc2_bytes_decrypted != FIPS_RC2_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( rc2_computed_plaintext, rc2_ecb_known_plaintext,
+                       FIPS_RC2_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+
+static CK_RV
+sftk_fips_RC4_PowerUpSelfTest( void )
+{
+    /* RC4 Known Key (40-bits). */
+    static const PRUint8 rc4_known_key[] = { "RSARC" };
+
+    /* RC4 Known Plaintext (64-bits). */
+    static const PRUint8 rc4_known_plaintext[] = { "Netscape" };
+
+    /* RC4 Known Ciphertext (64-bits). */
+    static const PRUint8 rc4_known_ciphertext[] = {
+				0x29,0x33,0xc7,0x9a,0x9d,0x6c,0x09,0xdd};
+
+    /* RC4 variables. */
+    PRUint8        rc4_computed_ciphertext[FIPS_RC4_ENCRYPT_LENGTH];
+    PRUint8        rc4_computed_plaintext[FIPS_RC4_DECRYPT_LENGTH];
+    RC4Context *   rc4_context;
+    unsigned int   rc4_bytes_encrypted;
+    unsigned int   rc4_bytes_decrypted;
+    SECStatus      rc4_status;
+
+
+    /**************************************************/
+    /* RC4 Single-Round Known Answer Encryption Test: */
+    /**************************************************/
+
+    rc4_context = RC4_CreateContext( rc4_known_key, FIPS_RC4_KEY_LENGTH );
+
+    if( rc4_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    rc4_status = RC4_Encrypt( rc4_context, rc4_computed_ciphertext,
+                              &rc4_bytes_encrypted, FIPS_RC4_ENCRYPT_LENGTH,
+                              rc4_known_plaintext, FIPS_RC4_DECRYPT_LENGTH );
+
+    RC4_DestroyContext( rc4_context, PR_TRUE );
+
+    if( ( rc4_status != SECSuccess ) ||
+        ( rc4_bytes_encrypted != FIPS_RC4_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( rc4_computed_ciphertext, rc4_known_ciphertext,
+                       FIPS_RC4_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /**************************************************/
+    /* RC4 Single-Round Known Answer Decryption Test: */
+    /**************************************************/
+
+    rc4_context = RC4_CreateContext( rc4_known_key, FIPS_RC4_KEY_LENGTH );
+
+    if( rc4_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    rc4_status = RC4_Decrypt( rc4_context, rc4_computed_plaintext,
+                              &rc4_bytes_decrypted, FIPS_RC4_DECRYPT_LENGTH,
+                              rc4_known_ciphertext, FIPS_RC4_ENCRYPT_LENGTH );
+
+    RC4_DestroyContext( rc4_context, PR_TRUE );
+
+    if( ( rc4_status != SECSuccess ) ||
+        ( rc4_bytes_decrypted != FIPS_RC4_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( rc4_computed_plaintext, rc4_known_plaintext,
+                       FIPS_RC4_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+
+static CK_RV
+sftk_fips_DES_PowerUpSelfTest( void )
+{
+    /* DES Known Key (56-bits). */
+    static const PRUint8 des_known_key[] = { "ANSI DES" };
+
+    /* DES-CBC Known Initialization Vector (64-bits). */
+    static const PRUint8 des_cbc_known_initialization_vector[] = { "Security" };
+
+    /* DES Known Plaintext (64-bits). */
+    static const PRUint8 des_ecb_known_plaintext[] = { "Netscape" };
+    static const PRUint8 des_cbc_known_plaintext[] = { "Netscape" };
+
+    /* DES Known Ciphertext (64-bits). */
+    static const PRUint8 des_ecb_known_ciphertext[] = {
+			       0x26,0x14,0xe9,0xc3,0x28,0x80,0x50,0xb0};
+    static const PRUint8 des_cbc_known_ciphertext[]  = {
+			       0x5e,0x95,0x94,0x5d,0x76,0xa2,0xd3,0x7d};
+
+    /* DES variables. */
+    PRUint8        des_computed_ciphertext[FIPS_DES_ENCRYPT_LENGTH];
+    PRUint8        des_computed_plaintext[FIPS_DES_DECRYPT_LENGTH];
+    DESContext *   des_context;
+    unsigned int   des_bytes_encrypted;
+    unsigned int   des_bytes_decrypted;
+    SECStatus      des_status;
+
+
+    /******************************************************/
+    /* DES-ECB Single-Round Known Answer Encryption Test: */
+    /******************************************************/
+
+    des_context = DES_CreateContext( des_known_key, NULL, NSS_DES, PR_TRUE );
+
+    if( des_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des_status = DES_Encrypt( des_context, des_computed_ciphertext,
+                              &des_bytes_encrypted, FIPS_DES_ENCRYPT_LENGTH,
+                              des_ecb_known_plaintext,
+                              FIPS_DES_DECRYPT_LENGTH );
+
+    DES_DestroyContext( des_context, PR_TRUE );
+
+    if( ( des_status != SECSuccess ) ||
+        ( des_bytes_encrypted != FIPS_DES_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des_computed_ciphertext, des_ecb_known_ciphertext,
+                       FIPS_DES_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* DES-ECB Single-Round Known Answer Decryption Test: */
+    /******************************************************/
+
+    des_context = DES_CreateContext( des_known_key, NULL, NSS_DES, PR_FALSE );
+
+    if( des_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des_status = DES_Decrypt( des_context, des_computed_plaintext,
+                              &des_bytes_decrypted, FIPS_DES_DECRYPT_LENGTH,
+                              des_ecb_known_ciphertext,
+                              FIPS_DES_ENCRYPT_LENGTH );
+
+    DES_DestroyContext( des_context, PR_TRUE );
+
+    if( ( des_status != SECSuccess ) ||
+        ( des_bytes_decrypted != FIPS_DES_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des_computed_plaintext, des_ecb_known_plaintext,
+                       FIPS_DES_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* DES-CBC Single-Round Known Answer Encryption Test. */
+    /******************************************************/
+
+    des_context = DES_CreateContext( des_known_key,
+                                     des_cbc_known_initialization_vector,
+                                     NSS_DES_CBC, PR_TRUE );
+
+    if( des_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des_status = DES_Encrypt( des_context, des_computed_ciphertext,
+                              &des_bytes_encrypted, FIPS_DES_ENCRYPT_LENGTH,
+                              des_cbc_known_plaintext,
+                              FIPS_DES_DECRYPT_LENGTH );
+
+    DES_DestroyContext( des_context, PR_TRUE );
+
+    if( ( des_status != SECSuccess ) ||
+        ( des_bytes_encrypted != FIPS_DES_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des_computed_ciphertext, des_cbc_known_ciphertext,
+                       FIPS_DES_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* DES-CBC Single-Round Known Answer Decryption Test. */
+    /******************************************************/
+
+    des_context = DES_CreateContext( des_known_key,
+                                     des_cbc_known_initialization_vector,
+                                     NSS_DES_CBC, PR_FALSE );
+
+    if( des_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des_status = DES_Decrypt( des_context, des_computed_plaintext,
+                              &des_bytes_decrypted, FIPS_DES_DECRYPT_LENGTH,
+                              des_cbc_known_ciphertext,
+                              FIPS_DES_ENCRYPT_LENGTH );
+
+    DES_DestroyContext( des_context, PR_TRUE );
+
+    if( ( des_status != SECSuccess ) ||
+        ( des_bytes_decrypted != FIPS_DES_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des_computed_plaintext, des_cbc_known_plaintext,
+                       FIPS_DES_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+
+static CK_RV
+sftk_fips_DES3_PowerUpSelfTest( void )
+{
+    /* DES3 Known Key (56-bits). */
+    static const PRUint8 des3_known_key[] = { "ANSI Triple-DES Key Data" };
+
+    /* DES3-CBC Known Initialization Vector (64-bits). */
+    static const PRUint8 des3_cbc_known_initialization_vector[] = { "Security" };
+
+    /* DES3 Known Plaintext (64-bits). */
+    static const PRUint8 des3_ecb_known_plaintext[] = { "Netscape" };
+    static const PRUint8 des3_cbc_known_plaintext[] = { "Netscape" };
+
+    /* DES3 Known Ciphertext (64-bits). */
+    static const PRUint8 des3_ecb_known_ciphertext[] = {
+			   0x55,0x8e,0xad,0x3c,0xee,0x49,0x69,0xbe};
+    static const PRUint8 des3_cbc_known_ciphertext[] = {
+			   0x43,0xdc,0x6a,0xc1,0xaf,0xa6,0x32,0xf5};
+
+    /* DES3 variables. */
+    PRUint8        des3_computed_ciphertext[FIPS_DES3_ENCRYPT_LENGTH];
+    PRUint8        des3_computed_plaintext[FIPS_DES3_DECRYPT_LENGTH];
+    DESContext *   des3_context;
+    unsigned int   des3_bytes_encrypted;
+    unsigned int   des3_bytes_decrypted;
+    SECStatus      des3_status;
+
+
+    /*******************************************************/
+    /* DES3-ECB Single-Round Known Answer Encryption Test. */
+    /*******************************************************/
+
+    des3_context = DES_CreateContext( des3_known_key, NULL,
+                                     NSS_DES_EDE3, PR_TRUE );
+
+    if( des3_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des3_status = DES_Encrypt( des3_context, des3_computed_ciphertext,
+                               &des3_bytes_encrypted, FIPS_DES3_ENCRYPT_LENGTH,
+                               des3_ecb_known_plaintext,
+                               FIPS_DES3_DECRYPT_LENGTH );
+
+    DES_DestroyContext( des3_context, PR_TRUE );
+
+    if( ( des3_status != SECSuccess ) ||
+        ( des3_bytes_encrypted != FIPS_DES3_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des3_computed_ciphertext, des3_ecb_known_ciphertext,
+                       FIPS_DES3_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /*******************************************************/
+    /* DES3-ECB Single-Round Known Answer Decryption Test. */
+    /*******************************************************/
+
+    des3_context = DES_CreateContext( des3_known_key, NULL,
+                                     NSS_DES_EDE3, PR_FALSE );
+
+    if( des3_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des3_status = DES_Decrypt( des3_context, des3_computed_plaintext,
+                               &des3_bytes_decrypted, FIPS_DES3_DECRYPT_LENGTH,
+                               des3_ecb_known_ciphertext,
+                               FIPS_DES3_ENCRYPT_LENGTH );
+
+    DES_DestroyContext( des3_context, PR_TRUE );
+
+    if( ( des3_status != SECSuccess ) ||
+        ( des3_bytes_decrypted != FIPS_DES3_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des3_computed_plaintext, des3_ecb_known_plaintext,
+                       FIPS_DES3_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /*******************************************************/
+    /* DES3-CBC Single-Round Known Answer Encryption Test. */
+    /*******************************************************/
+
+    des3_context = DES_CreateContext( des3_known_key,
+                                      des3_cbc_known_initialization_vector,
+                                      NSS_DES_EDE3_CBC, PR_TRUE );
+
+    if( des3_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des3_status = DES_Encrypt( des3_context, des3_computed_ciphertext,
+                               &des3_bytes_encrypted, FIPS_DES3_ENCRYPT_LENGTH,
+                               des3_cbc_known_plaintext,
+                               FIPS_DES3_DECRYPT_LENGTH );
+
+    DES_DestroyContext( des3_context, PR_TRUE );
+
+    if( ( des3_status != SECSuccess ) ||
+        ( des3_bytes_encrypted != FIPS_DES3_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des3_computed_ciphertext, des3_cbc_known_ciphertext,
+                       FIPS_DES3_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /*******************************************************/
+    /* DES3-CBC Single-Round Known Answer Decryption Test. */
+    /*******************************************************/
+
+    des3_context = DES_CreateContext( des3_known_key,
+                                      des3_cbc_known_initialization_vector,
+                                      NSS_DES_EDE3_CBC, PR_FALSE );
+
+    if( des3_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    des3_status = DES_Decrypt( des3_context, des3_computed_plaintext,
+                               &des3_bytes_decrypted, FIPS_DES3_DECRYPT_LENGTH,
+                               des3_cbc_known_ciphertext,
+                               FIPS_DES3_ENCRYPT_LENGTH );
+
+    DES_DestroyContext( des3_context, PR_TRUE );
+
+    if( ( des3_status != SECSuccess ) ||
+        ( des3_bytes_decrypted != FIPS_DES3_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( des3_computed_plaintext, des3_cbc_known_plaintext,
+                       FIPS_DES3_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+
+/* AES self-test for 128-bit, 192-bit, or 256-bit key sizes*/
+static CK_RV
+sftk_fips_AES_PowerUpSelfTest( int aes_key_size )
+{
+    /* AES Known Key (up to 256-bits). */
+    static const PRUint8 aes_known_key[] = 
+        { "AES-128 RIJNDAELLEADNJIR 821-SEA" };
+
+    /* AES-CBC Known Initialization Vector (128-bits). */
+    static const PRUint8 aes_cbc_known_initialization_vector[] = 
+        { "SecurityytiruceS" };
+
+    /* AES Known Plaintext (128-bits). (blocksize is 128-bits) */
+    static const PRUint8 aes_known_plaintext[] = { "NetscapeepacsteN" };
+
+    /* AES Known Ciphertext (128-bit key). */
+    static const PRUint8 aes_ecb128_known_ciphertext[] = {
+        0x3c,0xa5,0x96,0xf3,0x34,0x6a,0x96,0xc1,
+        0x03,0x88,0x16,0x7b,0x20,0xbf,0x35,0x47 };
+
+    static const PRUint8 aes_cbc128_known_ciphertext[]  = {
+        0xcf,0x15,0x1d,0x4f,0x96,0xe4,0x4f,0x63,
+        0x15,0x54,0x14,0x1d,0x4e,0xd8,0xd5,0xea };
+
+    /* AES Known Ciphertext (192-bit key). */
+    static const PRUint8 aes_ecb192_known_ciphertext[] = { 
+        0xa0,0x18,0x62,0xed,0x88,0x19,0xcb,0x62,
+        0x88,0x1d,0x4d,0xfe,0x84,0x02,0x89,0x0e };
+
+    static const PRUint8 aes_cbc192_known_ciphertext[]  = { 
+        0x83,0xf7,0xa4,0x76,0xd1,0x6f,0x07,0xbe,
+        0x07,0xbc,0x43,0x2f,0x6d,0xad,0x29,0xe1 };
+
+    /* AES Known Ciphertext (256-bit key). */
+    static const PRUint8 aes_ecb256_known_ciphertext[] = { 
+        0xdb,0xa6,0x52,0x01,0x8a,0x70,0xae,0x66,
+        0x3a,0x99,0xd8,0x95,0x7f,0xfb,0x01,0x67 };
+    
+    static const PRUint8 aes_cbc256_known_ciphertext[]  = { 
+        0x37,0xea,0x07,0x06,0x31,0x1c,0x59,0x27,
+        0xc5,0xc5,0x68,0x71,0x6e,0x34,0x40,0x16 };
+
+    const PRUint8 *aes_ecb_known_ciphertext =
+        ( aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_ecb128_known_ciphertext :
+        ( aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_ecb192_known_ciphertext :
+                                aes_ecb256_known_ciphertext;
+
+    const PRUint8 *aes_cbc_known_ciphertext =
+        ( aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_cbc128_known_ciphertext :
+        ( aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_cbc192_known_ciphertext :
+                                aes_cbc256_known_ciphertext;
+
+    /* AES variables. */
+    PRUint8        aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH];
+    PRUint8        aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH];
+    AESContext *   aes_context;
+    unsigned int   aes_bytes_encrypted;
+    unsigned int   aes_bytes_decrypted;
+    SECStatus      aes_status;
+
+    /*check if aes_key_size is 128, 192, or 256 bits */
+    if ((aes_key_size != FIPS_AES_128_KEY_SIZE) && 
+        (aes_key_size != FIPS_AES_192_KEY_SIZE) && 
+        (aes_key_size != FIPS_AES_256_KEY_SIZE)) 
+            return( CKR_DEVICE_ERROR );
+
+    /******************************************************/
+    /* AES-ECB Single-Round Known Answer Encryption Test: */
+    /******************************************************/
+
+    aes_context = AES_CreateContext( aes_known_key, NULL, NSS_AES, PR_TRUE,
+                                     aes_key_size, FIPS_AES_BLOCK_SIZE );
+
+    if( aes_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    aes_status = AES_Encrypt( aes_context, aes_computed_ciphertext,
+                              &aes_bytes_encrypted, FIPS_AES_ENCRYPT_LENGTH,
+                              aes_known_plaintext,
+                              FIPS_AES_DECRYPT_LENGTH );
+    
+    AES_DestroyContext( aes_context, PR_TRUE );
+
+    if( ( aes_status != SECSuccess ) ||
+        ( aes_bytes_encrypted != FIPS_AES_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( aes_computed_ciphertext, aes_ecb_known_ciphertext,
+                       FIPS_AES_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* AES-ECB Single-Round Known Answer Decryption Test: */
+    /******************************************************/
+
+    aes_context = AES_CreateContext( aes_known_key, NULL, NSS_AES, PR_FALSE,
+                                     aes_key_size, FIPS_AES_BLOCK_SIZE );
+
+    if( aes_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    aes_status = AES_Decrypt( aes_context, aes_computed_plaintext,
+                              &aes_bytes_decrypted, FIPS_AES_DECRYPT_LENGTH,
+                              aes_ecb_known_ciphertext,
+                              FIPS_AES_ENCRYPT_LENGTH );
+
+    AES_DestroyContext( aes_context, PR_TRUE );
+
+    if( ( aes_status != SECSuccess ) ||         
+        ( aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( aes_computed_plaintext, aes_known_plaintext,
+                       FIPS_AES_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* AES-CBC Single-Round Known Answer Encryption Test. */
+    /******************************************************/
+
+    aes_context = AES_CreateContext( aes_known_key,
+                                     aes_cbc_known_initialization_vector,
+                                     NSS_AES_CBC, PR_TRUE, aes_key_size, 
+                                     FIPS_AES_BLOCK_SIZE );
+
+    if( aes_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    aes_status = AES_Encrypt( aes_context, aes_computed_ciphertext,
+                              &aes_bytes_encrypted, FIPS_AES_ENCRYPT_LENGTH,
+                              aes_known_plaintext,
+                              FIPS_AES_DECRYPT_LENGTH );
+
+    AES_DestroyContext( aes_context, PR_TRUE );
+
+    if( ( aes_status != SECSuccess ) ||
+        ( aes_bytes_encrypted != FIPS_AES_ENCRYPT_LENGTH ) ||
+        ( PORT_Memcmp( aes_computed_ciphertext, aes_cbc_known_ciphertext,
+                       FIPS_AES_ENCRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+
+    /******************************************************/
+    /* AES-CBC Single-Round Known Answer Decryption Test. */
+    /******************************************************/
+
+    aes_context = AES_CreateContext( aes_known_key,
+                                     aes_cbc_known_initialization_vector,
+                                     NSS_AES_CBC, PR_FALSE, aes_key_size, 
+                                     FIPS_AES_BLOCK_SIZE );
+
+    if( aes_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    aes_status = AES_Decrypt( aes_context, aes_computed_plaintext,
+                              &aes_bytes_decrypted, FIPS_AES_DECRYPT_LENGTH,
+                              aes_cbc_known_ciphertext,
+                              FIPS_AES_ENCRYPT_LENGTH );
+
+    AES_DestroyContext( aes_context, PR_TRUE );
+
+    if( ( aes_status != SECSuccess ) ||
+        ( aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH ) ||
+        ( PORT_Memcmp( aes_computed_plaintext, aes_known_plaintext,
+                       FIPS_AES_DECRYPT_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+/* Known Hash Message (512-bits).  Used for all hashes (incl. SHA-N [N>1]). */
+static const PRUint8 known_hash_message[] = {
+  "The test message for the MD2, MD5, and SHA-1 hashing algorithms." };
+
+
+static CK_RV
+sftk_fips_MD2_PowerUpSelfTest( void )
+{
+    /* MD2 Known Digest Message (128-bits). */
+    static const PRUint8 md2_known_digest[]  = {
+                                   0x41,0x5a,0x12,0xb2,0x3f,0x28,0x97,0x17,
+                                   0x0c,0x71,0x4e,0xcc,0x40,0xc8,0x1d,0x1b};
+
+    /* MD2 variables. */
+    MD2Context * md2_context;
+    unsigned int md2_bytes_hashed;
+    PRUint8      md2_computed_digest[MD2_LENGTH];
+
+
+    /***********************************************/
+    /* MD2 Single-Round Known Answer Hashing Test. */
+    /***********************************************/
+
+    md2_context = MD2_NewContext();
+
+    if( md2_context == NULL )
+        return( CKR_HOST_MEMORY );
+
+    MD2_Begin( md2_context );
+
+    MD2_Update( md2_context, known_hash_message,
+                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
+
+    MD2_End( md2_context, md2_computed_digest, &md2_bytes_hashed, MD2_LENGTH );
+
+    MD2_DestroyContext( md2_context , PR_TRUE );
+    
+    if( ( md2_bytes_hashed != MD2_LENGTH ) ||
+        ( PORT_Memcmp( md2_computed_digest, md2_known_digest,
+                       MD2_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+
+static CK_RV
+sftk_fips_MD5_PowerUpSelfTest( void )
+{
+    /* MD5 Known Digest Message (128-bits). */
+    static const PRUint8 md5_known_digest[]  = {
+				   0x25,0xc8,0xc0,0x10,0xc5,0x6e,0x68,0x28,
+				   0x28,0xa4,0xa5,0xd2,0x98,0x9a,0xea,0x2d};
+
+    /* MD5 variables. */
+    PRUint8        md5_computed_digest[MD5_LENGTH];
+    SECStatus      md5_status;
+
+
+    /***********************************************/
+    /* MD5 Single-Round Known Answer Hashing Test. */
+    /***********************************************/
+
+    md5_status = MD5_HashBuf( md5_computed_digest, known_hash_message,
+                              FIPS_KNOWN_HASH_MESSAGE_LENGTH );
+
+    if( ( md5_status != SECSuccess ) ||
+        ( PORT_Memcmp( md5_computed_digest, md5_known_digest,
+                       MD5_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+/****************************************************/
+/* Single Round HMAC SHA-X test                     */
+/****************************************************/
+static SECStatus
+sftk_fips_HMAC(unsigned char *hmac_computed,
+               const PRUint8 *secret_key,
+               unsigned int secret_key_length,
+               const PRUint8 *message,
+               unsigned int message_length,
+               HASH_HashType hashAlg )
+{
+    SECStatus hmac_status = SECFailure;
+    HMACContext *cx = NULL;
+    SECHashObject *hashObj = NULL;
+    unsigned int bytes_hashed = 0;
+
+    hashObj = (SECHashObject *) HASH_GetRawHashObject(hashAlg);
+ 
+    if (!hashObj) 
+        return( SECFailure );
+
+    cx = HMAC_Create(hashObj, secret_key, 
+                     secret_key_length, 
+                     PR_TRUE);  /* PR_TRUE for in FIPS mode */
+
+    if (cx == NULL) 
+        return( SECFailure );
+
+    HMAC_Begin(cx);
+    HMAC_Update(cx, message, message_length);
+    hmac_status = HMAC_Finish(cx, hmac_computed, &bytes_hashed, 
+                              hashObj->length);
+
+    HMAC_Destroy(cx, PR_TRUE);
+
+    return( hmac_status );
+}
+
+static CK_RV
+sftk_fips_HMAC_PowerUpSelfTest( void )
+{
+    static const PRUint8 HMAC_known_secret_key[] = {
+                         "Firefox and ThunderBird are awesome!"};
+
+    static const PRUint8 HMAC_known_secret_key_length 
+                         = sizeof HMAC_known_secret_key;
+
+    /* known SHA1 hmac (20 bytes) */
+    static const PRUint8 known_SHA1_hmac[] = {
+        0xd5, 0x85, 0xf6, 0x5b, 0x39, 0xfa, 0xb9, 0x05, 
+        0x3b, 0x57, 0x1d, 0x61, 0xe7, 0xb8, 0x84, 0x1e, 
+        0x5d, 0x0e, 0x1e, 0x11};
+
+    /* known SHA256 hmac (32 bytes) */
+    static const PRUint8 known_SHA256_hmac[] = {
+        0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44, 
+        0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14, 0x22, 0xe0, 
+        0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9, 
+        0xa7, 0x1b, 0x56, 0x7d, 0x1d, 0x29, 0x40, 0x48};        
+
+    /* known SHA384 hmac (48 bytes) */
+    static const PRUint8 known_SHA384_hmac[] = {
+        0xcd, 0x56, 0x14, 0xec, 0x05, 0x53, 0x06, 0x2b,
+        0x7e, 0x9c, 0x8a, 0x18, 0x5e, 0xea, 0xf3, 0x91,
+        0x33, 0xfb, 0x64, 0xf6, 0xe3, 0x9f, 0x89, 0x0b,
+        0xaf, 0xbe, 0x83, 0x4d, 0x3f, 0x3c, 0x43, 0x4d,
+        0x4a, 0x0c, 0x56, 0x98, 0xf8, 0xca, 0xb4, 0xaa,
+        0x9a, 0xf4, 0x0a, 0xaf, 0x4f, 0x69, 0xca, 0x87};
+
+    /* known SHA512 hmac (64 bytes) */
+    static const PRUint8 known_SHA512_hmac[] = {
+        0xf6, 0x0e, 0x97, 0x12, 0x00, 0x67, 0x6e, 0xb9,
+        0x0c, 0xb2, 0x63, 0xf0, 0x60, 0xac, 0x75, 0x62,
+        0x70, 0x95, 0x2a, 0x52, 0x22, 0xee, 0xdd, 0xd2,
+        0x71, 0xb1, 0xe8, 0x26, 0x33, 0xd3, 0x13, 0x27,
+        0xcb, 0xff, 0x44, 0xef, 0x87, 0x97, 0x16, 0xfb,
+        0xd3, 0x0b, 0x48, 0xbe, 0x12, 0x4e, 0xda, 0xb1,
+        0x89, 0x90, 0xfb, 0x06, 0x0c, 0xbe, 0xe5, 0xc4,
+        0xff, 0x24, 0x37, 0x3d, 0xc7, 0xe4, 0xe4, 0x37};
+
+    SECStatus    hmac_status;
+    PRUint8      hmac_computed[HASH_LENGTH_MAX]; 
+
+    /***************************************************/
+    /* HMAC SHA-1 Single-Round Known Answer HMAC Test. */
+    /***************************************************/
+
+    hmac_status = sftk_fips_HMAC(hmac_computed, 
+                                 HMAC_known_secret_key,
+                                 HMAC_known_secret_key_length,
+                                 known_hash_message,
+                                 FIPS_KNOWN_HASH_MESSAGE_LENGTH,
+                                 HASH_AlgSHA1); 
+
+    if( ( hmac_status != SECSuccess ) || 
+        ( PORT_Memcmp( hmac_computed, known_SHA1_hmac,
+                       SHA1_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    /***************************************************/
+    /* HMAC SHA-256 Single-Round Known Answer Test.    */
+    /***************************************************/
+
+    hmac_status = sftk_fips_HMAC(hmac_computed, 
+                                 HMAC_known_secret_key,
+                                 HMAC_known_secret_key_length,
+                                 known_hash_message,
+                                 FIPS_KNOWN_HASH_MESSAGE_LENGTH,
+                                 HASH_AlgSHA256); 
+
+    if( ( hmac_status != SECSuccess ) || 
+        ( PORT_Memcmp( hmac_computed, known_SHA256_hmac,
+                       SHA256_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    /***************************************************/
+    /* HMAC SHA-384 Single-Round Known Answer Test.    */
+    /***************************************************/
+
+    hmac_status = sftk_fips_HMAC(hmac_computed,
+                                 HMAC_known_secret_key,
+                                 HMAC_known_secret_key_length,
+                                 known_hash_message,
+                                 FIPS_KNOWN_HASH_MESSAGE_LENGTH,
+                                 HASH_AlgSHA384);
+
+    if( ( hmac_status != SECSuccess ) ||
+        ( PORT_Memcmp( hmac_computed, known_SHA384_hmac,
+                       SHA384_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    /***************************************************/
+    /* HMAC SHA-512 Single-Round Known Answer Test.    */
+    /***************************************************/
+
+    hmac_status = sftk_fips_HMAC(hmac_computed,
+                                 HMAC_known_secret_key,
+                                 HMAC_known_secret_key_length,
+                                 known_hash_message,
+                                 FIPS_KNOWN_HASH_MESSAGE_LENGTH,
+                                 HASH_AlgSHA512);
+
+    if( ( hmac_status != SECSuccess ) ||
+        ( PORT_Memcmp( hmac_computed, known_SHA512_hmac,
+                       SHA512_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+static CK_RV
+sftk_fips_SHA_PowerUpSelfTest( void )
+{
+    /* SHA-1 Known Digest Message (160-bits). */
+    static const PRUint8 sha1_known_digest[] = {
+			       0x0a,0x6d,0x07,0xba,0x1e,0xbd,0x8a,0x1b,
+			       0x72,0xf6,0xc7,0x22,0xf1,0x27,0x9f,0xf0,
+			       0xe0,0x68,0x47,0x7a};
+
+    /* SHA-256 Known Digest Message (256-bits). */
+    static const PRUint8 sha256_known_digest[] = {
+        0x38,0xa9,0xc1,0xf0,0x35,0xf6,0x5d,0x61,
+        0x11,0xd4,0x0b,0xdc,0xce,0x35,0x14,0x8d,
+        0xf2,0xdd,0xaf,0xaf,0xcf,0xb7,0x87,0xe9,
+        0x96,0xa5,0xd2,0x83,0x62,0x46,0x56,0x79};
+ 
+    /* SHA-384 Known Digest Message (384-bits). */
+    static const PRUint8 sha384_known_digest[] = {
+        0x11,0xfe,0x1c,0x00,0x89,0x48,0xde,0xb3,
+        0x99,0xee,0x1c,0x18,0xb4,0x10,0xfb,0xfe,
+        0xe3,0xa8,0x2c,0xf3,0x04,0xb0,0x2f,0xc8,
+        0xa3,0xc4,0x5e,0xea,0x7e,0x60,0x48,0x7b,
+        0xce,0x2c,0x62,0xf7,0xbc,0xa7,0xe8,0xa3,
+        0xcf,0x24,0xce,0x9c,0xe2,0x8b,0x09,0x72};
+
+    /* SHA-512 Known Digest Message (512-bits). */
+    static const PRUint8 sha512_known_digest[] = {
+        0xc8,0xb3,0x27,0xf9,0x0b,0x24,0xc8,0xbf,
+        0x4c,0xba,0x33,0x54,0xf2,0x31,0xbf,0xdb,
+        0xab,0xfd,0xb3,0x15,0xd7,0xfa,0x48,0x99,
+        0x07,0x60,0x0f,0x57,0x41,0x1a,0xdd,0x28,
+        0x12,0x55,0x25,0xac,0xba,0x3a,0x99,0x12,
+        0x2c,0x7a,0x8f,0x75,0x3a,0xe1,0x06,0x6f,
+        0x30,0x31,0xc9,0x33,0xc6,0x1b,0x90,0x1a,
+        0x6c,0x98,0x9a,0x87,0xd0,0xb2,0xf8,0x07};
+
+    /* SHA-X variables. */
+    PRUint8        sha_computed_digest[HASH_LENGTH_MAX];
+    SECStatus      sha_status;
+
+    /*************************************************/
+    /* SHA-1 Single-Round Known Answer Hashing Test. */
+    /*************************************************/
+
+    sha_status = SHA1_HashBuf( sha_computed_digest, known_hash_message,
+                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
+ 
+    if( ( sha_status != SECSuccess ) ||
+        ( PORT_Memcmp( sha_computed_digest, sha1_known_digest,
+                       SHA1_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    /***************************************************/
+    /* SHA-256 Single-Round Known Answer Hashing Test. */
+    /***************************************************/
+
+    sha_status = SHA256_HashBuf( sha_computed_digest, known_hash_message,
+                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
+
+    if( ( sha_status != SECSuccess ) ||
+        ( PORT_Memcmp( sha_computed_digest, sha256_known_digest,
+                       SHA256_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    /***************************************************/
+    /* SHA-384 Single-Round Known Answer Hashing Test. */
+    /***************************************************/
+
+    sha_status = SHA384_HashBuf( sha_computed_digest, known_hash_message,
+                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
+
+    if( ( sha_status != SECSuccess ) ||
+        ( PORT_Memcmp( sha_computed_digest, sha384_known_digest,
+                       SHA384_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    /***************************************************/
+    /* SHA-512 Single-Round Known Answer Hashing Test. */
+    /***************************************************/
+
+    sha_status = SHA512_HashBuf( sha_computed_digest, known_hash_message,
+                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
+
+    if( ( sha_status != SECSuccess ) ||
+        ( PORT_Memcmp( sha_computed_digest, sha512_known_digest,
+                       SHA512_LENGTH ) != 0 ) )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+}
+
+/*
+* Single round RSA Signature Known Answer Test
+*/
+static SECStatus
+sftk_fips_RSA_PowerUpSigSelfTest (HASH_HashType  shaAlg,
+                                  NSSLOWKEYPublicKey *rsa_public_key,
+                                  NSSLOWKEYPrivateKey *rsa_private_key,
+                                  const unsigned char *rsa_known_msg,
+                                  const unsigned int rsa_kmsg_length,
+                                  const unsigned char *rsa_known_signature)
+{
+    SECOidTag      shaOid;   /* SHA OID */
+    unsigned char  sha[HASH_LENGTH_MAX];    /* SHA digest */
+    unsigned int   shaLength = 0;           /* length of SHA */
+    unsigned int   rsa_bytes_signed;
+    unsigned char  rsa_computed_signature[FIPS_RSA_SIGNATURE_LENGTH];
+    SECStatus      rv;
+
+    if (shaAlg == HASH_AlgSHA1) {
+        if (SHA1_HashBuf(sha, rsa_known_msg, rsa_kmsg_length)
+                            != SECSuccess) {
+             goto loser;
+        }
+        shaLength = SHA1_LENGTH;
+        shaOid = SEC_OID_SHA1;
+    } else if (shaAlg == HASH_AlgSHA256) {
+        if (SHA256_HashBuf(sha, rsa_known_msg, rsa_kmsg_length)
+                            != SECSuccess) {
+             goto loser;
+        }
+        shaLength = SHA256_LENGTH;
+        shaOid = SEC_OID_SHA256;
+    } else if (shaAlg == HASH_AlgSHA384) {
+        if (SHA384_HashBuf(sha, rsa_known_msg, rsa_kmsg_length)
+                            != SECSuccess) {
+             goto loser;
+        }
+        shaLength = SHA384_LENGTH;
+        shaOid = SEC_OID_SHA384;
+    } else if (shaAlg == HASH_AlgSHA512) {
+        if (SHA512_HashBuf(sha, rsa_known_msg, rsa_kmsg_length)
+                            != SECSuccess) {
+             goto loser;
+        }
+        shaLength = SHA512_LENGTH;
+        shaOid = SEC_OID_SHA512;
+    } else {
+        goto loser;
+    }
+
+    /*************************************************/
+    /* RSA Single-Round Known Answer Signature Test. */
+    /*************************************************/
+
+    /* Perform RSA signature with the RSA private key. */
+    rv = RSA_HashSign( shaOid,
+                       rsa_private_key,
+                       rsa_computed_signature,
+                       &rsa_bytes_signed,
+                       FIPS_RSA_SIGNATURE_LENGTH,
+                       sha,
+                       shaLength);
+
+    if( ( rv != SECSuccess ) ||
+        ( rsa_bytes_signed != FIPS_RSA_SIGNATURE_LENGTH ) ||
+        ( PORT_Memcmp( rsa_computed_signature, rsa_known_signature,
+                       FIPS_RSA_SIGNATURE_LENGTH ) != 0 ) ) {
+        goto loser;
+    }
+
+    /****************************************************/
+    /* RSA Single-Round Known Answer Verification Test. */
+    /****************************************************/
+
+    /* Perform RSA verification with the RSA public key. */
+    rv = RSA_HashCheckSign( shaOid,
+                            rsa_public_key,
+                            rsa_computed_signature,
+                            rsa_bytes_signed,
+                            sha,
+                            shaLength);
+
+    if( rv != SECSuccess ) {
+         goto loser;
+    }
+    return( SECSuccess );
+
+loser:
+
+    return( SECFailure );
+
+}
+
+static CK_RV
+sftk_fips_RSA_PowerUpSelfTest( void )
+{
+    /* RSA Known Modulus used in both Public/Private Key Values (2048-bits). */
+    static const PRUint8 rsa_modulus[FIPS_RSA_MODULUS_LENGTH] = {
+                            0xb8, 0x15, 0x00, 0x33, 0xda, 0x0c, 0x9d, 0xa5,
+                            0x14, 0x8c, 0xde, 0x1f, 0x23, 0x07, 0x54, 0xe2,
+                            0xc6, 0xb9, 0x51, 0x04, 0xc9, 0x65, 0x24, 0x6e,
+                            0x0a, 0x46, 0x34, 0x5c, 0x37, 0x86, 0x6b, 0x88,
+                            0x24, 0x27, 0xac, 0xa5, 0x02, 0x79, 0xfb, 0xed,
+                            0x75, 0xc5, 0x3f, 0x6e, 0xdf, 0x05, 0x5f, 0x0f,
+                            0x20, 0x70, 0xa0, 0x5b, 0x85, 0xdb, 0xac, 0xb9,
+                            0x5f, 0x02, 0xc2, 0x64, 0x1e, 0x84, 0x5b, 0x3e,
+                            0xad, 0xbf, 0xf6, 0x2e, 0x51, 0xd6, 0xad, 0xf7,
+                            0xa7, 0x86, 0x75, 0x86, 0xec, 0xa7, 0xe1, 0xf7,
+                            0x08, 0xbf, 0xdc, 0x56, 0xb1, 0x3b, 0xca, 0xd8,
+                            0xfc, 0x51, 0xdf, 0x9a, 0x2a, 0x37, 0x06, 0xf2,
+                            0xd1, 0x6b, 0x9a, 0x5e, 0x2a, 0xe5, 0x20, 0x57,
+                            0x35, 0x9f, 0x1f, 0x98, 0xcf, 0x40, 0xc7, 0xd6,
+                            0x98, 0xdb, 0xde, 0xf5, 0x64, 0x53, 0xf7, 0x9d,
+                            0x45, 0xf3, 0xd6, 0x78, 0xb9, 0xe3, 0xa3, 0x20,
+                            0xcd, 0x79, 0x43, 0x35, 0xef, 0xd7, 0xfb, 0xb9,
+                            0x80, 0x88, 0x27, 0x2f, 0x63, 0xa8, 0x67, 0x3d,
+                            0x4a, 0xfa, 0x06, 0xc6, 0xd2, 0x86, 0x0b, 0xa7,
+                            0x28, 0xfd, 0xe0, 0x1e, 0x93, 0x4b, 0x17, 0x2e,
+                            0xb0, 0x11, 0x6f, 0xc6, 0x2b, 0x98, 0x0f, 0x15,
+                            0xe3, 0x87, 0x16, 0x7a, 0x7c, 0x67, 0x3e, 0x12,
+                            0x2b, 0xf8, 0xbe, 0x48, 0xc1, 0x97, 0x47, 0xf4,
+                            0x1f, 0x81, 0x80, 0x12, 0x28, 0xe4, 0x7b, 0x1e,
+                            0xb7, 0x00, 0xa4, 0xde, 0xaa, 0xfb, 0x0f, 0x77,
+                            0x84, 0xa3, 0xd6, 0xb2, 0x03, 0x48, 0xdd, 0x53,
+                            0x8b, 0x46, 0x41, 0x28, 0x52, 0xc4, 0x53, 0xf0,
+                            0x1c, 0x95, 0xd9, 0x36, 0xe0, 0x0f, 0x26, 0x46,
+                            0x9c, 0x61, 0x0e, 0x80, 0xca, 0x86, 0xaf, 0x39,
+                            0x95, 0xe5, 0x60, 0x43, 0x61, 0x3e, 0x2b, 0xb4,
+                            0xe8, 0xbd, 0x8d, 0x77, 0x62, 0xf5, 0x32, 0x43,
+                            0x2f, 0x4b, 0x65, 0x82, 0x14, 0xdd, 0x29, 0x5b};
+
+    /* RSA Known Public Key Values (24-bits). */
+    static const PRUint8 rsa_public_exponent[FIPS_RSA_PUBLIC_EXPONENT_LENGTH] 
+                                                       = { 0x01, 0x00, 0x01 };
+    /* RSA Known Private Key Values (version                 is    8-bits), */
+    /*                              (private exponent        is 2048-bits), */
+    /*                              (private prime0          is 1024-bits), */
+    /*                              (private prime1          is 1024-bits), */
+    /*                              (private prime exponent0 is 1024-bits), */
+    /*                              (private prime exponent1 is 1024-bits), */
+    /*                          and (private coefficient     is 1024-bits). */
+    static const PRUint8 rsa_version[] = { 0x00 };
+
+    static const PRUint8 rsa_private_exponent[FIPS_RSA_PRIVATE_EXPONENT_LENGTH]
+                         = {0x29, 0x08, 0x05, 0x53, 0x89, 0x76, 0xe6, 0x6c,
+                            0xb5, 0x77, 0xf0, 0xca, 0xdf, 0xf3, 0xf2, 0x67,
+                            0xda, 0x03, 0xd4, 0x9b, 0x4c, 0x88, 0xce, 0xe5,
+                            0xf8, 0x44, 0x4d, 0xc7, 0x80, 0x58, 0xe5, 0xff,
+                            0x22, 0x8f, 0xf5, 0x5b, 0x92, 0x81, 0xbe, 0x35,
+                            0xdf, 0xda, 0x67, 0x99, 0x3e, 0xfc, 0xe3, 0x83,
+                            0x6b, 0xa7, 0xaf, 0x16, 0xb7, 0x6f, 0x8f, 0xc0,
+                            0x81, 0xfd, 0x0b, 0x77, 0x65, 0x95, 0xfb, 0x00,
+                            0xad, 0x99, 0xec, 0x35, 0xc6, 0xe8, 0x23, 0x3e,
+                            0xe0, 0x88, 0x88, 0x09, 0xdb, 0x16, 0x50, 0xb7,
+                            0xcf, 0xab, 0x74, 0x61, 0x9e, 0x7f, 0xc5, 0x67,
+                            0x38, 0x56, 0xc7, 0x90, 0x85, 0x78, 0x5e, 0x84,
+                            0x21, 0x49, 0xea, 0xce, 0xb2, 0xa0, 0xff, 0xe4,
+                            0x70, 0x7f, 0x57, 0x7b, 0xa8, 0x36, 0xb8, 0x54,
+                            0x8d, 0x1d, 0xf5, 0x44, 0x9d, 0x68, 0x59, 0xf9,
+                            0x24, 0x6e, 0x85, 0x8f, 0xc3, 0x5f, 0x8a, 0x2c,
+                            0x94, 0xb7, 0xbc, 0x0e, 0xa5, 0xef, 0x93, 0x06,
+                            0x38, 0xcd, 0x07, 0x0c, 0xae, 0xb8, 0x44, 0x1a,
+                            0xd8, 0xe7, 0xf5, 0x9a, 0x1e, 0x9c, 0x18, 0xc7,
+                            0x6a, 0xc2, 0x7f, 0x28, 0x01, 0x4f, 0xb4, 0xb8,
+                            0x90, 0x97, 0x5a, 0x43, 0x38, 0xad, 0xe8, 0x95,
+                            0x68, 0x83, 0x1a, 0x1b, 0x10, 0x07, 0xe6, 0x02,
+                            0x52, 0x1f, 0xbf, 0x76, 0x6b, 0x46, 0xd6, 0xfb,
+                            0xc3, 0xbe, 0xb5, 0xac, 0x52, 0x53, 0x01, 0x1c,
+                            0xf3, 0xc5, 0xeb, 0x64, 0xf2, 0x1e, 0xc4, 0x38,
+                            0xe9, 0xaa, 0xd9, 0xc3, 0x72, 0x51, 0xa5, 0x44,
+                            0x58, 0x69, 0x0b, 0x1b, 0x98, 0x7f, 0xf2, 0x23,
+                            0xff, 0xeb, 0xf0, 0x75, 0x24, 0xcf, 0xc5, 0x1e,
+                            0xb8, 0x6a, 0xc5, 0x2f, 0x4f, 0x23, 0x50, 0x7d,
+                            0x15, 0x9d, 0x19, 0x7a, 0x0b, 0x82, 0xe0, 0x21,
+                            0x5b, 0x5f, 0x9d, 0x50, 0x2b, 0x83, 0xe4, 0x48,
+                            0xcc, 0x39, 0xe5, 0xfb, 0x13, 0x7b, 0x6f, 0x81 };
+
+    static const PRUint8 rsa_prime0[FIPS_RSA_PRIME0_LENGTH]   = {
+                            0xe4, 0xbf, 0x21, 0x62, 0x9b, 0xa9, 0x77, 0x40,
+                            0x8d, 0x2a, 0xce, 0xa1, 0x67, 0x5a, 0x4c, 0x96,
+                            0x45, 0x98, 0x67, 0xbd, 0x75, 0x22, 0x33, 0x6f,
+                            0xe6, 0xcb, 0x77, 0xde, 0x9e, 0x97, 0x7d, 0x96,
+                            0x8c, 0x5e, 0x5d, 0x34, 0xfb, 0x27, 0xfc, 0x6d,
+                            0x74, 0xdb, 0x9d, 0x2e, 0x6d, 0xf6, 0xea, 0xfc,
+                            0xce, 0x9e, 0xda, 0xa7, 0x25, 0xa2, 0xf4, 0x58,
+                            0x6d, 0x0a, 0x3f, 0x01, 0xc2, 0xb4, 0xab, 0x38,
+                            0xc1, 0x14, 0x85, 0xb6, 0xfa, 0x94, 0xc3, 0x85,
+                            0xf9, 0x3c, 0x2e, 0x96, 0x56, 0x01, 0xe7, 0xd6,
+                            0x14, 0x71, 0x4f, 0xfb, 0x4c, 0x85, 0x52, 0xc4,
+                            0x61, 0x1e, 0xa5, 0x1e, 0x96, 0x13, 0x0d, 0x8f,
+                            0x66, 0xae, 0xa0, 0xcd, 0x7d, 0x25, 0x66, 0x19,
+                            0x15, 0xc2, 0xcf, 0xc3, 0x12, 0x3c, 0xe8, 0xa4,
+                            0x52, 0x4c, 0xcb, 0x28, 0x3c, 0xc4, 0xbf, 0x95,
+                            0x33, 0xe3, 0x81, 0xea, 0x0c, 0x6c, 0xa2, 0x05};
+    static const PRUint8 rsa_prime1[FIPS_RSA_PRIME1_LENGTH]   = {
+                            0xce, 0x03, 0x94, 0xf4, 0xa9, 0x2c, 0x1e, 0x06,
+                            0xe7, 0x40, 0x30, 0x01, 0xf7, 0xbb, 0x68, 0x8c,
+                            0x27, 0xd2, 0x15, 0xe3, 0x28, 0x49, 0x5b, 0xa8,
+                            0xc1, 0x9a, 0x42, 0x7e, 0x31, 0xf9, 0x08, 0x34,
+                            0x81, 0xa2, 0x0f, 0x04, 0x61, 0x34, 0xe3, 0x36,
+                            0x92, 0xb1, 0x09, 0x2b, 0xe9, 0xef, 0x84, 0x88,
+                            0xbe, 0x9c, 0x98, 0x60, 0xa6, 0x60, 0x84, 0xe9,
+                            0x75, 0x6f, 0xcc, 0x81, 0xd1, 0x96, 0xef, 0xdd,
+                            0x2e, 0xca, 0xc4, 0xf5, 0x42, 0xfb, 0x13, 0x2b,
+                            0x57, 0xbf, 0x14, 0x5e, 0xc2, 0x7f, 0x77, 0x35,
+                            0x29, 0xc4, 0xe5, 0xe0, 0xf9, 0x6d, 0x15, 0x4a,
+                            0x42, 0x56, 0x1c, 0x3e, 0x0c, 0xc5, 0xce, 0x70,
+                            0x08, 0x63, 0x1e, 0x73, 0xdb, 0x7e, 0x74, 0x05,
+                            0x32, 0x01, 0xc6, 0x36, 0x32, 0x75, 0x6b, 0xed,
+                            0x9d, 0xfe, 0x7c, 0x7e, 0xa9, 0x57, 0xb4, 0xe9,
+                            0x22, 0xe4, 0xe7, 0xfe, 0x36, 0x07, 0x9b, 0xdf};
+    static const PRUint8 rsa_exponent0[FIPS_RSA_EXPONENT0_LENGTH] = {
+                            0x04, 0x5a, 0x3a, 0xa9, 0x64, 0xaa, 0xd9, 0xd1,
+                            0x09, 0x9e, 0x99, 0xe5, 0xea, 0x50, 0x86, 0x8a,
+                            0x89, 0x72, 0x77, 0xee, 0xdb, 0xee, 0xb5, 0xa9,
+                            0xd8, 0x6b, 0x60, 0xb1, 0x84, 0xb4, 0xff, 0x37,
+                            0xc1, 0x1d, 0xfe, 0x8a, 0x06, 0x89, 0x61, 0x3d,
+                            0x37, 0xef, 0x01, 0xd3, 0xa3, 0x56, 0x02, 0x6c,
+                            0xa3, 0x05, 0xd4, 0xc5, 0x3f, 0x6b, 0x15, 0x59,
+                            0x25, 0x61, 0xff, 0x86, 0xea, 0x0c, 0x84, 0x01,
+                            0x85, 0x72, 0xfd, 0x84, 0x58, 0xca, 0x41, 0xda,
+                            0x27, 0xbe, 0xe4, 0x68, 0x09, 0xe4, 0xe9, 0x63,
+                            0x62, 0x6a, 0x31, 0x8a, 0x67, 0x8f, 0x55, 0xde,
+                            0xd4, 0xb6, 0x3f, 0x90, 0x10, 0x6c, 0xf6, 0x62,
+                            0x17, 0x23, 0x15, 0x7e, 0x33, 0x76, 0x65, 0xb5,
+                            0xee, 0x7b, 0x11, 0x76, 0xf5, 0xbe, 0xe0, 0xf2,
+                            0x57, 0x7a, 0x8c, 0x97, 0x0c, 0x68, 0xf5, 0xf8,
+                            0x41, 0xcf, 0x7f, 0x66, 0x53, 0xac, 0x31, 0x7d};
+    static const PRUint8 rsa_exponent1[FIPS_RSA_EXPONENT1_LENGTH] = {
+                            0x93, 0x54, 0x14, 0x6e, 0x73, 0x9d, 0x4d, 0x4b,
+                            0xfa, 0x8c, 0xf8, 0xc8, 0x2f, 0x76, 0x22, 0xea,
+                            0x38, 0x80, 0x11, 0x8f, 0x05, 0xfc, 0x90, 0x44,
+                            0x3b, 0x50, 0x2a, 0x45, 0x3d, 0x4f, 0xaf, 0x02,
+                            0x7d, 0xc2, 0x7b, 0xa2, 0xd2, 0x31, 0x94, 0x5c,
+                            0x2e, 0xc3, 0xd4, 0x9f, 0x47, 0x09, 0x37, 0x6a,
+                            0xe3, 0x85, 0xf1, 0xa3, 0x0c, 0xd8, 0xf1, 0xb4,
+                            0x53, 0x7b, 0xc4, 0x71, 0x02, 0x86, 0x42, 0xbb,
+                            0x96, 0xff, 0x03, 0xa3, 0xb2, 0x67, 0x03, 0xea,
+                            0x77, 0x31, 0xfb, 0x4b, 0x59, 0x24, 0xf7, 0x07,
+                            0x59, 0xfb, 0xa9, 0xba, 0x1e, 0x26, 0x58, 0x97,
+                            0x66, 0xa1, 0x56, 0x49, 0x39, 0xb1, 0x2c, 0x55,
+                            0x0a, 0x6a, 0x78, 0x18, 0xba, 0xdb, 0xcf, 0xf4,
+                            0xf7, 0x32, 0x35, 0xa2, 0x04, 0xab, 0xdc, 0xa7,
+                            0x6d, 0xd9, 0xd5, 0x06, 0x6f, 0xec, 0x7d, 0x40,
+                            0x4c, 0xe8, 0x0e, 0xd0, 0xc9, 0xaa, 0xdf, 0x59};
+    static const PRUint8 rsa_coefficient[FIPS_RSA_COEFFICIENT_LENGTH] = {
+                            0x17, 0xd7, 0xf5, 0x0a, 0xf0, 0x68, 0x97, 0x96,
+                            0xc4, 0x29, 0x18, 0x77, 0x9a, 0x1f, 0xe3, 0xf3,
+                            0x12, 0x13, 0x0f, 0x7e, 0x7b, 0xb9, 0xc1, 0x91,
+                            0xf9, 0xc7, 0x08, 0x56, 0x5c, 0xa4, 0xbc, 0x83,
+                            0x71, 0xf9, 0x78, 0xd9, 0x2b, 0xec, 0xfe, 0x6b,
+                            0xdc, 0x2f, 0x63, 0xc9, 0xcd, 0x50, 0x14, 0x5b,
+                            0xd3, 0x6e, 0x85, 0x4d, 0x0c, 0xa2, 0x0b, 0xa0,
+                            0x09, 0xb6, 0xca, 0x34, 0x9c, 0xc2, 0xc1, 0x4a,
+                            0xb0, 0xbc, 0x45, 0x93, 0xa5, 0x7e, 0x99, 0xb5,
+                            0xbd, 0xe4, 0x69, 0x29, 0x08, 0x28, 0xd2, 0xcd,
+                            0xab, 0x24, 0x78, 0x48, 0x41, 0x26, 0x0b, 0x37,
+                            0xa3, 0x43, 0xd1, 0x95, 0x1a, 0xd6, 0xee, 0x22,
+                            0x1c, 0x00, 0x0b, 0xc2, 0xb7, 0xa4, 0xa3, 0x21,
+                            0xa9, 0xcd, 0xe4, 0x69, 0xd3, 0x45, 0x02, 0xb1,
+                            0xb7, 0x3a, 0xbf, 0x51, 0x35, 0x1b, 0x78, 0xc2,
+                            0xcf, 0x0c, 0x0d, 0x60, 0x09, 0xa9, 0x44, 0x02};
+
+    /* RSA Known Plaintext Message (1024-bits). */
+    static const PRUint8 rsa_known_plaintext_msg[FIPS_RSA_MESSAGE_LENGTH] = {
+                                         "Known plaintext message utilized"
+                                         "for RSA Encryption &  Decryption"
+                                         "blocks SHA256, SHA384  and      "
+                                         "SHA512 RSA Signature KAT tests. "
+                                         "Known plaintext message utilized"
+                                         "for RSA Encryption &  Decryption"
+                                         "blocks SHA256, SHA384  and      "
+                                         "SHA512 RSA Signature KAT  tests."};
+
+    /* RSA Known Ciphertext (2048-bits). */
+    static const PRUint8 rsa_known_ciphertext[] = {
+                            0x04, 0x12, 0x46, 0xe3, 0x6a, 0xee, 0xde, 0xdd,
+                            0x49, 0xa1, 0xd9, 0x83, 0xf7, 0x35, 0xf9, 0x70,
+                            0x88, 0x03, 0x2d, 0x01, 0x8b, 0xd1, 0xbf, 0xdb,
+                            0xe5, 0x1c, 0x85, 0xbe, 0xb5, 0x0b, 0x48, 0x45,
+                            0x7a, 0xf0, 0xa0, 0xe3, 0xa2, 0xbb, 0x4b, 0xf6,
+                            0x27, 0xd0, 0x1b, 0x12, 0xe3, 0x77, 0x52, 0x34,
+                            0x9e, 0x8e, 0x03, 0xd2, 0xf8, 0x79, 0x6e, 0x39,
+                            0x79, 0x53, 0x3c, 0x44, 0x14, 0x94, 0xbb, 0x8d,
+                            0xaa, 0x14, 0x44, 0xa0, 0x7b, 0xa5, 0x8c, 0x93,
+                            0x5f, 0x99, 0xa4, 0xa3, 0x6e, 0x7a, 0x38, 0x40,
+                            0x78, 0xfa, 0x36, 0x91, 0x5e, 0x9a, 0x9c, 0xba,
+                            0x1e, 0xd4, 0xf9, 0xda, 0x4b, 0x0f, 0xa8, 0xa3,
+                            0x1c, 0xf3, 0x3a, 0xd1, 0xa5, 0xb4, 0x51, 0x16,
+                            0xed, 0x4b, 0xcf, 0xec, 0x93, 0x7b, 0x90, 0x21,
+                            0xbc, 0x3a, 0xf4, 0x0b, 0xd1, 0x3a, 0x2b, 0xba,
+                            0xa6, 0x7d, 0x5b, 0x53, 0xd8, 0x64, 0xf9, 0x29,
+                            0x7b, 0x7f, 0x77, 0x3e, 0x51, 0x4c, 0x9a, 0x94,
+                            0xd2, 0x4b, 0x4a, 0x8d, 0x61, 0x74, 0x97, 0xae,
+                            0x53, 0x6a, 0xf4, 0x90, 0xc2, 0x2c, 0x49, 0xe2,
+                            0xfa, 0xeb, 0x91, 0xc5, 0xe5, 0x83, 0x13, 0xc9,
+                            0x44, 0x4b, 0x95, 0x2c, 0x57, 0x70, 0x15, 0x5c,
+                            0x64, 0x8d, 0x1a, 0xfd, 0x2a, 0xc7, 0xb2, 0x9c,
+                            0x5c, 0x99, 0xd3, 0x4a, 0xfd, 0xdd, 0xf6, 0x82,
+                            0x87, 0x8c, 0x5a, 0xc4, 0xa8, 0x0d, 0x2a, 0xef,
+                            0xc3, 0xa2, 0x7e, 0x8e, 0x67, 0x9f, 0x6f, 0x63,
+                            0xdb, 0xbb, 0x1d, 0x31, 0xc4, 0xbb, 0xbc, 0x13,
+                            0x3f, 0x54, 0xc6, 0xf6, 0xc5, 0x28, 0x32, 0xab,
+                            0x96, 0x42, 0x10, 0x36, 0x40, 0x92, 0xbb, 0x57,
+                            0x55, 0x38, 0xf5, 0x43, 0x7e, 0x43, 0xc4, 0x65,
+                            0x47, 0x64, 0xaa, 0x0f, 0x4c, 0xe9, 0x49, 0x16,
+                            0xec, 0x6a, 0x50, 0xfd, 0x14, 0x49, 0xca, 0xdb,
+                            0x44, 0x54, 0xca, 0xbe, 0xa3, 0x0e, 0x5f, 0xef};
+
+    /* RSA Known Signed Hash (2048-bits). */
+    static const PRUint8 rsa_known_sha256_signature[] = {
+                            0x8c, 0x2d, 0x2e, 0xfb, 0x37, 0xb5, 0x6f, 0x38,
+                            0x9f, 0x06, 0x5a, 0xf3, 0x8c, 0xa0, 0xd0, 0x7a,
+                            0xde, 0xcf, 0xf9, 0x14, 0x95, 0x59, 0xd3, 0x5f,
+                            0x51, 0x5d, 0x5d, 0xad, 0xd8, 0x71, 0x33, 0x50,
+                            0x1d, 0x03, 0x3b, 0x3a, 0x32, 0x00, 0xb4, 0xde,
+                            0x7f, 0xe4, 0xb1, 0xe5, 0x6b, 0x83, 0xf4, 0x80,
+                            0x10, 0x3b, 0xb8, 0x8a, 0xdb, 0xe8, 0x0a, 0x42,
+                            0x9e, 0x8d, 0xd7, 0xbe, 0xed, 0xde, 0x5a, 0x3d,
+                            0xc6, 0xdb, 0xfe, 0x49, 0x6a, 0xe9, 0x1e, 0x75,
+                            0x66, 0xf1, 0x3f, 0x9e, 0x3f, 0xff, 0x05, 0x65,
+                            0xde, 0xca, 0x62, 0x62, 0xf3, 0xec, 0x53, 0x09,
+                            0xa0, 0x37, 0xd5, 0x66, 0x62, 0x72, 0x14, 0xb6,
+                            0x51, 0x32, 0x67, 0x50, 0xc1, 0xe1, 0x2f, 0x9e,
+                            0x98, 0x4e, 0x53, 0x96, 0x55, 0x4b, 0xc4, 0x92,
+                            0xc3, 0xb4, 0x80, 0xf0, 0x35, 0xc9, 0x00, 0x4b,
+                            0x5c, 0x85, 0x92, 0xb1, 0xe8, 0x6e, 0xa5, 0x51,
+                            0x38, 0x9f, 0xc9, 0x11, 0xb6, 0x14, 0xdf, 0x34,
+                            0x64, 0x40, 0x82, 0x82, 0xde, 0x16, 0x69, 0x93,
+                            0x89, 0x4e, 0x5c, 0x32, 0xf2, 0x0a, 0x4e, 0x9e,
+                            0xbd, 0x63, 0x99, 0x4f, 0xf3, 0x15, 0x90, 0xc2,
+                            0xfe, 0x6f, 0xb7, 0xf4, 0xad, 0xd4, 0x8e, 0x0b,
+                            0xd2, 0xf5, 0x22, 0xd2, 0x71, 0x65, 0x13, 0xf7,
+                            0x82, 0x7b, 0x75, 0xb6, 0xc1, 0xb4, 0x45, 0xbd,
+                            0x8f, 0x95, 0xcf, 0x5b, 0x95, 0x32, 0xef, 0x18,
+                            0x5f, 0xd3, 0xdf, 0x7e, 0x22, 0xdd, 0x25, 0xeb,
+                            0xe1, 0xbf, 0x3b, 0x9a, 0x55, 0x75, 0x4f, 0x3c,
+                            0x38, 0x67, 0x57, 0x04, 0x04, 0x57, 0x27, 0xf6,
+                            0x34, 0x0e, 0x57, 0x8a, 0x7c, 0xff, 0x7d, 0xca,
+                            0x8c, 0x06, 0xf8, 0x9d, 0xdb, 0xe4, 0xd8, 0x19,
+                            0xdd, 0x4d, 0xfd, 0x8f, 0xa0, 0x06, 0x53, 0xe8,
+                            0x33, 0x00, 0x70, 0x3f, 0x6b, 0xc3, 0xbd, 0x9a,
+                            0x78, 0xb5, 0xa9, 0xef, 0x6d, 0xda, 0x67, 0x92};
+
+   /* RSA Known Signed Hash (2048-bits). */
+   static const PRUint8 rsa_known_sha384_signature[] = {
+                            0x20, 0x2d, 0x21, 0x3a, 0xaa, 0x1e, 0x05, 0x15,
+                            0x5c, 0xca, 0x84, 0x86, 0xc0, 0x15, 0x81, 0xdf,
+                            0xd4, 0x06, 0x9f, 0xe0, 0xc1, 0xed, 0xef, 0x0f,
+                            0xfe, 0xb3, 0xc3, 0xbb, 0x28, 0xa5, 0x56, 0xbf,
+                            0xe3, 0x11, 0x5c, 0xc2, 0xc0, 0x0b, 0xfa, 0xfa,
+                            0x3d, 0xd3, 0x06, 0x20, 0xe2, 0xc9, 0xe4, 0x66,
+                            0x28, 0xb7, 0xc0, 0x3b, 0x3c, 0x96, 0xc6, 0x49,
+                            0x3b, 0xcf, 0x86, 0x49, 0x31, 0xaf, 0x5b, 0xa3,
+                            0xec, 0x63, 0x10, 0xdf, 0xda, 0x2f, 0x68, 0xac,
+                            0x7b, 0x3a, 0x49, 0xfa, 0xe6, 0x0d, 0xfe, 0x37,
+                            0x17, 0x56, 0x8e, 0x5c, 0x48, 0x97, 0x43, 0xf7,
+                            0xa0, 0xbc, 0xe3, 0x4b, 0x42, 0xde, 0x58, 0x1d,
+                            0xd9, 0x5d, 0xb3, 0x08, 0x35, 0xbd, 0xa4, 0xe1,
+                            0x80, 0xc3, 0x64, 0xab, 0x21, 0x97, 0xad, 0xfb,
+                            0x71, 0xee, 0xa3, 0x3d, 0x9c, 0xaa, 0xfa, 0x16,
+                            0x60, 0x46, 0x32, 0xda, 0x44, 0x2e, 0x10, 0x92,
+                            0x20, 0xd8, 0x98, 0x80, 0x84, 0x75, 0x5b, 0x70,
+                            0x91, 0x00, 0x33, 0x19, 0x69, 0xc9, 0x2a, 0xec,
+                            0x3d, 0xe5, 0x5f, 0x0f, 0x9a, 0xa7, 0x97, 0x1f,
+                            0x79, 0xc3, 0x1d, 0x65, 0x74, 0x62, 0xc5, 0xa1,
+                            0x23, 0x65, 0x4b, 0x84, 0xa1, 0x03, 0x98, 0xf3,
+                            0xf1, 0x02, 0x24, 0xca, 0xe5, 0xd4, 0xc8, 0xa2,
+                            0x30, 0xad, 0x72, 0x7d, 0x29, 0x60, 0x1a, 0x8e,
+                            0x6f, 0x23, 0xa4, 0xda, 0x68, 0xa4, 0x45, 0x9c,
+                            0x39, 0x70, 0x44, 0x18, 0x4b, 0x73, 0xfe, 0xf8,
+                            0x33, 0x53, 0x1d, 0x7e, 0x93, 0x93, 0xac, 0xc7,
+                            0x1e, 0x6e, 0x6b, 0xfd, 0x9e, 0xba, 0xa6, 0x71,
+                            0x70, 0x47, 0x6a, 0xd6, 0x82, 0x32, 0xa2, 0x6e,
+                            0x20, 0x72, 0xb0, 0xba, 0xec, 0x91, 0xbb, 0x6b,
+                            0xcc, 0x84, 0x0a, 0x33, 0x2b, 0x8a, 0x8d, 0xeb,
+                            0x71, 0xcd, 0xca, 0x67, 0x1b, 0xad, 0x10, 0xd4,
+                            0xce, 0x4f, 0xc0, 0x29, 0xec, 0xfa, 0xed, 0xfa};
+
+   /* RSA Known Signed Hash (2048-bits). */
+   static const PRUint8 rsa_known_sha512_signature[] = {
+                            0x35, 0x0e, 0x74, 0x9d, 0xeb, 0xc7, 0x67, 0x31,
+                            0x9f, 0xff, 0x0b, 0xbb, 0x5e, 0x66, 0xb4, 0x2f,
+                            0xbf, 0x72, 0x60, 0x4f, 0xe9, 0xbd, 0xec, 0xc8,
+                            0x17, 0x79, 0x5f, 0x39, 0x83, 0xb4, 0x54, 0x2e,
+                            0x01, 0xb9, 0xd3, 0x20, 0x47, 0xcb, 0xd4, 0x42,
+                            0xf2, 0x6e, 0x36, 0xc1, 0x97, 0xad, 0xef, 0x8e,
+                            0xe6, 0x51, 0xee, 0x5e, 0x9e, 0x88, 0xb4, 0x9d,
+                            0xda, 0x3e, 0x77, 0x4b, 0xe8, 0xae, 0x48, 0x53,
+                            0x2c, 0xc4, 0xd3, 0x25, 0x6b, 0x23, 0xb7, 0x54,
+                            0x3c, 0x95, 0x8f, 0xfb, 0x6f, 0x6d, 0xc5, 0x56,
+                            0x39, 0x69, 0x28, 0x0e, 0x74, 0x9b, 0x31, 0xe8,
+                            0x76, 0x77, 0x2b, 0xc1, 0x44, 0x89, 0x81, 0x93,
+                            0xfc, 0xf6, 0xec, 0x5f, 0x8f, 0x89, 0xfc, 0x1d,
+                            0xa4, 0x53, 0x58, 0x8c, 0xe9, 0xc0, 0xc0, 0x26,
+                            0xe6, 0xdf, 0x6d, 0x27, 0xb1, 0x8e, 0x3e, 0xb6,
+                            0x47, 0xe1, 0x02, 0x96, 0xc2, 0x5f, 0x7f, 0x3d,
+                            0xc5, 0x6c, 0x2f, 0xea, 0xaa, 0x5e, 0x39, 0xfc,
+                            0x77, 0xca, 0x00, 0x02, 0x5c, 0x64, 0x7c, 0xce,
+                            0x7d, 0x63, 0x82, 0x05, 0xed, 0xf7, 0x5b, 0x55,
+                            0x58, 0xc0, 0xeb, 0x76, 0xd7, 0x95, 0x55, 0x37,
+                            0x85, 0x7d, 0x17, 0xad, 0xd2, 0x11, 0xfd, 0x97,
+                            0x48, 0xb5, 0xc2, 0x5e, 0xc7, 0x62, 0xc0, 0xe0,
+                            0x68, 0xa8, 0x61, 0x14, 0x41, 0xca, 0x25, 0x3a,
+                            0xec, 0x48, 0x54, 0x22, 0x83, 0x2b, 0x69, 0x54,
+                            0xfd, 0xc8, 0x99, 0x9a, 0xee, 0x37, 0x03, 0xa3,
+                            0x8f, 0x0f, 0x32, 0xb0, 0xaa, 0x74, 0x39, 0x04,
+                            0x7c, 0xd9, 0xc2, 0x8f, 0xbe, 0xf2, 0xc4, 0xbe,
+                            0xdd, 0x7a, 0x7a, 0x7f, 0x72, 0xd3, 0x80, 0x59,
+                            0x18, 0xa0, 0xa1, 0x2d, 0x6f, 0xa3, 0xa9, 0x48,
+                            0xed, 0x20, 0xa6, 0xea, 0xaa, 0x10, 0x83, 0x98,
+                            0x0c, 0x13, 0x69, 0x6e, 0xcd, 0x31, 0x6b, 0xd0,
+                            0x66, 0xa6, 0x5e, 0x30, 0x0c, 0x82, 0xd5, 0x81};
+
+    static const RSAPublicKey    bl_public_key = { NULL,
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus,         
+                                        FIPS_RSA_MODULUS_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent, 
+                                        FIPS_RSA_PUBLIC_EXPONENT_LENGTH }
+    };
+    static const RSAPrivateKey   bl_private_key = { NULL,
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_version,          
+                                        FIPS_RSA_PRIVATE_VERSION_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus,          
+                                        FIPS_RSA_MODULUS_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent,  
+                                        FIPS_RSA_PUBLIC_EXPONENT_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_private_exponent, 
+                                        FIPS_RSA_PRIVATE_EXPONENT_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_prime0,           
+                                        FIPS_RSA_PRIME0_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_prime1,           
+                                        FIPS_RSA_PRIME1_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_exponent0,        
+                                        FIPS_RSA_EXPONENT0_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_exponent1,        
+                                        FIPS_RSA_EXPONENT1_LENGTH },
+      { FIPS_RSA_TYPE, (unsigned char *)rsa_coefficient,      
+                                        FIPS_RSA_COEFFICIENT_LENGTH }
+    };
+
+    /* RSA variables. */
+#ifdef CREATE_TEMP_ARENAS
+    PLArenaPool *         rsa_public_arena;
+    PLArenaPool *         rsa_private_arena;
+#endif
+    NSSLOWKEYPublicKey *  rsa_public_key;
+    NSSLOWKEYPrivateKey * rsa_private_key;
+    SECStatus             rsa_status;
+
+    NSSLOWKEYPublicKey    low_public_key   = { NULL, NSSLOWKEYRSAKey, };
+    NSSLOWKEYPrivateKey   low_private_key  = { NULL, NSSLOWKEYRSAKey, };
+    PRUint8               rsa_computed_ciphertext[FIPS_RSA_ENCRYPT_LENGTH];
+    PRUint8               rsa_computed_plaintext[FIPS_RSA_DECRYPT_LENGTH];
+
+    /****************************************/
+    /* Compose RSA Public/Private Key Pair. */
+    /****************************************/
+
+    low_public_key.u.rsa  = bl_public_key;
+    low_private_key.u.rsa = bl_private_key;
+
+    rsa_public_key  = &low_public_key;
+    rsa_private_key = &low_private_key;
+
+#ifdef CREATE_TEMP_ARENAS
+    /* Create some space for the RSA public key. */
+    rsa_public_arena = PORT_NewArena( NSS_SOFTOKEN_DEFAULT_CHUNKSIZE );
+
+    if( rsa_public_arena == NULL ) {
+        PORT_SetError( SEC_ERROR_NO_MEMORY );
+        return( CKR_HOST_MEMORY );
+    }
+
+    /* Create some space for the RSA private key. */
+    rsa_private_arena = PORT_NewArena( NSS_SOFTOKEN_DEFAULT_CHUNKSIZE );
+
+    if( rsa_private_arena == NULL ) {
+        PORT_FreeArena( rsa_public_arena, PR_TRUE );
+        PORT_SetError( SEC_ERROR_NO_MEMORY );
+        return( CKR_HOST_MEMORY );
+    }
+
+    rsa_public_key->arena = rsa_public_arena;
+    rsa_private_key->arena = rsa_private_arena;
+#endif
+
+    /**************************************************/
+    /* RSA Single-Round Known Answer Encryption Test. */
+    /**************************************************/
+
+    /* Perform RSA Public Key Encryption. */
+    rsa_status = RSA_PublicKeyOp(&rsa_public_key->u.rsa,
+                                 rsa_computed_ciphertext,
+                                 rsa_known_plaintext_msg);
+
+    if( ( rsa_status != SECSuccess ) ||
+        ( PORT_Memcmp( rsa_computed_ciphertext, rsa_known_ciphertext,
+                       FIPS_RSA_ENCRYPT_LENGTH ) != 0 ) )
+        goto rsa_loser;
+
+    /**************************************************/
+    /* RSA Single-Round Known Answer Decryption Test. */
+    /**************************************************/
+
+    /* Perform RSA Private Key Decryption. */
+    rsa_status = RSA_PrivateKeyOp(&rsa_private_key->u.rsa,
+                                  rsa_computed_plaintext,
+                                  rsa_known_ciphertext);
+
+    if( ( rsa_status != SECSuccess ) ||
+        ( PORT_Memcmp( rsa_computed_plaintext, rsa_known_plaintext_msg,
+                       FIPS_RSA_DECRYPT_LENGTH ) != 0 ) )
+        goto rsa_loser;
+
+    rsa_status = sftk_fips_RSA_PowerUpSigSelfTest (HASH_AlgSHA256,
+                           rsa_public_key, rsa_private_key,
+                           rsa_known_plaintext_msg, FIPS_RSA_MESSAGE_LENGTH,
+                           rsa_known_sha256_signature);
+    if( rsa_status != SECSuccess )
+        goto rsa_loser;
+
+    rsa_status = sftk_fips_RSA_PowerUpSigSelfTest (HASH_AlgSHA384,
+                           rsa_public_key, rsa_private_key,
+                           rsa_known_plaintext_msg, FIPS_RSA_MESSAGE_LENGTH,
+                           rsa_known_sha384_signature);
+    if( rsa_status != SECSuccess )
+        goto rsa_loser;
+
+    rsa_status = sftk_fips_RSA_PowerUpSigSelfTest (HASH_AlgSHA512,
+                           rsa_public_key, rsa_private_key,
+                           rsa_known_plaintext_msg, FIPS_RSA_MESSAGE_LENGTH,
+                           rsa_known_sha512_signature);
+    if( rsa_status != SECSuccess )
+        goto rsa_loser;
+
+    /* Dispose of all RSA key material. */
+    nsslowkey_DestroyPublicKey( rsa_public_key );
+    nsslowkey_DestroyPrivateKey( rsa_private_key );
+
+    return( CKR_OK );
+
+rsa_loser:
+
+    nsslowkey_DestroyPublicKey( rsa_public_key );
+    nsslowkey_DestroyPrivateKey( rsa_private_key );
+
+    return( CKR_DEVICE_ERROR );
+}
+
+#ifdef NSS_ENABLE_ECC
+
+static CK_RV
+sftk_fips_ECDSA_Test(const PRUint8 *encodedParams, 
+                     unsigned int encodedParamsLen,
+                     const PRUint8 *knownSignature, 
+                     unsigned int knownSignatureLen) {
+
+    /* ECDSA Known Seed info for curves nistp256 and nistk283  */
+    static const PRUint8 ecdsa_Known_Seed[] = {
+                            0x6a, 0x9b, 0xf6, 0xf7, 0xce, 0xed, 0x79, 0x11,
+                            0xf0, 0xc7, 0xc8, 0x9a, 0xa5, 0xd1, 0x57, 0xb1,
+                            0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc,
+                            0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f};
+
+    static const PRUint8 msg[] = {
+                            "Firefox and ThunderBird are awesome!"};
+
+    unsigned char sha1[SHA1_LENGTH];  /* SHA-1 hash (160 bits) */
+    unsigned char sig[2*MAX_ECKEY_LEN];
+    SECItem signature, digest;
+    SECItem encodedparams;
+    ECParams *ecparams = NULL;
+    ECPrivateKey *ecdsa_private_key = NULL;
+    ECPublicKey ecdsa_public_key;
+    SECStatus ecdsaStatus = SECSuccess;
+
+    /* construct the ECDSA private/public key pair */
+    encodedparams.type = siBuffer;
+    encodedparams.data = (unsigned char *) encodedParams;
+    encodedparams.len = encodedParamsLen;
+    
+    if (EC_DecodeParams(&encodedparams, &ecparams) != SECSuccess) {
+        return( CKR_DEVICE_ERROR );
+    }
+
+    /* Generates a new EC key pair. The private key is a supplied
+     * random value (in seed) and the public key is the result of 
+     * performing a scalar point multiplication of that value with 
+     * the curve's base point.
+     */
+    ecdsaStatus = EC_NewKeyFromSeed(ecparams, &ecdsa_private_key, 
+                                   ecdsa_Known_Seed, 
+                                   sizeof(ecdsa_Known_Seed));
+    /* free the ecparams they are no longer needed */
+    PORT_FreeArena(ecparams->arena, PR_FALSE);
+    ecparams = NULL;
+    if (ecdsaStatus != SECSuccess) {
+        return ( CKR_DEVICE_ERROR );    
+    }
+
+    /* construct public key from private key. */
+    ecdsaStatus = EC_CopyParams(ecdsa_private_key->ecParams.arena, 
+                                &ecdsa_public_key.ecParams,
+                                &ecdsa_private_key->ecParams);
+    if (ecdsaStatus != SECSuccess) {
+        goto loser;
+    }
+    ecdsa_public_key.publicValue = ecdsa_private_key->publicValue;
+
+    /* validate public key value */
+    ecdsaStatus = EC_ValidatePublicKey(&ecdsa_public_key.ecParams, 
+                                       &ecdsa_public_key.publicValue);
+    if (ecdsaStatus != SECSuccess) {
+        goto loser;
+    }
+
+    /* validate public key value */
+    ecdsaStatus = EC_ValidatePublicKey(&ecdsa_private_key->ecParams, 
+                                       &ecdsa_private_key->publicValue);
+    if (ecdsaStatus != SECSuccess) {
+        goto loser;
+    }
+
+    /***************************************************/
+    /* ECDSA Single-Round Known Answer Signature Test. */
+    /***************************************************/
+    
+    ecdsaStatus = SHA1_HashBuf(sha1, msg, sizeof msg);
+    if (ecdsaStatus != SECSuccess) {
+        goto loser;
+    }
+    digest.type = siBuffer;
+    digest.data = sha1;
+    digest.len = SHA1_LENGTH;
+    
+    memset(sig, 0, sizeof sig);
+    signature.type = siBuffer;
+    signature.data = sig;
+    signature.len = sizeof sig;
+    
+    ecdsaStatus = ECDSA_SignDigestWithSeed(ecdsa_private_key, &signature, 
+                         &digest, ecdsa_Known_Seed, sizeof ecdsa_Known_Seed);
+    if (ecdsaStatus != SECSuccess) {
+        goto loser;
+    }
+
+    if( ( signature.len != knownSignatureLen ) ||
+        ( PORT_Memcmp( signature.data, knownSignature,
+                    knownSignatureLen ) != 0 ) ) {
+        ecdsaStatus = SECFailure;
+        goto loser;
+    }
+    
+    /******************************************************/
+    /* ECDSA Single-Round Known Answer Verification Test. */
+    /******************************************************/
+
+    /* Perform ECDSA verification process. */
+    ecdsaStatus = ECDSA_VerifyDigest(&ecdsa_public_key, &signature, &digest);
+
+loser:
+    /* free the memory for the private key arena*/
+    if (ecdsa_private_key != NULL) {
+        PORT_FreeArena(ecdsa_private_key->ecParams.arena, PR_FALSE);
+    }
+
+    if (ecdsaStatus != SECSuccess) {
+        return CKR_DEVICE_ERROR ;
+    }
+    return( CKR_OK );
+}
+
+static CK_RV
+sftk_fips_ECDSA_PowerUpSelfTest() {
+
+   /* ECDSA Known curve nistp256 == SEC_OID_SECG_EC_SECP256R1 params */
+    static const PRUint8 ecdsa_known_P256_EncodedParams[] = {
+                            0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x03,
+                            0x01,0x07};
+
+    static const PRUint8 ecdsa_known_P256_signature[] = {
+                            0x07,0xb1,0xcb,0x57,0x20,0xa7,0x10,0xd6, 
+                            0x9d,0x37,0x4b,0x1c,0xdc,0x35,0x90,0xff, 
+                            0x1a,0x2d,0x98,0x95,0x1b,0x2f,0xeb,0x7f, 
+                            0xbb,0x81,0xca,0xc0,0x69,0x75,0xea,0xc5,
+                            0x59,0x6a,0x62,0x49,0x3d,0x50,0xc9,0xe1, 
+                            0x27,0x3b,0xff,0x9b,0x13,0x66,0x67,0xdd, 
+                            0x7d,0xd1,0x0d,0x2d,0x7c,0x44,0x04,0x1b, 
+                            0x16,0x21,0x12,0xc5,0xcb,0xbd,0x9e,0x75};
+
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+    /* ECDSA Known curve nistk283 == SEC_OID_SECG_EC_SECT283K1 params */
+    static const PRUint8 ecdsa_known_K283_EncodedParams[] = {
+                            0x06,0x05,0x2b,0x81,0x04,0x00,0x10};
+                         
+    static const PRUint8 ecdsa_known_K283_signature[] = {
+                            0x00,0x45,0x88,0xc0,0x79,0x09,0x07,0xd1, 
+                            0x4e,0x88,0xe6,0xd5,0x2f,0x22,0x04,0x74, 
+                            0x35,0x24,0x65,0xe8,0x15,0xde,0x90,0x66, 
+                            0x94,0x70,0xdd,0x3a,0x14,0x70,0x02,0xd1,
+                            0xef,0x86,0xbd,0x15,0x00,0xd9,0xdc,0xfc, 
+                            0x87,0x2e,0x7c,0x99,0xe2,0xe3,0x79,0xb8, 
+                            0xd9,0x10,0x49,0x78,0x4b,0x59,0x8b,0x05, 
+                            0x77,0xec,0x6c,0xe8,0x35,0xe6,0x2e,0xa9,
+                            0xf9,0x77,0x1f,0x71,0x86,0xa5,0x4a,0xd0};
+#endif
+
+    CK_RV crv;
+
+    /* ECDSA GF(p) prime field curve test */
+    crv = sftk_fips_ECDSA_Test(ecdsa_known_P256_EncodedParams,
+                               sizeof ecdsa_known_P256_EncodedParams,
+                               ecdsa_known_P256_signature,
+                               sizeof ecdsa_known_P256_signature );
+    if (crv != CKR_OK) {
+        return( CKR_DEVICE_ERROR );
+    }
+
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+    /* ECDSA GF(2m) binary field curve test */
+    crv = sftk_fips_ECDSA_Test(ecdsa_known_K283_EncodedParams,
+                               sizeof ecdsa_known_K283_EncodedParams,
+                               ecdsa_known_K283_signature,
+                               sizeof ecdsa_known_K283_signature );
+    if (crv != CKR_OK) {
+        return( CKR_DEVICE_ERROR );
+    }
+#endif
+
+    return( CKR_OK );
+}
+
+#endif    /* NSS_ENABLE_ECC */
+
+static CK_RV
+sftk_fips_DSA_PowerUpSelfTest( void )
+{
+    /* DSA Known P (1024-bits), Q (160-bits), and G (1024-bits) Values. */
+    static const PRUint8 dsa_P[] = {
+         0x80,0xb0,0xd1,0x9d,0x6e,0xa4,0xf3,0x28, 
+         0x9f,0x24,0xa9,0x8a,0x49,0xd0,0x0c,0x63, 
+         0xe8,0x59,0x04,0xf9,0x89,0x4a,0x5e,0xc0, 
+         0x6d,0xd2,0x67,0x6b,0x37,0x81,0x83,0x0c,
+         0xfe,0x3a,0x8a,0xfd,0xa0,0x3b,0x08,0x91, 
+         0x1c,0xcb,0xb5,0x63,0xb0,0x1c,0x70,0xd0, 
+         0xae,0xe1,0x60,0x2e,0x12,0xeb,0x54,0xc7, 
+         0xcf,0xc6,0xcc,0xae,0x97,0x52,0x32,0x63,
+         0xd3,0xeb,0x55,0xea,0x2f,0x4c,0xd5,0xd7, 
+         0x3f,0xda,0xec,0x49,0x27,0x0b,0x14,0x56, 
+         0xc5,0x09,0xbe,0x4d,0x09,0x15,0x75,0x2b, 
+         0xa3,0x42,0x0d,0x03,0x71,0xdf,0x0f,0xf4,
+         0x0e,0xe9,0x0c,0x46,0x93,0x3d,0x3f,0xa6, 
+         0x6c,0xdb,0xca,0xe5,0xac,0x96,0xc8,0x64, 
+         0x5c,0xec,0x4b,0x35,0x65,0xfc,0xfb,0x5a, 
+         0x1b,0x04,0x1b,0xa1,0x0e,0xfd,0x88,0x15};
+        
+    static const PRUint8 dsa_Q[] = {
+         0xad,0x22,0x59,0xdf,0xe5,0xec,0x4c,0x6e, 
+         0xf9,0x43,0xf0,0x4b,0x2d,0x50,0x51,0xc6, 
+         0x91,0x99,0x8b,0xcf};
+        
+    static const PRUint8 dsa_G[] = {
+         0x78,0x6e,0xa9,0xd8,0xcd,0x4a,0x85,0xa4, 
+         0x45,0xb6,0x6e,0x5d,0x21,0x50,0x61,0xf6, 
+         0x5f,0xdf,0x5c,0x7a,0xde,0x0d,0x19,0xd3, 
+         0xc1,0x3b,0x14,0xcc,0x8e,0xed,0xdb,0x17,
+         0xb6,0xca,0xba,0x86,0xa9,0xea,0x51,0x2d, 
+         0xc1,0xa9,0x16,0xda,0xf8,0x7b,0x59,0x8a, 
+         0xdf,0xcb,0xa4,0x67,0x00,0x44,0xea,0x24, 
+         0x73,0xe5,0xcb,0x4b,0xaf,0x2a,0x31,0x25,
+         0x22,0x28,0x3f,0x16,0x10,0x82,0xf7,0xeb, 
+         0x94,0x0d,0xdd,0x09,0x22,0x14,0x08,0x79, 
+         0xba,0x11,0x0b,0xf1,0xff,0x2d,0x67,0xac, 
+         0xeb,0xb6,0x55,0x51,0x69,0x97,0xa7,0x25,
+         0x6b,0x9c,0xa0,0x9b,0xd5,0x08,0x9b,0x27, 
+         0x42,0x1c,0x7a,0x69,0x57,0xe6,0x2e,0xed, 
+         0xa9,0x5b,0x25,0xe8,0x1f,0xd2,0xed,0x1f, 
+         0xdf,0xe7,0x80,0x17,0xba,0x0d,0x4d,0x38};
+
+    /* DSA Known Random Values (known random key block       is 160-bits)  */
+    /*                     and (known random signature block is 160-bits). */
+    static const PRUint8 dsa_known_random_key_block[] = {
+                                                      "Mozilla Rules World!"};
+    static const PRUint8 dsa_known_random_signature_block[] = {
+                                                      "Random DSA Signature"};
+
+    /* DSA Known Digest (160-bits) */
+    static const PRUint8 dsa_known_digest[] = { "DSA Signature Digest" };
+
+    /* DSA Known Signature (320-bits). */
+    static const PRUint8 dsa_known_signature[] = {
+        0x25,0x7c,0x3a,0x79,0x32,0x45,0xb7,0x32, 
+        0x70,0xca,0x62,0x63,0x2b,0xf6,0x29,0x2c, 
+        0x22,0x2a,0x03,0xce,0x48,0x15,0x11,0x72, 
+        0x7b,0x7e,0xf5,0x7a,0xf3,0x10,0x3b,0xde,
+        0x34,0xc1,0x9e,0xd7,0x27,0x9e,0x77,0x38};
+
+    /* DSA variables. */
+    DSAPrivateKey *        dsa_private_key;
+    SECStatus              dsa_status;
+    SECItem                dsa_signature_item;
+    SECItem                dsa_digest_item;
+    DSAPublicKey           dsa_public_key;
+    PRUint8                dsa_computed_signature[FIPS_DSA_SIGNATURE_LENGTH];
+    static const PQGParams dsa_pqg = { NULL,
+			    { FIPS_DSA_TYPE, (unsigned char *)dsa_P, FIPS_DSA_PRIME_LENGTH },
+			    { FIPS_DSA_TYPE, (unsigned char *)dsa_Q, FIPS_DSA_SUBPRIME_LENGTH },
+			    { FIPS_DSA_TYPE, (unsigned char *)dsa_G, FIPS_DSA_BASE_LENGTH }};
+
+    /*******************************************/
+    /* Generate a DSA public/private key pair. */
+    /*******************************************/
+
+    /* Generate a DSA public/private key pair. */
+    dsa_status = DSA_NewKeyFromSeed(&dsa_pqg, dsa_known_random_key_block,
+                                    &dsa_private_key);
+
+    if( dsa_status != SECSuccess )
+        return( CKR_HOST_MEMORY );
+
+    /* construct public key from private key. */
+    dsa_public_key.params      = dsa_private_key->params;
+    dsa_public_key.publicValue = dsa_private_key->publicValue;
+
+    /*************************************************/
+    /* DSA Single-Round Known Answer Signature Test. */
+    /*************************************************/
+
+    dsa_signature_item.data = dsa_computed_signature;
+    dsa_signature_item.len  = sizeof dsa_computed_signature;
+
+    dsa_digest_item.data    = (unsigned char *)dsa_known_digest;
+    dsa_digest_item.len     = SHA1_LENGTH;
+
+    /* Perform DSA signature process. */
+    dsa_status = DSA_SignDigestWithSeed( dsa_private_key, 
+                                         &dsa_signature_item,
+                                         &dsa_digest_item,
+                                         dsa_known_random_signature_block );
+
+    if( ( dsa_status != SECSuccess ) ||
+        ( dsa_signature_item.len != FIPS_DSA_SIGNATURE_LENGTH ) ||
+        ( PORT_Memcmp( dsa_computed_signature, dsa_known_signature,
+                       FIPS_DSA_SIGNATURE_LENGTH ) != 0 ) ) {
+        dsa_status = SECFailure;
+    } else {
+
+    /****************************************************/
+    /* DSA Single-Round Known Answer Verification Test. */
+    /****************************************************/
+
+    /* Perform DSA verification process. */
+    dsa_status = DSA_VerifyDigest( &dsa_public_key, 
+                                   &dsa_signature_item,
+                                   &dsa_digest_item);
+    }
+
+    PORT_FreeArena(dsa_private_key->params.arena, PR_TRUE);
+    /* Don't free public key, it uses same arena as private key */
+
+    /* Verify DSA signature. */
+    if( dsa_status != SECSuccess )
+        return( CKR_DEVICE_ERROR );
+
+    return( CKR_OK );
+
+
+}
+
+static CK_RV
+sftk_fips_RNG_PowerUpSelfTest( void )
+{
+   static const PRUint8 entropy[] = {
+			0x8e,0x9c,0x0d,0x25,0x75,0x22,0x04,0xf9,
+			0xc5,0x79,0x10,0x8b,0x23,0x79,0x37,0x14,
+			0x9f,0x2c,0xc7,0x0b,0x39,0xf8,0xee,0xef,
+			0x95,0x0c,0x97,0x59,0xfc,0x0a,0x85,0x41,
+			0x76,0x9d,0x6d,0x67,0x00,0x4e,0x19,0x12,
+			0x02,0x16,0x53,0xea,0xf2,0x73,0xd7,0xd6,
+			0x7f,0x7e,0xc8,0xae,0x9c,0x09,0x99,0x7d,
+			0xbb,0x9e,0x48,0x7f,0xbb,0x96,0x46,0xb3,
+			0x03,0x75,0xf8,0xc8,0x69,0x45,0x3f,0x97,
+			0x5e,0x2e,0x48,0xe1,0x5d,0x58,0x97,0x4c };
+   static const PRUint8 rng_known_result[] = {
+			0x16,0xe1,0x8c,0x57,0x21,0xd8,0xf1,0x7e,
+			0x5a,0xa0,0x16,0x0b,0x7e,0xa6,0x25,0xb4,
+			0x24,0x19,0xdb,0x54,0xfa,0x35,0x13,0x66,
+			0xbb,0xaa,0x2a,0x1b,0x22,0x33,0x2e,0x4a,
+			0x14,0x07,0x9d,0x52,0xfc,0x73,0x61,0x48,
+			0xac,0xc1,0x22,0xfc,0xa4,0xfc,0xac,0xa4,
+			0xdb,0xda,0x5b,0x27,0x33,0xc4,0xb3 };
+   static const PRUint8 reseed_entropy[] = {
+			0xc6,0x0b,0x0a,0x30,0x67,0x07,0xf4,0xe2,
+			0x24,0xa7,0x51,0x6f,0x5f,0x85,0x3e,0x5d,
+			0x67,0x97,0xb8,0x3b,0x30,0x9c,0x7a,0xb1,
+			0x52,0xc6,0x1b,0xc9,0x46,0xa8,0x62,0x79 };
+   static const PRUint8 additional_input[] = {
+			0x86,0x82,0x28,0x98,0xe7,0xcb,0x01,0x14,
+			0xae,0x87,0x4b,0x1d,0x99,0x1b,0xc7,0x41,
+			0x33,0xff,0x33,0x66,0x40,0x95,0x54,0xc6,
+			0x67,0x4d,0x40,0x2a,0x1f,0xf9,0xeb,0x65 };
+   static const PRUint8 rng_reseed_result[] = {
+			0x02,0x0c,0xc6,0x17,0x86,0x49,0xba,0xc4,
+			0x7b,0x71,0x35,0x05,0xf0,0xdb,0x4a,0xc2,
+			0x2c,0x38,0xc1,0xa4,0x42,0xe5,0x46,0x4a,
+			0x7d,0xf0,0xbe,0x47,0x88,0xb8,0x0e,0xc6,
+			0x25,0x2b,0x1d,0x13,0xef,0xa6,0x87,0x96,
+			0xa3,0x7d,0x5b,0x80,0xc2,0x38,0x76,0x61,
+			0xc7,0x80,0x5d,0x0f,0x05,0x76,0x85 };
+   static const PRUint8 Q[] = {
+			0x85,0x89,0x9c,0x77,0xa3,0x79,0xff,0x1a,
+			0x86,0x6f,0x2f,0x3e,0x2e,0xf9,0x8c,0x9c,
+			0x9d,0xef,0xeb,0xed};
+   static const PRUint8 GENX[] = {
+			0x65,0x48,0xe3,0xca,0xac,0x64,0x2d,0xf7,
+			0x7b,0xd3,0x4e,0x79,0xc9,0x7d,0xa6,0xa8,
+			0xa2,0xc2,0x1f,0x8f,0xe9,0xb9,0xd3,0xa1,
+			0x3f,0xf7,0x0c,0xcd,0xa6,0xca,0xbf,0xce,
+			0x84,0x0e,0xb6,0xf1,0x0d,0xbe,0xa9,0xa3};
+   static const PRUint8 rng_known_DSAX[] = {
+			0x7a,0x86,0xf1,0x7f,0xbd,0x4e,0x6e,0xd9,
+			0x0a,0x26,0x21,0xd0,0x19,0xcb,0x86,0x73,
+			0x10,0x1f,0x60,0xd7};
+
+
+
+   SECStatus rng_status = SECSuccess;
+   PR_STATIC_ASSERT(sizeof(rng_known_result) >= sizeof(rng_reseed_result));
+   PRUint8 result[sizeof(rng_known_result)];
+   PRUint8 DSAX[FIPS_DSA_SUBPRIME_LENGTH];
+
+   /********************************************/
+   /* Generate random bytes with a known seed. */
+   /********************************************/
+   rng_status = PRNGTEST_Instantiate(entropy, sizeof entropy, 
+				     NULL, 0, NULL, 0);
+   if (rng_status != SECSuccess) {
+	return ( CKR_DEVICE_ERROR );
+   }
+   rng_status = PRNGTEST_Generate(result, sizeof rng_known_result, NULL, 0);
+   if ( ( rng_status != SECSuccess)  ||
+        ( PORT_Memcmp( result, rng_known_result,
+                       sizeof rng_known_result ) != 0 ) ) {
+	PRNGTEST_Uninstantiate();
+	return ( CKR_DEVICE_ERROR );
+   }
+   rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof reseed_entropy,
+				additional_input, sizeof additional_input);
+   if (rng_status != SECSuccess) {
+	PRNGTEST_Uninstantiate();
+	return ( CKR_DEVICE_ERROR );
+   }
+   rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
+   if ( ( rng_status != SECSuccess)  ||
+        ( PORT_Memcmp( result, rng_reseed_result,
+                       sizeof rng_reseed_result ) != 0 ) ) {
+	PRNGTEST_Uninstantiate();
+	return ( CKR_DEVICE_ERROR );
+   }
+   rng_status = PRNGTEST_Uninstantiate();
+   if (rng_status != SECSuccess) {
+	return ( CKR_DEVICE_ERROR );
+   }
+  
+   /*******************************************/
+   /* Generate DSAX fow given Q.              */
+   /*******************************************/
+
+   rng_status = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
+
+   /* Verify DSAX to perform the RNG integrity check */
+   if( ( rng_status != SECSuccess ) ||
+       ( PORT_Memcmp( DSAX, rng_known_DSAX,
+                      (FIPS_DSA_SUBPRIME_LENGTH) ) != 0 ) )
+       return( CKR_DEVICE_ERROR );
+       
+   return( CKR_OK ); 
+}
+
+static CK_RV
+sftk_fipsSoftwareIntegrityTest(void)
+{
+    CK_RV crv = CKR_OK;
+
+    /* make sure that our check file signatures are OK */
+    if( !BLAPI_VerifySelf( NULL ) || 
+	!BLAPI_SHVerify( SOFTOKEN_LIB_NAME, (PRFuncPtr) sftk_fips_HMAC ) ) {
+	crv = CKR_DEVICE_ERROR; /* better error code? checksum error? */
+    }
+    return crv;
+}
+
+CK_RV
+sftk_fipsPowerUpSelfTest( void )
+{
+    CK_RV rv;
+
+    /* RC2 Power-Up SelfTest(s). */
+    rv = sftk_fips_RC2_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* RC4 Power-Up SelfTest(s). */
+    rv = sftk_fips_RC4_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* DES Power-Up SelfTest(s). */
+    rv = sftk_fips_DES_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* DES3 Power-Up SelfTest(s). */
+    rv = sftk_fips_DES3_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+ 
+    /* AES Power-Up SelfTest(s) for 128-bit key. */
+    rv = sftk_fips_AES_PowerUpSelfTest(FIPS_AES_128_KEY_SIZE);
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* AES Power-Up SelfTest(s) for 192-bit key. */
+    rv = sftk_fips_AES_PowerUpSelfTest(FIPS_AES_192_KEY_SIZE);
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* AES Power-Up SelfTest(s) for 256-bit key. */
+    rv = sftk_fips_AES_PowerUpSelfTest(FIPS_AES_256_KEY_SIZE);
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* MD2 Power-Up SelfTest(s). */
+    rv = sftk_fips_MD2_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* MD5 Power-Up SelfTest(s). */
+    rv = sftk_fips_MD5_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* SHA-X Power-Up SelfTest(s). */
+    rv = sftk_fips_SHA_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* HMAC SHA-X Power-Up SelfTest(s). */
+    rv = sftk_fips_HMAC_PowerUpSelfTest();
+ 
+    if( rv != CKR_OK )
+        return rv;
+
+    /* RSA Power-Up SelfTest(s). */
+    rv = sftk_fips_RSA_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* DSA Power-Up SelfTest(s). */
+    rv = sftk_fips_DSA_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* RNG Power-Up SelfTest(s). */
+    rv = sftk_fips_RNG_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+    
+#ifdef NSS_ENABLE_ECC
+    /* ECDSA Power-Up SelfTest(s). */
+    rv = sftk_fips_ECDSA_PowerUpSelfTest();
+
+    if( rv != CKR_OK )
+        return rv;
+#endif
+
+    /* Software/Firmware Integrity Test. */
+    rv = sftk_fipsSoftwareIntegrityTest();
+
+    if( rv != CKR_OK )
+        return rv;
+
+    /* Passed Power-Up SelfTest(s). */
+    return( CKR_OK );
+}
+
diff --git a/mozilla/security/nss/lib/softoken/fipstokn.c b/mozilla/security/nss/lib/softoken/fipstokn.c
new file mode 100644
index 0000000..96fc6f2
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/fipstokn.c
@@ -0,0 +1,1607 @@
+/* ***** 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 ***** */
+/*
+ * This file implements PKCS 11 on top of our existing security modules
+ *
+ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
+ *   This implementation has two slots:
+ *	slot 1 is our generic crypto support. It does not require login
+ *   (unless you've enabled FIPS). It supports Public Key ops, and all they
+ *   bulk ciphers and hashes. It can also support Private Key ops for imported
+ *   Private keys. It does not have any token storage.
+ *	slot 2 is our private key support. It requires a login before use. It
+ *   can store Private Keys and Certs as token objects. Currently only private
+ *   keys and their associated Certificates are saved on the token.
+ *
+ *   In this implementation, session objects are only visible to the session
+ *   that created or generated them.
+ */
+#include "seccomon.h"
+#include "softoken.h"
+#include "lowkeyi.h"
+#include "pkcs11.h"
+#include "pkcs11i.h"
+#include "prenv.h"
+#include "prprf.h"
+
+#include <ctype.h>
+
+#ifdef XP_UNIX
+#define NSS_AUDIT_WITH_SYSLOG 1
+#include <syslog.h>
+#include <unistd.h>
+#endif
+
+#ifdef SOLARIS
+#include <bsm/libbsm.h>
+#define AUE_FIPS_AUDIT 34444
+#endif
+
+#ifdef LINUX
+#include <pthread.h>
+#include <dlfcn.h>
+#define LIBAUDIT_NAME "libaudit.so.0"
+#ifndef AUDIT_CRYPTO_TEST_USER
+#define AUDIT_CRYPTO_TEST_USER          2400 /* Crypto test results */
+#define AUDIT_CRYPTO_PARAM_CHANGE_USER  2401 /* Crypto attribute change */
+#define AUDIT_CRYPTO_LOGIN              2402 /* Logged in as crypto officer */
+#define AUDIT_CRYPTO_LOGOUT             2403 /* Logged out from crypto */
+#define AUDIT_CRYPTO_KEY_USER           2404 /* Create,delete,negotiate */
+#define AUDIT_CRYPTO_FAILURE_USER       2405 /* Fail decrypt,encrypt,randomize */
+#endif
+static void *libaudit_handle;
+static int (*audit_open_func)(void);
+static void (*audit_close_func)(int fd);
+static int (*audit_log_user_message_func)(int audit_fd, int type,
+    const char *message, const char *hostname, const char *addr,
+    const char *tty, int result);
+static int (*audit_send_user_message_func)(int fd, int type,
+    const char *message);
+
+static pthread_once_t libaudit_once_control = PTHREAD_ONCE_INIT;
+
+static void
+libaudit_init(void)
+{
+    libaudit_handle = dlopen(LIBAUDIT_NAME, RTLD_LAZY);
+    if (!libaudit_handle) {
+	return;
+    }
+    audit_open_func = dlsym(libaudit_handle, "audit_open");
+    audit_close_func = dlsym(libaudit_handle, "audit_close");
+    /*
+     * audit_send_user_message is the older function.
+     * audit_log_user_message, if available, is preferred.
+     */
+    audit_log_user_message_func = dlsym(libaudit_handle,
+					"audit_log_user_message");
+    if (!audit_log_user_message_func) {
+	audit_send_user_message_func = dlsym(libaudit_handle,
+					     "audit_send_user_message");
+    }
+    if (!audit_open_func || !audit_close_func ||
+	(!audit_log_user_message_func && !audit_send_user_message_func)) {
+	dlclose(libaudit_handle);
+	libaudit_handle = NULL;
+	audit_open_func = NULL;
+	audit_close_func = NULL;
+	audit_log_user_message_func = NULL;
+	audit_send_user_message_func = NULL;
+    }
+}
+#endif /* LINUX */
+
+
+/*
+ * ******************** Password Utilities *******************************
+ */
+static PRBool isLoggedIn = PR_FALSE;
+PRBool sftk_fatalError = PR_FALSE;
+
+/*
+ * This function returns
+ *   - CKR_PIN_INVALID if the password/PIN is not a legal UTF8 string
+ *   - CKR_PIN_LEN_RANGE if the password/PIN is too short or does not
+ *     consist of characters from three or more character classes.
+ *   - CKR_OK otherwise
+ *
+ * The minimum password/PIN length is FIPS_MIN_PIN Unicode characters.
+ * We define five character classes: digits (0-9), ASCII lowercase letters,
+ * ASCII uppercase letters, ASCII non-alphanumeric characters (such as
+ * space and punctuation marks), and non-ASCII characters.  If an ASCII
+ * uppercase letter is the first character of the password/PIN, the
+ * uppercase letter is not counted toward its character class.  Similarly,
+ * if a digit is the last character of the password/PIN, the digit is not
+ * counted toward its character class.
+ *
+ * Although NSC_SetPIN and NSC_InitPIN already do the maximum and minimum
+ * password/PIN length checks, they check the length in bytes as opposed
+ * to characters.  To meet the minimum password/PIN guessing probability
+ * requirements in FIPS 140-2, we need to check the length in characters.
+ */
+static CK_RV sftk_newPinCheck(CK_CHAR_PTR pPin, CK_ULONG ulPinLen) {
+    unsigned int i;
+    int nchar = 0;      /* number of characters */
+    int ntrail = 0;     /* number of trailing bytes to follow */
+    int ndigit = 0;     /* number of decimal digits */
+    int nlower = 0;     /* number of ASCII lowercase letters */
+    int nupper = 0;     /* number of ASCII uppercase letters */
+    int nnonalnum = 0;  /* number of ASCII non-alphanumeric characters */
+    int nnonascii = 0;  /* number of non-ASCII characters */
+    int nclass;         /* number of character classes */
+
+    for (i = 0; i < ulPinLen; i++) {
+	unsigned int byte = pPin[i];
+
+	if (ntrail) {
+	    if ((byte & 0xc0) != 0x80) {
+		/* illegal */
+		nchar = -1;
+		break;
+	    }
+	    if (--ntrail == 0) {
+		nchar++;
+		nnonascii++;
+	    }
+	    continue;
+	}
+	if ((byte & 0x80) == 0x00) {
+	    /* single-byte (ASCII) character */
+	    nchar++;
+	    if (isdigit(byte)) {
+		if (i < ulPinLen - 1) {
+		    ndigit++;
+		}
+	    } else if (islower(byte)) {
+		nlower++;
+	    } else if (isupper(byte)) {
+		if (i > 0) {
+		    nupper++;
+		}
+	    } else {
+		nnonalnum++;
+	    }
+	} else if ((byte & 0xe0) == 0xc0) {
+	    /* leading byte of two-byte character */
+	    ntrail = 1;
+	} else if ((byte & 0xf0) == 0xe0) {
+	    /* leading byte of three-byte character */
+	    ntrail = 2;
+	} else if ((byte & 0xf8) == 0xf0) {
+	    /* leading byte of four-byte character */
+	    ntrail = 3;
+	} else {
+	    /* illegal */
+	    nchar = -1;
+	    break;
+	}
+    }
+    if (nchar == -1) {
+	/* illegal UTF8 string */
+	return CKR_PIN_INVALID;
+    }
+    if (nchar < FIPS_MIN_PIN) {
+	return CKR_PIN_LEN_RANGE;
+    }
+    nclass = (ndigit != 0) + (nlower != 0) + (nupper != 0) +
+	     (nnonalnum != 0) + (nnonascii != 0);
+    if (nclass < 3) {
+	return CKR_PIN_LEN_RANGE;
+    }
+    return CKR_OK;
+}
+
+
+/* FIPS required checks before any useful cryptographic services */
+static CK_RV sftk_fipsCheck(void) {
+    if (sftk_fatalError) 
+	return CKR_DEVICE_ERROR;
+    if (!isLoggedIn) 
+	return CKR_USER_NOT_LOGGED_IN;
+    return CKR_OK;
+}
+
+
+#define SFTK_FIPSCHECK() \
+    CK_RV rv; \
+    if ((rv = sftk_fipsCheck()) != CKR_OK) return rv;
+
+#define SFTK_FIPSFATALCHECK() \
+    if (sftk_fatalError) return CKR_DEVICE_ERROR;
+
+
+/* grab an attribute out of a raw template */
+void *
+fc_getAttribute(CK_ATTRIBUTE_PTR pTemplate, 
+				CK_ULONG ulCount, CK_ATTRIBUTE_TYPE type)
+{
+    int i;
+
+    for (i=0; i < (int) ulCount; i++) {
+	if (pTemplate[i].type == type) {
+	    return pTemplate[i].pValue;
+	}
+    }
+    return NULL;
+}
+
+
+#define __PASTE(x,y)	x##y
+
+/* ------------- forward declare all the NSC_ functions ------------- */
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+#define CK_PKCS11_FUNCTION_INFO(name) CK_RV __PASTE(NS,name)
+#define CK_NEED_ARG_LIST 1
+
+#include "pkcs11f.h"
+
+/* ------------- forward declare all the FIPS functions ------------- */
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+#define CK_PKCS11_FUNCTION_INFO(name) CK_RV __PASTE(F,name)
+#define CK_NEED_ARG_LIST 1
+
+#include "pkcs11f.h"
+
+/* ------------- build the CK_CRYPTO_TABLE ------------------------- */
+static CK_FUNCTION_LIST sftk_fipsTable = {
+    { 1, 10 },
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+#define CK_PKCS11_FUNCTION_INFO(name) __PASTE(F,name),
+
+
+#include "pkcs11f.h"
+
+};
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+/* CKO_NOT_A_KEY can be any object class that's not a key object. */
+#define CKO_NOT_A_KEY CKO_DATA
+
+#define SFTK_IS_KEY_OBJECT(objClass) \
+    (((objClass) == CKO_PUBLIC_KEY) || \
+    ((objClass) == CKO_PRIVATE_KEY) || \
+    ((objClass) == CKO_SECRET_KEY))
+
+#define SFTK_IS_NONPUBLIC_KEY_OBJECT(objClass) \
+    (((objClass) == CKO_PRIVATE_KEY) || ((objClass) == CKO_SECRET_KEY))
+
+static CK_RV
+sftk_get_object_class_and_fipsCheck(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hObject, CK_OBJECT_CLASS *pObjClass)
+{
+    CK_RV rv;
+    CK_ATTRIBUTE class; 
+    class.type = CKA_CLASS;
+    class.pValue = pObjClass;
+    class.ulValueLen = sizeof(*pObjClass);
+    rv = NSC_GetAttributeValue(hSession, hObject, &class, 1);
+    if ((rv == CKR_OK) && SFTK_IS_NONPUBLIC_KEY_OBJECT(*pObjClass)) {
+	rv = sftk_fipsCheck();
+    }
+    return rv;
+}
+
+#ifdef LINUX
+
+int
+sftk_mapLinuxAuditType(NSSAuditSeverity severity, NSSAuditType auditType)
+{
+    switch (auditType) {
+    case NSS_AUDIT_ACCESS_KEY:
+    case NSS_AUDIT_CHANGE_KEY: 
+    case NSS_AUDIT_COPY_KEY:
+    case NSS_AUDIT_DERIVE_KEY:
+    case NSS_AUDIT_DESTROY_KEY:
+    case NSS_AUDIT_DIGEST_KEY:
+    case NSS_AUDIT_GENERATE_KEY: 
+    case NSS_AUDIT_LOAD_KEY:
+    case NSS_AUDIT_UNWRAP_KEY:
+    case NSS_AUDIT_WRAP_KEY:
+	return AUDIT_CRYPTO_KEY_USER;
+    case NSS_AUDIT_CRYPT:
+	return (severity == NSS_AUDIT_ERROR) ? AUDIT_CRYPTO_FAILURE_USER : 
+					 AUDIT_CRYPTO_KEY_USER;
+    case NSS_AUDIT_FIPS_STATE:
+    case NSS_AUDIT_INIT_PIN:
+    case NSS_AUDIT_INIT_TOKEN:
+    case NSS_AUDIT_SET_PIN:
+	return AUDIT_CRYPTO_PARAM_CHANGE_USER;
+    case NSS_AUDIT_SELF_TEST: 
+	return AUDIT_CRYPTO_TEST_USER;
+    case NSS_AUDIT_LOGIN:
+	return AUDIT_CRYPTO_LOGIN;
+    case NSS_AUDIT_LOGOUT:
+	return AUDIT_CRYPTO_LOGOUT;
+    /* we skip the fault case here so we can get compiler 
+     * warnings if new 'NSSAuditType's are added without
+     * added them to this list, defaults fall through */
+    }
+    /* default */
+    return AUDIT_CRYPTO_PARAM_CHANGE_USER;
+} 
+#endif
+
+
+/**********************************************************************
+ *
+ *     FIPS 140 auditable event logging
+ *
+ **********************************************************************/
+
+PRBool sftk_audit_enabled = PR_FALSE;
+
+/*
+ * Each audit record must have the following information:
+ * - Date and time of the event
+ * - Type of event
+ * - user (subject) identity
+ * - outcome (success or failure) of the event
+ * - process ID
+ * - name (ID) of the object
+ * - for changes to data (except for authentication data and CSPs), the new
+ *   and old values of the data
+ * - for authentication attempts, the origin of the attempt (e.g., terminal
+ *   identifier)
+ * - for assuming a role, the type of role, and the location of the request
+ */
+void
+sftk_LogAuditMessage(NSSAuditSeverity severity, NSSAuditType auditType,
+		     const char *msg)
+{
+#ifdef NSS_AUDIT_WITH_SYSLOG
+    int level;
+
+    switch (severity) {
+    case NSS_AUDIT_ERROR:
+	level = LOG_ERR;
+	break;
+    case NSS_AUDIT_WARNING:
+	level = LOG_WARNING;
+	break;
+    default:
+	level = LOG_INFO;
+	break;
+    }
+    /* timestamp is provided by syslog in the message header */
+    syslog(level | LOG_USER /* facility */,
+	   "NSS " SOFTOKEN_LIB_NAME "[pid=%d uid=%d]: %s",
+	   (int)getpid(), (int)getuid(), msg);
+#ifdef LINUX
+    if (pthread_once(&libaudit_once_control, libaudit_init) != 0) {
+	return;
+    }
+    if (libaudit_handle) {
+	int audit_fd;
+	int linuxAuditType;
+	int result = (severity != NSS_AUDIT_ERROR); /* 1=success; 0=failed */
+	char *message = PR_smprintf("NSS " SOFTOKEN_LIB_NAME ": %s", msg);
+	if (!message) {
+	    return;
+	}
+	audit_fd = audit_open_func();
+	if (audit_fd < 0) {
+	    PR_smprintf_free(message);
+	    return;
+	}
+	linuxAuditType = sftk_mapLinuxAuditType(severity, auditType);
+	if (audit_log_user_message_func) {
+	    audit_log_user_message_func(audit_fd, linuxAuditType, message,
+					NULL, NULL, NULL, result);
+	} else {
+	    audit_send_user_message_func(audit_fd, linuxAuditType, message);
+	}
+	audit_close_func(audit_fd);
+	PR_smprintf_free(message);
+    }
+#endif /* LINUX */
+#ifdef SOLARIS
+    {
+        int rd;
+        char *message = PR_smprintf("NSS " SOFTOKEN_LIB_NAME ": %s", msg);
+
+        if (!message) {
+            return;
+        }
+
+        /* open the record descriptor */
+        if ((rd = au_open()) == -1) {
+            PR_smprintf_free(message);
+            return;
+        }
+
+        /* write the audit tokens to the audit record */
+        if (au_write(rd, au_to_text(message))) {
+            (void)au_close(rd, AU_TO_NO_WRITE, AUE_FIPS_AUDIT);
+            PR_smprintf_free(message);
+            return;
+        }
+
+        /* close the record and send it to the audit trail */
+        (void)au_close(rd, AU_TO_WRITE, AUE_FIPS_AUDIT);
+
+        PR_smprintf_free(message);
+    }
+#endif /* SOLARIS */
+#else
+    /* do nothing */
+#endif
+}
+
+
+/**********************************************************************
+ *
+ *     Start of PKCS 11 functions 
+ *
+ **********************************************************************/
+/* return the function list */
+CK_RV FC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList) {
+
+    CHECK_FORK();
+
+    *pFunctionList = &sftk_fipsTable;
+    return CKR_OK;
+}
+
+/* sigh global so pkcs11 can read it */
+PRBool nsf_init = PR_FALSE;
+
+/* FC_Initialize initializes the PKCS #11 library. */
+CK_RV FC_Initialize(CK_VOID_PTR pReserved) {
+    const char *envp;
+    CK_RV crv;
+
+    sftk_ForkReset(pReserved, &crv);
+
+    if (nsf_init) {
+	return CKR_CRYPTOKI_ALREADY_INITIALIZED;
+    }
+
+    if ((envp = PR_GetEnv("NSS_ENABLE_AUDIT")) != NULL) {
+	sftk_audit_enabled = (atoi(envp) == 1);
+    }
+
+    crv = nsc_CommonInitialize(pReserved, PR_TRUE);
+
+    /* not an 'else' rv can be set by either SFTK_LowInit or SFTK_SlotInit*/
+    if (crv != CKR_OK) {
+	sftk_fatalError = PR_TRUE;
+	return crv;
+    }
+
+    sftk_fatalError = PR_FALSE; /* any error has been reset */
+
+    crv = sftk_fipsPowerUpSelfTest();
+    if (crv != CKR_OK) {
+        nsc_CommonFinalize(NULL, PR_TRUE);
+	sftk_fatalError = PR_TRUE;
+	if (sftk_audit_enabled) {
+	    char msg[128];
+	    PR_snprintf(msg,sizeof msg,
+			"C_Initialize()=0x%08lX "
+			"power-up self-tests failed",
+			(PRUint32)crv);
+	    sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
+	}
+	return crv;
+    }
+    nsf_init = PR_TRUE;
+
+    return CKR_OK;
+}
+
+/*FC_Finalize indicates that an application is done with the PKCS #11 library.*/
+CK_RV FC_Finalize (CK_VOID_PTR pReserved) {
+   CK_RV crv;
+
+   if (sftk_ForkReset(pReserved, &crv)) {
+       return crv;
+   }
+
+   if (!nsf_init) {
+      return CKR_OK;
+   }
+
+   crv = nsc_CommonFinalize (pReserved, PR_TRUE);
+
+   nsf_init = (PRBool) !(crv == CKR_OK);
+   return crv;
+}
+
+
+/* FC_GetInfo returns general information about PKCS #11. */
+CK_RV  FC_GetInfo(CK_INFO_PTR pInfo) {
+    CHECK_FORK();
+
+    return NSC_GetInfo(pInfo);
+}
+
+/* FC_GetSlotList obtains a list of slots in the system. */
+CK_RV FC_GetSlotList(CK_BBOOL tokenPresent,
+	 		CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) {
+    CHECK_FORK();
+
+    return nsc_CommonGetSlotList(tokenPresent,pSlotList,pulCount,
+							 NSC_FIPS_MODULE);
+}
+	
+/* FC_GetSlotInfo obtains information about a particular slot in the system. */
+CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) {
+    CHECK_FORK();
+
+    return NSC_GetSlotInfo(slotID,pInfo);
+}
+
+
+/*FC_GetTokenInfo obtains information about a particular token in the system.*/
+ CK_RV FC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) {
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    crv = NSC_GetTokenInfo(slotID,pInfo);
+    if (crv == CKR_OK) 
+       pInfo->flags |= CKF_LOGIN_REQUIRED;
+    return crv;
+
+}
+
+
+
+/*FC_GetMechanismList obtains a list of mechanism types supported by a token.*/
+ CK_RV FC_GetMechanismList(CK_SLOT_ID slotID,
+	CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pusCount) {
+     CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    if (slotID == FIPS_SLOT_ID) slotID = NETSCAPE_SLOT_ID;
+    /* FIPS Slot supports all functions */
+    return NSC_GetMechanismList(slotID,pMechanismList,pusCount);
+}
+
+
+/* FC_GetMechanismInfo obtains information about a particular mechanism 
+ * possibly supported by a token. */
+ CK_RV FC_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
+    					CK_MECHANISM_INFO_PTR pInfo) {
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    if (slotID == FIPS_SLOT_ID) slotID = NETSCAPE_SLOT_ID;
+    /* FIPS Slot supports all functions */
+    return NSC_GetMechanismInfo(slotID,type,pInfo);
+}
+
+
+/* FC_InitToken initializes a token. */
+ CK_RV FC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin,
+ 				CK_ULONG usPinLen,CK_CHAR_PTR pLabel) {
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    crv = NSC_InitToken(slotID,pPin,usPinLen,pLabel);
+    if (sftk_audit_enabled) {
+	char msg[128];
+	NSSAuditSeverity severity = (crv == CKR_OK) ?
+		NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+	/* pLabel points to a 32-byte label, which is not null-terminated */
+	PR_snprintf(msg,sizeof msg,
+		"C_InitToken(slotID=%lu, pLabel=\"%.32s\")=0x%08lX",
+		(PRUint32)slotID,pLabel,(PRUint32)crv);
+	sftk_LogAuditMessage(severity, NSS_AUDIT_INIT_TOKEN, msg);
+    }
+    return crv;
+}
+
+
+/* FC_InitPIN initializes the normal user's PIN. */
+ CK_RV FC_InitPIN(CK_SESSION_HANDLE hSession,
+    					CK_CHAR_PTR pPin, CK_ULONG ulPinLen) {
+    CK_RV rv;
+
+    CHECK_FORK();
+
+    if (sftk_fatalError) return CKR_DEVICE_ERROR;
+    if ((rv = sftk_newPinCheck(pPin,ulPinLen)) == CKR_OK) {
+	rv = NSC_InitPIN(hSession,pPin,ulPinLen);
+    }
+    if (sftk_audit_enabled) {
+	char msg[128];
+	NSSAuditSeverity severity = (rv == CKR_OK) ?
+		NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+	PR_snprintf(msg,sizeof msg,
+		"C_InitPIN(hSession=0x%08lX)=0x%08lX",
+		(PRUint32)hSession,(PRUint32)rv);
+	sftk_LogAuditMessage(severity, NSS_AUDIT_INIT_PIN, msg);
+    }
+    return rv;
+}
+
+
+/* FC_SetPIN modifies the PIN of user that is currently logged in. */
+/* NOTE: This is only valid for the PRIVATE_KEY_SLOT */
+ CK_RV FC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
+    CK_ULONG usOldLen, CK_CHAR_PTR pNewPin, CK_ULONG usNewLen) {
+    CK_RV rv;
+
+    CHECK_FORK();
+
+    if ((rv = sftk_fipsCheck()) == CKR_OK &&
+	(rv = sftk_newPinCheck(pNewPin,usNewLen)) == CKR_OK) {
+	rv = NSC_SetPIN(hSession,pOldPin,usOldLen,pNewPin,usNewLen);
+    }
+    if (sftk_audit_enabled) {
+	char msg[128];
+	NSSAuditSeverity severity = (rv == CKR_OK) ?
+		NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+	PR_snprintf(msg,sizeof msg,
+		"C_SetPIN(hSession=0x%08lX)=0x%08lX",
+		(PRUint32)hSession,(PRUint32)rv);
+	sftk_LogAuditMessage(severity, NSS_AUDIT_SET_PIN, msg);
+    }
+    return rv;
+}
+
+/* FC_OpenSession opens a session between an application and a token. */
+ CK_RV FC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
+   CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession) {
+    SFTK_FIPSFATALCHECK();
+
+    CHECK_FORK();
+
+    return NSC_OpenSession(slotID,flags,pApplication,Notify,phSession);
+}
+
+
+/* FC_CloseSession closes a session between an application and a token. */
+ CK_RV FC_CloseSession(CK_SESSION_HANDLE hSession) {
+    CHECK_FORK();
+
+    return NSC_CloseSession(hSession);
+}
+
+
+/* FC_CloseAllSessions closes all sessions with a token. */
+ CK_RV FC_CloseAllSessions (CK_SLOT_ID slotID) {
+
+    CHECK_FORK();
+
+    return NSC_CloseAllSessions (slotID);
+}
+
+
+/* FC_GetSessionInfo obtains information about the session. */
+ CK_RV FC_GetSessionInfo(CK_SESSION_HANDLE hSession,
+						CK_SESSION_INFO_PTR pInfo) {
+    CK_RV rv;
+    SFTK_FIPSFATALCHECK();
+
+    CHECK_FORK();
+
+    rv = NSC_GetSessionInfo(hSession,pInfo);
+    if (rv == CKR_OK) {
+	if ((isLoggedIn) && (pInfo->state == CKS_RO_PUBLIC_SESSION)) {
+		pInfo->state = CKS_RO_USER_FUNCTIONS;
+	}
+	if ((isLoggedIn) && (pInfo->state == CKS_RW_PUBLIC_SESSION)) {
+		pInfo->state = CKS_RW_USER_FUNCTIONS;
+	}
+    }
+    return rv;
+}
+
+/* FC_Login logs a user into a token. */
+ CK_RV FC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
+				    CK_CHAR_PTR pPin, CK_ULONG usPinLen) {
+    CK_RV rv;
+    PRBool successful;
+    if (sftk_fatalError) return CKR_DEVICE_ERROR;
+    rv = NSC_Login(hSession,userType,pPin,usPinLen);
+    successful = (rv == CKR_OK) || (rv == CKR_USER_ALREADY_LOGGED_IN);
+    if (successful)
+	isLoggedIn = PR_TRUE;
+    if (sftk_audit_enabled) {
+	char msg[128];
+	NSSAuditSeverity severity;
+	severity = successful ? NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+	PR_snprintf(msg,sizeof msg,
+		    "C_Login(hSession=0x%08lX, userType=%lu)=0x%08lX",
+		    (PRUint32)hSession,(PRUint32)userType,(PRUint32)rv);
+	sftk_LogAuditMessage(severity, NSS_AUDIT_LOGIN, msg);
+    }
+    return rv;
+}
+
+/* FC_Logout logs a user out from a token. */
+ CK_RV FC_Logout(CK_SESSION_HANDLE hSession) {
+    CK_RV rv;
+
+    CHECK_FORK();
+
+    if ((rv = sftk_fipsCheck()) == CKR_OK) {
+	rv = NSC_Logout(hSession);
+	isLoggedIn = PR_FALSE;
+    }
+    if (sftk_audit_enabled) {
+	char msg[128];
+	NSSAuditSeverity severity = (rv == CKR_OK) ?
+		NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
+	PR_snprintf(msg,sizeof msg,
+		    "C_Logout(hSession=0x%08lX)=0x%08lX",
+		    (PRUint32)hSession,(PRUint32)rv);
+	sftk_LogAuditMessage(severity, NSS_AUDIT_LOGOUT, msg);
+    }
+    return rv;
+}
+
+
+/* FC_CreateObject creates a new object. */
+ CK_RV FC_CreateObject(CK_SESSION_HANDLE hSession,
+		CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 
+					CK_OBJECT_HANDLE_PTR phObject) {
+    CK_OBJECT_CLASS * classptr;
+
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    classptr = (CK_OBJECT_CLASS *)fc_getAttribute(pTemplate,ulCount,CKA_CLASS);
+    if (classptr == NULL) return CKR_TEMPLATE_INCOMPLETE;
+
+    /* FIPS can't create keys from raw key material */
+    if (SFTK_IS_NONPUBLIC_KEY_OBJECT(*classptr)) {
+	rv = CKR_ATTRIBUTE_VALUE_INVALID;
+    } else {
+	rv = NSC_CreateObject(hSession,pTemplate,ulCount,phObject);
+    }
+    if (sftk_audit_enabled && SFTK_IS_KEY_OBJECT(*classptr)) {
+	sftk_AuditCreateObject(hSession,pTemplate,ulCount,phObject,rv);
+    }
+    return rv;
+}
+
+
+
+
+
+/* FC_CopyObject copies an object, creating a new object for the copy. */
+ CK_RV FC_CopyObject(CK_SESSION_HANDLE hSession,
+       CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+					CK_OBJECT_HANDLE_PTR phNewObject) {
+    CK_RV rv;
+    CK_OBJECT_CLASS objClass = CKO_NOT_A_KEY;
+
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    rv = sftk_get_object_class_and_fipsCheck(hSession, hObject, &objClass);
+    if (rv == CKR_OK) {
+	rv = NSC_CopyObject(hSession,hObject,pTemplate,ulCount,phNewObject);
+    }
+    if (sftk_audit_enabled && SFTK_IS_KEY_OBJECT(objClass)) {
+	sftk_AuditCopyObject(hSession,
+	    hObject,pTemplate,ulCount,phNewObject,rv);
+    }
+    return rv;
+}
+
+
+/* FC_DestroyObject destroys an object. */
+ CK_RV FC_DestroyObject(CK_SESSION_HANDLE hSession,
+		 				CK_OBJECT_HANDLE hObject) {
+    CK_RV rv;
+    CK_OBJECT_CLASS objClass = CKO_NOT_A_KEY;
+
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    rv = sftk_get_object_class_and_fipsCheck(hSession, hObject, &objClass);
+    if (rv == CKR_OK) {
+	rv = NSC_DestroyObject(hSession,hObject);
+    }
+    if (sftk_audit_enabled && SFTK_IS_KEY_OBJECT(objClass)) {
+	sftk_AuditDestroyObject(hSession,hObject,rv);
+    }
+    return rv;
+}
+
+
+/* FC_GetObjectSize gets the size of an object in bytes. */
+ CK_RV FC_GetObjectSize(CK_SESSION_HANDLE hSession,
+    			CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) {
+    CK_RV rv;
+    CK_OBJECT_CLASS objClass = CKO_NOT_A_KEY;
+
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    rv = sftk_get_object_class_and_fipsCheck(hSession, hObject, &objClass);
+    if (rv == CKR_OK) {
+	rv = NSC_GetObjectSize(hSession, hObject, pulSize);
+    }
+    if (sftk_audit_enabled && SFTK_IS_KEY_OBJECT(objClass)) {
+	sftk_AuditGetObjectSize(hSession, hObject, pulSize, rv);
+    }
+    return rv;
+}
+
+
+/* FC_GetAttributeValue obtains the value of one or more object attributes. */
+ CK_RV FC_GetAttributeValue(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount) {
+    CK_RV rv;
+    CK_OBJECT_CLASS objClass = CKO_NOT_A_KEY;
+
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    rv = sftk_get_object_class_and_fipsCheck(hSession, hObject, &objClass);
+    if (rv == CKR_OK) {
+	rv = NSC_GetAttributeValue(hSession,hObject,pTemplate,ulCount);
+    }
+    if (sftk_audit_enabled && SFTK_IS_KEY_OBJECT(objClass)) {
+	sftk_AuditGetAttributeValue(hSession,hObject,pTemplate,ulCount,rv);
+    }
+    return rv;
+}
+
+
+/* FC_SetAttributeValue modifies the value of one or more object attributes */
+ CK_RV FC_SetAttributeValue (CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount) {
+    CK_RV rv;
+    CK_OBJECT_CLASS objClass = CKO_NOT_A_KEY;
+
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    rv = sftk_get_object_class_and_fipsCheck(hSession, hObject, &objClass);
+    if (rv == CKR_OK) {
+	rv = NSC_SetAttributeValue(hSession,hObject,pTemplate,ulCount);
+    }
+    if (sftk_audit_enabled && SFTK_IS_KEY_OBJECT(objClass)) {
+	sftk_AuditSetAttributeValue(hSession,hObject,pTemplate,ulCount,rv);
+    }
+    return rv;
+}
+
+
+
+/* FC_FindObjectsInit initializes a search for token and session objects 
+ * that match a template. */
+ CK_RV FC_FindObjectsInit(CK_SESSION_HANDLE hSession,
+    			CK_ATTRIBUTE_PTR pTemplate,CK_ULONG usCount) {
+    /* let publically readable object be found */
+    unsigned int i;
+    CK_RV rv;
+    PRBool needLogin = PR_FALSE;
+
+
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+
+    for (i=0; i < usCount; i++) {
+	CK_OBJECT_CLASS class;
+	if (pTemplate[i].type != CKA_CLASS) {
+	    continue;
+	}
+	if (pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS)) {
+	    continue;
+	}
+	if (pTemplate[i].pValue == NULL) {
+	    continue;
+	}
+	class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
+	if ((class == CKO_PRIVATE_KEY) || (class == CKO_SECRET_KEY)) {
+	    needLogin = PR_TRUE;
+	    break;
+	}
+    }
+    if (needLogin) {
+	if ((rv = sftk_fipsCheck()) != CKR_OK) return rv;
+    }
+    return NSC_FindObjectsInit(hSession,pTemplate,usCount);
+}
+
+
+/* FC_FindObjects continues a search for token and session objects 
+ * that match a template, obtaining additional object handles. */
+ CK_RV FC_FindObjects(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE_PTR phObject,CK_ULONG usMaxObjectCount,
+    					CK_ULONG_PTR pusObjectCount) {
+    CHECK_FORK();
+
+    /* let publically readable object be found */
+    SFTK_FIPSFATALCHECK();
+    return NSC_FindObjects(hSession,phObject,usMaxObjectCount,
+    							pusObjectCount);
+}
+
+
+/*
+ ************** Crypto Functions:     Encrypt ************************
+ */
+
+/* FC_EncryptInit initializes an encryption operation. */
+ CK_RV FC_EncryptInit(CK_SESSION_HANDLE hSession,
+		 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_EncryptInit(hSession,pMechanism,hKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditCryptInit("Encrypt",hSession,pMechanism,hKey,rv);
+    }
+    return rv;
+}
+
+/* FC_Encrypt encrypts single-part data. */
+ CK_RV FC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+    		CK_ULONG usDataLen, CK_BYTE_PTR pEncryptedData,
+					 CK_ULONG_PTR pusEncryptedDataLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_Encrypt(hSession,pData,usDataLen,pEncryptedData,
+							pusEncryptedDataLen);
+}
+
+
+/* FC_EncryptUpdate continues a multiple-part encryption operation. */
+ CK_RV FC_EncryptUpdate(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pPart, CK_ULONG usPartLen, CK_BYTE_PTR pEncryptedPart,	
+					CK_ULONG_PTR pusEncryptedPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_EncryptUpdate(hSession,pPart,usPartLen,pEncryptedPart,
+						pusEncryptedPartLen);
+}
+
+
+/* FC_EncryptFinal finishes a multiple-part encryption operation. */
+ CK_RV FC_EncryptFinal(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pusLastEncryptedPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_EncryptFinal(hSession,pLastEncryptedPart,
+						pusLastEncryptedPartLen);
+}
+
+/*
+ ************** Crypto Functions:     Decrypt ************************
+ */
+
+
+/* FC_DecryptInit initializes a decryption operation. */
+ CK_RV FC_DecryptInit( CK_SESSION_HANDLE hSession,
+			 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_DecryptInit(hSession,pMechanism,hKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditCryptInit("Decrypt",hSession,pMechanism,hKey,rv);
+    }
+    return rv;
+}
+
+/* FC_Decrypt decrypts encrypted data in a single part. */
+ CK_RV FC_Decrypt(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pEncryptedData,CK_ULONG usEncryptedDataLen,CK_BYTE_PTR pData,
+    						CK_ULONG_PTR pusDataLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_Decrypt(hSession,pEncryptedData,usEncryptedDataLen,pData,
+    								pusDataLen);
+}
+
+
+/* FC_DecryptUpdate continues a multiple-part decryption operation. */
+ CK_RV FC_DecryptUpdate(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pEncryptedPart, CK_ULONG usEncryptedPartLen,
+    				CK_BYTE_PTR pPart, CK_ULONG_PTR pusPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_DecryptUpdate(hSession,pEncryptedPart,usEncryptedPartLen,
+    							pPart,pusPartLen);
+}
+
+
+/* FC_DecryptFinal finishes a multiple-part decryption operation. */
+ CK_RV FC_DecryptFinal(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pLastPart, CK_ULONG_PTR pusLastPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_DecryptFinal(hSession,pLastPart,pusLastPartLen);
+}
+
+
+/*
+ ************** Crypto Functions:     Digest (HASH)  ************************
+ */
+
+/* FC_DigestInit initializes a message-digesting operation. */
+ CK_RV FC_DigestInit(CK_SESSION_HANDLE hSession,
+    					CK_MECHANISM_PTR pMechanism) {
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    return NSC_DigestInit(hSession, pMechanism);
+}
+
+
+/* FC_Digest digests data in a single part. */
+ CK_RV FC_Digest(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pData, CK_ULONG usDataLen, CK_BYTE_PTR pDigest,
+    						CK_ULONG_PTR pusDigestLen) {
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    return NSC_Digest(hSession,pData,usDataLen,pDigest,pusDigestLen);
+}
+
+
+/* FC_DigestUpdate continues a multiple-part message-digesting operation. */
+ CK_RV FC_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
+					    CK_ULONG usPartLen) {
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    return NSC_DigestUpdate(hSession,pPart,usPartLen);
+}
+
+
+/* FC_DigestFinal finishes a multiple-part message-digesting operation. */
+ CK_RV FC_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,
+    						CK_ULONG_PTR pusDigestLen) {
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    return NSC_DigestFinal(hSession,pDigest,pusDigestLen);
+}
+
+
+/*
+ ************** Crypto Functions:     Sign  ************************
+ */
+
+/* FC_SignInit initializes a signature (private key encryption) operation,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+ CK_RV FC_SignInit(CK_SESSION_HANDLE hSession,
+		 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_SignInit(hSession,pMechanism,hKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditCryptInit("Sign",hSession,pMechanism,hKey,rv);
+    }
+    return rv;
+}
+
+
+/* FC_Sign signs (encrypts with private key) data in a single part,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+ CK_RV FC_Sign(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pData,CK_ULONG usDataLen,CK_BYTE_PTR pSignature,
+    					CK_ULONG_PTR pusSignatureLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_Sign(hSession,pData,usDataLen,pSignature,pusSignatureLen);
+}
+
+
+/* FC_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+ CK_RV FC_SignUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
+    							CK_ULONG usPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_SignUpdate(hSession,pPart,usPartLen);
+}
+
+
+/* FC_SignFinal finishes a multiple-part signature operation, 
+ * returning the signature. */
+ CK_RV FC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature,
+					    CK_ULONG_PTR pusSignatureLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_SignFinal(hSession,pSignature,pusSignatureLen);
+}
+
+/*
+ ************** Crypto Functions:     Sign Recover  ************************
+ */
+/* FC_SignRecoverInit initializes a signature operation,
+ * where the (digest) data can be recovered from the signature. 
+ * E.g. encryption with the user's private key */
+ CK_RV FC_SignRecoverInit(CK_SESSION_HANDLE hSession,
+			 CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_SignRecoverInit(hSession,pMechanism,hKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditCryptInit("SignRecover",hSession,pMechanism,hKey,rv);
+    }
+    return rv;
+}
+
+
+/* FC_SignRecover signs data in a single operation
+ * where the (digest) data can be recovered from the signature. 
+ * E.g. encryption with the user's private key */
+ CK_RV FC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+  CK_ULONG usDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pusSignatureLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_SignRecover(hSession,pData,usDataLen,pSignature,pusSignatureLen);
+}
+
+/*
+ ************** Crypto Functions:     verify  ************************
+ */
+
+/* FC_VerifyInit initializes a verification operation, 
+ * where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature (e.g. DSA) */
+ CK_RV FC_VerifyInit(CK_SESSION_HANDLE hSession,
+			   CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_VerifyInit(hSession,pMechanism,hKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditCryptInit("Verify",hSession,pMechanism,hKey,rv);
+    }
+    return rv;
+}
+
+
+/* FC_Verify verifies a signature in a single-part operation, 
+ * where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+ CK_RV FC_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+    CK_ULONG usDataLen, CK_BYTE_PTR pSignature, CK_ULONG usSignatureLen) {
+    /* make sure we're legal */
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_Verify(hSession,pData,usDataLen,pSignature,usSignatureLen);
+}
+
+
+/* FC_VerifyUpdate continues a multiple-part verification operation, 
+ * where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+ CK_RV FC_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+						CK_ULONG usPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_VerifyUpdate(hSession,pPart,usPartLen);
+}
+
+
+/* FC_VerifyFinal finishes a multiple-part verification operation, 
+ * checking the signature. */
+ CK_RV FC_VerifyFinal(CK_SESSION_HANDLE hSession,
+			CK_BYTE_PTR pSignature,CK_ULONG usSignatureLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_VerifyFinal(hSession,pSignature,usSignatureLen);
+}
+
+/*
+ ************** Crypto Functions:     Verify  Recover ************************
+ */
+
+/* FC_VerifyRecoverInit initializes a signature verification operation, 
+ * where the data is recovered from the signature. 
+ * E.g. Decryption with the user's public key */
+ CK_RV FC_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_VerifyRecoverInit(hSession,pMechanism,hKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditCryptInit("VerifyRecover",hSession,pMechanism,hKey,rv);
+    }
+    return rv;
+}
+
+
+/* FC_VerifyRecover verifies a signature in a single-part operation, 
+ * where the data is recovered from the signature. 
+ * E.g. Decryption with the user's public key */
+ CK_RV FC_VerifyRecover(CK_SESSION_HANDLE hSession,
+		 CK_BYTE_PTR pSignature,CK_ULONG usSignatureLen,
+    				CK_BYTE_PTR pData,CK_ULONG_PTR pusDataLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_VerifyRecover(hSession,pSignature,usSignatureLen,pData,
+								pusDataLen);
+}
+
+/*
+ **************************** Key Functions:  ************************
+ */
+
+/* FC_GenerateKey generates a secret key, creating a new key object. */
+ CK_RV FC_GenerateKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,
+    						CK_OBJECT_HANDLE_PTR phKey) {
+    CK_BBOOL *boolptr;
+
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    /* all secret keys must be sensitive, if the upper level code tries to say
+     * otherwise, reject it. */
+    boolptr = (CK_BBOOL *) fc_getAttribute(pTemplate, ulCount, CKA_SENSITIVE);
+    if (boolptr != NULL) {
+	if (!(*boolptr)) {
+	    return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+    }
+
+    rv = NSC_GenerateKey(hSession,pMechanism,pTemplate,ulCount,phKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditGenerateKey(hSession,pMechanism,pTemplate,ulCount,phKey,rv);
+    }
+    return rv;
+}
+
+
+/* FC_GenerateKeyPair generates a public-key/private-key pair, 
+ * creating new key objects. */
+ CK_RV FC_GenerateKeyPair (CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+    CK_ULONG usPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+    CK_ULONG usPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey,
+					CK_OBJECT_HANDLE_PTR phPrivateKey) {
+    CK_BBOOL *boolptr;
+    CK_RV crv;
+
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+
+    /* all private keys must be sensitive, if the upper level code tries to say
+     * otherwise, reject it. */
+    boolptr = (CK_BBOOL *) fc_getAttribute(pPrivateKeyTemplate, 
+				usPrivateKeyAttributeCount, CKA_SENSITIVE);
+    if (boolptr != NULL) {
+	if (!(*boolptr)) {
+	    return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+    }
+    crv = NSC_GenerateKeyPair (hSession,pMechanism,pPublicKeyTemplate,
+    		usPublicKeyAttributeCount,pPrivateKeyTemplate,
+		usPrivateKeyAttributeCount,phPublicKey,phPrivateKey);
+    if (crv == CKR_GENERAL_ERROR) {
+	/* pairwise consistency check failed. */
+	sftk_fatalError = PR_TRUE;
+    }
+    if (sftk_audit_enabled) {
+	sftk_AuditGenerateKeyPair(hSession,pMechanism,pPublicKeyTemplate,
+    		usPublicKeyAttributeCount,pPrivateKeyTemplate,
+		usPrivateKeyAttributeCount,phPublicKey,phPrivateKey,crv);
+    }
+    return crv;
+}
+
+
+/* FC_WrapKey wraps (i.e., encrypts) a key. */
+ CK_RV FC_WrapKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey,
+    CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey,
+					 CK_ULONG_PTR pulWrappedKeyLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_WrapKey(hSession,pMechanism,hWrappingKey,hKey,pWrappedKey,
+							pulWrappedKeyLen);
+    if (sftk_audit_enabled) {
+	sftk_AuditWrapKey(hSession,pMechanism,hWrappingKey,hKey,pWrappedKey,
+							pulWrappedKeyLen,rv);
+    }
+    return rv;
+}
+
+
+/* FC_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */
+ CK_RV FC_UnwrapKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,
+    CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,
+    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
+						 CK_OBJECT_HANDLE_PTR phKey) {
+    CK_BBOOL *boolptr;
+
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    /* all secret keys must be sensitive, if the upper level code tries to say
+     * otherwise, reject it. */
+    boolptr = (CK_BBOOL *) fc_getAttribute(pTemplate, 
+					ulAttributeCount, CKA_SENSITIVE);
+    if (boolptr != NULL) {
+	if (!(*boolptr)) {
+	    return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+    }
+    rv = NSC_UnwrapKey(hSession,pMechanism,hUnwrappingKey,pWrappedKey,
+			ulWrappedKeyLen,pTemplate,ulAttributeCount,phKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditUnwrapKey(hSession,pMechanism,hUnwrappingKey,pWrappedKey,
+			ulWrappedKeyLen,pTemplate,ulAttributeCount,phKey,rv);
+    }
+    return rv;
+}
+
+
+/* FC_DeriveKey derives a key from a base key, creating a new key object. */
+ CK_RV FC_DeriveKey( CK_SESSION_HANDLE hSession,
+	 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey,
+	 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, 
+						CK_OBJECT_HANDLE_PTR phKey) {
+    CK_BBOOL *boolptr;
+
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    /* all secret keys must be sensitive, if the upper level code tries to say
+     * otherwise, reject it. */
+    boolptr = (CK_BBOOL *) fc_getAttribute(pTemplate, 
+					ulAttributeCount, CKA_SENSITIVE);
+    if (boolptr != NULL) {
+	if (!(*boolptr)) {
+	    return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+    }
+    rv = NSC_DeriveKey(hSession,pMechanism,hBaseKey,pTemplate,
+			ulAttributeCount, phKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditDeriveKey(hSession,pMechanism,hBaseKey,pTemplate,
+			ulAttributeCount,phKey,rv);
+    }
+    return rv;
+}
+
+/*
+ **************************** Radom Functions:  ************************
+ */
+
+/* FC_SeedRandom mixes additional seed material into the token's random number 
+ * generator. */
+ CK_RV FC_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
+    CK_ULONG usSeedLen) {
+    CK_RV crv;
+
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    crv = NSC_SeedRandom(hSession,pSeed,usSeedLen);
+    if (crv != CKR_OK) {
+	sftk_fatalError = PR_TRUE;
+    }
+    return crv;
+}
+
+
+/* FC_GenerateRandom generates random data. */
+ CK_RV FC_GenerateRandom(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR	pRandomData, CK_ULONG ulRandomLen) {
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    SFTK_FIPSFATALCHECK();
+    crv = NSC_GenerateRandom(hSession,pRandomData,ulRandomLen);
+    if (crv != CKR_OK) {
+	sftk_fatalError = PR_TRUE;
+	if (sftk_audit_enabled) {
+	    char msg[128];
+	    PR_snprintf(msg,sizeof msg,
+			"C_GenerateRandom(hSession=0x%08lX, pRandomData=%p, "
+			"ulRandomLen=%lu)=0x%08lX "
+			"self-test: continuous RNG test failed",
+			(PRUint32)hSession,pRandomData,
+			(PRUint32)ulRandomLen,(PRUint32)crv);
+	    sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
+	}
+    }
+    return crv;
+}
+
+
+/* FC_GetFunctionStatus obtains an updated status of a function running 
+ * in parallel with an application. */
+ CK_RV FC_GetFunctionStatus(CK_SESSION_HANDLE hSession) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_GetFunctionStatus(hSession);
+}
+
+
+/* FC_CancelFunction cancels a function running in parallel */
+ CK_RV FC_CancelFunction(CK_SESSION_HANDLE hSession) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_CancelFunction(hSession);
+}
+
+/*
+ ****************************  Version 1.1 Functions:  ************************
+ */
+
+/* FC_GetOperationState saves the state of the cryptographic 
+ *operation in a session. */
+CK_RV FC_GetOperationState(CK_SESSION_HANDLE hSession, 
+	CK_BYTE_PTR  pOperationState, CK_ULONG_PTR pulOperationStateLen) {
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    return NSC_GetOperationState(hSession,pOperationState,pulOperationStateLen);
+}
+
+
+/* FC_SetOperationState restores the state of the cryptographic operation 
+ * in a session. */
+CK_RV FC_SetOperationState(CK_SESSION_HANDLE hSession, 
+	CK_BYTE_PTR  pOperationState, CK_ULONG  ulOperationStateLen,
+        CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) {
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    return NSC_SetOperationState(hSession,pOperationState,ulOperationStateLen,
+        				hEncryptionKey,hAuthenticationKey);
+}
+
+/* FC_FindObjectsFinal finishes a search for token and session objects. */
+CK_RV FC_FindObjectsFinal(CK_SESSION_HANDLE hSession) {
+    /* let publically readable object be found */
+    SFTK_FIPSFATALCHECK();
+    CHECK_FORK();
+
+    return NSC_FindObjectsFinal(hSession);
+}
+
+
+/* Dual-function cryptographic operations */
+
+/* FC_DigestEncryptUpdate continues a multiple-part digesting and encryption 
+ * operation. */
+CK_RV FC_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
+    CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
+					 CK_ULONG_PTR pulEncryptedPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_DigestEncryptUpdate(hSession,pPart,ulPartLen,pEncryptedPart,
+					 pulEncryptedPartLen);
+}
+
+
+/* FC_DecryptDigestUpdate continues a multiple-part decryption and digesting 
+ * operation. */
+CK_RV FC_DecryptDigestUpdate(CK_SESSION_HANDLE hSession,
+     CK_BYTE_PTR  pEncryptedPart, CK_ULONG  ulEncryptedPartLen,
+    				CK_BYTE_PTR  pPart, CK_ULONG_PTR pulPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_DecryptDigestUpdate(hSession, pEncryptedPart,ulEncryptedPartLen,
+    				pPart,pulPartLen);
+}
+
+/* FC_SignEncryptUpdate continues a multiple-part signing and encryption 
+ * operation. */
+CK_RV FC_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
+	 CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
+					 CK_ULONG_PTR pulEncryptedPartLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_SignEncryptUpdate(hSession,pPart,ulPartLen,pEncryptedPart,
+					 pulEncryptedPartLen);
+}
+
+/* FC_DecryptVerifyUpdate continues a multiple-part decryption and verify 
+ * operation. */
+CK_RV FC_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, 
+	CK_BYTE_PTR  pEncryptedData, CK_ULONG  ulEncryptedDataLen, 
+				CK_BYTE_PTR  pData, CK_ULONG_PTR pulDataLen) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    return NSC_DecryptVerifyUpdate(hSession,pEncryptedData,ulEncryptedDataLen, 
+				pData,pulDataLen);
+}
+
+
+/* FC_DigestKey continues a multi-part message-digesting operation,
+ * by digesting the value of a secret key as part of the data already digested.
+ */
+CK_RV FC_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) {
+    SFTK_FIPSCHECK();
+    CHECK_FORK();
+
+    rv = NSC_DigestKey(hSession,hKey);
+    if (sftk_audit_enabled) {
+	sftk_AuditDigestKey(hSession,hKey,rv);
+    }
+    return rv;
+}
+
+
+CK_RV FC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
+							 CK_VOID_PTR pReserved)
+{
+    CHECK_FORK();
+
+    return NSC_WaitForSlotEvent(flags, pSlot, pReserved);
+}
diff --git a/mozilla/security/nss/lib/softoken/lgglue.c b/mozilla/security/nss/lib/softoken/lgglue.c
new file mode 100644
index 0000000..ec0173c
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/lgglue.c
@@ -0,0 +1,492 @@
+/* ***** 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 ***** */
+/* 
+ *  The following code handles the storage of PKCS 11 modules used by the
+ * NSS. This file is written to abstract away how the modules are
+ * stored so we can deside that later.
+ */
+#include "sftkdb.h"
+#include "sftkdbti.h"
+#include "sdb.h"
+#include "prsystem.h"
+#include "prprf.h"
+#include "prenv.h"
+#include "lgglue.h"
+#include "secerr.h"
+#include "softoken.h"
+
+static LGOpenFunc legacy_glue_open = NULL;
+static LGReadSecmodFunc legacy_glue_readSecmod = NULL;
+static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL;
+static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL;
+static LGAddSecmodFunc legacy_glue_addSecmod = NULL;
+static LGShutdownFunc legacy_glue_shutdown = NULL;
+
+#if 0  /* STATIC LIBRARIES */
+/*
+ * The following 3 functions duplicate the work done by bl_LoadLibrary.
+ * We should make bl_LoadLibrary a global and replace the call to
+ * sftkdb_LoadLibrary(const char *libname) with it.
+ */
+#ifdef XP_UNIX
+#include <unistd.h>
+#define LG_MAX_LINKS 20
+static char *
+sftkdb_resolvePath(const char *orig)
+{
+    int count = 0;
+    int len =0;
+    int ret = -1;
+    char *resolved = NULL;
+    char *source = NULL;
+
+    len = 1025; /* MAX PATH +1*/
+    if (strlen(orig)+1 > len) {
+	/* PATH TOO LONG */
+	return NULL;
+    }
+    resolved = PORT_Alloc(len);
+    if (!resolved) {
+	return NULL;
+    }
+    source = PORT_Alloc(len);
+    if (!source) {
+	goto loser;
+    }
+    PORT_Strcpy(source, orig);
+    /* Walk down all the links */
+    while ( count++ < LG_MAX_LINKS) {
+	char *tmp;
+	/* swap our previous sorce out with resolved */
+	/* read it */
+	ret = readlink(source, resolved, len-1);
+	if (ret  < 0) {
+	    break;
+ 	}
+	resolved[ret] = 0;
+	tmp = source; source = resolved; resolved = tmp;
+    }
+    if (count > 1) {
+	ret = 0;
+    }
+loser:
+    if (resolved) {
+	PORT_Free(resolved);
+    }
+    if (ret < 0) {
+	if (source) {
+	    PORT_Free(source);
+	    source = NULL;
+	}
+    }
+    return source;
+}
+
+#endif
+
+static PRLibrary *
+sftkdb_LoadFromPath(const char *path, const char *libname)
+{
+    char *c;
+    int pathLen, nameLen, fullPathLen;
+    char *fullPathName = NULL;
+    PRLibSpec libSpec;
+    PRLibrary *lib = NULL;
+
+
+    /* strip of our parent's library name */ 
+    c = strrchr(path, PR_GetDirectorySeparator());
+    if (!c) {
+	return NULL; /* invalid path */
+    }
+    pathLen = (c-path)+1;
+    nameLen = strlen(libname);
+    fullPathLen = pathLen + nameLen +1;
+    fullPathName = (char *)PORT_Alloc(fullPathLen);
+    if (fullPathName == NULL) {
+	return NULL; /* memory allocation error */
+    }
+    PORT_Memcpy(fullPathName, path, pathLen);
+    PORT_Memcpy(fullPathName+pathLen, libname, nameLen);
+    fullPathName[fullPathLen-1] = 0;
+
+    libSpec.type = PR_LibSpec_Pathname;
+    libSpec.value.pathname = fullPathName;
+    lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
+    PORT_Free(fullPathName);
+    return lib;
+}
+
+
+static PRLibrary *
+sftkdb_LoadLibrary(const char *libname)
+{
+    PRLibrary *lib = NULL;
+    PRFuncPtr fn_addr;
+    char *parentLibPath = NULL;
+
+    fn_addr  = (PRFuncPtr) &sftkdb_LoadLibrary;
+    parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr);
+
+    if (!parentLibPath) {
+	goto done;
+    }
+
+    lib = sftkdb_LoadFromPath(parentLibPath, libname);
+#ifdef XP_UNIX
+    /* handle symbolic link case */
+    if (!lib) {
+	char *trueParentLibPath = sftkdb_resolvePath(parentLibPath);
+	if (!trueParentLibPath) {
+	    goto done;
+	}
+    	lib = sftkdb_LoadFromPath(trueParentLibPath, libname);
+	PORT_Free(trueParentLibPath);
+    }
+#endif
+
+done:
+    if (parentLibPath) {
+	PORT_Free(parentLibPath);
+    }
+
+    /* still couldn't load it, try the generic path */
+    if (!lib) {
+	PRLibSpec libSpec;
+	libSpec.type = PR_LibSpec_Pathname;
+	libSpec.value.pathname = libname;
+	lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
+    }
+
+    return lib;
+}
+#endif  /* STATIC LIBRARIES */
+
+/*
+ * stub files for legacy db's to be able to encrypt and decrypt
+ * various keys and attributes.
+ */
+static SECStatus
+sftkdb_encrypt_stub(PRArenaPool *arena, SDB *sdb, SECItem *plainText,
+		    SECItem **cipherText)
+{
+    SFTKDBHandle *handle = sdb->app_private;
+    SECStatus rv;
+
+    if (handle == NULL) {
+	return SECFailure;
+    }
+
+    /* if we aren't the key handle, try the other handle */
+    if (handle->type != SFTK_KEYDB_TYPE) {
+	handle = handle->peerDB;
+    }
+
+    /* not a key handle */
+    if (handle == NULL || handle->passwordLock == NULL) {
+	return SECFailure;
+    }
+
+    PZ_Lock(handle->passwordLock);
+    if (handle->passwordKey.data == NULL) {
+	PZ_Unlock(handle->passwordLock);
+	/* PORT_SetError */
+	return SECFailure;
+    }
+
+    rv = sftkdb_EncryptAttribute(arena, 
+	handle->newKey?handle->newKey:&handle->passwordKey, 
+	plainText, cipherText);
+    PZ_Unlock(handle->passwordLock);
+
+    return rv;
+}
+
+/*
+ * stub files for legacy db's to be able to encrypt and decrypt
+ * various keys and attributes.
+ */
+static SECStatus
+sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) 
+{
+    SFTKDBHandle *handle = sdb->app_private;
+    SECStatus rv;
+    SECItem *oldKey = NULL;
+
+    if (handle == NULL) {
+	return SECFailure;
+    }
+
+    /* if we aren't th handle, try the other handle */
+    oldKey = handle->oldKey;
+    if (handle->type != SFTK_KEYDB_TYPE) {
+	handle = handle->peerDB;
+    }
+
+    /* not a key handle */
+    if (handle == NULL || handle->passwordLock == NULL) {
+	return SECFailure;
+    }
+
+    PZ_Lock(handle->passwordLock);
+    if (handle->passwordKey.data == NULL) {
+	PZ_Unlock(handle->passwordLock);
+	/* PORT_SetError */
+	return SECFailure;
+    }
+    rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey,
+		cipherText, plainText);
+    PZ_Unlock(handle->passwordLock);
+
+    return rv;
+}
+
+static const char *LEGACY_LIB_NAME = 
+	SHLIB_PREFIX"nssdbm"SHLIB_VERSION"."SHLIB_SUFFIX;
+/*
+ * 2 bools to tell us if we've check the legacy library successfully or
+ * not. Initialize on startup to false by the C BSS segment;
+ */
+static PRBool legacy_glue_libCheckFailed;    /* set if we failed the check */
+static PRBool legacy_glue_libCheckSucceeded; /* set if we passed the check */
+static PRLibrary *legacy_glue_lib = NULL;
+static SECStatus 
+sftkdbLoad_Legacy(PRBool isFIPS)
+{
+    PRLibrary *lib = NULL;
+    LGSetCryptFunc setCryptFunction = NULL;
+
+    if (legacy_glue_lib) {
+	/* this check is necessary because it's possible we loaded the
+	 * legacydb to read secmod.db, which told us whether we were in
+	 * FIPS mode or not. */
+	if (isFIPS && !legacy_glue_libCheckSucceeded) {
+	    if (legacy_glue_libCheckFailed || 
+		!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
+    	    	legacy_glue_libCheckFailed = PR_TRUE;
+		/* don't clobber legacy glue to avoid race. just let it
+		 * get cleared in shutdown */
+		return SECFailure;
+	    }
+    	    legacy_glue_libCheckSucceeded = PR_TRUE;
+	} 
+	return SECSuccess;
+    }
+
+#undef TRY_TO_USE_NSSDBM
+#if 1  /* STATIC LIBRARIES */
+#ifdef TRY_TO_USE_NSSDBM
+    lib = (PRLibrary *) 0x8;
+
+    legacy_glue_open = legacy_Open;
+    legacy_glue_readSecmod = legacy_ReadSecmodDB;
+    legacy_glue_releaseSecmod = legacy_ReleaseSecmodDBData;
+    legacy_glue_deleteSecmod = legacy_DeleteSecmodDB;
+    legacy_glue_addSecmod = legacy_AddSecmodDB;
+    legacy_glue_shutdown = legacy_Shutdown;
+    setCryptFunction = legacy_SetCryptFunctions;
+#else
+    fprintf(stderr, "NSSDBM omitted!\n");
+    return SECFailure;
+#endif
+#else
+    lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME);
+    if (lib == NULL) {
+	return SECFailure;
+    }
+    
+    legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open");
+    legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib,
+						 "legacy_ReadSecmodDB");
+    legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib,
+					 	 "legacy_ReleaseSecmodDBData");
+    legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib,
+						 "legacy_DeleteSecmodDB");
+    legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, 
+						 "legacy_AddSecmodDB");
+    legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, 
+						"legacy_Shutdown");
+    setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, 
+						"legacy_SetCryptFunctions");
+
+    if (!legacy_glue_open || !legacy_glue_readSecmod || 
+	    !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || 
+	    !legacy_glue_addSecmod || !setCryptFunction) {
+	PR_UnloadLibrary(lib);
+	return SECFailure;
+    }
+#endif  /* STATIC LIBRARIES */
+
+    /* verify the loaded library if we are in FIPS mode */
+    if (isFIPS) {
+	if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
+#if 0  /* STATIC LIBRARIES */
+	    PR_UnloadLibrary(lib);
+#endif
+	    return SECFailure;
+	}
+    	legacy_glue_libCheckSucceeded = PR_TRUE;
+    } 
+
+    setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub);
+    legacy_glue_lib = lib;
+    return SECSuccess;
+}
+
+CK_RV
+sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, 
+		int certVersion, int keyVersion, int flags, PRBool isFIPS,
+		SDB **certDB, SDB **keyDB)
+{
+    SECStatus rv;
+
+    rv = sftkdbLoad_Legacy(isFIPS);
+    if (rv != SECSuccess) {
+	return CKR_GENERAL_ERROR;
+    }
+    if (!legacy_glue_open) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return (*legacy_glue_open)(dir, certPrefix, keyPrefix, 
+				certVersion, keyVersion,
+				flags, certDB, keyDB);
+}
+
+char **
+sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, 
+			const char *dbname, char *params, PRBool rw)
+{
+    SECStatus rv;
+
+    rv = sftkdbLoad_Legacy(PR_FALSE);
+    if (rv != SECSuccess) {
+	return NULL;
+    }
+    if (!legacy_glue_readSecmod) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return NULL;
+    }
+    return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw);
+}
+
+SECStatus
+sftkdbCall_ReleaseSecmodDBData(const char *appName, 
+			const char *filename, const char *dbname, 
+			char **moduleSpecList, PRBool rw)
+{
+    SECStatus rv;
+
+    rv = sftkdbLoad_Legacy(PR_FALSE);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    if (!legacy_glue_releaseSecmod) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return (*legacy_glue_releaseSecmod)(appName, filename, dbname, 
+					  moduleSpecList, rw);
+}
+
+SECStatus
+sftkdbCall_DeleteSecmodDB(const char *appName, 
+		      const char *filename, const char *dbname, 
+		      char *args, PRBool rw)
+{
+    SECStatus rv;
+
+    rv = sftkdbLoad_Legacy(PR_FALSE);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    if (!legacy_glue_deleteSecmod) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw);
+}
+
+SECStatus
+sftkdbCall_AddSecmodDB(const char *appName, 
+		   const char *filename, const char *dbname, 
+		   char *module, PRBool rw)
+{
+    SECStatus rv;
+
+    rv = sftkdbLoad_Legacy(PR_FALSE);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    if (!legacy_glue_addSecmod) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw);
+}
+
+CK_RV
+sftkdbCall_Shutdown(void)
+{
+    CK_RV crv = CKR_OK;
+    char *disableUnload = NULL;
+    if (!legacy_glue_lib) {
+	return CKR_OK;
+    }
+    if (legacy_glue_shutdown) {
+#ifdef NO_FORK_CHECK
+	PRBool parentForkedAfterC_Initialize = PR_FALSE;
+#endif
+	crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize);
+    }
+#if 0  /* STATIC LIBRARIES */
+    disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
+    if (!disableUnload) {
+        PR_UnloadLibrary(legacy_glue_lib);
+    }
+#endif
+    legacy_glue_lib = NULL;
+    legacy_glue_open = NULL;
+    legacy_glue_readSecmod = NULL;
+    legacy_glue_releaseSecmod = NULL;
+    legacy_glue_deleteSecmod = NULL;
+    legacy_glue_addSecmod = NULL;
+    legacy_glue_libCheckFailed    = PR_FALSE;
+    legacy_glue_libCheckSucceeded = PR_FALSE;
+    return crv;
+}
+    
+
diff --git a/mozilla/security/nss/lib/softoken/lgglue.h b/mozilla/security/nss/lib/softoken/lgglue.h
new file mode 100644
index 0000000..31fead6
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/lgglue.h
@@ -0,0 +1,111 @@
+/* ***** 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 ***** */
+/* 
+ * This code defines the glue layer between softoken and the legacy DB library
+ */
+#include "sdb.h"
+
+/*
+ * function prototypes for the callbacks into softoken from the legacyDB
+ */
+
+typedef SECStatus (*LGEncryptFunc)(PRArenaPool *arena, SDB *sdb, 
+				  SECItem *plainText, SECItem **cipherText);
+typedef SECStatus (*LGDecryptFunc)(SDB *sdb, SECItem *cipherText, 
+				   SECItem **plainText);
+
+/*
+ * function prototypes for the exported functions.
+ */
+typedef CK_RV (*LGOpenFunc) (const char *dir, const char *certPrefix, 
+		const char *keyPrefix, 
+		int certVersion, int keyVersion, int flags, 
+		SDB **certDB, SDB **keyDB);
+typedef char ** (*LGReadSecmodFunc)(const char *appName, 
+			const char *filename, 
+			const char *dbname, char *params, PRBool rw);
+typedef SECStatus (*LGReleaseSecmodFunc)(const char *appName,
+			const char *filename, 
+			const char *dbname, char **params, PRBool rw);
+typedef SECStatus (*LGDeleteSecmodFunc)(const char *appName,
+			const char *filename, 
+			const char *dbname, char *params, PRBool rw);
+typedef SECStatus (*LGAddSecmodFunc)(const char *appName, 
+			const char *filename, 
+			const char *dbname, char *params, PRBool rw);
+typedef SECStatus (*LGShutdownFunc)(PRBool forked);
+typedef void (*LGSetForkStateFunc)(PRBool);
+typedef void (*LGSetCryptFunc)(LGEncryptFunc, LGDecryptFunc);
+
+extern CK_RV legacy_Open(const char *dir, const char *certPrefix, 
+		const char *keyPrefix, 
+		int certVersion, int keyVersion, int flags, 
+		SDB **certDB, SDB **keyDB);
+extern char ** legacy_ReadSecmodDB(const char *appName, 
+			const char *filename, 
+			const char *dbname, char *params, PRBool rw);
+extern SECStatus legacy_ReleaseSecmodDBData(const char *appName,
+			const char *filename, 
+			const char *dbname, char **params, PRBool rw);
+extern SECStatus legacy_DeleteSecmodDB(const char *appName,
+			const char *filename, 
+			const char *dbname, char *params, PRBool rw);
+extern SECStatus legacy_AddSecmodDB(const char *appName, 
+			const char *filename, 
+			const char *dbname, char *params, PRBool rw);
+extern SECStatus legacy_Shutdown(PRBool forked);
+extern void legacy_SetCryptFunctions(LGEncryptFunc, LGDecryptFunc);
+
+/*
+ * Softoken Glue Functions
+ */
+CK_RV sftkdbCall_open(const char *dir, const char *certPrefix, 
+		const char *keyPrefix, 
+		int certVersion, int keyVersion, int flags, PRBool isFIPS,
+		SDB **certDB, SDB **keyDB);
+char ** sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, 
+			const char *dbname, char *params, PRBool rw);
+SECStatus sftkdbCall_ReleaseSecmodDBData(const char *appName, 
+			const char *filename, const char *dbname, 
+			char **moduleSpecList, PRBool rw);
+SECStatus sftkdbCall_DeleteSecmodDB(const char *appName, 
+		      const char *filename, const char *dbname, 
+		      char *args, PRBool rw);
+SECStatus sftkdbCall_AddSecmodDB(const char *appName, 
+		   const char *filename, const char *dbname, 
+		   char *module, PRBool rw);
+CK_RV sftkdbCall_Shutdown(void);
+
diff --git a/mozilla/security/nss/lib/softoken/lowkey.c b/mozilla/security/nss/lib/softoken/lowkey.c
new file mode 100644
index 0000000..4174cef
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/lowkey.c
@@ -0,0 +1,525 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 "lowkeyi.h"
+#include "secoid.h"
+#include "secitem.h"
+#include "secder.h"
+#include "base64.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+#ifdef NSS_ENABLE_ECC
+#include "softoken.h"
+#endif
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_BitStringTemplate)
+SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+const SEC_ASN1Template nsslowkey_AttributeTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 
+	0, NULL, sizeof(NSSLOWKEYAttribute) },
+    { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) },
+    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN ,
+        offsetof(NSSLOWKEYAttribute, attrValue),
+	SEC_ASN1_SUB(SEC_AnyTemplate) },
+    { 0 }
+};
+
+const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate },
+};
+/* ASN1 Templates for new decoder/encoder */
+const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) },
+    { SEC_ASN1_INTEGER,
+	offsetof(NSSLOWKEYPrivateKeyInfo,version) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	offsetof(NSSLOWKEYPrivateKeyInfo,algorithm),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OCTET_STRING,
+	offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+	offsetof(NSSLOWKEYPrivateKeyInfo, attributes),
+	nsslowkey_SetOfAttributeTemplate },
+    { 0 }
+};
+
+const SEC_ASN1Template nsslowkey_PQGParamsTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) },
+    { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) },
+    { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) },
+    { SEC_ASN1_INTEGER, offsetof(PQGParams,base) },
+    { 0, }
+};
+
+const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.version) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.modulus) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.publicExponent) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.privateExponent) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime1) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime2) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent1) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent2) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.coefficient) },
+    { 0 }                                                                     
+};                                                                            
+
+
+const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.publicValue) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.privateValue) },
+    { 0, }
+};
+
+const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[] = {
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.privateValue) },
+};
+
+const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.publicValue) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.privateValue) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.base) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.prime) },
+    { 0, }
+};
+
+#ifdef NSS_ENABLE_ECC
+
+/* XXX This is just a placeholder for later when we support
+ * generic curves and need full-blown support for parsing EC
+ * parameters. For now, we only support named curves in which
+ * EC params are simply encoded as an object ID and we don't
+ * use nsslowkey_ECParamsTemplate.
+ */
+const SEC_ASN1Template nsslowkey_ECParamsTemplate[] = {
+    { SEC_ASN1_CHOICE, offsetof(ECParams,type), NULL, sizeof(ECParams) },
+    { SEC_ASN1_OBJECT_ID, offsetof(ECParams,curveOID), NULL, ec_params_named },
+    { 0, }
+};
+
+
+/* NOTE: The SECG specification allows the private key structure
+ * to contain curve parameters but recommends that they be stored
+ * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo
+ * instead.
+ */
+const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.ec.version) },
+    { SEC_ASN1_OCTET_STRING, 
+      offsetof(NSSLOWKEYPrivateKey,u.ec.privateValue) },
+    /* XXX The following template works for now since we only
+     * support named curves for which the parameters are
+     * encoded as an object ID. When we support generic curves,
+     * we'll need to define nsslowkey_ECParamsTemplate
+     */
+#if 1
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+      SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
+      SEC_ASN1_XTRN | 0, 
+      offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams.curveOID), 
+      SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, 
+#else
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+      SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0, 
+      offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams), 
+      nsslowkey_ECParamsTemplate }, 
+#endif
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+      SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
+      SEC_ASN1_XTRN | 1, 
+      offsetof(NSSLOWKEYPrivateKey,u.ec.publicValue),
+      SEC_ASN1_SUB(SEC_BitStringTemplate) }, 
+    { 0, }
+};
+#endif /* NSS_ENABLE_ECC */
+/*
+ * See bugzilla bug 125359
+ * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
+ * all of the templates above that en/decode into integers must be converted
+ * from ASN.1's signed integer type.  This is done by marking either the
+ * source or destination (encoding or decoding, respectively) type as
+ * siUnsignedInteger.
+ */
+
+void
+prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
+{
+    key->u.rsa.modulus.type = siUnsignedInteger;
+    key->u.rsa.publicExponent.type = siUnsignedInteger;
+    key->u.rsa.privateExponent.type = siUnsignedInteger;
+    key->u.rsa.prime1.type = siUnsignedInteger;
+    key->u.rsa.prime2.type = siUnsignedInteger;
+    key->u.rsa.exponent1.type = siUnsignedInteger;
+    key->u.rsa.exponent2.type = siUnsignedInteger;
+    key->u.rsa.coefficient.type = siUnsignedInteger;
+}
+
+void
+prepare_low_pqg_params_for_asn1(PQGParams *params)
+{
+    params->prime.type = siUnsignedInteger;
+    params->subPrime.type = siUnsignedInteger;
+    params->base.type = siUnsignedInteger;
+}
+
+void
+prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
+{
+    key->u.dsa.publicValue.type = siUnsignedInteger;
+    key->u.dsa.privateValue.type = siUnsignedInteger;
+    key->u.dsa.params.prime.type = siUnsignedInteger;
+    key->u.dsa.params.subPrime.type = siUnsignedInteger;
+    key->u.dsa.params.base.type = siUnsignedInteger;
+}
+
+void
+prepare_low_dsa_priv_key_export_for_asn1(NSSLOWKEYPrivateKey *key)
+{
+    key->u.dsa.privateValue.type = siUnsignedInteger;
+}
+
+void
+prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
+{
+    key->u.dh.prime.type = siUnsignedInteger;
+    key->u.dh.base.type = siUnsignedInteger;
+    key->u.dh.publicValue.type = siUnsignedInteger;
+    key->u.dh.privateValue.type = siUnsignedInteger;
+}
+
+#ifdef NSS_ENABLE_ECC
+void
+prepare_low_ecparams_for_asn1(ECParams *params)
+{
+    params->DEREncoding.type = siUnsignedInteger;
+    params->curveOID.type = siUnsignedInteger;
+}
+
+void
+prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
+{
+    key->u.ec.version.type = siUnsignedInteger;
+    key->u.ec.ecParams.DEREncoding.type = siUnsignedInteger;
+    key->u.ec.ecParams.curveOID.type = siUnsignedInteger;
+    key->u.ec.privateValue.type = siUnsignedInteger;
+    key->u.ec.publicValue.type = siUnsignedInteger;
+}
+#endif /* NSS_ENABLE_ECC */
+
+void
+nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *privk)
+{
+    if (privk && privk->arena) {
+	PORT_FreeArena(privk->arena, PR_TRUE);
+    }
+}
+
+void
+nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *pubk)
+{
+    if (pubk && pubk->arena) {
+	PORT_FreeArena(pubk->arena, PR_FALSE);
+    }
+}
+unsigned
+nsslowkey_PublicModulusLen(NSSLOWKEYPublicKey *pubk)
+{
+    unsigned char b0;
+
+    /* interpret modulus length as key strength... in
+     * fortezza that's the public key length */
+
+    switch (pubk->keyType) {
+    case NSSLOWKEYRSAKey:
+    	b0 = pubk->u.rsa.modulus.data[0];
+    	return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
+    default:
+	break;
+    }
+    return 0;
+}
+
+unsigned
+nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privk)
+{
+
+    unsigned char b0;
+
+    switch (privk->keyType) {
+    case NSSLOWKEYRSAKey:
+	b0 = privk->u.rsa.modulus.data[0];
+	return b0 ? privk->u.rsa.modulus.len : privk->u.rsa.modulus.len - 1;
+    default:
+	break;
+    }
+    return 0;
+}
+
+NSSLOWKEYPublicKey *
+nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk)
+{
+    NSSLOWKEYPublicKey *pubk;
+    PLArenaPool *arena;
+
+
+    arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+        PORT_SetError (SEC_ERROR_NO_MEMORY);
+        return NULL;
+    }
+
+    switch(privk->keyType) {
+      case NSSLOWKEYRSAKey:
+      case NSSLOWKEYNullKey:
+	pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
+						sizeof (NSSLOWKEYPublicKey));
+	if (pubk != NULL) {
+	    SECStatus rv;
+
+	    pubk->arena = arena;
+	    pubk->keyType = privk->keyType;
+	    if (privk->keyType == NSSLOWKEYNullKey) return pubk;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.rsa.modulus,
+				  &privk->u.rsa.modulus);
+	    if (rv == SECSuccess) {
+		rv = SECITEM_CopyItem (arena, &pubk->u.rsa.publicExponent,
+				       &privk->u.rsa.publicExponent);
+		if (rv == SECSuccess)
+		    return pubk;
+	    }
+	} else {
+	    PORT_SetError (SEC_ERROR_NO_MEMORY);
+	}
+	break;
+      case NSSLOWKEYDSAKey:
+	pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
+						    sizeof(NSSLOWKEYPublicKey));
+	if (pubk != NULL) {
+	    SECStatus rv;
+
+	    pubk->arena = arena;
+	    pubk->keyType = privk->keyType;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue,
+				  &privk->u.dsa.publicValue);
+	    if (rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime,
+				  &privk->u.dsa.params.prime);
+	    if (rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime,
+				  &privk->u.dsa.params.subPrime);
+	    if (rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base,
+				  &privk->u.dsa.params.base);
+	    if (rv == SECSuccess) return pubk;
+	}
+	break;
+      case NSSLOWKEYDHKey:
+	pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
+						    sizeof(NSSLOWKEYPublicKey));
+	if (pubk != NULL) {
+	    SECStatus rv;
+
+	    pubk->arena = arena;
+	    pubk->keyType = privk->keyType;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue,
+				  &privk->u.dh.publicValue);
+	    if (rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.dh.prime,
+				  &privk->u.dh.prime);
+	    if (rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.dh.base,
+				  &privk->u.dh.base);
+	    if (rv == SECSuccess) return pubk;
+	}
+	break;
+#ifdef NSS_ENABLE_ECC
+      case NSSLOWKEYECKey:
+	pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
+						    sizeof(NSSLOWKEYPublicKey));
+	if (pubk != NULL) {
+	    SECStatus rv;
+
+	    pubk->arena = arena;
+	    pubk->keyType = privk->keyType;
+	    rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue,
+				  &privk->u.ec.publicValue);
+	    if (rv != SECSuccess) break;
+	    pubk->u.ec.ecParams.arena = arena;
+	    /* Copy the rest of the params */
+	    rv = EC_CopyParams(arena, &(pubk->u.ec.ecParams),
+			       &(privk->u.ec.ecParams));
+	    if (rv == SECSuccess) return pubk;
+	}
+	break;
+#endif /* NSS_ENABLE_ECC */
+	/* No Fortezza in Low Key implementations (Fortezza keys aren't
+	 * stored in our data base */
+    default:
+	break;
+    }
+
+    PORT_FreeArena (arena, PR_FALSE);
+    return NULL;
+}
+
+NSSLOWKEYPrivateKey *
+nsslowkey_CopyPrivateKey(NSSLOWKEYPrivateKey *privKey)
+{
+    NSSLOWKEYPrivateKey *returnKey = NULL;
+    SECStatus rv = SECFailure;
+    PLArenaPool *poolp;
+
+    if(!privKey) {
+	return NULL;
+    }
+
+    poolp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if(!poolp) {
+	return NULL;
+    }
+
+    returnKey = (NSSLOWKEYPrivateKey*)PORT_ArenaZAlloc(poolp, sizeof(NSSLOWKEYPrivateKey));
+    if(!returnKey) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    returnKey->keyType = privKey->keyType;
+    returnKey->arena = poolp;
+
+    switch(privKey->keyType) {
+	case NSSLOWKEYRSAKey:
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.modulus), 
+	    				&(privKey->u.rsa.modulus));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.version), 
+	    				&(privKey->u.rsa.version));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.publicExponent), 
+	    				&(privKey->u.rsa.publicExponent));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.privateExponent), 
+	    				&(privKey->u.rsa.privateExponent));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime1), 
+	    				&(privKey->u.rsa.prime1));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime2), 
+	    				&(privKey->u.rsa.prime2));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent1), 
+	    				&(privKey->u.rsa.exponent1));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent2), 
+	    				&(privKey->u.rsa.exponent2));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.coefficient), 
+	    				&(privKey->u.rsa.coefficient));
+	    if(rv != SECSuccess) break;
+	    break;
+	case NSSLOWKEYDSAKey:
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.publicValue),
+	    				&(privKey->u.dsa.publicValue));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.privateValue),
+	    				&(privKey->u.dsa.privateValue));
+	    if(rv != SECSuccess) break;
+	    returnKey->u.dsa.params.arena = poolp;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.prime),
+					&(privKey->u.dsa.params.prime));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.subPrime),
+					&(privKey->u.dsa.params.subPrime));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.base),
+					&(privKey->u.dsa.params.base));
+	    if(rv != SECSuccess) break;
+	    break;
+	case NSSLOWKEYDHKey:
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.publicValue),
+	    				&(privKey->u.dh.publicValue));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.privateValue),
+	    				&(privKey->u.dh.privateValue));
+	    if(rv != SECSuccess) break;
+	    returnKey->u.dsa.params.arena = poolp;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.prime),
+					&(privKey->u.dh.prime));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.base),
+					&(privKey->u.dh.base));
+	    if(rv != SECSuccess) break;
+	    break;
+#ifdef NSS_ENABLE_ECC
+	case NSSLOWKEYECKey:
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.version),
+	    				&(privKey->u.ec.version));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.publicValue),
+	    				&(privKey->u.ec.publicValue));
+	    if(rv != SECSuccess) break;
+	    rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.privateValue),
+	    				&(privKey->u.ec.privateValue));
+	    if(rv != SECSuccess) break;
+	    returnKey->u.ec.ecParams.arena = poolp;
+	    /* Copy the rest of the params */
+	    rv = EC_CopyParams(poolp, &(returnKey->u.ec.ecParams),
+			       &(privKey->u.ec.ecParams));
+	    if (rv != SECSuccess) break;
+	    break;
+#endif /* NSS_ENABLE_ECC */
+	default:
+	    rv = SECFailure;
+    }
+
+loser:
+
+    if(rv != SECSuccess) {
+	PORT_FreeArena(poolp, PR_TRUE);
+	returnKey = NULL;
+    }
+
+    return returnKey;
+}
diff --git a/mozilla/security/nss/lib/softoken/lowkeyi.h b/mozilla/security/nss/lib/softoken/lowkeyi.h
new file mode 100644
index 0000000..ec6f0e9
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/lowkeyi.h
@@ -0,0 +1,108 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: lowkeyi.h,v 1.11 2007/06/13 00:24:56 rrelyea%redhat.com Exp $ */
+
+#ifndef _LOWKEYI_H_
+#define _LOWKEYI_H_
+
+#include "prtypes.h"
+#include "seccomon.h"
+#include "secoidt.h"
+#include "lowkeyti.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+ * See bugzilla bug 125359
+ * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
+ * all of the templates above that en/decode into integers must be converted
+ * from ASN.1's signed integer type.  This is done by marking either the
+ * source or destination (encoding or decoding, respectively) type as
+ * siUnsignedInteger.
+ */
+extern void prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key);
+extern void prepare_low_pqg_params_for_asn1(PQGParams *params);
+extern void prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key);
+extern void prepare_low_dsa_priv_key_export_for_asn1(NSSLOWKEYPrivateKey *key);
+extern void prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key);
+#ifdef NSS_ENABLE_ECC
+extern void prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key);
+extern void prepare_low_ecparams_for_asn1(ECParams *params);
+#endif /* NSS_ENABLE_ECC */
+
+/*
+** Destroy a private key object.
+**	"key" the object
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *key);
+
+/*
+** Destroy a public key object.
+**	"key" the object
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *key);
+
+/*
+** Return the modulus length of "pubKey".
+*/
+extern unsigned int nsslowkey_PublicModulusLen(NSSLOWKEYPublicKey *pubKey);
+
+
+/*
+** Return the modulus length of "privKey".
+*/
+extern unsigned int nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privKey);
+
+
+/*
+** Convert a low private key "privateKey" into a public low key
+*/
+extern NSSLOWKEYPublicKey 
+		*nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privateKey);
+
+/* Make a copy of a low private key in it's own arena.
+ * a return of NULL indicates an error.
+ */
+extern NSSLOWKEYPrivateKey *
+nsslowkey_CopyPrivateKey(NSSLOWKEYPrivateKey *privKey);
+
+
+SEC_END_PROTOS
+
+#endif /* _LOWKEYI_H_ */
diff --git a/mozilla/security/nss/lib/softoken/lowkeyti.h b/mozilla/security/nss/lib/softoken/lowkeyti.h
new file mode 100644
index 0000000..15bb973
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/lowkeyti.h
@@ -0,0 +1,127 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+#ifndef _LOWKEYTI_H_
+#define _LOWKEYTI_H_ 1
+
+#include "blapit.h"
+#include "prtypes.h"
+#include "plarena.h"
+#include "secitem.h"
+#include "secasn1t.h"
+#include "secoidt.h"
+
+/*
+** Typedef for callback to get a password "key".
+*/
+extern const SEC_ASN1Template nsslowkey_PQGParamsTemplate[];
+extern const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[];
+extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[];
+extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[];
+extern const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[];
+extern const SEC_ASN1Template nsslowkey_DHPrivateKeyExportTemplate[];
+#ifdef NSS_ENABLE_ECC
+#define NSSLOWKEY_EC_PRIVATE_KEY_VERSION   1  /* as per SECG 1 C.4 */
+extern const SEC_ASN1Template nsslowkey_ECParamsTemplate[];
+extern const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[];
+#endif /* NSS_ENABLE_ECC */
+
+extern const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[];
+extern const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[];
+
+/*
+ * PKCS #8 attributes
+ */
+struct NSSLOWKEYAttributeStr {
+    SECItem attrType;
+    SECItem *attrValue;
+};
+typedef struct NSSLOWKEYAttributeStr NSSLOWKEYAttribute;
+
+/*
+** A PKCS#8 private key info object
+*/
+struct NSSLOWKEYPrivateKeyInfoStr {
+    PLArenaPool *arena;
+    SECItem version;
+    SECAlgorithmID algorithm;
+    SECItem privateKey;
+    NSSLOWKEYAttribute **attributes;
+};
+typedef struct NSSLOWKEYPrivateKeyInfoStr NSSLOWKEYPrivateKeyInfo;
+#define NSSLOWKEY_PRIVATE_KEY_INFO_VERSION	0	/* what we *create* */
+
+typedef enum { 
+    NSSLOWKEYNullKey = 0, 
+    NSSLOWKEYRSAKey = 1, 
+    NSSLOWKEYDSAKey = 2, 
+    NSSLOWKEYDHKey = 4,
+    NSSLOWKEYECKey = 5
+} NSSLOWKEYType;
+
+/*
+** An RSA public key object.
+*/
+struct NSSLOWKEYPublicKeyStr {
+    PLArenaPool *arena;
+    NSSLOWKEYType keyType ;
+    union {
+        RSAPublicKey rsa;
+	DSAPublicKey dsa;
+	DHPublicKey  dh;
+	ECPublicKey  ec;
+    } u;
+};
+typedef struct NSSLOWKEYPublicKeyStr NSSLOWKEYPublicKey;
+
+/*
+** Low Level private key object
+** This is only used by the raw Crypto engines (crypto), keydb (keydb),
+** and PKCS #11. Everyone else uses the high level key structure.
+*/
+struct NSSLOWKEYPrivateKeyStr {
+    PLArenaPool *arena;
+    NSSLOWKEYType keyType;
+    union {
+        RSAPrivateKey rsa;
+	DSAPrivateKey dsa;
+	DHPrivateKey  dh;
+	ECPrivateKey  ec;
+    } u;
+};
+typedef struct NSSLOWKEYPrivateKeyStr NSSLOWKEYPrivateKey;
+
+#endif	/* _LOWKEYTI_H_ */
diff --git a/mozilla/security/nss/lib/softoken/lowpbe.c b/mozilla/security/nss/lib/softoken/lowpbe.c
new file mode 100644
index 0000000..f918398
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/lowpbe.c
@@ -0,0 +1,1410 @@
+/* ***** 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 "plarena.h"
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "secport.h"
+#include "hasht.h"
+#include "pkcs11t.h"
+#include "blapi.h"
+#include "hasht.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "lowpbe.h"
+#include "secoid.h"
+#include "alghmac.h"
+#include "softoken.h"
+#include "secerr.h"
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+/* template for PKCS 5 PBE Parameter.  This template has been expanded
+ * based upon the additions in PKCS 12.  This should eventually be moved
+ * if RSA updates PKCS 5.
+ */
+static const SEC_ASN1Template NSSPKCS5PBEParameterTemplate[] =
+{
+    { SEC_ASN1_SEQUENCE, 
+	0, NULL, sizeof(NSSPKCS5PBEParameter) },
+    { SEC_ASN1_OCTET_STRING, 
+	offsetof(NSSPKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER,
+	offsetof(NSSPKCS5PBEParameter, iteration) },
+    { 0 }
+};
+
+static const SEC_ASN1Template NSSPKCS5PKCS12V2PBEParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSPKCS5PBEParameter) },
+    { SEC_ASN1_OCTET_STRING, offsetof(NSSPKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, iteration) },
+    { 0 }
+};
+
+
+/* PKCS5 v2 */
+
+struct nsspkcs5V2PBEParameterStr {
+    SECAlgorithmID keyParams;  /* parameters of the key generation */
+    SECAlgorithmID algParams;  /* paramters for the encryption or mac op */
+};
+
+typedef struct nsspkcs5V2PBEParameterStr nsspkcs5V2PBEParameter;
+#define PBKDF2
+
+#ifdef PBKDF2
+static const SEC_ASN1Template NSSPKCS5V2PBES2ParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(nsspkcs5V2PBEParameter) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+        offsetof(nsspkcs5V2PBEParameter, keyParams), 
+        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+        offsetof(nsspkcs5V2PBEParameter, algParams),
+        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { 0 }
+};
+
+static const SEC_ASN1Template NSSPKCS5V2PBEParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSPKCS5PBEParameter) },
+    /* this is really a choice, but since we don't understand any other
+     *choice, just inline it. */
+    { SEC_ASN1_OCTET_STRING, offsetof(NSSPKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, iteration) },
+    { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, keyLength) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+        offsetof(NSSPKCS5PBEParameter, prfAlg),
+        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { 0 }
+};
+#endif
+
+SECStatus
+nsspkcs5_HashBuf(const SECHashObject *hashObj, unsigned char *dest,
+					 unsigned char *src, int len)
+{
+    void *ctx;
+    unsigned int retLen;
+
+    ctx = hashObj->create();
+    if(ctx == NULL) {
+	return SECFailure;
+    }
+    hashObj->begin(ctx);
+    hashObj->update(ctx, src, len);
+    hashObj->end(ctx, dest, &retLen, hashObj->length);
+    hashObj->destroy(ctx, PR_TRUE);
+    return SECSuccess;
+}
+
+/* generate bits using any hash
+ */
+static SECItem *
+nsspkcs5_PBKDF1(const SECHashObject *hashObj, SECItem *salt, SECItem *pwd, 
+						int iter, PRBool faulty3DES) 
+{
+    SECItem *hash = NULL, *pre_hash = NULL;
+    SECStatus rv = SECFailure;
+
+    if((salt == NULL) || (pwd == NULL) || (iter < 0)) {
+	return NULL;
+    }
+	
+    hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+    pre_hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+
+    if((hash != NULL) && (pre_hash != NULL)) {
+	int i, ph_len;
+
+	ph_len = hashObj->length;
+	if((salt->len + pwd->len) > hashObj->length) {
+	    ph_len = salt->len + pwd->len;
+	}
+
+	rv = SECFailure;
+
+	/* allocate buffers */
+	hash->len = hashObj->length;
+	hash->data = (unsigned char *)PORT_ZAlloc(hash->len);
+	pre_hash->data = (unsigned char *)PORT_ZAlloc(ph_len);
+
+	/* in pbeSHA1TripleDESCBC there was an allocation error that made
+	 * it into the caller.  We do not want to propagate those errors
+	 * further, so we are doing it correctly, but reading the old method.
+	 */
+	if (faulty3DES) {
+	    pre_hash->len = ph_len;
+	} else {
+	    pre_hash->len = salt->len + pwd->len;
+	}
+
+	/* preform hash */
+	if ((hash->data != NULL) && (pre_hash->data != NULL)) {
+	    rv = SECSuccess;
+	    /* check for 0 length password */
+	    if(pwd->len > 0) {
+		PORT_Memcpy(pre_hash->data, pwd->data, pwd->len);
+	    }
+	    if(salt->len > 0) {
+		PORT_Memcpy((pre_hash->data+pwd->len), salt->data, salt->len);
+	    }
+	    for(i = 0; ((i < iter) && (rv == SECSuccess)); i++) {
+		rv = nsspkcs5_HashBuf(hashObj, hash->data, 
+					pre_hash->data, pre_hash->len);
+		if(rv != SECFailure) {
+		    pre_hash->len = hashObj->length;
+		    PORT_Memcpy(pre_hash->data, hash->data, hashObj->length);
+		}
+	    }
+	}
+    }
+
+    if(pre_hash != NULL) {
+	SECITEM_FreeItem(pre_hash, PR_TRUE);
+    }
+
+    if((rv != SECSuccess) && (hash != NULL)) {
+	SECITEM_FreeItem(hash, PR_TRUE);
+	hash = NULL;
+    }
+
+    return hash;
+}
+
+/* this bit generation routine is described in PKCS 12 and the proposed
+ * extensions to PKCS 5.  an initial hash is generated following the
+ * instructions laid out in PKCS 5.  If the number of bits generated is
+ * insufficient, then the method discussed in the proposed extensions to
+ * PKCS 5 in PKCS 12 are used.  This extension makes use of the HMAC
+ * function.  And the P_Hash function from the TLS standard.
+ */
+static SECItem *
+nsspkcs5_PFXPBE(const SECHashObject *hashObj, NSSPKCS5PBEParameter *pbe_param,
+				SECItem *init_hash, unsigned int bytes_needed)
+{
+    SECItem *ret_bits = NULL;
+    int hash_size = 0;
+    unsigned int i;
+    unsigned int hash_iter;
+    unsigned int dig_len;
+    SECStatus rv = SECFailure;
+    unsigned char *state = NULL;
+    unsigned int state_len;
+    HMACContext *cx = NULL;
+
+    hash_size = hashObj->length;
+    hash_iter = (bytes_needed + (unsigned int)hash_size - 1) / hash_size;
+
+    /* allocate return buffer */
+    ret_bits = (SECItem  *)PORT_ZAlloc(sizeof(SECItem));
+    if(ret_bits == NULL)
+	return NULL;
+    ret_bits->data = (unsigned char *)PORT_ZAlloc((hash_iter * hash_size) + 1);
+    ret_bits->len = (hash_iter * hash_size);
+    if(ret_bits->data == NULL) {
+	PORT_Free(ret_bits);
+	return NULL;
+    }
+
+    /* allocate intermediate hash buffer.  8 is for the 8 bytes of
+     * data which are added based on iteration number 
+     */
+
+    if ((unsigned int)hash_size > pbe_param->salt.len) {
+	state_len = hash_size;
+    } else {
+	state_len = pbe_param->salt.len;
+    }
+    state = (unsigned char *)PORT_ZAlloc(state_len);
+    if(state == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    if(pbe_param->salt.len > 0) {
+	PORT_Memcpy(state, pbe_param->salt.data, pbe_param->salt.len);
+    }
+
+    cx = HMAC_Create(hashObj, init_hash->data, init_hash->len, PR_TRUE);
+    if (cx == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    for(i = 0; i < hash_iter; i++) { 
+
+	/* generate output bits */
+	HMAC_Begin(cx);
+	HMAC_Update(cx, state, state_len);
+	HMAC_Update(cx, pbe_param->salt.data, pbe_param->salt.len);
+	rv = HMAC_Finish(cx, ret_bits->data + (i * hash_size),
+			 &dig_len, hash_size);
+	if (rv != SECSuccess)
+	    goto loser;
+	PORT_Assert((unsigned int)hash_size == dig_len);
+
+	/* generate new state */
+	HMAC_Begin(cx);
+	HMAC_Update(cx, state, state_len);
+	rv = HMAC_Finish(cx, state, &state_len, state_len);
+	if (rv != SECSuccess)
+	    goto loser;
+	PORT_Assert(state_len == dig_len);
+    }
+
+loser:
+    if (state != NULL)
+	PORT_ZFree(state, state_len);
+    HMAC_Destroy(cx, PR_TRUE);
+
+    if(rv != SECSuccess) {
+	SECITEM_ZfreeItem(ret_bits, PR_TRUE);
+	ret_bits = NULL;
+    }
+
+    return ret_bits;
+}
+
+/* generate bits for the key and iv determination.  if enough bits
+ * are not generated using PKCS 5, then we need to generate more bits
+ * based on the extension proposed in PKCS 12
+ */
+static SECItem *
+nsspkcs5_PBKDF1Extended(const SECHashObject *hashObj,
+	 NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, PRBool faulty3DES)
+{
+    SECItem * hash 		= NULL;
+    SECItem * newHash 		= NULL;
+    int       bytes_needed;
+    int       bytes_available;
+    
+    bytes_needed = pbe_param->ivLen + pbe_param->keyLen;
+    bytes_available = hashObj->length;
+    
+    hash = nsspkcs5_PBKDF1(hashObj, &pbe_param->salt, pwitem, 
+						pbe_param->iter, faulty3DES);
+
+    if(hash == NULL) {
+	return NULL;
+    }
+
+    if(bytes_needed <= bytes_available) {
+	return hash;
+    } 
+
+    newHash = nsspkcs5_PFXPBE(hashObj, pbe_param, hash, bytes_needed);
+    if (hash != newHash)
+	SECITEM_FreeItem(hash, PR_TRUE);
+    return newHash;
+}
+
+#ifdef PBKDF2
+
+/*
+ * PBDKDF2 is PKCS #5 v2.0 it's currently not used by NSS
+ */
+static void
+do_xor(unsigned char *dest, unsigned char *src, int len)
+{
+   /* use byt xor, not all platforms are happy about inaligned 
+    * integer fetches */
+    while (len--) {
+    	*dest = *dest ^ *src;
+	dest++;
+	src++;
+    }
+}
+
+static SECStatus
+nsspkcs5_PBKFD2_F(const SECHashObject *hashobj, SECItem *pwitem, SECItem *salt,
+			int iterations, unsigned int i, unsigned char *T)
+{
+    int j;
+    HMACContext *cx = NULL;
+    unsigned int hLen = hashobj->length;
+    SECStatus rv = SECFailure;
+    unsigned char *last = NULL;
+    unsigned int lastLength = salt->len + 4;
+    unsigned int lastBufLength;
+
+    cx=HMAC_Create(hashobj,pwitem->data,pwitem->len,PR_FALSE);
+    if (cx == NULL) {
+	goto loser;
+    }
+    PORT_Memset(T,0,hLen);
+    lastBufLength = PR_MAX(lastLength, hLen);
+    last = PORT_Alloc(lastBufLength);
+    if (last == NULL) {
+	goto loser;
+    }
+    PORT_Memcpy(last,salt->data,salt->len);
+    last[salt->len  ] = (i >> 24) & 0xff;
+    last[salt->len+1] = (i >> 16) & 0xff;
+    last[salt->len+2] = (i >> 8) & 0xff;
+    last[salt->len+3] =    i  & 0xff;
+
+    /* NOTE: we need at least one iteration to return success! */
+    for (j=0; j < iterations; j++) {
+	HMAC_Begin(cx);
+	HMAC_Update(cx,last,lastLength);
+	rv =HMAC_Finish(cx,last,&lastLength,hLen);
+	if (rv !=SECSuccess) {
+	   break;
+	}
+	do_xor(T,last,hLen);
+    }
+loser:
+    if (cx) {
+	HMAC_Destroy(cx, PR_TRUE);
+    }
+    if (last) {
+	PORT_ZFree(last,lastBufLength);
+    }
+    return rv;
+}
+
+static SECItem *
+nsspkcs5_PBKDF2(const SECHashObject *hashobj, NSSPKCS5PBEParameter *pbe_param, 
+							SECItem *pwitem)
+{
+    int iterations = pbe_param->iter;
+    int bytesNeeded = pbe_param->keyLen;
+    unsigned int dkLen = bytesNeeded;
+    unsigned int hLen = hashobj->length;
+    unsigned int nblocks = (dkLen+hLen-1) / hLen;
+    unsigned int i;
+    unsigned char *rp;
+    unsigned char *T = NULL;
+    SECItem *result = NULL;
+    SECItem *salt = &pbe_param->salt;
+    SECStatus rv = SECFailure;
+
+    result = SECITEM_AllocItem(NULL,NULL,nblocks*hLen);
+    if (result == NULL) {
+	return NULL;
+    }
+
+    T = PORT_Alloc(hLen);
+    if (T == NULL) {
+	goto loser;
+    }
+
+    for (i=1,rp=result->data; i <= nblocks ; i++, rp +=hLen) {
+	rv = nsspkcs5_PBKFD2_F(hashobj,pwitem,salt,iterations,i,T);
+	if (rv != SECSuccess) {
+	    break;
+	}
+	PORT_Memcpy(rp,T,hLen);
+    }
+
+loser:
+    if (T) {
+	PORT_ZFree(T,hLen);
+    }
+    if (rv != SECSuccess) {
+	SECITEM_FreeItem(result,PR_TRUE);
+	result = NULL;
+    } else {
+	result->len = dkLen;
+    }
+	
+    return result;
+}
+#endif
+
+#define HMAC_BUFFER 64
+#define NSSPBE_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y))
+#define NSSPBE_MIN(x,y) ((x) < (y) ? (x) : (y))
+/*
+ * This is the extended PBE function defined by the final PKCS #12 spec.
+ */
+static SECItem *
+nsspkcs5_PKCS12PBE(const SECHashObject *hashObject, 
+		   NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, 
+		   PBEBitGenID bitGenPurpose, unsigned int bytesNeeded)
+{
+    PRArenaPool *arena = NULL;
+    unsigned int SLen,PLen;
+    unsigned int hashLength = hashObject->length;
+    unsigned char *S, *P;
+    SECItem *A = NULL, B, D, I;
+    SECItem *salt = &pbe_param->salt;
+    unsigned int c,i = 0;
+    unsigned int hashLen;
+    int iter;
+    unsigned char *iterBuf;
+    void *hash = NULL;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if(!arena) {
+	return NULL;
+    }
+
+    /* how many hash object lengths are needed */
+    c = (bytesNeeded + (hashLength-1))/hashLength;
+
+    /* initialize our buffers */
+    D.len = HMAC_BUFFER;
+    /* B and D are the same length, use one alloc go get both */
+    D.data = (unsigned char*)PORT_ArenaZAlloc(arena, D.len*2);
+    B.len = D.len;
+    B.data = D.data + D.len;
+
+    /* if all goes well, A will be returned, so don't use our temp arena */
+    A = SECITEM_AllocItem(NULL,NULL,c*hashLength);
+    if (A == NULL) {
+	goto loser;
+    }
+    
+    SLen = NSSPBE_ROUNDUP(salt->len,HMAC_BUFFER);
+    PLen = NSSPBE_ROUNDUP(pwitem->len,HMAC_BUFFER);
+    I.len = SLen+PLen;
+    I.data = (unsigned char*)PORT_ArenaZAlloc(arena, I.len);
+    if (I.data == NULL) {
+	goto loser;
+    }
+
+    /* S & P are only used to initialize I */
+    S = I.data;
+    P = S + SLen;
+
+    PORT_Memset(D.data, (char)bitGenPurpose, D.len);
+    if (SLen) {
+	for (i=0; i < SLen; i += salt->len) {
+	    PORT_Memcpy(S+i, salt->data, NSSPBE_MIN(SLen-i,salt->len));
+	}
+    } 
+    if (PLen) {
+	for (i=0; i < PLen; i += pwitem->len) {
+	    PORT_Memcpy(P+i, pwitem->data, NSSPBE_MIN(PLen-i,pwitem->len));
+	}
+    } 
+
+    iterBuf = (unsigned char*)PORT_ArenaZAlloc(arena,hashLength);
+    if (iterBuf == NULL) {
+	goto loser;
+    }
+
+    hash = hashObject->create();
+    if(!hash) {
+	goto loser;
+    }
+    /* calculate the PBE now */
+    for(i = 0; i < c; i++) {
+	int Bidx;	/* must be signed or the for loop won't terminate */
+	unsigned int k, j;
+	unsigned char *Ai = A->data+i*hashLength;
+
+
+	for(iter = 0; iter < pbe_param->iter; iter++) {
+	    hashObject->begin(hash);
+
+	    if (iter) {
+		hashObject->update(hash, iterBuf, hashLen);
+	    } else {
+		hashObject->update(hash, D.data, D.len);
+		hashObject->update(hash, I.data, I.len); 
+	    }
+
+	    hashObject->end(hash, iterBuf, &hashLen, hashObject->length);
+	    if(hashLen != hashObject->length) {
+		break;
+	    }
+	}
+
+	PORT_Memcpy(Ai, iterBuf, hashLength);
+	for (Bidx = 0; Bidx < B.len; Bidx += hashLength) {
+	    PORT_Memcpy(B.data+Bidx,iterBuf,NSSPBE_MIN(B.len-Bidx,hashLength));
+	}
+
+	k = I.len/B.len;
+	for(j = 0; j < k; j++) {
+	    unsigned int q, carryBit;
+	    unsigned char *Ij = I.data + j*B.len;
+
+	    /* (Ij = Ij+B+1) */
+	    for (Bidx = (B.len-1), q=1, carryBit=0; Bidx >= 0; Bidx--,q=0) {
+		q += (unsigned int)Ij[Bidx];
+		q += (unsigned int)B.data[Bidx];
+		q += carryBit;
+
+		carryBit = (q > 0xff);
+		Ij[Bidx] = (unsigned char)(q & 0xff);
+	    }
+	}
+    }
+loser:
+    if (hash) {
+    	hashObject->destroy(hash, PR_TRUE);
+    }
+    if(arena) {
+	PORT_FreeArena(arena, PR_TRUE);
+    }
+
+    if (A) {
+        /* if i != c, then we didn't complete the loop above and must of failed
+         * somwhere along the way */
+        if (i != c) {
+	    SECITEM_ZfreeItem(A,PR_TRUE);
+	    A = NULL;
+        } else {
+    	    A->len = bytesNeeded;
+        }
+    }
+    
+    return A;
+}
+
+/*
+ * generate key as per PKCS 5
+ */
+SECItem *
+nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem,
+		      SECItem *iv, PRBool faulty3DES)
+{
+    SECItem *hash = NULL, *key = NULL;
+    const SECHashObject *hashObj;
+    PRBool getIV = PR_FALSE;
+
+    if((pbe_param == NULL) || (pwitem == NULL)) {
+	return NULL;
+    }
+
+    key = SECITEM_AllocItem(NULL,NULL,pbe_param->keyLen);
+    if (key == NULL) {
+	return NULL;
+    }
+
+    if (iv && (pbe_param->ivLen) && (iv->data == NULL)) {
+	getIV = PR_TRUE;
+    	iv->data = (unsigned char *)PORT_Alloc(pbe_param->ivLen);
+    	if (iv->data == NULL) {
+	    goto loser;
+	}
+	iv->len = pbe_param->ivLen;
+    }
+
+    hashObj = HASH_GetRawHashObject(pbe_param->hashType);
+    switch (pbe_param->pbeType) {
+    case NSSPKCS5_PBKDF1:
+	hash = nsspkcs5_PBKDF1Extended(hashObj,pbe_param,pwitem,faulty3DES);
+	if (hash == NULL) {
+	    goto loser;
+	}
+	PORT_Assert(hash->len >= key->len+(getIV ? iv->len : 0));
+	if (getIV) {
+	    PORT_Memcpy(iv->data, hash->data+(hash->len - iv->len),iv->len);
+	} 
+	
+    	break;
+#ifdef PBKDF2
+    case NSSPKCS5_PBKDF2:
+	hash = nsspkcs5_PBKDF2(hashObj,pbe_param,pwitem);
+	if (getIV) {
+	    PORT_Memcpy(iv->data, pbe_param->ivData, iv->len);
+	}
+    	break;
+#endif
+    case NSSPKCS5_PKCS12_V2:
+	if (getIV) {
+	    hash = nsspkcs5_PKCS12PBE(hashObj,pbe_param,pwitem,
+						pbeBitGenCipherIV,iv->len);
+	    if (hash == NULL) {
+		goto loser;
+	    }
+	    PORT_Memcpy(iv->data,hash->data,iv->len);
+	    SECITEM_ZfreeItem(hash,PR_TRUE);
+	    hash = NULL;
+	}
+	hash = nsspkcs5_PKCS12PBE(hashObj,pbe_param,pwitem,
+						pbe_param->keyID,key->len);
+    default:
+	break;
+    }
+
+    if (hash == NULL) {
+	goto loser;
+    }
+
+    if (pbe_param->is2KeyDES) {
+	PORT_Memcpy(key->data, hash->data, (key->len * 2) / 3);
+	PORT_Memcpy(&(key->data[(key->len  * 2) / 3]), key->data,
+		    key->len / 3);
+    } else {
+	PORT_Memcpy(key->data, hash->data, key->len);
+    }
+
+    SECITEM_ZfreeItem(hash, PR_TRUE);
+    return key;
+
+loser:
+    if (getIV && iv->data) {
+	PORT_ZFree(iv->data,iv->len);
+	iv->data = NULL;
+    }
+
+    SECITEM_ZfreeItem(key, PR_TRUE);
+    return NULL;
+}
+
+static SECStatus
+nsspkcs5_FillInParam(SECOidTag algorithm, NSSPKCS5PBEParameter *pbe_param)
+{
+    PRBool skipType = PR_FALSE;
+
+    pbe_param->keyLen = 5;
+    pbe_param->ivLen = 8;
+    pbe_param->hashType = HASH_AlgSHA1;
+    pbe_param->pbeType = NSSPKCS5_PBKDF1;
+    pbe_param->encAlg = SEC_OID_RC2_CBC;
+    pbe_param->is2KeyDES = PR_FALSE;
+    switch(algorithm) {
+    /* DES3 Algorithms */
+    case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
+	pbe_param->is2KeyDES = PR_TRUE;
+	/* fall through */
+    case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
+	pbe_param->pbeType = NSSPKCS5_PKCS12_V2;
+	/* fall through */
+    case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:
+	pbe_param->keyLen = 24;
+	pbe_param->encAlg = SEC_OID_DES_EDE3_CBC;
+	break;
+
+    /* DES Algorithms */
+    case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:
+    	pbe_param->hashType = HASH_AlgMD2;
+	goto finish_des;
+    case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:
+    	pbe_param->hashType = HASH_AlgMD5;
+	/* fall through */
+    case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC:
+finish_des:
+	pbe_param->keyLen = 8;
+	pbe_param->encAlg =  SEC_OID_DES_CBC;
+	break;
+
+    /* RC2 Algorithms */
+    case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	pbe_param->keyLen = 16;
+	/* fall through */
+    case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	pbe_param->pbeType = NSSPKCS5_PKCS12_V2;
+	break;
+    case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	pbe_param->keyLen = 16;
+	/* fall through */
+    case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	break;
+
+    /* RC4 algorithms */
+    case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	skipType = PR_TRUE;
+	/* fall through */
+    case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	pbe_param->keyLen = 16;
+	/* fall through */
+    case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	if (!skipType) {
+    	    pbe_param->pbeType = NSSPKCS5_PKCS12_V2;
+	}
+	/* fall through */
+    case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4:
+        pbe_param->ivLen = 0;
+        pbe_param->encAlg =  SEC_OID_RC4;
+        break;
+
+#ifdef PBKDF2
+    case SEC_OID_PKCS5_PBKDF2:
+    case SEC_OID_PKCS5_PBES2:
+    case SEC_OID_PKCS5_PBMAC1:
+	/* everything else will be filled in by the template */
+        pbe_param->ivLen = 0;
+	pbe_param->pbeType = NSSPKCS5_PBKDF2;
+        pbe_param->encAlg =  SEC_OID_PKCS5_PBKDF2;
+	pbe_param->keyLen = 0; /* needs to be set by caller after return */
+	break;
+#endif
+
+    default:
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+/* decode the algid and generate a PKCS 5 parameter from it
+ */
+NSSPKCS5PBEParameter *
+nsspkcs5_NewParam(SECOidTag alg, SECItem *salt, int iterator)
+{
+    PRArenaPool *arena = NULL;
+    NSSPKCS5PBEParameter *pbe_param = NULL;
+    SECStatus rv = SECFailure;
+
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (arena == NULL)
+	return NULL;
+
+    /* allocate memory for the parameter */
+    pbe_param = (NSSPKCS5PBEParameter *)PORT_ArenaZAlloc(arena, 
+	sizeof(NSSPKCS5PBEParameter));
+
+    if (pbe_param == NULL) {
+	goto loser;
+    }
+
+    pbe_param->poolp = arena;
+
+    rv = nsspkcs5_FillInParam(alg, pbe_param);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    pbe_param->iter = iterator;
+    if (salt) {
+	rv = SECITEM_CopyItem(arena,&pbe_param->salt,salt);
+    }
+
+    /* default key gen */
+    pbe_param->keyID = pbeBitGenCipherKey;
+
+loser:
+    if (rv != SECSuccess) {
+	PORT_FreeArena(arena, PR_TRUE);
+	pbe_param = NULL;
+    }
+
+    return pbe_param;
+}
+
+/*
+ * find the hash type needed to implement a specific HMAC.
+ * OID definitions are from pkcs 5 v2.0 and 2.1
+ */
+HASH_HashType
+HASH_FromHMACOid(SECOidTag hmac)
+{
+    switch (hmac) {
+    case SEC_OID_HMAC_SHA1:
+    	return HASH_AlgSHA1;
+    case SEC_OID_HMAC_SHA256:
+    	return HASH_AlgSHA256;
+    case SEC_OID_HMAC_SHA384:
+    	return HASH_AlgSHA384;
+    case SEC_OID_HMAC_SHA512:
+    	return HASH_AlgSHA512;
+    case SEC_OID_HMAC_SHA224:
+    default:
+	break;
+    }
+    return HASH_AlgNULL;
+}
+
+/* decode the algid and generate a PKCS 5 parameter from it
+ */
+NSSPKCS5PBEParameter *
+nsspkcs5_AlgidToParam(SECAlgorithmID *algid)
+{
+    NSSPKCS5PBEParameter *pbe_param = NULL;
+    nsspkcs5V2PBEParameter pbev2_param;
+    SECOidTag algorithm;
+    SECStatus rv = SECFailure;
+
+    if (algid == NULL) {
+	return NULL;
+    }
+
+    algorithm = SECOID_GetAlgorithmTag(algid);
+    if (algorithm == SEC_OID_UNKNOWN) {
+	goto loser;
+    }
+
+    pbe_param = nsspkcs5_NewParam(algorithm, NULL, 1);
+    if (pbe_param == NULL) {
+	goto loser;
+    }
+
+    /* decode parameter */
+    rv = SECFailure;
+    switch (pbe_param->pbeType) {
+    case NSSPKCS5_PBKDF1:
+	rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, 
+	    NSSPKCS5PBEParameterTemplate, &algid->parameters);
+	break;
+    case NSSPKCS5_PKCS12_V2:
+	rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, 
+		NSSPKCS5PKCS12V2PBEParameterTemplate, &algid->parameters);
+	break;
+#ifdef PBKDF2
+    case NSSPKCS5_PBKDF2:
+	PORT_Memset(&pbev2_param,0, sizeof(pbev2_param));
+	/* just the PBE */
+	if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	    rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param,
+		NSSPKCS5V2PBEParameterTemplate, &algid->parameters);
+	} else {
+	    /* PBE data an others */
+	    rv = SEC_ASN1DecodeItem(pbe_param->poolp, &pbev2_param, 
+		NSSPKCS5V2PBES2ParameterTemplate, &algid->parameters);
+	    if (rv != SECSuccess) {
+		break;
+	    }
+            pbe_param->encAlg = SECOID_GetAlgorithmTag(&pbev2_param.algParams);
+	    rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param,
+		NSSPKCS5V2PBEParameterTemplate, 
+		&pbev2_param.keyParams.parameters);
+	    if (rv != SECSuccess) {
+		break;
+	    }
+    	    pbe_param->keyLen = DER_GetInteger(&pbe_param->keyLength);
+	}
+	/* we we are encrypting, save any iv's */
+	if (algorithm == SEC_OID_PKCS5_PBES2) {
+	    pbe_param->ivLen = pbev2_param.algParams.parameters.len;
+	    pbe_param->ivData = pbev2_param.algParams.parameters.data;
+	}
+	pbe_param->hashType = 
+	    HASH_FromHMACOid(SECOID_GetAlgorithmTag(&pbe_param->prfAlg));
+	if (pbe_param->hashType == HASH_AlgNULL) {
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    rv = SECFailure;
+	}
+	break;
+#endif
+    }
+
+loser:
+    if (rv == SECSuccess) {
+    	pbe_param->iter = DER_GetInteger(&pbe_param->iteration);
+    } else {
+	nsspkcs5_DestroyPBEParameter(pbe_param);
+	pbe_param = NULL;
+    }
+
+    return pbe_param;
+}
+
+/* destroy a pbe parameter.  it assumes that the parameter was 
+ * generated using the appropriate create function and therefor
+ * contains an arena pool.
+ */
+void 
+nsspkcs5_DestroyPBEParameter(NSSPKCS5PBEParameter *pbe_param)
+{
+    if (pbe_param != NULL) {
+	PORT_FreeArena(pbe_param->poolp, PR_FALSE);
+    }
+}
+
+
+/* crypto routines */
+/* perform DES encryption and decryption.  these routines are called
+ * by nsspkcs5_CipherData.  In the case of an error, NULL is returned.
+ */
+static SECItem *
+sec_pkcs5_des(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des, 
+								PRBool encrypt)
+{
+    SECItem *dest;
+    SECItem *dup_src;
+    SECStatus rv = SECFailure;
+    int pad;
+
+    if((src == NULL) || (key == NULL) || (iv == NULL))
+	return NULL;
+
+    dup_src = SECITEM_DupItem(src);
+    if(dup_src == NULL) {
+	return NULL;
+    }
+
+    if(encrypt != PR_FALSE) {
+	void *dummy;
+
+	dummy = CBC_PadBuffer(NULL, dup_src->data, 
+	    dup_src->len, &dup_src->len, 8 /* DES_BLOCK_SIZE */);
+	if(dummy == NULL) {
+	    SECITEM_FreeItem(dup_src, PR_TRUE);
+	    return NULL;
+	}
+	dup_src->data = (unsigned char*)dummy;
+    }
+
+    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+    if(dest != NULL) {
+	/* allocate with over flow */
+	dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64);
+	if(dest->data != NULL) {
+	    DESContext *ctxt;
+	    ctxt = DES_CreateContext(key->data, iv->data, 
+			(triple_des ? NSS_DES_EDE3_CBC : NSS_DES_CBC), 
+			encrypt);
+	
+	    if(ctxt != NULL) {
+		rv = (encrypt ? DES_Encrypt : DES_Decrypt)(
+			ctxt, dest->data, &dest->len,
+			dup_src->len + 64, dup_src->data, dup_src->len);
+
+		/* remove padding -- assumes 64 bit blocks */
+		if((encrypt == PR_FALSE) && (rv == SECSuccess)) {
+		    pad = dest->data[dest->len-1];
+		    if((pad > 0) && (pad <= 8)) {
+			if(dest->data[dest->len-pad] != pad) {
+			    rv = SECFailure;
+			    PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+			} else {
+			    dest->len -= pad;
+			}
+		    } else {
+			rv = SECFailure;
+			PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+		    }
+		}
+		DES_DestroyContext(ctxt, PR_TRUE);
+	    }
+	}
+    }
+
+    if(rv == SECFailure) {
+	if(dest != NULL) {
+	    SECITEM_FreeItem(dest, PR_TRUE);
+	}
+	dest = NULL;
+    }
+
+    if(dup_src != NULL) {
+	SECITEM_FreeItem(dup_src, PR_TRUE);
+    }
+
+    return dest;
+}
+
+/* perform aes encryption/decryption if an error occurs, NULL is returned
+ */
+static SECItem *
+sec_pkcs5_aes(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des, 
+								PRBool encrypt)
+{
+    SECItem *dest;
+    SECItem *dup_src;
+    SECStatus rv = SECFailure;
+    int pad;
+
+    if((src == NULL) || (key == NULL) || (iv == NULL))
+	return NULL;
+
+    dup_src = SECITEM_DupItem(src);
+    if(dup_src == NULL) {
+	return NULL;
+    }
+
+    if(encrypt != PR_FALSE) {
+	void *dummy;
+
+	dummy = CBC_PadBuffer(NULL, dup_src->data, 
+	    dup_src->len, &dup_src->len,AES_BLOCK_SIZE);
+	if(dummy == NULL) {
+	    SECITEM_FreeItem(dup_src, PR_TRUE);
+	    return NULL;
+	}
+	dup_src->data = (unsigned char*)dummy;
+    }
+
+    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+    if(dest != NULL) {
+	/* allocate with over flow */
+	dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64);
+	if(dest->data != NULL) {
+	    AESContext *ctxt;
+	    ctxt = AES_CreateContext(key->data, iv->data, 
+			NSS_AES_CBC, encrypt, key->len, 16);
+	
+	    if(ctxt != NULL) {
+		rv = (encrypt ? AES_Encrypt : AES_Decrypt)(
+			ctxt, dest->data, &dest->len,
+			dup_src->len + 64, dup_src->data, dup_src->len);
+
+		/* remove padding -- assumes 64 bit blocks */
+		if((encrypt == PR_FALSE) && (rv == SECSuccess)) {
+		    pad = dest->data[dest->len-1];
+		    if((pad > 0) && (pad <= 16)) {
+			if(dest->data[dest->len-pad] != pad) {
+			    rv = SECFailure;
+			    PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+			} else {
+			    dest->len -= pad;
+			}
+		    } else {
+			rv = SECFailure;
+			PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+		    }
+		}
+		AES_DestroyContext(ctxt, PR_TRUE);
+	    }
+	}
+    }
+
+    if(rv == SECFailure) {
+	if(dest != NULL) {
+	    SECITEM_FreeItem(dest, PR_TRUE);
+	}
+	dest = NULL;
+    }
+
+    if(dup_src != NULL) {
+	SECITEM_FreeItem(dup_src, PR_TRUE);
+    }
+
+    return dest;
+}
+
+/* perform rc2 encryption/decryption if an error occurs, NULL is returned
+ */
+static SECItem *
+sec_pkcs5_rc2(SECItem *key, SECItem *iv, SECItem *src, PRBool dummy, 
+								PRBool encrypt)
+{
+    SECItem *dest;
+    SECItem *dup_src;
+    SECStatus rv = SECFailure;
+    int pad;
+
+    if((src == NULL) || (key == NULL) || (iv == NULL)) {
+	return NULL;
+    }
+
+    dup_src = SECITEM_DupItem(src);
+    if(dup_src == NULL) {
+	return NULL;
+    }
+
+    if(encrypt != PR_FALSE) {
+	void *dummy;
+
+	dummy = CBC_PadBuffer(NULL, dup_src->data, 
+		      dup_src->len, &dup_src->len, 8 /* RC2_BLOCK_SIZE */);
+	if(dummy == NULL) {
+	    SECITEM_FreeItem(dup_src, PR_TRUE);
+	    return NULL;
+	}
+	dup_src->data = (unsigned char*)dummy;
+    }
+
+    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+    if(dest != NULL) {
+	dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64);
+	if(dest->data != NULL) {
+	    RC2Context *ctxt;
+
+	    ctxt = RC2_CreateContext(key->data, key->len, iv->data,
+					 	NSS_RC2_CBC, key->len);
+
+	    if(ctxt != NULL) {
+		rv = (encrypt ? RC2_Encrypt: RC2_Decrypt)(
+			ctxt, dest->data, &dest->len,
+			dup_src->len + 64, dup_src->data, dup_src->len);
+
+		/* assumes 8 byte blocks  -- remove padding */	
+		if((rv == SECSuccess) && (encrypt != PR_TRUE)) {
+		    pad = dest->data[dest->len-1];
+		    if((pad > 0) && (pad <= 8)) {
+			if(dest->data[dest->len-pad] != pad) {
+			    PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+			    rv = SECFailure;
+			} else {
+			    dest->len -= pad;
+			}
+		    } else {
+			PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+			rv = SECFailure;
+		    }
+		}
+
+	    }
+	}
+    }
+
+    if((rv != SECSuccess) && (dest != NULL)) {
+	SECITEM_FreeItem(dest, PR_TRUE);
+	dest = NULL;
+    }
+
+    if(dup_src != NULL) {
+	SECITEM_FreeItem(dup_src, PR_TRUE);
+    }
+
+    return dest;
+}
+
+/* perform rc4 encryption and decryption */
+static SECItem *
+sec_pkcs5_rc4(SECItem *key, SECItem *iv, SECItem *src, PRBool dummy_op,
+								 PRBool encrypt)
+{
+    SECItem *dest;
+    SECStatus rv = SECFailure;
+
+    if((src == NULL) || (key == NULL) || (iv == NULL)) {
+	return NULL;
+    }
+
+    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+    if(dest != NULL) {
+	dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
+	    (src->len + 64));
+	if(dest->data != NULL) {
+	    RC4Context *ctxt;
+
+	    ctxt = RC4_CreateContext(key->data, key->len);
+	    if(ctxt) { 
+		rv = (encrypt ? RC4_Encrypt : RC4_Decrypt)(
+				ctxt, dest->data, &dest->len,
+				src->len + 64, src->data, src->len);
+		RC4_DestroyContext(ctxt, PR_TRUE);
+	    }
+	}
+    }
+
+    if((rv != SECSuccess) && (dest)) {
+	SECITEM_FreeItem(dest, PR_TRUE);
+	dest = NULL;
+    }
+
+    return dest;
+}
+/* function pointer template for crypto functions */
+typedef SECItem *(* pkcs5_crypto_func)(SECItem *key, SECItem *iv,
+                                         SECItem *src, PRBool op1, PRBool op2);
+
+/* performs the cipher operation on the src and returns the result.
+ * if an error occurs, NULL is returned. 
+ *
+ * a null length password is allowed.  this corresponds to encrypting
+ * the data with ust the salt.
+ */
+/* change this to use PKCS 11? */
+SECItem *
+nsspkcs5_CipherData(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, 
+		    SECItem *src, PRBool encrypt, PRBool *update)
+{
+    SECItem *key = NULL, iv;
+    SECItem *dest = NULL;
+    PRBool tripleDES = PR_TRUE;
+    pkcs5_crypto_func cryptof;
+
+    iv.data = NULL;
+
+    if (update) { 
+        *update = PR_FALSE;
+    }
+
+    if ((pwitem == NULL) || (src == NULL)) {
+	return NULL;
+    }
+
+    /* get key, and iv */
+    key = nsspkcs5_ComputeKeyAndIV(pbe_param, pwitem, &iv, PR_FALSE);
+    if(key == NULL) {
+	return NULL;
+    }
+
+    switch(pbe_param->encAlg) {
+    /* PKCS 5 v2 only */
+    case SEC_OID_AES_128_CBC:
+    case SEC_OID_AES_192_CBC:
+    case SEC_OID_AES_256_CBC:
+	cryptof = sec_pkcs5_aes;
+	break;
+    case SEC_OID_DES_EDE3_CBC:
+	cryptof = sec_pkcs5_des;
+	tripleDES = PR_TRUE;
+	break;
+    case SEC_OID_DES_CBC:
+	cryptof = sec_pkcs5_des;
+	tripleDES = PR_FALSE;
+	break;
+    case SEC_OID_RC2_CBC:
+	cryptof = sec_pkcs5_rc2;
+	break;
+    case SEC_OID_RC4:
+	cryptof = sec_pkcs5_rc4;
+	break;
+    default:
+	cryptof = NULL;
+	break;
+    }
+
+    if (cryptof == NULL) {
+	goto loser;
+    }
+
+    dest = (*cryptof)(key, &iv, src, tripleDES, encrypt);
+    /* 
+     * it's possible for some keys and keydb's to claim to
+     * be triple des when they're really des. In this case
+     * we simply try des. If des works we set the update flag
+     * so the key db knows it needs to update all it's entries.
+     *  The case can only happen on decrypted of a 
+     *  SEC_OID_DES_EDE3_CBD.
+     */
+    if ((dest == NULL) && (encrypt == PR_FALSE) && 
+				(pbe_param->encAlg == SEC_OID_DES_EDE3_CBC)) {
+	dest = (*cryptof)(key, &iv, src, PR_FALSE, encrypt);
+	if (update && (dest != NULL)) *update = PR_TRUE;
+    }
+
+loser:
+    if (key != NULL) {
+	SECITEM_ZfreeItem(key, PR_TRUE);
+    }
+    if (iv.data != NULL) {
+	SECITEM_ZfreeItem(&iv, PR_FALSE);
+    }
+
+    return dest;
+}
+
+/* creates a algorithm ID containing the PBE algorithm and appropriate
+ * parameters.  the required parameter is the algorithm.  if salt is
+ * not specified, it is generated randomly.  if IV is specified, it overrides
+ * the PKCS 5 generation of the IV.  
+ *
+ * the returned SECAlgorithmID should be destroyed using 
+ * SECOID_DestroyAlgorithmID
+ */
+SECAlgorithmID *
+nsspkcs5_CreateAlgorithmID(PRArenaPool *arena, SECOidTag algorithm, 
+					NSSPKCS5PBEParameter *pbe_param)
+{
+    SECAlgorithmID *algid, *ret_algid = NULL;
+    SECItem der_param;
+    nsspkcs5V2PBEParameter pkcs5v2_param;
+
+    SECStatus rv = SECFailure;
+    void *dummy = NULL;
+
+    if (arena == NULL) {
+	return NULL;
+    }
+
+    der_param.data = NULL;
+    der_param.len = 0;
+
+    /* generate the algorithm id */
+    algid = (SECAlgorithmID *)PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
+    if (algid == NULL) {
+	goto loser;
+    }
+
+    if (pbe_param->iteration.data == NULL) {
+	dummy = SEC_ASN1EncodeInteger(pbe_param->poolp,&pbe_param->iteration,
+								pbe_param->iter);
+	if (dummy == NULL) {
+	    goto loser;
+	}
+    }
+    switch (pbe_param->pbeType) {
+    case NSSPKCS5_PBKDF1:
+	dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param,
+					NSSPKCS5PBEParameterTemplate);
+	break;
+    case NSSPKCS5_PKCS12_V2:
+	dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param,
+	    				NSSPKCS5PKCS12V2PBEParameterTemplate);
+	break;
+#ifdef PBKDF2
+    case NSSPKCS5_PBKDF2:
+        if (pbe_param->keyLength.data == NULL) {
+	    dummy = SEC_ASN1EncodeInteger(pbe_param->poolp,
+				&pbe_param->keyLength, pbe_param->keyLen);
+	    if (dummy == NULL) {
+		goto loser;
+	    }
+	}
+	PORT_Memset(&pkcs5v2_param, 0, sizeof(pkcs5v2_param));
+	dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param,
+	    				NSSPKCS5V2PBEParameterTemplate);
+	if (dummy == NULL) {
+	    break;
+	}
+	dummy = NULL;
+	rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.keyParams, 
+				  SEC_OID_PKCS5_PBKDF2, &der_param);
+	if (rv != SECSuccess) {
+	    break;
+	}
+	der_param.data = pbe_param->ivData;
+	der_param.len = pbe_param->ivLen;
+	rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.algParams, 
+		pbe_param->encAlg, pbe_param->ivLen ? &der_param : NULL);
+	if (rv != SECSuccess) {
+	    break;
+	}
+	dummy = SEC_ASN1EncodeItem(arena,  &der_param, &pkcs5v2_param,
+	    				NSSPKCS5V2PBES2ParameterTemplate);
+	break;
+#endif
+    default:
+	break;
+    }
+
+    if (dummy == NULL) {
+	goto loser;
+    }
+	
+    rv = SECOID_SetAlgorithmID(arena, algid, algorithm, &der_param);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID));
+    if (ret_algid == NULL) {
+	goto loser;
+    }
+
+    rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid);
+    if (rv != SECSuccess) {
+	SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE);
+	ret_algid = NULL;
+    }
+
+loser:	
+
+    return ret_algid;
+}
diff --git a/mozilla/security/nss/lib/softoken/lowpbe.h b/mozilla/security/nss/lib/softoken/lowpbe.h
new file mode 100644
index 0000000..974b2fa
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/lowpbe.h
@@ -0,0 +1,140 @@
+/* ***** 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 ***** */
+
+#ifndef _SECPKCS5_H_
+#define _SECPKCS5_H_
+
+#include "plarena.h"
+#include "secitem.h"
+#include "seccomon.h"
+#include "secoidt.h"
+#include "hasht.h"
+
+typedef SECItem * (* SEC_PKCS5GetPBEPassword)(void *arg);
+
+/* used for V2 PKCS 12 Draft Spec */ 
+typedef enum {
+    pbeBitGenIDNull = 0,
+    pbeBitGenCipherKey = 0x01,
+    pbeBitGenCipherIV = 0x02,
+    pbeBitGenIntegrityKey = 0x03
+} PBEBitGenID;
+
+typedef enum {
+    NSSPKCS5_PBKDF1 = 0,
+    NSSPKCS5_PBKDF2 = 1,
+    NSSPKCS5_PKCS12_V2 = 2
+} NSSPKCS5PBEType;
+
+typedef struct NSSPKCS5PBEParameterStr NSSPKCS5PBEParameter;
+
+struct NSSPKCS5PBEParameterStr {
+    PRArenaPool *poolp;
+    SECItem	salt;		/* octet string */
+    SECItem	iteration;	/* integer */
+    SECItem	keyLength;	/* integer */
+
+    /* used locally */
+    int		iter;
+    int 	keyLen;
+    int		ivLen;
+    unsigned char *ivData;
+    HASH_HashType hashType;
+    NSSPKCS5PBEType pbeType;
+    SECAlgorithmID  prfAlg;	
+    PBEBitGenID	keyID;
+    SECOidTag	encAlg;
+    PRBool	is2KeyDES;
+};
+
+
+SEC_BEGIN_PROTOS
+/* Create a PKCS5 Algorithm ID
+ * The algorithm ID is set up using the PKCS #5 parameter structure
+ *  algorithm is the PBE algorithm ID for the desired algorithm
+ *  pbe is a pbe param block with all the info needed to create the 
+ *   algorithm id.
+ * If an error occurs or the algorithm specified is not supported 
+ * or is not a password based encryption algorithm, NULL is returned.
+ * Otherwise, a pointer to the algorithm id is returned.
+ */
+extern SECAlgorithmID *
+nsspkcs5_CreateAlgorithmID(PRArenaPool *arena, SECOidTag algorithm, 
+						NSSPKCS5PBEParameter *pbe);
+
+/*
+ * Convert an Algorithm ID to a PBE Param.
+ * NOTE: this does not suppport PKCS 5 v2 because it's only used for the
+ * keyDB which only support PKCS 5 v1, PFX, and PKCS 12.
+ */
+NSSPKCS5PBEParameter *
+nsspkcs5_AlgidToParam(SECAlgorithmID *algid);
+
+/*
+ * Convert an Algorithm ID to a PBE Param.
+ * NOTE: this does not suppport PKCS 5 v2 because it's only used for the
+ * keyDB which only support PKCS 5 v1, PFX, and PKCS 12.
+ */
+NSSPKCS5PBEParameter *
+nsspkcs5_NewParam(SECOidTag alg, SECItem *salt, int iterator);
+
+
+/* Encrypt/Decrypt data using password based encryption.  
+ *  algid is the PBE algorithm identifier,
+ *  pwitem is the password,
+ *  src is the source for encryption/decryption,
+ *  encrypt is PR_TRUE for encryption, PR_FALSE for decryption.
+ * The key and iv are generated based upon PKCS #5 then the src
+ * is either encrypted or decrypted.  If an error occurs, NULL
+ * is returned, otherwise the ciphered contents is returned.
+ */
+extern SECItem *
+nsspkcs5_CipherData(NSSPKCS5PBEParameter *, SECItem *pwitem,
+		    SECItem *src, PRBool encrypt, PRBool *update);
+
+extern SECItem *
+nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *, SECItem *pwitem,
+		    			SECItem *iv, PRBool faulty3DES);
+
+/* Destroys PBE parameter */
+extern void
+nsspkcs5_DestroyPBEParameter(NSSPKCS5PBEParameter *param);
+
+HASH_HashType HASH_FromHMACOid(SECOidTag oid);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/softoken/padbuf.c b/mozilla/security/nss/lib/softoken/padbuf.c
new file mode 100644
index 0000000..8c43fa2
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/padbuf.c
@@ -0,0 +1,81 @@
+/* ***** 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 "blapit.h"
+#include "secport.h"
+#include "secerr.h"
+
+/*
+ * Prepare a buffer for any padded CBC encryption algorithm, growing to the 
+ * appropriate boundary and filling with the appropriate padding.
+ * blockSize must be a power of 2.
+ *
+ * NOTE: If arena is non-NULL, we re-allocate from there, otherwise
+ * we assume (and use) XP memory (re)allocation.
+ */
+unsigned char *
+CBC_PadBuffer(PRArenaPool *arena, unsigned char *inbuf, unsigned int inlen,
+	      unsigned int *outlen, int blockSize)
+{
+    unsigned char *outbuf;
+    unsigned int   des_len;
+    unsigned int   i;
+    unsigned char  des_pad_len;
+
+    /*
+     * We need from 1 to blockSize bytes -- we *always* grow.
+     * The extra bytes contain the value of the length of the padding:
+     * if we have 2 bytes of padding, then the padding is "0x02, 0x02".
+     */
+    des_len = (inlen + blockSize) & ~(blockSize - 1);
+
+    if (arena != NULL) {
+	outbuf = (unsigned char*)PORT_ArenaGrow (arena, inbuf, inlen, des_len);
+    } else {
+	outbuf = (unsigned char*)PORT_Realloc (inbuf, des_len);
+    }
+
+    if (outbuf == NULL) {
+	PORT_SetError (SEC_ERROR_NO_MEMORY);
+	return NULL;
+    }
+
+    des_pad_len = des_len - inlen;
+    for (i = inlen; i < des_len; i++)
+	outbuf[i] = des_pad_len;
+
+    *outlen = des_len;
+    return outbuf;
+}
diff --git a/mozilla/security/nss/lib/softoken/pk11init.h b/mozilla/security/nss/lib/softoken/pk11init.h
new file mode 100644
index 0000000..d91a0d3
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/pk11init.h
@@ -0,0 +1,55 @@
+/* ***** 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 ***** */
+/*
+ * Internal header file included in pk11wrap dir, or in softoken
+ */
+#ifndef _PK11_INIT_H_
+#define _PK11_INIT_H_ 1
+
+/* hold slot default flags until we initialize a slot. This structure is only
+ * useful between the time we define a module (either by hand or from the
+ * database) and the time the module is loaded. Not reference counted  */
+struct PK11PreSlotInfoStr {
+    CK_SLOT_ID slotID;  	/* slot these flags are for */
+    unsigned long defaultFlags; /* bit mask of default implementation this slot
+				 * provides */
+    int askpw;			/* slot specific password bits */
+    long timeout;		/* slot specific timeout value */
+    char hasRootCerts;		/* is this the root cert PKCS #11 module? */
+    char hasRootTrust;		/* is this the root cert PKCS #11 module? */
+};
+
+#endif /* _PK11_INIT_H_ 1 */
diff --git a/mozilla/security/nss/lib/softoken/pk11pars.h b/mozilla/security/nss/lib/softoken/pk11pars.h
new file mode 100644
index 0000000..dea16e7
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/pk11pars.h
@@ -0,0 +1,872 @@
+/* ***** 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) 2001
+ * 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 ***** */
+/*
+ * The following handles the loading, unloading and management of
+ * various PCKS #11 modules
+ */
+
+
+/*
+ * this header file contains routines for parsing PKCS #11 module spec
+ * strings. It contains 'C' code and should only be included in one module.
+ * Currently it is included in both softoken and the wrapper.
+ */
+#include <ctype.h>
+#include "pkcs11.h"
+#include "seccomon.h"
+#include "prprf.h"
+#include "secmodt.h"
+#include "pk11init.h"
+
+#define SECMOD_ARG_LIBRARY_PARAMETER "library="
+#define SECMOD_ARG_NAME_PARAMETER "name="
+#define SECMOD_ARG_MODULE_PARAMETER "parameters="
+#define SECMOD_ARG_NSS_PARAMETER "NSS="
+#define SECMOD_ARG_FORTEZZA_FLAG "FORTEZZA"
+#define SECMOD_ARG_ESCAPE '\\'
+
+struct secmodargSlotFlagTable {
+    char *name;
+    int len;
+    unsigned long value;
+};
+
+#define SECMOD_DEFAULT_CIPHER_ORDER 0
+#define SECMOD_DEFAULT_TRUST_ORDER 50
+
+
+#define SECMOD_ARG_ENTRY(arg,flag) \
+{ #arg , sizeof(#arg)-1, flag }
+static struct secmodargSlotFlagTable secmod_argSlotFlagTable[] = {
+	SECMOD_ARG_ENTRY(RSA,SECMOD_RSA_FLAG),
+	SECMOD_ARG_ENTRY(DSA,SECMOD_RSA_FLAG),
+	SECMOD_ARG_ENTRY(RC2,SECMOD_RC4_FLAG),
+	SECMOD_ARG_ENTRY(RC4,SECMOD_RC2_FLAG),
+	SECMOD_ARG_ENTRY(DES,SECMOD_DES_FLAG),
+	SECMOD_ARG_ENTRY(DH,SECMOD_DH_FLAG),
+	SECMOD_ARG_ENTRY(FORTEZZA,SECMOD_FORTEZZA_FLAG),
+	SECMOD_ARG_ENTRY(RC5,SECMOD_RC5_FLAG),
+	SECMOD_ARG_ENTRY(SHA1,SECMOD_SHA1_FLAG),
+	SECMOD_ARG_ENTRY(MD5,SECMOD_MD5_FLAG),
+	SECMOD_ARG_ENTRY(MD2,SECMOD_MD2_FLAG),
+	SECMOD_ARG_ENTRY(SSL,SECMOD_SSL_FLAG),
+	SECMOD_ARG_ENTRY(TLS,SECMOD_TLS_FLAG),
+	SECMOD_ARG_ENTRY(AES,SECMOD_AES_FLAG),
+	SECMOD_ARG_ENTRY(Camellia,SECMOD_CAMELLIA_FLAG),
+	SECMOD_ARG_ENTRY(SEED,SECMOD_SEED_FLAG),
+	SECMOD_ARG_ENTRY(PublicCerts,SECMOD_FRIENDLY_FLAG),
+	SECMOD_ARG_ENTRY(RANDOM,SECMOD_RANDOM_FLAG),
+};
+
+#define SECMOD_HANDLE_STRING_ARG(param,target,value,command) \
+    if (PORT_Strncasecmp(param,value,sizeof(value)-1) == 0) { \
+	param += sizeof(value)-1; \
+	if (target) PORT_Free(target); \
+	target = secmod_argFetchValue(param,&next); \
+	param += next; \
+	command ;\
+    } else  
+
+#define SECMOD_HANDLE_FINAL_ARG(param) \
+    { param = secmod_argSkipParameter(param); } param = secmod_argStrip(param);
+	
+
+static int secmod_argSlotFlagTableSize = 
+	sizeof(secmod_argSlotFlagTable)/sizeof(secmod_argSlotFlagTable[0]);
+
+
+static PRBool secmod_argGetPair(char c) {
+    switch (c) {
+    case '\'': return c;
+    case '\"': return c;
+    case '<': return '>';
+    case '{': return '}';
+    case '[': return ']';
+    case '(': return ')';
+    default: break;
+    }
+    return ' ';
+}
+
+static PRBool secmod_argIsBlank(char c) {
+   return isspace((unsigned char )c);
+}
+
+static PRBool secmod_argIsEscape(char c) {
+    return c == '\\';
+}
+
+static PRBool secmod_argIsQuote(char c) {
+    switch (c) {
+    case '\'':
+    case '\"':
+    case '<':
+    case '{': /* } end curly to keep vi bracket matching working */
+    case '(': /* ) */
+    case '[': /* ] */ return PR_TRUE;
+    default: break;
+    }
+    return PR_FALSE;
+}
+
+static PRBool secmod_argHasChar(char *v, char c)
+{
+   for ( ;*v; v++) {
+	if (*v == c) return PR_TRUE;
+   }
+   return PR_FALSE;
+}
+
+static PRBool secmod_argHasBlanks(char *v)
+{
+   for ( ;*v; v++) {
+	if (secmod_argIsBlank(*v)) return PR_TRUE;
+   }
+   return PR_FALSE;
+}
+
+static char *secmod_argStrip(char *c) {
+   while (*c && secmod_argIsBlank(*c)) c++;
+   return c;
+}
+
+static char *
+secmod_argFindEnd(char *string) {
+    char endChar = ' ';
+    PRBool lastEscape = PR_FALSE;
+
+    if (secmod_argIsQuote(*string)) {
+	endChar = secmod_argGetPair(*string);
+	string++;
+    }
+
+    for (;*string; string++) {
+	if (lastEscape) {
+	    lastEscape = PR_FALSE;
+	    continue;
+	}
+	if (secmod_argIsEscape(*string) && !lastEscape) {
+	    lastEscape = PR_TRUE;
+	    continue;
+	} 
+	if ((endChar == ' ') && secmod_argIsBlank(*string)) break;
+	if (*string == endChar) {
+	    break;
+	}
+    }
+
+    return string;
+}
+
+static char *
+secmod_argFetchValue(char *string, int *pcount)
+{
+    char *end = secmod_argFindEnd(string);
+    char *retString, *copyString;
+    PRBool lastEscape = PR_FALSE;
+    int len;
+
+    len = end - string;
+    if (len == 0) {
+	*pcount = 0;
+	return NULL;
+    }
+
+    copyString = retString = (char *)PORT_Alloc(len+1);
+
+    if (*end) len++;
+    *pcount = len;
+    if (retString == NULL) return NULL;
+
+
+    if (secmod_argIsQuote(*string)) string++;
+    for (; string < end; string++) {
+	if (secmod_argIsEscape(*string) && !lastEscape) {
+	    lastEscape = PR_TRUE;
+	    continue;
+	}
+	lastEscape = PR_FALSE;
+	*copyString++ = *string;
+    }
+    *copyString = 0;
+    return retString;
+}
+
+static char *
+secmod_argSkipParameter(char *string) 
+{
+     char *end;
+     /* look for the end of the <name>= */
+     for (;*string; string++) {
+	if (*string == '=') { string++; break; }
+	if (secmod_argIsBlank(*string)) return(string); 
+     }
+
+     end = secmod_argFindEnd(string);
+     if (*end) end++;
+     return end;
+}
+
+
+static SECStatus
+secmod_argParseModuleSpec(char *modulespec, char **lib, char **mod, 
+					char **parameters, char **nss)
+{
+    int next;
+    modulespec = secmod_argStrip(modulespec);
+
+    *lib = *mod = *parameters = *nss = 0;
+
+    while (*modulespec) {
+	SECMOD_HANDLE_STRING_ARG(modulespec,*lib,SECMOD_ARG_LIBRARY_PARAMETER,;)
+	SECMOD_HANDLE_STRING_ARG(modulespec,*mod,SECMOD_ARG_NAME_PARAMETER,;)
+	SECMOD_HANDLE_STRING_ARG(modulespec,*parameters,
+						SECMOD_ARG_MODULE_PARAMETER,;)
+	SECMOD_HANDLE_STRING_ARG(modulespec,*nss,SECMOD_ARG_NSS_PARAMETER,;)
+	SECMOD_HANDLE_FINAL_ARG(modulespec)
+   }
+   return SECSuccess;
+}
+
+
+static char *
+secmod_argGetParamValue(char *paramName,char *parameters)
+{
+    char searchValue[256];
+    int paramLen = strlen(paramName);
+    char *returnValue = NULL;
+    int next;
+
+    if ((parameters == NULL) || (*parameters == 0)) return NULL;
+
+    PORT_Assert(paramLen+2 < sizeof(searchValue));
+
+    PORT_Strcpy(searchValue,paramName);
+    PORT_Strcat(searchValue,"=");
+    while (*parameters) {
+	if (PORT_Strncasecmp(parameters,searchValue,paramLen+1) == 0) {
+	    parameters += paramLen+1;
+	    returnValue = secmod_argFetchValue(parameters,&next);
+	    break;
+	} else {
+	    parameters = secmod_argSkipParameter(parameters);
+	}
+	parameters = secmod_argStrip(parameters);
+   }
+   return returnValue;
+}
+    
+
+static char *
+secmod_argNextFlag(char *flags)
+{
+    for (; *flags ; flags++) {
+	if (*flags == ',') {
+	    flags++;
+	    break;
+	}
+    }
+    return flags;
+}
+
+static PRBool
+secmod_argHasFlag(char *label, char *flag, char *parameters)
+{
+    char *flags,*index;
+    int len = strlen(flag);
+    PRBool found = PR_FALSE;
+
+    flags = secmod_argGetParamValue(label,parameters);
+    if (flags == NULL) return PR_FALSE;
+
+    for (index=flags; *index; index=secmod_argNextFlag(index)) {
+	if (PORT_Strncasecmp(index,flag,len) == 0) {
+	    found=PR_TRUE;
+	    break;
+	}
+    }
+    PORT_Free(flags);
+    return found;
+}
+
+static void
+secmod_argSetNewCipherFlags(unsigned long *newCiphers,char *cipherList)
+{
+    newCiphers[0] = newCiphers[1] = 0;
+    if ((cipherList == NULL) || (*cipherList == 0)) return;
+
+    for (;*cipherList; cipherList=secmod_argNextFlag(cipherList)) {
+	if (PORT_Strncasecmp(cipherList,SECMOD_ARG_FORTEZZA_FLAG,
+				sizeof(SECMOD_ARG_FORTEZZA_FLAG)-1) == 0) {
+	    newCiphers[0] |= SECMOD_FORTEZZA_FLAG;
+	} 
+
+	/* add additional flags here as necessary */
+	/* direct bit mapping escape */
+	if (*cipherList == 0) {
+	   if (cipherList[1] == 'l') {
+		newCiphers[1] |= atoi(&cipherList[2]);
+	   } else {
+		newCiphers[0] |= atoi(&cipherList[2]);
+	   }
+	}
+    }
+}
+
+
+/*
+ * decode a number. handle octal (leading '0'), hex (leading '0x') or decimal
+ */
+static long
+secmod_argDecodeNumber(char *num)
+{
+    int	radix = 10;
+    unsigned long value = 0;
+    long retValue = 0;
+    int sign = 1;
+    int digit;
+
+    if (num == NULL) return retValue;
+
+    num = secmod_argStrip(num);
+
+    if (*num == '-') {
+	sign = -1;
+	num++;
+    }
+
+    if (*num == '0') {
+	radix = 8;
+	num++;
+	if ((*num == 'x') || (*num == 'X')) {
+	    radix = 16;
+	    num++;
+	}
+    }
+
+   
+    for ( ;*num; num++ ) {
+	if (isdigit(*num)) {
+	    digit = *num - '0';
+	} else if ((*num >= 'a') && (*num <= 'f'))  {
+	    digit = *num - 'a' + 10;
+	} else if ((*num >= 'A') && (*num <= 'F'))  {
+	    digit = *num - 'A' + 10;
+	} else {
+	    break;
+	}
+	if (digit >= radix) break;
+	value = value*radix + digit;
+    }
+
+    retValue = ((int) value) * sign;
+    return retValue;
+}
+
+static long
+secmod_argReadLong(char *label,char *params, long defValue, PRBool *isdefault)
+{
+    char *value;
+    long retValue;
+    if (isdefault) *isdefault = PR_FALSE; 
+
+    value = secmod_argGetParamValue(label,params);
+    if (value == NULL) {
+	if (isdefault) *isdefault = PR_TRUE;
+	return defValue;
+    }
+    retValue = secmod_argDecodeNumber(value);
+    if (value) PORT_Free(value);
+
+    return retValue;
+}
+
+
+static unsigned long
+secmod_argSlotFlags(char *label,char *params)
+{
+    char *flags,*index;
+    unsigned long retValue = 0;
+    int i;
+    PRBool all = PR_FALSE;
+
+    flags = secmod_argGetParamValue(label,params);
+    if (flags == NULL) return 0;
+
+    if (PORT_Strcasecmp(flags,"all") == 0) all = PR_TRUE;
+
+    for (index=flags; *index; index=secmod_argNextFlag(index)) {
+	for (i=0; i < secmod_argSlotFlagTableSize; i++) {
+	    if (all || (PORT_Strncasecmp(index, secmod_argSlotFlagTable[i].name,
+				secmod_argSlotFlagTable[i].len) == 0)) {
+		retValue |= secmod_argSlotFlagTable[i].value;
+	    }
+	}
+    }
+    PORT_Free(flags);
+    return retValue;
+}
+
+
+static void
+secmod_argDecodeSingleSlotInfo(char *name, char *params, 
+                               PK11PreSlotInfo *slotInfo)
+{
+    char *askpw;
+
+    slotInfo->slotID=secmod_argDecodeNumber(name);
+    slotInfo->defaultFlags=secmod_argSlotFlags("slotFlags",params);
+    slotInfo->timeout=secmod_argReadLong("timeout",params, 0, NULL);
+
+    askpw = secmod_argGetParamValue("askpw",params);
+    slotInfo->askpw = 0;
+
+    if (askpw) {
+	if (PORT_Strcasecmp(askpw,"every") == 0) {
+    	    slotInfo->askpw = -1;
+	} else if (PORT_Strcasecmp(askpw,"timeout") == 0) {
+    	    slotInfo->askpw = 1;
+	} 
+	PORT_Free(askpw);
+	slotInfo->defaultFlags |= PK11_OWN_PW_DEFAULTS;
+    }
+    slotInfo->hasRootCerts = secmod_argHasFlag("rootFlags", "hasRootCerts", 
+                                               params);
+    slotInfo->hasRootTrust = secmod_argHasFlag("rootFlags", "hasRootTrust", 
+                                               params);
+}
+
+static char *
+secmod_argGetName(char *inString, int *next) 
+{
+    char *name=NULL;
+    char *string;
+    int len;
+
+    /* look for the end of the <name>= */
+    for (string = inString;*string; string++) {
+	if (*string == '=') { break; }
+	if (secmod_argIsBlank(*string)) break;
+    }
+
+    len = string - inString;
+
+    *next = len; 
+    if (*string == '=') (*next) += 1;
+    if (len > 0) {
+	name = PORT_Alloc(len+1);
+	PORT_Strncpy(name,inString,len);
+	name[len] = 0;
+    }
+    return name;
+}
+
+static PK11PreSlotInfo *
+secmod_argParseSlotInfo(PRArenaPool *arena, char *slotParams, int *retCount)
+{
+    char *slotIndex;
+    PK11PreSlotInfo *slotInfo = NULL;
+    int i=0,count = 0,next;
+
+    *retCount = 0;
+    if ((slotParams == NULL) || (*slotParams == 0))  return NULL;
+
+    /* first count the number of slots */
+    for (slotIndex = secmod_argStrip(slotParams); *slotIndex; 
+	 slotIndex = secmod_argStrip(secmod_argSkipParameter(slotIndex))) {
+	count++;
+    }
+
+    /* get the data structures */
+    if (arena) {
+	slotInfo = (PK11PreSlotInfo *) 
+			PORT_ArenaAlloc(arena,count*sizeof(PK11PreSlotInfo));
+	PORT_Memset(slotInfo,0,count*sizeof(PK11PreSlotInfo));
+    } else {
+	slotInfo = (PK11PreSlotInfo *) 
+			PORT_ZAlloc(count*sizeof(PK11PreSlotInfo));
+    }
+    if (slotInfo == NULL) return NULL;
+
+    for (slotIndex = secmod_argStrip(slotParams), i = 0; 
+					*slotIndex && i < count ; ) {
+	char *name;
+	name = secmod_argGetName(slotIndex,&next);
+	slotIndex += next;
+
+	if (!secmod_argIsBlank(*slotIndex)) {
+	    char *args = secmod_argFetchValue(slotIndex,&next);
+	    slotIndex += next;
+	    if (args) {
+		secmod_argDecodeSingleSlotInfo(name,args,&slotInfo[i]);
+		i++;
+		PORT_Free(args);
+	    }
+	}
+	if (name) PORT_Free(name);
+	slotIndex = secmod_argStrip(slotIndex);
+    }
+    *retCount = i;
+    return slotInfo;
+}
+
+static char *secmod_nullString = "";
+
+static char *
+secmod_formatValue(PRArenaPool *arena, char *value, char quote)
+{
+    char *vp,*vp2,*retval;
+    int size = 0, escapes = 0;
+
+    for (vp=value; *vp ;vp++) {
+	if ((*vp == quote) || (*vp == SECMOD_ARG_ESCAPE)) escapes++;
+	size++;
+    }
+    if (arena) {
+	retval = PORT_ArenaZAlloc(arena,size+escapes+1);
+    } else {
+	retval = PORT_ZAlloc(size+escapes+1);
+    }
+    if (retval == NULL) return NULL;
+    vp2 = retval;
+    for (vp=value; *vp; vp++) {
+	if ((*vp == quote) || (*vp == SECMOD_ARG_ESCAPE)) 
+				*vp2++ = SECMOD_ARG_ESCAPE;
+	*vp2++ = *vp;
+    }
+    return retval;
+}
+    
+static char *secmod_formatPair(char *name,char *value, char quote)
+{
+    char openQuote = quote;
+    char closeQuote = secmod_argGetPair(quote);
+    char *newValue = NULL;
+    char *returnValue;
+    PRBool need_quote = PR_FALSE;
+
+    if (!value || (*value == 0)) return secmod_nullString;
+
+    if (secmod_argHasBlanks(value) || secmod_argIsQuote(value[0]))
+							 need_quote=PR_TRUE;
+
+    if ((need_quote && secmod_argHasChar(value,closeQuote))
+				 || secmod_argHasChar(value,SECMOD_ARG_ESCAPE)) {
+	value = newValue = secmod_formatValue(NULL, value,quote);
+	if (newValue == NULL) return secmod_nullString;
+    }
+    if (need_quote) {
+    	returnValue = PR_smprintf("%s=%c%s%c",name,openQuote,value,closeQuote);
+    } else {
+    	returnValue = PR_smprintf("%s=%s",name,value);
+    }
+    if (returnValue == NULL) returnValue = secmod_nullString;
+
+    if (newValue) PORT_Free(newValue);
+
+    return returnValue;
+}
+
+static char *secmod_formatIntPair(char *name, unsigned long value, 
+                                  unsigned long def)
+{
+    char *returnValue;
+
+    if (value == def) return secmod_nullString;
+
+    returnValue = PR_smprintf("%s=%d",name,value);
+
+    return returnValue;
+}
+
+static void
+secmod_freePair(char *pair)
+{
+    if (pair && pair != secmod_nullString) {
+	PR_smprintf_free(pair);
+    }
+}
+
+#define MAX_FLAG_SIZE  sizeof("internal")+sizeof("FIPS")+sizeof("moduleDB")+\
+				sizeof("moduleDBOnly")+sizeof("critical")
+static char *
+secmod_mkNSSFlags(PRBool internal, PRBool isFIPS,
+		PRBool isModuleDB, PRBool isModuleDBOnly, PRBool isCritical)
+{
+    char *flags = (char *)PORT_ZAlloc(MAX_FLAG_SIZE);
+    PRBool first = PR_TRUE;
+
+    PORT_Memset(flags,0,MAX_FLAG_SIZE);
+    if (internal) {
+	PORT_Strcat(flags,"internal");
+	first = PR_FALSE;
+    }
+    if (isFIPS) {
+	if (!first) PORT_Strcat(flags,",");
+	PORT_Strcat(flags,"FIPS");
+	first = PR_FALSE;
+    }
+    if (isModuleDB) {
+	if (!first) PORT_Strcat(flags,",");
+	PORT_Strcat(flags,"moduleDB");
+	first = PR_FALSE;
+    }
+    if (isModuleDBOnly) {
+	if (!first) PORT_Strcat(flags,",");
+	PORT_Strcat(flags,"moduleDBOnly");
+	first = PR_FALSE;
+    }
+    if (isCritical) {
+	if (!first) PORT_Strcat(flags,",");
+	PORT_Strcat(flags,"critical");
+	first = PR_FALSE;
+    }
+    return flags;
+}
+
+static char *
+secmod_mkCipherFlags(unsigned long ssl0, unsigned long ssl1)
+{
+    char *cipher = NULL;
+    int i;
+
+    for (i=0; i < sizeof(ssl0)*8; i++) {
+	if (ssl0 & (1<<i)) {
+	    char *string;
+	    if ((1<<i) == SECMOD_FORTEZZA_FLAG) {
+		string = PR_smprintf("%s","FORTEZZA");
+	    } else {
+		string = PR_smprintf("0h0x%08x",1<<i);
+	    }
+	    if (cipher) {
+		char *tmp;
+		tmp = PR_smprintf("%s,%s",cipher,string);
+		PR_smprintf_free(cipher);
+		PR_smprintf_free(string);
+		cipher = tmp;
+	    } else {
+		cipher = string;
+	    }
+	}
+    }
+    for (i=0; i < sizeof(ssl0)*8; i++) {
+	if (ssl1 & (1<<i)) {
+	    if (cipher) {
+		char *tmp;
+		tmp = PR_smprintf("%s,0l0x%08x",cipher,1<<i);
+		PR_smprintf_free(cipher);
+		cipher = tmp;
+	    } else {
+		cipher = PR_smprintf("0l0x%08x",1<<i);
+	    }
+	}
+    }
+
+    return cipher;
+}
+
+static char *
+secmod_mkSlotFlags(unsigned long defaultFlags)
+{
+    char *flags=NULL;
+    int i,j;
+
+    for (i=0; i < sizeof(defaultFlags)*8; i++) {
+	if (defaultFlags & (1<<i)) {
+	    char *string = NULL;
+
+	    for (j=0; j < secmod_argSlotFlagTableSize; j++) {
+		if (secmod_argSlotFlagTable[j].value == ( 1UL << i )) {
+		    string = secmod_argSlotFlagTable[j].name;
+		    break;
+		}
+	    }
+	    if (string) {
+		if (flags) {
+		    char *tmp;
+		    tmp = PR_smprintf("%s,%s",flags,string);
+		    PR_smprintf_free(flags);
+		    flags = tmp;
+		} else {
+		    flags = PR_smprintf("%s",string);
+		}
+	    }
+	}
+    }
+
+    return flags;
+}
+
+#define SECMOD_MAX_ROOT_FLAG_SIZE  sizeof("hasRootCerts")+sizeof("hasRootTrust")
+
+static char *
+secmod_mkRootFlags(PRBool hasRootCerts, PRBool hasRootTrust)
+{
+    char *flags= (char *)PORT_ZAlloc(SECMOD_MAX_ROOT_FLAG_SIZE);
+    PRBool first = PR_TRUE;
+
+    PORT_Memset(flags,0,SECMOD_MAX_ROOT_FLAG_SIZE);
+    if (hasRootCerts) {
+	PORT_Strcat(flags,"hasRootCerts");
+	first = PR_FALSE;
+    }
+    if (hasRootTrust) {
+	if (!first) PORT_Strcat(flags,",");
+	PORT_Strcat(flags,"hasRootTrust");
+	first = PR_FALSE;
+    }
+    return flags;
+}
+
+static char *
+secmod_mkSlotString(unsigned long slotID, unsigned long defaultFlags,
+		  unsigned long timeout, unsigned char askpw_in,
+		  PRBool hasRootCerts, PRBool hasRootTrust) {
+    char *askpw,*flags,*rootFlags,*slotString;
+    char *flagPair,*rootFlagsPair;
+	
+    switch (askpw_in) {
+    case 0xff:
+	askpw = "every";
+	break;
+    case 1:
+	askpw = "timeout";
+	break;
+    default:
+	askpw = "any";
+	break;
+    }
+    flags = secmod_mkSlotFlags(defaultFlags);
+    rootFlags = secmod_mkRootFlags(hasRootCerts,hasRootTrust);
+    flagPair=secmod_formatPair("slotFlags",flags,'\'');
+    rootFlagsPair=secmod_formatPair("rootFlags",rootFlags,'\'');
+    if (flags) PR_smprintf_free(flags);
+    if (rootFlags) PORT_Free(rootFlags);
+    if (defaultFlags & PK11_OWN_PW_DEFAULTS) {
+    	slotString = PR_smprintf("0x%08lx=[%s askpw=%s timeout=%d %s]",
+				(PRUint32)slotID,flagPair,askpw,timeout,
+				rootFlagsPair);
+    } else {
+    	slotString = PR_smprintf("0x%08lx=[%s %s]",
+				(PRUint32)slotID,flagPair,rootFlagsPair);
+    }
+    secmod_freePair(flagPair);
+    secmod_freePair(rootFlagsPair);
+    return slotString;
+}
+
+static char *
+secmod_mkNSS(char **slotStrings, int slotCount, PRBool internal, PRBool isFIPS,
+	  PRBool isModuleDB,  PRBool isModuleDBOnly, PRBool isCritical, 
+	  unsigned long trustOrder, unsigned long cipherOrder,
+				unsigned long ssl0, unsigned long ssl1) {
+    int slotLen, i;
+    char *slotParams, *ciphers, *nss, *nssFlags, *tmp;
+    char *trustOrderPair,*cipherOrderPair,*slotPair,*cipherPair,*flagPair;
+
+
+    /* now let's build up the string
+     * first the slot infos
+     */
+    slotLen=0;
+    for (i=0; i < (int)slotCount; i++) {
+	slotLen += PORT_Strlen(slotStrings[i])+1;
+    }
+    slotLen += 1; /* space for the final NULL */
+
+    slotParams = (char *)PORT_ZAlloc(slotLen);
+    PORT_Memset(slotParams,0,slotLen);
+    for (i=0; i < (int)slotCount; i++) {
+	PORT_Strcat(slotParams,slotStrings[i]);
+	PORT_Strcat(slotParams," ");
+	PR_smprintf_free(slotStrings[i]);
+	slotStrings[i]=NULL;
+    }
+    
+    /*
+     * now the NSS structure
+     */
+    nssFlags = secmod_mkNSSFlags(internal,isFIPS,isModuleDB,isModuleDBOnly,
+							isCritical); 
+	/* for now only the internal module is critical */
+    ciphers = secmod_mkCipherFlags(ssl0, ssl1);
+
+    trustOrderPair=secmod_formatIntPair("trustOrder",trustOrder,
+					SECMOD_DEFAULT_TRUST_ORDER);
+    cipherOrderPair=secmod_formatIntPair("cipherOrder",cipherOrder,
+					SECMOD_DEFAULT_CIPHER_ORDER);
+    slotPair=secmod_formatPair("slotParams",slotParams,'{'); /* } */
+    if (slotParams) PORT_Free(slotParams);
+    cipherPair=secmod_formatPair("ciphers",ciphers,'\'');
+    if (ciphers) PR_smprintf_free(ciphers);
+    flagPair=secmod_formatPair("Flags",nssFlags,'\'');
+    if (nssFlags) PORT_Free(nssFlags);
+    nss = PR_smprintf("%s %s %s %s %s",trustOrderPair,
+			cipherOrderPair,slotPair,cipherPair,flagPair);
+    secmod_freePair(trustOrderPair);
+    secmod_freePair(cipherOrderPair);
+    secmod_freePair(slotPair);
+    secmod_freePair(cipherPair);
+    secmod_freePair(flagPair);
+    tmp = secmod_argStrip(nss);
+    if (*tmp == '\0') {
+	PR_smprintf_free(nss);
+	nss = NULL;
+    }
+    return nss;
+}
+
+static char *
+secmod_mkNewModuleSpec(char *dllName, char *commonName, char *parameters, 
+								char *NSS) {
+    char *moduleSpec;
+    char *lib,*name,*param,*nss;
+
+    /*
+     * now the final spec
+     */
+    lib = secmod_formatPair("library",dllName,'\"');
+    name = secmod_formatPair("name",commonName,'\"');
+    param = secmod_formatPair("parameters",parameters,'\"');
+    nss = secmod_formatPair("NSS",NSS,'\"');
+    moduleSpec = PR_smprintf("%s %s %s %s", lib,name,param,nss);
+    secmod_freePair(lib);
+    secmod_freePair(name);
+    secmod_freePair(param);
+    secmod_freePair(nss);
+    return (moduleSpec);
+}
+
diff --git a/mozilla/security/nss/lib/softoken/pkcs11.c b/mozilla/security/nss/lib/softoken/pkcs11.c
new file mode 100644
index 0000000..e536f8c
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/pkcs11.c
@@ -0,0 +1,4420 @@
+/* ***** 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):
+ *   Dr Stephen Henson <stephen.henson@gemplus.com>
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * This file implements PKCS 11 on top of our existing security modules
+ *
+ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
+ *   This implementation has two slots:
+ *	slot 1 is our generic crypto support. It does not require login.
+ *   It supports Public Key ops, and all they bulk ciphers and hashes. 
+ *   It can also support Private Key ops for imported Private keys. It does 
+ *   not have any token storage.
+ *	slot 2 is our private key support. It requires a login before use. It
+ *   can store Private Keys and Certs as token objects. Currently only private
+ *   keys and their associated Certificates are saved on the token.
+ *
+ *   In this implementation, session objects are only visible to the session
+ *   that created or generated them.
+ */
+#include "seccomon.h"
+#include "secitem.h"
+#include "pkcs11.h"
+#include "pkcs11i.h"
+#include "softoken.h"
+#include "lowkeyi.h"
+#include "blapi.h"
+#include "secder.h"
+#include "secport.h"
+#include "secrng.h"
+#include "prtypes.h"
+#include "nspr.h"
+#include "softkver.h"
+#include "secoid.h"
+#include "sftkdb.h"
+#include "sftkpars.h"
+#include "ec.h"
+#include "secasn1.h"
+
+PRBool parentForkedAfterC_Initialize;
+
+#ifndef NO_FORK_CHECK
+
+PRBool sftkForkCheckDisabled;
+
+#if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
+PRBool forked = PR_FALSE;
+#endif
+
+#if defined(CHECK_FORK_GETPID) || defined(CHECK_FORK_MIXED)
+#include <unistd.h>
+pid_t myPid;
+#endif
+
+#ifdef CHECK_FORK_MIXED
+#include <sys/systeminfo.h>
+PRBool usePthread_atfork;
+#endif
+
+#endif
+
+/*
+ * ******************** Static data *******************************
+ */
+
+/* The next three strings must be exactly 32 characters long */
+static char *manufacturerID      = "Mozilla Foundation              ";
+static char manufacturerID_space[33];
+static char *libraryDescription  = "NSS Internal Crypto Services    ";
+static char libraryDescription_space[33];
+
+/*
+ * In FIPS mode, we disallow login attempts for 1 second after a login
+ * failure so that there are at most 60 login attempts per minute.
+ */
+static PRIntervalTime loginWaitTime;
+static PRUint32	      minSessionObjectHandle = 1U;
+
+#define __PASTE(x,y)    x##y
+
+/*
+ * we renamed all our internal functions, get the correct
+ * definitions for them...
+ */ 
+#undef CK_PKCS11_FUNCTION_INFO
+#undef CK_NEED_ARG_LIST
+
+#define CK_EXTERN extern
+#define CK_PKCS11_FUNCTION_INFO(func) \
+		CK_RV __PASTE(NS,func)
+#define CK_NEED_ARG_LIST	1
+ 
+#include "pkcs11f.h"
+ 
+ 
+ 
+/* build the crypto module table */
+static const CK_FUNCTION_LIST sftk_funcList = {
+    { 1, 10 },
+ 
+#undef CK_PKCS11_FUNCTION_INFO
+#undef CK_NEED_ARG_LIST
+ 
+#define CK_PKCS11_FUNCTION_INFO(func) \
+				__PASTE(NS,func),
+#include "pkcs11f.h"
+ 
+};
+ 
+#undef CK_PKCS11_FUNCTION_INFO
+#undef CK_NEED_ARG_LIST
+ 
+ 
+#undef __PASTE
+
+/* List of DES Weak Keys */ 
+typedef unsigned char desKey[8];
+static const desKey  sftk_desWeakTable[] = {
+#ifdef noParity
+    /* weak */
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e },
+    { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 },
+    { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
+    /* semi-weak */
+    { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe },
+    { 0xfe, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0xfe },
+
+    { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 },
+    { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e },
+
+    { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x0f, 0x00, 0x0f },
+    { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 },
+
+    { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
+    { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e },
+
+    { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e },
+    { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 },
+
+    { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe },
+    { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 },
+#else
+    /* weak */
+    { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+    { 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e },
+    { 0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1 },
+    { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
+
+    /* semi-weak */
+    { 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe },
+    { 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01 },
+
+    { 0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1 },
+    { 0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e },
+
+    { 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1 },
+    { 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01 },
+
+    { 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
+    { 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e },
+
+    { 0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e },
+    { 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01 },
+
+    { 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe }, 
+    { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1 }
+#endif
+};
+
+    
+static const int sftk_desWeakTableSize = sizeof(sftk_desWeakTable)/
+						sizeof(sftk_desWeakTable[0]);
+
+/* DES KEY Parity conversion table. Takes each byte/2 as an index, returns
+ * that byte with the proper parity bit set */
+static const unsigned char parityTable[256] = {
+/* Even...0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e */
+/* E */   0x01,0x02,0x04,0x07,0x08,0x0b,0x0d,0x0e,
+/* Odd....0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e */
+/* O */   0x10,0x13,0x15,0x16,0x19,0x1a,0x1c,0x1f,
+/* Odd....0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e */
+/* O */   0x20,0x23,0x25,0x26,0x29,0x2a,0x2c,0x2f,
+/* Even...0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e */
+/* E */   0x31,0x32,0x34,0x37,0x38,0x3b,0x3d,0x3e,
+/* Odd....0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e */
+/* O */   0x40,0x43,0x45,0x46,0x49,0x4a,0x4c,0x4f,
+/* Even...0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e */
+/* E */   0x51,0x52,0x54,0x57,0x58,0x5b,0x5d,0x5e,
+/* Even...0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e */
+/* E */   0x61,0x62,0x64,0x67,0x68,0x6b,0x6d,0x6e,
+/* Odd....0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e */
+/* O */   0x70,0x73,0x75,0x76,0x79,0x7a,0x7c,0x7f,
+/* Odd....0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e */
+/* O */   0x80,0x83,0x85,0x86,0x89,0x8a,0x8c,0x8f,
+/* Even...0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e */
+/* E */   0x91,0x92,0x94,0x97,0x98,0x9b,0x9d,0x9e,
+/* Even...0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae */
+/* E */   0xa1,0xa2,0xa4,0xa7,0xa8,0xab,0xad,0xae,
+/* Odd....0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe */
+/* O */   0xb0,0xb3,0xb5,0xb6,0xb9,0xba,0xbc,0xbf,
+/* Even...0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce */
+/* E */   0xc1,0xc2,0xc4,0xc7,0xc8,0xcb,0xcd,0xce,
+/* Odd....0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde */
+/* O */   0xd0,0xd3,0xd5,0xd6,0xd9,0xda,0xdc,0xdf,
+/* Odd....0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee */
+/* O */   0xe0,0xe3,0xe5,0xe6,0xe9,0xea,0xec,0xef,
+/* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */
+/* E */   0xf1,0xf2,0xf4,0xf7,0xf8,0xfb,0xfd,0xfe,
+};
+
+/* Mechanisms */
+struct mechanismList {
+    CK_MECHANISM_TYPE	type;
+    CK_MECHANISM_INFO	info;
+    PRBool		privkey;
+};
+
+/*
+ * the following table includes a complete list of mechanism defined by
+ * PKCS #11 version 2.01. Those Mechanisms not supported by this PKCS #11
+ * module are ifdef'ed out.
+ */
+#define CKF_EN_DE		CKF_ENCRYPT      | CKF_DECRYPT
+#define CKF_WR_UN		CKF_WRAP         | CKF_UNWRAP
+#define CKF_SN_VR		CKF_SIGN         | CKF_VERIFY
+#define CKF_SN_RE		CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER
+
+#define CKF_EN_DE_WR_UN 	CKF_EN_DE       | CKF_WR_UN
+#define CKF_SN_VR_RE		CKF_SN_VR       | CKF_SN_RE
+#define CKF_DUZ_IT_ALL		CKF_EN_DE_WR_UN | CKF_SN_VR_RE
+
+#define CKF_EC_PNU		CKF_EC_FP | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS
+
+#define CKF_EC_BPNU		CKF_EC_F_2M | CKF_EC_PNU
+
+#define CK_MAX 0xffffffff
+
+static const struct mechanismList mechanisms[] = {
+
+     /*
+      * PKCS #11 Mechanism List.
+      *
+      * The first argument is the PKCS #11 Mechanism we support.
+      * The second argument is Mechanism info structure. It includes:
+      *    The minimum key size,
+      *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
+      *       in bytes for RC5, AES, Camellia, and CAST*
+      *       ignored for DES*, IDEA and FORTEZZA based
+      *    The maximum key size,
+      *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
+      *       in bytes for RC5, AES, Camellia, and CAST*
+      *       ignored for DES*, IDEA and FORTEZZA based
+      *     Flags
+      *	      What operations are supported by this mechanism.
+      *  The third argument is a bool which tells if this mechanism is 
+      *    supported in the database token.
+      *
+      */
+
+     /* ------------------------- RSA Operations ---------------------------*/
+     {CKM_RSA_PKCS_KEY_PAIR_GEN,{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_GENERATE_KEY_PAIR},PR_TRUE},
+     {CKM_RSA_PKCS,             {RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_DUZ_IT_ALL},       PR_TRUE},
+#ifdef SFTK_RSA9796_SUPPORTED
+     {CKM_RSA_9796,		{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_DUZ_IT_ALL},       PR_TRUE},
+#endif
+     {CKM_RSA_X_509,		{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_DUZ_IT_ALL},       PR_TRUE},
+     /* -------------- RSA Multipart Signing Operations -------------------- */
+     {CKM_MD2_RSA_PKCS,		{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_SN_VR}, 	PR_TRUE},
+     {CKM_MD5_RSA_PKCS,		{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_SN_VR}, 	PR_TRUE},
+     {CKM_SHA1_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_SN_VR}, 	PR_TRUE},
+     {CKM_SHA256_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_SN_VR}, 	PR_TRUE},
+     {CKM_SHA384_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_SN_VR}, 	PR_TRUE},
+     {CKM_SHA512_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
+				 CKF_SN_VR}, 	PR_TRUE},
+     /* ------------------------- DSA Operations --------------------------- */
+     {CKM_DSA_KEY_PAIR_GEN,	{DSA_MIN_P_BITS, DSA_MAX_P_BITS,
+				 CKF_GENERATE_KEY_PAIR}, PR_TRUE},
+     {CKM_DSA,			{DSA_MIN_P_BITS, DSA_MAX_P_BITS, 
+				 CKF_SN_VR},              PR_TRUE},
+     {CKM_DSA_SHA1,		{DSA_MIN_P_BITS, DSA_MAX_P_BITS,
+				 CKF_SN_VR},              PR_TRUE},
+     /* -------------------- Diffie Hellman Operations --------------------- */
+     /* no diffie hellman yet */
+     {CKM_DH_PKCS_KEY_PAIR_GEN,	{DH_MIN_P_BITS, DH_MAX_P_BITS, 
+				 CKF_GENERATE_KEY_PAIR}, PR_TRUE}, 
+     {CKM_DH_PKCS_DERIVE,	{DH_MIN_P_BITS, DH_MAX_P_BITS,
+				 CKF_DERIVE}, 	PR_TRUE}, 
+#ifdef NSS_ENABLE_ECC
+     /* -------------------- Elliptic Curve Operations --------------------- */
+     {CKM_EC_KEY_PAIR_GEN,      {112, 571, CKF_GENERATE_KEY_PAIR|CKF_EC_BPNU}, PR_TRUE}, 
+     {CKM_ECDH1_DERIVE,         {112, 571, CKF_DERIVE|CKF_EC_BPNU}, PR_TRUE}, 
+     {CKM_ECDSA,                {112, 571, CKF_SN_VR|CKF_EC_BPNU}, PR_TRUE}, 
+     {CKM_ECDSA_SHA1,           {112, 571, CKF_SN_VR|CKF_EC_BPNU}, PR_TRUE}, 
+#endif /* NSS_ENABLE_ECC */
+     /* ------------------------- RC2 Operations --------------------------- */
+     {CKM_RC2_KEY_GEN,		{1, 128, CKF_GENERATE},		PR_TRUE},
+     {CKM_RC2_ECB,		{1, 128, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_RC2_CBC,		{1, 128, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_RC2_MAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_RC2_MAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_RC2_CBC_PAD,		{1, 128, CKF_EN_DE_WR_UN},	PR_TRUE},
+     /* ------------------------- RC4 Operations --------------------------- */
+     {CKM_RC4_KEY_GEN,		{1, 256, CKF_GENERATE},		PR_FALSE},
+     {CKM_RC4,			{1, 256, CKF_EN_DE_WR_UN},	PR_FALSE},
+     /* ------------------------- DES Operations --------------------------- */
+     {CKM_DES_KEY_GEN,		{ 8,  8, CKF_GENERATE},		PR_TRUE},
+     {CKM_DES_ECB,		{ 8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_DES_CBC,		{ 8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_DES_MAC,		{ 8,  8, CKF_SN_VR},		PR_TRUE},
+     {CKM_DES_MAC_GENERAL,	{ 8,  8, CKF_SN_VR},		PR_TRUE},
+     {CKM_DES_CBC_PAD,		{ 8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_DES2_KEY_GEN,		{24, 24, CKF_GENERATE},		PR_TRUE},
+     {CKM_DES3_KEY_GEN,		{24, 24, CKF_GENERATE},		PR_TRUE },
+     {CKM_DES3_ECB,		{24, 24, CKF_EN_DE_WR_UN},	PR_TRUE },
+     {CKM_DES3_CBC,		{24, 24, CKF_EN_DE_WR_UN},	PR_TRUE },
+     {CKM_DES3_MAC,		{24, 24, CKF_SN_VR},		PR_TRUE },
+     {CKM_DES3_MAC_GENERAL,	{24, 24, CKF_SN_VR},		PR_TRUE },
+     {CKM_DES3_CBC_PAD,		{24, 24, CKF_EN_DE_WR_UN},	PR_TRUE },
+     /* ------------------------- CDMF Operations --------------------------- */
+     {CKM_CDMF_KEY_GEN,		{8,  8, CKF_GENERATE},		PR_TRUE},
+     {CKM_CDMF_ECB,		{8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_CDMF_CBC,		{8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_CDMF_MAC,		{8,  8, CKF_SN_VR},		PR_TRUE},
+     {CKM_CDMF_MAC_GENERAL,	{8,  8, CKF_SN_VR},		PR_TRUE},
+     {CKM_CDMF_CBC_PAD,		{8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
+     /* ------------------------- AES Operations --------------------------- */
+     {CKM_AES_KEY_GEN,		{16, 32, CKF_GENERATE},		PR_TRUE},
+     {CKM_AES_ECB,		{16, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_AES_CBC,		{16, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_AES_MAC,		{16, 32, CKF_SN_VR},		PR_TRUE},
+     {CKM_AES_MAC_GENERAL,	{16, 32, CKF_SN_VR},		PR_TRUE},
+     {CKM_AES_CBC_PAD,		{16, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
+     /* ------------------------- Camellia Operations --------------------- */
+     {CKM_CAMELLIA_KEY_GEN,	{16, 32, CKF_GENERATE},         PR_TRUE},
+     {CKM_CAMELLIA_ECB,  	{16, 32, CKF_EN_DE_WR_UN},      PR_TRUE},
+     {CKM_CAMELLIA_CBC, 	{16, 32, CKF_EN_DE_WR_UN},      PR_TRUE},
+     {CKM_CAMELLIA_MAC, 	{16, 32, CKF_SN_VR},            PR_TRUE},
+     {CKM_CAMELLIA_MAC_GENERAL,	{16, 32, CKF_SN_VR},            PR_TRUE},
+     {CKM_CAMELLIA_CBC_PAD,	{16, 32, CKF_EN_DE_WR_UN},      PR_TRUE},
+     /* ------------------------- SEED Operations --------------------------- */
+     {CKM_SEED_KEY_GEN,		{16, 16, CKF_GENERATE},		PR_TRUE},
+     {CKM_SEED_ECB,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_SEED_CBC,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_SEED_MAC,		{16, 16, CKF_SN_VR},		PR_TRUE},
+     {CKM_SEED_MAC_GENERAL,	{16, 16, CKF_SN_VR},		PR_TRUE},
+     {CKM_SEED_CBC_PAD,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE},
+     /* ------------------------- Hashing Operations ----------------------- */
+     {CKM_MD2,			{0,   0, CKF_DIGEST},		PR_FALSE},
+     {CKM_MD2_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_MD2_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_MD5,			{0,   0, CKF_DIGEST},		PR_FALSE},
+     {CKM_MD5_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_MD5_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA_1,		{0,   0, CKF_DIGEST},		PR_FALSE},
+     {CKM_SHA_1_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA_1_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA256,		{0,   0, CKF_DIGEST},		PR_FALSE},
+     {CKM_SHA256_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA256_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA384,		{0,   0, CKF_DIGEST},		PR_FALSE},
+     {CKM_SHA384_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA384_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA512,		{0,   0, CKF_DIGEST},		PR_FALSE},
+     {CKM_SHA512_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_SHA512_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
+     {CKM_TLS_PRF_GENERAL,	{0, 512, CKF_SN_VR},		PR_FALSE},
+     /* ------------------------- CAST Operations --------------------------- */
+#ifdef NSS_SOFTOKEN_DOES_CAST
+     /* Cast operations are not supported ( yet? ) */
+     {CKM_CAST_KEY_GEN,		{1,  8, CKF_GENERATE},		PR_TRUE}, 
+     {CKM_CAST_ECB,		{1,  8, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST_CBC,		{1,  8, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST_MAC,		{1,  8, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_CAST_MAC_GENERAL,	{1,  8, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_CAST_CBC_PAD,		{1,  8, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST3_KEY_GEN,	{1, 16, CKF_GENERATE},		PR_TRUE}, 
+     {CKM_CAST3_ECB,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST3_CBC,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST3_MAC,		{1, 16, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_CAST3_MAC_GENERAL,	{1, 16, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_CAST3_CBC_PAD,	{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST5_KEY_GEN,	{1, 16, CKF_GENERATE},		PR_TRUE}, 
+     {CKM_CAST5_ECB,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST5_CBC,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_CAST5_MAC,		{1, 16, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_CAST5_MAC_GENERAL,	{1, 16, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_CAST5_CBC_PAD,	{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+#endif
+#if NSS_SOFTOKEN_DOES_RC5
+     /* ------------------------- RC5 Operations --------------------------- */
+     {CKM_RC5_KEY_GEN,		{1, 32, CKF_GENERATE},          PR_TRUE},
+     {CKM_RC5_ECB,		{1, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_RC5_CBC,		{1, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
+     {CKM_RC5_MAC,		{1, 32, CKF_SN_VR},  		PR_TRUE},
+     {CKM_RC5_MAC_GENERAL,	{1, 32, CKF_SN_VR},  		PR_TRUE},
+     {CKM_RC5_CBC_PAD,		{1, 32, CKF_EN_DE_WR_UN}, 	PR_TRUE},
+#endif
+#ifdef NSS_SOFTOKEN_DOES_IDEA
+     /* ------------------------- IDEA Operations -------------------------- */
+     {CKM_IDEA_KEY_GEN,		{16, 16, CKF_GENERATE}, 	PR_TRUE}, 
+     {CKM_IDEA_ECB,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_IDEA_CBC,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
+     {CKM_IDEA_MAC,		{16, 16, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_IDEA_MAC_GENERAL,	{16, 16, CKF_SN_VR},		PR_TRUE}, 
+     {CKM_IDEA_CBC_PAD,		{16, 16, CKF_EN_DE_WR_UN}, 	PR_TRUE}, 
+#endif
+     /* --------------------- Secret Key Operations ------------------------ */
+     {CKM_GENERIC_SECRET_KEY_GEN,	{1, 32, CKF_GENERATE}, PR_TRUE}, 
+     {CKM_CONCATENATE_BASE_AND_KEY,	{1, 32, CKF_GENERATE}, PR_FALSE}, 
+     {CKM_CONCATENATE_BASE_AND_DATA,	{1, 32, CKF_GENERATE}, PR_FALSE}, 
+     {CKM_CONCATENATE_DATA_AND_BASE,	{1, 32, CKF_GENERATE}, PR_FALSE}, 
+     {CKM_XOR_BASE_AND_DATA,		{1, 32, CKF_GENERATE}, PR_FALSE}, 
+     {CKM_EXTRACT_KEY_FROM_KEY,		{1, 32, CKF_DERIVE},   PR_FALSE}, 
+     /* ---------------------- SSL Key Derivations ------------------------- */
+     {CKM_SSL3_PRE_MASTER_KEY_GEN,	{48, 48, CKF_GENERATE}, PR_FALSE}, 
+     {CKM_SSL3_MASTER_KEY_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_SSL3_MASTER_KEY_DERIVE_DH,	{8, 128, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_SSL3_KEY_AND_MAC_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_SSL3_MD5_MAC,			{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_SSL3_SHA1_MAC,		{ 0, 20, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_MD5_KEY_DERIVATION,		{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_MD2_KEY_DERIVATION,		{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_SHA1_KEY_DERIVATION,		{ 0, 20, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_TLS_MASTER_KEY_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_TLS_MASTER_KEY_DERIVE_DH,	{8, 128, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_TLS_KEY_AND_MAC_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
+     /* ---------------------- PBE Key Derivations  ------------------------ */
+     {CKM_PBE_MD2_DES_CBC,		{8, 8, CKF_DERIVE},   PR_TRUE},
+     {CKM_PBE_MD5_DES_CBC,		{8, 8, CKF_DERIVE},   PR_TRUE},
+     /* ------------------ NETSCAPE PBE Key Derivations  ------------------- */
+     {CKM_NETSCAPE_PBE_SHA1_DES_CBC,	     { 8, 8, CKF_GENERATE}, PR_TRUE},
+     {CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC, {24,24, CKF_GENERATE}, PR_TRUE},
+     {CKM_PBE_SHA1_DES3_EDE_CBC,	     {24,24, CKF_GENERATE}, PR_TRUE},
+     {CKM_PBE_SHA1_DES2_EDE_CBC,	     {24,24, CKF_GENERATE}, PR_TRUE},
+     {CKM_PBE_SHA1_RC2_40_CBC,		     {40,40, CKF_GENERATE}, PR_TRUE},
+     {CKM_PBE_SHA1_RC2_128_CBC,		     {128,128, CKF_GENERATE}, PR_TRUE},
+     {CKM_PBE_SHA1_RC4_40,		     {40,40, CKF_GENERATE}, PR_TRUE},
+     {CKM_PBE_SHA1_RC4_128,		     {128,128, CKF_GENERATE}, PR_TRUE},
+     {CKM_PBA_SHA1_WITH_SHA1_HMAC,	     {20,20, CKF_GENERATE}, PR_TRUE},
+     {CKM_PKCS5_PBKD2,   		     {1,256, CKF_GENERATE}, PR_TRUE},
+     {CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN,    {20,20, CKF_GENERATE}, PR_TRUE},
+     {CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN,     {16,16, CKF_GENERATE}, PR_TRUE},
+     {CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN,     {16,16, CKF_GENERATE}, PR_TRUE},
+     /* ------------------ AES Key Wrap (also encrypt)  ------------------- */
+     {CKM_NETSCAPE_AES_KEY_WRAP,	{16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
+     {CKM_NETSCAPE_AES_KEY_WRAP_PAD,	{16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
+};
+static const CK_ULONG mechanismCount = sizeof(mechanisms)/sizeof(mechanisms[0]);
+
+/* sigh global so fipstokn can read it */
+PRBool nsc_init = PR_FALSE;
+
+#if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
+
+#include <pthread.h>
+
+static void ForkedChild(void)
+{
+    if (nsc_init || nsf_init) {
+        forked = PR_TRUE;
+    }
+}
+
+#endif
+
+static char *
+sftk_setStringName(const char *inString, char *buffer, int buffer_length, 		PRBool nullTerminate)
+{
+    int full_length, string_length;
+
+    full_length = nullTerminate ? buffer_length -1 : buffer_length;
+    string_length = PORT_Strlen(inString);
+    /* 
+     *  shorten the string, respecting utf8 encoding
+     *  to do so, we work backward from the end 
+     *  bytes looking from the end are either:
+     *    - ascii [0x00,0x7f]
+     *    - the [2-n]th byte of a multibyte sequence 
+     *        [0x3F,0xBF], i.e, most significant 2 bits are '10'
+     *    - the first byte of a multibyte sequence [0xC0,0xFD],
+     *        i.e, most significant 2 bits are '11'
+     *
+     *    When the string is too long, we lop off any trailing '10' bytes,
+     *  if any. When these are all eliminated we lop off
+     *  one additional byte. Thus if we lopped any '10'
+     *  we'll be lopping a '11' byte (the first byte of the multibyte sequence),
+     *  otherwise we're lopping off an ascii character.
+     *
+     *    To test for '10' bytes, we first AND it with 
+     *  11000000 (0xc0) so that we get 10000000 (0x80) if and only if
+     *  the byte starts with 10. We test for equality.
+     */
+    while ( string_length > full_length ) {
+	/* need to shorten */
+	while ( string_length > 0 && 
+	      ((inString[string_length-1]&(char)0xc0) == (char)0x80)) {
+	    /* lop off '10' byte */
+	    string_length--;
+	}
+	/* 
+	 * test string_length in case bad data is received
+	 * and string consisted of all '10' bytes,
+	 * avoiding any infinite loop
+         */
+	if ( string_length ) {
+	    /* remove either '11' byte or an asci byte */
+	    string_length--;
+	}
+    }
+    PORT_Memset(buffer,' ',full_length);
+    if (nullTerminate) {
+	buffer[full_length] = 0;
+    }
+    PORT_Memcpy(buffer,inString,string_length);
+    return buffer;
+}
+/*
+ * Configuration utils
+ */
+static CK_RV
+sftk_configure(const char *man, const char *libdes)
+{
+
+    /* make sure the internationalization was done correctly... */
+    if (man) {
+	manufacturerID = sftk_setStringName(man,manufacturerID_space,
+					sizeof(manufacturerID_space), PR_TRUE);
+    }
+    if (libdes) {
+	libraryDescription = sftk_setStringName(libdes,
+		libraryDescription_space, sizeof(libraryDescription_space), 
+		PR_TRUE);
+    }
+
+    return CKR_OK;
+}
+
+/*
+ * ******************** Password Utilities *******************************
+ */
+
+/*
+ * see if the key DB password is enabled
+ */
+static PRBool
+sftk_hasNullPassword(SFTKSlot *slot, SFTKDBHandle *keydb)
+{
+    PRBool pwenabled;
+   
+    pwenabled = PR_FALSE;
+    if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
+	PRBool tokenRemoved = PR_FALSE;
+    	SECStatus rv = sftkdb_CheckPassword(keydb, "", &tokenRemoved);
+	if (tokenRemoved) {
+	    sftk_CloseAllSessions(slot, PR_FALSE);
+	}
+	return (rv  == SECSuccess);
+    }
+
+    return pwenabled;
+}
+
+/*
+ * ******************** Object Creation Utilities ***************************
+ */
+
+
+/* Make sure a given attribute exists. If it doesn't, initialize it to
+ * value and len
+ */
+CK_RV
+sftk_defaultAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type,void *value,
+							unsigned int len)
+{
+    if ( !sftk_hasAttribute(object, type)) {
+	return sftk_AddAttributeType(object,type,value,len);
+    }
+    return CKR_OK;
+}
+
+/*
+ * check the consistancy and initialize a Data Object 
+ */
+static CK_RV
+sftk_handleDataObject(SFTKSession *session,SFTKObject *object)
+{
+    CK_RV crv;
+
+    /* first reject private and token data objects */
+    if (sftk_isTrue(object,CKA_PRIVATE) || sftk_isTrue(object,CKA_TOKEN)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    /* now just verify the required date fields */
+    crv = sftk_defaultAttribute(object,CKA_APPLICATION,NULL,0);
+    if (crv != CKR_OK) return crv;
+    crv = sftk_defaultAttribute(object,CKA_VALUE,NULL,0);
+    if (crv != CKR_OK) return crv;
+
+    return CKR_OK;
+}
+
+/*
+ * check the consistancy and initialize a Certificate Object 
+ */
+static CK_RV
+sftk_handleCertObject(SFTKSession *session,SFTKObject *object)
+{
+    CK_CERTIFICATE_TYPE type;
+    SFTKAttribute *attribute;
+    CK_RV crv;
+
+    /* certificates must have a type */
+    if ( !sftk_hasAttribute(object,CKA_CERTIFICATE_TYPE) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    /* we can't store any certs private */
+    if (sftk_isTrue(object,CKA_PRIVATE)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+	
+    /* We only support X.509 Certs for now */
+    attribute = sftk_FindAttribute(object,CKA_CERTIFICATE_TYPE);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+    type = *(CK_CERTIFICATE_TYPE *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+
+    if (type != CKC_X_509) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    /* X.509 Certificate */
+
+    /* make sure we have a cert */
+    if ( !sftk_hasAttribute(object,CKA_VALUE) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    /* in PKCS #11, Subject is a required field */
+    if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    /* in PKCS #11, Issuer is a required field */
+    if ( !sftk_hasAttribute(object,CKA_ISSUER) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    /* in PKCS #11, Serial is a required field */
+    if ( !sftk_hasAttribute(object,CKA_SERIAL_NUMBER) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    /* add it to the object */
+    object->objectInfo = NULL;
+    object->infoFree = (SFTKFree) NULL;
+    
+    /* now just verify the required date fields */
+    crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0);
+    if (crv != CKR_OK) { return crv; }
+
+    if (sftk_isTrue(object,CKA_TOKEN)) {
+	SFTKSlot *slot = session->slot;
+	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
+
+	if (certHandle == NULL) {
+	    return CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	crv = sftkdb_write(certHandle, object, &object->handle);
+	sftk_freeDB(certHandle);
+	return crv;
+    }
+
+    return CKR_OK;
+}
+	
+/*
+ * check the consistancy and initialize a Trust Object 
+ */
+static CK_RV
+sftk_handleTrustObject(SFTKSession *session,SFTKObject *object)
+{
+    /* we can't store any certs private */
+    if (sftk_isTrue(object,CKA_PRIVATE)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    /* certificates must have a type */
+    if ( !sftk_hasAttribute(object,CKA_ISSUER) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    if ( !sftk_hasAttribute(object,CKA_SERIAL_NUMBER) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    if ( !sftk_hasAttribute(object,CKA_CERT_SHA1_HASH) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    if ( !sftk_hasAttribute(object,CKA_CERT_MD5_HASH) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    if (sftk_isTrue(object,CKA_TOKEN)) {
+	SFTKSlot *slot = session->slot;
+	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
+	CK_RV crv;
+
+	if (certHandle == NULL) {
+	    return CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	crv = sftkdb_write(certHandle, object, &object->handle);
+	sftk_freeDB(certHandle);
+	return crv;
+    }
+
+    return CKR_OK;
+}
+
+/*
+ * check the consistancy and initialize a Trust Object 
+ */
+static CK_RV
+sftk_handleSMimeObject(SFTKSession *session,SFTKObject *object)
+{
+
+    /* we can't store any certs private */
+    if (sftk_isTrue(object,CKA_PRIVATE)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    /* certificates must have a type */
+    if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    if ( !sftk_hasAttribute(object,CKA_NETSCAPE_EMAIL) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    if (sftk_isTrue(object,CKA_TOKEN)) {
+	SFTKSlot *slot = session->slot;
+	SFTKDBHandle *certHandle;
+	CK_RV crv;
+
+	PORT_Assert(slot);
+	if (slot == NULL) {
+	    return CKR_SESSION_HANDLE_INVALID;
+	}
+
+	certHandle = sftk_getCertDB(slot);
+	if (certHandle == NULL) {
+	    return CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	crv = sftkdb_write(certHandle, object, &object->handle);
+	sftk_freeDB(certHandle);
+	return crv;
+    }
+
+    return CKR_OK;
+}
+
+/*
+ * check the consistancy and initialize a Trust Object 
+ */
+static CK_RV
+sftk_handleCrlObject(SFTKSession *session,SFTKObject *object)
+{
+
+    /* we can't store any certs private */
+    if (sftk_isTrue(object,CKA_PRIVATE)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    /* certificates must have a type */
+    if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    if ( !sftk_hasAttribute(object,CKA_VALUE) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    if (sftk_isTrue(object,CKA_TOKEN)) {
+	SFTKSlot *slot = session->slot;
+	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
+	CK_RV crv;
+
+	if (certHandle == NULL) {
+	    return CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	crv = sftkdb_write(certHandle, object, &object->handle);
+	sftk_freeDB(certHandle);
+	return crv;
+    }
+
+    return CKR_OK;
+}
+
+/*
+ * check the consistancy and initialize a Public Key Object 
+ */
+static CK_RV
+sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
+							 CK_KEY_TYPE key_type)
+{
+    CK_BBOOL encrypt = CK_TRUE;
+    CK_BBOOL recover = CK_TRUE;
+    CK_BBOOL wrap = CK_TRUE;
+    CK_BBOOL derive = CK_FALSE;
+    CK_BBOOL verify = CK_TRUE;
+    CK_RV crv;
+
+    switch (key_type) {
+    case CKK_RSA:
+	crv = sftk_ConstrainAttribute(object, CKA_MODULUS,
+						 RSA_MIN_MODULUS_BITS, 0, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	crv = sftk_ConstrainAttribute(object, CKA_PUBLIC_EXPONENT, 2, 0, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	break;
+    case CKK_DSA:
+	crv = sftk_ConstrainAttribute(object, CKA_SUBPRIME, 
+						DSA_Q_BITS, DSA_Q_BITS, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	crv = sftk_ConstrainAttribute(object, CKA_PRIME, 
+					DSA_MIN_P_BITS, DSA_MAX_P_BITS, 64);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	crv = sftk_ConstrainAttribute(object, CKA_BASE, 1, DSA_MAX_P_BITS, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	crv = sftk_ConstrainAttribute(object, CKA_VALUE, 1, DSA_MAX_P_BITS, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	encrypt = CK_FALSE;
+	recover = CK_FALSE;
+	wrap = CK_FALSE;
+	break;
+    case CKK_DH:
+	crv = sftk_ConstrainAttribute(object, CKA_PRIME, 
+					DH_MIN_P_BITS, DH_MAX_P_BITS, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	crv = sftk_ConstrainAttribute(object, CKA_BASE, 1, DH_MAX_P_BITS, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	crv = sftk_ConstrainAttribute(object, CKA_VALUE, 1, DH_MAX_P_BITS, 0);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	verify = CK_FALSE;
+	derive = CK_TRUE;
+	encrypt = CK_FALSE;
+	recover = CK_FALSE;
+	wrap = CK_FALSE;
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKK_EC:
+	if ( !sftk_hasAttribute(object, CKA_EC_PARAMS)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_EC_POINT)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	derive = CK_TRUE;    /* for ECDH */
+	verify = CK_TRUE;    /* for ECDSA */
+	encrypt = CK_FALSE;
+	recover = CK_FALSE;
+	wrap = CK_FALSE;
+	break;
+#endif /* NSS_ENABLE_ECC */
+    default:
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    /* make sure the required fields exist */
+    crv = sftk_defaultAttribute(object,CKA_SUBJECT,NULL,0);
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_ENCRYPT,&encrypt,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_VERIFY,&verify,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_VERIFY_RECOVER,
+						&recover,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_WRAP,&wrap,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_DERIVE,&derive,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+
+    object->objectInfo = sftk_GetPubKey(object,key_type, &crv);
+    if (object->objectInfo == NULL) {
+	return crv;
+    }
+    object->infoFree = (SFTKFree) nsslowkey_DestroyPublicKey;
+
+    if (sftk_isTrue(object,CKA_TOKEN)) {
+	SFTKSlot *slot = session->slot;
+	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
+
+	if (certHandle == NULL) {
+	    return CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	crv = sftkdb_write(certHandle, object, &object->handle);
+	sftk_freeDB(certHandle);
+	return crv;
+    }
+
+    return CKR_OK;
+}
+
+static NSSLOWKEYPrivateKey * 
+sftk_mkPrivKey(SFTKObject *object,CK_KEY_TYPE key, CK_RV *rvp);
+
+/*
+ * check the consistancy and initialize a Private Key Object 
+ */
+static CK_RV
+sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE key_type)
+{
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL encrypt = CK_TRUE;
+    CK_BBOOL sign = CK_FALSE;
+    CK_BBOOL recover = CK_TRUE;
+    CK_BBOOL wrap = CK_TRUE;
+    CK_BBOOL derive = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    SECItem mod;
+    CK_RV crv;
+
+    switch (key_type) {
+    case CKK_RSA:
+	if ( !sftk_hasAttribute(object, CKA_MODULUS)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_PUBLIC_EXPONENT)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_PRIVATE_EXPONENT)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_PRIME_1)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_PRIME_2)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_EXPONENT_1)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_EXPONENT_2)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_COEFFICIENT)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	/* make sure Netscape DB attribute is set correctly */
+	crv = sftk_Attribute2SSecItem(NULL, &mod, object, CKA_MODULUS);
+	if (crv != CKR_OK) return crv;
+	crv = sftk_forceAttribute(object, CKA_NETSCAPE_DB, 
+						sftk_item_expand(&mod));
+	if (mod.data) PORT_Free(mod.data);
+	if (crv != CKR_OK) return crv;
+
+	sign = CK_TRUE;
+	derive = CK_FALSE;
+	break;
+    case CKK_DSA:
+	if ( !sftk_hasAttribute(object, CKA_SUBPRIME)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	sign = CK_TRUE;
+	derive = CK_FALSE;
+	/* fall through */
+    case CKK_DH:
+	if ( !sftk_hasAttribute(object, CKA_PRIME)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_BASE)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_VALUE)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	encrypt = CK_FALSE;
+	recover = CK_FALSE;
+	wrap = CK_FALSE;
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKK_EC:
+	if ( !sftk_hasAttribute(object, CKA_EC_PARAMS)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	if ( !sftk_hasAttribute(object, CKA_VALUE)) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	encrypt = CK_FALSE;
+	sign = CK_TRUE;
+	recover = CK_FALSE;
+	wrap = CK_FALSE;
+	break;
+#endif /* NSS_ENABLE_ECC */
+    default:
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    crv = sftk_defaultAttribute(object,CKA_SUBJECT,NULL,0);
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_SENSITIVE,&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_DECRYPT,&encrypt,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_SIGN,&sign,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_SIGN_RECOVER,&recover,
+							     sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_UNWRAP,&wrap,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_DERIVE,&derive,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    /* the next two bits get modified only in the key gen and token cases */
+    crv = sftk_forceAttribute(object,CKA_ALWAYS_SENSITIVE,
+						&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_forceAttribute(object,CKA_NEVER_EXTRACTABLE,
+						&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+
+    /* should we check the non-token RSA private keys? */
+
+    if (sftk_isTrue(object,CKA_TOKEN)) {
+	SFTKSlot *slot = session->slot;
+	SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
+	CK_RV crv;
+
+	if (keyHandle == NULL) {
+	    return CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	crv = sftkdb_write(keyHandle, object, &object->handle);
+	sftk_freeDB(keyHandle);
+	return crv;
+    } else {
+	object->objectInfo = sftk_mkPrivKey(object,key_type,&crv);
+	if (object->objectInfo == NULL) return crv;
+	object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
+    }
+    return CKR_OK;
+}
+
+/* forward declare the DES formating function for handleSecretKey */
+void sftk_FormatDESKey(unsigned char *key, int length);
+
+/* Validate secret key data, and set defaults */
+static CK_RV
+validateSecretKey(SFTKSession *session, SFTKObject *object, 
+					CK_KEY_TYPE key_type, PRBool isFIPS)
+{
+    CK_RV crv;
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    SFTKAttribute *attribute = NULL;
+    unsigned long requiredLen;
+
+    crv = sftk_defaultAttribute(object,CKA_SENSITIVE,
+				isFIPS?&cktrue:&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_EXTRACTABLE,
+						&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_ENCRYPT,&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_DECRYPT,&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_SIGN,&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_VERIFY,&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_WRAP,&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_UNWRAP,&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+
+    if ( !sftk_hasAttribute(object, CKA_VALUE)) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    /* the next two bits get modified only in the key gen and token cases */
+    crv = sftk_forceAttribute(object,CKA_ALWAYS_SENSITIVE,
+						&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_forceAttribute(object,CKA_NEVER_EXTRACTABLE,
+						&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+
+    /* some types of keys have a value length */
+    crv = CKR_OK;
+    switch (key_type) {
+    /* force CKA_VALUE_LEN to be set */
+    case CKK_GENERIC_SECRET:
+    case CKK_RC2:
+    case CKK_RC4:
+#if NSS_SOFTOKEN_DOES_RC5
+    case CKK_RC5:
+#endif
+#ifdef NSS_SOFTOKEN_DOES_CAST
+    case CKK_CAST:
+    case CKK_CAST3:
+    case CKK_CAST5:
+#endif
+#if NSS_SOFTOKEN_DOES_IDEA
+    case CKK_IDEA:
+#endif
+	attribute = sftk_FindAttribute(object,CKA_VALUE);
+	/* shouldn't happen */
+	if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+	crv = sftk_forceAttribute(object, CKA_VALUE_LEN, 
+			&attribute->attrib.ulValueLen, sizeof(CK_ULONG));
+	sftk_FreeAttribute(attribute);
+	break;
+    /* force the value to have the correct parity */
+    case CKK_DES:
+    case CKK_DES2:
+    case CKK_DES3:
+    case CKK_CDMF:
+	attribute = sftk_FindAttribute(object,CKA_VALUE);
+	/* shouldn't happen */
+	if (attribute == NULL) 
+	    return CKR_TEMPLATE_INCOMPLETE;
+	requiredLen = sftk_MapKeySize(key_type);
+	if (attribute->attrib.ulValueLen != requiredLen) {
+	    sftk_FreeAttribute(attribute);
+	    return CKR_KEY_SIZE_RANGE;
+	}
+	sftk_FormatDESKey((unsigned char*)attribute->attrib.pValue,
+						 attribute->attrib.ulValueLen);
+	sftk_FreeAttribute(attribute);
+	break;
+    case CKK_AES:
+	attribute = sftk_FindAttribute(object,CKA_VALUE);
+	/* shouldn't happen */
+	if (attribute == NULL) 
+	    return CKR_TEMPLATE_INCOMPLETE;
+	if (attribute->attrib.ulValueLen != 16 &&
+	    attribute->attrib.ulValueLen != 24 &&
+	    attribute->attrib.ulValueLen != 32) {
+	    sftk_FreeAttribute(attribute);
+	    return CKR_KEY_SIZE_RANGE;
+	}
+	crv = sftk_forceAttribute(object, CKA_VALUE_LEN, 
+			&attribute->attrib.ulValueLen, sizeof(CK_ULONG));
+	sftk_FreeAttribute(attribute);
+	break;
+    default:
+	break;
+    }
+
+    return crv;
+}
+
+/*
+ * check the consistancy and initialize a Secret Key Object 
+ */
+static CK_RV
+sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object,
+					CK_KEY_TYPE key_type, PRBool isFIPS)
+{
+    CK_RV crv;
+
+    /* First validate and set defaults */
+    crv = validateSecretKey(session, object, key_type, isFIPS);
+    if (crv != CKR_OK) goto loser;
+
+    /* If the object is a TOKEN object, store in the database */
+    if (sftk_isTrue(object,CKA_TOKEN)) {
+	SFTKSlot *slot = session->slot;
+	SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
+	CK_RV crv;
+
+	if (keyHandle == NULL) {
+	    return CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	crv = sftkdb_write(keyHandle, object, &object->handle);
+	sftk_freeDB(keyHandle);
+	return crv;
+    }
+
+loser:
+
+    return crv;
+}
+
+/*
+ * check the consistancy and initialize a Key Object 
+ */
+static CK_RV
+sftk_handleKeyObject(SFTKSession *session, SFTKObject *object)
+{
+    SFTKAttribute *attribute;
+    CK_KEY_TYPE key_type;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_RV crv;
+
+    /* verify the required fields */
+    if ( !sftk_hasAttribute(object,CKA_KEY_TYPE) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    /* now verify the common fields */
+    crv = sftk_defaultAttribute(object,CKA_ID,NULL,0);
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_START_DATE,NULL,0);
+    if (crv != CKR_OK)  return crv; 
+    crv = sftk_defaultAttribute(object,CKA_END_DATE,NULL,0);
+    if (crv != CKR_OK)  return crv; 
+    /* CKA_DERIVE is common to all keys, but it's default value is
+     * key dependent */
+    crv = sftk_defaultAttribute(object,CKA_LOCAL,&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+
+    /* get the key type */
+    attribute = sftk_FindAttribute(object,CKA_KEY_TYPE);
+    if (!attribute) {
+        return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+
+    switch (object->objclass) {
+    case CKO_PUBLIC_KEY:
+	return sftk_handlePublicKeyObject(session,object,key_type);
+    case CKO_PRIVATE_KEY:
+	return sftk_handlePrivateKeyObject(session,object,key_type);
+    case CKO_SECRET_KEY:
+	/* make sure the required fields exist */
+	return sftk_handleSecretKeyObject(session,object,key_type,
+			     (PRBool)(session->slot->slotID == FIPS_SLOT_ID));
+    default:
+	break;
+    }
+    return CKR_ATTRIBUTE_VALUE_INVALID;
+}
+
+/*
+ * check the consistancy and Verify a DSA Parameter Object 
+ */
+static CK_RV
+sftk_handleDSAParameterObject(SFTKSession *session, SFTKObject *object)
+{
+    SFTKAttribute *primeAttr = NULL;
+    SFTKAttribute *subPrimeAttr = NULL;
+    SFTKAttribute *baseAttr = NULL;
+    SFTKAttribute *seedAttr = NULL;
+    SFTKAttribute *hAttr = NULL;
+    SFTKAttribute *attribute;
+    CK_RV crv = CKR_TEMPLATE_INCOMPLETE;
+    PQGParams params;
+    PQGVerify vfy, *verify = NULL;
+    SECStatus result,rv;
+
+    primeAttr = sftk_FindAttribute(object,CKA_PRIME);
+    if (primeAttr == NULL) goto loser;
+    params.prime.data = primeAttr->attrib.pValue;
+    params.prime.len = primeAttr->attrib.ulValueLen;
+
+    subPrimeAttr = sftk_FindAttribute(object,CKA_SUBPRIME);
+    if (subPrimeAttr == NULL) goto loser;
+    params.subPrime.data = subPrimeAttr->attrib.pValue;
+    params.subPrime.len = subPrimeAttr->attrib.ulValueLen;
+
+    baseAttr = sftk_FindAttribute(object,CKA_BASE);
+    if (baseAttr == NULL) goto loser;
+    params.base.data = baseAttr->attrib.pValue;
+    params.base.len = baseAttr->attrib.ulValueLen;
+
+    attribute = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_COUNTER);
+    if (attribute != NULL) {
+	vfy.counter = *(CK_ULONG *) attribute->attrib.pValue;
+	sftk_FreeAttribute(attribute);
+
+	seedAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_SEED);
+	if (seedAttr == NULL) goto loser;
+	vfy.seed.data = seedAttr->attrib.pValue;
+	vfy.seed.len = seedAttr->attrib.ulValueLen;
+
+	hAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_H);
+	if (hAttr == NULL) goto loser;
+	vfy.h.data = hAttr->attrib.pValue;
+	vfy.h.len = hAttr->attrib.ulValueLen;
+
+	verify = &vfy;
+    }
+
+    crv = CKR_FUNCTION_FAILED;
+    rv = PQG_VerifyParams(&params,verify,&result);
+    if (rv == SECSuccess) {
+	crv = (result== SECSuccess) ? CKR_OK : CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+loser:
+    if (hAttr) sftk_FreeAttribute(hAttr);
+    if (seedAttr) sftk_FreeAttribute(seedAttr);
+    if (baseAttr) sftk_FreeAttribute(baseAttr);
+    if (subPrimeAttr) sftk_FreeAttribute(subPrimeAttr);
+    if (primeAttr) sftk_FreeAttribute(primeAttr);
+
+    return crv;
+}
+
+/*
+ * check the consistancy and initialize a Key Parameter Object 
+ */
+static CK_RV
+sftk_handleKeyParameterObject(SFTKSession *session, SFTKObject *object)
+{
+    SFTKAttribute *attribute;
+    CK_KEY_TYPE key_type;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_RV crv;
+
+    /* verify the required fields */
+    if ( !sftk_hasAttribute(object,CKA_KEY_TYPE) ) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+
+    /* now verify the common fields */
+    crv = sftk_defaultAttribute(object,CKA_LOCAL,&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK)  return crv; 
+
+    /* get the key type */
+    attribute = sftk_FindAttribute(object,CKA_KEY_TYPE);
+    if (!attribute) {
+        return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+
+    switch (key_type) {
+    case CKK_DSA:
+	return sftk_handleDSAParameterObject(session,object);
+	
+    default:
+	break;
+    }
+    return CKR_KEY_TYPE_INCONSISTENT;
+}
+
+/* 
+ * Handle Object does all the object consistancy checks, automatic attribute
+ * generation, attribute defaulting, etc. If handleObject succeeds, the object
+ * will be assigned an object handle, and the object installed in the session
+ * or stored in the DB.
+ */
+CK_RV
+sftk_handleObject(SFTKObject *object, SFTKSession *session)
+{
+    SFTKSlot *slot = session->slot;
+    SFTKAttribute *attribute;
+    SFTKObject *duplicateObject = NULL;
+    CK_OBJECT_HANDLE handle;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_RV crv;
+
+    /* make sure all the base object types are defined. If not set the
+     * defaults */
+    crv = sftk_defaultAttribute(object,CKA_TOKEN,&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK) return crv;
+    crv = sftk_defaultAttribute(object,CKA_PRIVATE,&ckfalse,sizeof(CK_BBOOL));
+    if (crv != CKR_OK) return crv;
+    crv = sftk_defaultAttribute(object,CKA_LABEL,NULL,0);
+    if (crv != CKR_OK) return crv;
+    crv = sftk_defaultAttribute(object,CKA_MODIFIABLE,&cktrue,sizeof(CK_BBOOL));
+    if (crv != CKR_OK) return crv;
+
+    /* don't create a private object if we aren't logged in */
+    if ((!slot->isLoggedIn) && (slot->needLogin) &&
+				(sftk_isTrue(object,CKA_PRIVATE))) {
+	return CKR_USER_NOT_LOGGED_IN;
+    }
+
+
+    if (((session->info.flags & CKF_RW_SESSION) == 0) &&
+				(sftk_isTrue(object,CKA_TOKEN))) {
+	return CKR_SESSION_READ_ONLY;
+    }
+	
+    /* Assign a unique SESSION object handle to every new object,
+     * whether it is a session object or a token object.  
+     * At this point, all new objects are structured as session objects.
+     * Objects with the CKA_TOKEN attribute true will be turned into 
+     * token objects and will have a token object handle assigned to 
+     * them by a call to sftk_mkHandle in the handler for each object 
+     * class, invoked below.
+     *
+     * It may be helpful to note/remember that 
+     * sftk_narrowToXxxObject uses sftk_isToken,
+     * sftk_isToken examines the sign bit of the object's handle, but
+     * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute.
+     */
+    do {
+	PRUint32 wrappedAround;
+
+	duplicateObject = NULL;
+	PZ_Lock(slot->objectLock);
+	wrappedAround = slot->sessionObjectHandleCount &  SFTK_TOKEN_MASK;
+	handle        = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
+	if (!handle) /* don't allow zero handle */
+	    handle = minSessionObjectHandle;  
+	slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
+	/* Is there already a session object with this handle? */
+	if (wrappedAround) {
+	    sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable, \
+	                   slot->sessObjHashSize);
+	}
+	PZ_Unlock(slot->objectLock);
+    } while (duplicateObject != NULL);
+    object->handle = handle;
+
+    /* get the object class */
+    attribute = sftk_FindAttribute(object,CKA_CLASS);
+    if (attribute == NULL) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    object->objclass = *(CK_OBJECT_CLASS *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+
+    /* Now handle the specific object class. 
+     * At this point, all objects are session objects, and the session
+     * number must be passed to the object class handlers.
+     */
+    switch (object->objclass) {
+    case CKO_DATA:
+	crv = sftk_handleDataObject(session,object);
+	break;
+    case CKO_CERTIFICATE:
+	crv = sftk_handleCertObject(session,object);
+	break;
+    case CKO_NETSCAPE_TRUST:
+	crv = sftk_handleTrustObject(session,object);
+	break;
+    case CKO_NETSCAPE_CRL:
+	crv = sftk_handleCrlObject(session,object);
+	break;
+    case CKO_NETSCAPE_SMIME:
+	crv = sftk_handleSMimeObject(session,object);
+	break;
+    case CKO_PRIVATE_KEY:
+    case CKO_PUBLIC_KEY:
+    case CKO_SECRET_KEY:
+	crv = sftk_handleKeyObject(session,object);
+	break;
+    case CKO_KG_PARAMETERS:
+	crv = sftk_handleKeyParameterObject(session,object);
+	break;
+    default:
+	crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	break;
+    }
+
+    /* can't fail from here on out unless the pk_handlXXX functions have
+     * failed the request */
+    if (crv != CKR_OK) {
+	return crv;
+    }
+
+    /* Now link the object into the slot and session structures.
+     * If the object has a true CKA_TOKEN attribute, the above object
+     * class handlers will have set the sign bit in the object handle,
+     * causing the following test to be true.
+     */
+    if (sftk_isToken(object->handle)) {
+	sftk_convertSessionToToken(object);
+    } else {
+	object->slot = slot;
+	sftk_AddObject(session,object);
+    }
+
+    return CKR_OK;
+}
+
+/*
+ * ******************** Public Key Utilities ***************************
+ */
+/* Generate a low public key structure from an object */
+NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,CK_KEY_TYPE key_type, 
+								CK_RV *crvp)
+{
+    NSSLOWKEYPublicKey *pubKey;
+    PLArenaPool *arena;
+    CK_RV crv;
+
+    if (object->objclass != CKO_PUBLIC_KEY) {
+	*crvp = CKR_KEY_TYPE_INCONSISTENT;
+	return NULL;
+    }
+
+    if (sftk_isToken(object->handle)) {
+/* ferret out the token object handle */
+    }
+
+    /* If we already have a key, use it */
+    if (object->objectInfo) {
+	*crvp = CKR_OK;
+	return (NSSLOWKEYPublicKey *)object->objectInfo;
+    }
+
+    /* allocate the structure */
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	*crvp = CKR_HOST_MEMORY;
+	return NULL;
+    }
+
+    pubKey = (NSSLOWKEYPublicKey *)
+			PORT_ArenaAlloc(arena,sizeof(NSSLOWKEYPublicKey));
+    if (pubKey == NULL) {
+    	PORT_FreeArena(arena,PR_FALSE);
+	*crvp = CKR_HOST_MEMORY;
+	return NULL;
+    }
+
+    /* fill in the structure */
+    pubKey->arena = arena;
+    switch (key_type) {
+    case CKK_RSA:
+	pubKey->keyType = NSSLOWKEYRSAKey;
+	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.modulus,
+							object,CKA_MODULUS);
+    	if (crv != CKR_OK) break;
+    	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.publicExponent,
+						object,CKA_PUBLIC_EXPONENT);
+	break;
+    case CKK_DSA:
+	pubKey->keyType = NSSLOWKEYDSAKey;
+	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.prime,
+							object,CKA_PRIME);
+    	if (crv != CKR_OK) break;
+	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.subPrime,
+							object,CKA_SUBPRIME);
+    	if (crv != CKR_OK) break;
+	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.base,
+							object,CKA_BASE);
+    	if (crv != CKR_OK) break;
+    	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.publicValue,
+							object,CKA_VALUE);
+	break;
+    case CKK_DH:
+	pubKey->keyType = NSSLOWKEYDHKey;
+	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.prime,
+							object,CKA_PRIME);
+    	if (crv != CKR_OK) break;
+	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.base,
+							object,CKA_BASE);
+    	if (crv != CKR_OK) break;
+    	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.publicValue,
+							object,CKA_VALUE);
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKK_EC:
+	pubKey->keyType = NSSLOWKEYECKey;
+	crv = sftk_Attribute2SSecItem(arena,
+	                              &pubKey->u.ec.ecParams.DEREncoding,
+	                              object,CKA_EC_PARAMS);
+	if (crv != CKR_OK) break;
+
+	/* Fill out the rest of the ecParams structure 
+	 * based on the encoded params
+	 */
+	if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding,
+		    &pubKey->u.ec.ecParams) != SECSuccess) {
+	    crv = CKR_DOMAIN_PARAMS_INVALID;
+	    break;
+	}
+	    
+	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.ec.publicValue,
+	                              object,CKA_EC_POINT);
+	if (crv == CKR_OK) {
+	    int keyLen,curveLen;
+
+	    curveLen = (pubKey->u.ec.ecParams.fieldID.size +7)/8;
+	    keyLen = (2*curveLen)+1;
+
+	    /* special note: We can't just use the first byte to determine
+	     * between these 2 cases because both EC_POINT_FORM_UNCOMPRESSED 
+	     * and SEC_ASN1_OCTET_STRING are 0x04 */
+
+	    /* handle the non-DER encoded case (UNCOMPRESSED only) */	
+	    if (pubKey->u.ec.publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED
+		&& pubKey->u.ec.publicValue.len == keyLen) {
+		break; /* key was not DER encoded, no need to unwrap */
+	    }
+
+	    /* if we ever support compressed, handle it here */
+
+	    /* handle the encoded case */
+	    if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) 
+		&& pubKey->u.ec.publicValue.len > keyLen) {
+		SECItem publicValue;
+		SECStatus rv;
+
+		rv = SEC_QuickDERDecodeItem(arena, &publicValue, 
+					 SEC_ASN1_GET(SEC_OctetStringTemplate), 
+					 &pubKey->u.ec.publicValue);
+		/* nope, didn't decode correctly */
+		if ((rv != SECSuccess)
+		    || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)
+		    || (publicValue.len != keyLen)) {
+	   	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
+		    break;
+		}
+		/* replace our previous with the decoded key */
+		pubKey->u.ec.publicValue = publicValue;
+		break;
+	    }
+	   crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+	break;
+#endif /* NSS_ENABLE_ECC */
+    default:
+	crv = CKR_KEY_TYPE_INCONSISTENT;
+	break;
+    }
+    *crvp = crv;
+    if (crv != CKR_OK) {
+    	PORT_FreeArena(arena,PR_FALSE);
+	return NULL;
+    }
+
+    object->objectInfo = pubKey;
+    object->infoFree = (SFTKFree) nsslowkey_DestroyPublicKey;
+    return pubKey;
+}
+
+/* make a private key from a verified object */
+static NSSLOWKEYPrivateKey *
+sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
+{
+    NSSLOWKEYPrivateKey *privKey;
+    SFTKItemTemplate itemTemplate[SFTK_MAX_ITEM_TEMPLATE];
+    int itemTemplateCount = 0;
+    PLArenaPool *arena;
+    CK_RV crv = CKR_OK;
+    SECStatus rv;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	*crvp = CKR_HOST_MEMORY;
+	return NULL;
+    }
+
+    privKey = (NSSLOWKEYPrivateKey *)
+			PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey));
+    if (privKey == NULL)  {
+	PORT_FreeArena(arena,PR_FALSE);
+	*crvp = CKR_HOST_MEMORY;
+	return NULL;
+    }
+
+    /* in future this would be a switch on key_type */
+    privKey->arena = arena;
+    switch (key_type) {
+    case CKK_RSA:
+	privKey->keyType = NSSLOWKEYRSAKey;
+
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.modulus,CKA_MODULUS);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.publicExponent, CKA_PUBLIC_EXPONENT);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.privateExponent, CKA_PRIVATE_EXPONENT);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.prime1, CKA_PRIME_1);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.prime2, CKA_PRIME_2);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.exponent1, CKA_EXPONENT_1);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.exponent2, CKA_EXPONENT_2);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.rsa.coefficient, CKA_COEFFICIENT);
+	itemTemplateCount++;
+        rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version,
+                          NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
+	if (rv != SECSuccess) crv = CKR_HOST_MEMORY;
+	break;
+
+    case CKK_DSA:
+	privKey->keyType = NSSLOWKEYDSAKey;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.dsa.params.prime, CKA_PRIME);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.dsa.params.subPrime, CKA_SUBPRIME);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.dsa.params.base, CKA_BASE);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.dsa.privateValue, CKA_VALUE);
+	itemTemplateCount++;
+	/* privKey was zero'd so public value is already set to NULL, 0
+	 * if we don't set it explicitly */
+	break;
+
+    case CKK_DH:
+	privKey->keyType = NSSLOWKEYDHKey;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.dh.prime, CKA_PRIME);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.dh.base, CKA_BASE);
+	itemTemplateCount++;
+	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
+		&privKey->u.dh.privateValue, CKA_VALUE);
+	itemTemplateCount++;
+	/* privKey was zero'd so public value is already set to NULL, 0
+	 * if we don't set it explicitly */
+	break;
+
+#ifdef NSS_ENABLE_ECC
+    case CKK_EC:
+	privKey->keyType = NSSLOWKEYECKey;
+	crv = sftk_Attribute2SSecItem(arena, 
+				      &privKey->u.ec.ecParams.DEREncoding,
+				      object,CKA_EC_PARAMS);
+    	if (crv != CKR_OK) break;
+
+	/* Fill out the rest of the ecParams structure
+	 * based on the encoded params
+	 */
+	if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding,
+		    &privKey->u.ec.ecParams) != SECSuccess) {
+	    crv = CKR_DOMAIN_PARAMS_INVALID;
+	    break;
+	}
+	crv = sftk_Attribute2SSecItem(arena,&privKey->u.ec.privateValue,
+							object,CKA_VALUE);
+	if (crv != CKR_OK) break;
+
+	if (sftk_hasAttribute(object, CKA_NETSCAPE_DB)) {
+	    crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue,
+ 				object, CKA_NETSCAPE_DB);
+	    if (crv != CKR_OK) break;
+	    /* privKey was zero'd so public value is already set to NULL, 0
+	     * if we don't set it explicitly */
+	}
+        rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version,
+                          NSSLOWKEY_EC_PRIVATE_KEY_VERSION);
+	if (rv != SECSuccess) crv = CKR_HOST_MEMORY;
+	break;
+#endif /* NSS_ENABLE_ECC */
+
+    default:
+	crv = CKR_KEY_TYPE_INCONSISTENT;
+	break;
+    }
+    if (crv == CKR_OK && itemTemplateCount != 0) {
+	PORT_Assert(itemTemplateCount > 0);
+	PORT_Assert(itemTemplateCount <= SFTK_MAX_ITEM_TEMPLATE);
+	crv = sftk_MultipleAttribute2SecItem(arena, object, itemTemplate, 
+						itemTemplateCount);
+    }
+    *crvp = crv;
+    if (crv != CKR_OK) {
+	PORT_FreeArena(arena,PR_FALSE);
+	return NULL;
+    }
+    return privKey;
+}
+
+
+/* Generate a low private key structure from an object */
+NSSLOWKEYPrivateKey *
+sftk_GetPrivKey(SFTKObject *object,CK_KEY_TYPE key_type, CK_RV *crvp)
+{
+    NSSLOWKEYPrivateKey *priv = NULL;
+
+    if (object->objclass != CKO_PRIVATE_KEY) {
+	*crvp = CKR_KEY_TYPE_INCONSISTENT;
+	return NULL;
+    }
+    if (object->objectInfo) {
+	*crvp = CKR_OK;
+	return (NSSLOWKEYPrivateKey *)object->objectInfo;
+    }
+
+    priv = sftk_mkPrivKey(object, key_type, crvp);
+    object->objectInfo = priv;
+    object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
+    return priv;
+}
+
+/*
+ **************************** Symetric Key utils ************************
+ */
+/*
+ * set the DES key with parity bits correctly
+ */
+void
+sftk_FormatDESKey(unsigned char *key, int length)
+{
+    int i;
+
+    /* format the des key */
+    for (i=0; i < length; i++) {
+	key[i] = parityTable[key[i]>>1];
+    }
+}
+
+/*
+ * check a des key (des2 or des3 subkey) for weak keys.
+ */
+PRBool
+sftk_CheckDESKey(unsigned char *key)
+{
+    int i;
+
+    /* format the des key with parity  */
+    sftk_FormatDESKey(key, 8);
+
+    for (i=0; i < sftk_desWeakTableSize; i++) {
+	if (PORT_Memcmp(key,sftk_desWeakTable[i],8) == 0) {
+	    return PR_TRUE;
+	}
+    }
+    return PR_FALSE;
+}
+
+/*
+ * check if a des or triple des key is weak.
+ */
+PRBool
+sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type)
+{
+
+    switch(key_type) {
+    case CKK_DES:
+	return sftk_CheckDESKey(key);
+    case CKM_DES2_KEY_GEN:
+	if (sftk_CheckDESKey(key)) return PR_TRUE;
+	return sftk_CheckDESKey(&key[8]);
+    case CKM_DES3_KEY_GEN:
+	if (sftk_CheckDESKey(key)) return PR_TRUE;
+	if (sftk_CheckDESKey(&key[8])) return PR_TRUE;
+	return sftk_CheckDESKey(&key[16]);
+    default:
+	break;
+    }
+    return PR_FALSE;
+}
+
+
+/**********************************************************************
+ *
+ *     Start of PKCS 11 functions 
+ *
+ **********************************************************************/
+
+
+/* return the function list */
+CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
+{
+    CHECK_FORK();
+
+    *pFunctionList = (CK_FUNCTION_LIST_PTR) &sftk_funcList;
+    return CKR_OK;
+}
+
+/* return the function list */
+CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
+{
+    CHECK_FORK();
+
+    return NSC_GetFunctionList(pFunctionList);
+}
+
+static PLHashNumber
+sftk_HashNumber(const void *key)
+{
+    return (PLHashNumber) key;
+}
+
+/*
+ * eventually I'd like to expunge all occurances of XXX_SLOT_ID and
+ * just go with the info in the slot. This is one place, however,
+ * where it might be a little difficult.
+ */
+const char *
+sftk_getDefTokName(CK_SLOT_ID slotID)
+{
+    static char buf[33];
+
+    switch (slotID) {
+    case NETSCAPE_SLOT_ID:
+	return "NSS Generic Crypto Services     ";
+    case PRIVATE_KEY_SLOT_ID:
+	return "NSS Certificate DB              ";
+    case FIPS_SLOT_ID:
+        return "NSS FIPS 140-2 Certificate DB   ";
+    default:
+	break;
+    }
+    sprintf(buf,"NSS Application Token %08x  ",(unsigned int) slotID);
+    return buf;
+}
+
+const char *
+sftk_getDefSlotName(CK_SLOT_ID slotID)
+{
+    static char buf[65];
+
+    switch (slotID) {
+    case NETSCAPE_SLOT_ID:
+	return 
+	 "NSS Internal Cryptographic Services                             ";
+    case PRIVATE_KEY_SLOT_ID:
+	return 
+	 "NSS User Private Key and Certificate Services                   ";
+    case FIPS_SLOT_ID:
+        return 
+         "NSS FIPS 140-2 User Private Key Services                        ";
+    default:
+	break;
+    }
+    sprintf(buf,
+     "NSS Application Slot %08x                                   ",
+							(unsigned int) slotID);
+    return buf;
+}
+
+static CK_ULONG nscSlotCount[2] = {0 , 0};
+static CK_SLOT_ID_PTR nscSlotList[2] = {NULL, NULL};
+static CK_ULONG nscSlotListSize[2] = {0, 0};
+static PLHashTable *nscSlotHashTable[2] = {NULL, NULL};
+
+static int
+sftk_GetModuleIndex(CK_SLOT_ID slotID)
+{
+    if ((slotID == FIPS_SLOT_ID) || (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID)) {
+	return NSC_FIPS_MODULE;
+    }
+    return NSC_NON_FIPS_MODULE;
+}
+
+/* look up a slot structure from the ID (used to be a macro when we only
+ * had two slots) */
+/* if all is true, return the slot even if it has been 'unloaded' */
+/* if all is false, only return the slots which are present */
+SFTKSlot *
+sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all)
+{
+    SFTKSlot *slot;
+    int index = sftk_GetModuleIndex(slotID);
+    
+    if (nscSlotHashTable[index] == NULL) return NULL;
+    slot = (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index], 
+							(void *)slotID);
+    /* cleared slots shouldn't 'show up' */
+    if (slot && !all && !slot->present) slot = NULL;
+    return slot;
+}
+
+SFTKSlot *
+sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
+{
+    CK_ULONG slotIDIndex = (handle >> 24) & 0x7f;
+    CK_ULONG moduleIndex = (handle >> 31) & 1;
+
+    if (slotIDIndex >= nscSlotCount[moduleIndex]) {
+	return NULL;
+    }
+
+    return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex], PR_FALSE);
+}
+ 
+static CK_RV
+sftk_RegisterSlot(SFTKSlot *slot, int moduleIndex)
+{
+    PLHashEntry *entry;
+    int index;
+
+    index = sftk_GetModuleIndex(slot->slotID);
+
+    /* make sure the slotID for this module is valid */
+    if (moduleIndex != index) {
+	return CKR_SLOT_ID_INVALID;
+    }
+
+    if (nscSlotList[index] == NULL) {
+	nscSlotListSize[index] = NSC_SLOT_LIST_BLOCK_SIZE;
+	nscSlotList[index] = (CK_SLOT_ID *)
+		PORT_ZAlloc(nscSlotListSize[index]*sizeof(CK_SLOT_ID));
+	if (nscSlotList[index] == NULL) {
+	    return CKR_HOST_MEMORY;
+	}
+    }
+    if (nscSlotCount[index] >= nscSlotListSize[index]) {
+	CK_SLOT_ID* oldNscSlotList = nscSlotList[index];
+	CK_ULONG oldNscSlotListSize = nscSlotListSize[index];
+	nscSlotListSize[index] += NSC_SLOT_LIST_BLOCK_SIZE;
+	nscSlotList[index] = (CK_SLOT_ID *) PORT_Realloc(oldNscSlotList,
+				nscSlotListSize[index]*sizeof(CK_SLOT_ID));
+	if (nscSlotList[index] == NULL) {
+            nscSlotList[index] = oldNscSlotList;
+            nscSlotListSize[index] = oldNscSlotListSize;
+            return CKR_HOST_MEMORY;
+	}
+    }
+
+    if (nscSlotHashTable[index] == NULL) {
+	nscSlotHashTable[index] = PL_NewHashTable(64,sftk_HashNumber,
+				PL_CompareValues, PL_CompareValues, NULL, 0);
+	if (nscSlotHashTable[index] == NULL) {
+	    return CKR_HOST_MEMORY;
+	}
+    }
+
+    entry = PL_HashTableAdd(nscSlotHashTable[index],(void *)slot->slotID,slot);
+    if (entry == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    slot->index = (nscSlotCount[index] & 0x7f) | ((index << 7) & 0x80);
+    nscSlotList[index][nscSlotCount[index]++] = slot->slotID;
+
+    return CKR_OK;
+}
+
+
+/*
+ * ths function has all the common initialization that happens whenever we
+ * create a new slot or repurpose an old slot (only valid for slotID's 4 
+ * and greater).
+ *
+ * things that are not reinitialized are:
+ *   slotID (can't change)
+ *   slotDescription (can't change once defined) 
+ *   the locks and hash tables (difficult to change in running code, and
+ *     unnecessary. hash tables and list are cleared on shutdown, but they
+ *     are cleared in a 'friendly' way).
+ *   session and object ID counters -- so any old sessions and objects in the
+ *     application will get properly notified that the world has changed.
+ * 
+ * things that are reinitialized:
+ *   database (otherwise what would the point be;).
+ *   state variables related to databases.
+ *   session count stat info.
+ *   tokenDescription.
+ *
+ * NOTE: slotID's 4 and greater show up as removable devices.
+ *
+ */
+CK_RV
+SFTK_SlotReInit(SFTKSlot *slot, char *configdir, char *updatedir, 
+	char *updateID, sftk_token_parameters *params, int moduleIndex)
+{
+    PRBool needLogin = !params->noKeyDB;
+    CK_RV crv;
+
+    slot->hasTokens = PR_FALSE;
+    slot->sessionIDConflict = 0;
+    slot->sessionCount = 0;
+    slot->rwSessionCount = 0;
+    slot->needLogin = PR_FALSE;
+    slot->isLoggedIn = PR_FALSE;
+    slot->ssoLoggedIn = PR_FALSE;
+    slot->DB_loaded = PR_FALSE;
+    slot->certDB = NULL;
+    slot->keyDB = NULL;
+    slot->minimumPinLen = 0;
+    slot->readOnly = params->readOnly;
+    sftk_setStringName(params->tokdes ? params->tokdes : 
+	sftk_getDefTokName(slot->slotID), slot->tokDescription, 
+					sizeof(slot->tokDescription),PR_TRUE);
+    sftk_setStringName(params->updtokdes ? params->updtokdes : " ", 
+				slot->updateTokDescription, 
+				sizeof(slot->updateTokDescription),PR_TRUE);
+
+    if ((!params->noCertDB) || (!params->noKeyDB)) {
+	SFTKDBHandle * certHandle = NULL;
+	SFTKDBHandle *keyHandle = NULL;
+	crv = sftk_DBInit(params->configdir ? params->configdir : configdir,
+		params->certPrefix, params->keyPrefix, 
+		params->updatedir ? params->updatedir : updatedir,
+		params->updCertPrefix, params->updKeyPrefix,
+		params->updateID  ? params->updateID : updateID, 
+		params->readOnly, params->noCertDB, params->noKeyDB,
+		params->forceOpen, 
+		moduleIndex == NSC_FIPS_MODULE,
+		&certHandle, &keyHandle);
+	if (crv != CKR_OK) {
+	    goto loser;
+	}
+
+	slot->certDB = certHandle;
+	slot->keyDB = keyHandle;
+    }
+    if (needLogin) {
+	/* if the data base is initialized with a null password,remember that */
+	slot->needLogin = 
+		(PRBool)!sftk_hasNullPassword(slot, slot->keyDB);
+	if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) {
+	    slot->minimumPinLen = params->minPW;
+	}
+	if ((slot->minimumPinLen == 0) && (params->pwRequired)) {
+	    slot->minimumPinLen = 1;
+	}
+	if ((moduleIndex == NSC_FIPS_MODULE) &&
+		(slot->minimumPinLen < FIPS_MIN_PIN)) {
+	    slot->minimumPinLen = FIPS_MIN_PIN;
+	}
+    }
+
+    slot->present = PR_TRUE;
+    return CKR_OK;
+
+loser:
+    SFTK_ShutdownSlot(slot);
+    return crv;
+}
+
+/*
+ * initialize one of the slot structures. figure out which by the ID
+ */
+CK_RV
+SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
+		sftk_token_parameters *params, int moduleIndex)
+{
+    unsigned int i;
+    CK_SLOT_ID slotID = params->slotID;
+    SFTKSlot *slot;
+    CK_RV crv = CKR_HOST_MEMORY;
+
+    /*
+     * first we initialize everything that is 'permanent' with this slot.
+     * that is everything we aren't going to shutdown if we close this slot
+     * and open it up again with different databases */
+
+    slot = PORT_ZNew(SFTKSlot);
+
+    if (slot == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    slot->optimizeSpace = params->optimizeSpace;
+    if (slot->optimizeSpace) {
+	slot->sessObjHashSize = SPACE_SESSION_OBJECT_HASH_SIZE;
+	slot->sessHashSize = SPACE_SESSION_HASH_SIZE;
+	slot->numSessionLocks = 1;
+    } else {
+	slot->sessObjHashSize = TIME_SESSION_OBJECT_HASH_SIZE;
+	slot->sessHashSize = TIME_SESSION_HASH_SIZE;
+	slot->numSessionLocks = slot->sessHashSize/BUCKETS_PER_SESSION_LOCK;
+    }
+    slot->sessionLockMask = slot->numSessionLocks-1;
+
+    slot->slotLock = PZ_NewLock(nssILockSession);
+    if (slot->slotLock == NULL)
+	goto mem_loser;
+    slot->sessionLock = PORT_ZNewArray(PZLock *, slot->numSessionLocks);
+    if (slot->sessionLock == NULL)
+	goto mem_loser;
+    for (i=0; i < slot->numSessionLocks; i++) {
+        slot->sessionLock[i] = PZ_NewLock(nssILockSession);
+        if (slot->sessionLock[i] == NULL) 
+	    goto mem_loser;
+    }
+    slot->objectLock = PZ_NewLock(nssILockObject);
+    if (slot->objectLock == NULL) 
+    	goto mem_loser;
+    slot->pwCheckLock = PR_NewLock();
+    if (slot->pwCheckLock == NULL) 
+    	goto mem_loser;
+    slot->head = PORT_ZNewArray(SFTKSession *, slot->sessHashSize);
+    if (slot->head == NULL) 
+	goto mem_loser;
+    slot->sessObjHashTable = PORT_ZNewArray(SFTKObject *, slot->sessObjHashSize);
+    if (slot->sessObjHashTable == NULL) 
+	goto mem_loser;
+    slot->tokObjHashTable = PL_NewHashTable(64,sftk_HashNumber,PL_CompareValues,
+					SECITEM_HashCompare, NULL, 0);
+    if (slot->tokObjHashTable == NULL) 
+	goto mem_loser;
+
+    slot->sessionIDCount = 0;
+    slot->sessionObjectHandleCount = minSessionObjectHandle;
+    slot->slotID = slotID;
+    sftk_setStringName(params->slotdes ? params->slotdes : 
+	      sftk_getDefSlotName(slotID), slot->slotDescription, 
+					sizeof(slot->slotDescription), PR_TRUE);
+
+    /* call the reinit code to set everything that changes between token
+     * init calls */
+    crv = SFTK_SlotReInit(slot, configdir, updatedir, updateID,
+			   params, moduleIndex);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    crv = sftk_RegisterSlot(slot, moduleIndex);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    return CKR_OK;
+
+mem_loser:
+    crv = CKR_HOST_MEMORY;
+loser:
+   SFTK_DestroySlotData(slot);
+    return crv;
+}
+
+
+CK_RV sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout)
+{
+    SFTKSession *session;
+    unsigned int i;
+    SFTKDBHandle *handle;
+
+    /* first log out the card */
+    /* special case - if we are in a middle of upgrade, we want to close the
+     * sessions to fake a token removal to tell the upper level code we have
+     * switched from one database to another, but we don't want to 
+     * explicity logout in case we can continue the upgrade with the 
+      * existing password if possible.
+     */
+    if (logout) {
+	handle = sftk_getKeyDB(slot);
+	SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
+	slot->isLoggedIn = PR_FALSE;
+	if (handle) {
+	    sftkdb_ClearPassword(handle);
+	}
+	SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
+	if (handle) {
+            sftk_freeDB(handle);
+	}
+    }
+
+    /* now close all the current sessions */
+    /* NOTE: If you try to open new sessions before NSC_CloseAllSessions
+     * completes, some of those new sessions may or may not be closed by
+     * NSC_CloseAllSessions... but any session running when this code starts
+     * will guarrenteed be close, and no session will be partially closed */
+    for (i=0; i < slot->sessHashSize; i++) {
+	PZLock *lock = SFTK_SESSION_LOCK(slot,i);
+	do {
+	    SKIP_AFTER_FORK(PZ_Lock(lock));
+	    session = slot->head[i];
+	    /* hand deque */
+	    /* this duplicates function of NSC_close session functions, but 
+	     * because we know that we are freeing all the sessions, we can
+	     * do more efficient processing */
+	    if (session) {
+		slot->head[i] = session->next;
+		if (session->next) session->next->prev = NULL;
+		session->next = session->prev = NULL;
+		SKIP_AFTER_FORK(PZ_Unlock(lock));
+		SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
+		--slot->sessionCount;
+		SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
+		if (session->info.flags & CKF_RW_SESSION) {
+		    PR_AtomicDecrement(&slot->rwSessionCount);
+		}
+	    } else {
+		SKIP_AFTER_FORK(PZ_Unlock(lock));
+	    }
+	    if (session) sftk_FreeSession(session);
+	} while (session != NULL);
+    }
+    return CKR_OK;
+}
+
+/*
+ * shut down the databases.
+ * we get the slot lock (which also protects slot->certDB and slot->keyDB)
+ * and clear the values so the new users will not find the databases.
+ * once things are clear, we can release our references to the databases.
+ * The databases will close when the last reference is released.
+ *
+ * We use reference counts so that we don't crash if someone shuts down
+ * a token that another thread is actively using.
+ */
+static void
+sftk_DBShutdown(SFTKSlot *slot)
+{
+    SFTKDBHandle *certHandle;
+    SFTKDBHandle      *keyHandle;
+    SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
+    certHandle = slot->certDB;
+    slot->certDB = NULL;
+    keyHandle = slot->keyDB;
+    slot->keyDB = NULL;
+    SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
+    if (certHandle) {
+	sftk_freeDB(certHandle);
+    }
+    if (keyHandle) {
+	sftk_freeDB(keyHandle);
+    }
+}
+
+CK_RV
+SFTK_ShutdownSlot(SFTKSlot *slot)
+{
+    /* make sure no new PK11 calls work except C_GetSlotInfo */
+    slot->present = PR_FALSE;
+
+    /* close all outstanding sessions
+     * the sessHashSize variable guarentees we have all the session
+     * mechanism set up */
+    if (slot->head) {
+	sftk_CloseAllSessions(slot, PR_TRUE);
+     }
+
+    /* clear all objects.. session objects are cleared as a result of
+     * closing all the sessions. We just need to clear the token object
+     * cache. slot->tokObjHashTable guarentees we have the token 
+     * infrastructure set up. */
+    if (slot->tokObjHashTable) {
+	SFTK_ClearTokenKeyHashTable(slot);
+    }
+
+    /* clear the slot description for the next guy */
+    PORT_Memset(slot->tokDescription, 0, sizeof(slot->tokDescription));
+
+    /* now shut down the databases. */
+    sftk_DBShutdown(slot);
+    return CKR_OK;
+}
+
+/*
+ * initialize one of the slot structures. figure out which by the ID
+ */
+CK_RV
+SFTK_DestroySlotData(SFTKSlot *slot)
+{
+    unsigned int i;
+
+    SFTK_ShutdownSlot(slot);
+
+    if (slot->tokObjHashTable) {
+	PL_HashTableDestroy(slot->tokObjHashTable);
+	slot->tokObjHashTable = NULL;
+    }
+
+    if (slot->sessObjHashTable) {
+	PORT_Free(slot->sessObjHashTable);
+	slot->sessObjHashTable = NULL;
+    }
+    slot->sessObjHashSize = 0;
+
+    if (slot->head) {
+	PORT_Free(slot->head);
+	slot->head = NULL;
+    }
+    slot->sessHashSize = 0;
+
+    /* OK everything has been disassembled, now we can finally get rid
+     * of the locks */
+    SKIP_AFTER_FORK(PZ_DestroyLock(slot->slotLock));
+    slot->slotLock = NULL;
+    if (slot->sessionLock) {
+	for (i=0; i < slot->numSessionLocks; i++) {
+	    if (slot->sessionLock[i]) {
+		SKIP_AFTER_FORK(PZ_DestroyLock(slot->sessionLock[i]));
+		slot->sessionLock[i] = NULL;
+	    }
+	}
+	PORT_Free(slot->sessionLock);
+	slot->sessionLock = NULL;
+    }
+    if (slot->objectLock) {
+	SKIP_AFTER_FORK(PZ_DestroyLock(slot->objectLock));
+	slot->objectLock = NULL;
+    }
+    if (slot->pwCheckLock) {
+	SKIP_AFTER_FORK(PR_DestroyLock(slot->pwCheckLock));
+	slot->pwCheckLock = NULL;
+    }
+    PORT_Free(slot);
+    return CKR_OK;
+}
+
+#ifndef NO_FORK_CHECK
+
+static CK_RV ForkCheck(void)
+{
+    CHECK_FORK();
+    return CKR_OK;
+}
+
+#endif
+
+/*
+ * handle the SECMOD.db
+ */
+char **
+NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
+{
+    char *secmod = NULL;
+    char *appName = NULL;
+    char *filename = NULL;
+#ifdef NSS_DISABLE_DBM
+    SDBType dbType = SDB_SQL;
+#else
+    SDBType dbType = SDB_LEGACY;
+#endif
+    PRBool rw;
+    static char *success="Success";
+    char **rvstr = NULL;
+
+#ifndef NO_FORK_CHECK
+    if (CKR_OK != ForkCheck()) return NULL;
+#endif
+
+    secmod = sftk_getSecmodName(parameters, &dbType, &appName,&filename, &rw);
+
+    switch (function) {
+    case SECMOD_MODULE_DB_FUNCTION_FIND:
+	rvstr = sftkdb_ReadSecmodDB(dbType,appName,filename,secmod,(char *)parameters,rw);
+	break;
+    case SECMOD_MODULE_DB_FUNCTION_ADD:
+	rvstr = (sftkdb_AddSecmodDB(dbType,appName,filename,secmod,(char *)args,rw) 
+				== SECSuccess) ? &success: NULL;
+	break;
+    case SECMOD_MODULE_DB_FUNCTION_DEL:
+	rvstr = (sftkdb_DeleteSecmodDB(dbType,appName,filename,secmod,(char *)args,rw)
+				 == SECSuccess) ? &success: NULL;
+	break;
+    case SECMOD_MODULE_DB_FUNCTION_RELEASE:
+	rvstr = (sftkdb_ReleaseSecmodDBData(dbType, appName,filename,secmod,
+			(char **)args,rw) == SECSuccess) ? &success: NULL;
+	break;
+    }
+    if (secmod) PR_smprintf_free(secmod);
+    if (appName) PORT_Free(appName);
+    if (filename) PORT_Free(filename);
+    return rvstr;
+}
+
+static void nscFreeAllSlots(int moduleIndex)
+{
+    /* free all the slots */
+    SFTKSlot *slot = NULL;
+    CK_SLOT_ID slotID;
+    int i;
+
+    if (nscSlotList[moduleIndex]) {
+	CK_ULONG tmpSlotCount = nscSlotCount[moduleIndex];
+	CK_SLOT_ID_PTR tmpSlotList = nscSlotList[moduleIndex];
+	PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
+
+	/* first close all the session */
+	for (i=0; i < (int) tmpSlotCount; i++) {
+	    slotID = tmpSlotList[i];
+	    (void) NSC_CloseAllSessions(slotID);
+	}
+
+	/* now clear out the statics */
+	nscSlotList[moduleIndex] = NULL;
+	nscSlotCount[moduleIndex] = 0;
+	nscSlotHashTable[moduleIndex] = NULL;
+	nscSlotListSize[moduleIndex] = 0;
+
+	for (i=0; i < (int) tmpSlotCount; i++) {
+	    slotID = tmpSlotList[i];
+	    slot = (SFTKSlot *)
+			PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
+	    PORT_Assert(slot);
+	    if (!slot) continue;
+	    SFTK_DestroySlotData(slot);
+	    PL_HashTableRemove(tmpSlotHashTable, (void *)slotID);
+	}
+	PORT_Free(tmpSlotList);
+	PL_HashTableDestroy(tmpSlotHashTable);
+    }
+}
+
+static void
+sftk_closePeer(PRBool isFIPS)
+{
+    CK_SLOT_ID slotID = isFIPS ? PRIVATE_KEY_SLOT_ID: FIPS_SLOT_ID;
+    SFTKSlot *slot;
+    int moduleIndex = isFIPS? NSC_NON_FIPS_MODULE : NSC_FIPS_MODULE;
+    PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
+
+    slot = (SFTKSlot *) PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
+    if (slot == NULL) {
+	return;
+    }
+    sftk_DBShutdown(slot);
+    return;
+}
+
+/* NSC_Initialize initializes the Cryptoki library. */
+CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
+{
+    CK_RV crv = CKR_OK;
+    SECStatus rv;
+    CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *) pReserved;
+    int i;
+    int moduleIndex = isFIPS? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
+
+    if (isFIPS) {
+	loginWaitTime = PR_SecondsToInterval(1);
+    }
+
+    ENABLE_FORK_CHECK();
+
+    rv = SECOID_Init();
+    if (rv != SECSuccess) {
+	crv = CKR_DEVICE_ERROR;
+	return crv;
+    }
+
+    rv = RNG_RNGInit();         /* initialize random number generator */
+    if (rv != SECSuccess) {
+	crv = CKR_DEVICE_ERROR;
+	return crv;
+    }
+    rv = BL_Init();             /* initialize freebl engine */
+    if (rv != SECSuccess) {
+	crv = CKR_DEVICE_ERROR;
+	return crv;
+    }
+
+    /* NOTE:
+     * we should be getting out mutexes from this list, not statically binding
+     * them from NSPR. This should happen before we allow the internal to split
+     * off from the rest on NSS.
+     */
+
+   /* initialize the key and cert db's */
+    if (init_args && (!(init_args->flags & CKF_OS_LOCKING_OK))) {
+        if (init_args->CreateMutex && init_args->DestroyMutex &&
+            init_args->LockMutex && init_args->UnlockMutex) {
+            /* softoken always uses NSPR (ie. OS locking), and doesn't know how
+             * to use the lock functions provided by the application.
+             */
+            crv = CKR_CANT_LOCK;
+            return crv;
+        }
+        if (init_args->CreateMutex || init_args->DestroyMutex ||
+            init_args->LockMutex || init_args->UnlockMutex) {
+            /* only some of the lock functions were provided by the
+             * application. This is invalid per PKCS#11 spec.
+             */
+            crv = CKR_ARGUMENTS_BAD;
+            return crv;
+        }
+    }
+    crv = CKR_ARGUMENTS_BAD;
+    if ((init_args && init_args->LibraryParameters)) {
+	sftk_parameters paramStrings;
+       
+	crv = sftk_parseParameters
+		((char *)init_args->LibraryParameters, &paramStrings, isFIPS);
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+	crv = sftk_configure(paramStrings.man, paramStrings.libdes);
+        if (crv != CKR_OK) {
+	    goto loser;
+	}
+
+	/* if we have a peer already open, have him close his DB's so we
+	 * don't clobber each other. */
+	if ((isFIPS && nsc_init) || (!isFIPS && nsf_init)) {
+	    sftk_closePeer(isFIPS);
+	    if (sftk_audit_enabled) {
+		if (isFIPS && nsc_init) {
+		    sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE, 
+				"enabled FIPS mode");
+		} else {
+		    sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE, 
+				"disabled FIPS mode");
+		}
+	    }
+	}
+
+	for (i=0; i < paramStrings.token_count; i++) {
+	    crv = SFTK_SlotInit(paramStrings.configdir, 
+			paramStrings.updatedir, paramStrings.updateID,
+			&paramStrings.tokens[i], moduleIndex);
+	    if (crv != CKR_OK) {
+                nscFreeAllSlots(moduleIndex);
+                break;
+            }
+	}
+loser:
+	sftk_freeParams(&paramStrings);
+    }
+    if (CKR_OK == crv) {
+        sftk_InitFreeLists();
+    }
+
+#ifndef NO_FORK_CHECK
+    if (CKR_OK == crv) {
+#if defined(CHECK_FORK_MIXED)
+        /* Before Solaris 10, fork handlers are not unregistered at dlclose()
+         * time. So, we only use pthread_atfork on Solaris 10 and later. For
+         * earlier versions, we use PID checks.
+         */
+        char buf[200];
+        int major = 0, minor = 0;
+
+        long rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+        if (rv > 0 && rv < sizeof(buf)) {
+            if (2 == sscanf(buf, "%d.%d", &major, &minor)) {
+                /* Are we on Solaris 10 or greater ? */
+                if (major >5 || (5 == major && minor >= 10)) {
+                    /* we are safe to use pthread_atfork */
+                    usePthread_atfork = PR_TRUE;
+                }
+            }
+        }
+        if (usePthread_atfork) {
+            pthread_atfork(NULL, NULL, ForkedChild);
+        } else {
+            myPid = getpid();
+        }
+
+#elif defined(CHECK_FORK_PTHREAD)
+        pthread_atfork(NULL, NULL, ForkedChild);
+#elif defined(CHECK_FORK_GETPID)
+        myPid = getpid();
+#else
+#error Incorrect fork check method.
+#endif
+    }
+#endif
+    return crv;
+}
+
+CK_RV NSC_Initialize(CK_VOID_PTR pReserved)
+{
+    CK_RV crv;
+    
+    sftk_ForkReset(pReserved, &crv);
+
+    if (nsc_init) {
+	return CKR_CRYPTOKI_ALREADY_INITIALIZED;
+    }
+    crv = nsc_CommonInitialize(pReserved,PR_FALSE);
+    nsc_init = (PRBool) (crv == CKR_OK);
+    return crv;
+}
+
+
+/* NSC_Finalize indicates that an application is done with the 
+ * Cryptoki library.*/
+CK_RV nsc_CommonFinalize (CK_VOID_PTR pReserved, PRBool isFIPS)
+{
+    /* propagate the fork status to freebl and util */
+    BL_SetForkState(parentForkedAfterC_Initialize);
+    UTIL_SetForkState(parentForkedAfterC_Initialize);
+
+    nscFreeAllSlots(isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE);
+
+    /* don't muck with the globals if our peer is still initialized */
+    if (isFIPS && nsc_init) {
+	return CKR_OK;
+    }
+    if (!isFIPS && nsf_init) {
+	return CKR_OK;
+    }
+
+    sftk_CleanupFreeLists();
+    sftkdb_Shutdown();
+
+    /* This function does not discard all our previously aquired entropy. */
+    RNG_RNGShutdown();
+
+    /* tell freeBL to clean up after itself */
+    BL_Cleanup();
+    
+    /* reset fork status in freebl. We must do this before BL_Unload so that
+     * this call doesn't force freebl to be reloaded. */
+    BL_SetForkState(PR_FALSE);
+    
+    /* unload freeBL shared library from memory. This may only decrement the
+     * OS refcount if it's been loaded multiple times, eg. by libssl */
+    BL_Unload();
+
+    /* clean up the default OID table */
+    SECOID_Shutdown();
+
+    /* reset fork status in util */
+    UTIL_SetForkState(PR_FALSE);
+
+    nsc_init = PR_FALSE;
+
+#ifdef CHECK_FORK_MIXED
+    if (!usePthread_atfork) {
+        myPid = 0; /* allow CHECK_FORK in the next softoken initialization to
+                    * succeed */
+    } else {
+        forked = PR_FALSE; /* allow reinitialization */
+    }
+#elif defined(CHECK_FORK_GETPID)
+    myPid = 0; /* allow reinitialization */
+#elif defined (CHECK_FORK_PTHREAD)
+    forked = PR_FALSE; /* allow reinitialization */
+#endif
+    return CKR_OK;
+}
+
+/* Hard-reset the entire softoken PKCS#11 module if the parent process forked
+ * while it was initialized. */
+PRBool sftk_ForkReset(CK_VOID_PTR pReserved, CK_RV* crv)
+{
+#ifndef NO_FORK_CHECK
+    if (PARENT_FORKED()) {
+        parentForkedAfterC_Initialize = PR_TRUE;
+        if (nsc_init) {
+            /* finalize non-FIPS token */
+            *crv = nsc_CommonFinalize(pReserved, PR_FALSE);
+            PORT_Assert(CKR_OK == *crv);
+            nsc_init = (PRBool) !(*crv == CKR_OK);
+        }
+        if (nsf_init) {
+            /* finalize FIPS token */
+            *crv = nsc_CommonFinalize(pReserved, PR_TRUE);
+            PORT_Assert(CKR_OK == *crv);
+            nsf_init = (PRBool) !(*crv == CKR_OK);
+        }
+        parentForkedAfterC_Initialize = PR_FALSE;
+        return PR_TRUE;
+    }
+#endif
+    return PR_FALSE;
+}
+
+/* NSC_Finalize indicates that an application is done with the 
+ * Cryptoki library.*/
+CK_RV NSC_Finalize (CK_VOID_PTR pReserved)
+{
+    CK_RV crv;
+
+    /* reset entire PKCS#11 module upon fork */
+    if (sftk_ForkReset(pReserved, &crv)) {
+        return crv;
+    }
+
+    if (!nsc_init) {
+        return CKR_OK;
+    }
+
+    crv = nsc_CommonFinalize (pReserved, PR_FALSE);
+
+    nsc_init = (PRBool) !(crv == CKR_OK);
+
+    return crv;
+}
+
+extern const char __nss_softokn_rcsid[];
+extern const char __nss_softokn_sccsid[];
+
+/* NSC_GetInfo returns general information about Cryptoki. */
+CK_RV  NSC_GetInfo(CK_INFO_PTR pInfo)
+{
+    volatile char c; /* force a reference that won't get optimized away */
+
+    CHECK_FORK();
+    
+    c = __nss_softokn_rcsid[0] + __nss_softokn_sccsid[0]; 
+    pInfo->cryptokiVersion.major = 2;
+    pInfo->cryptokiVersion.minor = 20;
+    PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
+    pInfo->libraryVersion.major = SOFTOKEN_VMAJOR;
+    pInfo->libraryVersion.minor = SOFTOKEN_VMINOR;
+    PORT_Memcpy(pInfo->libraryDescription,libraryDescription,32);
+    pInfo->flags = 0;
+    return CKR_OK;
+}
+
+
+/* NSC_GetSlotList obtains a list of slots in the system. */
+CK_RV nsc_CommonGetSlotList(CK_BBOOL tokenPresent, 
+	CK_SLOT_ID_PTR	pSlotList, CK_ULONG_PTR pulCount, int moduleIndex)
+{
+    *pulCount = nscSlotCount[moduleIndex];
+    if (pSlotList != NULL) {
+	PORT_Memcpy(pSlotList,nscSlotList[moduleIndex],
+				nscSlotCount[moduleIndex]*sizeof(CK_SLOT_ID));
+    }
+    return CKR_OK;
+}
+
+/* NSC_GetSlotList obtains a list of slots in the system. */
+CK_RV NSC_GetSlotList(CK_BBOOL tokenPresent,
+	 		CK_SLOT_ID_PTR	pSlotList, CK_ULONG_PTR pulCount)
+{
+    CHECK_FORK();
+    return nsc_CommonGetSlotList(tokenPresent, pSlotList, pulCount, 
+							NSC_NON_FIPS_MODULE);
+}
+	
+/* NSC_GetSlotInfo obtains information about a particular slot in the system. */
+CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
+{
+    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_TRUE);
+
+    CHECK_FORK();
+
+    if (slot == NULL) return CKR_SLOT_ID_INVALID;
+
+    pInfo->firmwareVersion.major = 0;
+    pInfo->firmwareVersion.minor = 0;
+
+    PORT_Memcpy(pInfo->manufacturerID,manufacturerID,
+		sizeof(pInfo->manufacturerID));
+    PORT_Memcpy(pInfo->slotDescription,slot->slotDescription,
+		sizeof(pInfo->slotDescription));
+    pInfo->flags = (slot->present) ? CKF_TOKEN_PRESENT : 0;
+
+    /* all user defined slots are defined as removable */
+    if (slotID >= SFTK_MIN_USER_SLOT_ID) {
+	pInfo->flags |= CKF_REMOVABLE_DEVICE;
+    } else {
+	/* In the case where we are doing a merge update, we need
+	 * the DB slot to be removable so the token name can change
+	 * appropriately. */
+	SFTKDBHandle *handle = sftk_getKeyDB(slot);
+	if (handle) { 
+	    if (sftkdb_InUpdateMerge(handle)) {
+		pInfo->flags |= CKF_REMOVABLE_DEVICE;
+	    }
+            sftk_freeDB(handle);
+	}
+    }
+
+    /* ok we really should read it out of the keydb file. */
+    /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */
+    pInfo->hardwareVersion.major = SOFTOKEN_VMAJOR;
+    pInfo->hardwareVersion.minor = SOFTOKEN_VMINOR;
+    return CKR_OK;
+}
+
+/*
+ * check the current state of the 'needLogin' flag in case the database has
+ * been changed underneath us.
+ */
+static PRBool
+sftk_checkNeedLogin(SFTKSlot *slot, SFTKDBHandle *keyHandle)
+{
+    if (sftkdb_PWCached(keyHandle) == SECSuccess) {
+	return slot->needLogin;
+    }
+    slot->needLogin = (PRBool)!sftk_hasNullPassword(slot, keyHandle);
+    return (slot->needLogin);
+}
+
+static PRBool
+sftk_isBlank(const char *s, int len)
+{
+    int i;
+    for (i=0; i < len; i++) {
+	if (s[i] != ' ') {
+	    return PR_FALSE;
+	}
+    }
+    return PR_TRUE;
+}
+
+/* NSC_GetTokenInfo obtains information about a particular token in 
+ * the system. */
+CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo)
+{
+    SFTKSlot *slot;
+    SFTKDBHandle *handle;
+
+    CHECK_FORK();
+    
+    if (!nsc_init && !nsf_init) return CKR_CRYPTOKI_NOT_INITIALIZED;
+    slot = sftk_SlotFromID(slotID, PR_FALSE);
+    if (slot == NULL) return CKR_SLOT_ID_INVALID;
+
+    PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
+    PORT_Memcpy(pInfo->model,"NSS 3           ",16);
+    PORT_Memcpy(pInfo->serialNumber,"0000000000000000",16);
+    PORT_Memcpy(pInfo->utcTime,"0000000000000000",16);
+    pInfo->ulMaxSessionCount = 0; /* arbitrarily large */
+    pInfo->ulSessionCount = slot->sessionCount;
+    pInfo->ulMaxRwSessionCount = 0; /* arbitarily large */
+    pInfo->ulRwSessionCount = slot->rwSessionCount;
+    pInfo->firmwareVersion.major = 0;
+    pInfo->firmwareVersion.minor = 0;
+    PORT_Memcpy(pInfo->label,slot->tokDescription,sizeof(pInfo->label));
+    handle = sftk_getKeyDB(slot);
+    pInfo->flags = CKF_RNG | CKF_DUAL_CRYPTO_OPERATIONS;
+    if (handle == NULL) {
+	pInfo->flags |= CKF_WRITE_PROTECTED;
+	pInfo->ulMaxPinLen = 0;
+	pInfo->ulMinPinLen = 0;
+	pInfo->ulTotalPublicMemory = 0;
+	pInfo->ulFreePublicMemory = 0;
+	pInfo->ulTotalPrivateMemory = 0;
+	pInfo->ulFreePrivateMemory = 0;
+	pInfo->hardwareVersion.major = 4;
+	pInfo->hardwareVersion.minor = 0;
+    } else {
+	/*
+	 * we have three possible states which we may be in:
+	 *   (1) No DB password has been initialized. This also means we
+	 *   have no keys in the key db.
+	 *   (2) Password initialized to NULL. This means we have keys, but
+	 *   the user has chosen not use a password.
+	 *   (3) Finally we have an initialized password whicn is not NULL, and
+	 *   we will need to prompt for it.
+	 */
+	if (sftkdb_HasPasswordSet(handle) == SECFailure) {
+	    pInfo->flags |= CKF_LOGIN_REQUIRED;
+	} else if (!sftk_checkNeedLogin(slot,handle)) {
+	    pInfo->flags |= CKF_USER_PIN_INITIALIZED;
+	} else {
+	    pInfo->flags |= CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED;
+	/* 
+         * if we are doing a merge style update, and we need to get the password
+	 * of our source database (the database we are updating from), make sure we
+         * return a token name that will match the database we are prompting for.
+	 */
+	if (sftkdb_NeedUpdateDBPassword(handle)) {
+	    /* if we have an update tok description, use it. otherwise
+             * use the updateID for this database */
+	    if (!sftk_isBlank(slot->updateTokDescription,
+						sizeof(pInfo->label))) {
+		PORT_Memcpy(pInfo->label,slot->updateTokDescription,
+				sizeof(pInfo->label));
+	    } else {
+		/* build from updateID */
+		const char *updateID = sftkdb_GetUpdateID(handle);
+		if (updateID) {
+		    sftk_setStringName(updateID, (char *)pInfo->label,
+				 sizeof(pInfo->label), PR_FALSE);
+		}
+	    }
+	}
+	}
+	pInfo->ulMaxPinLen = SFTK_MAX_PIN;
+	pInfo->ulMinPinLen = (CK_ULONG)slot->minimumPinLen;
+	pInfo->ulTotalPublicMemory = 1;
+	pInfo->ulFreePublicMemory = 1;
+	pInfo->ulTotalPrivateMemory = 1;
+	pInfo->ulFreePrivateMemory = 1;
+#ifdef SHDB_FIXME
+	pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION;
+	pInfo->hardwareVersion.minor = handle->version;
+#else
+	pInfo->hardwareVersion.major = 0;
+	pInfo->hardwareVersion.minor = 0;
+#endif
+        sftk_freeDB(handle);
+    }
+    /*
+     * CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED  how CKF_TOKEN_INITIALIZED
+     *                                              should be set
+     *         0                   0                           1
+     *         1                   0                           0
+     *         0                   1                           1
+     *         1                   1                           1
+     */
+    if (!(pInfo->flags & CKF_LOGIN_REQUIRED) ||
+	(pInfo->flags & CKF_USER_PIN_INITIALIZED)) {
+	pInfo->flags |= CKF_TOKEN_INITIALIZED;
+    }
+    return CKR_OK;
+}
+
+/* NSC_GetMechanismList obtains a list of mechanism types 
+ * supported by a token. */
+CK_RV NSC_GetMechanismList(CK_SLOT_ID slotID,
+	CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
+{
+    CK_ULONG i;
+
+    CHECK_FORK();
+
+    switch (slotID) {
+    /* default: */
+    case NETSCAPE_SLOT_ID:
+	*pulCount = mechanismCount;
+	if (pMechanismList != NULL) {
+	    for (i=0; i < mechanismCount; i++) {
+		pMechanismList[i] = mechanisms[i].type;
+	    }
+	}
+	break;
+     default:
+	*pulCount = 0;
+	for (i=0; i < mechanismCount; i++) {
+	    if (mechanisms[i].privkey) {
+		(*pulCount)++;
+		if (pMechanismList != NULL) {
+		    *pMechanismList++ = mechanisms[i].type;
+		}
+	    }
+	}
+	break;
+    }
+    return CKR_OK;
+}
+
+
+/* NSC_GetMechanismInfo obtains information about a particular mechanism 
+ * possibly supported by a token. */
+CK_RV NSC_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
+    					CK_MECHANISM_INFO_PTR pInfo)
+{
+    PRBool isPrivateKey;
+    CK_ULONG i;
+
+    CHECK_FORK();
+    
+    switch (slotID) {
+    case NETSCAPE_SLOT_ID:
+	isPrivateKey = PR_FALSE;
+	break;
+    default:
+	isPrivateKey = PR_TRUE;
+	break;
+    }
+    for (i=0; i < mechanismCount; i++) {
+        if (type == mechanisms[i].type) {
+	    if (isPrivateKey && !mechanisms[i].privkey) {
+    		return CKR_MECHANISM_INVALID;
+	    }
+	    PORT_Memcpy(pInfo,&mechanisms[i].info, sizeof(CK_MECHANISM_INFO));
+	    return CKR_OK;
+	}
+    }
+    return CKR_MECHANISM_INVALID;
+}
+
+CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
+{
+    CK_ULONG i;
+    CK_FLAGS flags;
+
+    switch (op) {
+    case CKA_ENCRYPT:         flags = CKF_ENCRYPT;         break;
+    case CKA_DECRYPT:         flags = CKF_DECRYPT;         break;
+    case CKA_WRAP:            flags = CKF_WRAP;            break;
+    case CKA_UNWRAP:          flags = CKF_UNWRAP;          break;
+    case CKA_SIGN:            flags = CKF_SIGN;            break;
+    case CKA_SIGN_RECOVER:    flags = CKF_SIGN_RECOVER;    break;
+    case CKA_VERIFY:          flags = CKF_VERIFY;          break;
+    case CKA_VERIFY_RECOVER:  flags = CKF_VERIFY_RECOVER;  break;
+    case CKA_DERIVE:          flags = CKF_DERIVE;          break;
+    default:
+    	return CKR_ARGUMENTS_BAD;
+    }
+    for (i=0; i < mechanismCount; i++) {
+        if (type == mechanisms[i].type) {
+	    return (flags & mechanisms[i].info.flags) ? CKR_OK 
+	                                              : CKR_MECHANISM_INVALID;
+	}
+    }
+    return CKR_MECHANISM_INVALID;
+}
+
+/* NSC_InitToken initializes a token. */
+CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin,
+ 				CK_ULONG ulPinLen,CK_CHAR_PTR pLabel) {
+    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
+    SFTKDBHandle *handle;
+    SFTKDBHandle *certHandle;
+    SECStatus rv;
+    unsigned int i;
+    SFTKObject *object;
+
+    CHECK_FORK();
+
+    if (slot == NULL) return CKR_SLOT_ID_INVALID;
+
+    /* don't initialize the database if we aren't talking to a token
+     * that uses the key database.
+     */
+    if (slotID == NETSCAPE_SLOT_ID) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    /* first, delete all our loaded key and cert objects from our 
+     * internal list. */
+    PZ_Lock(slot->objectLock);
+    for (i=0; i < slot->sessObjHashSize; i++) {
+	do {
+	    object = slot->sessObjHashTable[i];
+	    /* hand deque */
+	    /* this duplicates function of NSC_close session functions, but 
+	     * because we know that we are freeing all the sessions, we can
+	     * do more efficient processing */
+	    if (object) {
+		slot->sessObjHashTable[i] = object->next;
+
+		if (object->next) object->next->prev = NULL;
+		object->next = object->prev = NULL;
+	    }
+	    if (object) sftk_FreeObject(object);
+	} while (object != NULL);
+    }
+    slot->DB_loaded = PR_FALSE;
+    PZ_Unlock(slot->objectLock);
+
+    /* then clear out the key database */
+    handle = sftk_getKeyDB(slot);
+    if (handle == NULL) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    rv = sftkdb_ResetKeyDB(handle);
+    sftk_freeDB(handle);
+    if (rv != SECSuccess) {
+	return CKR_DEVICE_ERROR;
+    }
+
+    /* finally  mark all the user certs as non-user certs */
+    certHandle = sftk_getCertDB(slot);
+    if (certHandle == NULL) return CKR_OK;
+
+    sftk_freeDB(certHandle);
+
+    return CKR_OK; /*is this the right function for not implemented*/
+}
+
+
+/* NSC_InitPIN initializes the normal user's PIN. */
+CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession,
+    					CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
+{
+    SFTKSession *sp = NULL;
+    SFTKSlot *slot;
+    SFTKDBHandle *handle = NULL;
+    char newPinStr[SFTK_MAX_PIN+1];
+    SECStatus rv;
+    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
+    PRBool tokenRemoved = PR_FALSE;
+
+    CHECK_FORK();
+    
+    sp = sftk_SessionFromHandle(hSession);
+    if (sp == NULL) {
+	goto loser;
+    }
+
+    slot = sftk_SlotFromSession(sp);
+    if (slot == NULL) {
+	goto loser;
+    }
+
+    handle = sftk_getKeyDB(slot);
+    if (handle == NULL) {
+	crv = CKR_PIN_LEN_RANGE;
+	goto loser;
+    }
+
+
+    if (sp->info.state != CKS_RW_SO_FUNCTIONS) {
+	crv = CKR_USER_NOT_LOGGED_IN;
+	goto loser;
+    }
+
+    sftk_FreeSession(sp);
+    sp = NULL;
+
+    /* make sure the pins aren't too long */
+    if (ulPinLen > SFTK_MAX_PIN) {
+	crv = CKR_PIN_LEN_RANGE;
+	goto loser;
+    }
+    if (ulPinLen < (CK_ULONG)slot->minimumPinLen) {
+	crv = CKR_PIN_LEN_RANGE;
+	goto loser;
+    }
+
+    if (sftkdb_HasPasswordSet(handle) != SECFailure) {
+	crv = CKR_DEVICE_ERROR;
+	goto loser;
+    }
+
+    /* convert to null terminated string */
+    PORT_Memcpy(newPinStr, pPin, ulPinLen);
+    newPinStr[ulPinLen] = 0; 
+
+    /* build the hashed pins which we pass around */
+
+    /* change the data base */
+    rv = sftkdb_ChangePassword(handle, NULL, newPinStr, &tokenRemoved);
+    if (tokenRemoved) {
+	sftk_CloseAllSessions(slot, PR_FALSE);
+    }
+    sftk_freeDB(handle);
+    handle = NULL;
+
+    /* Now update our local copy of the pin */
+    if (rv == SECSuccess) {
+	if (ulPinLen == 0) slot->needLogin = PR_FALSE;
+	return CKR_OK;
+    }
+    crv = CKR_PIN_INCORRECT;
+
+loser:
+    if (sp) {
+	sftk_FreeSession(sp);
+    }
+    if (handle) {
+	sftk_freeDB(handle);
+    }
+    return crv;
+}
+
+
+/* NSC_SetPIN modifies the PIN of user that is currently logged in. */
+/* NOTE: This is only valid for the PRIVATE_KEY_SLOT */
+CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
+    CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
+{
+    SFTKSession *sp = NULL;
+    SFTKSlot *slot;
+    SFTKDBHandle *handle = NULL;
+    char newPinStr[SFTK_MAX_PIN+1],oldPinStr[SFTK_MAX_PIN+1];
+    SECStatus rv;
+    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
+    PRBool tokenRemoved = PR_FALSE;
+
+    CHECK_FORK();
+    
+    sp = sftk_SessionFromHandle(hSession);
+    if (sp == NULL) {
+	goto loser;
+    }
+
+    slot = sftk_SlotFromSession(sp);
+    if (!slot) {
+	goto loser;
+    }
+
+    handle = sftk_getKeyDB(slot);
+    if (handle == NULL) {
+	sftk_FreeSession(sp);
+	return CKR_PIN_LEN_RANGE; /* XXX FIXME wrong return value */
+    }
+
+    if (slot->needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) {
+	crv = CKR_USER_NOT_LOGGED_IN;
+	goto loser;
+    }
+
+    sftk_FreeSession(sp);
+    sp = NULL;
+
+    /* make sure the pins aren't too long */
+    if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) {
+	crv = CKR_PIN_LEN_RANGE;
+	goto loser;
+    }
+    if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
+	crv = CKR_PIN_LEN_RANGE;
+	goto loser;
+    }
+
+
+    /* convert to null terminated string */
+    PORT_Memcpy(newPinStr,pNewPin,ulNewLen);
+    newPinStr[ulNewLen] = 0; 
+    PORT_Memcpy(oldPinStr,pOldPin,ulOldLen);
+    oldPinStr[ulOldLen] = 0; 
+
+    /* change the data base password */
+    PR_Lock(slot->pwCheckLock);
+    rv = sftkdb_ChangePassword(handle, oldPinStr, newPinStr, &tokenRemoved);
+    if (tokenRemoved) {
+	sftk_CloseAllSessions(slot, PR_FALSE);
+    }
+    sftk_freeDB(handle);
+    handle = NULL;
+    if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
+	PR_Sleep(loginWaitTime);
+    }
+    PR_Unlock(slot->pwCheckLock);
+
+    /* Now update our local copy of the pin */
+    if (rv == SECSuccess) {
+	slot->needLogin = (PRBool)(ulNewLen != 0);
+	return CKR_OK;
+    }
+    crv = CKR_PIN_INCORRECT;
+loser:
+    if (sp) {
+	sftk_FreeSession(sp);
+    }
+    if (handle) {
+	sftk_freeDB(handle);
+    }
+    return crv;
+}
+
+/* NSC_OpenSession opens a session between an application and a token. */
+CK_RV NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
+   CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)
+{
+    SFTKSlot *slot;
+    CK_SESSION_HANDLE sessionID;
+    SFTKSession *session;
+    SFTKSession *sameID;
+
+    CHECK_FORK();
+    
+    slot = sftk_SlotFromID(slotID, PR_FALSE);
+    if (slot == NULL) return CKR_SLOT_ID_INVALID;
+
+    /* new session (we only have serial sessions) */
+    session = sftk_NewSession(slotID, Notify, pApplication,
+						 flags | CKF_SERIAL_SESSION);
+    if (session == NULL) return CKR_HOST_MEMORY;
+
+    if (slot->readOnly && (flags & CKF_RW_SESSION)) {
+	/* NETSCAPE_SLOT_ID is Read ONLY */
+	session->info.flags &= ~CKF_RW_SESSION;
+    }
+    PZ_Lock(slot->slotLock);
+    ++slot->sessionCount;
+    PZ_Unlock(slot->slotLock);
+    if (session->info.flags & CKF_RW_SESSION) {
+	PR_AtomicIncrement(&slot->rwSessionCount);
+    }
+
+    do {
+        PZLock *lock;
+        do {
+            sessionID = (PR_AtomicIncrement(&slot->sessionIDCount) & 0xffffff)
+                        | (slot->index << 24);
+        } while (sessionID == CK_INVALID_HANDLE);
+        lock = SFTK_SESSION_LOCK(slot,sessionID);
+        PZ_Lock(lock);
+        sftkqueue_find(sameID, sessionID, slot->head, slot->sessHashSize);
+        if (sameID == NULL) {
+            session->handle = sessionID;
+            sftk_update_state(slot, session);
+            sftkqueue_add(session, sessionID, slot->head,slot->sessHashSize);
+        } else {
+            slot->sessionIDConflict++;  /* for debugging */
+        }
+        PZ_Unlock(lock);
+    } while (sameID != NULL);
+
+    *phSession = sessionID;
+    return CKR_OK;
+}
+
+
+/* NSC_CloseSession closes a session between an application and a token. */
+CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession)
+{
+    SFTKSlot *slot;
+    SFTKSession *session;
+    PRBool sessionFound;
+    PZLock *lock;
+
+    CHECK_FORK();
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    slot = sftk_SlotFromSession(session);
+    sessionFound = PR_FALSE;
+
+    /* lock */
+    lock = SFTK_SESSION_LOCK(slot,hSession);
+    PZ_Lock(lock);
+    if (sftkqueue_is_queued(session,hSession,slot->head,slot->sessHashSize)) {
+	sessionFound = PR_TRUE;
+	sftkqueue_delete(session,hSession,slot->head,slot->sessHashSize);
+	session->refCount--; /* can't go to zero while we hold the reference */
+	PORT_Assert(session->refCount > 0);
+    }
+    PZ_Unlock(lock);
+
+    if (sessionFound) {
+	SFTKDBHandle *handle;
+	handle = sftk_getKeyDB(slot);
+	PZ_Lock(slot->slotLock);
+	if (--slot->sessionCount == 0) {
+	    slot->isLoggedIn = PR_FALSE;
+	    if (handle) {
+		sftkdb_ClearPassword(handle);
+	    }
+	}
+	PZ_Unlock(slot->slotLock);
+	if (handle) {
+	    sftk_freeDB(handle);
+	}
+	if (session->info.flags & CKF_RW_SESSION) {
+	    PR_AtomicDecrement(&slot->rwSessionCount);
+	}
+    }
+
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+
+/* NSC_CloseAllSessions closes all sessions with a token. */
+CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID)
+{
+    SFTKSlot *slot;
+
+#ifndef NO_CHECK_FORK
+    /* skip fork check if we are being called from C_Initialize or C_Finalize */
+    if (!parentForkedAfterC_Initialize) {
+        CHECK_FORK();
+    }
+#endif
+
+    slot = sftk_SlotFromID(slotID, PR_FALSE);
+    if (slot == NULL) return CKR_SLOT_ID_INVALID;
+
+    return sftk_CloseAllSessions(slot, PR_TRUE);
+}
+
+
+
+/* NSC_GetSessionInfo obtains information about the session. */
+CK_RV NSC_GetSessionInfo(CK_SESSION_HANDLE hSession,
+    						CK_SESSION_INFO_PTR pInfo)
+{
+    SFTKSession *session;
+
+    CHECK_FORK();
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+    PORT_Memcpy(pInfo,&session->info,sizeof(CK_SESSION_INFO));
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+/* NSC_Login logs a user into a token. */
+CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
+				    CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
+{
+    SFTKSlot *slot;
+    SFTKSession *session;
+    SFTKDBHandle *handle;
+    CK_FLAGS sessionFlags;
+    SECStatus rv;
+    CK_RV crv;
+    char pinStr[SFTK_MAX_PIN+1];
+    PRBool tokenRemoved = PR_FALSE;
+
+    CHECK_FORK();
+
+    /* get the slot */
+    slot = sftk_SlotFromSessionHandle(hSession);
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    /* make sure the session is valid */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    sessionFlags = session->info.flags;
+    sftk_FreeSession(session);
+    session = NULL;
+
+    /* can't log into the Netscape Slot */
+    if (slot->slotID == NETSCAPE_SLOT_ID) {
+	 return CKR_USER_TYPE_INVALID;
+    }
+
+    if (slot->isLoggedIn) return CKR_USER_ALREADY_LOGGED_IN;
+    slot->ssoLoggedIn = PR_FALSE;
+
+    if (ulPinLen > SFTK_MAX_PIN) return CKR_PIN_LEN_RANGE;
+
+    /* convert to null terminated string */
+    PORT_Memcpy(pinStr,pPin,ulPinLen);
+    pinStr[ulPinLen] = 0; 
+
+    handle = sftk_getKeyDB(slot);
+    if (handle == NULL) {
+	 return CKR_USER_TYPE_INVALID;
+    }
+
+    /*
+     * Deal with bootstrap. We allow the SSO to login in with a NULL
+     * password if and only if we haven't initialized the KEY DB yet.
+     * We only allow this on a RW session.
+     */
+    rv = sftkdb_HasPasswordSet(handle);
+    if (rv == SECFailure) {
+	/* allow SSO's to log in only if there is not password on the
+	 * key database */
+	if (((userType == CKU_SO) && (sessionFlags & CKF_RW_SESSION))
+	    /* fips always needs to authenticate, even if there isn't a db */
+					|| (slot->slotID == FIPS_SLOT_ID)) {
+	    /* should this be a fixed password? */
+	    if (ulPinLen == 0) {
+		sftkdb_ClearPassword(handle);
+    		PZ_Lock(slot->slotLock);
+		slot->isLoggedIn = PR_TRUE;
+		slot->ssoLoggedIn = (PRBool)(userType == CKU_SO);
+		PZ_Unlock(slot->slotLock);
+		sftk_update_all_states(slot);
+		crv = CKR_OK;
+		goto done;
+	    }
+	    crv = CKR_PIN_INCORRECT;
+	    goto done;
+	} 
+	crv = CKR_USER_TYPE_INVALID;
+	goto done;
+    } 
+
+    /* don't allow the SSO to log in if the user is already initialized */
+    if (userType != CKU_USER) { 
+	crv = CKR_USER_TYPE_INVALID; 
+	goto done;
+    }
+
+
+    /* build the hashed pins which we pass around */
+    PR_Lock(slot->pwCheckLock);
+    rv = sftkdb_CheckPassword(handle,pinStr, &tokenRemoved);
+    if (tokenRemoved) {
+	sftk_CloseAllSessions(slot, PR_FALSE);
+    }
+    if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
+	PR_Sleep(loginWaitTime);
+    }
+    PR_Unlock(slot->pwCheckLock);
+    if (rv == SECSuccess) {
+	PZ_Lock(slot->slotLock);
+	/* make sure the login state matches the underlying
+	 * database state */
+	slot->isLoggedIn = sftkdb_PWCached(handle) == SECSuccess ?
+		PR_TRUE : PR_FALSE;
+	PZ_Unlock(slot->slotLock);
+
+ 	sftk_freeDB(handle);
+	handle = NULL;
+
+	/* update all sessions */
+	sftk_update_all_states(slot);
+	return CKR_OK;
+    }
+
+    crv = CKR_PIN_INCORRECT;
+done:
+    if (handle) {
+	sftk_freeDB(handle);
+    }
+    return crv;
+}
+
+/* NSC_Logout logs a user out from a token. */
+CK_RV NSC_Logout(CK_SESSION_HANDLE hSession)
+{
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    SFTKSession *session;
+    SFTKDBHandle *handle;
+
+    CHECK_FORK();
+
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    sftk_FreeSession(session);
+    session = NULL;
+
+    if (!slot->isLoggedIn) return CKR_USER_NOT_LOGGED_IN;
+
+    handle = sftk_getKeyDB(slot);
+    PZ_Lock(slot->slotLock);
+    slot->isLoggedIn = PR_FALSE;
+    slot->ssoLoggedIn = PR_FALSE;
+    if (handle) {
+	sftkdb_ClearPassword(handle);
+    }
+    PZ_Unlock(slot->slotLock);
+    if (handle) {
+	sftk_freeDB(handle);
+    }
+
+    sftk_update_all_states(slot);
+    return CKR_OK;
+}
+
+/*
+ * Create a new slot on the fly. The slot that is passed in is the
+ * slot the request came from. Only the crypto or FIPS slots can
+ * be used. The resulting slot will live in the same module as
+ * the slot the request was passed to. object is the creation object
+ * that specifies the module spec for the new slot.
+ */
+static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class,
+                                SFTKObject *object)
+{
+    CK_SLOT_ID idMin, idMax;
+    PRBool isFIPS = PR_FALSE;
+    unsigned long moduleIndex;
+    SFTKAttribute *attribute;
+    sftk_parameters paramStrings;
+    char *paramString;
+    CK_SLOT_ID slotID = 0;
+    SFTKSlot *newSlot = NULL;
+    CK_RV crv = CKR_OK;
+
+    /* only the crypto or FIPS slots can create new slot objects */
+    if (slot->slotID == NETSCAPE_SLOT_ID) {
+	idMin = SFTK_MIN_USER_SLOT_ID;
+	idMax = SFTK_MAX_USER_SLOT_ID;
+	moduleIndex = NSC_NON_FIPS_MODULE;
+	isFIPS = PR_FALSE;
+    } else if (slot->slotID == FIPS_SLOT_ID) {
+	idMin = SFTK_MIN_FIPS_USER_SLOT_ID;
+	idMax = SFTK_MAX_FIPS_USER_SLOT_ID;
+	moduleIndex = NSC_FIPS_MODULE;
+	isFIPS = PR_TRUE;
+    } else {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    attribute = sftk_FindAttribute(object,CKA_NETSCAPE_MODULE_SPEC);
+    if (attribute == NULL) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    paramString = (char *)attribute->attrib.pValue;
+    crv = sftk_parseParameters(paramString, &paramStrings, isFIPS);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    /* enforce only one at a time */
+    if (paramStrings.token_count != 1) {
+	crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	goto loser;
+    }
+
+    slotID = paramStrings.tokens[0].slotID;
+
+    /* stay within the valid ID space */
+    if ((slotID < idMin) || (slotID > idMax)) {
+	crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	goto loser;
+    }
+
+    /* unload any existing slot at this id */
+    newSlot = sftk_SlotFromID(slotID, PR_TRUE);
+    if (newSlot && newSlot->present) {
+	crv = SFTK_ShutdownSlot(newSlot);
+	if (crv != CKR_OK) {
+	    goto loser;
+	}
+    }
+
+    /* if we were just planning on deleting the slot, then do so now */
+    if (class == CKO_NETSCAPE_DELSLOT) {
+	/* sort of a unconventional use of this error code, be we are
+         * overusing CKR_ATTRIBUTE_VALUE_INVALID, and it does apply */
+	crv = newSlot ? CKR_OK : CKR_SLOT_ID_INVALID;
+	goto loser; /* really exit */
+    }
+
+    if (newSlot) {
+	crv = SFTK_SlotReInit(newSlot, paramStrings.configdir, 
+			paramStrings.updatedir, paramStrings.updateID,
+			&paramStrings.tokens[0], moduleIndex);
+    } else {
+	crv = SFTK_SlotInit(paramStrings.configdir, 
+			paramStrings.updatedir, paramStrings.updateID,
+			&paramStrings.tokens[0], moduleIndex);
+    }
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+loser:
+    sftk_freeParams(&paramStrings);
+    sftk_FreeAttribute(attribute);
+
+    return crv;
+}
+
+
+/* NSC_CreateObject creates a new object. */
+CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession,
+		CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 
+					CK_OBJECT_HANDLE_PTR phObject)
+{
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    SFTKSession *session;
+    SFTKObject *object;
+    /* make sure class isn't randomly CKO_NETSCAPE_NEWSLOT or
+     * CKO_NETSCPE_DELSLOT. */
+    CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED;
+    CK_RV crv;
+    int i;
+
+    CHECK_FORK();
+
+    *phObject = CK_INVALID_HANDLE;
+
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * now lets create an object to hang the attributes off of
+     */
+    object = sftk_NewObject(slot); /* fill in the handle later */
+    if (object == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    /*
+     * load the template values into the object
+     */
+    for (i=0; i < (int) ulCount; i++) {
+	crv = sftk_AddAttributeType(object,sftk_attr_expand(&pTemplate[i]));
+	if (crv != CKR_OK) {
+	    sftk_FreeObject(object);
+	    return crv;
+	}
+	if ((pTemplate[i].type == CKA_CLASS) && pTemplate[i].pValue) {
+	    class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
+	}
+    }
+
+    /* get the session */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+	sftk_FreeObject(object);
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    /*
+     * handle pseudo objects (CKO_NEWSLOT)
+     */
+    if ((class == CKO_NETSCAPE_NEWSLOT)  || (class == CKO_NETSCAPE_DELSLOT)) {
+	crv = sftk_CreateNewSlot(slot, class, object);
+	goto done;
+    } 
+
+    /*
+     * handle the base object stuff
+     */
+    crv = sftk_handleObject(object,session);
+    *phObject = object->handle;
+done:
+    sftk_FreeSession(session);
+    sftk_FreeObject(object);
+
+    return crv;
+}
+
+
+
+/* NSC_CopyObject copies an object, creating a new object for the copy. */
+CK_RV NSC_CopyObject(CK_SESSION_HANDLE hSession,
+       CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+					CK_OBJECT_HANDLE_PTR phNewObject) 
+{
+    SFTKObject *destObject,*srcObject;
+    SFTKSession *session;
+    CK_RV crv = CKR_OK;
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    int i;
+
+    CHECK_FORK();
+
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    /* Get srcObject so we can find the class */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+    srcObject = sftk_ObjectFromHandle(hObject,session);
+    if (srcObject == NULL) {
+	sftk_FreeSession(session);
+	return CKR_OBJECT_HANDLE_INVALID;
+    }
+    /*
+     * create an object to hang the attributes off of
+     */
+    destObject = sftk_NewObject(slot); /* fill in the handle later */
+    if (destObject == NULL) {
+	sftk_FreeSession(session);
+        sftk_FreeObject(srcObject);
+	return CKR_HOST_MEMORY;
+    }
+
+    /*
+     * load the template values into the object
+     */
+    for (i=0; i < (int) ulCount; i++) {
+	if (sftk_modifyType(pTemplate[i].type,srcObject->objclass) == SFTK_NEVER) {
+	    crv = CKR_ATTRIBUTE_READ_ONLY;
+	    break;
+	}
+	crv = sftk_AddAttributeType(destObject,sftk_attr_expand(&pTemplate[i]));
+	if (crv != CKR_OK) { break; }
+    }
+    if (crv != CKR_OK) {
+	sftk_FreeSession(session);
+        sftk_FreeObject(srcObject);
+	sftk_FreeObject(destObject);
+	return crv;
+    }
+
+    /* sensitive can only be changed to CK_TRUE */
+    if (sftk_hasAttribute(destObject,CKA_SENSITIVE)) {
+	if (!sftk_isTrue(destObject,CKA_SENSITIVE)) {
+	    sftk_FreeSession(session);
+            sftk_FreeObject(srcObject);
+	    sftk_FreeObject(destObject);
+	    return CKR_ATTRIBUTE_READ_ONLY;
+	}
+    }
+
+    /*
+     * now copy the old attributes from the new attributes
+     */
+    /* don't create a token object if we aren't in a rw session */
+    /* we need to hold the lock to copy a consistant version of
+     * the object. */
+    crv = sftk_CopyObject(destObject,srcObject);
+
+    destObject->objclass = srcObject->objclass;
+    sftk_FreeObject(srcObject);
+    if (crv != CKR_OK) {
+	sftk_FreeObject(destObject);
+	sftk_FreeSession(session);
+        return crv;
+    }
+
+    crv = sftk_handleObject(destObject,session);
+    *phNewObject = destObject->handle;
+    sftk_FreeSession(session);
+    sftk_FreeObject(destObject);
+    
+    return crv;
+}
+
+
+/* NSC_GetObjectSize gets the size of an object in bytes. */
+CK_RV NSC_GetObjectSize(CK_SESSION_HANDLE hSession,
+    			CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize)
+{
+    CHECK_FORK();
+
+    *pulSize = 0;
+    return CKR_OK;
+}
+
+
+/* NSC_GetAttributeValue obtains the value of one or more object attributes. */
+CK_RV NSC_GetAttributeValue(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
+{
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    SFTKSession *session;
+    SFTKObject *object;
+    SFTKAttribute *attribute;
+    PRBool sensitive;
+    CK_RV crv;
+    int i;
+
+    CHECK_FORK();
+
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * make sure we're allowed
+     */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    /* short circuit everything for token objects */
+    if (sftk_isToken(hObject)) {
+	SFTKSlot *slot = sftk_SlotFromSession(session);
+	SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, hObject);
+	SFTKDBHandle *keydb = NULL;
+
+	if (dbHandle == NULL) {
+	    sftk_FreeSession(session);
+	    return CKR_OBJECT_HANDLE_INVALID;
+	}
+
+	crv = sftkdb_GetAttributeValue(dbHandle, hObject, pTemplate, ulCount);
+
+	/* make sure we don't export any sensitive information */
+	keydb = sftk_getKeyDB(slot);
+	if (dbHandle == keydb) {
+	    for (i=0; i < (int) ulCount; i++) {
+		if (sftk_isSensitive(pTemplate[i].type,CKO_PRIVATE_KEY)) {
+		    crv = CKR_ATTRIBUTE_SENSITIVE;
+		    if (pTemplate[i].pValue && (pTemplate[i].ulValueLen!= -1)){
+			PORT_Memset(pTemplate[i].pValue, 0, 
+					pTemplate[i].ulValueLen);
+		    }
+		    pTemplate[i].ulValueLen = -1;
+		}
+	    }
+	}
+
+	sftk_FreeSession(session);
+	sftk_freeDB(dbHandle);
+	if (keydb) {
+	    sftk_freeDB(keydb);
+	}
+	return crv;
+    }
+
+    /* handle the session object */
+    object = sftk_ObjectFromHandle(hObject,session);
+    sftk_FreeSession(session);
+    if (object == NULL) {
+	return CKR_OBJECT_HANDLE_INVALID;
+    }
+
+    /* don't read a private object if we aren't logged in */
+    if ((!slot->isLoggedIn) && (slot->needLogin) &&
+				(sftk_isTrue(object,CKA_PRIVATE))) {
+	sftk_FreeObject(object);
+	return CKR_USER_NOT_LOGGED_IN;
+    }
+
+    crv = CKR_OK;
+    sensitive = sftk_isTrue(object,CKA_SENSITIVE);
+    for (i=0; i < (int) ulCount; i++) {
+	/* Make sure that this attribute is retrievable */
+	if (sensitive && sftk_isSensitive(pTemplate[i].type,object->objclass)) {
+	    crv = CKR_ATTRIBUTE_SENSITIVE;
+	    pTemplate[i].ulValueLen = -1;
+	    continue;
+	}
+	attribute = sftk_FindAttribute(object,pTemplate[i].type);
+	if (attribute == NULL) {
+	    crv = CKR_ATTRIBUTE_TYPE_INVALID;
+	    pTemplate[i].ulValueLen = -1;
+	    continue;
+	}
+	if (pTemplate[i].pValue != NULL) {
+	    PORT_Memcpy(pTemplate[i].pValue,attribute->attrib.pValue,
+						attribute->attrib.ulValueLen);
+	}
+	pTemplate[i].ulValueLen = attribute->attrib.ulValueLen;
+	sftk_FreeAttribute(attribute);
+    }
+
+    sftk_FreeObject(object);
+    return crv;
+}
+
+/* NSC_SetAttributeValue modifies the value of one or more object attributes */
+CK_RV NSC_SetAttributeValue (CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
+{
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    SFTKSession *session;
+    SFTKAttribute *attribute;
+    SFTKObject *object;
+    PRBool isToken;
+    CK_RV crv = CKR_OK;
+    CK_BBOOL legal;
+    int i;
+
+    CHECK_FORK();
+
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * make sure we're allowed
+     */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    object = sftk_ObjectFromHandle(hObject,session);
+    if (object == NULL) {
+        sftk_FreeSession(session);
+	return CKR_OBJECT_HANDLE_INVALID;
+    }
+
+    /* don't modify a private object if we aren't logged in */
+    if ((!slot->isLoggedIn) && (slot->needLogin) &&
+				(sftk_isTrue(object,CKA_PRIVATE))) {
+	sftk_FreeSession(session);
+	sftk_FreeObject(object);
+	return CKR_USER_NOT_LOGGED_IN;
+    }
+
+    /* don't modify a token object if we aren't in a rw session */
+    isToken = sftk_isTrue(object,CKA_TOKEN);
+    if (((session->info.flags & CKF_RW_SESSION) == 0) && isToken) {
+	sftk_FreeSession(session);
+	sftk_FreeObject(object);
+	return CKR_SESSION_READ_ONLY;
+    }
+    sftk_FreeSession(session);
+
+    /* only change modifiable objects */
+    if (!sftk_isTrue(object,CKA_MODIFIABLE)) {
+	sftk_FreeObject(object);
+	return CKR_ATTRIBUTE_READ_ONLY;
+    }
+
+    for (i=0; i < (int) ulCount; i++) {
+	/* Make sure that this attribute is changeable */
+	switch (sftk_modifyType(pTemplate[i].type,object->objclass)) {
+	case SFTK_NEVER:
+	case SFTK_ONCOPY:
+        default:
+	    crv = CKR_ATTRIBUTE_READ_ONLY;
+	    break;
+
+        case SFTK_SENSITIVE:
+	    legal = (pTemplate[i].type == CKA_EXTRACTABLE) ? CK_FALSE : CK_TRUE;
+	    if ((*(CK_BBOOL *)pTemplate[i].pValue) != legal) {
+	        crv = CKR_ATTRIBUTE_READ_ONLY;
+	    }
+	    break;
+        case SFTK_ALWAYS:
+	    break;
+	}
+	if (crv != CKR_OK) break;
+
+	/* find the old attribute */
+	attribute = sftk_FindAttribute(object,pTemplate[i].type);
+	if (attribute == NULL) {
+	    crv =CKR_ATTRIBUTE_TYPE_INVALID;
+	    break;
+	}
+    	sftk_FreeAttribute(attribute);
+	crv = sftk_forceAttribute(object,sftk_attr_expand(&pTemplate[i]));
+	if (crv != CKR_OK) break;
+
+    }
+
+    sftk_FreeObject(object);
+    return crv;
+}
+
+static CK_RV
+sftk_expandSearchList(SFTKSearchResults *search, int count)
+{
+    search->array_size += count;
+    search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,
+			sizeof(CK_OBJECT_HANDLE)*search->array_size);
+    return search->handles ? CKR_OK : CKR_HOST_MEMORY;
+}
+
+
+
+static CK_RV
+sftk_searchDatabase(SFTKDBHandle *handle, SFTKSearchResults *search,
+                        const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
+{
+    CK_RV crv;
+    int objectListSize = search->array_size-search->size;
+    CK_OBJECT_HANDLE *array = &search->handles[search->size];
+    SDBFind *find;
+    CK_ULONG count;
+
+    crv = sftkdb_FindObjectsInit(handle, pTemplate, ulCount, &find);
+    if (crv != CKR_OK)
+	return crv;
+    do {
+	crv = sftkdb_FindObjects(handle, find, array, objectListSize, &count);
+	if ((crv != CKR_OK) || (count == 0))
+	    break;
+	search->size += count;
+	objectListSize -= count;
+	if (objectListSize > 0)
+	    break;
+	crv = sftk_expandSearchList(search,NSC_SEARCH_BLOCK_SIZE);
+	objectListSize = NSC_SEARCH_BLOCK_SIZE;
+	array = &search->handles[search->size];
+    } while (crv == CKR_OK);
+    sftkdb_FindObjectsFinal(handle, find);
+
+    return crv;
+}
+
+/* softoken used to search the SMimeEntries automatically instead of
+ * doing this in pk11wrap. This code should really be up in
+ * pk11wrap so that it will work with other tokens other than softoken.
+ */
+CK_RV
+sftk_emailhack(SFTKSlot *slot, SFTKDBHandle *handle, 
+    SFTKSearchResults *search, CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
+{
+    PRBool isCert = PR_FALSE;
+    int emailIndex = -1;
+    int i;
+    SFTKSearchResults smime_search;
+    CK_ATTRIBUTE smime_template[2];
+    CK_OBJECT_CLASS smime_class = CKO_NETSCAPE_SMIME;
+    SFTKAttribute *attribute = NULL;
+    SFTKObject *object = NULL;
+    CK_RV crv = CKR_OK;
+
+
+    smime_search.handles = NULL; /* paranoia, some one is bound to add a goto
+				  * loser before this gets initialized */
+
+    /* see if we are looking for email certs */
+    for (i=0; i < ulCount; i++) {
+	if (pTemplate[i].type == CKA_CLASS) {
+	   if ((pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS) ||
+	       (*(CK_OBJECT_CLASS *)pTemplate[i].pValue) != CKO_CERTIFICATE)) {
+		/* not a cert, skip out */
+		break;
+	   }
+	   isCert = PR_TRUE;
+	} else if (pTemplate[i].type == CKA_NETSCAPE_EMAIL) {
+	   emailIndex = i;
+	 
+	}
+	if (isCert && (emailIndex != -1)) break;
+    }
+
+    if (!isCert || (emailIndex == -1)) {
+	return CKR_OK;
+    }
+
+    /* we are doing a cert and email search, find the SMimeEntry */
+    smime_template[0].type = CKA_CLASS;
+    smime_template[0].pValue = &smime_class;
+    smime_template[0].ulValueLen = sizeof(smime_class);
+    smime_template[1] = pTemplate[emailIndex];
+
+    smime_search.handles = (CK_OBJECT_HANDLE *)
+		PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
+    if (smime_search.handles == NULL) {
+	crv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    smime_search.index = 0;
+    smime_search.size = 0;
+    smime_search.array_size = NSC_SEARCH_BLOCK_SIZE;
+	
+    crv = sftk_searchDatabase(handle, &smime_search, smime_template, 2);
+    if (crv != CKR_OK || smime_search.size == 0) {
+	goto loser;
+    }
+
+    /* get the SMime subject */
+    object = sftk_NewTokenObject(slot, NULL, smime_search.handles[0]);
+    if (object == NULL) {
+	crv = CKR_HOST_MEMORY; /* is there any other reason for this failure? */
+	goto loser;
+    }
+    attribute = sftk_FindAttribute(object,CKA_SUBJECT);
+    if (attribute == NULL) {
+	crv = CKR_ATTRIBUTE_TYPE_INVALID;
+	goto loser;
+    }
+
+    /* now find the certs with that subject */
+    pTemplate[emailIndex] = attribute->attrib;
+    /* now add the appropriate certs to the search list */
+    crv = sftk_searchDatabase(handle, search, pTemplate, ulCount);
+    pTemplate[emailIndex] = smime_template[1]; /* restore the user's template*/
+
+loser:
+    if (attribute) {
+	sftk_FreeAttribute(attribute);
+    }
+    if (object) {
+	sftk_FreeObject(object);
+    }
+    if (smime_search.handles) {
+	PORT_Free(smime_search.handles);
+    }
+
+    return crv;
+}
+	
+
+static CK_RV
+sftk_searchTokenList(SFTKSlot *slot, SFTKSearchResults *search,
+                        CK_ATTRIBUTE *pTemplate, CK_LONG ulCount,
+                        PRBool *tokenOnly, PRBool isLoggedIn)
+{
+    CK_RV crv;
+    CK_RV crv2;
+    SFTKDBHandle *certHandle = sftk_getCertDB(slot);
+
+    crv = sftk_searchDatabase(certHandle, search, pTemplate, ulCount);
+    crv2 = sftk_emailhack(slot, certHandle, search, pTemplate, ulCount);
+    if (crv == CKR_OK) crv2 = crv;
+    sftk_freeDB(certHandle);
+
+    if (crv == CKR_OK && isLoggedIn) {
+	SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
+    	crv = sftk_searchDatabase(keyHandle, search, pTemplate, ulCount);
+    	sftk_freeDB(keyHandle);
+    }
+    return crv;
+}
+
+/* NSC_FindObjectsInit initializes a search for token and session objects 
+ * that match a template. */
+CK_RV NSC_FindObjectsInit(CK_SESSION_HANDLE hSession,
+    			CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
+{
+    SFTKSearchResults *search = NULL, *freeSearch = NULL;
+    SFTKSession *session = NULL;
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    PRBool tokenOnly = PR_FALSE;
+    CK_RV crv = CKR_OK;
+    PRBool isLoggedIn;
+
+    CHECK_FORK();
+    
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+	crv = CKR_SESSION_HANDLE_INVALID;
+	goto loser;
+    }
+   
+    search = (SFTKSearchResults *)PORT_Alloc(sizeof(SFTKSearchResults));
+    if (search == NULL) {
+	crv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    search->handles = (CK_OBJECT_HANDLE *)
+		PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
+    if (search->handles == NULL) {
+	crv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    search->index = 0;
+    search->size = 0;
+    search->array_size = NSC_SEARCH_BLOCK_SIZE;
+    isLoggedIn = (PRBool)((!slot->needLogin) || slot->isLoggedIn);
+
+    crv = sftk_searchTokenList(slot, search, pTemplate, ulCount, &tokenOnly,
+								isLoggedIn);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    
+    /* build list of found objects in the session */
+    if (!tokenOnly) {
+	crv = sftk_searchObjectList(search, slot->sessObjHashTable, 
+				slot->sessObjHashSize, slot->objectLock, 
+					pTemplate, ulCount, isLoggedIn);
+    }
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    if ((freeSearch = session->search) != NULL) {
+	session->search = NULL;
+	sftk_FreeSearch(freeSearch);
+    }
+    session->search = search;
+    sftk_FreeSession(session);
+    return CKR_OK;
+
+loser:
+    if (search) {
+	sftk_FreeSearch(search);
+    }
+    if (session) {
+	sftk_FreeSession(session);
+    }
+    return crv;
+}
+
+
+/* NSC_FindObjects continues a search for token and session objects 
+ * that match a template, obtaining additional object handles. */
+CK_RV NSC_FindObjects(CK_SESSION_HANDLE hSession,
+    CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,
+    					CK_ULONG_PTR pulObjectCount)
+{
+    SFTKSession *session;
+    SFTKSearchResults *search;
+    int	transfer;
+    int left;
+
+    CHECK_FORK();
+
+    *pulObjectCount = 0;
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    if (session->search == NULL) {
+	sftk_FreeSession(session);
+	return CKR_OK;
+    }
+    search = session->search;
+    left = session->search->size - session->search->index;
+    transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
+    if (transfer > 0) {
+	PORT_Memcpy(phObject,&search->handles[search->index],
+                                        transfer*sizeof(CK_OBJECT_HANDLE));
+    } else {
+       *phObject = CK_INVALID_HANDLE;
+    }
+
+    search->index += transfer;
+    if (search->index == search->size) {
+	session->search = NULL;
+	sftk_FreeSearch(search);
+    }
+    *pulObjectCount = transfer;
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+/* NSC_FindObjectsFinal finishes a search for token and session objects. */
+CK_RV NSC_FindObjectsFinal(CK_SESSION_HANDLE hSession)
+{
+    SFTKSession *session;
+    SFTKSearchResults *search;
+
+    CHECK_FORK();
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    search = session->search;
+    session->search = NULL;
+    sftk_FreeSession(session);
+    if (search != NULL) {
+	sftk_FreeSearch(search);
+    }
+    return CKR_OK;
+}
+
+
+
+CK_RV NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
+							 CK_VOID_PTR pReserved)
+{
+    CHECK_FORK();
+
+    return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
diff --git a/mozilla/security/nss/lib/softoken/pkcs11c.c b/mozilla/security/nss/lib/softoken/pkcs11c.c
new file mode 100644
index 0000000..d45c6ff
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/pkcs11c.c
@@ -0,0 +1,6276 @@
+/* ***** 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):
+ *   Dr Stephen Henson <stephen.henson@gemplus.com>
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * This file implements PKCS 11 on top of our existing security modules
+ *
+ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
+ *   This implementation has two slots:
+ *	slot 1 is our generic crypto support. It does not require login.
+ *   It supports Public Key ops, and all they bulk ciphers and hashes. 
+ *   It can also support Private Key ops for imported Private keys. It does 
+ *   not have any token storage.
+ *	slot 2 is our private key support. It requires a login before use. It
+ *   can store Private Keys and Certs as token objects. Currently only private
+ *   keys and their associated Certificates are saved on the token.
+ *
+ *   In this implementation, session objects are only visible to the session
+ *   that created or generated them.
+ */
+#include "seccomon.h"
+#include "secitem.h"
+#include "secport.h"
+#include "blapi.h"
+#include "pkcs11.h"
+#include "pkcs11i.h"
+#include "lowkeyi.h"
+#include "sechash.h"
+#include "secder.h"
+#include "secdig.h"
+#include "lowpbe.h"	/* We do PBE below */
+#include "pkcs11t.h"
+#include "secoid.h"
+#include "alghmac.h"
+#include "softoken.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+#include "prprf.h"
+
+#define __PASTE(x,y)    x##y
+
+/*
+ * we renamed all our internal functions, get the correct
+ * definitions for them...
+ */ 
+#undef CK_PKCS11_FUNCTION_INFO
+#undef CK_NEED_ARG_LIST
+
+#define CK_EXTERN extern
+#define CK_PKCS11_FUNCTION_INFO(func) \
+		CK_RV __PASTE(NS,func)
+#define CK_NEED_ARG_LIST	1
+ 
+#include "pkcs11f.h"
+
+typedef struct {
+    uint8 client_version[2];
+    uint8 random[46];
+} SSL3RSAPreMasterSecret;
+
+static void sftk_Null(void *data, PRBool freeit)
+{
+    return;
+} 
+
+#ifdef NSS_ENABLE_ECC
+#ifdef EC_DEBUG
+#define SEC_PRINT(str1, str2, num, sitem) \
+    printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
+            str1, str2, num, sitem->len); \
+    for (i = 0; i < sitem->len; i++) { \
+	    printf("%02x:", sitem->data[i]); \
+    } \
+    printf("\n") 
+#else
+#define SEC_PRINT(a, b, c, d) 
+#endif
+#endif /* NSS_ENABLE_ECC */
+
+/*
+ * free routines.... Free local type  allocated data, and convert
+ * other free routines to the destroy signature.
+ */
+static void
+sftk_FreePrivKey(NSSLOWKEYPrivateKey *key, PRBool freeit)
+{
+    nsslowkey_DestroyPrivateKey(key);
+}
+
+static void
+sftk_Space(void *data, PRBool freeit)
+{
+    PORT_Free(data);
+} 
+
+/*
+ * map all the SEC_ERROR_xxx error codes that may be returned by freebl
+ * functions to CKR_xxx.  return CKR_DEVICE_ERROR by default for backward
+ * compatibility.
+ */
+static CK_RV
+sftk_MapCryptError(int error)
+{
+    switch (error) {
+	case SEC_ERROR_INVALID_ARGS:
+	case SEC_ERROR_BAD_DATA:  /* MP_RANGE gets mapped to this */
+	    return CKR_ARGUMENTS_BAD;
+	case SEC_ERROR_INPUT_LEN:
+	    return CKR_DATA_LEN_RANGE;
+	case SEC_ERROR_OUTPUT_LEN:
+	    return CKR_BUFFER_TOO_SMALL;
+	case SEC_ERROR_LIBRARY_FAILURE:
+	    return CKR_GENERAL_ERROR;
+	case SEC_ERROR_NO_MEMORY:
+	    return CKR_HOST_MEMORY;
+	case SEC_ERROR_BAD_SIGNATURE:
+	    return CKR_SIGNATURE_INVALID;
+	case SEC_ERROR_INVALID_KEY:
+	    return CKR_KEY_SIZE_RANGE;
+	case SEC_ERROR_BAD_KEY:  /* an EC public key that fails validation */
+	    return CKR_KEY_SIZE_RANGE;  /* the closest error code */
+	case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
+	    return CKR_TEMPLATE_INCONSISTENT;
+	/* EC functions set this error if NSS_ENABLE_ECC is not defined */
+	case SEC_ERROR_UNSUPPORTED_KEYALG:
+	    return CKR_MECHANISM_INVALID;
+	case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
+	    return CKR_DOMAIN_PARAMS_INVALID;
+	/* key pair generation failed after max number of attempts */
+	case SEC_ERROR_NEED_RANDOM:
+	    return CKR_FUNCTION_FAILED;
+    }
+    return CKR_DEVICE_ERROR;
+}
+
+/* used by Decrypt and UnwrapKey (indirectly) */
+static CK_RV
+sftk_MapDecryptError(int error)
+{
+    switch (error) {
+	case SEC_ERROR_BAD_DATA:
+	    return CKR_ENCRYPTED_DATA_INVALID;
+	default:
+	    return sftk_MapCryptError(error);
+    }
+}
+
+/*
+ * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for
+ * backward compatibilty.
+ */
+static CK_RV
+sftk_MapVerifyError(int error)
+{
+    CK_RV crv = sftk_MapCryptError(error);
+    if (crv == CKR_DEVICE_ERROR)
+	crv = CKR_SIGNATURE_INVALID;
+    return crv;
+}
+
+
+/*
+ * turn a CDMF key into a des key. CDMF is an old IBM scheme to export DES by
+ * Deprecating a full des key to 40 bit key strenth.
+ */
+static CK_RV
+sftk_cdmf2des(unsigned char *cdmfkey, unsigned char *deskey)
+{
+    unsigned char key1[8] = { 0xc4, 0x08, 0xb0, 0x54, 0x0b, 0xa1, 0xe0, 0xae };
+    unsigned char key2[8] = { 0xef, 0x2c, 0x04, 0x1c, 0xe6, 0x38, 0x2f, 0xe6 };
+    unsigned char enc_src[8];
+    unsigned char enc_dest[8];
+    unsigned int leng,i;
+    DESContext *descx;
+    SECStatus rv;
+    
+    
+    /* zero the parity bits */
+    for (i=0; i < 8; i++) {
+	enc_src[i] = cdmfkey[i] & 0xfe;
+    }
+
+    /* encrypt with key 1 */
+    descx = DES_CreateContext(key1, NULL, NSS_DES, PR_TRUE);
+    if (descx == NULL) return CKR_HOST_MEMORY;
+    rv = DES_Encrypt(descx, enc_dest, &leng, 8, enc_src, 8);
+    DES_DestroyContext(descx,PR_TRUE);
+    if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
+
+    /* xor source with des, zero the parity bits and deprecate the key*/
+    for (i=0; i < 8; i++) {
+	if (i & 1) {
+	    enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0xfe;
+	} else {
+	    enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0x0e;
+	}
+    }
+
+    /* encrypt with key 2 */
+    descx = DES_CreateContext(key2, NULL, NSS_DES, PR_TRUE);
+    if (descx == NULL) return CKR_HOST_MEMORY;
+    rv = DES_Encrypt(descx, deskey, &leng, 8, enc_src, 8);
+    DES_DestroyContext(descx,PR_TRUE);
+    if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
+
+    /* set the corret parity on our new des key */	
+    sftk_FormatDESKey(deskey, 8);
+    return CKR_OK;
+}
+
+
+/* NSC_DestroyObject destroys an object. */
+CK_RV
+NSC_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
+{
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    SFTKSession *session;
+    SFTKObject *object;
+    SFTKFreeStatus status;
+
+    CHECK_FORK();
+
+    if (slot == NULL) {
+	return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * This whole block just makes sure we really can destroy the
+     * requested object.
+     */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    object = sftk_ObjectFromHandle(hObject,session);
+    if (object == NULL) {
+	sftk_FreeSession(session);
+	return CKR_OBJECT_HANDLE_INVALID;
+    }
+
+    /* don't destroy a private object if we aren't logged in */
+    if ((!slot->isLoggedIn) && (slot->needLogin) &&
+				(sftk_isTrue(object,CKA_PRIVATE))) {
+	sftk_FreeSession(session);
+	sftk_FreeObject(object);
+	return CKR_USER_NOT_LOGGED_IN;
+    }
+
+    /* don't destroy a token object if we aren't in a rw session */
+
+    if (((session->info.flags & CKF_RW_SESSION) == 0) &&
+				(sftk_isTrue(object,CKA_TOKEN))) {
+	sftk_FreeSession(session);
+	sftk_FreeObject(object);
+	return CKR_SESSION_READ_ONLY;
+    }
+
+    sftk_DeleteObject(session,object);
+
+    sftk_FreeSession(session);
+
+    /*
+     * get some indication if the object is destroyed. Note: this is not
+     * 100%. Someone may have an object reference outstanding (though that
+     * should not be the case by here. Also note that the object is "half"
+     * destroyed. Our internal representation is destroyed, but it may still
+     * be in the data base.
+     */
+    status = sftk_FreeObject(object);
+
+    return (status != SFTK_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR;
+}
+
+
+/*
+ ************** Crypto Functions:     Utilities ************************
+ */
+
+
+/* 
+ * return a context based on the SFTKContext type.
+ */
+SFTKSessionContext *
+sftk_ReturnContextByType(SFTKSession *session, SFTKContextType type)
+{
+    switch (type) {
+	case SFTK_ENCRYPT:
+	case SFTK_DECRYPT:
+	    return session->enc_context;
+	case SFTK_HASH:
+	    return session->hash_context;
+	case SFTK_SIGN:
+	case SFTK_SIGN_RECOVER:
+	case SFTK_VERIFY:
+	case SFTK_VERIFY_RECOVER:
+	    return session->hash_context;
+    }
+    return NULL;
+}
+
+/* 
+ * change a context based on the SFTKContext type.
+ */
+void
+sftk_SetContextByType(SFTKSession *session, SFTKContextType type, 
+						SFTKSessionContext *context)
+{
+    switch (type) {
+	case SFTK_ENCRYPT:
+	case SFTK_DECRYPT:
+	    session->enc_context = context;
+	    break;
+	case SFTK_HASH:
+	    session->hash_context = context;
+	    break;
+	case SFTK_SIGN:
+	case SFTK_SIGN_RECOVER:
+	case SFTK_VERIFY:
+	case SFTK_VERIFY_RECOVER:
+	    session->hash_context = context;
+	    break;
+    }
+    return;
+}
+
+/*
+ * code to grab the context. Needed by every C_XXXUpdate, C_XXXFinal,
+ * and C_XXX function. The function takes a session handle, the context type,
+ * and wether or not the session needs to be multipart. It returns the context,
+ * and optionally returns the session pointer (if sessionPtr != NULL) if session
+ * pointer is returned, the caller is responsible for freeing it.
+ */
+static CK_RV
+sftk_GetContext(CK_SESSION_HANDLE handle,SFTKSessionContext **contextPtr,
+	SFTKContextType type, PRBool needMulti, SFTKSession **sessionPtr)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+
+    session = sftk_SessionFromHandle(handle);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    context = sftk_ReturnContextByType(session,type);
+    /* make sure the context is valid */
+    if((context==NULL)||(context->type!=type)||(needMulti&&!(context->multi))){
+        sftk_FreeSession(session);
+	return CKR_OPERATION_NOT_INITIALIZED;
+    }
+    *contextPtr = context;
+    if (sessionPtr != NULL) {
+	*sessionPtr = session;
+    } else {
+	sftk_FreeSession(session);
+    }
+    return CKR_OK;
+}
+
+/*
+ ************** Crypto Functions:     Encrypt ************************
+ */
+
+/*
+ * All the NSC_InitXXX functions have a set of common checks and processing they
+ * all need to do at the beginning. This is done here.
+ */
+static CK_RV
+sftk_InitGeneric(SFTKSession *session,SFTKSessionContext **contextPtr,
+		 SFTKContextType ctype,SFTKObject **keyPtr,
+		 CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
+		 CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
+{
+    SFTKObject *key = NULL;
+    SFTKAttribute *att;
+    SFTKSessionContext *context;
+
+    /* We can only init if there is not current context active */
+    if (sftk_ReturnContextByType(session,ctype) != NULL) {
+	return CKR_OPERATION_ACTIVE;
+    }
+
+    /* find the key */
+    if (keyPtr) {
+        key = sftk_ObjectFromHandle(hKey,session);
+        if (key == NULL) {
+	    return CKR_KEY_HANDLE_INVALID;
+    	}
+
+	/* make sure it's a valid  key for this operation */
+	if (((key->objclass != CKO_SECRET_KEY) && (key->objclass != pubKeyType))
+					|| !sftk_isTrue(key,operation)) {
+	    sftk_FreeObject(key);
+	    return CKR_KEY_TYPE_INCONSISTENT;
+	}
+	/* get the key type */
+	att = sftk_FindAttribute(key,CKA_KEY_TYPE);
+	if (att == NULL) {
+	    sftk_FreeObject(key);
+	    return CKR_KEY_TYPE_INCONSISTENT;
+	}
+	PORT_Assert(att->attrib.ulValueLen == sizeof(CK_KEY_TYPE));
+	if (att->attrib.ulValueLen != sizeof(CK_KEY_TYPE)) {
+	    sftk_FreeAttribute(att);
+	    sftk_FreeObject(key);
+	    return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+	PORT_Memcpy(keyTypePtr, att->attrib.pValue, sizeof(CK_KEY_TYPE));
+	sftk_FreeAttribute(att);
+	*keyPtr = key;
+    }
+
+    /* allocate the context structure */
+    context = (SFTKSessionContext *)PORT_Alloc(sizeof(SFTKSessionContext));
+    if (context == NULL) {
+	if (key) sftk_FreeObject(key);
+	return CKR_HOST_MEMORY;
+    }
+    context->type = ctype;
+    context->multi = PR_TRUE;
+    context->cipherInfo = NULL;
+    context->hashInfo = NULL;
+    context->doPad = PR_FALSE;
+    context->padDataLength = 0;
+    context->key = key;
+    context->blockSize = 0;
+
+    *contextPtr = context;
+    return CKR_OK;
+}
+
+/* NSC_CryptInit initializes an encryption/Decryption operation. */
+/* This function is used by NSC_EncryptInit, NSC_DecryptInit, 
+ *                          NSC_WrapKey, NSC_UnwrapKey, 
+ *                          NSC_SignInit, NSC_VerifyInit (via sftk_InitCBCMac),
+ * The only difference in their uses is the value of etype.
+ */
+static CK_RV
+sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+		 CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE etype,
+		 SFTKContextType contextType, PRBool isEncrypt)
+{
+    SFTKSession *session;
+    SFTKObject *key;
+    SFTKSessionContext *context;
+    SFTKAttribute *att;
+    CK_RC2_CBC_PARAMS *rc2_param;
+#if NSS_SOFTOKEN_DOES_RC5
+    CK_RC5_CBC_PARAMS *rc5_param;
+    SECItem rc5Key;
+#endif
+    CK_KEY_TYPE key_type;
+    CK_RV crv = CKR_OK;
+    unsigned effectiveKeyLength;
+    unsigned char newdeskey[24];
+    PRBool useNewKey=PR_FALSE;
+    int t;
+
+    crv = sftk_MechAllowsOperation(pMechanism->mechanism, etype);
+    if (crv != CKR_OK) 
+    	return crv;
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+    crv = sftk_InitGeneric(session,&context,contextType,&key,hKey,&key_type,
+    			isEncrypt ?CKO_PUBLIC_KEY:CKO_PRIVATE_KEY, etype);
+						
+    if (crv != CKR_OK) {
+	sftk_FreeSession(session);
+	return crv;
+    }
+
+    context->doPad = PR_FALSE;
+    switch(pMechanism->mechanism) {
+    case CKM_RSA_PKCS:
+    case CKM_RSA_X_509:
+	if (key_type != CKK_RSA) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	context->multi = PR_FALSE;
+	if (isEncrypt) {
+	    NSSLOWKEYPublicKey *pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
+	    if (pubKey == NULL) {
+		break;
+	    }
+	    context->maxLen = nsslowkey_PublicModulusLen(pubKey);
+	    context->cipherInfo =  (void *)pubKey;
+	    context->update = (SFTKCipher) 
+		(pMechanism->mechanism == CKM_RSA_X_509
+					? RSA_EncryptRaw : RSA_EncryptBlock);
+	} else {
+	    NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
+	    if (privKey == NULL) {
+		break;
+	    }
+	    context->maxLen = nsslowkey_PrivateModulusLen(privKey);
+	    context->cipherInfo =  (void *)privKey;
+	    context->update = (SFTKCipher) 
+		(pMechanism->mechanism == CKM_RSA_X_509
+					? RSA_DecryptRaw : RSA_DecryptBlock);
+	}
+	context->destroy = sftk_Null;
+	break;
+    case CKM_RC2_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_RC2_ECB:
+    case CKM_RC2_CBC:
+	context->blockSize = 8;
+	if (key_type != CKK_RC2) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	rc2_param = (CK_RC2_CBC_PARAMS *)pMechanism->pParameter;
+	effectiveKeyLength = (rc2_param->ulEffectiveBits+7)/8;
+	context->cipherInfo = 
+	    RC2_CreateContext((unsigned char*)att->attrib.pValue,
+			      att->attrib.ulValueLen, rc2_param->iv,
+			      pMechanism->mechanism == CKM_RC2_ECB ? NSS_RC2 :
+			      NSS_RC2_CBC,effectiveKeyLength);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->update = (SFTKCipher) (isEncrypt ? RC2_Encrypt : RC2_Decrypt);
+	context->destroy = (SFTKDestroy) RC2_DestroyContext;
+	break;
+#if NSS_SOFTOKEN_DOES_RC5
+    case CKM_RC5_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_RC5_ECB:
+    case CKM_RC5_CBC:
+	if (key_type != CKK_RC5) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
+	context->blockSize = rc5_param->ulWordsize*2;
+	rc5Key.data = (unsigned char*)att->attrib.pValue;
+	rc5Key.len = att->attrib.ulValueLen;
+	context->cipherInfo = RC5_CreateContext(&rc5Key,rc5_param->ulRounds,
+	   rc5_param->ulWordsize,rc5_param->pIv,
+		 pMechanism->mechanism == CKM_RC5_ECB ? NSS_RC5 : NSS_RC5_CBC);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->update = (SFTKCipher) (isEncrypt ? RC5_Encrypt : RC5_Decrypt);
+	context->destroy = (SFTKDestroy) RC5_DestroyContext;
+	break;
+#endif
+    case CKM_RC4:
+	if (key_type != CKK_RC4) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	context->cipherInfo = 
+	    RC4_CreateContext((unsigned char*)att->attrib.pValue,
+			      att->attrib.ulValueLen);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;  /* WRONG !!! */
+	    break;
+	}
+	context->update = (SFTKCipher) (isEncrypt ? RC4_Encrypt : RC4_Decrypt);
+	context->destroy = (SFTKDestroy) RC4_DestroyContext;
+	break;
+    case CKM_CDMF_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_CDMF_ECB:
+    case CKM_CDMF_CBC:
+	if (key_type != CKK_CDMF) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	t = (pMechanism->mechanism == CKM_CDMF_ECB) ? NSS_DES : NSS_DES_CBC;
+	if (crv != CKR_OK) break;
+	goto finish_des;
+    case CKM_DES_ECB:
+	if (key_type != CKK_DES) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	t = NSS_DES;
+	goto finish_des;
+    case CKM_DES_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_DES_CBC:
+	if (key_type != CKK_DES) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	t = NSS_DES_CBC;
+	goto finish_des;
+    case CKM_DES3_ECB:
+	if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	t = NSS_DES_EDE3;
+	goto finish_des;
+    case CKM_DES3_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_DES3_CBC:
+	if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	t = NSS_DES_EDE3_CBC;
+finish_des:
+	context->blockSize = 8;
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	if (key_type == CKK_DES2 && 
+            (t == NSS_DES_EDE3_CBC || t == NSS_DES_EDE3)) {
+	    /* extend DES2 key to DES3 key. */
+	    memcpy(newdeskey, att->attrib.pValue, 16);
+	    memcpy(newdeskey + 16, newdeskey, 8);
+	    useNewKey=PR_TRUE;
+	} else if (key_type == CKK_CDMF) {
+	    crv = sftk_cdmf2des((unsigned char*)att->attrib.pValue,newdeskey);
+	    if (crv != CKR_OK) {
+		sftk_FreeAttribute(att);
+		break;
+	    }
+	    useNewKey=PR_TRUE;
+	}
+	context->cipherInfo = DES_CreateContext(
+		useNewKey ? newdeskey : (unsigned char*)att->attrib.pValue,
+		(unsigned char*)pMechanism->pParameter,t, isEncrypt);
+	if (useNewKey) 
+	    memset(newdeskey, 0, sizeof newdeskey);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->update = (SFTKCipher) (isEncrypt ? DES_Encrypt : DES_Decrypt);
+	context->destroy = (SFTKDestroy) DES_DestroyContext;
+	break;
+    case CKM_SEED_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_SEED_CBC:
+        if (!pMechanism->pParameter ||
+	     pMechanism->ulParameterLen != 16) {
+            crv = CKR_MECHANISM_PARAM_INVALID;
+            break;
+        }
+        /* fall thru */
+    case CKM_SEED_ECB:
+	context->blockSize = 16;
+	if (key_type != CKK_SEED) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	context->cipherInfo = SEED_CreateContext(
+	    (unsigned char*)att->attrib.pValue,
+	    (unsigned char*)pMechanism->pParameter,
+	    pMechanism->mechanism == CKM_SEED_ECB ? NSS_SEED : NSS_SEED_CBC,
+	    isEncrypt);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->update = (SFTKCipher)(isEncrypt ? SEED_Encrypt : SEED_Decrypt);
+	context->destroy = (SFTKDestroy) SEED_DestroyContext;
+	break;
+
+    case CKM_CAMELLIA_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_CAMELLIA_CBC:
+	if (!pMechanism->pParameter ||
+		 pMechanism->ulParameterLen != 16) {
+	    crv = CKR_MECHANISM_PARAM_INVALID;
+	    break;
+	}
+	/* fall thru */
+    case CKM_CAMELLIA_ECB:
+	context->blockSize = 16;
+	if (key_type != CKK_CAMELLIA) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	context->cipherInfo = Camellia_CreateContext(
+	    (unsigned char*)att->attrib.pValue,
+	    (unsigned char*)pMechanism->pParameter,
+	    pMechanism->mechanism ==
+	    CKM_CAMELLIA_ECB ? NSS_CAMELLIA : NSS_CAMELLIA_CBC,
+	    isEncrypt, att->attrib.ulValueLen);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->update = (SFTKCipher) (isEncrypt ?
+					Camellia_Encrypt : Camellia_Decrypt);
+	context->destroy = (SFTKDestroy) Camellia_DestroyContext;
+	break;
+
+    case CKM_AES_CBC_PAD:
+	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_AES_ECB:
+    case CKM_AES_CBC:
+	context->blockSize = 16;
+	if (key_type != CKK_AES) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	context->cipherInfo = AES_CreateContext(
+	    (unsigned char*)att->attrib.pValue,
+	    (unsigned char*)pMechanism->pParameter,
+	    pMechanism->mechanism == CKM_AES_ECB ? NSS_AES : NSS_AES_CBC,
+	    isEncrypt, att->attrib.ulValueLen, 16);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->update = (SFTKCipher) (isEncrypt ? AES_Encrypt : AES_Decrypt);
+	context->destroy = (SFTKDestroy) AES_DestroyContext;
+	break;
+
+    case CKM_NETSCAPE_AES_KEY_WRAP_PAD:
+    	context->doPad = PR_TRUE;
+	/* fall thru */
+    case CKM_NETSCAPE_AES_KEY_WRAP:
+	context->multi = PR_FALSE;
+	context->blockSize = 8;
+	if (key_type != CKK_AES) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att = sftk_FindAttribute(key,CKA_VALUE);
+	if (att == NULL) {
+	    crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	context->cipherInfo = AESKeyWrap_CreateContext(
+	    (unsigned char*)att->attrib.pValue,
+	    (unsigned char*)pMechanism->pParameter,
+	    isEncrypt, att->attrib.ulValueLen);
+	sftk_FreeAttribute(att);
+	if (context->cipherInfo == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->update = (SFTKCipher) (isEncrypt ? AESKeyWrap_Encrypt 
+	                                          : AESKeyWrap_Decrypt);
+	context->destroy = (SFTKDestroy) AESKeyWrap_DestroyContext;
+	break;
+
+    default:
+	crv = CKR_MECHANISM_INVALID;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+        sftk_FreeContext(context);
+	sftk_FreeSession(session);
+	return crv;
+    }
+    sftk_SetContextByType(session, contextType, context);
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+/* NSC_EncryptInit initializes an encryption operation. */
+CK_RV NSC_EncryptInit(CK_SESSION_HANDLE hSession,
+		 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+    CHECK_FORK();
+    return sftk_CryptInit(hSession, pMechanism, hKey, CKA_ENCRYPT, 
+						SFTK_ENCRYPT, PR_TRUE);
+}
+
+/* NSC_EncryptUpdate continues a multiple-part encryption operation. */
+CK_RV NSC_EncryptUpdate(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,	
+					CK_ULONG_PTR pulEncryptedPartLen)
+{
+    SFTKSessionContext *context;
+    unsigned int outlen,i;
+    unsigned int padoutlen = 0;
+    unsigned int maxout = *pulEncryptedPartLen;
+    CK_RV crv;
+    SECStatus rv;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,NULL);
+    if (crv != CKR_OK) return crv;
+
+    if (!pEncryptedPart) {
+	if (context->doPad) {
+	    CK_ULONG totalDataAvailable = ulPartLen + context->padDataLength;
+	    CK_ULONG blocksToSend = totalDataAvailable/context->blockSize;
+
+	    *pulEncryptedPartLen = blocksToSend * context->blockSize;
+	    return CKR_OK;
+	}
+	*pulEncryptedPartLen = ulPartLen;
+	return CKR_OK;
+    }
+
+    /* do padding */
+    if (context->doPad) {
+	/* deal with previous buffered data */
+	if (context->padDataLength != 0) {
+	    /* fill in the padded to a full block size */
+	    for (i=context->padDataLength; 
+			(ulPartLen != 0) && i < context->blockSize; i++) {
+		context->padBuf[i] = *pPart++;
+		ulPartLen--;
+		context->padDataLength++;
+	    }
+
+	    /* not enough data to encrypt yet? then return */
+	    if (context->padDataLength != context->blockSize) {
+		*pulEncryptedPartLen = 0;
+		return CKR_OK;
+	    }
+	    /* encrypt the current padded data */
+    	    rv = (*context->update)(context->cipherInfo, pEncryptedPart, 
+		&padoutlen, context->blockSize, context->padBuf,
+							context->blockSize);
+	    if (rv != SECSuccess) {
+		return sftk_MapCryptError(PORT_GetError());
+	    }
+	    pEncryptedPart += padoutlen;
+	    maxout -= padoutlen;
+	}
+	/* save the residual */
+	context->padDataLength = ulPartLen % context->blockSize;
+	if (context->padDataLength) {
+	    PORT_Memcpy(context->padBuf,
+			&pPart[ulPartLen-context->padDataLength],
+							context->padDataLength);
+	    ulPartLen -= context->padDataLength;
+	}
+	/* if we've exhausted our new buffer, we're done */
+	if (ulPartLen == 0) {
+	    *pulEncryptedPartLen = padoutlen;
+	    return CKR_OK;
+	}
+    }
+
+
+    /* do it: NOTE: this assumes buf size in is >= buf size out! */
+    rv = (*context->update)(context->cipherInfo,pEncryptedPart, 
+					&outlen, maxout, pPart, ulPartLen);
+    *pulEncryptedPartLen = (CK_ULONG) (outlen + padoutlen);
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+}
+
+
+/* NSC_EncryptFinal finishes a multiple-part encryption operation. */
+CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen,i;
+    unsigned int maxout = *pulLastEncryptedPartLen;
+    CK_RV crv;
+    SECStatus rv = SECSuccess;
+    PRBool contextFinished = PR_TRUE;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,&session);
+    if (crv != CKR_OK) return crv;
+
+    *pulLastEncryptedPartLen = 0;
+    if (!pLastEncryptedPart) {
+	/* caller is checking the amount of remaining data */
+	if (context->blockSize > 0 && context->doPad) {
+	    *pulLastEncryptedPartLen = context->blockSize;
+	    contextFinished = PR_FALSE; /* still have padding to go */
+	}
+	goto finish;
+    }
+
+    /* do padding */
+    if (context->doPad) {
+	unsigned char  padbyte = (unsigned char) 
+				(context->blockSize - context->padDataLength); 
+	/* fill out rest of pad buffer with pad magic*/
+	for (i=context->padDataLength; i < context->blockSize; i++) {
+	    context->padBuf[i] = padbyte;
+	}
+	rv = (*context->update)(context->cipherInfo,pLastEncryptedPart, 
+			&outlen, maxout, context->padBuf, context->blockSize);
+	if (rv == SECSuccess) *pulLastEncryptedPartLen = (CK_ULONG) outlen;
+    }
+
+finish:
+    if (contextFinished) {
+	sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
+	sftk_FreeContext(context);
+    }
+    sftk_FreeSession(session);
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+}
+
+/* NSC_Encrypt encrypts single-part data. */
+CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+    		   CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
+		   CK_ULONG_PTR pulEncryptedDataLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen;
+    unsigned int maxoutlen = *pulEncryptedDataLen;
+    CK_RV crv;
+    CK_RV crv2;
+    SECStatus rv = SECSuccess;
+    SECItem   pText;
+
+    pText.type = siBuffer;
+    pText.data = pData;
+    pText.len  = ulDataLen;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,&session);
+    if (crv != CKR_OK) return crv;
+
+    if (!pEncryptedData) {
+	*pulEncryptedDataLen = context->multi ? 
+		ulDataLen + 2 * context->blockSize : context->maxLen;
+	goto finish;
+    }
+
+    if (context->doPad) {
+	if (context->multi) {
+	    CK_ULONG finalLen;
+	    /* padding is fairly complicated, have the update and final 
+	     * code deal with it */
+	    sftk_FreeSession(session);
+	    crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData, 
+	                            pulEncryptedDataLen);
+	    if (crv != CKR_OK) 
+	    	*pulEncryptedDataLen = 0;
+	    maxoutlen      -= *pulEncryptedDataLen;
+	    pEncryptedData += *pulEncryptedDataLen;
+	    finalLen = maxoutlen;
+	    crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen);
+	    if (crv2 == CKR_OK) 
+	    	*pulEncryptedDataLen += finalLen;
+	    return crv == CKR_OK ? crv2 : crv;
+	}
+	/* doPad without multi means that padding must be done on the first
+	** and only update.  There will be no final.
+	*/
+	PORT_Assert(context->blockSize > 1);
+	if (context->blockSize > 1) {
+	    CK_ULONG remainder = ulDataLen % context->blockSize;
+	    CK_ULONG padding   = context->blockSize - remainder;
+	    pText.len += padding;
+	    pText.data = PORT_ZAlloc(pText.len);
+	    if (pText.data) {
+		memcpy(pText.data, pData, ulDataLen);
+		memset(pText.data + ulDataLen, padding, padding);
+	    } else {
+		crv = CKR_HOST_MEMORY;
+		goto fail;
+	    }
+	}
+    }
+
+    /* do it: NOTE: this assumes buf size is big enough. */
+    rv = (*context->update)(context->cipherInfo, pEncryptedData, 
+			    &outlen, maxoutlen, pText.data, pText.len);
+    crv = (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+    *pulEncryptedDataLen = (CK_ULONG) outlen;
+    if (pText.data != pData)
+    	PORT_ZFree(pText.data, pText.len);
+fail:
+    sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
+    sftk_FreeContext(context);
+finish:
+    sftk_FreeSession(session);
+
+    return crv;
+}
+
+
+/*
+ ************** Crypto Functions:     Decrypt ************************
+ */
+
+/* NSC_DecryptInit initializes a decryption operation. */
+CK_RV NSC_DecryptInit( CK_SESSION_HANDLE hSession,
+			 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+    CHECK_FORK();
+
+    return sftk_CryptInit(hSession, pMechanism, hKey, CKA_DECRYPT,
+						SFTK_DECRYPT, PR_FALSE);
+}
+
+/* NSC_DecryptUpdate continues a multiple-part decryption operation. */
+CK_RV NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen,
+    				CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
+{
+    SFTKSessionContext *context;
+    unsigned int padoutlen = 0;
+    unsigned int outlen;
+    unsigned int maxout = *pulPartLen;
+    CK_RV crv;
+    SECStatus rv;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,NULL);
+    if (crv != CKR_OK) return crv;
+
+    /* this can only happen on an NSS programming error */
+    PORT_Assert((context->padDataLength == 0) 
+		|| context->padDataLength == context->blockSize);
+
+
+    if (!pPart) {
+	if (context->doPad) {
+	    /* we can check the data length here because if we are padding,
+	     * then we must be using a block cipher. In the non-padding case
+	     * the error will be returned by the underlying decryption
+	     * function when do do the actual decrypt. We need to do the
+	     * check here to avoid returning a negative length to the caller.
+ 	     */
+	    if ((ulEncryptedPartLen == 0) ||
+		(ulEncryptedPartLen % context->blockSize) != 0) {
+		return CKR_ENCRYPTED_DATA_LEN_RANGE;
+	    }
+	    *pulPartLen = 
+		ulEncryptedPartLen + context->padDataLength - context->blockSize;
+	    return CKR_OK;
+	}
+	/* for stream ciphers there is are no constraints on ulEncryptedPartLen.
+	 * for block ciphers, it must be a multiple of blockSize. The error is
+	 * detected when this function is called again do decrypt the output.
+	 */
+	*pulPartLen = ulEncryptedPartLen;
+	return CKR_OK;
+    }
+
+    if (context->doPad) {
+	/* first decrypt our saved buffer */
+	if (context->padDataLength != 0) {
+    	    rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
+		 maxout, context->padBuf, context->blockSize);
+    	    if (rv != SECSuccess) return sftk_MapDecryptError(PORT_GetError());
+	    pPart += padoutlen;
+	    maxout -= padoutlen;
+	}
+	/* now save the final block for the next decrypt or the final */
+	PORT_Memcpy(context->padBuf,&pEncryptedPart[ulEncryptedPartLen -
+				context->blockSize], context->blockSize);
+	context->padDataLength = context->blockSize;
+	ulEncryptedPartLen -= context->padDataLength;
+    }
+
+    /* do it: NOTE: this assumes buf size in is >= buf size out! */
+    rv = (*context->update)(context->cipherInfo,pPart, &outlen,
+		 maxout, pEncryptedPart, ulEncryptedPartLen);
+    *pulPartLen = (CK_ULONG) (outlen + padoutlen);
+    return (rv == SECSuccess)  ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
+}
+
+
+/* NSC_DecryptFinal finishes a multiple-part decryption operation. */
+CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen;
+    unsigned int maxout = *pulLastPartLen;
+    CK_RV crv;
+    SECStatus rv = SECSuccess;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,&session);
+    if (crv != CKR_OK) return crv;
+
+    *pulLastPartLen = 0;
+    if (!pLastPart) {
+	/* caller is checking the amount of remaining data */
+	if (context->padDataLength > 0) {
+	    *pulLastPartLen = context->padDataLength;
+	}
+	rv = SECSuccess;
+	goto finish;
+    }
+
+    if (context->doPad) {
+	/* decrypt our saved buffer */
+	if (context->padDataLength != 0) {
+	    /* this assumes that pLastPart is big enough to hold the *whole*
+	     * buffer!!! */
+    	    rv = (*context->update)(context->cipherInfo, pLastPart, &outlen,
+		 maxout, context->padBuf, context->blockSize);
+    	    if (rv == SECSuccess) {
+		unsigned int padSize = 
+			    (unsigned int) pLastPart[context->blockSize-1];
+		if ((padSize > context->blockSize) || (padSize == 0)) {
+		    rv = SECFailure;
+		} else {
+		    *pulLastPartLen = outlen - padSize;
+		}
+	    }
+	}
+    }
+
+    sftk_SetContextByType(session, SFTK_DECRYPT, NULL);
+    sftk_FreeContext(context);
+finish:
+    sftk_FreeSession(session);
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
+}
+
+/* NSC_Decrypt decrypts encrypted data in a single part. */
+CK_RV NSC_Decrypt(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,
+    						CK_ULONG_PTR pulDataLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen;
+    unsigned int maxoutlen = *pulDataLen;
+    CK_RV crv;
+    CK_RV crv2;
+    SECStatus rv = SECSuccess;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_FALSE,&session);
+    if (crv != CKR_OK) return crv;
+
+    if (!pData) {
+	*pulDataLen = ulEncryptedDataLen + context->blockSize;
+	goto finish;
+    }
+
+    if (context->doPad && context->multi) {
+	CK_ULONG finalLen;
+	/* padding is fairly complicated, have the update and final 
+	 * code deal with it */
+	sftk_FreeSession(session);
+	crv = NSC_DecryptUpdate(hSession,pEncryptedData,ulEncryptedDataLen,
+							pData, pulDataLen);
+	if (crv != CKR_OK) 
+	    *pulDataLen = 0;
+	maxoutlen -= *pulDataLen;
+	pData     += *pulDataLen;
+	finalLen = maxoutlen;
+	crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
+	if (crv2 == CKR_OK) 
+	    *pulDataLen += finalLen;
+	return crv == CKR_OK ? crv2 : crv;
+    }
+
+    rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
+					pEncryptedData, ulEncryptedDataLen);
+    /* XXX need to do MUCH better error mapping than this. */
+    crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
+    if (rv == SECSuccess && context->doPad) {
+    	CK_ULONG padding = pData[outlen - 1];
+	if (padding > context->blockSize || !padding) {
+	    crv = CKR_ENCRYPTED_DATA_INVALID;
+	} else
+	    outlen -= padding;
+    }
+    *pulDataLen = (CK_ULONG) outlen;
+    sftk_SetContextByType(session, SFTK_DECRYPT, NULL);
+    sftk_FreeContext(context);
+finish:
+    sftk_FreeSession(session);
+    return crv;
+}
+
+
+
+/*
+ ************** Crypto Functions:     Digest (HASH)  ************************
+ */
+
+/* NSC_DigestInit initializes a message-digesting operation. */
+CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession,
+    					CK_MECHANISM_PTR pMechanism)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    CK_RV crv = CKR_OK;
+
+    CHECK_FORK();
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) 
+    	return CKR_SESSION_HANDLE_INVALID;
+    crv = sftk_InitGeneric(session,&context,SFTK_HASH,NULL,0,NULL, 0, 0);
+    if (crv != CKR_OK) {
+	sftk_FreeSession(session);
+	return crv;
+    }
+
+
+#define INIT_MECH(mech,mmm) \
+    case mech: { \
+	mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
+	context->cipherInfo    = (void *)mmm ## _ctx; \
+	context->cipherInfoLen = mmm ## _FlattenSize(mmm ## _ctx); \
+	context->currentMech   = mech; \
+	context->hashUpdate    = (SFTKHash)    mmm ## _Update; \
+	context->end           = (SFTKEnd)     mmm ## _End; \
+	context->destroy       = (SFTKDestroy) mmm ## _DestroyContext; \
+	context->maxLen        = mmm ## _LENGTH; \
+        if (mmm ## _ctx) \
+	    mmm ## _Begin(mmm ## _ctx); \
+	else  \
+	    crv = CKR_HOST_MEMORY; \
+	break; \
+    }
+
+    switch(pMechanism->mechanism) {
+    INIT_MECH(CKM_MD2,    MD2)
+    INIT_MECH(CKM_MD5,    MD5)
+    INIT_MECH(CKM_SHA_1,  SHA1)
+    INIT_MECH(CKM_SHA256, SHA256)
+    INIT_MECH(CKM_SHA384, SHA384)
+    INIT_MECH(CKM_SHA512, SHA512)
+
+    default:
+	crv = CKR_MECHANISM_INVALID;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+        sftk_FreeContext(context);
+	sftk_FreeSession(session);
+	return crv;
+    }
+    sftk_SetContextByType(session, SFTK_HASH, context);
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+
+/* NSC_Digest digests data in a single part. */
+CK_RV NSC_Digest(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest,
+    						CK_ULONG_PTR pulDigestLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int digestLen;
+    unsigned int maxout = *pulDigestLen;
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_FALSE,&session);
+    if (crv != CKR_OK) return crv;
+
+    if (pDigest == NULL) {
+	*pulDigestLen = context->maxLen;
+	goto finish;
+    }
+
+    /* do it: */
+    (*context->hashUpdate)(context->cipherInfo, pData, ulDataLen);
+    /*  NOTE: this assumes buf size is bigenough for the algorithm */
+    (*context->end)(context->cipherInfo, pDigest, &digestLen,maxout);
+    *pulDigestLen = digestLen;
+
+    sftk_SetContextByType(session, SFTK_HASH, NULL);
+    sftk_FreeContext(context);
+finish:
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+
+/* NSC_DigestUpdate continues a multiple-part message-digesting operation. */
+CK_RV NSC_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
+					    CK_ULONG ulPartLen)
+{
+    SFTKSessionContext *context;
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_TRUE,NULL);
+    if (crv != CKR_OK) return crv;
+    /* do it: */
+    (*context->hashUpdate)(context->cipherInfo, pPart, ulPartLen);
+    return CKR_OK;
+}
+
+
+/* NSC_DigestFinal finishes a multiple-part message-digesting operation. */
+CK_RV NSC_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,
+    						CK_ULONG_PTR pulDigestLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int maxout = *pulDigestLen;
+    unsigned int digestLen;
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session);
+    if (crv != CKR_OK) return crv;
+
+    if (pDigest != NULL) {
+        (*context->end)(context->cipherInfo, pDigest, &digestLen, maxout);
+        *pulDigestLen = digestLen;
+	sftk_SetContextByType(session, SFTK_HASH, NULL);
+	sftk_FreeContext(context);
+    } else {
+	*pulDigestLen = context->maxLen;
+    }
+
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+/*
+ * these helper functions are used by Generic Macing and Signing functions
+ * that use hashes as part of their operations. 
+ */
+#define DOSUB(mmm) \
+static CK_RV \
+sftk_doSub ## mmm(SFTKSessionContext *context) { \
+    mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
+    context->hashInfo    = (void *)      mmm ## _ctx; \
+    context->hashUpdate  = (SFTKHash)    mmm ## _Update; \
+    context->end         = (SFTKEnd)     mmm ## _End; \
+    context->hashdestroy = (SFTKDestroy) mmm ## _DestroyContext; \
+    if (!context->hashInfo) { \
+	return CKR_HOST_MEMORY; \
+    } \
+    mmm ## _Begin( mmm ## _ctx ); \
+    return CKR_OK; \
+}
+
+DOSUB(MD2)
+DOSUB(MD5)
+DOSUB(SHA1)
+DOSUB(SHA256)
+DOSUB(SHA384)
+DOSUB(SHA512)
+
+/*
+ * HMAC General copies only a portion of the result. This update routine likes
+ * the final HMAC output with the signature.
+ */
+static SECStatus
+sftk_HMACCopy(CK_ULONG *copyLen,unsigned char *sig,unsigned int *sigLen,
+		unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
+{
+    if (maxLen < *copyLen) return SECFailure;
+    PORT_Memcpy(sig,hash,*copyLen);
+    *sigLen = *copyLen;
+    return SECSuccess;
+}
+
+/* Verify is just a compare for HMAC */
+static SECStatus
+sftk_HMACCmp(CK_ULONG *copyLen,unsigned char *sig,unsigned int sigLen,
+				unsigned char *hash, unsigned int hashLen)
+{
+    return (PORT_Memcmp(sig,hash,*copyLen) == 0) ? SECSuccess : SECFailure ; 
+}
+
+/*
+ * common HMAC initalization routine
+ */
+static CK_RV
+sftk_doHMACInit(SFTKSessionContext *context,HASH_HashType hash,
+					SFTKObject *key, CK_ULONG mac_size)
+{
+    SFTKAttribute *keyval;
+    HMACContext *HMACcontext;
+    CK_ULONG *intpointer;
+    const SECHashObject *hashObj = HASH_GetRawHashObject(hash);
+    PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
+
+    /* required by FIPS 198 Section 4 */
+    if (isFIPS && (mac_size < 4 || mac_size < hashObj->length/2)) {
+	return CKR_BUFFER_TOO_SMALL;
+    }
+
+    keyval = sftk_FindAttribute(key,CKA_VALUE);
+    if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
+
+    HMACcontext = HMAC_Create(hashObj, 
+		(const unsigned char*)keyval->attrib.pValue,
+		keyval->attrib.ulValueLen, isFIPS);
+    context->hashInfo = HMACcontext;
+    context->multi = PR_TRUE;
+    sftk_FreeAttribute(keyval);
+    if (context->hashInfo == NULL) {
+	if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
+	    return CKR_KEY_SIZE_RANGE;
+	}
+	return CKR_HOST_MEMORY;
+    }
+    context->hashUpdate = (SFTKHash) HMAC_Update;
+    context->end = (SFTKEnd) HMAC_Finish;
+
+    context->hashdestroy = (SFTKDestroy) HMAC_Destroy;
+    intpointer = (CK_ULONG *) PORT_Alloc(sizeof(CK_ULONG));
+    if (intpointer == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    *intpointer = mac_size;
+    context->cipherInfo = (void *) intpointer;
+    context->destroy = (SFTKDestroy) sftk_Space;
+    context->update = (SFTKCipher) sftk_HMACCopy;
+    context->verify = (SFTKVerify) sftk_HMACCmp;
+    context->maxLen = hashObj->length;
+    HMAC_Begin(HMACcontext);
+    return CKR_OK;
+}
+
+/*
+ *  SSL Macing support. SSL Macs are inited, then update with the base
+ * hashing algorithm, then finalized in sign and verify
+ */
+
+/*
+ * FROM SSL:
+ * 60 bytes is 3 times the maximum length MAC size that is supported.
+ * We probably should have one copy of this table. We still need this table
+ * in ssl to 'sign' the handshake hashes.
+ */
+static unsigned char ssl_pad_1 [60] = {
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36
+};
+static unsigned char ssl_pad_2 [60] = {
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c
+};
+
+static SECStatus
+sftk_SSLMACSign(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int *sigLen,
+		unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
+{
+    unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
+    unsigned int out;
+
+    info->begin(info->hashContext);
+    info->update(info->hashContext,info->key,info->keySize);
+    info->update(info->hashContext,ssl_pad_2,info->padSize);
+    info->update(info->hashContext,hash,hashLen);
+    info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
+    PORT_Memcpy(sig,tmpBuf,info->macSize);
+    *sigLen = info->macSize;
+    return SECSuccess;
+}
+
+static SECStatus
+sftk_SSLMACVerify(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int sigLen,
+		unsigned char *hash, unsigned int hashLen)
+{
+    unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
+    unsigned int out;
+
+    info->begin(info->hashContext);
+    info->update(info->hashContext,info->key,info->keySize);
+    info->update(info->hashContext,ssl_pad_2,info->padSize);
+    info->update(info->hashContext,hash,hashLen);
+    info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
+    return (PORT_Memcmp(sig,tmpBuf,info->macSize) == 0) ? 
+						SECSuccess : SECFailure;
+}
+
+/*
+ * common HMAC initalization routine
+ */
+static CK_RV
+sftk_doSSLMACInit(SFTKSessionContext *context,SECOidTag oid,
+					SFTKObject *key, CK_ULONG mac_size)
+{
+    SFTKAttribute *keyval;
+    SFTKBegin begin;
+    int padSize;
+    SFTKSSLMACInfo *sslmacinfo;
+    CK_RV crv = CKR_MECHANISM_INVALID;
+
+    if (oid == SEC_OID_SHA1) {
+	crv = sftk_doSubSHA1(context);
+	if (crv != CKR_OK) return crv;
+	begin = (SFTKBegin) SHA1_Begin;
+	padSize = 40;
+    } else {
+	crv = sftk_doSubMD5(context);
+	if (crv != CKR_OK) return crv;
+	begin = (SFTKBegin) MD5_Begin;
+	padSize = 48;
+    }
+    context->multi = PR_TRUE;
+
+    keyval = sftk_FindAttribute(key,CKA_VALUE);
+    if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
+
+    context->hashUpdate(context->hashInfo,keyval->attrib.pValue,
+						 keyval->attrib.ulValueLen);
+    context->hashUpdate(context->hashInfo,ssl_pad_1,padSize);
+    sslmacinfo = (SFTKSSLMACInfo *) PORT_Alloc(sizeof(SFTKSSLMACInfo));
+    if (sslmacinfo == NULL) {
+        sftk_FreeAttribute(keyval);
+	return CKR_HOST_MEMORY;
+    }
+    sslmacinfo->macSize = mac_size;
+    sslmacinfo->hashContext = context->hashInfo;
+    PORT_Memcpy(sslmacinfo->key,keyval->attrib.pValue,
+					keyval->attrib.ulValueLen);
+    sslmacinfo->keySize = keyval->attrib.ulValueLen;
+    sslmacinfo->begin = begin;
+    sslmacinfo->end = context->end;
+    sslmacinfo->update = context->hashUpdate;
+    sslmacinfo->padSize = padSize;
+    sftk_FreeAttribute(keyval);
+    context->cipherInfo = (void *) sslmacinfo;
+    context->destroy = (SFTKDestroy) sftk_Space;
+    context->update = (SFTKCipher) sftk_SSLMACSign;
+    context->verify = (SFTKVerify) sftk_SSLMACVerify;
+    context->maxLen = mac_size;
+    return CKR_OK;
+}
+
+/*
+ ************** Crypto Functions:     Sign  ************************
+ */
+
+/*
+ * Check if We're using CBCMacing and initialize the session context if we are.
+ */
+static CK_RV
+sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ 	CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE keyUsage,
+						 SFTKContextType contextType)
+	
+{
+    CK_MECHANISM cbc_mechanism;
+    CK_ULONG mac_bytes = SFTK_INVALID_MAC_SIZE;
+    CK_RC2_CBC_PARAMS rc2_params;
+#if NSS_SOFTOKEN_DOES_RC5
+    CK_RC5_CBC_PARAMS rc5_params;
+    CK_RC5_MAC_GENERAL_PARAMS *rc5_mac;
+#endif
+    unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE];
+    SFTKSessionContext *context;
+    CK_RV crv;
+    int blockSize;
+
+    switch (pMechanism->mechanism) {
+    case CKM_RC2_MAC_GENERAL:
+	mac_bytes = 
+	    ((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
+	/* fall through */
+    case CKM_RC2_MAC:
+	/* this works because ulEffectiveBits is in the same place in both the
+	 * CK_RC2_MAC_GENERAL_PARAMS and CK_RC2_CBC_PARAMS */
+	rc2_params.ulEffectiveBits = ((CK_RC2_MAC_GENERAL_PARAMS *)
+				pMechanism->pParameter)->ulEffectiveBits;
+	PORT_Memset(rc2_params.iv,0,sizeof(rc2_params.iv));
+	cbc_mechanism.mechanism = CKM_RC2_CBC;
+	cbc_mechanism.pParameter = &rc2_params;
+	cbc_mechanism.ulParameterLen = sizeof(rc2_params);
+	blockSize = 8;
+	break;
+#if NSS_SOFTOKEN_DOES_RC5
+    case CKM_RC5_MAC_GENERAL:
+	mac_bytes = 
+	    ((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
+	/* fall through */
+    case CKM_RC5_MAC:
+	/* this works because ulEffectiveBits is in the same place in both the
+	 * CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */
+	rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
+	rc5_params.ulWordsize = rc5_mac->ulWordsize;
+	rc5_params.ulRounds = rc5_mac->ulRounds;
+	rc5_params.pIv = ivBlock;
+	blockSize = rc5_mac->ulWordsize*2;
+	rc5_params.ulIvLen = blockSize;
+	PORT_Memset(ivBlock,0,blockSize);
+	cbc_mechanism.mechanism = CKM_RC5_CBC;
+	cbc_mechanism.pParameter = &rc5_params;
+	cbc_mechanism.ulParameterLen = sizeof(rc5_params);
+	break;
+#endif
+    /* add cast and idea later */
+    case CKM_DES_MAC_GENERAL:
+	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
+	/* fall through */
+    case CKM_DES_MAC:
+	blockSize = 8;
+	PORT_Memset(ivBlock,0,blockSize);
+	cbc_mechanism.mechanism = CKM_DES_CBC;
+	cbc_mechanism.pParameter = &ivBlock;
+	cbc_mechanism.ulParameterLen = blockSize;
+	break;
+    case CKM_DES3_MAC_GENERAL:
+	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
+	/* fall through */
+    case CKM_DES3_MAC:
+	blockSize = 8;
+	PORT_Memset(ivBlock,0,blockSize);
+	cbc_mechanism.mechanism = CKM_DES3_CBC;
+	cbc_mechanism.pParameter = &ivBlock;
+	cbc_mechanism.ulParameterLen = blockSize;
+	break;
+    case CKM_CDMF_MAC_GENERAL:
+	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
+	/* fall through */
+    case CKM_CDMF_MAC:
+	blockSize = 8;
+	PORT_Memset(ivBlock,0,blockSize);
+	cbc_mechanism.mechanism = CKM_CDMF_CBC;
+	cbc_mechanism.pParameter = &ivBlock;
+	cbc_mechanism.ulParameterLen = blockSize;
+	break;
+    case CKM_SEED_MAC_GENERAL:
+	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
+	/* fall through */
+    case CKM_SEED_MAC:
+	blockSize = 16;
+	PORT_Memset(ivBlock,0,blockSize);
+	cbc_mechanism.mechanism = CKM_SEED_CBC;
+	cbc_mechanism.pParameter = &ivBlock;
+	cbc_mechanism.ulParameterLen = blockSize;
+	break;
+    case CKM_CAMELLIA_MAC_GENERAL:
+	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
+	/* fall through */
+    case CKM_CAMELLIA_MAC:
+	blockSize = 16;
+	PORT_Memset(ivBlock,0,blockSize);
+	cbc_mechanism.mechanism = CKM_CAMELLIA_CBC;
+	cbc_mechanism.pParameter = &ivBlock;
+	cbc_mechanism.ulParameterLen = blockSize;
+	break;
+    case CKM_AES_MAC_GENERAL:
+	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
+	/* fall through */
+    case CKM_AES_MAC:
+	blockSize = 16;
+	PORT_Memset(ivBlock,0,blockSize);
+	cbc_mechanism.mechanism = CKM_AES_CBC;
+	cbc_mechanism.pParameter = &ivBlock;
+	cbc_mechanism.ulParameterLen = blockSize;
+	break;
+    default:
+	return CKR_FUNCTION_NOT_SUPPORTED;
+    }
+
+    crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey, keyUsage,
+							contextType, PR_TRUE);
+    if (crv != CKR_OK) return crv;
+    crv = sftk_GetContext(hSession,&context,contextType,PR_TRUE,NULL);
+
+    /* this shouldn't happen! */
+    PORT_Assert(crv == CKR_OK);
+    if (crv != CKR_OK) return crv;
+    context->blockSize = blockSize;
+    if (mac_bytes == SFTK_INVALID_MAC_SIZE) mac_bytes = blockSize/2;
+    context->macSize = mac_bytes;
+    return CKR_OK;
+}
+
+/*
+ * encode RSA PKCS #1 Signature data before signing... 
+ */
+static SECStatus
+sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen,
+		unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
+{
+    return RSA_HashSign(info->hashOid,info->key,sig,sigLen,maxLen,
+							hash,hashLen);
+}
+
+/* XXX Old template; want to expunge it eventually. */
+static DERTemplate SECAlgorithmIDTemplate[] = {
+    { DER_SEQUENCE,
+	  0, NULL, sizeof(SECAlgorithmID) },
+    { DER_OBJECT_ID,
+	  offsetof(SECAlgorithmID,algorithm), },
+    { DER_OPTIONAL | DER_ANY,
+	  offsetof(SECAlgorithmID,parameters), },
+    { 0, }
+};
+
+/*
+ * XXX OLD Template.  Once all uses have been switched over to new one,
+ * remove this.
+ */
+static DERTemplate SGNDigestInfoTemplate[] = {
+    { DER_SEQUENCE,
+	  0, NULL, sizeof(SGNDigestInfo) },
+    { DER_INLINE,
+	  offsetof(SGNDigestInfo,digestAlgorithm),
+	  SECAlgorithmIDTemplate, },
+    { DER_OCTET_STRING,
+	  offsetof(SGNDigestInfo,digest), },
+    { 0, }
+};
+
+SECStatus
+RSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
+		unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
+		unsigned char *hash, unsigned int hashLen)
+{
+    
+    SECStatus rv = SECFailure;
+    SECItem digder;
+    PLArenaPool *arena = NULL;
+    SGNDigestInfo *di = NULL;
+
+    digder.data = NULL;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if ( !arena ) { goto loser; }
+    
+    /* Construct digest info */
+    di = SGN_CreateDigestInfo(hashOid, hash, hashLen);
+    if (!di) { goto loser; }
+
+    /* Der encode the digest as a DigestInfo */
+    rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    /*
+    ** Encrypt signature after constructing appropriate PKCS#1 signature
+    ** block
+    */
+    rv = RSA_Sign(key,sig,sigLen,maxLen,digder.data,digder.len);
+
+  loser:
+    SGN_DestroyDigestInfo(di);
+    if (arena != NULL) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return rv;
+}
+
+static SECStatus
+nsc_DSA_Verify_Stub(void *ctx, void *sigBuf, unsigned int sigLen,
+                               void *dataBuf, unsigned int dataLen)
+{
+    SECItem signature, digest;
+    NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
+
+    signature.data = (unsigned char *)sigBuf;
+    signature.len = sigLen;
+    digest.data = (unsigned char *)dataBuf;
+    digest.len = dataLen;
+    return DSA_VerifyDigest(&(key->u.dsa), &signature, &digest);
+}
+
+static SECStatus
+nsc_DSA_Sign_Stub(void *ctx, void *sigBuf,
+                  unsigned int *sigLen, unsigned int maxSigLen,
+                  void *dataBuf, unsigned int dataLen)
+{
+    SECItem signature, digest;
+    SECStatus rv;
+    NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
+
+    signature.data = (unsigned char *)sigBuf;
+    signature.len = maxSigLen;
+    digest.data = (unsigned char *)dataBuf;
+    digest.len = dataLen;
+    rv = DSA_SignDigest(&(key->u.dsa), &signature, &digest);
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+	sftk_fatalError = PR_TRUE;
+    }
+    *sigLen = signature.len;
+    return rv;
+}
+
+#ifdef NSS_ENABLE_ECC
+static SECStatus
+nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen,
+                    void *dataBuf, unsigned int dataLen)
+{
+    SECItem signature, digest;
+    NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
+
+    signature.data = (unsigned char *)sigBuf;
+    signature.len = sigLen;
+    digest.data = (unsigned char *)dataBuf;
+    digest.len = dataLen;
+    return ECDSA_VerifyDigest(&(key->u.ec), &signature, &digest);
+}
+
+static SECStatus
+nsc_ECDSASignStub(void *ctx, void *sigBuf,
+                  unsigned int *sigLen, unsigned int maxSigLen,
+                  void *dataBuf, unsigned int dataLen)
+{
+    SECItem signature, digest;
+    SECStatus rv;
+    NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
+
+    signature.data = (unsigned char *)sigBuf;
+    signature.len = maxSigLen;
+    digest.data = (unsigned char *)dataBuf;
+    digest.len = dataLen;
+    rv = ECDSA_SignDigest(&(key->u.ec), &signature, &digest);
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+	sftk_fatalError = PR_TRUE;
+    }
+    *sigLen = signature.len;
+    return rv;
+}
+#endif /* NSS_ENABLE_ECC */
+
+/* NSC_SignInit setups up the signing operations. There are three basic
+ * types of signing:
+ *	(1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied
+ *  to data in a single Sign operation (which often looks a lot like an
+ *  encrypt, with data coming in and data going out).
+ *	(2) Hash based signing, where we continually hash the data, then apply
+ *  some sort of signature to the end.
+ *	(3) Block Encryption CBC MAC's, where the Data is encrypted with a key,
+ *  and only the final block is part of the mac.
+ *
+ *  For case number 3, we initialize a context much like the Encryption Context
+ *  (in fact we share code). We detect case 3 in C_SignUpdate, C_Sign, and 
+ *  C_Final by the following method... if it's not multi-part, and it's doesn't
+ *  have a hash context, it must be a block Encryption CBC MAC.
+ *
+ *  For case number 2, we initialize a hash structure, as well as make it 
+ *  multi-part. Updates are simple calls to the hash update function. Final
+ *  calls the hashend, then passes the result to the 'update' function (which
+ *  operates as a final signature function). In some hash based MAC'ing (as
+ *  opposed to hash base signatures), the update function is can be simply a 
+ *  copy (as is the case with HMAC).
+ */
+CK_RV NSC_SignInit(CK_SESSION_HANDLE hSession,
+		 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+    SFTKSession *session;
+    SFTKObject *key;
+    SFTKSessionContext *context;
+    CK_KEY_TYPE key_type;
+    CK_RV crv = CKR_OK;
+    NSSLOWKEYPrivateKey *privKey;
+    SFTKHashSignInfo *info = NULL;
+
+    CHECK_FORK();
+
+    /* Block Cipher MACing Algorithms use a different Context init method..*/
+    crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, SFTK_SIGN);
+    if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
+
+    /* we're not using a block cipher mac */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    crv = sftk_InitGeneric(session,&context,SFTK_SIGN,&key,hKey,&key_type,
+						CKO_PRIVATE_KEY,CKA_SIGN);
+    if (crv != CKR_OK) {
+	sftk_FreeSession(session);
+	return crv;
+    }
+
+    context->multi = PR_FALSE;
+
+#define INIT_RSA_SIGN_MECH(mmm) \
+    case CKM_ ## mmm ## _RSA_PKCS: \
+        context->multi = PR_TRUE; \
+	crv = sftk_doSub ## mmm (context); \
+	if (crv != CKR_OK) break; \
+	context->update = (SFTKCipher) sftk_HashSign; \
+	info = PORT_New(SFTKHashSignInfo); \
+	if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
+	info->hashOid = SEC_OID_ ## mmm ; \
+	goto finish_rsa; 
+
+    switch(pMechanism->mechanism) {
+    INIT_RSA_SIGN_MECH(MD5)
+    INIT_RSA_SIGN_MECH(MD2)
+    INIT_RSA_SIGN_MECH(SHA1)
+    INIT_RSA_SIGN_MECH(SHA256)
+    INIT_RSA_SIGN_MECH(SHA384)
+    INIT_RSA_SIGN_MECH(SHA512)
+
+    case CKM_RSA_PKCS:
+	context->update = (SFTKCipher) RSA_Sign;
+	goto finish_rsa;
+    case CKM_RSA_X_509:
+	context->update = (SFTKCipher)  RSA_SignRaw;
+finish_rsa:
+	if (key_type != CKK_RSA) {
+	    if (info) PORT_Free(info);
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
+	if (privKey == NULL) {
+	    if (info) PORT_Free(info);
+	    break;
+	}
+	/* OK, info is allocated only if we're doing hash and sign mechanism.
+	 * It's necessary to be able to set the correct OID in the final 
+	 * signature.
+	 */
+	if (info) {
+	    info->key = privKey;
+	    context->cipherInfo = info;
+	    context->destroy = (SFTKDestroy)sftk_Space;
+	} else {
+	    context->cipherInfo = privKey;
+	    context->destroy = (SFTKDestroy)sftk_Null;
+	}
+	context->maxLen = nsslowkey_PrivateModulusLen(privKey);
+	break;
+
+    case CKM_DSA_SHA1:
+        context->multi = PR_TRUE;
+	crv = sftk_doSubSHA1(context);
+	if (crv != CKR_OK) break;
+	/* fall through */
+    case CKM_DSA:
+	if (key_type != CKK_DSA) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	privKey = sftk_GetPrivKey(key,CKK_DSA,&crv);
+	if (privKey == NULL) {
+	    break;
+	}
+	context->cipherInfo = privKey;
+	context->update     = (SFTKCipher) nsc_DSA_Sign_Stub;
+	context->destroy    = (privKey == key->objectInfo) ?
+		(SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
+	context->maxLen     = DSA_SIGNATURE_LEN;
+
+	break;
+
+#ifdef NSS_ENABLE_ECC
+    case CKM_ECDSA_SHA1:
+	context->multi = PR_TRUE;
+	crv = sftk_doSubSHA1(context);
+	if (crv != CKR_OK) break;
+	/* fall through */
+    case CKM_ECDSA:
+	if (key_type != CKK_EC) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	privKey = sftk_GetPrivKey(key,CKK_EC,&crv);
+	if (privKey == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->cipherInfo = privKey;
+	context->update     = (SFTKCipher) nsc_ECDSASignStub;
+	context->destroy    = (privKey == key->objectInfo) ?
+		(SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
+	context->maxLen     = MAX_ECKEY_LEN * 2;
+
+	break;
+#endif /* NSS_ENABLE_ECC */
+
+#define INIT_HMAC_MECH(mmm) \
+    case CKM_ ## mmm ## _HMAC_GENERAL: \
+	crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, \
+				*(CK_ULONG *)pMechanism->pParameter); \
+	break; \
+    case CKM_ ## mmm ## _HMAC: \
+	crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, mmm ## _LENGTH); \
+	break; 
+
+    INIT_HMAC_MECH(MD2)
+    INIT_HMAC_MECH(MD5)
+    INIT_HMAC_MECH(SHA256)
+    INIT_HMAC_MECH(SHA384)
+    INIT_HMAC_MECH(SHA512)
+
+    case CKM_SHA_1_HMAC_GENERAL:
+	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
+				*(CK_ULONG *)pMechanism->pParameter);
+	break;
+    case CKM_SHA_1_HMAC:
+	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
+	break;
+
+    case CKM_SSL3_MD5_MAC:
+	crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
+					*(CK_ULONG *)pMechanism->pParameter);
+	break;
+    case CKM_SSL3_SHA1_MAC:
+	crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
+					*(CK_ULONG *)pMechanism->pParameter);
+	break;
+    case CKM_TLS_PRF_GENERAL:
+	crv = sftk_TLSPRFInit(context, key, key_type);
+	break;
+    default:
+	crv = CKR_MECHANISM_INVALID;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+        sftk_FreeContext(context);
+	sftk_FreeSession(session);
+	return crv;
+    }
+    sftk_SetContextByType(session, SFTK_SIGN, context);
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+
+/* MACUpdate is the common implementation for SignUpdate and VerifyUpdate.
+ * (sign and verify only very in their setup and final operations) */
+static CK_RV 
+sftk_MACUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
+    					CK_ULONG ulPartLen,SFTKContextType type)
+{
+    unsigned int outlen;
+    SFTKSessionContext *context;
+    CK_RV crv;
+    SECStatus rv;
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,type,PR_TRUE,NULL);
+    if (crv != CKR_OK) return crv;
+
+    if (context->hashInfo) {
+	(*context->hashUpdate)(context->hashInfo, pPart, ulPartLen);
+	return CKR_OK;
+    }
+
+    /* must be block cipher macing */
+
+    /* deal with previous buffered data */
+    if (context->padDataLength != 0) {
+	int i;
+	/* fill in the padded to a full block size */
+	for (i=context->padDataLength; (ulPartLen != 0) && 
+					i < (int)context->blockSize; i++) {
+	    context->padBuf[i] = *pPart++;
+	    ulPartLen--;
+	    context->padDataLength++;
+	}
+
+	/* not enough data to encrypt yet? then return */
+	if (context->padDataLength != context->blockSize)  return CKR_OK;
+	/* encrypt the current padded data */
+    	rv = (*context->update)(context->cipherInfo,context->macBuf,&outlen,
+			SFTK_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
+    	if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
+    }
+
+    /* save the residual */
+    context->padDataLength = ulPartLen % context->blockSize;
+    if (context->padDataLength) {
+	PORT_Memcpy(context->padBuf,
+		    &pPart[ulPartLen-context->padDataLength],
+		    context->padDataLength);
+	ulPartLen -= context->padDataLength;
+    }
+
+    /* if we've exhausted our new buffer, we're done */
+    if (ulPartLen == 0) { return CKR_OK; }
+
+    /* run the data through out encrypter */	
+    while (ulPartLen) {
+    	rv = (*context->update)(context->cipherInfo, context->padBuf, &outlen, 
+			SFTK_MAX_BLOCK_SIZE, pPart, context->blockSize);
+	if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
+	/* paranoia.. make sure we exit the loop */
+	PORT_Assert(ulPartLen >= context->blockSize);
+	if (ulPartLen < context->blockSize) break;
+	ulPartLen -= context->blockSize;
+    }
+
+    return CKR_OK;
+	
+}
+
+/* NSC_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+CK_RV NSC_SignUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
+    							CK_ULONG ulPartLen)
+{
+    CHECK_FORK();
+
+    return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_SIGN);
+}
+
+
+/* NSC_SignFinal finishes a multiple-part signature operation, 
+ * returning the signature. */
+CK_RV NSC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature,
+					    CK_ULONG_PTR pulSignatureLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen;
+    unsigned int digestLen;
+    unsigned int maxoutlen = *pulSignatureLen;
+    unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
+    CK_RV crv;
+    SECStatus rv = SECSuccess;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    *pulSignatureLen = 0;
+    crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_TRUE,&session);
+    if (crv != CKR_OK) return crv;
+
+    if (!pSignature) {
+	*pulSignatureLen = context->maxLen;
+	goto finish;
+    } else if (context->hashInfo) {
+        (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
+	rv = (*context->update)(context->cipherInfo, pSignature,
+					&outlen, maxoutlen, tmpbuf, digestLen);
+        *pulSignatureLen = (CK_ULONG) outlen;
+    } else {
+	/* deal with the last block if any residual */
+	if (context->padDataLength) {
+	    /* fill out rest of pad buffer with pad magic*/
+	    int i;
+	    for (i=context->padDataLength; i < (int)context->blockSize; i++) {
+		context->padBuf[i] = 0;
+	    }
+	    rv = (*context->update)(context->cipherInfo,context->macBuf,
+		&outlen,SFTK_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
+	}
+	if (rv == SECSuccess) {
+	    PORT_Memcpy(pSignature,context->macBuf,context->macSize);
+	    *pulSignatureLen = context->macSize;
+	}
+    }
+
+    sftk_FreeContext(context);
+    sftk_SetContextByType(session, SFTK_SIGN, NULL);
+
+finish:
+    sftk_FreeSession(session);
+
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+}
+
+/* NSC_Sign signs (encrypts with private key) data in a single part,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+CK_RV NSC_Sign(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,
+    					CK_ULONG_PTR pulSignatureLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen;
+    unsigned int maxoutlen = *pulSignatureLen;
+    CK_RV crv,crv2;
+    SECStatus rv = SECSuccess;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_FALSE,&session);
+    if (crv != CKR_OK) return crv;
+
+    if (!pSignature) {
+	*pulSignatureLen = context->maxLen;
+	goto finish;
+    }
+
+    /* multi part Signing are completely implemented by SignUpdate and
+     * sign Final */
+    if (context->multi) {
+        sftk_FreeSession(session);
+	crv = NSC_SignUpdate(hSession,pData,ulDataLen);
+	if (crv != CKR_OK) *pulSignatureLen = 0;
+	crv2 = NSC_SignFinal(hSession, pSignature, pulSignatureLen);
+	return crv == CKR_OK ? crv2 :crv;
+    }
+
+    rv = (*context->update)(context->cipherInfo, pSignature,
+					&outlen, maxoutlen, pData, ulDataLen);
+    *pulSignatureLen = (CK_ULONG) outlen;
+    sftk_FreeContext(context);
+    sftk_SetContextByType(session, SFTK_SIGN, NULL);
+
+finish:
+    sftk_FreeSession(session);
+
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+}
+
+
+/*
+ ************** Crypto Functions:     Sign Recover  ************************
+ */
+/* NSC_SignRecoverInit initializes a signature operation,
+ * where the (digest) data can be recovered from the signature. 
+ * E.g. encryption with the user's private key */
+CK_RV NSC_SignRecoverInit(CK_SESSION_HANDLE hSession,
+			 CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
+{
+    CHECK_FORK();
+
+    switch (pMechanism->mechanism) {
+    case CKM_RSA_PKCS:
+    case CKM_RSA_X_509:
+	return NSC_SignInit(hSession,pMechanism,hKey);
+    default:
+	break;
+    }
+    return CKR_MECHANISM_INVALID;
+}
+
+
+/* NSC_SignRecover signs data in a single operation
+ * where the (digest) data can be recovered from the signature. 
+ * E.g. encryption with the user's private key */
+CK_RV NSC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+  CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+    CHECK_FORK();
+
+    return NSC_Sign(hSession,pData,ulDataLen,pSignature,pulSignatureLen);
+}
+
+/*
+ ************** Crypto Functions:     verify  ************************
+ */
+
+/* Handle RSA Signature formatting */
+static SECStatus
+sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, 
+	unsigned int sigLen, unsigned char *digest, unsigned int digestLen)
+{
+    return RSA_HashCheckSign(info->hashOid, info->key, sig, sigLen,
+						digest, digestLen);
+}
+
+SECStatus
+RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
+	unsigned char *sig, unsigned int sigLen,
+	unsigned char *digest, unsigned int digestLen)
+{
+
+    SECItem it;
+    SGNDigestInfo *di = NULL;
+    SECStatus rv = SECSuccess;
+    
+    it.data = NULL;
+
+    if (key == NULL) goto loser;
+
+    it.len = nsslowkey_PublicModulusLen(key); 
+    if (!it.len) goto loser;
+
+    it.data = (unsigned char *) PORT_Alloc(it.len);
+    if (it.data == NULL) goto loser;
+
+    /* decrypt the block */
+    rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen);
+    if (rv != SECSuccess) goto loser;
+
+    di = SGN_DecodeDigestInfo(&it);
+    if (di == NULL) goto loser;
+    if (di->digest.len != digestLen)  goto loser; 
+
+    /* make sure the tag is OK */
+    if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) {
+	goto loser;
+    }
+    /* make sure the "parameters" are not too bogus. */
+    if (di->digestAlgorithm.parameters.len > 2) {
+	goto loser;
+    }
+    /* Now check the signature */
+    if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) {
+	goto done;
+    }
+
+  loser:
+    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+    rv = SECFailure;
+
+  done:
+    if (it.data != NULL) PORT_Free(it.data);
+    if (di != NULL) SGN_DestroyDigestInfo(di);
+    
+    return rv;
+}
+
+/* NSC_VerifyInit initializes a verification operation, 
+ * where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature (e.g. DSA) */
+CK_RV NSC_VerifyInit(CK_SESSION_HANDLE hSession,
+			   CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) 
+{
+    SFTKSession *session;
+    SFTKObject *key;
+    SFTKSessionContext *context;
+    CK_KEY_TYPE key_type;
+    CK_RV crv = CKR_OK;
+    NSSLOWKEYPublicKey *pubKey;
+    SFTKHashVerifyInfo *info = NULL;
+
+    CHECK_FORK();
+
+    /* Block Cipher MACing Algorithms use a different Context init method..*/
+    crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_VERIFY, SFTK_VERIFY);
+    if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    crv = sftk_InitGeneric(session,&context,SFTK_VERIFY,&key,hKey,&key_type,
+						CKO_PUBLIC_KEY,CKA_VERIFY);
+    if (crv != CKR_OK) {
+	sftk_FreeSession(session);
+	return crv;
+    }
+
+    context->multi = PR_FALSE;
+
+#define INIT_RSA_VFY_MECH(mmm) \
+    case CKM_ ## mmm ## _RSA_PKCS: \
+        context->multi = PR_TRUE; \
+	crv = sftk_doSub ## mmm (context); \
+	if (crv != CKR_OK) break; \
+	context->verify = (SFTKVerify) sftk_hashCheckSign; \
+	info = PORT_New(SFTKHashVerifyInfo); \
+	if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
+	info->hashOid = SEC_OID_ ## mmm ; \
+	goto finish_rsa; 
+
+    switch(pMechanism->mechanism) {
+    INIT_RSA_VFY_MECH(MD5) 
+    INIT_RSA_VFY_MECH(MD2) 
+    INIT_RSA_VFY_MECH(SHA1) 
+    INIT_RSA_VFY_MECH(SHA256) 
+    INIT_RSA_VFY_MECH(SHA384) 
+    INIT_RSA_VFY_MECH(SHA512) 
+
+    case CKM_RSA_PKCS:
+	context->verify = (SFTKVerify) RSA_CheckSign;
+	goto finish_rsa;
+    case CKM_RSA_X_509:
+	context->verify = (SFTKVerify) RSA_CheckSignRaw;
+finish_rsa:
+	if (key_type != CKK_RSA) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
+	if (pubKey == NULL) {
+	    break;
+	}
+	if (info) {
+	    info->key = pubKey;
+	    context->cipherInfo = info;
+	    context->destroy = sftk_Space;
+	} else {
+	    context->cipherInfo = pubKey;
+	    context->destroy = sftk_Null;
+	}
+	break;
+    case CKM_DSA_SHA1:
+        context->multi = PR_TRUE;
+	crv = sftk_doSubSHA1(context);
+	if (crv != CKR_OK) break;
+	/* fall through */
+    case CKM_DSA:
+	if (key_type != CKK_DSA) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	pubKey = sftk_GetPubKey(key,CKK_DSA,&crv);
+	if (pubKey == NULL) {
+	    break;
+	}
+	context->cipherInfo = pubKey;
+	context->verify     = (SFTKVerify) nsc_DSA_Verify_Stub;
+	context->destroy    = sftk_Null;
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKM_ECDSA_SHA1:
+	context->multi = PR_TRUE;
+	crv = sftk_doSubSHA1(context);
+	if (crv != CKR_OK) break;
+	/* fall through */
+    case CKM_ECDSA:
+	if (key_type != CKK_EC) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	pubKey = sftk_GetPubKey(key,CKK_EC,&crv);
+	if (pubKey == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	context->cipherInfo = pubKey;
+	context->verify     = (SFTKVerify) nsc_ECDSAVerifyStub;
+	context->destroy    = sftk_Null;
+	break;
+#endif /* NSS_ENABLE_ECC */
+
+    INIT_HMAC_MECH(MD2)
+    INIT_HMAC_MECH(MD5)
+    INIT_HMAC_MECH(SHA256)
+    INIT_HMAC_MECH(SHA384)
+    INIT_HMAC_MECH(SHA512)
+
+    case CKM_SHA_1_HMAC_GENERAL:
+	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
+				*(CK_ULONG *)pMechanism->pParameter);
+	break;
+    case CKM_SHA_1_HMAC:
+	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
+	break;
+
+    case CKM_SSL3_MD5_MAC:
+	crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
+					*(CK_ULONG *)pMechanism->pParameter);
+	break;
+    case CKM_SSL3_SHA1_MAC:
+	crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
+					*(CK_ULONG *)pMechanism->pParameter);
+	break;
+    case CKM_TLS_PRF_GENERAL:
+	crv = sftk_TLSPRFInit(context, key, key_type);
+	break;
+
+    default:
+	crv = CKR_MECHANISM_INVALID;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+	if (info) PORT_Free(info);
+        PORT_Free(context);
+	sftk_FreeSession(session);
+	return crv;
+    }
+    sftk_SetContextByType(session, SFTK_VERIFY, context);
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+/* NSC_Verify verifies a signature in a single-part operation, 
+ * where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+CK_RV NSC_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+    CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    CK_RV crv, crv2;
+    SECStatus rv;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_FALSE,&session);
+    if (crv != CKR_OK) return crv;
+
+    /* multi part Verifying are completely implemented by VerifyUpdate and
+     * VerifyFinal */
+    if (context->multi) {
+	sftk_FreeSession(session);
+	crv = NSC_VerifyUpdate(hSession, pData, ulDataLen);
+	crv2 = NSC_VerifyFinal(hSession, pSignature, ulSignatureLen);
+	return crv == CKR_OK ? crv2 :crv;
+    }
+
+    rv = (*context->verify)(context->cipherInfo,pSignature, ulSignatureLen,
+							 pData, ulDataLen);
+    sftk_FreeContext(context);
+    sftk_SetContextByType(session, SFTK_VERIFY, NULL);
+    sftk_FreeSession(session);
+
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapVerifyError(PORT_GetError());
+
+}
+
+
+/* NSC_VerifyUpdate continues a multiple-part verification operation, 
+ * where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature */
+CK_RV NSC_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+						CK_ULONG ulPartLen)
+{
+    CHECK_FORK();
+
+    return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_VERIFY);
+}
+
+
+/* NSC_VerifyFinal finishes a multiple-part verification operation, 
+ * checking the signature. */
+CK_RV NSC_VerifyFinal(CK_SESSION_HANDLE hSession,
+			CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen;
+    unsigned int digestLen;
+    unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
+    CK_RV crv;
+    SECStatus rv = SECSuccess;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_TRUE,&session);
+    if (crv != CKR_OK) return crv;
+
+    if (context->hashInfo) {
+        (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
+	rv = (*context->verify)(context->cipherInfo, pSignature, 
+					ulSignatureLen, tmpbuf, digestLen);
+    } else {
+	if (context->padDataLength) {
+	    /* fill out rest of pad buffer with pad magic*/
+	    int i;
+	    for (i=context->padDataLength; i < (int)context->blockSize; i++) {
+		context->padBuf[i] = 0;
+	    }
+	    rv = (*context->update)(context->cipherInfo,context->macBuf, 
+		&outlen,SFTK_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
+	}
+	if (rv == SECSuccess) {
+	    rv =(PORT_Memcmp(pSignature,context->macBuf,context->macSize) == 0)
+				 ? SECSuccess : SECFailure;
+	}
+    }
+
+    sftk_FreeContext(context);
+    sftk_SetContextByType(session, SFTK_VERIFY, NULL);
+    sftk_FreeSession(session);
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapVerifyError(PORT_GetError());
+
+}
+
+/*
+ ************** Crypto Functions:     Verify  Recover ************************
+ */
+
+/* NSC_VerifyRecoverInit initializes a signature verification operation, 
+ * where the data is recovered from the signature. 
+ * E.g. Decryption with the user's public key */
+CK_RV NSC_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
+{
+    SFTKSession *session;
+    SFTKObject *key;
+    SFTKSessionContext *context;
+    CK_KEY_TYPE key_type;
+    CK_RV crv = CKR_OK;
+    NSSLOWKEYPublicKey *pubKey;
+
+    CHECK_FORK();
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+    crv = sftk_InitGeneric(session,&context,SFTK_VERIFY_RECOVER,
+			&key,hKey,&key_type,CKO_PUBLIC_KEY,CKA_VERIFY_RECOVER);
+    if (crv != CKR_OK) {
+	sftk_FreeSession(session);
+	return crv;
+    }
+
+    context->multi = PR_TRUE;
+
+    switch(pMechanism->mechanism) {
+    case CKM_RSA_PKCS:
+    case CKM_RSA_X_509:
+	if (key_type != CKK_RSA) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	context->multi = PR_FALSE;
+	pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
+	if (pubKey == NULL) {
+	    break;
+	}
+	context->cipherInfo = pubKey;
+	context->update = (SFTKCipher) (pMechanism->mechanism == CKM_RSA_X_509
+			? RSA_CheckSignRecoverRaw : RSA_CheckSignRecover);
+	context->destroy = sftk_Null;
+	break;
+    default:
+	crv = CKR_MECHANISM_INVALID;
+	break;
+    }
+
+    if (crv != CKR_OK) {
+        PORT_Free(context);
+	sftk_FreeSession(session);
+	return crv;
+    }
+    sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, context);
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+
+/* NSC_VerifyRecover verifies a signature in a single-part operation, 
+ * where the data is recovered from the signature. 
+ * E.g. Decryption with the user's public key */
+CK_RV NSC_VerifyRecover(CK_SESSION_HANDLE hSession,
+		 CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen,
+    				CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)
+{
+    SFTKSession *session;
+    SFTKSessionContext *context;
+    unsigned int outlen;
+    unsigned int maxoutlen = *pulDataLen;
+    CK_RV crv;
+    SECStatus rv;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession,&context,SFTK_VERIFY_RECOVER,
+							PR_FALSE,&session);
+    if (crv != CKR_OK) return crv;
+    if (pData == NULL) {
+	/* to return the actual size, we need  to do the decrypt, just return
+	 * the max size, which is the size of the input signature. */
+	*pulDataLen = ulSignatureLen;
+	rv = SECSuccess;
+	goto finish;
+    }
+
+    rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
+						pSignature, ulSignatureLen);
+    *pulDataLen = (CK_ULONG) outlen;
+
+    sftk_FreeContext(context);
+    sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, NULL);
+finish:
+    sftk_FreeSession(session);
+    return (rv == SECSuccess)  ? CKR_OK : sftk_MapVerifyError(PORT_GetError());
+}
+
+/*
+ **************************** Random Functions:  ************************
+ */
+
+/* NSC_SeedRandom mixes additional seed material into the token's random number 
+ * generator. */
+CK_RV NSC_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
+    CK_ULONG ulSeedLen) 
+{
+    SECStatus rv;
+
+    CHECK_FORK();
+
+    rv = RNG_RandomUpdate(pSeed, ulSeedLen);
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+}
+
+/* NSC_GenerateRandom generates random data. */
+CK_RV NSC_GenerateRandom(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR	pRandomData, CK_ULONG ulRandomLen)
+{
+    SECStatus rv;
+
+    CHECK_FORK();
+
+    rv = RNG_GenerateGlobalRandomBytes(pRandomData, ulRandomLen);
+    /*
+     * This may fail with SEC_ERROR_NEED_RANDOM, which means the RNG isn't
+     * seeded with enough entropy.
+     */
+    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+}
+
+/*
+ **************************** Key Functions:  ************************
+ */
+
+
+/*
+ * generate a password based encryption key. This code uses
+ * PKCS5 to do the work.
+ */
+static CK_RV
+nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
+			void *buf, CK_ULONG *key_length, PRBool faulty3DES)
+{
+    SECItem *pbe_key = NULL, iv, pwitem;
+    CK_PBE_PARAMS *pbe_params = NULL;
+    CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
+
+    *key_length = 0;
+    iv.data = NULL; iv.len = 0;
+
+    if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
+	pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
+	pwitem.data = (unsigned char *)pbkd2_params->pPassword;
+	/* was this a typo in the PKCS #11 spec? */
+	pwitem.len = *pbkd2_params->ulPasswordLen;
+    } else {
+	pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
+	pwitem.data = (unsigned char *)pbe_params->pPassword;
+	pwitem.len = pbe_params->ulPasswordLen;
+    }
+    pbe_key = nsspkcs5_ComputeKeyAndIV(pkcs5_pbe, &pwitem, &iv, faulty3DES);
+    if (pbe_key == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    PORT_Memcpy(buf, pbe_key->data, pbe_key->len);
+    *key_length = pbe_key->len;
+    SECITEM_ZfreeItem(pbe_key, PR_TRUE);
+    pbe_key = NULL;
+
+    if (iv.data) {
+        if (pbe_params && pbe_params->pInitVector != NULL) {
+	    PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len);
+        }
+        PORT_Free(iv.data);
+    }
+
+    return CKR_OK;
+}
+static CK_RV
+nsc_parameter_gen(CK_KEY_TYPE key_type, SFTKObject *key)
+{
+    SFTKAttribute *attribute;
+    CK_ULONG counter;
+    unsigned int seedBits = 0;
+    unsigned int primeBits;
+    unsigned int j;
+    CK_RV crv = CKR_OK;
+    PQGParams *params = NULL;
+    PQGVerify *vfy = NULL;
+    SECStatus rv;
+
+    attribute = sftk_FindAttribute(key, CKA_PRIME_BITS);
+    if (attribute == NULL) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    primeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+    j = PQG_PBITS_TO_INDEX(primeBits);
+    if (j == (unsigned int)-1) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    attribute = sftk_FindAttribute(key, CKA_NETSCAPE_PQG_SEED_BITS);
+    if (attribute != NULL) {
+	seedBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
+	sftk_FreeAttribute(attribute);
+    }
+
+    sftk_DeleteAttributeType(key,CKA_PRIME_BITS);
+    sftk_DeleteAttributeType(key,CKA_NETSCAPE_PQG_SEED_BITS);
+
+    if (seedBits == 0) {
+	rv = PQG_ParamGen(j, &params, &vfy);
+    } else {
+	rv = PQG_ParamGenSeedLen(j,seedBits/8, &params, &vfy);
+    }
+
+    if (rv != SECSuccess) {
+	if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+	    sftk_fatalError = PR_TRUE;
+	}
+	return sftk_MapCryptError(PORT_GetError());
+    }
+    crv = sftk_AddAttributeType(key,CKA_PRIME,
+				 params->prime.data, params->prime.len);
+    if (crv != CKR_OK) goto loser;
+    crv = sftk_AddAttributeType(key,CKA_SUBPRIME,
+				 params->subPrime.data, params->subPrime.len);
+    if (crv != CKR_OK) goto loser;
+    crv = sftk_AddAttributeType(key,CKA_BASE,
+				 params->base.data, params->base.len);
+    if (crv != CKR_OK) goto loser;
+    counter = vfy->counter;
+    crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_COUNTER,
+				 &counter, sizeof(counter));
+    crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_SEED,
+				 vfy->seed.data, vfy->seed.len);
+    if (crv != CKR_OK) goto loser;
+    crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_H,
+				 vfy->h.data, vfy->h.len);
+    if (crv != CKR_OK) goto loser;
+
+loser:
+    if (params) {
+	PQG_DestroyParams(params);
+    }
+    if (vfy) {
+	PQG_DestroyVerify(vfy);
+    }
+    return crv;
+}
+
+
+static CK_RV
+nsc_SetupBulkKeyGen(CK_MECHANISM_TYPE mechanism, CK_KEY_TYPE *key_type,
+							CK_ULONG *key_length)
+{
+    CK_RV crv = CKR_OK;
+
+    switch (mechanism) {
+    case CKM_RC2_KEY_GEN:
+	*key_type = CKK_RC2;
+	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
+	break;
+#if NSS_SOFTOKEN_DOES_RC5
+    case CKM_RC5_KEY_GEN:
+	*key_type = CKK_RC5;
+	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
+	break;
+#endif
+    case CKM_RC4_KEY_GEN:
+	*key_type = CKK_RC4;
+	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
+	break;
+    case CKM_GENERIC_SECRET_KEY_GEN:
+	*key_type = CKK_GENERIC_SECRET;
+	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
+	break;
+    case CKM_CDMF_KEY_GEN:
+	*key_type = CKK_CDMF;
+	*key_length = 8;
+	break;
+    case CKM_DES_KEY_GEN:
+	*key_type = CKK_DES;
+	*key_length = 8;
+	break;
+    case CKM_DES2_KEY_GEN:
+	*key_type = CKK_DES2;
+	*key_length = 16;
+	break;
+    case CKM_DES3_KEY_GEN:
+	*key_type = CKK_DES3;
+	*key_length = 24;
+	break;
+    case CKM_SEED_KEY_GEN:
+	*key_type = CKK_SEED;
+	*key_length = 16;
+	break;
+    case CKM_CAMELLIA_KEY_GEN:
+	*key_type = CKK_CAMELLIA;
+	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
+	break;
+    case CKM_AES_KEY_GEN:
+	*key_type = CKK_AES;
+	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
+	break;
+    default:
+	PORT_Assert(0);
+	crv = CKR_MECHANISM_INVALID;
+	break;
+    }
+
+    return crv;
+}
+
+CK_RV
+nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe)
+{
+    SECItem  salt;
+    CK_PBE_PARAMS *pbe_params = NULL;
+    NSSPKCS5PBEParameter *params;
+    PRArenaPool *arena = NULL;
+    SECStatus rv;
+
+    *pbe = NULL;
+
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (arena == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    params = (NSSPKCS5PBEParameter *) PORT_ArenaZAlloc(arena,
+				sizeof(NSSPKCS5PBEParameter));
+    if (params == NULL) {
+	PORT_FreeArena(arena,PR_TRUE);
+	return CKR_HOST_MEMORY;
+    }
+
+    params->poolp = arena;
+    params->ivLen = 0;
+    params->pbeType = NSSPKCS5_PKCS12_V2;
+    params->hashType = HASH_AlgSHA1;
+    params->encAlg = SEC_OID_SHA1; /* any invalid value */
+    params->is2KeyDES = PR_FALSE;
+    params->keyID = pbeBitGenIntegrityKey;
+    pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
+    params->iter = pbe_params->ulIteration;
+
+    salt.data = (unsigned char *)pbe_params->pSalt;
+    salt.len = (unsigned int)pbe_params->ulSaltLen;
+    rv = SECITEM_CopyItem(arena,&params->salt,&salt);
+    if (rv != SECSuccess) {
+	PORT_FreeArena(arena,PR_TRUE);
+	return CKR_HOST_MEMORY;
+    }
+    switch (pMechanism->mechanism) {
+    case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
+    case CKM_PBA_SHA1_WITH_SHA1_HMAC:
+	params->hashType = HASH_AlgSHA1; 
+	params->keyLen = 20;
+	break;
+    case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
+	params->hashType = HASH_AlgMD5; 
+	params->keyLen = 16;
+	break;
+    case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
+	params->hashType = HASH_AlgMD2; 
+	params->keyLen = 16;
+	break;
+    default:
+	PORT_FreeArena(arena,PR_TRUE);
+	return CKR_MECHANISM_INVALID;
+    }
+    *pbe = params;
+    return CKR_OK;
+}
+
+/* maybe this should be table driven? */
+static CK_RV
+nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter  **pbe,
+				CK_KEY_TYPE *key_type, CK_ULONG *key_length)
+{
+    CK_RV crv = CKR_OK;
+    SECOidData *oid;
+    CK_PBE_PARAMS *pbe_params = NULL;
+    NSSPKCS5PBEParameter *params = NULL;
+    CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
+    SECItem salt;
+    CK_ULONG iteration = 0;
+
+    *pbe = NULL;
+
+    oid = SECOID_FindOIDByMechanism(pMechanism->mechanism);
+    if (oid == NULL) {
+	return CKR_MECHANISM_INVALID;
+    }
+
+    if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
+	pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
+	if (pbkd2_params->saltSource != CKZ_SALT_SPECIFIED) {
+	    return CKR_MECHANISM_PARAM_INVALID;
+	}
+	salt.data = (unsigned char *)pbkd2_params->pSaltSourceData;
+	salt.len = (unsigned int)pbkd2_params->ulSaltSourceDataLen;
+	iteration = pbkd2_params->iterations;
+    } else {
+	pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
+	salt.data = (unsigned char *)pbe_params->pSalt;
+	salt.len = (unsigned int)pbe_params->ulSaltLen;
+	iteration = pbe_params->ulIteration;
+    }
+    params=nsspkcs5_NewParam(oid->offset, &salt, iteration);
+    if (params == NULL) {
+	return CKR_MECHANISM_INVALID;
+    }
+
+    switch (params->encAlg) {
+    case SEC_OID_DES_CBC:
+	*key_type = CKK_DES;
+	*key_length = params->keyLen;
+	break;
+    case SEC_OID_DES_EDE3_CBC:
+	*key_type = params->is2KeyDES ? CKK_DES2 : CKK_DES3;
+	*key_length = params->keyLen;
+	break;
+    case SEC_OID_RC2_CBC:
+	*key_type = CKK_RC2;
+	*key_length = params->keyLen;
+	break;
+    case SEC_OID_RC4:
+	*key_type = CKK_RC4;
+	*key_length = params->keyLen;
+	break;
+    case SEC_OID_PKCS5_PBKDF2:
+	/* sigh, PKCS #11 currently only defines SHA1 for the KDF hash type. 
+	 * we do the check here because this where we would handle multiple
+	 * hash types in the future */
+	if (pbkd2_params == NULL || 
+		pbkd2_params->prf != CKP_PKCS5_PBKD2_HMAC_SHA1) {
+	    crv = CKR_MECHANISM_PARAM_INVALID;
+	    break;
+	}
+	/* key type must already be set */
+	if (*key_type == CKK_INVALID_KEY_TYPE) {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    break;
+	}
+	/* PBKDF2 needs to calculate the key length from the other parameters
+	 */
+	if (*key_length == 0) {
+	    *key_length = sftk_MapKeySize(*key_type);
+	}
+	if (*key_length == 0) {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    break;
+	}
+	params->keyLen = *key_length;
+	break;
+    default:
+	crv = CKR_MECHANISM_INVALID;
+	nsspkcs5_DestroyPBEParameter(params);
+	break;
+    }
+    if (crv == CKR_OK) {
+    	*pbe = params;
+    }
+    return crv;
+}
+
+/* NSC_GenerateKey generates a secret key, creating a new key object. */
+CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,
+    						CK_OBJECT_HANDLE_PTR phKey)
+{
+    SFTKObject *key;
+    SFTKSession *session;
+    PRBool checkWeak = PR_FALSE;
+    CK_ULONG key_length = 0;
+    CK_KEY_TYPE key_type = CKK_INVALID_KEY_TYPE;
+    CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
+    CK_RV crv = CKR_OK;
+    CK_BBOOL cktrue = CK_TRUE;
+    int i;
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    unsigned char buf[MAX_KEY_LEN];
+    enum {nsc_pbe, nsc_ssl, nsc_bulk, nsc_param} key_gen_type;
+    NSSPKCS5PBEParameter *pbe_param;
+    SSL3RSAPreMasterSecret *rsa_pms;
+    CK_VERSION *version;
+    /* in very old versions of NSS, there were implementation errors with key 
+     * generation methods.  We want to beable to read these, but not 
+     * produce them any more.  The affected algorithm was 3DES.
+     */
+    PRBool faultyPBE3DES = PR_FALSE;
+
+    CHECK_FORK();
+
+    if (!slot) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * now lets create an object to hang the attributes off of
+     */
+    key = sftk_NewObject(slot); /* fill in the handle later */
+    if (key == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    /*
+     * load the template values into the object
+     */
+    for (i=0; i < (int) ulCount; i++) {
+	if (pTemplate[i].type == CKA_VALUE_LEN) {
+	    key_length = *(CK_ULONG *)pTemplate[i].pValue;
+	    continue;
+	}
+	/* some algorithms need keytype specified */
+	if (pTemplate[i].type == CKA_KEY_TYPE) {
+	    key_type = *(CK_ULONG *)pTemplate[i].pValue;
+	    continue;
+	}
+
+	crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
+	if (crv != CKR_OK) break;
+    }
+    if (crv != CKR_OK) {
+	sftk_FreeObject(key);
+	return crv;
+    }
+
+    /* make sure we don't have any class, key_type, or value fields */
+    sftk_DeleteAttributeType(key,CKA_CLASS);
+    sftk_DeleteAttributeType(key,CKA_KEY_TYPE);
+    sftk_DeleteAttributeType(key,CKA_VALUE);
+
+    /* Now Set up the parameters to generate the key (based on mechanism) */
+    key_gen_type = nsc_bulk; /* bulk key by default */
+    switch (pMechanism->mechanism) {
+    case CKM_CDMF_KEY_GEN:
+    case CKM_DES_KEY_GEN:
+    case CKM_DES2_KEY_GEN:
+    case CKM_DES3_KEY_GEN:
+	checkWeak = PR_TRUE;
+    case CKM_RC2_KEY_GEN:
+    case CKM_RC4_KEY_GEN:
+    case CKM_GENERIC_SECRET_KEY_GEN:
+    case CKM_SEED_KEY_GEN:
+    case CKM_CAMELLIA_KEY_GEN:
+    case CKM_AES_KEY_GEN:
+#if NSS_SOFTOKEN_DOES_RC5
+    case CKM_RC5_KEY_GEN:
+#endif
+	crv = nsc_SetupBulkKeyGen(pMechanism->mechanism,&key_type,&key_length);
+	break;
+    case CKM_SSL3_PRE_MASTER_KEY_GEN:
+	key_type = CKK_GENERIC_SECRET;
+	key_length = 48;
+	key_gen_type = nsc_ssl;
+	break;
+    case CKM_PBA_SHA1_WITH_SHA1_HMAC:
+    case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
+    case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
+    case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
+	key_gen_type = nsc_pbe;
+	key_type = CKK_GENERIC_SECRET;
+	crv = nsc_SetupHMACKeyGen(pMechanism, &pbe_param);
+	break;
+    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
+	faultyPBE3DES = PR_TRUE;
+    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
+    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
+    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
+    case CKM_PBE_SHA1_DES3_EDE_CBC:
+    case CKM_PBE_SHA1_DES2_EDE_CBC:
+    case CKM_PBE_SHA1_RC2_128_CBC:
+    case CKM_PBE_SHA1_RC2_40_CBC:
+    case CKM_PBE_SHA1_RC4_128:
+    case CKM_PBE_SHA1_RC4_40:
+    case CKM_PBE_MD5_DES_CBC:
+    case CKM_PBE_MD2_DES_CBC:
+    case CKM_PKCS5_PBKD2:
+	key_gen_type = nsc_pbe;
+	crv = nsc_SetupPBEKeyGen(pMechanism,&pbe_param, &key_type, &key_length);
+	break;
+    case CKM_DSA_PARAMETER_GEN:
+	key_gen_type = nsc_param;
+	key_type = CKK_DSA;
+	objclass = CKO_KG_PARAMETERS;
+	crv = CKR_OK;
+	break;
+    default:
+	crv = CKR_MECHANISM_INVALID;
+	break;
+    }
+
+    /* make sure we aren't going to overflow the buffer */
+    if (sizeof(buf) < key_length) {
+	/* someone is getting pretty optimistic about how big their key can
+	 * be... */
+        crv = CKR_TEMPLATE_INCONSISTENT;
+    }
+
+    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
+
+    /* if there was no error,
+     * key_type *MUST* be set in the switch statement above */
+    PORT_Assert( key_type != CKK_INVALID_KEY_TYPE );
+
+    /*
+     * now to the actual key gen.
+     */
+    switch (key_gen_type) {
+    case nsc_pbe:
+	crv = nsc_pbe_key_gen(pbe_param, pMechanism, buf, &key_length,
+			       faultyPBE3DES);
+	nsspkcs5_DestroyPBEParameter(pbe_param);
+	break;
+    case nsc_ssl:
+	rsa_pms = (SSL3RSAPreMasterSecret *)buf;
+	version = (CK_VERSION *)pMechanism->pParameter;
+	rsa_pms->client_version[0] = version->major;
+        rsa_pms->client_version[1] = version->minor;
+        crv = 
+	    NSC_GenerateRandom(0,&rsa_pms->random[0], sizeof(rsa_pms->random));
+	break;
+    case nsc_bulk:
+	/* get the key, check for weak keys and repeat if found */
+	do {
+            crv = NSC_GenerateRandom(0, buf, key_length);
+	} while (crv == CKR_OK && checkWeak && sftk_IsWeakKey(buf,key_type));
+	break;
+    case nsc_param:
+	/* generate parameters */
+	*buf = 0;
+	crv = nsc_parameter_gen(key_type,key);
+	break;
+    }
+
+    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
+
+    /* Add the class, key_type, and value */
+    crv = sftk_AddAttributeType(key,CKA_CLASS,&objclass,sizeof(CK_OBJECT_CLASS));
+    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
+    crv = sftk_AddAttributeType(key,CKA_KEY_TYPE,&key_type,sizeof(CK_KEY_TYPE));
+    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
+    if (key_length != 0) {
+	crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
+	if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
+    }
+
+    /* get the session */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+	sftk_FreeObject(key);
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    /*
+     * handle the base object stuff
+     */
+    crv = sftk_handleObject(key,session);
+    sftk_FreeSession(session);
+    if (sftk_isTrue(key,CKA_SENSITIVE)) {
+	sftk_forceAttribute(key,CKA_ALWAYS_SENSITIVE,&cktrue,sizeof(CK_BBOOL));
+    }
+    if (!sftk_isTrue(key,CKA_EXTRACTABLE)) {
+	sftk_forceAttribute(key,CKA_NEVER_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL));
+    }
+
+    *phKey = key->handle;
+    sftk_FreeObject(key);
+    return crv;
+}
+
+#define PAIRWISE_DIGEST_LENGTH			SHA1_LENGTH /* 160-bits */
+#define PAIRWISE_MESSAGE_LENGTH			20          /* 160-bits */
+
+/*
+ * FIPS 140-2 pairwise consistency check utilized to validate key pair.
+ *
+ * This function returns
+ *   CKR_OK               if pairwise consistency check passed
+ *   CKR_GENERAL_ERROR    if pairwise consistency check failed
+ *   other error codes    if paiswise consistency check could not be
+ *                        performed, for example, CKR_HOST_MEMORY.
+ */
+static CK_RV
+sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession,
+    SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType)
+{
+    /*
+     *                      Key type    Mechanism type
+     *                      --------------------------------
+     * For encrypt/decrypt: CKK_RSA  => CKM_RSA_PKCS
+     *                      others   => CKM_INVALID_MECHANISM
+     *
+     * For sign/verify:     CKK_RSA  => CKM_RSA_PKCS
+     *                      CKK_DSA  => CKM_DSA
+     *                      CKK_EC   => CKM_ECDSA
+     *                      others   => CKM_INVALID_MECHANISM
+     *
+     * None of these mechanisms has a parameter.
+     */
+    CK_MECHANISM mech = {0, NULL, 0};
+
+    CK_ULONG modulusLen;
+    PRBool isEncryptable = PR_FALSE;
+    PRBool canSignVerify = PR_FALSE;
+    PRBool isDerivable = PR_FALSE;
+    CK_RV crv;
+
+    /* Variables used for Encrypt/Decrypt functions. */
+    unsigned char *known_message = (unsigned char *)"Known Crypto Message";
+    unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH];
+    CK_ULONG bytes_decrypted;
+    unsigned char *ciphertext;
+    unsigned char *text_compared;
+    CK_ULONG bytes_encrypted;
+    CK_ULONG bytes_compared;
+
+    /* Variables used for Signature/Verification functions. */
+    /* always uses SHA-1 digest */
+    unsigned char *known_digest = (unsigned char *)"Mozilla Rules World!";
+    unsigned char *signature;
+    CK_ULONG signature_length;
+
+    if (keyType == CKK_RSA) {
+	SFTKAttribute *attribute;
+
+	/* Get modulus length of private key. */
+	attribute = sftk_FindAttribute(privateKey, CKA_MODULUS);
+	if (attribute == NULL) {
+	    return CKR_DEVICE_ERROR;
+	}
+	modulusLen = attribute->attrib.ulValueLen;
+	if (*(unsigned char *)attribute->attrib.pValue == 0) {
+	    modulusLen--;
+	}
+	sftk_FreeAttribute(attribute);
+    }
+
+    /**************************************************/
+    /* Pairwise Consistency Check of Encrypt/Decrypt. */
+    /**************************************************/
+
+    isEncryptable = sftk_isTrue(privateKey, CKA_DECRYPT); 
+
+    /*
+     * If the decryption attribute is set, attempt to encrypt
+     * with the public key and decrypt with the private key.
+     */
+    if (isEncryptable) {
+	if (keyType != CKK_RSA) {
+	    return CKR_DEVICE_ERROR;
+	}
+	bytes_encrypted = modulusLen;
+	mech.mechanism = CKM_RSA_PKCS;
+
+	/* Allocate space for ciphertext. */
+	ciphertext = (unsigned char *) PORT_ZAlloc(bytes_encrypted);
+	if (ciphertext == NULL) {
+	    return CKR_HOST_MEMORY;
+	}
+
+	/* Prepare for encryption using the public key. */
+	crv = NSC_EncryptInit(hSession, &mech, publicKey->handle);
+	if (crv != CKR_OK) {
+	    PORT_Free(ciphertext);
+	    return crv;
+	}
+
+	/* Encrypt using the public key. */
+	crv = NSC_Encrypt(hSession,
+			  known_message,
+			  PAIRWISE_MESSAGE_LENGTH,
+			  ciphertext,
+			  &bytes_encrypted);
+	if (crv != CKR_OK) {
+	    PORT_Free(ciphertext);
+	    return crv;
+	}
+
+	/* Always use the smaller of these two values . . . */
+	bytes_compared = PR_MIN(bytes_encrypted, PAIRWISE_MESSAGE_LENGTH);
+
+	/*
+	 * If there was a failure, the plaintext
+	 * goes at the end, therefore . . .
+	 */
+	text_compared = ciphertext + bytes_encrypted - bytes_compared;
+
+	/*
+	 * Check to ensure that ciphertext does
+	 * NOT EQUAL known input message text
+	 * per FIPS PUB 140-2 directive.
+	 */
+	if (PORT_Memcmp(text_compared, known_message,
+			bytes_compared) == 0) {
+	    /* Set error to Invalid PRIVATE Key. */
+	    PORT_SetError(SEC_ERROR_INVALID_KEY);
+	    PORT_Free(ciphertext);
+	    return CKR_GENERAL_ERROR;
+	}
+
+	/* Prepare for decryption using the private key. */
+	crv = NSC_DecryptInit(hSession, &mech, privateKey->handle);
+	if (crv != CKR_OK) {
+	    PORT_Free(ciphertext);
+	    return crv;
+	}
+
+	memset(plaintext, 0, PAIRWISE_MESSAGE_LENGTH);
+
+	/*
+	 * Initialize bytes decrypted to be the
+	 * expected PAIRWISE_MESSAGE_LENGTH.
+	 */
+	bytes_decrypted = PAIRWISE_MESSAGE_LENGTH;
+
+	/*
+	 * Decrypt using the private key.
+	 * NOTE:  No need to reset the
+	 *        value of bytes_encrypted.
+	 */
+	crv = NSC_Decrypt(hSession,
+			  ciphertext,
+			  bytes_encrypted,
+			  plaintext,
+			  &bytes_decrypted);
+
+	/* Finished with ciphertext; free it. */
+	PORT_Free(ciphertext);
+
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+
+	/*
+	 * Check to ensure that the output plaintext
+	 * does EQUAL known input message text.
+	 */
+	if ((bytes_decrypted != PAIRWISE_MESSAGE_LENGTH) ||
+	    (PORT_Memcmp(plaintext, known_message,
+			 PAIRWISE_MESSAGE_LENGTH) != 0)) {
+	    /* Set error to Bad PUBLIC Key. */
+	    PORT_SetError(SEC_ERROR_BAD_KEY);
+	    return CKR_GENERAL_ERROR;
+	}
+    }
+
+    /**********************************************/
+    /* Pairwise Consistency Check of Sign/Verify. */
+    /**********************************************/
+
+    canSignVerify = sftk_isTrue(privateKey, CKA_SIGN);
+    
+    if (canSignVerify) {
+	/* Determine length of signature. */
+	switch (keyType) {
+	case CKK_RSA:
+	    signature_length = modulusLen;
+	    mech.mechanism = CKM_RSA_PKCS;
+	    break;
+	case CKK_DSA:
+	    signature_length = DSA_SIGNATURE_LEN;
+	    mech.mechanism = CKM_DSA;
+	    break;
+#ifdef NSS_ENABLE_ECC
+	case CKK_EC:
+	    signature_length = MAX_ECKEY_LEN * 2;
+	    mech.mechanism = CKM_ECDSA;
+	    break;
+#endif
+	default:
+	    return CKR_DEVICE_ERROR;
+	}
+	
+	/* Allocate space for signature data. */
+	signature = (unsigned char *) PORT_ZAlloc(signature_length);
+	if (signature == NULL) {
+	    return CKR_HOST_MEMORY;
+	}
+	
+	/* Sign the known hash using the private key. */
+	crv = NSC_SignInit(hSession, &mech, privateKey->handle);
+	if (crv != CKR_OK) {
+	    PORT_Free(signature);
+	    return crv;
+	}
+
+	crv = NSC_Sign(hSession,
+		       known_digest,
+		       PAIRWISE_DIGEST_LENGTH,
+		       signature,
+		       &signature_length);
+	if (crv != CKR_OK) {
+	    PORT_Free(signature);
+	    return crv;
+	}
+	
+	/* Verify the known hash using the public key. */
+	crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
+	if (crv != CKR_OK) {
+	    PORT_Free(signature);
+	    return crv;
+	}
+
+	crv = NSC_Verify(hSession,
+			 known_digest,
+			 PAIRWISE_DIGEST_LENGTH,
+			 signature,
+			 signature_length);
+
+	/* Free signature data. */
+	PORT_Free(signature);
+
+	if ((crv == CKR_SIGNATURE_LEN_RANGE) ||
+		(crv == CKR_SIGNATURE_INVALID)) {
+	    return CKR_GENERAL_ERROR;
+	}
+	if (crv != CKR_OK) {
+	    return crv;
+	}
+    }
+
+    /**********************************************/
+    /* Pairwise Consistency Check for Derivation  */
+    /**********************************************/
+
+    isDerivable = sftk_isTrue(privateKey, CKA_DERIVE);
+    
+    if (isDerivable) {
+	/* 
+	 * We are not doing consistency check for Diffie-Hellman Key - 
+	 * otherwise it would be here
+	 * This is also true for Elliptic Curve Diffie-Hellman keys
+	 * NOTE: EC keys are currently subjected to pairwise
+	 * consistency check for signing/verification.
+	 */
+	/*
+	 * FIPS 140-2 had the following pairwise consistency test for
+	 * public and private keys used for key agreement:
+	 *   If the keys are used to perform key agreement, then the
+	 *   cryptographic module shall create a second, compatible
+	 *   key pair.  The cryptographic module shall perform both
+	 *   sides of the key agreement algorithm and shall compare
+	 *   the resulting shared values.  If the shared values are
+	 *   not equal, the test shall fail.
+	 * This test was removed in Change Notice 3.
+	 */
+
+    }
+
+    return CKR_OK;
+}
+
+/* NSC_GenerateKeyPair generates a public-key/private-key pair, 
+ * creating new key objects. */
+CK_RV NSC_GenerateKeyPair (CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+    CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+    CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey,
+    					CK_OBJECT_HANDLE_PTR phPrivateKey)
+{
+    SFTKObject *	publicKey,*privateKey;
+    SFTKSession *	session;
+    CK_KEY_TYPE 	key_type;
+    CK_RV 		crv 	= CKR_OK;
+    CK_BBOOL 		cktrue 	= CK_TRUE;
+    SECStatus 		rv;
+    CK_OBJECT_CLASS 	pubClass = CKO_PUBLIC_KEY;
+    CK_OBJECT_CLASS 	privClass = CKO_PRIVATE_KEY;
+    int 		i;
+    SFTKSlot *		slot 	= sftk_SlotFromSessionHandle(hSession);
+    unsigned int bitSize;
+
+    /* RSA */
+    int 		public_modulus_bits = 0;
+    SECItem 		pubExp;
+    RSAPrivateKey *	rsaPriv;
+
+    /* DSA */
+    PQGParams 		pqgParam;
+    DHParams  		dhParam;
+    DSAPrivateKey *	dsaPriv;
+
+    /* Diffie Hellman */
+    int 		private_value_bits = 0;
+    DHPrivateKey *	dhPriv;
+
+#ifdef NSS_ENABLE_ECC
+    /* Elliptic Curve Cryptography */
+    SECItem  		ecEncodedParams;  /* DER Encoded parameters */
+    ECPrivateKey *	ecPriv;
+    ECParams *          ecParams;
+#endif /* NSS_ENABLE_ECC */
+
+    CHECK_FORK();
+
+    if (!slot) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * now lets create an object to hang the attributes off of
+     */
+    publicKey = sftk_NewObject(slot); /* fill in the handle later */
+    if (publicKey == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    /*
+     * load the template values into the publicKey
+     */
+    for (i=0; i < (int) ulPublicKeyAttributeCount; i++) {
+	if (pPublicKeyTemplate[i].type == CKA_MODULUS_BITS) {
+	    public_modulus_bits = *(CK_ULONG *)pPublicKeyTemplate[i].pValue;
+	    continue;
+	}
+
+	crv = sftk_AddAttributeType(publicKey,
+				    sftk_attr_expand(&pPublicKeyTemplate[i]));
+	if (crv != CKR_OK) break;
+    }
+
+    if (crv != CKR_OK) {
+	sftk_FreeObject(publicKey);
+	return CKR_HOST_MEMORY;
+    }
+
+    privateKey = sftk_NewObject(slot); /* fill in the handle later */
+    if (privateKey == NULL) {
+	sftk_FreeObject(publicKey);
+	return CKR_HOST_MEMORY;
+    }
+    /*
+     * now load the private key template
+     */
+    for (i=0; i < (int) ulPrivateKeyAttributeCount; i++) {
+	if (pPrivateKeyTemplate[i].type == CKA_VALUE_BITS) {
+	    private_value_bits = *(CK_ULONG *)pPrivateKeyTemplate[i].pValue;
+	    continue;
+	}
+
+	crv = sftk_AddAttributeType(privateKey,
+				    sftk_attr_expand(&pPrivateKeyTemplate[i]));
+	if (crv != CKR_OK) break;
+    }
+
+    if (crv != CKR_OK) {
+	sftk_FreeObject(publicKey);
+	sftk_FreeObject(privateKey);
+	return CKR_HOST_MEMORY;
+    }
+    sftk_DeleteAttributeType(privateKey,CKA_CLASS);
+    sftk_DeleteAttributeType(privateKey,CKA_KEY_TYPE);
+    sftk_DeleteAttributeType(privateKey,CKA_VALUE);
+    sftk_DeleteAttributeType(publicKey,CKA_CLASS);
+    sftk_DeleteAttributeType(publicKey,CKA_KEY_TYPE);
+    sftk_DeleteAttributeType(publicKey,CKA_VALUE);
+
+    /* Now Set up the parameters to generate the key (based on mechanism) */
+    switch (pMechanism->mechanism) {
+    case CKM_RSA_PKCS_KEY_PAIR_GEN:
+	/* format the keys */
+    	sftk_DeleteAttributeType(publicKey,CKA_MODULUS);
+    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
+    	sftk_DeleteAttributeType(privateKey,CKA_MODULUS);
+    	sftk_DeleteAttributeType(privateKey,CKA_PRIVATE_EXPONENT);
+    	sftk_DeleteAttributeType(privateKey,CKA_PUBLIC_EXPONENT);
+    	sftk_DeleteAttributeType(privateKey,CKA_PRIME_1);
+    	sftk_DeleteAttributeType(privateKey,CKA_PRIME_2);
+    	sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_1);
+    	sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_2);
+    	sftk_DeleteAttributeType(privateKey,CKA_COEFFICIENT);
+	key_type = CKK_RSA;
+	if (public_modulus_bits == 0) {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    break;
+	}
+	if (public_modulus_bits < RSA_MIN_MODULUS_BITS) {
+	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	    break;
+	}
+	if (public_modulus_bits % 2 != 0) {
+	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	    break;
+	}
+
+	/* extract the exponent */
+	crv=sftk_Attribute2SSecItem(NULL,&pubExp,publicKey,CKA_PUBLIC_EXPONENT);
+	if (crv != CKR_OK) break;
+        bitSize = sftk_GetLengthInBits(pubExp.data, pubExp.len);
+	if (bitSize < 2) {
+	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	    break;
+	}
+        crv = sftk_AddAttributeType(privateKey,CKA_PUBLIC_EXPONENT,
+				    		    sftk_item_expand(&pubExp));
+	if (crv != CKR_OK) {
+	    PORT_Free(pubExp.data);
+	    break;
+	}
+
+	rsaPriv = RSA_NewKey(public_modulus_bits, &pubExp);
+	PORT_Free(pubExp.data);
+	if (rsaPriv == NULL) {
+	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+		sftk_fatalError = PR_TRUE;
+	    }
+	    crv = sftk_MapCryptError(PORT_GetError());
+	    break;
+	}
+        /* now fill in the RSA dependent paramenters in the public key */
+        crv = sftk_AddAttributeType(publicKey,CKA_MODULUS,
+			   sftk_item_expand(&rsaPriv->modulus));
+	if (crv != CKR_OK) goto kpg_done;
+        /* now fill in the RSA dependent paramenters in the private key */
+        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
+			   sftk_item_expand(&rsaPriv->modulus));
+	if (crv != CKR_OK) goto kpg_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_MODULUS,
+			   sftk_item_expand(&rsaPriv->modulus));
+	if (crv != CKR_OK) goto kpg_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_PRIVATE_EXPONENT,
+			   sftk_item_expand(&rsaPriv->privateExponent));
+	if (crv != CKR_OK) goto kpg_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_PRIME_1,
+			   sftk_item_expand(&rsaPriv->prime1));
+	if (crv != CKR_OK) goto kpg_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_PRIME_2,
+			   sftk_item_expand(&rsaPriv->prime2));
+	if (crv != CKR_OK) goto kpg_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_1,
+			   sftk_item_expand(&rsaPriv->exponent1));
+	if (crv != CKR_OK) goto kpg_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_2,
+			   sftk_item_expand(&rsaPriv->exponent2));
+	if (crv != CKR_OK) goto kpg_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_COEFFICIENT,
+			   sftk_item_expand(&rsaPriv->coefficient));
+kpg_done:
+	/* Should zeroize the contents first, since this func doesn't. */
+	PORT_FreeArena(rsaPriv->arena, PR_TRUE);
+	break;
+    case CKM_DSA_KEY_PAIR_GEN:
+    	sftk_DeleteAttributeType(publicKey,CKA_VALUE);
+    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
+	sftk_DeleteAttributeType(privateKey,CKA_PRIME);
+	sftk_DeleteAttributeType(privateKey,CKA_SUBPRIME);
+	sftk_DeleteAttributeType(privateKey,CKA_BASE);
+	key_type = CKK_DSA;
+
+	/* extract the necessary paramters and copy them to the private key */
+	crv=sftk_Attribute2SSecItem(NULL,&pqgParam.prime,publicKey,CKA_PRIME);
+	if (crv != CKR_OK) break;
+	crv=sftk_Attribute2SSecItem(NULL,&pqgParam.subPrime,publicKey,
+	                            CKA_SUBPRIME);
+	if (crv != CKR_OK) {
+	    PORT_Free(pqgParam.prime.data);
+	    break;
+	}
+	crv=sftk_Attribute2SSecItem(NULL,&pqgParam.base,publicKey,CKA_BASE);
+	if (crv != CKR_OK) {
+	    PORT_Free(pqgParam.prime.data);
+	    PORT_Free(pqgParam.subPrime.data);
+	    break;
+	}
+        crv = sftk_AddAttributeType(privateKey,CKA_PRIME,
+				    sftk_item_expand(&pqgParam.prime));
+	if (crv != CKR_OK) {
+	    PORT_Free(pqgParam.prime.data);
+	    PORT_Free(pqgParam.subPrime.data);
+	    PORT_Free(pqgParam.base.data);
+	    break;
+	}
+        crv = sftk_AddAttributeType(privateKey,CKA_SUBPRIME,
+			    	    sftk_item_expand(&pqgParam.subPrime));
+	if (crv != CKR_OK) {
+	    PORT_Free(pqgParam.prime.data);
+	    PORT_Free(pqgParam.subPrime.data);
+	    PORT_Free(pqgParam.base.data);
+	    break;
+	}
+        crv = sftk_AddAttributeType(privateKey,CKA_BASE,
+			    	    sftk_item_expand(&pqgParam.base));
+	if (crv != CKR_OK) {
+	    PORT_Free(pqgParam.prime.data);
+	    PORT_Free(pqgParam.subPrime.data);
+	    PORT_Free(pqgParam.base.data);
+	    break;
+	}
+
+        bitSize = sftk_GetLengthInBits(pqgParam.subPrime.data, 
+							pqgParam.subPrime.len);
+        if (bitSize != DSA_Q_BITS)  {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    PORT_Free(pqgParam.prime.data);
+	    PORT_Free(pqgParam.subPrime.data);
+	    PORT_Free(pqgParam.base.data);
+	    break;
+	}
+        bitSize = sftk_GetLengthInBits(pqgParam.prime.data,pqgParam.prime.len);
+        if ((bitSize <  DSA_MIN_P_BITS) || (bitSize > DSA_MAX_P_BITS)) {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    PORT_Free(pqgParam.prime.data);
+	    PORT_Free(pqgParam.subPrime.data);
+	    PORT_Free(pqgParam.base.data);
+	    break;
+	}
+        bitSize = sftk_GetLengthInBits(pqgParam.base.data,pqgParam.base.len);
+        if ((bitSize <  1) || (bitSize > DSA_MAX_P_BITS)) {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    PORT_Free(pqgParam.prime.data);
+	    PORT_Free(pqgParam.subPrime.data);
+	    PORT_Free(pqgParam.base.data);
+	    break;
+	}
+	    
+	/* Generate the key */
+	rv = DSA_NewKey(&pqgParam, &dsaPriv);
+
+	PORT_Free(pqgParam.prime.data);
+	PORT_Free(pqgParam.subPrime.data);
+	PORT_Free(pqgParam.base.data);
+
+	if (rv != SECSuccess) {
+	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+		sftk_fatalError = PR_TRUE;
+	    }
+	    crv = sftk_MapCryptError(PORT_GetError());
+	    break;
+	}
+
+	/* store the generated key into the attributes */
+        crv = sftk_AddAttributeType(publicKey,CKA_VALUE,
+			   sftk_item_expand(&dsaPriv->publicValue));
+	if (crv != CKR_OK) goto dsagn_done;
+
+        /* now fill in the RSA dependent paramenters in the private key */
+        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
+			   sftk_item_expand(&dsaPriv->publicValue));
+	if (crv != CKR_OK) goto dsagn_done;
+        crv = sftk_AddAttributeType(privateKey,CKA_VALUE,
+			   sftk_item_expand(&dsaPriv->privateValue));
+
+dsagn_done:
+	/* should zeroize, since this function doesn't. */
+	PORT_FreeArena(dsaPriv->params.arena, PR_TRUE);
+	break;
+
+    case CKM_DH_PKCS_KEY_PAIR_GEN:
+	sftk_DeleteAttributeType(privateKey,CKA_PRIME);
+	sftk_DeleteAttributeType(privateKey,CKA_BASE);
+	sftk_DeleteAttributeType(privateKey,CKA_VALUE);
+    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
+	key_type = CKK_DH;
+
+	/* extract the necessary parameters and copy them to private keys */
+        crv = sftk_Attribute2SSecItem(NULL, &dhParam.prime, publicKey, 
+				      CKA_PRIME);
+	if (crv != CKR_OK) break;
+	crv = sftk_Attribute2SSecItem(NULL, &dhParam.base, publicKey, CKA_BASE);
+	if (crv != CKR_OK) {
+	    PORT_Free(dhParam.prime.data);
+	    break;
+	}
+	crv = sftk_AddAttributeType(privateKey, CKA_PRIME, 
+				    sftk_item_expand(&dhParam.prime));
+	if (crv != CKR_OK) {
+	    PORT_Free(dhParam.prime.data);
+	    PORT_Free(dhParam.base.data);
+	    break;
+	}
+	crv = sftk_AddAttributeType(privateKey, CKA_BASE, 
+				    sftk_item_expand(&dhParam.base));
+	if (crv != CKR_OK) {
+	    PORT_Free(dhParam.prime.data);
+	    PORT_Free(dhParam.base.data);
+	    break;
+	}
+        bitSize = sftk_GetLengthInBits(dhParam.prime.data,dhParam.prime.len);
+        if ((bitSize <  DH_MIN_P_BITS) || (bitSize > DH_MAX_P_BITS)) {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    PORT_Free(dhParam.prime.data);
+	    PORT_Free(dhParam.base.data);
+	    break;
+	}
+        bitSize = sftk_GetLengthInBits(dhParam.base.data,dhParam.base.len);
+        if ((bitSize <  1) || (bitSize > DH_MAX_P_BITS)) {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    PORT_Free(dhParam.prime.data);
+	    PORT_Free(dhParam.base.data);
+	    break;
+	}
+
+	rv = DH_NewKey(&dhParam, &dhPriv);
+	PORT_Free(dhParam.prime.data);
+	PORT_Free(dhParam.base.data);
+	if (rv != SECSuccess) { 
+	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+		sftk_fatalError = PR_TRUE;
+	    }
+	    crv = sftk_MapCryptError(PORT_GetError());
+	    break;
+	}
+
+	crv=sftk_AddAttributeType(publicKey, CKA_VALUE, 
+				sftk_item_expand(&dhPriv->publicValue));
+	if (crv != CKR_OK) goto dhgn_done;
+
+        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
+			   sftk_item_expand(&dhPriv->publicValue));
+	if (crv != CKR_OK) goto dhgn_done;
+
+	crv=sftk_AddAttributeType(privateKey, CKA_VALUE, 
+			      sftk_item_expand(&dhPriv->privateValue));
+
+dhgn_done:
+	/* should zeroize, since this function doesn't. */
+	PORT_FreeArena(dhPriv->arena, PR_TRUE);
+	break;
+
+#ifdef NSS_ENABLE_ECC
+    case CKM_EC_KEY_PAIR_GEN:
+	sftk_DeleteAttributeType(privateKey,CKA_EC_PARAMS);
+	sftk_DeleteAttributeType(privateKey,CKA_VALUE);
+    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
+	key_type = CKK_EC;
+
+	/* extract the necessary parameters and copy them to private keys */
+	crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey, 
+				      CKA_EC_PARAMS);
+	if (crv != CKR_OK) break;
+
+	crv = sftk_AddAttributeType(privateKey, CKA_EC_PARAMS, 
+				    sftk_item_expand(&ecEncodedParams));
+	if (crv != CKR_OK) {
+	  PORT_Free(ecEncodedParams.data);
+	  break;
+	}
+
+	/* Decode ec params before calling EC_NewKey */
+	rv = EC_DecodeParams(&ecEncodedParams, &ecParams);
+	PORT_Free(ecEncodedParams.data);
+	if (rv != SECSuccess) {
+	    crv = sftk_MapCryptError(PORT_GetError());
+	    break;
+	}
+	rv = EC_NewKey(ecParams, &ecPriv);
+	PORT_FreeArena(ecParams->arena, PR_TRUE);
+	if (rv != SECSuccess) { 
+	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+		sftk_fatalError = PR_TRUE;
+	    }
+	    crv = sftk_MapCryptError(PORT_GetError());
+	    break;
+	}
+
+	if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) {
+	    crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, 
+				sftk_item_expand(&ecPriv->publicValue));
+	} else {
+	    SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL, 
+					&ecPriv->publicValue, 
+					SEC_ASN1_GET(SEC_OctetStringTemplate));
+	    if (!pubValue) {
+		crv = CKR_ARGUMENTS_BAD;
+		goto ecgn_done;
+	    }
+	    crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, 
+				sftk_item_expand(pubValue));
+	    SECITEM_FreeItem(pubValue, PR_TRUE);
+	}
+	if (crv != CKR_OK) goto ecgn_done;
+
+	crv = sftk_AddAttributeType(privateKey, CKA_VALUE, 
+			      sftk_item_expand(&ecPriv->privateValue));
+	if (crv != CKR_OK) goto ecgn_done;
+
+        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
+			   sftk_item_expand(&ecPriv->publicValue));
+ecgn_done:
+	/* should zeroize, since this function doesn't. */
+	PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
+	break;
+#endif /* NSS_ENABLE_ECC */
+
+    default:
+	crv = CKR_MECHANISM_INVALID;
+    }
+
+    if (crv != CKR_OK) {
+	sftk_FreeObject(privateKey);
+	sftk_FreeObject(publicKey);
+	return crv;
+    }
+
+
+    /* Add the class, key_type The loop lets us check errors blow out
+     *  on errors and clean up at the bottom */
+    session = NULL; /* make pedtantic happy... session cannot leave the*/
+		    /* loop below NULL unless an error is set... */
+    do {
+	crv = sftk_AddAttributeType(privateKey,CKA_CLASS,&privClass,
+						sizeof(CK_OBJECT_CLASS));
+        if (crv != CKR_OK) break;
+	crv = sftk_AddAttributeType(publicKey,CKA_CLASS,&pubClass,
+						sizeof(CK_OBJECT_CLASS));
+        if (crv != CKR_OK) break;
+	crv = sftk_AddAttributeType(privateKey,CKA_KEY_TYPE,&key_type,
+						sizeof(CK_KEY_TYPE));
+        if (crv != CKR_OK) break;
+	crv = sftk_AddAttributeType(publicKey,CKA_KEY_TYPE,&key_type,
+						sizeof(CK_KEY_TYPE));
+        if (crv != CKR_OK) break;
+        session = sftk_SessionFromHandle(hSession);
+        if (session == NULL) crv = CKR_SESSION_HANDLE_INVALID;
+    } while (0);
+
+    if (crv != CKR_OK) {
+	 sftk_FreeObject(privateKey);
+	 sftk_FreeObject(publicKey);
+	 return crv;
+    }
+
+    /*
+     * handle the base object cleanup for the public Key
+     */
+    crv = sftk_handleObject(privateKey,session);
+    if (crv != CKR_OK) {
+        sftk_FreeSession(session);
+	sftk_FreeObject(privateKey);
+	sftk_FreeObject(publicKey);
+	return crv;
+    }
+
+    /*
+     * handle the base object cleanup for the private Key
+     * If we have any problems, we destroy the public Key we've
+     * created and linked.
+     */
+    crv = sftk_handleObject(publicKey,session);
+    sftk_FreeSession(session);
+    if (crv != CKR_OK) {
+	sftk_FreeObject(publicKey);
+	NSC_DestroyObject(hSession,privateKey->handle);
+	sftk_FreeObject(privateKey);
+	return crv;
+    }
+    if (sftk_isTrue(privateKey,CKA_SENSITIVE)) {
+	sftk_forceAttribute(privateKey,CKA_ALWAYS_SENSITIVE,
+						&cktrue,sizeof(CK_BBOOL));
+    }
+    if (sftk_isTrue(publicKey,CKA_SENSITIVE)) {
+	sftk_forceAttribute(publicKey,CKA_ALWAYS_SENSITIVE,
+						&cktrue,sizeof(CK_BBOOL));
+    }
+    if (!sftk_isTrue(privateKey,CKA_EXTRACTABLE)) {
+	sftk_forceAttribute(privateKey,CKA_NEVER_EXTRACTABLE,
+						&cktrue,sizeof(CK_BBOOL));
+    }
+    if (!sftk_isTrue(publicKey,CKA_EXTRACTABLE)) {
+	sftk_forceAttribute(publicKey,CKA_NEVER_EXTRACTABLE,
+						&cktrue,sizeof(CK_BBOOL));
+    }
+
+    /* Perform FIPS 140-2 pairwise consistency check. */
+    crv = sftk_PairwiseConsistencyCheck(hSession,
+					publicKey, privateKey, key_type);
+    if (crv != CKR_OK) {
+	NSC_DestroyObject(hSession,publicKey->handle);
+	sftk_FreeObject(publicKey);
+	NSC_DestroyObject(hSession,privateKey->handle);
+	sftk_FreeObject(privateKey);
+	if (sftk_audit_enabled) {
+	    char msg[128];
+	    PR_snprintf(msg,sizeof msg,
+			"C_GenerateKeyPair(hSession=0x%08lX, "
+			"pMechanism->mechanism=0x%08lX)=0x%08lX "
+			"self-test: pair-wise consistency test failed",
+			(PRUint32)hSession,(PRUint32)pMechanism->mechanism,
+			(PRUint32)crv);
+	    sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
+	}
+	return crv;
+    }
+
+    *phPrivateKey = privateKey->handle;
+    *phPublicKey = publicKey->handle;
+    sftk_FreeObject(publicKey);
+    sftk_FreeObject(privateKey);
+
+    return CKR_OK;
+}
+
+static SECItem *sftk_PackagePrivateKey(SFTKObject *key, CK_RV *crvp)
+{
+    NSSLOWKEYPrivateKey *lk = NULL;
+    NSSLOWKEYPrivateKeyInfo *pki = NULL;
+    SFTKAttribute *attribute = NULL;
+    PLArenaPool *arena = NULL;
+    SECOidTag algorithm = SEC_OID_UNKNOWN;
+    void *dummy, *param = NULL;
+    SECStatus rv = SECSuccess;
+    SECItem *encodedKey = NULL;
+#ifdef NSS_ENABLE_ECC
+    SECItem *fordebug;
+    int savelen;
+#endif
+
+    if(!key) {
+	*crvp = CKR_KEY_HANDLE_INVALID; /* really can't happen */
+	return NULL;
+    }
+
+    attribute = sftk_FindAttribute(key, CKA_KEY_TYPE);
+    if(!attribute) {
+	*crvp = CKR_KEY_TYPE_INCONSISTENT;
+	return NULL;
+    }
+
+    lk = sftk_GetPrivKey(key, *(CK_KEY_TYPE *)attribute->attrib.pValue, crvp);
+    sftk_FreeAttribute(attribute);
+    if(!lk) {
+	return NULL;
+    }
+
+    arena = PORT_NewArena(2048); 	/* XXX different size? */
+    if(!arena) {
+	*crvp = CKR_HOST_MEMORY;
+	rv = SECFailure;
+	goto loser;
+    }
+
+    pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
+					sizeof(NSSLOWKEYPrivateKeyInfo));
+    if(!pki) {
+	*crvp = CKR_HOST_MEMORY;
+	rv = SECFailure;
+	goto loser;
+    }
+    pki->arena = arena;
+
+    param = NULL;
+    switch(lk->keyType) {
+	case NSSLOWKEYRSAKey:
+	    prepare_low_rsa_priv_key_for_asn1(lk);
+	    dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
+				       nsslowkey_RSAPrivateKeyTemplate);
+	    algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
+	    break;
+	case NSSLOWKEYDSAKey:
+            prepare_low_dsa_priv_key_export_for_asn1(lk);
+	    dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
+				       nsslowkey_DSAPrivateKeyExportTemplate);
+	    prepare_low_pqg_params_for_asn1(&lk->u.dsa.params);
+	    param = SEC_ASN1EncodeItem(NULL, NULL, &(lk->u.dsa.params),
+				       nsslowkey_PQGParamsTemplate);
+	    algorithm = SEC_OID_ANSIX9_DSA_SIGNATURE;
+	    break;
+#ifdef NSS_ENABLE_ECC	    
+        case NSSLOWKEYECKey:
+            prepare_low_ec_priv_key_for_asn1(lk);
+	    /* Public value is encoded as a bit string so adjust length
+	     * to be in bits before ASN encoding and readjust 
+	     * immediately after.
+	     *
+	     * Since the SECG specification recommends not including the
+	     * parameters as part of ECPrivateKey, we zero out the curveOID
+	     * length before encoding and restore it later.
+	     */
+	    lk->u.ec.publicValue.len <<= 3;
+	    savelen = lk->u.ec.ecParams.curveOID.len;
+	    lk->u.ec.ecParams.curveOID.len = 0;
+	    dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
+				       nsslowkey_ECPrivateKeyTemplate);
+	    lk->u.ec.ecParams.curveOID.len = savelen;
+	    lk->u.ec.publicValue.len >>= 3;
+
+	    fordebug = &pki->privateKey;
+	    SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKey", lk->keyType,
+		      fordebug);
+
+	    param = SECITEM_DupItem(&lk->u.ec.ecParams.DEREncoding);
+
+	    algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+	    break;
+#endif /* NSS_ENABLE_ECC */
+	case NSSLOWKEYDHKey:
+	default:
+	    dummy = NULL;
+	    break;
+    }
+ 
+    if(!dummy || ((lk->keyType == NSSLOWKEYDSAKey) && !param)) {
+	*crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
+	rv = SECFailure;
+	goto loser;
+    }
+    
+    rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, 
+			       (SECItem*)param);
+    if(rv != SECSuccess) {
+	*crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
+	rv = SECFailure;
+	goto loser;
+    }
+
+    dummy = SEC_ASN1EncodeInteger(arena, &pki->version,
+				  NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
+    if(!dummy) {
+	*crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
+	rv = SECFailure;
+	goto loser;
+    }
+
+    encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, 
+				    nsslowkey_PrivateKeyInfoTemplate);
+    *crvp = encodedKey ? CKR_OK : CKR_DEVICE_ERROR;
+
+#ifdef NSS_ENABLE_ECC
+    fordebug = encodedKey;
+    SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKeyInfo", lk->keyType,
+	      fordebug);
+#endif
+loser:
+    if(arena) {
+	PORT_FreeArena(arena, PR_TRUE);
+    }
+
+    if(lk && (lk != key->objectInfo)) {
+	nsslowkey_DestroyPrivateKey(lk);
+    }
+ 
+    if(param) {
+	SECITEM_ZfreeItem((SECItem*)param, PR_TRUE);
+    }
+
+    if(rv != SECSuccess) {
+	return NULL;
+    }
+
+    return encodedKey;
+}
+    
+/* it doesn't matter yet, since we colapse error conditions in the
+ * level above, but we really should map those few key error differences */
+static CK_RV 
+sftk_mapWrap(CK_RV crv) 
+{ 
+    switch (crv) {
+    case CKR_ENCRYPTED_DATA_INVALID:  crv = CKR_WRAPPED_KEY_INVALID; break;
+    }
+    return crv; 
+}
+
+/* NSC_WrapKey wraps (i.e., encrypts) a key. */
+CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey,
+    CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey,
+					 CK_ULONG_PTR pulWrappedKeyLen)
+{
+    SFTKSession *session;
+    SFTKAttribute *attribute;
+    SFTKObject *key;
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+    	return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    key = sftk_ObjectFromHandle(hKey,session);
+    sftk_FreeSession(session);
+    if (key == NULL) {
+	return CKR_KEY_HANDLE_INVALID;
+    }
+
+    switch(key->objclass) {
+	case CKO_SECRET_KEY:
+	  {
+	    SFTKSessionContext *context = NULL;
+	    SECItem pText;
+
+	    attribute = sftk_FindAttribute(key,CKA_VALUE);
+
+	    if (attribute == NULL) {
+		crv = CKR_KEY_TYPE_INCONSISTENT;
+		break;
+	    }
+	    crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey, 
+					CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
+	    if (crv != CKR_OK) {
+		sftk_FreeAttribute(attribute);
+		break;
+	    }
+
+	    pText.type = siBuffer;
+	    pText.data = (unsigned char *)attribute->attrib.pValue;
+	    pText.len  = attribute->attrib.ulValueLen;
+
+	    /* Find out if this is a block cipher. */
+	    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,NULL);
+	    if (crv != CKR_OK || !context) 
+	        break;
+	    if (context->blockSize > 1) {
+		unsigned int remainder = pText.len % context->blockSize;
+	        if (!context->doPad && remainder) {
+		    /* When wrapping secret keys with unpadded block ciphers, 
+		    ** the keys are zero padded, if necessary, to fill out 
+		    ** a full block.
+		    */
+		    pText.len += context->blockSize - remainder;
+		    pText.data = PORT_ZAlloc(pText.len);
+		    if (pText.data)
+			memcpy(pText.data, attribute->attrib.pValue,
+			                   attribute->attrib.ulValueLen);
+		    else {
+			crv = CKR_HOST_MEMORY;
+			break;
+		    }
+		}
+	    }
+
+	    crv = NSC_Encrypt(hSession, (CK_BYTE_PTR)pText.data, 
+		              pText.len, pWrappedKey, pulWrappedKeyLen);
+	    /* always force a finalize, both on errors and when
+	     * we are just getting the size */
+	    if (crv != CKR_OK || pWrappedKey == NULL) {
+	    	CK_RV lcrv ;
+		lcrv = sftk_GetContext(hSession,&context,
+				       SFTK_ENCRYPT,PR_FALSE,NULL);
+		sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
+	    	if (lcrv == CKR_OK && context) {
+		    sftk_FreeContext(context);
+		}
+    	    }
+
+	    if (pText.data != (unsigned char *)attribute->attrib.pValue) 
+	    	PORT_ZFree(pText.data, pText.len);
+	    sftk_FreeAttribute(attribute);
+	    break;
+	  }
+
+	case CKO_PRIVATE_KEY:
+	    {
+		SECItem *bpki = sftk_PackagePrivateKey(key, &crv);
+		SFTKSessionContext *context = NULL;
+
+		if(!bpki) {
+		    break;
+		}
+
+		crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey,
+					CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
+		if(crv != CKR_OK) {
+		    SECITEM_ZfreeItem(bpki, PR_TRUE);
+		    crv = CKR_KEY_TYPE_INCONSISTENT;
+		    break;
+		}
+
+		crv = NSC_Encrypt(hSession, bpki->data, bpki->len,
+					pWrappedKey, pulWrappedKeyLen);
+		/* always force a finalize */
+		if (crv != CKR_OK || pWrappedKey == NULL) {
+	    	    CK_RV lcrv ;
+		    lcrv = sftk_GetContext(hSession,&context,
+					   SFTK_ENCRYPT,PR_FALSE,NULL);
+		    sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
+	    	    if (lcrv == CKR_OK && context)  {
+			sftk_FreeContext(context);
+		    }
+		}
+		SECITEM_ZfreeItem(bpki, PR_TRUE);
+		break;
+	    }
+
+	default:
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+    }
+    sftk_FreeObject(key);
+
+    return sftk_mapWrap(crv);
+}
+
+/*
+ * import a pprivate key info into the desired slot
+ */
+static SECStatus
+sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki)
+{
+    CK_BBOOL cktrue = CK_TRUE; 
+    CK_KEY_TYPE keyType = CKK_RSA;
+    SECStatus rv = SECFailure;
+    const SEC_ASN1Template *keyTemplate, *paramTemplate;
+    void *paramDest = NULL;
+    PLArenaPool *arena;
+    NSSLOWKEYPrivateKey *lpk = NULL;
+    NSSLOWKEYPrivateKeyInfo *pki = NULL;
+    CK_RV crv = CKR_KEY_TYPE_INCONSISTENT;
+
+    arena = PORT_NewArena(2048);
+    if(!arena) {
+	return SECFailure;
+    }
+
+    pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
+					sizeof(NSSLOWKEYPrivateKeyInfo));
+    if(!pki) {
+	PORT_FreeArena(arena, PR_FALSE);
+	return SECFailure;
+    }
+
+    if(SEC_ASN1DecodeItem(arena, pki, nsslowkey_PrivateKeyInfoTemplate, bpki) 
+				!= SECSuccess) {
+	PORT_FreeArena(arena, PR_TRUE);
+	return SECFailure;
+    }
+
+    lpk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(arena,
+						  sizeof(NSSLOWKEYPrivateKey));
+    if(lpk == NULL) {
+	goto loser;
+    }
+    lpk->arena = arena;
+
+    switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
+	case SEC_OID_PKCS1_RSA_ENCRYPTION:
+	    keyTemplate = nsslowkey_RSAPrivateKeyTemplate;
+	    paramTemplate = NULL;
+	    paramDest = NULL;
+	    lpk->keyType = NSSLOWKEYRSAKey;
+	    prepare_low_rsa_priv_key_for_asn1(lpk);
+	    break;
+	case SEC_OID_ANSIX9_DSA_SIGNATURE:
+	    keyTemplate = nsslowkey_DSAPrivateKeyExportTemplate;
+	    paramTemplate = nsslowkey_PQGParamsTemplate;
+	    paramDest = &(lpk->u.dsa.params);
+	    lpk->keyType = NSSLOWKEYDSAKey;
+	    prepare_low_dsa_priv_key_export_for_asn1(lpk);
+	    prepare_low_pqg_params_for_asn1(&lpk->u.dsa.params);
+	    break;
+	/* case NSSLOWKEYDHKey: */
+#ifdef NSS_ENABLE_ECC
+        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+	    keyTemplate = nsslowkey_ECPrivateKeyTemplate;
+	    paramTemplate = NULL;
+	    paramDest = &(lpk->u.ec.ecParams.DEREncoding);
+	    lpk->keyType = NSSLOWKEYECKey;
+	    prepare_low_ec_priv_key_for_asn1(lpk);
+	    prepare_low_ecparams_for_asn1(&lpk->u.ec.ecParams);
+	    break;
+#endif /* NSS_ENABLE_ECC */
+	default:
+	    keyTemplate = NULL;
+	    paramTemplate = NULL;
+	    paramDest = NULL;
+	    break;
+    }
+
+    if(!keyTemplate) {
+	goto loser;
+    }
+
+    /* decode the private key and any algorithm parameters */
+    rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
+
+#ifdef NSS_ENABLE_ECC
+    if (lpk->keyType == NSSLOWKEYECKey) {
+        /* convert length in bits to length in bytes */
+	lpk->u.ec.publicValue.len >>= 3;
+        rv = SECITEM_CopyItem(arena, 
+			      &(lpk->u.ec.ecParams.DEREncoding),
+	                      &(pki->algorithm.parameters));
+	if(rv != SECSuccess) {
+	    goto loser;
+	}
+    }
+#endif /* NSS_ENABLE_ECC */
+
+    if(rv != SECSuccess) {
+	goto loser;
+    }
+    if(paramDest && paramTemplate) {
+	rv = SEC_QuickDERDecodeItem(arena, paramDest, paramTemplate, 
+				 &(pki->algorithm.parameters));
+	if(rv != SECSuccess) {
+	    goto loser;
+	}
+    }
+
+    rv = SECFailure;
+
+    switch (lpk->keyType) {
+        case NSSLOWKEYRSAKey:
+	    keyType = CKK_RSA;
+	    if(sftk_hasAttribute(key, CKA_NETSCAPE_DB)) {
+		sftk_DeleteAttributeType(key, CKA_NETSCAPE_DB);
+	    }
+	    crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
+					sizeof(keyType));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_UNWRAP, &cktrue, 
+					sizeof(CK_BBOOL));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_DECRYPT, &cktrue, 
+					sizeof(CK_BBOOL));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
+					sizeof(CK_BBOOL));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
+				    sizeof(CK_BBOOL));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_MODULUS, 
+				sftk_item_expand(&lpk->u.rsa.modulus));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_PUBLIC_EXPONENT, 
+	     			sftk_item_expand(&lpk->u.rsa.publicExponent));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_PRIVATE_EXPONENT, 
+	     			sftk_item_expand(&lpk->u.rsa.privateExponent));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_PRIME_1, 
+				sftk_item_expand(&lpk->u.rsa.prime1));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_PRIME_2, 
+	     			sftk_item_expand(&lpk->u.rsa.prime2));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_EXPONENT_1, 
+	     			sftk_item_expand(&lpk->u.rsa.exponent1));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_EXPONENT_2, 
+	     			sftk_item_expand(&lpk->u.rsa.exponent2));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_COEFFICIENT, 
+	     			sftk_item_expand(&lpk->u.rsa.coefficient));
+	    break;
+        case NSSLOWKEYDSAKey:
+	    keyType = CKK_DSA;
+	    crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
+						CKR_KEY_TYPE_INCONSISTENT;
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
+						sizeof(keyType));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
+						sizeof(CK_BBOOL));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
+						sizeof(CK_BBOOL)); 
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_PRIME,    
+				    sftk_item_expand(&lpk->u.dsa.params.prime));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_SUBPRIME,
+				 sftk_item_expand(&lpk->u.dsa.params.subPrime));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_BASE,  
+				    sftk_item_expand(&lpk->u.dsa.params.base));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_VALUE, 
+			sftk_item_expand(&lpk->u.dsa.privateValue));
+	    if(crv != CKR_OK) break;
+	    break;
+#ifdef notdef
+        case NSSLOWKEYDHKey:
+	    template = dhTemplate;
+	    templateCount = sizeof(dhTemplate)/sizeof(CK_ATTRIBUTE);
+	    keyType = CKK_DH;
+	    break;
+#endif
+	/* what about fortezza??? */
+#ifdef NSS_ENABLE_ECC
+        case NSSLOWKEYECKey:
+	    keyType = CKK_EC;
+	    crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
+						CKR_KEY_TYPE_INCONSISTENT;
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
+						sizeof(keyType));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
+						sizeof(CK_BBOOL));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
+						sizeof(CK_BBOOL)); 
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_DERIVE, &cktrue, 
+						sizeof(CK_BBOOL)); 
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_EC_PARAMS,
+				 sftk_item_expand(&lpk->u.ec.ecParams.DEREncoding));
+	    if(crv != CKR_OK) break;
+	    crv = sftk_AddAttributeType(key, CKA_VALUE, 
+			sftk_item_expand(&lpk->u.ec.privateValue));
+	    if(crv != CKR_OK) break;
+	    /* XXX Do we need to decode the EC Params here ?? */
+	    break;
+#endif /* NSS_ENABLE_ECC */
+	default:
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+    }
+
+loser:
+    if(lpk) {
+	nsslowkey_DestroyPrivateKey(lpk);
+    }
+
+    if(crv != CKR_OK) {
+	return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+
+/* NSC_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */
+CK_RV NSC_UnwrapKey(CK_SESSION_HANDLE hSession,
+    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,
+    CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,
+    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
+						 CK_OBJECT_HANDLE_PTR phKey)
+{
+    SFTKObject *key = NULL;
+    SFTKSession *session;
+    CK_ULONG key_length = 0;
+    unsigned char * buf = NULL;
+    CK_RV crv = CKR_OK;
+    int i;
+    CK_ULONG bsize = ulWrappedKeyLen;
+    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+    SECItem bpki;
+    CK_OBJECT_CLASS target_type = CKO_SECRET_KEY;
+
+    CHECK_FORK();
+
+    if (!slot) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * now lets create an object to hang the attributes off of
+     */
+    key = sftk_NewObject(slot); /* fill in the handle later */
+    if (key == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    /*
+     * load the template values into the object
+     */
+    for (i=0; i < (int) ulAttributeCount; i++) {
+	if (pTemplate[i].type == CKA_VALUE_LEN) {
+	    key_length = *(CK_ULONG *)pTemplate[i].pValue;
+	    continue;
+	}
+        if (pTemplate[i].type == CKA_CLASS) {
+	    target_type = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
+	}
+	crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
+	if (crv != CKR_OK) break;
+    }
+    if (crv != CKR_OK) {
+	sftk_FreeObject(key);
+	return crv;
+    }
+
+    crv = sftk_CryptInit(hSession,pMechanism,hUnwrappingKey,CKA_UNWRAP,
+							SFTK_DECRYPT, PR_FALSE);
+    if (crv != CKR_OK) {
+	sftk_FreeObject(key);
+	return sftk_mapWrap(crv);
+    }
+
+    /* allocate the buffer to decrypt into 
+     * this assumes the unwrapped key is never larger than the
+     * wrapped key. For all the mechanisms we support this is true */
+    buf = (unsigned char *)PORT_Alloc( ulWrappedKeyLen);
+    bsize = ulWrappedKeyLen;
+
+    crv = NSC_Decrypt(hSession, pWrappedKey, ulWrappedKeyLen, buf, &bsize);
+    if (crv != CKR_OK) {
+	sftk_FreeObject(key);
+	PORT_Free(buf);
+	return sftk_mapWrap(crv);
+    }
+
+    switch(target_type) {
+	case CKO_SECRET_KEY:
+	    if (!sftk_hasAttribute(key,CKA_KEY_TYPE)) {
+		crv = CKR_TEMPLATE_INCOMPLETE;
+		break;
+	    }
+
+	    if (key_length == 0 || key_length > bsize) {
+		key_length = bsize;
+	    }
+	    if (key_length > MAX_KEY_LEN) {
+		crv = CKR_TEMPLATE_INCONSISTENT;
+		break;
+	    }
+    
+	    /* add the value */
+	    crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
+	    break;
+	case CKO_PRIVATE_KEY:
+	    bpki.data = (unsigned char *)buf;
+	    bpki.len = bsize;
+	    crv = CKR_OK;
+	    if(sftk_unwrapPrivateKey(key, &bpki) != SECSuccess) {
+		crv = CKR_TEMPLATE_INCOMPLETE;
+	    }
+	    break;
+	default:
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+    }
+
+    PORT_ZFree(buf, bsize);
+    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
+
+    /* get the session */
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+	sftk_FreeObject(key);
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    /*
+     * handle the base object stuff
+     */
+    crv = sftk_handleObject(key,session);
+    *phKey = key->handle;
+    sftk_FreeSession(session);
+    sftk_FreeObject(key);
+
+    return crv;
+
+}
+
+/*
+ * The SSL key gen mechanism create's lots of keys. This function handles the
+ * details of each of these key creation.
+ */
+static CK_RV
+sftk_buildSSLKey(CK_SESSION_HANDLE hSession, SFTKObject *baseKey, 
+    PRBool isMacKey, unsigned char *keyBlock, unsigned int keySize,
+						 CK_OBJECT_HANDLE *keyHandle)
+{
+    SFTKObject *key;
+    SFTKSession *session;
+    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+    CK_BBOOL cktrue = CK_TRUE;
+    CK_BBOOL ckfalse = CK_FALSE;
+    CK_RV crv = CKR_HOST_MEMORY;
+
+    /*
+     * now lets create an object to hang the attributes off of
+     */
+    *keyHandle = CK_INVALID_HANDLE;
+    key = sftk_NewObject(baseKey->slot); 
+    if (key == NULL) return CKR_HOST_MEMORY;
+    sftk_narrowToSessionObject(key)->wasDerived = PR_TRUE;
+
+    crv = sftk_CopyObject(key,baseKey);
+    if (crv != CKR_OK) goto loser;
+    if (isMacKey) {
+	crv = sftk_forceAttribute(key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
+	if (crv != CKR_OK) goto loser;
+	crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
+	if (crv != CKR_OK) goto loser;
+	crv = sftk_forceAttribute(key,CKA_ENCRYPT,&ckfalse,sizeof(CK_BBOOL));
+	if (crv != CKR_OK) goto loser;
+	crv = sftk_forceAttribute(key,CKA_DECRYPT,&ckfalse,sizeof(CK_BBOOL));
+	if (crv != CKR_OK) goto loser;
+	crv = sftk_forceAttribute(key,CKA_SIGN,&cktrue,sizeof(CK_BBOOL));
+	if (crv != CKR_OK) goto loser;
+	crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
+	if (crv != CKR_OK) goto loser;
+	crv = sftk_forceAttribute(key,CKA_WRAP,&ckfalse,sizeof(CK_BBOOL));
+	if (crv != CKR_OK) goto loser;
+	crv = sftk_forceAttribute(key,CKA_UNWRAP,&ckfalse,sizeof(CK_BBOOL));
+	if (crv != CKR_OK) goto loser;
+    }
+    crv = sftk_forceAttribute(key,CKA_VALUE,keyBlock,keySize);
+    if (crv != CKR_OK) goto loser;
+
+    /* get the session */
+    crv = CKR_HOST_MEMORY;
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) { goto loser; }
+
+    crv = sftk_handleObject(key,session);
+    sftk_FreeSession(session);
+    *keyHandle = key->handle;
+loser:
+    if (key) sftk_FreeObject(key);
+    return crv;
+}
+
+/*
+ * if there is an error, we need to free the keys we already created in SSL
+ * This is the routine that will do it..
+ */
+static void
+sftk_freeSSLKeys(CK_SESSION_HANDLE session,
+				CK_SSL3_KEY_MAT_OUT *returnedMaterial ) 
+{
+	if (returnedMaterial->hClientMacSecret != CK_INVALID_HANDLE) {
+	   NSC_DestroyObject(session,returnedMaterial->hClientMacSecret);
+	}
+	if (returnedMaterial->hServerMacSecret != CK_INVALID_HANDLE) {
+	   NSC_DestroyObject(session, returnedMaterial->hServerMacSecret);
+	}
+	if (returnedMaterial->hClientKey != CK_INVALID_HANDLE) {
+	   NSC_DestroyObject(session, returnedMaterial->hClientKey);
+	}
+	if (returnedMaterial->hServerKey != CK_INVALID_HANDLE) {
+	   NSC_DestroyObject(session, returnedMaterial->hServerKey);
+	}
+}
+
+/*
+ * when deriving from sensitive and extractable keys, we need to preserve some
+ * of the semantics in the derived key. This helper routine maintains these
+ * semantics.
+ */
+static CK_RV
+sftk_DeriveSensitiveCheck(SFTKObject *baseKey,SFTKObject *destKey) 
+{
+    PRBool hasSensitive;
+    PRBool sensitive = PR_FALSE;
+    PRBool hasExtractable;
+    PRBool extractable = PR_TRUE;
+    CK_RV crv = CKR_OK;
+    SFTKAttribute *att;
+
+    hasSensitive = PR_FALSE;
+    att = sftk_FindAttribute(destKey,CKA_SENSITIVE);
+    if (att) {
+        hasSensitive = PR_TRUE;
+	sensitive = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
+	sftk_FreeAttribute(att);
+    }
+
+    hasExtractable = PR_FALSE;
+    att = sftk_FindAttribute(destKey,CKA_EXTRACTABLE);
+    if (att) {
+        hasExtractable = PR_TRUE;
+	extractable = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
+	sftk_FreeAttribute(att);
+    }
+
+
+    /* don't make a key more accessible */
+    if (sftk_isTrue(baseKey,CKA_SENSITIVE) && hasSensitive && 
+						(sensitive == PR_FALSE)) {
+	return CKR_KEY_FUNCTION_NOT_PERMITTED;
+    }
+    if (!sftk_isTrue(baseKey,CKA_EXTRACTABLE) && hasExtractable && 
+						(extractable == PR_TRUE)) {
+	return CKR_KEY_FUNCTION_NOT_PERMITTED;
+    }
+
+    /* inherit parent's sensitivity */
+    if (!hasSensitive) {
+        att = sftk_FindAttribute(baseKey,CKA_SENSITIVE);
+	if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
+	crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
+	sftk_FreeAttribute(att);
+	if (crv != CKR_OK) return crv;
+    }
+    if (!hasExtractable) {
+        att = sftk_FindAttribute(baseKey,CKA_EXTRACTABLE);
+	if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
+	crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
+	sftk_FreeAttribute(att);
+	if (crv != CKR_OK) return crv;
+    }
+
+    /* we should inherit the parent's always extractable/ never sensitive info,
+     * but handleObject always forces this attributes, so we would need to do
+     * something special. */
+    return CKR_OK;
+}
+
+/*
+ * make known fixed PKCS #11 key types to their sizes in bytes
+ */	
+unsigned long
+sftk_MapKeySize(CK_KEY_TYPE keyType) 
+{
+    switch (keyType) {
+    case CKK_CDMF:
+	return 8;
+    case CKK_DES:
+	return 8;
+    case CKK_DES2:
+	return 16;
+    case CKK_DES3:
+	return 24;
+    /* IDEA and CAST need to be added */
+    default:
+	break;
+    }
+    return 0;
+}
+
+/*
+ * SSL Key generation given pre master secret
+ */
+#define NUM_MIXERS 9
+static const char * const mixers[NUM_MIXERS] = { 
+    "A", 
+    "BB", 
+    "CCC", 
+    "DDDD", 
+    "EEEEE", 
+    "FFFFFF", 
+    "GGGGGGG",
+    "HHHHHHHH",
+    "IIIIIIIII" };
+#define SSL3_PMS_LENGTH 48
+#define SSL3_MASTER_SECRET_LENGTH 48
+#define SSL3_RANDOM_LENGTH 32
+
+
+/* NSC_DeriveKey derives a key from a base key, creating a new key object. */
+CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession,
+	 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey,
+	 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, 
+						CK_OBJECT_HANDLE_PTR phKey)
+{
+    SFTKSession *   session;
+    SFTKSlot    *   slot	= sftk_SlotFromSessionHandle(hSession);
+    SFTKObject  *   key;
+    SFTKObject  *   sourceKey;
+    SFTKAttribute * att;
+    SFTKAttribute * att2;
+    unsigned char * buf;
+    SHA1Context *   sha;
+    MD5Context *    md5;
+    MD2Context *    md2;
+    CK_ULONG        macSize;
+    CK_ULONG        tmpKeySize;
+    CK_ULONG        IVSize;
+    CK_ULONG        keySize	= 0;
+    CK_RV           crv 	= CKR_OK;
+    CK_BBOOL        cktrue	= CK_TRUE;
+    CK_KEY_TYPE     keyType	= CKK_GENERIC_SECRET;
+    CK_OBJECT_CLASS classType	= CKO_SECRET_KEY;
+    CK_KEY_DERIVATION_STRING_DATA *stringPtr;
+    PRBool          isTLS = PR_FALSE;
+    PRBool          isDH = PR_FALSE;
+    SECStatus       rv;
+    int             i;
+    unsigned int    outLen;
+    unsigned char   sha_out[SHA1_LENGTH];
+    unsigned char   key_block[NUM_MIXERS * MD5_LENGTH];
+    unsigned char   key_block2[MD5_LENGTH];
+    PRBool          isFIPS;		
+
+    CHECK_FORK();
+
+    if (!slot) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+    /*
+     * now lets create an object to hang the attributes off of
+     */
+    if (phKey) *phKey = CK_INVALID_HANDLE;
+
+    key = sftk_NewObject(slot); /* fill in the handle later */
+    if (key == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    isFIPS = (slot->slotID == FIPS_SLOT_ID);
+
+    /*
+     * load the template values into the object
+     */
+    for (i=0; i < (int) ulAttributeCount; i++) {
+	crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
+	if (crv != CKR_OK) break;
+
+	if (pTemplate[i].type == CKA_KEY_TYPE) {
+	    keyType = *(CK_KEY_TYPE *)pTemplate[i].pValue;
+	}
+	if (pTemplate[i].type == CKA_VALUE_LEN) {
+	    keySize = *(CK_ULONG *)pTemplate[i].pValue;
+	}
+    }
+    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
+
+    if (keySize == 0) {
+	keySize = sftk_MapKeySize(keyType);
+    }
+
+    /* Derive can only create SECRET KEY's currently... */
+    classType = CKO_SECRET_KEY;
+    crv = sftk_forceAttribute (key,CKA_CLASS,&classType,sizeof(classType));
+    if (crv != CKR_OK) {
+	sftk_FreeObject(key);
+	return crv;
+    }
+
+    /* look up the base key we're deriving with */ 
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) {
+	sftk_FreeObject(key);
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+
+    sourceKey = sftk_ObjectFromHandle(hBaseKey,session);
+    sftk_FreeSession(session);
+    if (sourceKey == NULL) {
+	sftk_FreeObject(key);
+        return CKR_KEY_HANDLE_INVALID;
+    }
+
+    /* get the value of the base key */
+    att = sftk_FindAttribute(sourceKey,CKA_VALUE);
+    if (att == NULL) {
+	sftk_FreeObject(key);
+	sftk_FreeObject(sourceKey);
+        return CKR_KEY_HANDLE_INVALID;
+    }
+
+    switch (pMechanism->mechanism) {
+    /*
+     * generate the master secret 
+     */
+    case CKM_TLS_MASTER_KEY_DERIVE:
+    case CKM_TLS_MASTER_KEY_DERIVE_DH:
+	isTLS = PR_TRUE;
+	/* fall thru */
+    case CKM_SSL3_MASTER_KEY_DERIVE:
+    case CKM_SSL3_MASTER_KEY_DERIVE_DH:
+      {
+	CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master;
+	SSL3RSAPreMasterSecret *          rsa_pms;
+	unsigned char                     crsrdata[SSL3_RANDOM_LENGTH * 2];
+
+        if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) ||
+            (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH))
+		isDH = PR_TRUE;
+
+	/* first do the consistancy checks */
+	if (!isDH && (att->attrib.ulValueLen != SSL3_PMS_LENGTH)) {
+	    crv = CKR_KEY_TYPE_INCONSISTENT;
+	    break;
+	}
+	att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
+	if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
+					CKK_GENERIC_SECRET)) {
+	    if (att2) sftk_FreeAttribute(att2);
+	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
+	    break;
+	}
+	sftk_FreeAttribute(att2);
+	if (keyType != CKK_GENERIC_SECRET) {
+	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
+	    break;
+	}
+	if ((keySize != 0) && (keySize != SSL3_MASTER_SECRET_LENGTH)) {
+	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
+	    break;
+	}
+
+	/* finally do the key gen */
+	ssl3_master = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)
+					pMechanism->pParameter;
+
+	PORT_Memcpy(crsrdata, 
+	            ssl3_master->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
+	PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
+	            ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
+
+	if (ssl3_master->pVersion) {
+	    SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
+	    rsa_pms = (SSL3RSAPreMasterSecret *) att->attrib.pValue;
+	    /* don't leak more key material then necessary for SSL to work */
+	    if ((sessKey == NULL) || sessKey->wasDerived) {
+		ssl3_master->pVersion->major = 0xff;
+		ssl3_master->pVersion->minor = 0xff;
+	    } else {
+		ssl3_master->pVersion->major = rsa_pms->client_version[0];
+		ssl3_master->pVersion->minor = rsa_pms->client_version[1];
+	    }
+	}
+	if (ssl3_master->RandomInfo.ulClientRandomLen != SSL3_RANDOM_LENGTH) {
+	   crv = CKR_MECHANISM_PARAM_INVALID;
+	   break;
+	}
+	if (ssl3_master->RandomInfo.ulServerRandomLen != SSL3_RANDOM_LENGTH) {
+	   crv = CKR_MECHANISM_PARAM_INVALID;
+	   break;
+	}
+
+        if (isTLS) {
+	    SECStatus status;
+ 	    SECItem crsr   = { siBuffer, NULL, 0 };
+ 	    SECItem master = { siBuffer, NULL, 0 };
+ 	    SECItem pms    = { siBuffer, NULL, 0 };
+
+ 	    crsr.data   = crsrdata;
+	    crsr.len    = sizeof crsrdata;
+ 	    master.data = key_block;
+	    master.len  = SSL3_MASTER_SECRET_LENGTH;
+ 	    pms.data    = (unsigned char*)att->attrib.pValue;
+	    pms.len     =                 att->attrib.ulValueLen;
+
+	    status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
+	    if (status != SECSuccess) {
+	    	crv = CKR_FUNCTION_FAILED;
+		break;
+	    }
+	} else {
+	    /* now allocate the hash contexts */
+	    md5 = MD5_NewContext();
+	    if (md5 == NULL) { 
+		crv = CKR_HOST_MEMORY;
+		break;
+	    }
+	    sha = SHA1_NewContext();
+	    if (sha == NULL) { 
+		PORT_Free(md5);
+		crv = CKR_HOST_MEMORY;
+		break;
+	    }
+            for (i = 0; i < 3; i++) {
+              SHA1_Begin(sha);
+              SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
+              SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
+			  att->attrib.ulValueLen);
+              SHA1_Update(sha, crsrdata, sizeof crsrdata);
+              SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
+              PORT_Assert(outLen == SHA1_LENGTH);
+
+              MD5_Begin(md5);
+              MD5_Update(md5, (const unsigned char*)att->attrib.pValue, 
+			 att->attrib.ulValueLen);
+              MD5_Update(md5, sha_out, outLen);
+              MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
+              PORT_Assert(outLen == MD5_LENGTH);
+            }
+	    PORT_Free(md5);
+	    PORT_Free(sha);
+	}
+
+	/* store the results */
+	crv = sftk_forceAttribute
+			(key,CKA_VALUE,key_block,SSL3_MASTER_SECRET_LENGTH);
+	if (crv != CKR_OK) break;
+	keyType = CKK_GENERIC_SECRET;
+	crv = sftk_forceAttribute (key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
+	if (isTLS) {
+	    /* TLS's master secret is used to "sign" finished msgs with PRF. */
+	    /* XXX This seems like a hack.   But SFTK_Derive only accepts 
+	     * one "operation" argument. */
+	    crv = sftk_forceAttribute(key,CKA_SIGN,  &cktrue,sizeof(CK_BBOOL));
+	    if (crv != CKR_OK) break;
+	    crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
+	    if (crv != CKR_OK) break;
+	    /* While we're here, we might as well force this, too. */
+	    crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
+	    if (crv != CKR_OK) break;
+	}
+	break;
+      }
+
+    case CKM_TLS_KEY_AND_MAC_DERIVE:
+	isTLS = PR_TRUE;
+	/* fall thru */
+    case CKM_SSL3_KEY_AND_MAC_DERIVE:
+      {
+	CK_SSL3_KEY_MAT_PARAMS *ssl3_keys;
+	CK_SSL3_KEY_MAT_OUT *   ssl3_keys_out;
+	CK_ULONG                effKeySize;
+	unsigned int            block_needed;
+	unsigned char           srcrdata[SSL3_RANDOM_LENGTH * 2];
+	unsigned char           crsrdata[SSL3_RANDOM_LENGTH * 2];
+
+	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
+	if (crv != CKR_OK) break;
+
+	if (att->attrib.ulValueLen != SSL3_MASTER_SECRET_LENGTH) {
+	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
+	    break;
+	}
+	att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
+	if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
+					CKK_GENERIC_SECRET)) {
+	    if (att2) sftk_FreeAttribute(att2);
+	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
+	    break;
+	}
+	sftk_FreeAttribute(att2);
+	md5 = MD5_NewContext();
+	if (md5 == NULL) { 
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	sha = SHA1_NewContext();
+	if (sha == NULL) { 
+	    PORT_Free(md5);
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter;
+
+	PORT_Memcpy(srcrdata, 
+	            ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
+	PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, 
+		    ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
+
+	PORT_Memcpy(crsrdata, 
+		    ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
+	PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
+		    ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
+
+	/*
+	 * clear out our returned keys so we can recover on failure
+	 */
+	ssl3_keys_out = ssl3_keys->pReturnedKeyMaterial;
+	ssl3_keys_out->hClientMacSecret = CK_INVALID_HANDLE;
+	ssl3_keys_out->hServerMacSecret = CK_INVALID_HANDLE;
+	ssl3_keys_out->hClientKey       = CK_INVALID_HANDLE;
+	ssl3_keys_out->hServerKey       = CK_INVALID_HANDLE;
+
+	/*
+	 * How much key material do we need?
+	 */
+	macSize    = ssl3_keys->ulMacSizeInBits/8;
+	effKeySize = ssl3_keys->ulKeySizeInBits/8;
+	IVSize     = ssl3_keys->ulIVSizeInBits/8;
+	if (keySize == 0) {
+	    effKeySize = keySize;
+	}
+	block_needed = 2 * (macSize + effKeySize + 
+	                    ((!ssl3_keys->bIsExport) * IVSize));
+	PORT_Assert(block_needed <= sizeof key_block);
+	if (block_needed > sizeof key_block)
+	    block_needed = sizeof key_block;
+
+	/*
+	 * generate the key material: This looks amazingly similar to the
+	 * PMS code, and is clearly crying out for a function to provide it.
+	 */
+	if (isTLS) {
+	    SECStatus     status;
+	    SECItem       srcr   = { siBuffer, NULL, 0 };
+	    SECItem       keyblk = { siBuffer, NULL, 0 };
+	    SECItem       master = { siBuffer, NULL, 0 }; 
+
+	    srcr.data   = srcrdata;
+	    srcr.len    = sizeof srcrdata;
+	    keyblk.data = key_block;
+	    keyblk.len  = block_needed;
+	    master.data = (unsigned char*)att->attrib.pValue;
+	    master.len  =                 att->attrib.ulValueLen;
+
+	    status = TLS_PRF(&master, "key expansion", &srcr, &keyblk,
+			      isFIPS);
+	    if (status != SECSuccess) {
+		goto key_and_mac_derive_fail;
+	    }
+	} else {
+	    unsigned int block_bytes = 0;
+	    /* key_block = 
+	     *     MD5(master_secret + SHA('A' + master_secret + 
+	     *                      ServerHello.random + ClientHello.random)) +
+	     *     MD5(master_secret + SHA('BB' + master_secret + 
+	     *                      ServerHello.random + ClientHello.random)) +
+	     *     MD5(master_secret + SHA('CCC' + master_secret + 
+	     *                      ServerHello.random + ClientHello.random)) +
+	     *     [...];
+	     */
+	    for (i = 0; i < NUM_MIXERS && block_bytes < block_needed; i++) {
+	      SHA1_Begin(sha);
+	      SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
+	      SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
+			  att->attrib.ulValueLen);
+	      SHA1_Update(sha, srcrdata, sizeof srcrdata);
+	      SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
+	      PORT_Assert(outLen == SHA1_LENGTH);
+	      MD5_Begin(md5);
+	      MD5_Update(md5, (const unsigned char*)att->attrib.pValue,
+			 att->attrib.ulValueLen);
+	      MD5_Update(md5, sha_out, outLen);
+	      MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
+	      PORT_Assert(outLen == MD5_LENGTH);
+	      block_bytes += outLen;
+	    }
+	}
+
+	/*
+	 * Put the key material where it goes.
+	 */
+	i = 0;			/* now shows how much consumed */
+
+	/* 
+	 * The key_block is partitioned as follows:
+	 * client_write_MAC_secret[CipherSpec.hash_size]
+	 */
+	crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
+					 &ssl3_keys_out->hClientMacSecret);
+	if (crv != CKR_OK)
+	    goto key_and_mac_derive_fail;
+
+	i += macSize;
+
+	/* 
+	 * server_write_MAC_secret[CipherSpec.hash_size]
+	 */
+	crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
+					    &ssl3_keys_out->hServerMacSecret);
+	if (crv != CKR_OK) {
+	    goto key_and_mac_derive_fail;
+	}
+	i += macSize;
+
+	if (keySize) {
+	    if (!ssl3_keys->bIsExport) {
+		/* 
+		** Generate Domestic write keys and IVs.
+		** client_write_key[CipherSpec.key_material]
+		*/
+		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
+					keySize, &ssl3_keys_out->hClientKey);
+		if (crv != CKR_OK) {
+		    goto key_and_mac_derive_fail;
+		}
+		i += keySize;
+
+		/* 
+		** server_write_key[CipherSpec.key_material]
+		*/
+		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
+					keySize, &ssl3_keys_out->hServerKey);
+		if (crv != CKR_OK) {
+		    goto key_and_mac_derive_fail;
+		}
+		i += keySize;
+
+		/* 
+		** client_write_IV[CipherSpec.IV_size]
+		*/
+		if (IVSize > 0) {
+		    PORT_Memcpy(ssl3_keys_out->pIVClient, 
+		                &key_block[i], IVSize);
+		    i += IVSize;
+		}
+
+		/* 
+		** server_write_IV[CipherSpec.IV_size]
+		*/
+		if (IVSize > 0) {
+		    PORT_Memcpy(ssl3_keys_out->pIVServer, 
+		                &key_block[i], IVSize);
+		    i += IVSize;
+		}
+		PORT_Assert(i <= sizeof key_block);
+
+	    } else if (!isTLS) {
+
+		/*
+		** Generate SSL3 Export write keys and IVs.
+		** client_write_key[CipherSpec.key_material]
+		** final_client_write_key = MD5(client_write_key +
+		**                   ClientHello.random + ServerHello.random);
+		*/
+		MD5_Begin(md5);
+		MD5_Update(md5, &key_block[i], effKeySize);
+            	MD5_Update(md5, crsrdata, sizeof crsrdata);
+		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
+		i += effKeySize;
+		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
+				 	keySize,&ssl3_keys_out->hClientKey);
+		if (crv != CKR_OK) {
+		    goto key_and_mac_derive_fail;
+		}
+
+		/*
+		** server_write_key[CipherSpec.key_material]
+		** final_server_write_key = MD5(server_write_key +
+		**                    ServerHello.random + ClientHello.random);
+		*/
+		MD5_Begin(md5);
+		MD5_Update(md5, &key_block[i], effKeySize);
+            	MD5_Update(md5, srcrdata, sizeof srcrdata);
+		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
+		i += effKeySize;
+		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
+					 keySize,&ssl3_keys_out->hServerKey);
+		if (crv != CKR_OK) {
+		    goto key_and_mac_derive_fail;
+		}
+
+		/*
+		** client_write_IV = 
+		**	MD5(ClientHello.random + ServerHello.random);
+		*/
+		MD5_Begin(md5);
+            	MD5_Update(md5, crsrdata, sizeof crsrdata);
+		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
+		PORT_Memcpy(ssl3_keys_out->pIVClient, key_block2, IVSize);
+
+		/*
+		** server_write_IV = 
+		**	MD5(ServerHello.random + ClientHello.random);
+		*/
+		MD5_Begin(md5);
+            	MD5_Update(md5, srcrdata, sizeof srcrdata);
+		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
+		PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize);
+
+	    } else {
+
+		/*
+		** Generate TLS Export write keys and IVs.
+		*/
+		SECStatus     status;
+		SECItem       secret = { siBuffer, NULL, 0 };
+		SECItem       crsr   = { siBuffer, NULL, 0 };
+		SECItem       keyblk = { siBuffer, NULL, 0 };
+
+		/*
+		** client_write_key[CipherSpec.key_material]
+		** final_client_write_key = PRF(client_write_key, 
+		**                              "client write key",
+		**                              client_random + server_random);
+		*/
+		secret.data = &key_block[i];
+		secret.len  = effKeySize;
+		i          += effKeySize;
+		crsr.data   = crsrdata;
+		crsr.len    = sizeof crsrdata;
+		keyblk.data = key_block2;
+		keyblk.len  = sizeof key_block2;
+		status = TLS_PRF(&secret, "client write key", &crsr, &keyblk,
+				  isFIPS);
+		if (status != SECSuccess) {
+		    goto key_and_mac_derive_fail;
+		}
+		crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
+				       keySize, &ssl3_keys_out->hClientKey);
+		if (crv != CKR_OK) {
+		    goto key_and_mac_derive_fail;
+		}
+
+		/*
+		** server_write_key[CipherSpec.key_material]
+		** final_server_write_key = PRF(server_write_key,
+		**                              "server write key",
+		**                              client_random + server_random);
+		*/
+		secret.data = &key_block[i];
+		secret.len  = effKeySize;
+		i          += effKeySize;
+		keyblk.data = key_block2;
+		keyblk.len  = sizeof key_block2;
+		status = TLS_PRF(&secret, "server write key", &crsr, &keyblk,
+				  isFIPS);
+		if (status != SECSuccess) {
+		    goto key_and_mac_derive_fail;
+		}
+		crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
+				       keySize, &ssl3_keys_out->hServerKey);
+		if (crv != CKR_OK) {
+		    goto key_and_mac_derive_fail;
+		}
+
+		/*
+		** iv_block = PRF("", "IV block", 
+		**                    client_random + server_random);
+		** client_write_IV[SecurityParameters.IV_size]
+		** server_write_IV[SecurityParameters.IV_size]
+		*/
+		if (IVSize) {
+		    secret.data = NULL;
+		    secret.len  = 0;
+		    keyblk.data = &key_block[i];
+		    keyblk.len  = 2 * IVSize;
+		    status = TLS_PRF(&secret, "IV block", &crsr, &keyblk,
+				      isFIPS);
+		    if (status != SECSuccess) {
+			goto key_and_mac_derive_fail;
+		    }
+		    PORT_Memcpy(ssl3_keys_out->pIVClient, keyblk.data, IVSize);
+		    PORT_Memcpy(ssl3_keys_out->pIVServer, keyblk.data + IVSize,
+                                IVSize);
+		}
+	    }
+	}
+
+	crv = CKR_OK;
+
+	if (0) {
+key_and_mac_derive_fail:
+	    if (crv == CKR_OK)
+	    	crv = CKR_FUNCTION_FAILED;
+	    sftk_freeSSLKeys(hSession, ssl3_keys_out);
+	}
+	MD5_DestroyContext(md5, PR_TRUE);
+	SHA1_DestroyContext(sha, PR_TRUE);
+	sftk_FreeObject(key);
+	key = NULL;
+	break;
+      }
+
+    case CKM_CONCATENATE_BASE_AND_KEY:
+      {
+	SFTKObject *newKey;
+
+	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
+	if (crv != CKR_OK) break;
+
+	session = sftk_SessionFromHandle(hSession);
+	if (session == NULL) {
+            crv = CKR_SESSION_HANDLE_INVALID;
+	    break;
+    	}
+
+	newKey = sftk_ObjectFromHandle(*(CK_OBJECT_HANDLE *)
+					pMechanism->pParameter,session);
+	sftk_FreeSession(session);
+	if ( newKey == NULL) {
+            crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+
+	if (sftk_isTrue(newKey,CKA_SENSITIVE)) {
+	    crv = sftk_forceAttribute(newKey,CKA_SENSITIVE,&cktrue,
+							sizeof(CK_BBOOL));
+	    if (crv != CKR_OK) {
+		sftk_FreeObject(newKey);
+		break;
+	    }
+	}
+
+	att2 = sftk_FindAttribute(newKey,CKA_VALUE);
+	if (att2 == NULL) {
+	    sftk_FreeObject(newKey);
+            crv = CKR_KEY_HANDLE_INVALID;
+	    break;
+	}
+	tmpKeySize = att->attrib.ulValueLen+att2->attrib.ulValueLen;
+	if (keySize == 0) keySize = tmpKeySize;
+	if (keySize > tmpKeySize) {
+	    sftk_FreeObject(newKey);
+	    sftk_FreeAttribute(att2);
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+	}
+	buf = (unsigned char*)PORT_Alloc(tmpKeySize);
+	if (buf == NULL) {
+	    sftk_FreeAttribute(att2);
+	    sftk_FreeObject(newKey);
+	    crv = CKR_HOST_MEMORY;	
+	    break;
+	}
+
+	PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
+	PORT_Memcpy(buf+att->attrib.ulValueLen,
+				att2->attrib.pValue,att2->attrib.ulValueLen);
+
+	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
+	PORT_ZFree(buf,tmpKeySize);
+	sftk_FreeAttribute(att2);
+	sftk_FreeObject(newKey);
+	break;
+      }
+
+    case CKM_CONCATENATE_BASE_AND_DATA:
+	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
+	if (crv != CKR_OK) break;
+
+	stringPtr = (CK_KEY_DERIVATION_STRING_DATA *) pMechanism->pParameter;
+	tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
+	if (keySize == 0) keySize = tmpKeySize;
+	if (keySize > tmpKeySize) {
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+	}
+	buf = (unsigned char*)PORT_Alloc(tmpKeySize);
+	if (buf == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+
+	PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
+	PORT_Memcpy(buf+att->attrib.ulValueLen,stringPtr->pData,
+							stringPtr->ulLen);
+
+	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
+	PORT_ZFree(buf,tmpKeySize);
+	break;
+    case CKM_CONCATENATE_DATA_AND_BASE:
+	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
+	if (crv != CKR_OK) break;
+
+	stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
+	tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
+	if (keySize == 0) keySize = tmpKeySize;
+	if (keySize > tmpKeySize) {
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+	}
+	buf = (unsigned char*)PORT_Alloc(tmpKeySize);
+	if (buf == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+
+	PORT_Memcpy(buf,stringPtr->pData,stringPtr->ulLen);
+	PORT_Memcpy(buf+stringPtr->ulLen,att->attrib.pValue,
+							att->attrib.ulValueLen);
+
+	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
+	PORT_ZFree(buf,tmpKeySize);
+	break;
+    case CKM_XOR_BASE_AND_DATA:
+	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
+	if (crv != CKR_OK) break;
+
+	stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
+	tmpKeySize = PR_MIN(att->attrib.ulValueLen,stringPtr->ulLen);
+	if (keySize == 0) keySize = tmpKeySize;
+	if (keySize > tmpKeySize) {
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+	}
+	buf = (unsigned char*)PORT_Alloc(keySize);
+	if (buf == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+
+	
+	PORT_Memcpy(buf,att->attrib.pValue,keySize);
+	for (i=0; i < (int)keySize; i++) {
+	    buf[i] ^= stringPtr->pData[i];
+	}
+
+	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
+	PORT_ZFree(buf,keySize);
+	break;
+
+    case CKM_EXTRACT_KEY_FROM_KEY:
+      {
+	/* the following assumes 8 bits per byte */
+	CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter;
+	CK_ULONG shift   = extract & 0x7;      /* extract mod 8 the fast way */
+	CK_ULONG offset  = extract >> 3;       /* extract div 8 the fast way */
+
+	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
+	if (crv != CKR_OK) break;
+
+	if (keySize == 0)  {
+	    crv = CKR_TEMPLATE_INCOMPLETE;
+	    break;
+	}
+	/* make sure we have enough bits in the original key */
+	if (att->attrib.ulValueLen < 
+			(offset + keySize + ((shift != 0)? 1 :0)) ) {
+	    crv = CKR_MECHANISM_PARAM_INVALID;
+	    break;
+	}
+	buf = (unsigned char*)PORT_Alloc(keySize);
+	if (buf == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+
+	/* copy the bits we need into the new key */	
+	for (i=0; i < (int)keySize; i++) {
+	    unsigned char *value =
+			 ((unsigned char *)att->attrib.pValue)+offset+i;
+	    if (shift) {
+	        buf[i] = (value[0] << (shift)) | (value[1] >> (8 - shift));
+	    } else {
+		buf[i] = value[0];
+	    }
+	}
+
+	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
+	PORT_ZFree(buf,keySize);
+	break;
+      }
+    case CKM_MD2_KEY_DERIVATION:
+	if (keySize == 0) keySize = MD2_LENGTH;
+	if (keySize > MD2_LENGTH) {
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+	}
+	/* now allocate the hash contexts */
+	md2 = MD2_NewContext();
+	if (md2 == NULL) { 
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	MD2_Begin(md2);
+	MD2_Update(md2,(const unsigned char*)att->attrib.pValue,
+		   att->attrib.ulValueLen);
+	MD2_End(md2,key_block,&outLen,MD2_LENGTH);
+	MD2_DestroyContext(md2, PR_TRUE);
+
+	crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
+	break;
+    case CKM_MD5_KEY_DERIVATION:
+	if (keySize == 0) keySize = MD5_LENGTH;
+	if (keySize > MD5_LENGTH) {
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+	}
+	/* now allocate the hash contexts */
+	md5 = MD5_NewContext();
+	if (md5 == NULL) { 
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	MD5_Begin(md5);
+	MD5_Update(md5,(const unsigned char*)att->attrib.pValue,
+		   att->attrib.ulValueLen);
+	MD5_End(md5,key_block,&outLen,MD5_LENGTH);
+	MD5_DestroyContext(md5, PR_TRUE);
+
+	crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
+	break;
+     case CKM_SHA1_KEY_DERIVATION:
+	if (keySize == 0) keySize = SHA1_LENGTH;
+	if (keySize > SHA1_LENGTH) {
+	    crv = CKR_TEMPLATE_INCONSISTENT;
+	    break;
+	}
+	/* now allocate the hash contexts */
+	sha = SHA1_NewContext();
+	if (sha == NULL) { 
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+	SHA1_Begin(sha);
+	SHA1_Update(sha,(const unsigned char*)att->attrib.pValue,
+		    att->attrib.ulValueLen);
+	SHA1_End(sha,key_block,&outLen,SHA1_LENGTH);
+	SHA1_DestroyContext(sha, PR_TRUE);
+
+	crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize);
+	break;
+
+    case CKM_DH_PKCS_DERIVE:
+      {
+	SECItem  derived,  dhPublic;
+	SECItem  dhPrime,  dhValue;
+	/* sourceKey - values for the local existing low key */
+	/* get prime and value attributes */
+	crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME); 
+	if (crv != SECSuccess) break;
+	crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE); 
+	if (crv != SECSuccess) {
+ 	    PORT_Free(dhPrime.data);
+	    break;
+	}
+
+	dhPublic.data = pMechanism->pParameter;
+	dhPublic.len  = pMechanism->ulParameterLen;
+
+	/* calculate private value - oct */
+	rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize); 
+
+	PORT_Free(dhPrime.data);
+	PORT_Free(dhValue.data);
+     
+	if (rv == SECSuccess) {
+	    sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
+	    PORT_ZFree(derived.data, derived.len);
+	} else
+	    crv = CKR_HOST_MEMORY;
+	    
+	break;
+      }
+
+#ifdef NSS_ENABLE_ECC
+    case CKM_ECDH1_DERIVE:
+    case CKM_ECDH1_COFACTOR_DERIVE:
+      {
+	SECItem  ecScalar, ecPoint;
+	SECItem  tmp;
+	PRBool   withCofactor = PR_FALSE;
+	unsigned char secret_hash[20];
+	unsigned char *secret;
+	unsigned char *keyData = NULL;
+	int secretlen, curveLen, pubKeyLen;
+	CK_ECDH1_DERIVE_PARAMS *mechParams;
+	NSSLOWKEYPrivateKey *privKey;
+	PLArenaPool *arena = NULL;
+
+	/* Check mechanism parameters */
+	mechParams = (CK_ECDH1_DERIVE_PARAMS *) pMechanism->pParameter;
+	if ((pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) ||
+	    ((mechParams->kdf == CKD_NULL) &&
+		((mechParams->ulSharedDataLen != 0) || 
+		    (mechParams->pSharedData != NULL)))) {
+	    crv = CKR_MECHANISM_PARAM_INVALID;
+	    break;
+	}
+
+	privKey = sftk_GetPrivKey(sourceKey, CKK_EC, &crv);
+	if (privKey == NULL) {
+	    break;
+	}
+
+	/* Now we are working with a non-NULL private key */
+	SECITEM_CopyItem(NULL, &ecScalar, &privKey->u.ec.privateValue);
+
+	ecPoint.data = mechParams->pPublicData;
+	ecPoint.len  = mechParams->ulPublicDataLen;
+
+	curveLen = (privKey->u.ec.ecParams.fieldID.size +7)/8;
+	pubKeyLen = (2*curveLen) + 1;
+
+	/* if the len is too small, can't be a valid point */
+	if (ecPoint.len < pubKeyLen) {
+	    goto ec_loser;
+	}
+	/* if the len is too large, must be an encoded point (length is
+	 * equal case just falls through */
+	if (ecPoint.len > pubKeyLen) {
+	    SECItem newPoint;
+
+	    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+	    if (arena == NULL) {
+		goto ec_loser;
+	    }
+
+	    rv = SEC_QuickDERDecodeItem(arena, &newPoint, 
+					SEC_ASN1_GET(SEC_OctetStringTemplate), 
+					&ecPoint);
+	    if (rv != SECSuccess) {
+		goto ec_loser;
+	    }
+	    ecPoint = newPoint;
+	}
+
+	if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
+	    withCofactor = PR_TRUE;
+	} else {
+	    /* When not using cofactor derivation, one should
+	     * validate the public key to avoid small subgroup
+	     * attacks.
+	     */
+	    if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint) 
+		!= SECSuccess) {
+		goto ec_loser;
+	    }
+	}
+
+	rv = ECDH_Derive(&ecPoint, &privKey->u.ec.ecParams, &ecScalar,
+	                 withCofactor, &tmp); 
+	PORT_Free(ecScalar.data);
+	ecScalar.data = NULL;
+	if (privKey != sourceKey->objectInfo) {
+	   nsslowkey_DestroyPrivateKey(privKey);
+	   privKey=NULL;
+	}
+	if (arena) {
+	    PORT_FreeArena(arena,PR_FALSE);
+	    arena=NULL;
+	}
+
+	if (rv != SECSuccess) {
+	    crv = sftk_MapCryptError(PORT_GetError());
+	    break;
+	}
+
+	/*
+	 * tmp is the raw data created by ECDH_Derive,
+	 * secret and secretlen are the values we will eventually pass as our
+	 * generated key.
+	 */
+	secret = tmp.data;
+	secretlen = tmp.len;
+
+	/*
+	 * apply the kdf function.
+	 */
+	if (mechParams->kdf == CKD_SHA1_KDF) {
+	    /* Compute SHA1 hash */
+	    PORT_Memset(secret_hash, 0, 20);
+	    rv = SHA1_HashBuf(secret_hash, tmp.data, tmp.len);
+	    if (rv != SECSuccess) {
+		PORT_ZFree(tmp.data, tmp.len);
+		crv = CKR_HOST_MEMORY;
+		break;
+	    } 
+	    secret = secret_hash;
+	    secretlen = 20;
+	}
+
+	/*
+	 * if keySize is supplied, then we are generating a key of a specific 
+	 * length. This is done by taking the least significant 'keySize' 
+	 * bytes from the unsigned value calculated by ECDH. Note: this may 
+	 * mean padding temp with extra leading zeros from what ECDH_Derive 
+	 * already returned (which itself may contain leading zeros).
+ 	 */
+	if (keySize) {
+	    if (secretlen < keySize) {
+	        keyData = PORT_ZAlloc(keySize);
+		if (!keyData) {
+		    PORT_ZFree(tmp.data, tmp.len);
+		    crv = CKR_HOST_MEMORY;
+		    break;
+		}
+		PORT_Memcpy(&keyData[keySize-secretlen],secret,secretlen);
+		secret = keyData;
+	    } else {
+		secret += (secretlen - keySize);
+	    }
+	    secretlen = keySize;
+	}
+
+	sftk_forceAttribute(key, CKA_VALUE, secret, secretlen);
+	PORT_ZFree(tmp.data, tmp.len);
+	if (keyData) {
+	    PORT_ZFree(keyData, keySize);
+	}
+	PORT_Memset(secret_hash, 0, 20);
+	    
+	break;
+
+ec_loser:
+	crv = CKR_ARGUMENTS_BAD;
+	PORT_Free(ecScalar.data);
+	if (privKey != sourceKey->objectInfo)
+	    nsslowkey_DestroyPrivateKey(privKey);
+	if (arena) {
+	    PORT_FreeArena(arena, PR_FALSE);
+	}
+	break;
+
+      }
+#endif /* NSS_ENABLE_ECC */
+
+    default:
+	crv = CKR_MECHANISM_INVALID;
+    }
+    sftk_FreeAttribute(att);
+    sftk_FreeObject(sourceKey);
+    if (crv != CKR_OK) { 
+	if (key) sftk_FreeObject(key);
+	return crv;
+    }
+
+    /* link the key object into the list */
+    if (key) {
+	SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
+	PORT_Assert(sessKey);
+	/* get the session */
+	sessKey->wasDerived = PR_TRUE;
+	session = sftk_SessionFromHandle(hSession);
+	if (session == NULL) {
+	    sftk_FreeObject(key);
+	    return CKR_HOST_MEMORY;
+	}
+
+	crv = sftk_handleObject(key,session);
+	sftk_FreeSession(session);
+	*phKey = key->handle;
+	sftk_FreeObject(key);
+    }
+    return crv;
+}
+
+
+/* NSC_GetFunctionStatus obtains an updated status of a function running 
+ * in parallel with an application. */
+CK_RV NSC_GetFunctionStatus(CK_SESSION_HANDLE hSession)
+{
+    CHECK_FORK();
+
+    return CKR_FUNCTION_NOT_PARALLEL;
+}
+
+/* NSC_CancelFunction cancels a function running in parallel */
+CK_RV NSC_CancelFunction(CK_SESSION_HANDLE hSession)
+{
+    CHECK_FORK();
+
+    return CKR_FUNCTION_NOT_PARALLEL;
+}
+
+/* NSC_GetOperationState saves the state of the cryptographic 
+ *operation in a session.
+ * NOTE: This code only works for digest functions for now. eventually need
+ * to add full flatten/resurect to our state stuff so that all types of state
+ * can be saved */
+CK_RV NSC_GetOperationState(CK_SESSION_HANDLE hSession, 
+	CK_BYTE_PTR  pOperationState, CK_ULONG_PTR pulOperationStateLen)
+{
+    SFTKSessionContext *context;
+    SFTKSession *session;
+    CK_RV crv;
+    CK_ULONG pOSLen = *pulOperationStateLen;
+
+    CHECK_FORK();
+
+    /* make sure we're legal */
+    crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session);
+    if (crv != CKR_OK) return crv;
+
+    *pulOperationStateLen = context->cipherInfoLen + sizeof(CK_MECHANISM_TYPE)
+				+ sizeof(SFTKContextType);
+    if (pOperationState == NULL) {
+        sftk_FreeSession(session);
+	return CKR_OK;
+    } else {
+	if (pOSLen < *pulOperationStateLen) {
+	    return CKR_BUFFER_TOO_SMALL;
+	}
+    }
+    PORT_Memcpy(pOperationState,&context->type,sizeof(SFTKContextType));
+    pOperationState += sizeof(SFTKContextType);
+    PORT_Memcpy(pOperationState,&context->currentMech,
+						sizeof(CK_MECHANISM_TYPE));
+    pOperationState += sizeof(CK_MECHANISM_TYPE);
+    PORT_Memcpy(pOperationState,context->cipherInfo,context->cipherInfoLen);
+    sftk_FreeSession(session);
+    return CKR_OK;
+}
+
+
+#define sftk_Decrement(stateSize,len) \
+	stateSize = ((stateSize) > (CK_ULONG)(len)) ? \
+				((stateSize) - (CK_ULONG)(len)) : 0;
+
+/* NSC_SetOperationState restores the state of the cryptographic 
+ * operation in a session. This is coded like it can restore lots of
+ * states, but it only works for truly flat cipher structures. */
+CK_RV NSC_SetOperationState(CK_SESSION_HANDLE hSession, 
+	CK_BYTE_PTR  pOperationState, CK_ULONG  ulOperationStateLen,
+        CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey)
+{
+    SFTKSessionContext *context;
+    SFTKSession *session;
+    SFTKContextType type;
+    CK_MECHANISM mech;
+    CK_RV crv = CKR_OK;
+
+    CHECK_FORK();
+
+    while (ulOperationStateLen != 0) {
+	/* get what type of state we're dealing with... */
+	PORT_Memcpy(&type,pOperationState, sizeof(SFTKContextType));
+
+	/* fix up session contexts based on type */
+	session = sftk_SessionFromHandle(hSession);
+	if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+	context = sftk_ReturnContextByType(session, type);
+	sftk_SetContextByType(session, type, NULL);
+	if (context) { 
+	     sftk_FreeContext(context);
+	}
+	pOperationState += sizeof(SFTKContextType);
+	sftk_Decrement(ulOperationStateLen,sizeof(SFTKContextType));
+
+
+	/* get the mechanism structure */
+	PORT_Memcpy(&mech.mechanism,pOperationState,sizeof(CK_MECHANISM_TYPE));
+	pOperationState += sizeof(CK_MECHANISM_TYPE);
+	sftk_Decrement(ulOperationStateLen, sizeof(CK_MECHANISM_TYPE));
+	/* should be filled in... but not necessary for hash */
+	mech.pParameter = NULL;
+	mech.ulParameterLen = 0;
+	switch (type) {
+	case SFTK_HASH:
+	    crv = NSC_DigestInit(hSession,&mech);
+	    if (crv != CKR_OK) break;
+	    crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, 
+								NULL);
+	    if (crv != CKR_OK) break;
+	    PORT_Memcpy(context->cipherInfo,pOperationState,
+						context->cipherInfoLen);
+	    pOperationState += context->cipherInfoLen;
+	    sftk_Decrement(ulOperationStateLen,context->cipherInfoLen);
+	    break;
+	default:
+	    /* do sign/encrypt/decrypt later */
+	    crv = CKR_SAVED_STATE_INVALID;
+         }
+         sftk_FreeSession(session);
+	 if (crv != CKR_OK) break;
+    }
+    return crv;
+}
+
+/* Dual-function cryptographic operations */
+
+/* NSC_DigestEncryptUpdate continues a multiple-part digesting and encryption 
+ * operation. */
+CK_RV NSC_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
+    CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
+					 CK_ULONG_PTR pulEncryptedPartLen)
+{
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart,	
+						      pulEncryptedPartLen);
+    if (crv != CKR_OK) return crv;
+    crv = NSC_DigestUpdate(hSession,pPart,ulPartLen);
+
+    return crv;
+}
+
+
+/* NSC_DecryptDigestUpdate continues a multiple-part decryption and 
+ * digesting operation. */
+CK_RV NSC_DecryptDigestUpdate(CK_SESSION_HANDLE hSession,
+    CK_BYTE_PTR  pEncryptedPart, CK_ULONG  ulEncryptedPartLen,
+    				CK_BYTE_PTR  pPart, CK_ULONG_PTR pulPartLen)
+{
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    crv = NSC_DecryptUpdate(hSession,pEncryptedPart, ulEncryptedPartLen, 
+							pPart,	pulPartLen);
+    if (crv != CKR_OK) return crv;
+    crv = NSC_DigestUpdate(hSession,pPart,*pulPartLen);
+
+    return crv;
+}
+
+
+/* NSC_SignEncryptUpdate continues a multiple-part signing and 
+ * encryption operation. */
+CK_RV NSC_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
+	 CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
+					 CK_ULONG_PTR pulEncryptedPartLen)
+{
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart,	
+						      pulEncryptedPartLen);
+    if (crv != CKR_OK) return crv;
+    crv = NSC_SignUpdate(hSession,pPart,ulPartLen);
+
+    return crv;
+}
+
+
+/* NSC_DecryptVerifyUpdate continues a multiple-part decryption 
+ * and verify operation. */
+CK_RV NSC_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, 
+	CK_BYTE_PTR  pEncryptedData, CK_ULONG  ulEncryptedDataLen, 
+				CK_BYTE_PTR  pData, CK_ULONG_PTR pulDataLen)
+{
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    crv = NSC_DecryptUpdate(hSession,pEncryptedData, ulEncryptedDataLen, 
+							pData,	pulDataLen);
+    if (crv != CKR_OK) return crv;
+    crv = NSC_VerifyUpdate(hSession, pData, *pulDataLen);
+
+    return crv;
+}
+
+/* NSC_DigestKey continues a multi-part message-digesting operation,
+ * by digesting the value of a secret key as part of the data already digested.
+ */
+CK_RV NSC_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) 
+{
+    SFTKSession *session = NULL;
+    SFTKObject *key = NULL;
+    SFTKAttribute *att;
+    CK_RV crv;
+
+    CHECK_FORK();
+
+    session = sftk_SessionFromHandle(hSession);
+    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+    key = sftk_ObjectFromHandle(hKey,session);
+    sftk_FreeSession(session);
+    if (key == NULL)  return CKR_KEY_HANDLE_INVALID;
+
+    /* PUT ANY DIGEST KEY RESTRICTION CHECKS HERE */
+
+    /* make sure it's a valid  key for this operation */
+    if (key->objclass != CKO_SECRET_KEY) {
+	sftk_FreeObject(key);
+	return CKR_KEY_TYPE_INCONSISTENT;
+    }
+    /* get the key value */
+    att = sftk_FindAttribute(key,CKA_VALUE);
+    sftk_FreeObject(key);
+    if (!att) {
+        return CKR_KEY_HANDLE_INVALID;        
+    }
+    crv = NSC_DigestUpdate(hSession,(CK_BYTE_PTR)att->attrib.pValue,
+			   att->attrib.ulValueLen);
+    sftk_FreeAttribute(att);
+    return crv;
+}
diff --git a/mozilla/security/nss/lib/softoken/pkcs11i.h b/mozilla/security/nss/lib/softoken/pkcs11i.h
new file mode 100644
index 0000000..32d62c9
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/pkcs11i.h
@@ -0,0 +1,716 @@
+/* ***** 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 ***** */
+/*
+ * Internal data structures and functions used by pkcs11.c
+ */
+#ifndef _PKCS11I_H_
+#define _PKCS11I_H_ 1
+
+#include "nssilock.h"
+#include "seccomon.h"
+#include "secoidt.h"
+#include "lowkeyti.h"
+#include "pkcs11t.h"
+
+#include "sftkdbt.h"
+
+
+/* 
+ * Configuration Defines 
+ *
+ * The following defines affect the space verse speed trade offs of
+ * the PKCS #11 module. For the most part the current settings are optimized
+ * for web servers, where we want faster speed and lower lock contention at
+ * the expense of space.
+ */
+
+/* 
+ * The attribute allocation strategy is static allocation:
+ *   Attributes are pre-allocated as part of the session object and used from
+ *   the object array.
+ */
+#define MAX_OBJS_ATTRS 45	/* number of attributes to preallocate in
+				 * the object (must me the absolute max) */
+#define ATTR_SPACE 50  		/* Maximum size of attribute data before extra
+				 * data needs to be allocated. This is set to
+				 * enough space to hold an SSL MASTER secret */
+
+#define NSC_STRICT      PR_FALSE  /* forces the code to do strict template
+				   * matching when doing C_FindObject on token
+				   * objects. This will slow down search in
+				   * NSS. */
+/* default search block allocations and increments */
+#define NSC_CERT_BLOCK_SIZE     50
+#define NSC_SEARCH_BLOCK_SIZE   5 
+#define NSC_SLOT_LIST_BLOCK_SIZE 10
+
+#define NSC_FIPS_MODULE 1
+#define NSC_NON_FIPS_MODULE 0
+
+/* these are data base storage hashes, not cryptographic hashes.. The define
+ * the effective size of the various object hash tables */
+/* clients care more about memory usage than lookup performance on
+ * cyrptographic objects. Clients also have less objects around to play with 
+ *
+ * we eventually should make this configurable at runtime! Especially now that
+ * NSS is a shared library.
+ */
+#define SPACE_ATTRIBUTE_HASH_SIZE 32 
+#define SPACE_SESSION_OBJECT_HASH_SIZE 32
+#define SPACE_SESSION_HASH_SIZE 32
+#define TIME_ATTRIBUTE_HASH_SIZE 32
+#define TIME_SESSION_OBJECT_HASH_SIZE 1024
+#define TIME_SESSION_HASH_SIZE 1024
+#define MAX_OBJECT_LIST_SIZE 800  
+				  /* how many objects to keep on the free list
+				   * before we start freeing them */
+#define MAX_KEY_LEN 256 	  /* maximum symmetric key length in bytes */
+
+#define MULTIACCESS "multiaccess:"
+
+/*
+ * LOG2_BUCKETS_PER_SESSION_LOCK must be a prime number.
+ * With SESSION_HASH_SIZE=1024, LOG2 can be 9, 5, 1, or 0.
+ * With SESSION_HASH_SIZE=4096, LOG2 can be 11, 9, 5, 1, or 0.
+ *
+ * HASH_SIZE   LOG2_BUCKETS_PER   BUCKETS_PER_LOCK  NUMBER_OF_BUCKETS
+ * 1024        9                  512               2
+ * 1024        5                  32                32
+ * 1024        1                  2                 512
+ * 1024        0                  1                 1024
+ * 4096        11                 2048              2
+ * 4096        9                  512               8
+ * 4096        5                  32                128
+ * 4096        1                  2                 2048
+ * 4096        0                  1                 4096
+ */
+#define LOG2_BUCKETS_PER_SESSION_LOCK 1
+#define BUCKETS_PER_SESSION_LOCK (1 << (LOG2_BUCKETS_PER_SESSION_LOCK))
+/* NOSPREAD sessionID to hash table index macro has been slower. */
+
+/* define typedefs, double as forward declarations as well */
+typedef struct SFTKAttributeStr SFTKAttribute;
+typedef struct SFTKObjectListStr SFTKObjectList;
+typedef struct SFTKObjectFreeListStr SFTKObjectFreeList;
+typedef struct SFTKObjectListElementStr SFTKObjectListElement;
+typedef struct SFTKObjectStr SFTKObject;
+typedef struct SFTKSessionObjectStr SFTKSessionObject;
+typedef struct SFTKTokenObjectStr SFTKTokenObject;
+typedef struct SFTKSessionStr SFTKSession;
+typedef struct SFTKSlotStr SFTKSlot;
+typedef struct SFTKSessionContextStr SFTKSessionContext;
+typedef struct SFTKSearchResultsStr SFTKSearchResults;
+typedef struct SFTKHashVerifyInfoStr SFTKHashVerifyInfo;
+typedef struct SFTKHashSignInfoStr SFTKHashSignInfo;
+typedef struct SFTKSSLMACInfoStr SFTKSSLMACInfo;
+typedef struct SFTKItemTemplateStr SFTKItemTemplate;
+
+/* define function pointer typdefs for pointer tables */
+typedef void (*SFTKDestroy)(void *, PRBool);
+typedef void (*SFTKBegin)(void *);
+typedef SECStatus (*SFTKCipher)(void *,void *,unsigned int *,unsigned int,
+					void *, unsigned int);
+typedef SECStatus (*SFTKVerify)(void *,void *,unsigned int,void *,unsigned int);
+typedef void (*SFTKHash)(void *,void *,unsigned int);
+typedef void (*SFTKEnd)(void *,void *,unsigned int *,unsigned int);
+typedef void (*SFTKFree)(void *);
+
+/* Value to tell if an attribute is modifiable or not.
+ *    NEVER: attribute is only set on creation.
+ *    ONCOPY: attribute is set on creation and can only be changed on copy.
+ *    SENSITIVE: attribute can only be changed to TRUE.
+ *    ALWAYS: attribute can always be changed.
+ */
+typedef enum {
+	SFTK_NEVER = 0,
+	SFTK_ONCOPY = 1,
+	SFTK_SENSITIVE = 2,
+	SFTK_ALWAYS = 3
+} SFTKModifyType;
+
+/*
+ * Free Status Enum... tell us more information when we think we're
+ * deleting an object.
+ */
+typedef enum {
+	SFTK_DestroyFailure,
+	SFTK_Destroyed,
+	SFTK_Busy
+} SFTKFreeStatus;
+
+/*
+ * attribute values of an object.
+ */
+struct SFTKAttributeStr {
+    SFTKAttribute  	*next;
+    SFTKAttribute  	*prev;
+    PRBool		freeAttr;
+    PRBool		freeData;
+    /*must be called handle to make sftkqueue_find work */
+    CK_ATTRIBUTE_TYPE	handle;
+    CK_ATTRIBUTE 	attrib;
+    unsigned char space[ATTR_SPACE];
+};
+
+
+/*
+ * doubly link list of objects
+ */
+struct SFTKObjectListStr {
+    SFTKObjectList *next;
+    SFTKObjectList *prev;
+    SFTKObject	   *parent;
+};
+
+struct SFTKObjectFreeListStr {
+    SFTKObject	*head;
+    PZLock	*lock;
+    int		count;
+};
+
+/*
+ * PKCS 11 crypto object structure
+ */
+struct SFTKObjectStr {
+    SFTKObject *next;
+    SFTKObject	*prev;
+    CK_OBJECT_CLASS 	objclass;
+    CK_OBJECT_HANDLE	handle;
+    int 		refCount;
+    PZLock 		*refLock;
+    SFTKSlot	   	*slot;
+    void 		*objectInfo;
+    SFTKFree 		infoFree;
+};
+
+struct SFTKTokenObjectStr {
+    SFTKObject  obj;
+    SECItem	dbKey;
+};
+
+struct SFTKSessionObjectStr {
+    SFTKObject	   obj;
+    SFTKObjectList sessionList;
+    PZLock		*attributeLock;
+    SFTKSession   	*session;
+    PRBool		wasDerived;
+    int nextAttr;
+    SFTKAttribute	attrList[MAX_OBJS_ATTRS];
+    PRBool		optimizeSpace;
+    unsigned int	hashSize;
+    SFTKAttribute 	*head[1];
+};
+
+/*
+ * struct to deal with a temparary list of objects
+ */
+struct SFTKObjectListElementStr {
+    SFTKObjectListElement	*next;
+    SFTKObject 			*object;
+};
+
+/*
+ * Area to hold Search results
+ */
+struct SFTKSearchResultsStr {
+    CK_OBJECT_HANDLE	*handles;
+    int			size;
+    int			index;
+    int			array_size;
+};
+
+
+/* 
+ * the universal crypto/hash/sign/verify context structure
+ */
+typedef enum {
+    SFTK_ENCRYPT,
+    SFTK_DECRYPT,
+    SFTK_HASH,
+    SFTK_SIGN,
+    SFTK_SIGN_RECOVER,
+    SFTK_VERIFY,
+    SFTK_VERIFY_RECOVER
+} SFTKContextType;
+
+
+#define SFTK_MAX_BLOCK_SIZE 16
+/* currently SHA512 is the biggest hash length */
+#define SFTK_MAX_MAC_LENGTH 64
+#define SFTK_INVALID_MAC_SIZE 0xffffffff
+
+struct SFTKSessionContextStr {
+    SFTKContextType	type;
+    PRBool		multi; 		/* is multipart */
+    PRBool		doPad; 		/* use PKCS padding for block ciphers */
+    unsigned int	blockSize; 	/* blocksize for padding */
+    unsigned int	padDataLength; 	/* length of the valid data in padbuf */
+    unsigned char	padBuf[SFTK_MAX_BLOCK_SIZE];
+    unsigned char	macBuf[SFTK_MAX_BLOCK_SIZE];
+    CK_ULONG		macSize;	/* size of a general block cipher mac*/
+    void		*cipherInfo;
+    void		*hashInfo;
+    unsigned int	cipherInfoLen;
+    CK_MECHANISM_TYPE	currentMech;
+    SFTKCipher		update;
+    SFTKHash		hashUpdate;
+    SFTKEnd		end;
+    SFTKDestroy		destroy;
+    SFTKDestroy		hashdestroy;
+    SFTKVerify		verify;
+    unsigned int	maxLen;
+    SFTKObject		*key;
+};
+
+/*
+ * Sessions (have objects)
+ */
+struct SFTKSessionStr {
+    SFTKSession        *next;
+    SFTKSession        *prev;
+    CK_SESSION_HANDLE	handle;
+    int			refCount;
+    PZLock		*objectLock;
+    int			objectIDCount;
+    CK_SESSION_INFO	info;
+    CK_NOTIFY		notify;
+    CK_VOID_PTR		appData;
+    SFTKSlot		*slot;
+    SFTKSearchResults	*search;
+    SFTKSessionContext	*enc_context;
+    SFTKSessionContext	*hash_context;
+    SFTKSessionContext	*sign_context;
+    SFTKObjectList	*objects[1];
+};
+
+/*
+ * slots (have sessions and objects)
+ *
+ * The array of sessionLock's protect the session hash table (head[])
+ * as well as the reference count of session objects in that bucket
+ * (head[]->refCount),  objectLock protects all elements of the slot's
+ * object hash tables (sessObjHashTable[] and tokObjHashTable), and
+ * sessionObjectHandleCount.
+ * slotLock protects the remaining protected elements:
+ * password, isLoggedIn, ssoLoggedIn, and sessionCount,
+ * and pwCheckLock serializes the key database password checks in
+ * NSC_SetPIN and NSC_Login.
+ *
+ * Each of the fields below has the following lifetime as commented
+ * next to the fields:
+ *   invariant  - This value is set when the slot is first created and
+ * never changed until it is destroyed.
+ *   per load   - This value is set when the slot is first created, or 
+ * when the slot is used to open another directory. Between open and close
+ * this field does not change.
+ *   variable - This value changes through the normal process of slot operation.
+ *      - reset. The value of this variable is cleared during an open/close 
+ *   cycles.
+ *      - preserved. The value of this variable is preserved over open/close
+ *   cycles.
+ */
+struct SFTKSlotStr {
+    CK_SLOT_ID		slotID;			/* invariant */
+    PZLock		*slotLock;		/* invariant */
+    PZLock		**sessionLock;		/* invariant */
+    unsigned int	numSessionLocks;	/* invariant */
+    unsigned long	sessionLockMask;	/* invariant */
+    PZLock		*objectLock;		/* invariant */
+    PRLock		*pwCheckLock;		/* invariant */
+    PRBool		present;		/* variable -set */
+    PRBool		hasTokens;		/* per load */
+    PRBool		isLoggedIn;		/* variable - reset */
+    PRBool		ssoLoggedIn;		/* variable - reset */
+    PRBool		needLogin;		/* per load */
+    PRBool		DB_loaded;		/* per load */
+    PRBool		readOnly;		/* per load */
+    PRBool		optimizeSpace;		/* invariant */
+    SFTKDBHandle	*certDB;		/* per load */
+    SFTKDBHandle	*keyDB;			/* per load */
+    int			minimumPinLen;		/* per load */
+    PRInt32		sessionIDCount;		/* atomically incremented */
+                                        	/* (preserved) */
+    int			sessionIDConflict; 	/* not protected by a lock */
+                                            	/* (preserved) */
+    int			sessionCount;           /* variable - reset */
+    PRInt32             rwSessionCount;    	/* set by atomic operations */
+                                          	/* (reset) */
+    int			sessionObjectHandleCount;/* variable - perserved */
+    int			index;			/* invariant */
+    PLHashTable		*tokObjHashTable;	/* invariant */
+    SFTKObject		**sessObjHashTable;	/* variable - reset */
+    unsigned int	sessObjHashSize;	/* invariant */
+    SFTKSession		**head;			/* variable -reset */
+    unsigned int	sessHashSize;		/* invariant */
+    char		tokDescription[33];	/* per load */
+    char		updateTokDescription[33]; /* per load */
+    char		slotDescription[65];	/* invariant */
+};
+
+/*
+ * special joint operations Contexts
+ */
+struct SFTKHashVerifyInfoStr {
+    SECOidTag   	hashOid;
+    NSSLOWKEYPublicKey	*key;
+};
+
+struct SFTKHashSignInfoStr {
+    SECOidTag   	hashOid;
+    NSSLOWKEYPrivateKey	*key;
+};
+
+/* context for the Final SSLMAC message */
+struct SFTKSSLMACInfoStr {
+    void 		*hashContext;
+    SFTKBegin		begin;
+    SFTKHash		update;
+    SFTKEnd		end;
+    CK_ULONG		macSize;
+    int			padSize;
+    unsigned char	key[MAX_KEY_LEN];
+    unsigned int	keySize;
+};
+
+/*
+ * Template based on SECItems, suitable for passing as arrays
+ */
+struct SFTKItemTemplateStr {
+    CK_ATTRIBUTE_TYPE	type;
+    SECItem		*item;
+};
+
+/* macro for setting SFTKTemplates. */
+#define SFTK_SET_ITEM_TEMPLATE(templ, count, itemPtr, attr) \
+   templ[count].type = attr; \
+   templ[count].item = itemPtr
+
+#define SFTK_MAX_ITEM_TEMPLATE 10
+
+/*
+ * session handle modifiers
+ */
+#define SFTK_SESSION_SLOT_MASK	0xff000000L
+
+/*
+ * object handle modifiers
+ */
+#define SFTK_TOKEN_MASK		0x80000000L
+#define SFTK_TOKEN_MAGIC	0x80000000L
+#define SFTK_TOKEN_TYPE_MASK	0x70000000L
+/* keydb (high bit == 0) */
+#define SFTK_TOKEN_TYPE_PRIV	0x10000000L
+#define SFTK_TOKEN_TYPE_PUB	0x20000000L
+#define SFTK_TOKEN_TYPE_KEY	0x30000000L
+/* certdb (high bit == 1) */
+#define SFTK_TOKEN_TYPE_TRUST	0x40000000L
+#define SFTK_TOKEN_TYPE_CRL	0x50000000L
+#define SFTK_TOKEN_TYPE_SMIME	0x60000000L
+#define SFTK_TOKEN_TYPE_CERT	0x70000000L
+
+#define SFTK_TOKEN_KRL_HANDLE	(SFTK_TOKEN_MAGIC|SFTK_TOKEN_TYPE_CRL|1)
+/* how big (in bytes) a password/pin we can deal with */
+#define SFTK_MAX_PIN	255
+/* minimum password/pin length (in Unicode characters) in FIPS mode */
+#define FIPS_MIN_PIN	7
+
+/* slot ID's */
+#define NETSCAPE_SLOT_ID 1
+#define PRIVATE_KEY_SLOT_ID 2
+#define FIPS_SLOT_ID 3
+
+/* slot helper macros */
+#define sftk_SlotFromSession(sp) ((sp)->slot)
+#define sftk_isToken(id) (((id) & SFTK_TOKEN_MASK) == SFTK_TOKEN_MAGIC)
+
+/* the session hash multiplier (see bug 201081) */
+#define SHMULTIPLIER 1791398085
+
+/* queueing helper macros */
+#define sftk_hash(value,size) \
+	((PRUint32)((value) * SHMULTIPLIER) & (size-1))
+#define sftkqueue_add(element,id,head,hash_size) \
+	{ int tmp = sftk_hash(id,hash_size); \
+	(element)->next = (head)[tmp]; \
+	(element)->prev = NULL; \
+	if ((head)[tmp]) (head)[tmp]->prev = (element); \
+	(head)[tmp] = (element); }
+#define sftkqueue_find(element,id,head,hash_size) \
+	for( (element) = (head)[sftk_hash(id,hash_size)]; (element) != NULL; \
+					 (element) = (element)->next) { \
+	    if ((element)->handle == (id)) { break; } }
+#define sftkqueue_is_queued(element,id,head,hash_size) \
+	( ((element)->next) || ((element)->prev) || \
+	 ((head)[sftk_hash(id,hash_size)] == (element)) )
+#define sftkqueue_delete(element,id,head,hash_size) \
+	if ((element)->next) (element)->next->prev = (element)->prev; \
+	if ((element)->prev) (element)->prev->next = (element)->next; \
+	   else (head)[sftk_hash(id,hash_size)] = ((element)->next); \
+	(element)->next = NULL; \
+	(element)->prev = NULL; \
+
+#define sftkqueue_init_element(element) \
+    (element)->prev = NULL;
+
+#define sftkqueue_add2(element, id, index, head) \
+    {                                            \
+	(element)->next = (head)[index];         \
+	if ((head)[index])                       \
+	    (head)[index]->prev = (element);     \
+	(head)[index] = (element);               \
+    }
+
+#define sftkqueue_find2(element, id, index, head) \
+    for ( (element) = (head)[index];              \
+          (element) != NULL;                      \
+          (element) = (element)->next) {          \
+	if ((element)->handle == (id)) { break; } \
+    }
+
+#define sftkqueue_delete2(element, id, index, head) \
+	if ((element)->next) (element)->next->prev = (element)->prev; \
+	if ((element)->prev) (element)->prev->next = (element)->next; \
+	   else (head)[index] = ((element)->next);
+
+#define sftkqueue_clear_deleted_element(element) \
+	(element)->next = NULL; \
+	(element)->prev = NULL; \
+
+
+/* sessionID (handle) is used to determine session lock bucket */
+#ifdef NOSPREAD
+/* NOSPREAD:	(ID>>L2LPB) & (perbucket-1) */
+#define SFTK_SESSION_LOCK(slot,handle) \
+    ((slot)->sessionLock[((handle) >> LOG2_BUCKETS_PER_SESSION_LOCK) \
+        & (slot)->sessionLockMask])
+#else
+/* SPREAD:	ID & (perbucket-1) */
+#define SFTK_SESSION_LOCK(slot,handle) \
+    ((slot)->sessionLock[(handle) & (slot)->sessionLockMask])
+#endif
+
+/* expand an attribute & secitem structures out */
+#define sftk_attr_expand(ap) (ap)->type,(ap)->pValue,(ap)->ulValueLen
+#define sftk_item_expand(ip) (ip)->data,(ip)->len
+
+typedef struct sftk_token_parametersStr {
+    CK_SLOT_ID slotID;
+    char *configdir;
+    char *certPrefix;
+    char *keyPrefix;
+    char *updatedir;
+    char *updCertPrefix;
+    char *updKeyPrefix;
+    char *updateID;
+    char *tokdes;
+    char *slotdes;
+    char *updtokdes;
+    int minPW; 
+    PRBool readOnly;
+    PRBool noCertDB;
+    PRBool noKeyDB;
+    PRBool forceOpen;
+    PRBool pwRequired;
+    PRBool optimizeSpace;
+} sftk_token_parameters;
+
+typedef struct sftk_parametersStr {
+    char *configdir;
+    char *updatedir;
+    char *updateID;
+    char *secmodName;
+    char *man;
+    char *libdes; 
+    PRBool readOnly;
+    PRBool noModDB;
+    PRBool noCertDB;
+    PRBool forceOpen;
+    PRBool pwRequired;
+    PRBool optimizeSpace;
+    sftk_token_parameters *tokens;
+    int token_count;
+} sftk_parameters;
+
+
+/* machine dependent path stuff used by dbinit.c and pk11db.c */
+#ifdef macintosh
+#define PATH_SEPARATOR ":"
+#define SECMOD_DB "Security Modules"
+#define CERT_DB_FMT "%sCertificates%s"
+#define KEY_DB_FMT "%sKey Database%s"
+#else
+#define PATH_SEPARATOR "/"
+#define SECMOD_DB "secmod.db"
+#define CERT_DB_FMT "%scert%s.db"
+#define KEY_DB_FMT "%skey%s.db"
+#endif
+
+SEC_BEGIN_PROTOS
+
+/* shared functions between pkcs11.c and fipstokn.c */
+extern PRBool nsf_init;
+extern CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS);
+extern CK_RV nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS);
+extern PRBool sftk_ForkReset(CK_VOID_PTR pReserved, CK_RV* crv);
+extern CK_RV nsc_CommonGetSlotList(CK_BBOOL tokPresent, 
+	CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount, int moduleIndex);
+
+/* slot initialization, reinit, shutdown and destruction */
+extern CK_RV SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
+			sftk_token_parameters *params, int moduleIndex);
+extern CK_RV SFTK_SlotReInit(SFTKSlot *slot, char *configdir,
+			char *updatedir, char *updateID,
+			sftk_token_parameters *params, int moduleIndex);
+extern CK_RV SFTK_DestroySlotData(SFTKSlot *slot);
+extern CK_RV SFTK_ShutdownSlot(SFTKSlot *slot);
+extern CK_RV sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout);
+
+
+/* internal utility functions used by pkcs11.c */
+extern SFTKAttribute *sftk_FindAttribute(SFTKObject *object,
+					 CK_ATTRIBUTE_TYPE type);
+extern void sftk_FreeAttribute(SFTKAttribute *attribute);
+extern CK_RV sftk_AddAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
+				   void *valPtr,
+				  CK_ULONG length);
+extern CK_RV sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item,
+				    SFTKObject *object, CK_ATTRIBUTE_TYPE type);
+extern CK_RV sftk_MultipleAttribute2SecItem(PLArenaPool *arena, 
+		SFTKObject *object, SFTKItemTemplate *templ, int count);
+extern unsigned int sftk_GetLengthInBits(unsigned char *buf,
+							 unsigned int bufLen);
+extern CK_RV sftk_ConstrainAttribute(SFTKObject *object, 
+	CK_ATTRIBUTE_TYPE type, int minLength, int maxLength, int minMultiple);
+extern PRBool sftk_hasAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
+extern PRBool sftk_isTrue(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
+extern void sftk_DeleteAttributeType(SFTKObject *object,
+				     CK_ATTRIBUTE_TYPE type);
+extern CK_RV sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item,
+				    SFTKObject *object, CK_ATTRIBUTE_TYPE type);
+extern CK_RV sftk_Attribute2SSecItem(PLArenaPool *arena, SECItem *item,
+				     SFTKObject *object,
+				     CK_ATTRIBUTE_TYPE type);
+extern SFTKModifyType sftk_modifyType(CK_ATTRIBUTE_TYPE type,
+				      CK_OBJECT_CLASS inClass);
+extern PRBool sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass);
+extern char *sftk_getString(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
+extern void sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type);
+extern CK_RV sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
+                                                         CK_ULONG *longData);
+extern CK_RV sftk_forceAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
+				 void *value, unsigned int len);
+extern CK_RV sftk_defaultAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
+				   void *value, unsigned int len);
+extern unsigned int sftk_MapTrust(CK_TRUST trust, PRBool clientAuth);
+
+extern SFTKObject *sftk_NewObject(SFTKSlot *slot);
+extern CK_RV sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject);
+extern SFTKFreeStatus sftk_FreeObject(SFTKObject *object);
+extern CK_RV sftk_DeleteObject(SFTKSession *session, SFTKObject *object);
+extern void sftk_ReferenceObject(SFTKObject *object);
+extern SFTKObject *sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle,
+					 SFTKSession *session);
+extern void sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object);
+extern void sftk_AddObject(SFTKSession *session, SFTKObject *object);
+/* clear out all the existing object ID to database key mappings.
+ * used to reinit a token */
+extern CK_RV SFTK_ClearTokenKeyHashTable(SFTKSlot *slot);
+
+extern CK_RV sftk_searchObjectList(SFTKSearchResults *search,
+				   SFTKObject **head, unsigned int size,
+				   PZLock *lock, CK_ATTRIBUTE_PTR inTemplate,
+				   int count, PRBool isLoggedIn);
+extern SFTKObjectListElement *sftk_FreeObjectListElement(
+					     SFTKObjectListElement *objectList);
+extern void sftk_FreeObjectList(SFTKObjectListElement *objectList);
+extern void sftk_FreeSearch(SFTKSearchResults *search);
+extern CK_RV sftk_handleObject(SFTKObject *object, SFTKSession *session);
+
+extern SFTKSlot *sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all);
+extern SFTKSlot *sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle);
+extern SFTKSession *sftk_SessionFromHandle(CK_SESSION_HANDLE handle);
+extern void sftk_FreeSession(SFTKSession *session);
+extern SFTKSession *sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify,
+				    CK_VOID_PTR pApplication, CK_FLAGS flags);
+extern void sftk_update_state(SFTKSlot *slot,SFTKSession *session);
+extern void sftk_update_all_states(SFTKSlot *slot);
+extern void sftk_FreeContext(SFTKSessionContext *context);
+extern void sftk_InitFreeLists(void);
+extern void sftk_CleanupFreeLists(void);
+
+extern NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,
+					  CK_KEY_TYPE key_type, CK_RV *crvp);
+extern NSSLOWKEYPrivateKey *sftk_GetPrivKey(SFTKObject *object,
+					    CK_KEY_TYPE key_type, CK_RV *crvp);
+extern void sftk_FormatDESKey(unsigned char *key, int length);
+extern PRBool sftk_CheckDESKey(unsigned char *key);
+extern PRBool sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type);
+
+/* mechanism allows this operation */
+extern CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op);
+
+/* helper function which calls nsslowkey_FindKeyByPublicKey after safely
+ * acquiring a reference to the keydb from the slot */
+NSSLOWKEYPrivateKey *sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey);
+
+/*
+ * narrow objects
+ */
+SFTKSessionObject * sftk_narrowToSessionObject(SFTKObject *);
+SFTKTokenObject * sftk_narrowToTokenObject(SFTKObject *);
+
+/*
+ * token object utilities
+ */
+void sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle);
+PRBool sftk_poisonHandle(SFTKSlot *slot, SECItem *dbkey, 
+						CK_OBJECT_HANDLE handle);
+SFTKObject * sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, 
+						CK_OBJECT_HANDLE handle);
+SFTKTokenObject *sftk_convertSessionToToken(SFTKObject *so);
+
+/****************************************
+ * implement TLS Pseudo Random Function (PRF)
+ */
+
+extern CK_RV
+sftk_TLSPRFInit(SFTKSessionContext *context, 
+		  SFTKObject *        key, 
+		  CK_KEY_TYPE         key_type);
+
+SEC_END_PROTOS
+
+#endif /* _PKCS11I_H_ */
diff --git a/mozilla/security/nss/lib/softoken/pkcs11ni.h b/mozilla/security/nss/lib/softoken/pkcs11ni.h
new file mode 100644
index 0000000..9e584a9
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/pkcs11ni.h
@@ -0,0 +1,52 @@
+/* ***** 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
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ *
+ * 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 ***** */
+
+#ifndef _PKCS11NI_H_
+#define _PKCS11NI_H_
+
+/*
+ * pkcs11ni.h
+ *
+ * This file contains softoken private exports for NSS
+ */
+
+/* softoken slot ID's */
+#define SFTK_MIN_USER_SLOT_ID 4
+#define SFTK_MAX_USER_SLOT_ID 100
+#define SFTK_MIN_FIPS_USER_SLOT_ID 101
+#define SFTK_MAX_FIPS_USER_SLOT_ID 127
+
+
+#endif /* _PKCS11NI_H_ */
diff --git a/mozilla/security/nss/lib/softoken/pkcs11u.c b/mozilla/security/nss/lib/softoken/pkcs11u.c
new file mode 100644
index 0000000..7f44873
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/pkcs11u.c
@@ -0,0 +1,2012 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/*
+ * Internal PKCS #11 functions. Should only be called by pkcs11.c
+ */
+#include "pkcs11.h"
+#include "pkcs11i.h"
+#include "lowkeyi.h"
+#include "secasn1.h"
+#include "blapi.h"
+#include "secerr.h"
+#include "prnetdb.h" /* for PR_ntohl */
+#include "sftkdb.h"
+#include "softoken.h"
+
+/*
+ * ******************** Attribute Utilities *******************************
+ */
+
+/*
+ * create a new attribute with type, value, and length. Space is allocated
+ * to hold value.
+ */
+static SFTKAttribute *
+sftk_NewAttribute(SFTKObject *object,
+	CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG len)
+{
+    SFTKAttribute *attribute;
+
+    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
+    int index;
+
+    if (so == NULL)  {
+	/* allocate new attribute in a buffer */
+	PORT_Assert(0);
+	return NULL;
+    }
+    /* 
+     * We attempt to keep down contention on Malloc and Arena locks by
+     * limiting the number of these calls on high traversed paths. This
+     * is done for attributes by 'allocating' them from a pool already
+     * allocated by the parent object.
+     */
+    PZ_Lock(so->attributeLock);
+    index = so->nextAttr++;
+    PZ_Unlock(so->attributeLock);
+    PORT_Assert(index < MAX_OBJS_ATTRS);
+    if (index >= MAX_OBJS_ATTRS) return NULL;
+
+    attribute = &so->attrList[index];
+    attribute->attrib.type = type;
+    attribute->freeAttr = PR_FALSE;
+    attribute->freeData = PR_FALSE;
+    if (value) {
+        if (len <= ATTR_SPACE) {
+	    attribute->attrib.pValue = attribute->space;
+	} else {
+	    attribute->attrib.pValue = PORT_Alloc(len);
+    	    attribute->freeData = PR_TRUE;
+	}
+	if (attribute->attrib.pValue == NULL) {
+	    return NULL;
+	}
+	PORT_Memcpy(attribute->attrib.pValue,value,len);
+	attribute->attrib.ulValueLen = len;
+    } else {
+	attribute->attrib.pValue = NULL;
+	attribute->attrib.ulValueLen = 0;
+    }
+    attribute->attrib.type = type;
+    attribute->handle = type;
+    attribute->next = attribute->prev = NULL;
+    return attribute;
+}
+
+/*
+ * Free up all the memory associated with an attribute. Reference count
+ * must be zero to call this.
+ */
+static void
+sftk_DestroyAttribute(SFTKAttribute *attribute)
+{
+    if (attribute->freeData) {
+	if (attribute->attrib.pValue) {
+	    /* clear out the data in the attribute value... it may have been
+	     * sensitive data */
+	    PORT_Memset(attribute->attrib.pValue, 0,
+						attribute->attrib.ulValueLen);
+	}
+	PORT_Free(attribute->attrib.pValue);
+    }
+    PORT_Free(attribute);
+}
+
+/*
+ * release a reference to an attribute structure
+ */
+void
+sftk_FreeAttribute(SFTKAttribute *attribute)
+{
+    if (attribute->freeAttr) {
+	sftk_DestroyAttribute(attribute);
+	return;
+    }
+}
+
+static SFTKAttribute *    
+sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *myattribute = NULL;
+    SFTKDBHandle *dbHandle = NULL;
+    CK_RV crv = CKR_HOST_MEMORY;
+
+    myattribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute));
+    if (myattribute == NULL) {
+	goto loser;
+    }
+
+    dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
+
+    myattribute->handle = type;
+    myattribute->attrib.type = type;
+    myattribute->attrib.pValue = myattribute->space;
+    myattribute->attrib.ulValueLen = ATTR_SPACE;
+    myattribute->next = myattribute->prev = NULL;
+    myattribute->freeAttr = PR_TRUE;
+    myattribute->freeData = PR_FALSE;
+
+    crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
+		&myattribute->attrib, 1);
+
+    /* attribute is bigger than our attribute space buffer, malloc it */
+    if (crv == CKR_BUFFER_TOO_SMALL) {
+    	myattribute->attrib.pValue = NULL;
+    	crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
+		&myattribute->attrib, 1);
+	if (crv != CKR_OK) {
+	    goto loser;
+	}
+	myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen);
+	if (myattribute->attrib.pValue == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	myattribute->freeData = PR_TRUE;
+    	crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
+		 &myattribute->attrib, 1);
+    } 
+loser:
+    if (dbHandle) {
+	sftk_freeDB(dbHandle);
+    }
+    if (crv != CKR_OK) {
+	if (myattribute) {
+	    myattribute->attrib.ulValueLen = 0;
+	    sftk_FreeAttribute(myattribute);
+	    myattribute = NULL;
+	}
+    }
+    return myattribute;
+} 
+
+/*
+ * look up and attribute structure from a type and Object structure.
+ * The returned attribute is referenced and needs to be freed when 
+ * it is no longer needed.
+ */
+SFTKAttribute *
+sftk_FindAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *attribute;
+    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
+
+    if (sessObject == NULL) {
+	return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object),type);
+    }
+
+    PZ_Lock(sessObject->attributeLock);
+    sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
+    PZ_Unlock(sessObject->attributeLock);
+
+    return(attribute);
+}
+
+/*
+ * Take a buffer and it's length and return it's true size in bits;
+ */
+unsigned int
+sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)
+{
+    unsigned int size = bufLen * 8;
+    unsigned int i;
+
+    /* Get the real length in bytes */
+    for (i=0; i < bufLen; i++) {
+	unsigned char  c = *buf++;
+	if (c != 0) {
+	    unsigned char m;
+	    for (m=0x80; m > 0 ;  m = m >> 1) {
+		if ((c & m) != 0) {
+		    break;
+		} 
+		size--;
+	    }
+	    break;
+	}
+	size-=8;
+    }
+    return size;
+}
+
+/*
+ * Constrain a big num attribute. to size and padding
+ * minLength means length of the object must be greater than equal to minLength
+ * maxLength means length of the object must be less than equal to maxLength
+ * minMultiple means that object length mod minMultiple must equal 0.
+ * all input sizes are in bits.
+ * if any constraint is '0' that constraint is not checked.
+ */
+CK_RV
+sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 
+			int minLength, int maxLength, int minMultiple)
+{
+    SFTKAttribute *attribute;
+    int size;
+    unsigned char *ptr;
+
+    attribute = sftk_FindAttribute(object, type);
+    if (!attribute) {
+	return CKR_TEMPLATE_INCOMPLETE;
+    }
+    ptr = (unsigned char *) attribute->attrib.pValue;
+    if (ptr == NULL) {
+	sftk_FreeAttribute(attribute);
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);
+    sftk_FreeAttribute(attribute);
+
+    if ((minLength != 0) && (size <  minLength)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    if ((maxLength != 0) && (size >  maxLength)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    if ((minMultiple != 0) && ((size % minMultiple) != 0)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    return CKR_OK;
+}
+
+PRBool
+sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
+{
+    CK_ATTRIBUTE template;
+    CK_RV crv;
+    SFTKDBHandle *dbHandle;
+
+    dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
+    template.type = type;
+    template.pValue = NULL;
+    template.ulValueLen = 0;
+
+    crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1);
+    sftk_freeDB(dbHandle);
+
+    /* attribute is bigger than our attribute space buffer, malloc it */
+    return (crv == CKR_OK) ? PR_TRUE : PR_FALSE;
+}
+
+/*
+ * return true if object has attribute
+ */
+PRBool
+sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *attribute;
+    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
+
+    if (sessObject == NULL) {
+	return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type);
+    }
+
+    PZ_Lock(sessObject->attributeLock);
+    sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
+    PZ_Unlock(sessObject->attributeLock);
+
+    return (PRBool)(attribute != NULL);
+}
+
+/*
+ * add an attribute to an object
+ */
+static void
+sftk_AddAttribute(SFTKObject *object,SFTKAttribute *attribute)
+{
+    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
+
+    if (sessObject == NULL) return;
+    PZ_Lock(sessObject->attributeLock);
+    sftkqueue_add(attribute,attribute->handle,
+				sessObject->head, sessObject->hashSize);
+    PZ_Unlock(sessObject->attributeLock);
+}
+
+/* 
+ * copy an unsigned attribute into a SECItem. Secitem is allocated in
+ * the specified arena.
+ */
+CK_RV
+sftk_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
+                                      CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *attribute;
+
+    item->data = NULL;
+
+    attribute = sftk_FindAttribute(object, type);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+
+    (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
+    if (item->data == NULL) {
+	sftk_FreeAttribute(attribute);
+	return CKR_HOST_MEMORY;
+    }
+    PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);
+    sftk_FreeAttribute(attribute);
+    return CKR_OK;
+}
+
+/* 
+ * fetch multiple attributes into  SECItems. Secitem data is allocated in
+ * the specified arena.
+ */
+CK_RV
+sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object,
+	 SFTKItemTemplate *itemTemplate, int itemTemplateCount)
+{
+
+    CK_RV crv = CKR_OK;
+    CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE];
+    CK_ATTRIBUTE *template;
+    SFTKTokenObject *tokObject;
+    SFTKDBHandle *dbHandle = NULL;
+    int i;
+
+    tokObject = sftk_narrowToTokenObject(object);
+
+    /* session objects, just loop through the list */
+    if (tokObject == NULL) {
+	for (i=0; i < itemTemplateCount; i++) {
+	    crv = sftk_Attribute2SecItem(arena,itemTemplate[i].item, object,
+					 itemTemplate[i].type);
+	    if (crv != CKR_OK) {
+		return crv;
+	    }
+	}
+	return CKR_OK;
+    }
+
+    /* don't do any work if none is required */
+    if (itemTemplateCount == 0) {
+	return CKR_OK;
+    }
+
+    /* don't allocate the template unless we need it */
+    if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) {
+	template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount);
+    } else {
+	template = templateSpace;
+    }
+
+    if (template == NULL) {
+	crv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+
+    dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
+    if (dbHandle == NULL) {
+	crv = CKR_OBJECT_HANDLE_INVALID;
+	goto loser;
+    }
+
+    /* set up the PKCS #11 template */
+    for (i=0; i < itemTemplateCount; i++) {
+	template[i].type = itemTemplate[i].type;
+	template[i].pValue = NULL;
+	template[i].ulValueLen = 0;
+    }
+
+    /* fetch the attribute lengths */
+    crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
+				   template, itemTemplateCount);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    /* allocate space for the attributes */
+    for (i=0; i < itemTemplateCount ; i++) {
+	template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen);
+	if (template[i].pValue == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+    }
+
+    /* fetch the attributes */
+    crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
+				   template, itemTemplateCount);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    /* Fill in the items */	
+    for (i=0; i < itemTemplateCount; i++) {
+	itemTemplate[i].item->data = template[i].pValue;
+	itemTemplate[i].item->len = template[i].ulValueLen;
+    }
+
+loser:
+    if (template != templateSpace) {
+	PORT_Free(template);
+    }
+    if (dbHandle) {
+	sftk_freeDB(dbHandle);
+    }
+	     
+    return crv;
+}
+
+
+/*
+ * delete an attribute from an object
+ */
+static void
+sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)
+{
+    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
+
+    if (sessObject == NULL) {
+	return ;
+    }
+    PZ_Lock(sessObject->attributeLock);
+    if (sftkqueue_is_queued(attribute,attribute->handle,
+				sessObject->head, sessObject->hashSize)) {
+	sftkqueue_delete(attribute,attribute->handle,
+				sessObject->head, sessObject->hashSize);
+    }
+    PZ_Unlock(sessObject->attributeLock);
+}
+
+/*
+ * this is only valid for CK_BBOOL type attributes. Return the state
+ * of that attribute.
+ */
+PRBool
+sftk_isTrue(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *attribute;
+    PRBool tok = PR_FALSE;
+
+    attribute=sftk_FindAttribute(object,type);
+    if (attribute == NULL) { return PR_FALSE; }
+    tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
+    sftk_FreeAttribute(attribute);
+
+    return tok;
+}
+
+/*
+ * force an attribute to null.
+ * this is for sensitive keys which are stored in the database, we don't
+ * want to keep this info around in memory in the clear.
+ */
+void
+sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *attribute;
+
+    attribute=sftk_FindAttribute(object,type);
+    if (attribute == NULL) return;
+
+    if (attribute->attrib.pValue != NULL) {
+	PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen);
+	if (attribute->freeData) {
+	    PORT_Free(attribute->attrib.pValue);
+	}
+	attribute->freeData = PR_FALSE;
+	attribute->attrib.pValue = NULL;
+	attribute->attrib.ulValueLen = 0;
+    }
+    sftk_FreeAttribute(attribute);
+}
+
+
+static CK_RV
+sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, 
+						void *value, unsigned int len)
+{
+    CK_ATTRIBUTE attribute;
+    SFTKDBHandle *dbHandle = NULL;
+    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
+    CK_RV crv;
+
+    PORT_Assert(to);
+    if (to == NULL) {
+	return CKR_DEVICE_ERROR;
+    }
+
+    dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
+
+    attribute.type = type;
+    attribute.pValue = value;
+    attribute.ulValueLen = len;
+
+    crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1);
+    sftk_freeDB(dbHandle);
+    return crv;
+}
+	
+/*
+ * force an attribute to a specifc value.
+ */
+CK_RV
+sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, void *value,
+						unsigned int len)
+{
+    SFTKAttribute *attribute;
+    void *att_val = NULL;
+    PRBool freeData = PR_FALSE;
+
+    PORT_Assert(object);
+    PORT_Assert(object->refCount);
+    PORT_Assert(object->slot);
+    if (!object ||
+        !object->refCount ||
+        !object->slot) {
+        return CKR_DEVICE_ERROR;
+    }
+    if (sftk_isToken(object->handle)) {
+	return sftk_forceTokenAttribute(object,type,value,len);
+    }
+    attribute=sftk_FindAttribute(object,type);
+    if (attribute == NULL) return sftk_AddAttributeType(object,type,value,len);
+
+
+    if (value) {
+        if (len <= ATTR_SPACE) {
+	    att_val = attribute->space;
+	} else {
+	    att_val = PORT_Alloc(len);
+	    freeData = PR_TRUE;
+	}
+	if (att_val == NULL) {
+	    return CKR_HOST_MEMORY;
+	}
+	if (attribute->attrib.pValue == att_val) {
+	    PORT_Memset(attribute->attrib.pValue,0,
+					attribute->attrib.ulValueLen);
+	}
+	PORT_Memcpy(att_val,value,len);
+    }
+    if (attribute->attrib.pValue != NULL) {
+	if (attribute->attrib.pValue != att_val) {
+	    PORT_Memset(attribute->attrib.pValue,0,
+					attribute->attrib.ulValueLen);
+	}
+	if (attribute->freeData) {
+	    PORT_Free(attribute->attrib.pValue);
+	}
+	attribute->freeData = PR_FALSE;
+	attribute->attrib.pValue = NULL;
+	attribute->attrib.ulValueLen = 0;
+    }
+    if (att_val) {
+	attribute->attrib.pValue = att_val;
+	attribute->attrib.ulValueLen = len;
+	attribute->freeData = freeData;
+    }
+    sftk_FreeAttribute(attribute);
+    return CKR_OK;
+}
+
+/*
+ * return a null terminated string from attribute 'type'. This string
+ * is allocated and needs to be freed with PORT_Free() When complete.
+ */
+char *
+sftk_getString(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *attribute;
+    char *label = NULL;
+
+    attribute=sftk_FindAttribute(object,type);
+    if (attribute == NULL) return NULL;
+
+    if (attribute->attrib.pValue != NULL) {
+	label = (char *) PORT_Alloc(attribute->attrib.ulValueLen+1);
+	if (label == NULL) {
+    	    sftk_FreeAttribute(attribute);
+	    return NULL;
+	}
+
+	PORT_Memcpy(label,attribute->attrib.pValue,
+						attribute->attrib.ulValueLen);
+	label[attribute->attrib.ulValueLen] = 0;
+    }
+    sftk_FreeAttribute(attribute);
+    return label;
+}
+
+/*
+ * decode when a particular attribute may be modified
+ * 	SFTK_NEVER: This attribute must be set at object creation time and
+ *  can never be modified.
+ *	SFTK_ONCOPY: This attribute may be modified only when you copy the
+ *  object.
+ *	SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from
+ *  CK_FALSE to CK_TRUE.
+ *	SFTK_ALWAYS: This attribute can always be modified.
+ * Some attributes vary their modification type based on the class of the 
+ *   object.
+ */
+SFTKModifyType
+sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
+{
+    /* if we don't know about it, user user defined, always allow modify */
+    SFTKModifyType mtype = SFTK_ALWAYS; 
+
+    switch(type) {
+    /* NEVER */
+    case CKA_CLASS:
+    case CKA_CERTIFICATE_TYPE:
+    case CKA_KEY_TYPE:
+    case CKA_MODULUS:
+    case CKA_MODULUS_BITS:
+    case CKA_PUBLIC_EXPONENT:
+    case CKA_PRIVATE_EXPONENT:
+    case CKA_PRIME:
+    case CKA_SUBPRIME:
+    case CKA_BASE:
+    case CKA_PRIME_1:
+    case CKA_PRIME_2:
+    case CKA_EXPONENT_1:
+    case CKA_EXPONENT_2:
+    case CKA_COEFFICIENT:
+    case CKA_VALUE_LEN:
+    case CKA_ALWAYS_SENSITIVE:
+    case CKA_NEVER_EXTRACTABLE:
+    case CKA_NETSCAPE_DB:
+	mtype = SFTK_NEVER;
+	break;
+
+    /* ONCOPY */
+    case CKA_TOKEN:
+    case CKA_PRIVATE:
+    case CKA_MODIFIABLE:
+	mtype = SFTK_ONCOPY;
+	break;
+
+    /* SENSITIVE */
+    case CKA_SENSITIVE:
+    case CKA_EXTRACTABLE:
+	mtype = SFTK_SENSITIVE;
+	break;
+
+    /* ALWAYS */
+    case CKA_LABEL:
+    case CKA_APPLICATION:
+    case CKA_ID:
+    case CKA_SERIAL_NUMBER:
+    case CKA_START_DATE:
+    case CKA_END_DATE:
+    case CKA_DERIVE:
+    case CKA_ENCRYPT:
+    case CKA_DECRYPT:
+    case CKA_SIGN:
+    case CKA_VERIFY:
+    case CKA_SIGN_RECOVER:
+    case CKA_VERIFY_RECOVER:
+    case CKA_WRAP:
+    case CKA_UNWRAP:
+	mtype = SFTK_ALWAYS;
+	break;
+
+    /* DEPENDS ON CLASS */
+    case CKA_VALUE:
+	mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;
+	break;
+
+    case CKA_SUBJECT:
+	mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;
+	break;
+    default:
+	break;
+    }
+    return mtype;
+}
+
+/* decode if a particular attribute is sensitive (cannot be read
+ * back to the user of if the object is set to SENSITIVE) */
+PRBool
+sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
+{
+    switch(type) {
+    /* ALWAYS */
+    case CKA_PRIVATE_EXPONENT:
+    case CKA_PRIME_1:
+    case CKA_PRIME_2:
+    case CKA_EXPONENT_1:
+    case CKA_EXPONENT_2:
+    case CKA_COEFFICIENT:
+	return PR_TRUE;
+
+    /* DEPENDS ON CLASS */
+    case CKA_VALUE:
+	/* PRIVATE and SECRET KEYS have SENSITIVE values */
+	return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
+
+    default:
+	break;
+    }
+    return PR_FALSE;
+}
+
+/* 
+ * copy an attribute into a SECItem. Secitem is allocated in the specified
+ * arena.
+ */
+CK_RV
+sftk_Attribute2SecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
+					CK_ATTRIBUTE_TYPE type)
+{
+    int len;
+    SFTKAttribute *attribute;
+
+    attribute = sftk_FindAttribute(object, type);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+    len = attribute->attrib.ulValueLen;
+
+    if (arena) {
+    	item->data = (unsigned char *) PORT_ArenaAlloc(arena,len);
+    } else {
+    	item->data = (unsigned char *) PORT_Alloc(len);
+    }
+    if (item->data == NULL) {
+	sftk_FreeAttribute(attribute);
+	return CKR_HOST_MEMORY;
+    }
+    item->len = len;
+    PORT_Memcpy(item->data,attribute->attrib.pValue, len);
+    sftk_FreeAttribute(attribute);
+    return CKR_OK;
+}
+
+CK_RV
+sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
+							 CK_ULONG *longData)
+{
+    SFTKAttribute *attribute;
+
+    attribute = sftk_FindAttribute(object, type);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+
+    if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+
+    *longData = *(CK_ULONG *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+    return CKR_OK;
+}
+
+void
+sftk_DeleteAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
+{
+    SFTKAttribute *attribute;
+    attribute = sftk_FindAttribute(object, type);
+    if (attribute == NULL) return ;
+    sftk_DeleteAttribute(object,attribute);
+    sftk_FreeAttribute(attribute);
+}
+
+CK_RV
+sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type,void *valPtr,
+							CK_ULONG length)
+{
+    SFTKAttribute *attribute;
+    attribute = sftk_NewAttribute(object,type,valPtr,length);
+    if (attribute == NULL) { return CKR_HOST_MEMORY; }
+    sftk_AddAttribute(object,attribute);
+    return CKR_OK;
+}
+
+/*
+ * ******************** Object Utilities *******************************
+ */
+
+/* must be called holding sftk_tokenKeyLock(slot) */
+static SECItem *
+sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
+{
+    return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)handle);
+}
+
+/*
+ * use the refLock. This operations should be very rare, so the added
+ * contention on the ref lock should be lower than the overhead of adding
+ * a new lock. We use separate functions for this just in case I'm wrong.
+ */
+static void
+sftk_tokenKeyLock(SFTKSlot *slot) {
+    SKIP_AFTER_FORK(PZ_Lock(slot->objectLock));
+}
+
+static void
+sftk_tokenKeyUnlock(SFTKSlot *slot) {
+    SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock));
+}
+
+static PRIntn
+sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg)
+{
+    SECItem *item = (SECItem *)entry->value;
+
+    SECITEM_FreeItem(item, PR_TRUE);
+    return HT_ENUMERATE_NEXT;
+}
+
+CK_RV
+SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)
+{
+    sftk_tokenKeyLock(slot);
+    PORT_Assert(!slot->present);
+    PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL);
+    sftk_tokenKeyUnlock(slot);
+    return CKR_OK;
+}
+
+
+/* allocation hooks that allow us to recycle old object structures */
+static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 };
+static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 };
+
+SFTKObject *
+sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace, 
+     SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)
+{
+    SFTKObject *object;
+    int size = 0;
+
+    if (!optimizeSpace) {
+	PZ_Lock(list->lock);
+	object = list->head;
+	if (object) {
+	    list->head = object->next;
+	    list->count--;
+	}    	
+	PZ_Unlock(list->lock);
+	if (object) {
+	    object->next = object->prev = NULL;
+            *hasLocks = PR_TRUE;
+	    return object;
+	}
+    }
+    size = isSessionObject ? sizeof(SFTKSessionObject) 
+		+ hashSize *sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);
+
+    object  = (SFTKObject*)PORT_ZAlloc(size);
+    if (isSessionObject && object) {
+	((SFTKSessionObject *)object)->hashSize = hashSize;
+    }
+    *hasLocks = PR_FALSE;
+    return object;
+}
+
+static void
+sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,
+						PRBool isSessionObject) {
+
+    /* the code below is equivalent to :
+     *     optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;
+     * just faster.
+     */
+    PRBool optimizeSpace = isSessionObject && 
+				((SFTKSessionObject *)object)->optimizeSpace; 
+    if (object->refLock && !optimizeSpace 
+	               && (list->count < MAX_OBJECT_LIST_SIZE)) {
+	PZ_Lock(list->lock);
+	object->next = list->head;
+	list->head = object;
+	list->count++;
+	PZ_Unlock(list->lock);
+	return;
+    }
+    if (isSessionObject) {
+	SFTKSessionObject *so = (SFTKSessionObject *)object;
+	PZ_DestroyLock(so->attributeLock);
+	so->attributeLock = NULL;
+    }
+    if (object->refLock) {
+	PZ_DestroyLock(object->refLock);
+	object->refLock = NULL;
+    }
+    PORT_Free(object);
+}
+
+static SFTKObject *
+sftk_freeObjectData(SFTKObject *object) {
+   SFTKObject *next = object->next;
+
+   PORT_Free(object);
+   return next;
+}
+
+static void
+sftk_InitFreeList(SFTKObjectFreeList *list)
+{
+    list->lock = PZ_NewLock(nssILockObject);
+}
+
+void sftk_InitFreeLists(void)
+{
+    sftk_InitFreeList(&sessionObjectList);
+    sftk_InitFreeList(&tokenObjectList);
+}
+   
+static void
+sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)
+{
+    SFTKObject *object;
+
+    if (!list->lock) {
+	return;
+    }
+    SKIP_AFTER_FORK(PZ_Lock(list->lock));
+    for (object= list->head; object != NULL; 
+					object = sftk_freeObjectData(object)) {
+	PZ_DestroyLock(object->refLock);
+	if (isSessionList) {
+	    PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);
+	}
+    }
+    list->count = 0;
+    list->head = NULL;
+    SKIP_AFTER_FORK(PZ_Unlock(list->lock));
+    SKIP_AFTER_FORK(PZ_DestroyLock(list->lock));
+    list->lock = NULL;
+}
+
+void
+sftk_CleanupFreeLists(void)
+{
+    sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);
+    sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);
+}
+
+
+/*
+ * Create a new object
+ */
+SFTKObject *
+sftk_NewObject(SFTKSlot *slot)
+{
+    SFTKObject *object;
+    SFTKSessionObject *sessObject;
+    PRBool hasLocks = PR_FALSE;
+    unsigned int i;
+    unsigned int hashSize = 0;
+
+    hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE :
+				TIME_ATTRIBUTE_HASH_SIZE;
+
+    object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,
+				&sessionObjectList,  hashSize, PR_TRUE);
+    if (object == NULL) {
+	return NULL;
+    }
+    sessObject = (SFTKSessionObject *)object;
+    sessObject->nextAttr = 0;
+
+    for (i=0; i < MAX_OBJS_ATTRS; i++) {
+	sessObject->attrList[i].attrib.pValue = NULL;
+	sessObject->attrList[i].freeData = PR_FALSE;
+    }
+    sessObject->optimizeSpace = slot->optimizeSpace;
+
+    object->handle = 0;
+    object->next = object->prev = NULL;
+    object->slot = slot;
+    
+    object->refCount = 1;
+    sessObject->sessionList.next = NULL;
+    sessObject->sessionList.prev = NULL;
+    sessObject->sessionList.parent = object;
+    sessObject->session = NULL;
+    sessObject->wasDerived = PR_FALSE;
+    if (!hasLocks) object->refLock = PZ_NewLock(nssILockRefLock);
+    if (object->refLock == NULL) {
+	PORT_Free(object);
+	return NULL;
+    }
+    if (!hasLocks) sessObject->attributeLock = PZ_NewLock(nssILockAttribute);
+    if (sessObject->attributeLock == NULL) {
+	PZ_DestroyLock(object->refLock);
+	PORT_Free(object);
+	return NULL;
+    }
+    for (i=0; i < sessObject->hashSize; i++) {
+	sessObject->head[i] = NULL;
+    }
+    object->objectInfo = NULL;
+    object->infoFree = NULL;
+    return object;
+}
+
+static CK_RV
+sftk_DestroySessionObjectData(SFTKSessionObject *so)
+{
+	int i;
+
+	for (i=0; i < MAX_OBJS_ATTRS; i++) {
+	    unsigned char *value = so->attrList[i].attrib.pValue;
+	    if (value) {
+		PORT_Memset(value,0,so->attrList[i].attrib.ulValueLen);
+		if (so->attrList[i].freeData) {
+		    PORT_Free(value);
+		}
+		so->attrList[i].attrib.pValue = NULL;
+		so->attrList[i].freeData = PR_FALSE;
+	    }
+	}
+/*	PZ_DestroyLock(so->attributeLock);*/
+	return CKR_OK;
+}
+
+/*
+ * free all the data associated with an object. Object reference count must
+ * be 'zero'.
+ */
+static CK_RV
+sftk_DestroyObject(SFTKObject *object)
+{
+    CK_RV crv = CKR_OK;
+    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
+    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
+
+    PORT_Assert(object->refCount == 0);
+
+    /* delete the database value */
+    if (to) {
+	if (to->dbKey.data) {
+	   PORT_Free(to->dbKey.data);
+	   to->dbKey.data = NULL;
+	}
+    } 
+    if (so) {
+	sftk_DestroySessionObjectData(so);
+    }
+    if (object->objectInfo) {
+	(*object->infoFree)(object->objectInfo);
+	object->objectInfo = NULL;
+	object->infoFree = NULL;
+    }
+    if (so) {
+	sftk_PutObjectToList(object,&sessionObjectList,PR_TRUE);
+    } else {
+	sftk_PutObjectToList(object,&tokenObjectList,PR_FALSE);
+    }
+    return crv;
+}
+
+void
+sftk_ReferenceObject(SFTKObject *object)
+{
+    PZ_Lock(object->refLock);
+    object->refCount++;
+    PZ_Unlock(object->refLock);
+}
+
+static SFTKObject *
+sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)
+{
+    SFTKObject *object;
+    PRUint32 index = sftk_hash(handle, slot->sessObjHashSize);
+
+    if (sftk_isToken(handle)) {
+	return sftk_NewTokenObject(slot, NULL, handle);
+    }
+
+    PZ_Lock(slot->objectLock);
+    sftkqueue_find2(object, handle, index, slot->sessObjHashTable);
+    if (object) {
+	sftk_ReferenceObject(object);
+    }
+    PZ_Unlock(slot->objectLock);
+
+    return(object);
+}
+/*
+ * look up and object structure from a handle. OBJECT_Handles only make
+ * sense in terms of a given session.  make a reference to that object
+ * structure returned.
+ */
+SFTKObject *
+sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)
+{
+    SFTKSlot *slot = sftk_SlotFromSession(session);
+
+    return sftk_ObjectFromHandleOnSlot(handle,slot);
+}
+
+
+/*
+ * release a reference to an object handle
+ */
+SFTKFreeStatus
+sftk_FreeObject(SFTKObject *object)
+{
+    PRBool destroy = PR_FALSE;
+    CK_RV crv;
+
+    PZ_Lock(object->refLock);
+    if (object->refCount == 1) destroy = PR_TRUE;
+    object->refCount--;
+    PZ_Unlock(object->refLock);
+
+    if (destroy) {
+	crv = sftk_DestroyObject(object);
+	if (crv != CKR_OK) {
+	   return SFTK_DestroyFailure;
+	} 
+	return SFTK_Destroyed;
+    }
+    return SFTK_Busy;
+}
+ 
+/*
+ * add an object to a slot and session queue. These two functions
+ * adopt the object.
+ */
+void
+sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
+{
+    PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
+    sftkqueue_init_element(object);
+    PZ_Lock(slot->objectLock);
+    sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable);
+    PZ_Unlock(slot->objectLock);
+}
+
+void
+sftk_AddObject(SFTKSession *session, SFTKObject *object)
+{
+    SFTKSlot *slot = sftk_SlotFromSession(session);
+    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
+
+    if (so) {
+	PZ_Lock(session->objectLock);
+	sftkqueue_add(&so->sessionList,0,session->objects,0);
+	so->session = session;
+	PZ_Unlock(session->objectLock);
+    }
+    sftk_AddSlotObject(slot,object);
+    sftk_ReferenceObject(object);
+} 
+
+/*
+ * delete an object from a slot and session queue
+ */
+CK_RV
+sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
+{
+    SFTKSlot *slot = sftk_SlotFromSession(session);
+    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
+    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
+    CK_RV crv = CKR_OK;
+    PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
+
+    /* Handle Token case */
+    if (so && so->session) {
+	SFTKSession *session = so->session;
+	PZ_Lock(session->objectLock);
+	sftkqueue_delete(&so->sessionList,0,session->objects,0);
+	PZ_Unlock(session->objectLock);
+	PZ_Lock(slot->objectLock);
+	sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable);
+	PZ_Unlock(slot->objectLock);
+	sftkqueue_clear_deleted_element(object);
+	sftk_FreeObject(object); /* free the reference owned by the queue */
+    } else {
+	SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle);
+
+	PORT_Assert(to);
+	crv = sftkdb_DestroyObject(handle, object->handle);
+	sftk_freeDB(handle);
+    } 
+    return crv;
+}
+
+/*
+ * Token objects don't explicitly store their attributes, so we need to know
+ * what attributes make up a particular token object before we can copy it.
+ * below are the tables by object type.
+ */
+static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
+    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
+};
+static const CK_ULONG commonAttrsCount = 
+			sizeof(commonAttrs)/sizeof(commonAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
+    CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
+};
+static const CK_ULONG commonKeyAttrsCount = 
+			sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
+    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
+    CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
+};
+static const CK_ULONG secretKeyAttrsCount = 
+			sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
+    CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
+};
+static const CK_ULONG commonPubKeyAttrsCount = 
+			sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
+    CKA_MODULUS, CKA_PUBLIC_EXPONENT
+};
+static const CK_ULONG rsaPubKeyAttrsCount = 
+			sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
+    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dsaPubKeyAttrsCount = 
+			sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
+    CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dhPubKeyAttrsCount = 
+			sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]);
+#ifdef NSS_ENABLE_ECC
+static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
+    CKA_EC_PARAMS, CKA_EC_POINT
+};
+static const CK_ULONG ecPubKeyAttrsCount = 
+			sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]);
+#endif
+
+static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
+    CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
+    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB
+};
+static const CK_ULONG commonPrivKeyAttrsCount = 
+		sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
+    CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, 
+    CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
+};
+static const CK_ULONG rsaPrivKeyAttrsCount = 
+			sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
+    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dsaPrivKeyAttrsCount = 
+			sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
+    CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dhPrivKeyAttrsCount = 
+			sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]);
+#ifdef NSS_ENABLE_ECC
+static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
+    CKA_EC_PARAMS, CKA_VALUE
+};
+static const CK_ULONG ecPrivKeyAttrsCount = 
+			sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]);
+#endif
+
+static const CK_ATTRIBUTE_TYPE certAttrs[] = {
+    CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
+};
+static const CK_ULONG certAttrsCount = 
+		sizeof(certAttrs)/sizeof(certAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
+    CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
+    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
+    CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
+};
+static const CK_ULONG trustAttrsCount = 
+		sizeof(trustAttrs)/sizeof(trustAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
+    CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE
+};
+static const CK_ULONG smimeAttrsCount = 
+		sizeof(smimeAttrs)/sizeof(smimeAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
+    CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL
+};
+static const CK_ULONG crlAttrsCount = 
+		sizeof(crlAttrs)/sizeof(crlAttrs[0]);
+
+/* copy an object based on it's table */
+CK_RV
+stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to,
+	const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
+{
+    SFTKAttribute *attribute;
+    SFTKAttribute *newAttribute;
+    CK_RV crv = CKR_OK;
+    unsigned int i;
+
+    for (i=0; i < attrCount; i++) {
+	if (!sftk_hasAttribute(destObject,attrArray[i])) {
+	    attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]);
+	    if (!attribute) {
+		continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
+	    }
+	    /* we need to copy the attribute since each attribute
+	     * only has one set of link list pointers */
+	    newAttribute = sftk_NewAttribute( destObject,
+				sftk_attr_expand(&attribute->attrib));
+	    sftk_FreeAttribute(attribute); /* free the old attribute */
+	    if (!newAttribute) {
+		return CKR_HOST_MEMORY;
+	    }
+	    sftk_AddAttribute(destObject,newAttribute);
+	}
+    }
+    return crv;
+}
+
+CK_RV
+stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to)
+{
+    CK_RV crv;
+    CK_KEY_TYPE key_type;
+    SFTKAttribute *attribute;
+
+    /* copy the common attributes for all keys first */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
+							commonKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    /* copy the common attributes for all private keys next */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
+						commonPrivKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
+    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
+			     * copying the common attributes */
+    if (!attribute) {
+	/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
+	 * the fact is, the only reason we couldn't get the attribute would
+	 * be a memory error or database error (an error in the 'device').
+	 * if we have a database error code, we could return it here */
+	crv = CKR_DEVICE_ERROR;
+	goto fail;
+    }
+    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+    
+    /* finally copy the attributes for various private key types */
+    switch (key_type) {
+    case CKK_RSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
+							rsaPrivKeyAttrsCount);
+	break;
+    case CKK_DSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
+							dsaPrivKeyAttrsCount);
+	break;
+    case CKK_DH:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
+							dhPrivKeyAttrsCount);
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKK_EC:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
+							ecPrivKeyAttrsCount);
+	break;
+#endif
+     default:
+	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
+				* of token keys into our database. */
+    }
+fail:
+    return crv;
+}
+
+CK_RV
+stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to)
+{
+    CK_RV crv;
+    CK_KEY_TYPE key_type;
+    SFTKAttribute *attribute;
+
+    /* copy the common attributes for all keys first */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
+							commonKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+
+    /* copy the common attributes for all public keys next */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
+							commonPubKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
+    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
+			     * copying the common attributes */
+    if (!attribute) {
+	/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
+	 * the fact is, the only reason we couldn't get the attribute would
+	 * be a memory error or database error (an error in the 'device').
+	 * if we have a database error code, we could return it here */
+	crv = CKR_DEVICE_ERROR;
+	goto fail;
+    }
+    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+    
+    /* finally copy the attributes for various public key types */
+    switch (key_type) {
+    case CKK_RSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
+							rsaPubKeyAttrsCount);
+	break;
+    case CKK_DSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
+							dsaPubKeyAttrsCount);
+	break;
+    case CKK_DH:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
+							dhPubKeyAttrsCount);
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKK_EC:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
+							ecPubKeyAttrsCount);
+	break;
+#endif
+     default:
+	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
+				* of token keys into our database. */
+    }
+fail:
+    return crv;
+}
+CK_RV
+stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to)
+{
+    CK_RV crv;
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
+							commonKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
+							secretKeyAttrsCount);
+fail:
+    return crv;
+}
+
+/*
+ * Copy a token object. We need to explicitly copy the relevant
+ * attributes since token objects don't store those attributes in
+ * the token itself.
+ */
+CK_RV
+sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject)
+{
+    SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
+    CK_RV crv;
+
+    PORT_Assert(src_to);
+    if (src_to == NULL) {
+	return CKR_DEVICE_ERROR; /* internal state inconsistant */
+    }
+
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
+							commonAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    switch (src_to->obj.objclass) {
+    case CKO_CERTIFICATE:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
+							certAttrsCount);
+ 	break;
+    case CKO_NETSCAPE_TRUST:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
+							trustAttrsCount);
+	break;
+    case CKO_NETSCAPE_SMIME:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
+							smimeAttrsCount);
+	break;
+    case CKO_NETSCAPE_CRL:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
+							crlAttrsCount);
+	break;
+    case CKO_PRIVATE_KEY:
+	crv = stfk_CopyTokenPrivateKey(destObject,src_to);
+	break;
+    case CKO_PUBLIC_KEY:
+	crv = stfk_CopyTokenPublicKey(destObject,src_to);
+	break;
+    case CKO_SECRET_KEY:
+	crv = stfk_CopyTokenSecretKey(destObject,src_to);
+	break;
+    default:
+	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
+				* of token keys into our database. */
+    }
+fail:
+    return crv;
+}
+
+/*
+ * copy the attributes from one object to another. Don't overwrite existing
+ * attributes. NOTE: This is a pretty expensive operation since it
+ * grabs the attribute locks for the src object for a *long* time.
+ */
+CK_RV
+sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject)
+{
+    SFTKAttribute *attribute;
+    SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
+    unsigned int i;
+
+    if (src_so == NULL) {
+	return sftk_CopyTokenObject(destObject,srcObject); 
+    }
+
+    PZ_Lock(src_so->attributeLock);
+    for(i=0; i < src_so->hashSize; i++) {
+	attribute = src_so->head[i];
+	do {
+	    if (attribute) {
+		if (!sftk_hasAttribute(destObject,attribute->handle)) {
+		    /* we need to copy the attribute since each attribute
+		     * only has one set of link list pointers */
+		    SFTKAttribute *newAttribute = sftk_NewAttribute(
+			  destObject,sftk_attr_expand(&attribute->attrib));
+		    if (newAttribute == NULL) {
+			PZ_Unlock(src_so->attributeLock);
+			return CKR_HOST_MEMORY;
+		    }
+		    sftk_AddAttribute(destObject,newAttribute);
+		}
+		attribute=attribute->next;
+	    }
+	} while (attribute != NULL);
+    }
+    PZ_Unlock(src_so->attributeLock);
+
+    return CKR_OK;
+}
+
+/*
+ * ******************** Search Utilities *******************************
+ */
+
+/* add an object to a search list */
+CK_RV
+AddToList(SFTKObjectListElement **list,SFTKObject *object)
+{
+     SFTKObjectListElement *newElem = 
+	(SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));
+
+     if (newElem == NULL) return CKR_HOST_MEMORY;
+
+     newElem->next = *list;
+     newElem->object = object;
+     sftk_ReferenceObject(object);
+
+    *list = newElem;
+    return CKR_OK;
+}
+
+
+/* return true if the object matches the template */
+PRBool
+sftk_objectMatch(SFTKObject *object,CK_ATTRIBUTE_PTR theTemplate,int count)
+{
+    int i;
+
+    for (i=0; i < count; i++) {
+	SFTKAttribute *attribute = sftk_FindAttribute(object,theTemplate[i].type);
+	if (attribute == NULL) {
+	    return PR_FALSE;
+	}
+	if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) {
+	    if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue,
+					theTemplate[i].ulValueLen) == 0) {
+        	sftk_FreeAttribute(attribute);
+		continue;
+	    }
+	}
+        sftk_FreeAttribute(attribute);
+	return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+/* search through all the objects in the queue and return the template matches
+ * in the object list.
+ */
+CK_RV
+sftk_searchObjectList(SFTKSearchResults *search,SFTKObject **head, 
+	unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate, 
+						int count, PRBool isLoggedIn)
+{
+    unsigned int i;
+    SFTKObject *object;
+    CK_RV crv = CKR_OK;
+
+    for(i=0; i < size; i++) {
+        /* We need to hold the lock to copy a consistant version of
+         * the linked list. */
+        PZ_Lock(lock);
+	for (object = head[i]; object != NULL; object= object->next) {
+	    if (sftk_objectMatch(object,theTemplate,count)) {
+		/* don't return objects that aren't yet visible */
+		if ((!isLoggedIn) && sftk_isTrue(object,CKA_PRIVATE)) continue;
+		sftk_addHandle(search,object->handle);
+	    }
+	}
+        PZ_Unlock(lock);
+    }
+    return crv;
+}
+
+/*
+ * free a single list element. Return the Next object in the list.
+ */
+SFTKObjectListElement *
+sftk_FreeObjectListElement(SFTKObjectListElement *objectList)
+{
+    SFTKObjectListElement *ol = objectList->next;
+
+    sftk_FreeObject(objectList->object);
+    PORT_Free(objectList);
+    return ol;
+}
+
+/* free an entire object list */
+void
+sftk_FreeObjectList(SFTKObjectListElement *objectList)
+{
+    SFTKObjectListElement *ol;
+
+    for (ol= objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {}
+}
+
+/*
+ * free a search structure
+ */
+void
+sftk_FreeSearch(SFTKSearchResults *search)
+{
+    if (search->handles) {
+	PORT_Free(search->handles);
+    }
+    PORT_Free(search);
+}
+
+/*
+ * ******************** Session Utilities *******************************
+ */
+
+/* update the sessions state based in it's flags and wether or not it's
+ * logged in */
+void
+sftk_update_state(SFTKSlot *slot,SFTKSession *session)
+{
+    if (slot->isLoggedIn) {
+	if (slot->ssoLoggedIn) {
+    	    session->info.state = CKS_RW_SO_FUNCTIONS;
+	} else if (session->info.flags & CKF_RW_SESSION) {
+    	    session->info.state = CKS_RW_USER_FUNCTIONS;
+	} else {
+    	    session->info.state = CKS_RO_USER_FUNCTIONS;
+	}
+    } else {
+	if (session->info.flags & CKF_RW_SESSION) {
+    	    session->info.state = CKS_RW_PUBLIC_SESSION;
+	} else {
+    	    session->info.state = CKS_RO_PUBLIC_SESSION;
+	}
+    }
+}
+
+/* update the state of all the sessions on a slot */
+void
+sftk_update_all_states(SFTKSlot *slot)
+{
+    unsigned int i;
+    SFTKSession *session;
+
+    for (i=0; i < slot->sessHashSize; i++) {
+	PZLock *lock = SFTK_SESSION_LOCK(slot,i);
+	PZ_Lock(lock);
+	for (session = slot->head[i]; session; session = session->next) {
+	    sftk_update_state(slot,session);
+	}
+	PZ_Unlock(lock);
+    }
+}
+
+/*
+ * context are cipher and digest contexts that are associated with a session
+ */
+void
+sftk_FreeContext(SFTKSessionContext *context)
+{
+    if (context->cipherInfo) {
+	(*context->destroy)(context->cipherInfo,PR_TRUE);
+    }
+    if (context->hashInfo) {
+	(*context->hashdestroy)(context->hashInfo,PR_TRUE);
+    }
+    if (context->key) {
+	sftk_FreeObject(context->key);
+	context->key = NULL;
+    }
+    PORT_Free(context);
+}
+
+/*
+ * create a new nession. NOTE: The session handle is not set, and the
+ * session is not added to the slot's session queue.
+ */
+SFTKSession *
+sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
+							     CK_FLAGS flags)
+{
+    SFTKSession *session;
+    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
+
+    if (slot == NULL) return NULL;
+
+    session = (SFTKSession*)PORT_Alloc(sizeof(SFTKSession));
+    if (session == NULL) return NULL;
+
+    session->next = session->prev = NULL;
+    session->refCount = 1;
+    session->enc_context = NULL;
+    session->hash_context = NULL;
+    session->sign_context = NULL;
+    session->search = NULL;
+    session->objectIDCount = 1;
+    session->objectLock = PZ_NewLock(nssILockObject);
+    if (session->objectLock == NULL) {
+	PORT_Free(session);
+	return NULL;
+    }
+    session->objects[0] = NULL;
+
+    session->slot = slot;
+    session->notify = notify;
+    session->appData = pApplication;
+    session->info.flags = flags;
+    session->info.slotID = slotID;
+    session->info.ulDeviceError = 0;
+    sftk_update_state(slot,session);
+    return session;
+}
+
+
+/* free all the data associated with a session. */
+static void
+sftk_DestroySession(SFTKSession *session)
+{
+    SFTKObjectList *op,*next;
+    PORT_Assert(session->refCount == 0);
+
+    /* clean out the attributes */
+    /* since no one is referencing us, it's safe to walk the chain
+     * without a lock */
+    for (op = session->objects[0]; op != NULL; op = next) {
+        next = op->next;
+        /* paranoia */
+	op->next = op->prev = NULL;
+	sftk_DeleteObject(session,op->parent);
+    }
+    PZ_DestroyLock(session->objectLock);
+    if (session->enc_context) {
+	sftk_FreeContext(session->enc_context);
+    }
+    if (session->hash_context) {
+	sftk_FreeContext(session->hash_context);
+    }
+    if (session->sign_context) {
+	sftk_FreeContext(session->sign_context);
+    }
+    if (session->search) {
+	sftk_FreeSearch(session->search);
+    }
+    PORT_Free(session);
+}
+
+
+/*
+ * look up a session structure from a session handle
+ * generate a reference to it.
+ */
+SFTKSession *
+sftk_SessionFromHandle(CK_SESSION_HANDLE handle)
+{
+    SFTKSlot	*slot = sftk_SlotFromSessionHandle(handle);
+    SFTKSession *session;
+    PZLock	*lock;
+    
+    if (!slot) return NULL;
+    lock = SFTK_SESSION_LOCK(slot,handle);
+
+    PZ_Lock(lock);
+    sftkqueue_find(session,handle,slot->head,slot->sessHashSize);
+    if (session) session->refCount++;
+    PZ_Unlock(lock);
+
+    return (session);
+}
+
+/*
+ * release a reference to a session handle
+ */
+void
+sftk_FreeSession(SFTKSession *session)
+{
+    PRBool destroy = PR_FALSE;
+    SFTKSlot *slot = sftk_SlotFromSession(session);
+    PZLock *lock = SFTK_SESSION_LOCK(slot,session->handle);
+
+    PZ_Lock(lock);
+    if (session->refCount == 1) destroy = PR_TRUE;
+    session->refCount--;
+    PZ_Unlock(lock);
+
+    if (destroy) sftk_DestroySession(session);
+}
+
+void
+sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)
+{
+    if (search->handles == NULL) {
+	return;
+    }
+    if (search->size >= search->array_size) {
+	search->array_size += NSC_SEARCH_BLOCK_SIZE;
+	search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles,
+				 sizeof(CK_OBJECT_HANDLE)* search->array_size);
+	if (search->handles == NULL) {
+	   return;
+	}
+    }
+    search->handles[search->size] = handle;
+    search->size++;
+}
+
+static  CK_RV
+handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle, 
+	      CK_OBJECT_CLASS *objClass)
+{
+    SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle);
+    CK_ATTRIBUTE objClassTemplate;
+    CK_RV crv;
+
+    *objClass = CKO_DATA;
+    objClassTemplate.type = CKA_CLASS;
+    objClassTemplate.pValue = objClass;
+    objClassTemplate.ulValueLen = sizeof(*objClass);
+    crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1);
+    sftk_freeDB(dbHandle);
+    return crv;
+}
+
+SFTKObject *
+sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
+{
+    SFTKObject *object = NULL;
+    SFTKTokenObject *tokObject = NULL;
+    PRBool hasLocks = PR_FALSE;
+    CK_RV crv;
+
+    object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList,  0,
+							PR_FALSE);
+    if (object == NULL) {
+	return NULL;
+    }
+    tokObject = (SFTKTokenObject *) object;
+
+    object->handle = handle;
+    /* every object must have a class, if we can't get it, the object
+     * doesn't exist */
+    crv = handleToClass(slot, handle, &object->objclass);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    object->slot = slot;
+    object->objectInfo = NULL;
+    object->infoFree = NULL;
+    if (!hasLocks) {
+	object->refLock = PZ_NewLock(nssILockRefLock);
+    }
+    if (object->refLock == NULL) {
+	goto loser;
+    }
+    object->refCount = 1;
+
+    return object;
+loser:
+    if (object) {
+	(void) sftk_DestroyObject(object);
+    }
+    return NULL;
+
+}
+
+SFTKTokenObject *
+sftk_convertSessionToToken(SFTKObject *obj)
+{
+    SECItem *key;
+    SFTKSessionObject *so = (SFTKSessionObject *)obj;
+    SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
+    SECStatus rv;
+
+    sftk_DestroySessionObjectData(so);
+    PZ_DestroyLock(so->attributeLock);
+    if (to == NULL) {
+	return NULL;
+    }
+    sftk_tokenKeyLock(so->obj.slot);
+    key = sftk_lookupTokenKeyByHandle(so->obj.slot,so->obj.handle);
+    if (key == NULL) {
+    	sftk_tokenKeyUnlock(so->obj.slot);
+	return NULL;
+    }
+    rv = SECITEM_CopyItem(NULL,&to->dbKey,key);
+    sftk_tokenKeyUnlock(so->obj.slot);
+    if (rv == SECFailure) {
+	return NULL;
+    }
+
+    return to;
+}
+
+SFTKSessionObject *
+sftk_narrowToSessionObject(SFTKObject *obj)
+{
+    return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;
+}
+
+SFTKTokenObject *
+sftk_narrowToTokenObject(SFTKObject *obj)
+{
+    return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
+}
+
diff --git a/mozilla/security/nss/lib/softoken/rsawrapr.c b/mozilla/security/nss/lib/softoken/rsawrapr.c
new file mode 100644
index 0000000..cda6d75
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/rsawrapr.c
@@ -0,0 +1,917 @@
+/*
+ * PKCS#1 encoding and decoding functions.
+ * This file is believed to contain no code licensed from other parties.
+ *
+ * ***** 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 ***** */
+/* $Id: rsawrapr.c,v 1.11 2006/10/23 21:24:38 wtchang%redhat.com Exp $ */
+
+#include "blapi.h"
+#include "softoken.h"
+#include "sechash.h"
+
+#include "lowkeyi.h"
+#include "secerr.h"
+
+#define RSA_BLOCK_MIN_PAD_LEN		8
+#define RSA_BLOCK_FIRST_OCTET		0x00
+#define RSA_BLOCK_PRIVATE0_PAD_OCTET	0x00
+#define RSA_BLOCK_PRIVATE_PAD_OCTET	0xff
+#define RSA_BLOCK_AFTER_PAD_OCTET	0x00
+
+#define OAEP_SALT_LEN		8
+#define OAEP_PAD_LEN		8
+#define OAEP_PAD_OCTET		0x00
+
+#define FLAT_BUFSIZE 512	/* bytes to hold flattened SHA1Context. */
+
+static SHA1Context *
+SHA1_CloneContext(SHA1Context *original)
+{
+    SHA1Context *  clone	= NULL;
+    unsigned char *pBuf;
+    int            sha1ContextSize = SHA1_FlattenSize(original);
+    SECStatus      frv;
+    unsigned char  buf[FLAT_BUFSIZE];
+
+    PORT_Assert(sizeof buf >= sha1ContextSize);
+    if (sizeof buf >= sha1ContextSize) {
+    	pBuf = buf;
+    } else {
+        pBuf = PORT_Alloc(sha1ContextSize);
+	if (!pBuf)
+	    goto done;
+    }
+
+    frv = SHA1_Flatten(original, pBuf);
+    if (frv == SECSuccess) {
+	clone = SHA1_Resurrect(pBuf, NULL);
+	memset(pBuf, 0, sha1ContextSize);
+    }
+done:
+    if (pBuf != buf)
+    	PORT_Free(pBuf);
+    return clone;
+}
+
+/*
+ * Modify data by XORing it with a special hash of salt.
+ */
+static SECStatus
+oaep_xor_with_h1(unsigned char *data, unsigned int datalen,
+		 unsigned char *salt, unsigned int saltlen)
+{
+    SHA1Context *sha1cx;
+    unsigned char *dp, *dataend;
+    unsigned char end_octet;
+
+    sha1cx = SHA1_NewContext();
+    if (sha1cx == NULL) {
+	return SECFailure;
+    }
+
+    /*
+     * Get a hash of salt started; we will use it several times,
+     * adding in a different end octet (x00, x01, x02, ...).
+     */
+    SHA1_Begin (sha1cx);
+    SHA1_Update (sha1cx, salt, saltlen);
+    end_octet = 0;
+
+    dp = data;
+    dataend = data + datalen;
+
+    while (dp < dataend) {
+	SHA1Context *sha1cx_h1;
+	unsigned int sha1len, sha1off;
+	unsigned char sha1[SHA1_LENGTH];
+
+	/*
+	 * Create hash of (salt || end_octet)
+	 */
+	sha1cx_h1 = SHA1_CloneContext (sha1cx);
+	SHA1_Update (sha1cx_h1, &end_octet, 1);
+	SHA1_End (sha1cx_h1, sha1, &sha1len, sizeof(sha1));
+	SHA1_DestroyContext (sha1cx_h1, PR_TRUE);
+	PORT_Assert (sha1len == SHA1_LENGTH);
+
+	/*
+	 * XOR that hash with the data.
+	 * When we have fewer than SHA1_LENGTH octets of data
+	 * left to xor, use just the low-order ones of the hash.
+	 */
+	sha1off = 0;
+	if ((dataend - dp) < SHA1_LENGTH)
+	    sha1off = SHA1_LENGTH - (dataend - dp);
+	while (sha1off < SHA1_LENGTH)
+	    *dp++ ^= sha1[sha1off++];
+
+	/*
+	 * Bump for next hash chunk.
+	 */
+	end_octet++;
+    }
+
+    SHA1_DestroyContext (sha1cx, PR_TRUE);
+    return SECSuccess;
+}
+
+/*
+ * Modify salt by XORing it with a special hash of data.
+ */
+static SECStatus
+oaep_xor_with_h2(unsigned char *salt, unsigned int saltlen,
+		 unsigned char *data, unsigned int datalen)
+{
+    unsigned char sha1[SHA1_LENGTH];
+    unsigned char *psalt, *psha1, *saltend;
+    SECStatus rv;
+
+    /*
+     * Create a hash of data.
+     */
+    rv = SHA1_HashBuf (sha1, data, datalen);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+
+    /*
+     * XOR the low-order octets of that hash with salt.
+     */
+    PORT_Assert (saltlen <= SHA1_LENGTH);
+    saltend = salt + saltlen;
+    psalt = salt;
+    psha1 = sha1 + SHA1_LENGTH - saltlen;
+    while (psalt < saltend) {
+	*psalt++ ^= *psha1++;
+    }
+
+    return SECSuccess;
+}
+
+/*
+ * Format one block of data for public/private key encryption using
+ * the rules defined in PKCS #1.
+ */
+static unsigned char *
+rsa_FormatOneBlock(unsigned modulusLen, RSA_BlockType blockType,
+		   SECItem *data)
+{
+    unsigned char *block;
+    unsigned char *bp;
+    int padLen;
+    int i;
+    SECStatus rv;
+
+    block = (unsigned char *) PORT_Alloc(modulusLen);
+    if (block == NULL)
+	return NULL;
+
+    bp = block;
+
+    /*
+     * All RSA blocks start with two octets:
+     *	0x00 || BlockType
+     */
+    *bp++ = RSA_BLOCK_FIRST_OCTET;
+    *bp++ = (unsigned char) blockType;
+
+    switch (blockType) {
+
+      /*
+       * Blocks intended for private-key operation.
+       */
+      case RSA_BlockPrivate0: /* essentially unused */
+      case RSA_BlockPrivate:	 /* preferred method */
+	/*
+	 * 0x00 || BT || Pad || 0x00 || ActualData
+	 *   1      1   padLen    1      data->len
+	 * Pad is either all 0x00 or all 0xff bytes, depending on blockType.
+	 */
+	padLen = modulusLen - data->len - 3;
+	PORT_Assert (padLen >= RSA_BLOCK_MIN_PAD_LEN);
+	if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
+	    PORT_Free (block);
+	    return NULL;
+	}
+	PORT_Memset (bp,
+		   blockType == RSA_BlockPrivate0
+			? RSA_BLOCK_PRIVATE0_PAD_OCTET
+			: RSA_BLOCK_PRIVATE_PAD_OCTET,
+		   padLen);
+	bp += padLen;
+	*bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
+	PORT_Memcpy (bp, data->data, data->len);
+	break;
+
+      /*
+       * Blocks intended for public-key operation.
+       */
+      case RSA_BlockPublic:
+
+	/*
+	 * 0x00 || BT || Pad || 0x00 || ActualData
+	 *   1      1   padLen    1      data->len
+	 * Pad is all non-zero random bytes.
+	 */
+	padLen = modulusLen - data->len - 3;
+	PORT_Assert (padLen >= RSA_BLOCK_MIN_PAD_LEN);
+	if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
+	    PORT_Free (block);
+	    return NULL;
+	}
+	for (i = 0; i < padLen; i++) {
+	    /* Pad with non-zero random data. */
+	    do {
+		rv = RNG_GenerateGlobalRandomBytes(bp + i, 1);
+	    } while (rv == SECSuccess && bp[i] == RSA_BLOCK_AFTER_PAD_OCTET);
+	    if (rv != SECSuccess) {
+		sftk_fatalError = PR_TRUE;
+		PORT_Free (block);
+		return NULL;
+	    }
+	}
+	bp += padLen;
+	*bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
+	PORT_Memcpy (bp, data->data, data->len);
+
+	break;
+
+      /*
+       * Blocks intended for public-key operation, using
+       * Optimal Asymmetric Encryption Padding (OAEP).
+       */
+      case RSA_BlockOAEP:
+	/*
+	 * 0x00 || BT || Modified2(Salt) || Modified1(PaddedData)
+	 *   1      1     OAEP_SALT_LEN     OAEP_PAD_LEN + data->len [+ N]
+	 *
+	 * where:
+	 *   PaddedData is "Pad1 || ActualData [|| Pad2]"
+	 *   Salt is random data.
+	 *   Pad1 is all zeros.
+	 *   Pad2, if present, is random data.
+	 *   (The "modified" fields are all the same length as the original
+	 * unmodified values; they are just xor'd with other values.)
+	 *
+	 *   Modified1 is an XOR of PaddedData with a special octet
+	 * string constructed of iterated hashing of Salt (see below).
+	 *   Modified2 is an XOR of Salt with the low-order octets of
+	 * the hash of Modified1 (see farther below ;-).
+	 *
+	 * Whew!
+	 */
+
+
+	/*
+	 * Salt
+	 */
+	rv = RNG_GenerateGlobalRandomBytes(bp, OAEP_SALT_LEN);
+	if (rv != SECSuccess) {
+	    sftk_fatalError = PR_TRUE;
+	    PORT_Free (block);
+	    return NULL;
+	}
+	bp += OAEP_SALT_LEN;
+
+	/*
+	 * Pad1
+	 */
+	PORT_Memset (bp, OAEP_PAD_OCTET, OAEP_PAD_LEN);
+	bp += OAEP_PAD_LEN;
+
+	/*
+	 * Data
+	 */
+	PORT_Memcpy (bp, data->data, data->len);
+	bp += data->len;
+
+	/*
+	 * Pad2
+	 */
+	if (bp < (block + modulusLen)) {
+	    rv = RNG_GenerateGlobalRandomBytes(bp, block - bp + modulusLen);
+	    if (rv != SECSuccess) {
+		sftk_fatalError = PR_TRUE;
+		PORT_Free (block);
+		return NULL;
+	    }
+	}
+
+	/*
+	 * Now we have the following:
+	 * 0x00 || BT || Salt || PaddedData
+	 * (From this point on, "Pad1 || Data [|| Pad2]" is treated
+	 * as the one entity PaddedData.)
+	 *
+	 * We need to turn PaddedData into Modified1.
+	 */
+	if (oaep_xor_with_h1(block + 2 + OAEP_SALT_LEN,
+			     modulusLen - 2 - OAEP_SALT_LEN,
+			     block + 2, OAEP_SALT_LEN) != SECSuccess) {
+	    PORT_Free (block);
+	    return NULL;
+	}
+
+	/*
+	 * Now we have:
+	 * 0x00 || BT || Salt || Modified1(PaddedData)
+	 *
+	 * The remaining task is to turn Salt into Modified2.
+	 */
+	if (oaep_xor_with_h2(block + 2, OAEP_SALT_LEN,
+			     block + 2 + OAEP_SALT_LEN,
+			     modulusLen - 2 - OAEP_SALT_LEN) != SECSuccess) {
+	    PORT_Free (block);
+	    return NULL;
+	}
+
+	break;
+
+      default:
+	PORT_Assert (0);
+	PORT_Free (block);
+	return NULL;
+    }
+
+    return block;
+}
+
+static SECStatus
+rsa_FormatBlock(SECItem *result, unsigned modulusLen,
+		RSA_BlockType blockType, SECItem *data)
+{
+    /*
+     * XXX For now assume that the data length fits in a single
+     * XXX encryption block; the ASSERTs below force this.
+     * XXX To fix it, each case will have to loop over chunks whose
+     * XXX lengths satisfy the assertions, until all data is handled.
+     * XXX (Unless RSA has more to say about how to handle data
+     * XXX which does not fit in a single encryption block?)
+     * XXX And I do not know what the result is supposed to be,
+     * XXX so the interface to this function may need to change
+     * XXX to allow for returning multiple blocks, if they are
+     * XXX not wanted simply concatenated one after the other.
+     */
+
+    switch (blockType) {
+      case RSA_BlockPrivate0:
+      case RSA_BlockPrivate:
+      case RSA_BlockPublic:
+	/*
+	 * 0x00 || BT || Pad || 0x00 || ActualData
+	 *
+	 * The "3" below is the first octet + the second octet + the 0x00
+	 * octet that always comes just before the ActualData.
+	 */
+	PORT_Assert (data->len <= (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)));
+
+	result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
+	if (result->data == NULL) {
+	    result->len = 0;
+	    return SECFailure;
+	}
+	result->len = modulusLen;
+
+	break;
+
+      case RSA_BlockOAEP:
+	/*
+	 * 0x00 || BT || M1(Salt) || M2(Pad1||ActualData[||Pad2])
+	 *
+	 * The "2" below is the first octet + the second octet.
+	 * (The other fields do not contain the clear values, but are
+	 * the same length as the clear values.)
+	 */
+	PORT_Assert (data->len <= (modulusLen - (2 + OAEP_SALT_LEN
+						 + OAEP_PAD_LEN)));
+
+	result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
+	if (result->data == NULL) {
+	    result->len = 0;
+	    return SECFailure;
+	}
+	result->len = modulusLen;
+
+	break;
+
+      case RSA_BlockRaw:
+	/*
+	 * Pad || ActualData
+	 * Pad is zeros. The application is responsible for recovering
+	 * the actual data.
+	 */
+	if (data->len > modulusLen ) {
+	    return SECFailure;
+	}
+	result->data = (unsigned char*)PORT_ZAlloc(modulusLen);
+	result->len = modulusLen;
+	PORT_Memcpy(result->data+(modulusLen-data->len),data->data,data->len);
+	break;
+
+      default:
+	PORT_Assert (0);
+	result->data = NULL;
+	result->len = 0;
+	return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_Sign(NSSLOWKEYPrivateKey *key, 
+         unsigned char *      output, 
+	 unsigned int *       output_len,
+         unsigned int         maxOutputLen, 
+	 unsigned char *      input, 
+	 unsigned int         input_len)
+{
+    SECStatus     rv          = SECSuccess;
+    unsigned int  modulus_len = nsslowkey_PrivateModulusLen(key);
+    SECItem       formatted;
+    SECItem       unformatted;
+
+    if (maxOutputLen < modulus_len) 
+    	return SECFailure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	return SECFailure;
+
+    unformatted.len  = input_len;
+    unformatted.data = input;
+    formatted.data   = NULL;
+    rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockPrivate,
+			 &unformatted);
+    if (rv != SECSuccess) 
+    	goto done;
+
+    rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output, formatted.data);
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+	sftk_fatalError = PR_TRUE;
+    }
+    *output_len = modulus_len;
+
+    goto done;
+
+done:
+    if (formatted.data != NULL) 
+    	PORT_ZFree(formatted.data, modulus_len);
+    return rv;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSign(NSSLOWKEYPublicKey *key,
+              unsigned char *     sign, 
+	      unsigned int        sign_len, 
+	      unsigned char *     hash, 
+	      unsigned int        hash_len)
+{
+    SECStatus       rv;
+    unsigned int    modulus_len = nsslowkey_PublicModulusLen(key);
+    unsigned int    i;
+    unsigned char * buffer;
+
+    modulus_len = nsslowkey_PublicModulusLen(key);
+    if (sign_len != modulus_len) 
+    	goto failure;
+    /*
+     * 0x00 || BT || Pad || 0x00 || ActualData
+     *
+     * The "3" below is the first octet + the second octet + the 0x00
+     * octet that always comes just before the ActualData.
+     */
+    if (hash_len > modulus_len - (3 + RSA_BLOCK_MIN_PAD_LEN)) 
+    	goto failure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+
+    buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
+    if (!buffer)
+    	goto failure;
+
+    rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
+    if (rv != SECSuccess)
+	goto loser;
+
+    /*
+     * check the padding that was used
+     */
+    if (buffer[0] != 0 || buffer[1] != 1) 
+    	goto loser;
+    for (i = 2; i < modulus_len - hash_len - 1; i++) {
+	if (buffer[i] != 0xff) 
+	    goto loser;
+    }
+    if (buffer[i] != 0) 
+	goto loser;
+
+    /*
+     * make sure we get the same results
+     */
+    if (PORT_Memcmp(buffer + modulus_len - hash_len, hash, hash_len) != 0)
+	goto loser;
+
+    PORT_Free(buffer);
+    return SECSuccess;
+
+loser:
+    PORT_Free(buffer);
+failure:
+    return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSignRecover(NSSLOWKEYPublicKey *key,
+                     unsigned char *     data,
+                     unsigned int *      data_len, 
+		     unsigned int        max_output_len, 
+		     unsigned char *     sign,
+		     unsigned int        sign_len)
+{
+    SECStatus       rv;
+    unsigned int    modulus_len = nsslowkey_PublicModulusLen(key);
+    unsigned int    i;
+    unsigned char * buffer;
+
+    if (sign_len != modulus_len) 
+    	goto failure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+
+    buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
+    if (!buffer)
+    	goto failure;
+
+    rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
+    if (rv != SECSuccess)
+    	goto loser;
+    *data_len = 0;
+
+    /*
+     * check the padding that was used
+     */
+    if (buffer[0] != 0 || buffer[1] != 1) 
+    	goto loser;
+    for (i = 2; i < modulus_len; i++) {
+	if (buffer[i] == 0) {
+	    *data_len = modulus_len - i - 1;
+	    break;
+	}
+	if (buffer[i] != 0xff) 
+	    goto loser;
+    }
+    if (*data_len == 0) 
+    	goto loser;
+    if (*data_len > max_output_len) 
+    	goto loser;
+
+    /*
+     * make sure we get the same results
+     */
+    PORT_Memcpy(data,buffer + modulus_len - *data_len, *data_len);
+
+    PORT_Free(buffer);
+    return SECSuccess;
+
+loser:
+    PORT_Free(buffer);
+failure:
+    return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_EncryptBlock(NSSLOWKEYPublicKey *key, 
+                 unsigned char *     output, 
+		 unsigned int *      output_len,
+                 unsigned int        max_output_len, 
+		 unsigned char *     input, 
+		 unsigned int        input_len)
+{
+    SECStatus     rv;
+    unsigned int  modulus_len = nsslowkey_PublicModulusLen(key);
+    SECItem       formatted;
+    SECItem       unformatted;
+
+    formatted.data = NULL;
+    if (max_output_len < modulus_len) 
+    	goto failure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+
+    unformatted.len  = input_len;
+    unformatted.data = input;
+    formatted.data   = NULL;
+    rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockPublic,
+			 &unformatted);
+    if (rv != SECSuccess) 
+	goto failure;
+
+    rv = RSA_PublicKeyOp(&key->u.rsa, output, formatted.data);
+    if (rv != SECSuccess) 
+    	goto failure;
+
+    PORT_ZFree(formatted.data, modulus_len);
+    *output_len = modulus_len;
+    return SECSuccess;
+
+failure:
+    if (formatted.data != NULL) 
+	PORT_ZFree(formatted.data, modulus_len);
+    return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_DecryptBlock(NSSLOWKEYPrivateKey *key, 
+                 unsigned char *      output, 
+		 unsigned int *       output_len,
+                 unsigned int         max_output_len, 
+		 unsigned char *      input, 
+		 unsigned int         input_len)
+{
+    SECStatus       rv;
+    unsigned int    modulus_len = nsslowkey_PrivateModulusLen(key);
+    unsigned int    i;
+    unsigned char * buffer;
+
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+    if (input_len != modulus_len)
+    	goto failure;
+
+    buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
+    if (!buffer)
+    	goto failure;
+
+    rv = RSA_PrivateKeyOp(&key->u.rsa, buffer, input);
+    if (rv != SECSuccess) {
+	if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+	    sftk_fatalError = PR_TRUE;
+	}
+    	goto loser;
+    }
+
+    if (buffer[0] != 0 || buffer[1] != 2) 
+    	goto loser;
+    *output_len = 0;
+    for (i = 2; i < modulus_len; i++) {
+	if (buffer[i] == 0) {
+	    *output_len = modulus_len - i - 1;
+	    break;
+	}
+    }
+    if (*output_len == 0) 
+    	goto loser;
+    if (*output_len > max_output_len) 
+    	goto loser;
+
+    PORT_Memcpy(output, buffer + modulus_len - *output_len, *output_len);
+
+    PORT_Free(buffer);
+    return SECSuccess;
+
+loser:
+    PORT_Free(buffer);
+failure:
+    return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+/*
+ * added to make pkcs #11 happy
+ *   RAW is RSA_X_509
+ */
+SECStatus
+RSA_SignRaw(NSSLOWKEYPrivateKey *key, 
+            unsigned char *      output, 
+	    unsigned int *       output_len,
+            unsigned int         maxOutputLen, 
+	    unsigned char *      input, 
+	    unsigned int         input_len)
+{
+    SECStatus    rv          = SECSuccess;
+    unsigned int modulus_len = nsslowkey_PrivateModulusLen(key);
+    SECItem      formatted;
+    SECItem      unformatted;
+
+    if (maxOutputLen < modulus_len) 
+    	return SECFailure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	return SECFailure;
+
+    unformatted.len  = input_len;
+    unformatted.data = input;
+    formatted.data   = NULL;
+    rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockRaw, &unformatted);
+    if (rv != SECSuccess) 
+    	goto done;
+
+    rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output, formatted.data);
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+	sftk_fatalError = PR_TRUE;
+    }
+    *output_len = modulus_len;
+
+done:
+    if (formatted.data != NULL) 
+    	PORT_ZFree(formatted.data, modulus_len);
+    return rv;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSignRaw(NSSLOWKEYPublicKey *key,
+                 unsigned char *     sign, 
+		 unsigned int        sign_len, 
+		 unsigned char *     hash, 
+		 unsigned int        hash_len)
+{
+    SECStatus       rv;
+    unsigned int    modulus_len = nsslowkey_PublicModulusLen(key);
+    unsigned char * buffer;
+
+    if (sign_len != modulus_len) 
+    	goto failure;
+    if (hash_len > modulus_len) 
+    	goto failure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+
+    buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
+    if (!buffer)
+    	goto failure;
+
+    rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
+    if (rv != SECSuccess)
+	goto loser;
+
+    /*
+     * make sure we get the same results
+     */
+    /* NOTE: should we verify the leading zeros? */
+    if (PORT_Memcmp(buffer + (modulus_len-hash_len), hash, hash_len) != 0)
+	goto loser;
+
+    PORT_Free(buffer);
+    return SECSuccess;
+
+loser:
+    PORT_Free(buffer);
+failure:
+    return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSignRecoverRaw(NSSLOWKEYPublicKey *key,
+                        unsigned char *     data,
+                        unsigned int *      data_len, 
+			unsigned int        max_output_len, 
+			unsigned char *     sign,
+			unsigned int        sign_len)
+{
+    SECStatus      rv;
+    unsigned int   modulus_len = nsslowkey_PublicModulusLen(key);
+
+    if (sign_len != modulus_len) 
+    	goto failure;
+    if (max_output_len < modulus_len) 
+    	goto failure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+
+    rv = RSA_PublicKeyOp(&key->u.rsa, data, sign);
+    if (rv != SECSuccess)
+	goto failure;
+
+    *data_len = modulus_len;
+    return SECSuccess;
+
+failure:
+    return SECFailure;
+}
+
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_EncryptRaw(NSSLOWKEYPublicKey *key, 
+	       unsigned char *     output, 
+	       unsigned int *      output_len,
+               unsigned int        max_output_len, 
+	       unsigned char *     input, 
+	       unsigned int        input_len)
+{
+    SECStatus rv;
+    unsigned int  modulus_len = nsslowkey_PublicModulusLen(key);
+    SECItem       formatted;
+    SECItem       unformatted;
+
+    formatted.data = NULL;
+    if (max_output_len < modulus_len) 
+    	goto failure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+
+    unformatted.len  = input_len;
+    unformatted.data = input;
+    formatted.data   = NULL;
+    rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockRaw, &unformatted);
+    if (rv != SECSuccess)
+	goto failure;
+
+    rv = RSA_PublicKeyOp(&key->u.rsa, output, formatted.data);
+    if (rv != SECSuccess) 
+    	goto failure;
+
+    PORT_ZFree(formatted.data, modulus_len);
+    *output_len = modulus_len;
+    return SECSuccess;
+
+failure:
+    if (formatted.data != NULL) 
+	PORT_ZFree(formatted.data, modulus_len);
+    return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_DecryptRaw(NSSLOWKEYPrivateKey *key, 
+               unsigned char *      output, 
+	       unsigned int *       output_len,
+               unsigned int         max_output_len, 
+	       unsigned char *      input, 
+	       unsigned int         input_len)
+{
+    SECStatus     rv;
+    unsigned int  modulus_len = nsslowkey_PrivateModulusLen(key);
+
+    if (modulus_len <= 0) 
+    	goto failure;
+    if (modulus_len > max_output_len) 
+    	goto failure;
+    PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
+    if (key->keyType != NSSLOWKEYRSAKey)
+    	goto failure;
+    if (input_len != modulus_len) 
+    	goto failure;
+
+    rv = RSA_PrivateKeyOp(&key->u.rsa, output, input);
+    if (rv != SECSuccess) {
+	if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+	    sftk_fatalError = PR_TRUE;
+	}
+    	goto failure;
+    }
+
+    *output_len = modulus_len;
+    return SECSuccess;
+
+failure:
+    return SECFailure;
+}
diff --git a/mozilla/security/nss/lib/softoken/sdb.c b/mozilla/security/nss/lib/softoken/sdb.c
new file mode 100644
index 0000000..f9d8513
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sdb.c
@@ -0,0 +1,2063 @@
+/* ***** 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 Red Hat, Inc.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert Relyea (rrelyea@redhat.com)
+ *
+ * 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 ***** */
+/*
+ * This file implements PKCS 11 on top of our existing security modules
+ *
+ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
+ *   This implementation has two slots:
+ *	slot 1 is our generic crypto support. It does not require login.
+ *   It supports Public Key ops, and all they bulk ciphers and hashes. 
+ *   It can also support Private Key ops for imported Private keys. It does 
+ *   not have any token storage.
+ *	slot 2 is our private key support. It requires a login before use. It
+ *   can store Private Keys and Certs as token objects. Currently only private
+ *   keys and their associated Certificates are saved on the token.
+ *
+ *   In this implementation, session objects are only visible to the session
+ *   that created or generated them.
+ */
+
+#include "sdb.h"
+#include "pkcs11t.h"
+#include "seccomon.h"
+#include <sqlite3.h>
+#include "prthread.h"
+#include "prio.h"
+#include "stdio.h"
+#include "secport.h"
+#include "prmon.h"
+#include "prenv.h"
+#include "prsystem.h" /* for PR_GetDirectorySeparator() */
+#include "sys/stat.h"
+#if defined (_WIN32)
+#include <io.h>
+#endif
+
+#ifdef SQLITE_UNSAFE_THREADS
+#include "prlock.h"
+/*
+ * SQLite can be compiled to be thread safe or not.
+ * turn on SQLITE_UNSAFE_THREADS if the OS does not support
+ * a thread safe version of sqlite.
+ */
+static PRLock *sqlite_lock = NULL;
+
+#define LOCK_SQLITE()  PR_Lock(sqlite_lock);
+#define UNLOCK_SQLITE()  PR_Unlock(sqlite_lock);
+#else
+#define LOCK_SQLITE()  
+#define UNLOCK_SQLITE()  
+#endif
+
+typedef enum {
+	SDB_CERT = 1,
+	SDB_KEY = 2
+} sdbDataType;
+
+/*
+ * defines controlling how long we wait to acquire locks.
+ *
+ * SDB_SQLITE_BUSY_TIMEOUT specifies how long (in milliseconds)
+ *  sqlite will wait on lock. If that timeout expires, sqlite will
+ *  return SQLITE_BUSY.
+ * SDB_BUSY_RETRY_TIME specifies how many seconds the sdb_ code waits
+ *  after receiving a busy before retrying.
+ * SDB_MAX_BUSY_RETRIES specifies how many times the sdb_ will retry on
+ *  a busy condition.
+ *
+ * SDB_SQLITE_BUSY_TIMEOUT affects all opertions, both manual 
+ *   (prepare/step/reset/finalize) and automatic (sqlite3_exec()).
+ * SDB_BUSY_RETRY_TIME and SDB_MAX_BUSY_RETRIES only affect manual operations
+ * 
+ * total wait time for automatic operations: 
+ *   1 second (SDB_SQLITE_BUSY_TIMEOUT/1000).
+ * total wait time for manual operations: 
+ *   (1 second + 5 seconds) * 10 = 60 seconds.
+ * (SDB_SQLITE_BUSY_TIMEOUT/1000 + SDB_BUSY_RETRY_TIME)*SDB_MAX_BUSY_RETRIES
+ */
+#define SDB_SQLITE_BUSY_TIMEOUT 1000 /* milliseconds */
+#define SDB_BUSY_RETRY_TIME        5 /* seconds */
+#define SDB_MAX_BUSY_RETRIES      10
+
+/*
+ * Note on use of sqlReadDB: Only one thread at a time may have an actual
+ * operation going on given sqlite3 * database. An operation is defined as
+ * the time from a sqlite3_prepare() until the sqlite3_finalize().
+ * Multiple sqlite3 * databases can be open and have simultaneous operations
+ * going. We use the sqlXactDB for all write operations. This database
+ * is only opened when we first create a transaction and closed when the
+ * transaction is complete. sqlReadDB is open when we first opened the database
+ * and is used for all read operation. It's use is protected by a monitor. This
+ * is because an operation can span the use of FindObjectsInit() through the
+ * call to FindObjectsFinal(). In the intermediate time it is possible to call
+ * other operations like NSC_GetAttributeValue */
+
+struct SDBPrivateStr {
+    char *sqlDBName;		/* invariant, path to this database */
+    sqlite3 *sqlXactDB;		/* access protected by dbMon, use protected
+                                 * by the transaction. Current transaction db*/
+    PRThread *sqlXactThread;	/* protected by dbMon,
+			         * current transaction thread */
+    sqlite3 *sqlReadDB;		/* use protected by dbMon, value invariant */
+    PRIntervalTime lastUpdateTime;  /* last time the cache was updated */
+    PRIntervalTime updateInterval;  /* how long the cache can go before it 
+                                     * must be updated again */
+    sdbDataType type;		/* invariant, database type */
+    char *table;	        /* invariant, SQL table which contains the db */
+    char *cacheTable;	        /* invariant, SQL table cache of db */
+    PRMonitor *dbMon;		/* invariant, monitor to protect 
+				 * sqlXact* fields, and use of the sqlReadDB */
+};
+
+typedef struct SDBPrivateStr SDBPrivate;
+
+/*
+ * known attributes
+ */
+static const CK_ATTRIBUTE_TYPE known_attributes[] = {
+    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
+    CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
+    CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED,
+    CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL,
+    CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY,
+    CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE,
+    CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER,
+    CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE,
+    CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
+    CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT,
+    CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, 
+    CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE,
+    CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
+    CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
+    CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+    CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE,
+    CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT,
+    CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS,
+    CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
+    CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
+    CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
+    CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL,
+    CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP,
+    CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES,
+    CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED,
+    CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC,
+    CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
+    CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
+    CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
+    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING,
+    CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM,
+    CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
+    CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
+    CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS
+};
+
+static int known_attributes_size= sizeof(known_attributes)/
+			   sizeof(known_attributes[0]);
+
+/* Magic for an explicit NULL. NOTE: ideally this should be
+ * out of band data. Since it's not completely out of band, pick
+ * a value that has no meaning to any existing PKCS #11 attributes.
+ * This value is 1) not a valid string (imbedded '\0'). 2) not a U_LONG
+ * or a normal key (too short). 3) not a bool (too long). 4) not an RSA
+ * public exponent (too many bits).
+ */
+const unsigned char SQLITE_EXPLICIT_NULL[] = { 0xa5, 0x0, 0x5a };
+#define SQLITE_EXPLICIT_NULL_LEN 3
+
+/*
+ * determine when we've completed our tasks
+ */
+static int 
+sdb_done(int err, int *count)
+{
+    /* allow as many rows as the database wants to give */
+    if (err == SQLITE_ROW) {
+	*count = 0;
+	return 0;
+    }
+    if (err != SQLITE_BUSY) {
+	return 1;
+    }
+    /* err == SQLITE_BUSY, Dont' retry forever in this case */
+    if (++(*count) >= SDB_MAX_BUSY_RETRIES) {
+	return 1;
+    }
+    return 0;
+}
+
+/*
+ * 
+ * strdup limited to 'n' bytes. (Note: len of file is assumed to be >= len)
+ *
+ * We don't have a PORT_ version of this function,
+ * I suspect it's only normally available in glib,
+ */
+static char *
+sdb_strndup(const char *file, int len)
+{
+   char *result = PORT_Alloc(len+1);
+
+   if (result == NULL) {
+	return result;
+   }
+
+   PORT_Memcpy(result, file, len);
+   result[len] = 0;
+   return result;
+}
+
+/*
+ * call back from  sqlite3_exec("Pragma database_list"). Looks for the
+ * temp directory, then return the file the temp directory is stored
+ * at. */
+static int 
+sdb_getTempDirCallback(void *arg, int columnCount, char **cval, char **cname)
+{
+    int i;
+    int found = 0;
+    char *file = NULL;
+    char *end, *dir;
+    char dirsep;
+
+    /* we've already found the temp directory, don't look at any more records*/
+    if (*(char **)arg) {
+	return SQLITE_OK;
+    }
+
+    /* look at the columns to see if this record is the temp database,
+     * and does it say where it is stored */
+    for (i=0; i < columnCount; i++) {
+	if (PORT_Strcmp(cname[i],"name") == 0) {
+	    if (PORT_Strcmp(cval[i], "temp") == 0) {
+		found++;
+		continue;
+	    }
+	}
+	if (PORT_Strcmp(cname[i],"file") == 0) {
+	    if (cval[i] && (*cval[i] != 0)) {
+		file = cval[i];
+	    }
+	}
+    }
+
+    /* if we couldn't find it, ask for the next record */
+    if (!found || !file) {
+	return SQLITE_OK;
+    }
+
+    /* drop of the database file name and just return the directory */
+    dirsep = PR_GetDirectorySeparator();
+    end = PORT_Strrchr(file, dirsep);
+    if (!end) {
+	return SQLITE_OK;
+    }
+    dir = sdb_strndup(file, end-file);
+
+    *(char **)arg = dir;
+    return SQLITE_OK;
+}
+
+/*
+ * find out where sqlite stores the temp tables. We do this by creating
+ * a temp table, then looking for the database name that sqlite3 creates.
+ */
+static char *
+sdb_getTempDir(sqlite3 *sqlDB)
+{
+    char *tempDir = NULL;
+    int sqlerr;
+
+    /* create a temporary table */
+    sqlerr = sqlite3_exec(sqlDB, "CREATE TEMPORARY TABLE myTemp (id)",
+			  NULL, 0, NULL);
+    if (sqlerr != SQLITE_OK) {
+	return NULL;
+    }
+    /* look for through the database list for the temp directory */
+    sqlerr = sqlite3_exec(sqlDB, "PRAGMA database_list", 
+		sdb_getTempDirCallback, &tempDir, NULL);
+
+    /* drop the temp table we created */
+    sqlite3_exec(sqlDB, "DROP TABLE myTemp", NULL, 0, NULL);
+
+    if (sqlerr != SQLITE_OK) {
+	return NULL;
+    }
+    return tempDir;
+}
+
+
+/*
+ * Map SQL_LITE errors to PKCS #11 errors as best we can.
+ */
+static CK_RV
+sdb_mapSQLError(sdbDataType type, int sqlerr)
+{
+    switch (sqlerr) {
+    /* good matches */
+    case SQLITE_OK:
+    case SQLITE_DONE:
+	return CKR_OK;
+    case SQLITE_NOMEM:
+	return CKR_HOST_MEMORY;
+    case SQLITE_READONLY:
+	return CKR_TOKEN_WRITE_PROTECTED;
+    /* close matches */
+    case SQLITE_AUTH:
+    case SQLITE_PERM:
+	/*return CKR_USER_NOT_LOGGED_IN; */
+    case SQLITE_CANTOPEN:
+    case SQLITE_NOTFOUND:
+	/* NSS distiguishes between failure to open the cert and the key db */
+	return type == SDB_CERT ? 
+		CKR_NETSCAPE_CERTDB_FAILED : CKR_NETSCAPE_KEYDB_FAILED;
+    case SQLITE_IOERR:
+	return CKR_DEVICE_ERROR;
+    default:
+	break;
+    }
+    return CKR_GENERAL_ERROR;
+}
+
+
+/*
+ * build up database name from a directory, prefix, name, version and flags.
+ */
+static char *sdb_BuildFileName(const char * directory, 
+			const char *prefix, const char *type, 
+			int version, int flags)
+{
+    char *dbname = NULL;
+    /* build the full dbname */
+    dbname = sqlite3_mprintf("%s/%s%s%d.db",directory, prefix, type, version);
+    return dbname;
+}
+
+
+/*
+ * find out how expensive the access system call is for non-existant files
+ * in the given directory.  Return the number of operations done in 33 ms.
+ */
+static PRUint32
+sdb_measureAccess(const char *directory)
+{
+    PRUint32 i;
+    PRIntervalTime time;
+    PRIntervalTime delta;
+    PRIntervalTime duration = PR_MillisecondsToInterval(33);
+
+    /* no directory, just return one */
+    if (directory == NULL) {
+	return 1;
+    }
+
+    /* measure number of Access operations that can be done in 33 milliseconds
+     * (1/30'th of a second), or 10000 operations, which ever comes first.
+     */
+    time =  PR_IntervalNow();
+    for (i=0; i < 10000u; i++) { 
+	char *temp;
+	PRIntervalTime next;
+
+        temp  = sdb_BuildFileName(directory,"","._dOeSnotExist_", time+i, 0);
+	PR_Access(temp,PR_ACCESS_EXISTS);
+        sqlite3_free(temp);
+	next = PR_IntervalNow();
+	delta = next - time;
+	if (delta >= duration)
+	    break;
+    }
+
+    /* always return 1 or greater */
+    return i ? i : 1u;
+}
+
+/*
+ * some file sytems are very slow to run sqlite3 on, particularly if the
+ * access count is pretty high. On these filesystems is faster to create
+ * a temporary database on the local filesystem and access that. This
+ * code uses a temporary table to create that cache. Temp tables are
+ * automatically cleared when the database handle it was created on
+ * Is freed.
+ */
+static const char DROP_CACHE_CMD[] = "DROP TABLE %s";
+static const char CREATE_CACHE_CMD[] =
+  "CREATE TEMPORARY TABLE %s AS SELECT * FROM %s";
+static const char CREATE_ISSUER_INDEX_CMD[] = 
+  "CREATE INDEX issuer ON %s (a81)";
+static const char CREATE_SUBJECT_INDEX_CMD[] = 
+  "CREATE INDEX subject ON %s (a101)";
+static const char CREATE_LABEL_INDEX_CMD[] = "CREATE INDEX label ON %s (a3)";
+static const char CREATE_ID_INDEX_CMD[] = "CREATE INDEX ckaid ON %s (a102)";
+
+static CK_RV
+sdb_buildCache(sqlite3 *sqlDB, sdbDataType type, 
+		const char *cacheTable, const char *table)
+{
+    char *newStr;
+    int sqlerr = SQLITE_OK;
+
+    newStr = sqlite3_mprintf(CREATE_CACHE_CMD, cacheTable, table);
+    if (newStr == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+    sqlite3_free(newStr);
+    if (sqlerr != SQLITE_OK) {
+	return sdb_mapSQLError(type, sqlerr); 
+    }
+    /* failure to create the indexes is not an issue */
+    newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, cacheTable);
+    if (newStr == NULL) {
+	return CKR_OK;
+    }
+    sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+    sqlite3_free(newStr);
+    newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, cacheTable);
+    if (newStr == NULL) {
+	return CKR_OK;
+    }
+    sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+    sqlite3_free(newStr);
+    newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, cacheTable);
+    if (newStr == NULL) {
+	return CKR_OK;
+    }
+    sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+    sqlite3_free(newStr);
+    newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, cacheTable);
+    if (newStr == NULL) {
+	return CKR_OK;
+    }
+    sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+    sqlite3_free(newStr);
+    return CKR_OK;
+}
+
+/*
+ * update the cache and the data records describing it.
+ *  The cache is updated by dropping the temp database and recreating it.
+ */
+static CK_RV
+sdb_updateCache(SDBPrivate *sdb_p)
+{
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    char *newStr;
+
+    /* drop the old table */
+    newStr = sqlite3_mprintf(DROP_CACHE_CMD, sdb_p->cacheTable);
+    if (newStr == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    sqlerr = sqlite3_exec(sdb_p->sqlReadDB, newStr, NULL, 0, NULL);
+    sqlite3_free(newStr);
+    if ((sqlerr != SQLITE_OK) && (sqlerr != SQLITE_ERROR )) {
+        /* something went wrong with the drop, don't try to refresh...
+         * NOTE: SQLITE_ERROR is returned if the table doesn't exist. In
+         * that case, we just continue on and try to reload it */
+	return sdb_mapSQLError(sdb_p->type, sqlerr); 
+    }
+	
+
+    /* set up the new table */
+    error = sdb_buildCache(sdb_p->sqlReadDB,sdb_p->type,
+				sdb_p->cacheTable,sdb_p->table );
+    if (error == CKR_OK) {
+	/* we have a new cache! */
+	sdb_p->lastUpdateTime = PR_IntervalNow();
+    }
+    return error;
+}
+
+/*
+ *  The sharing of sqlite3 handles across threads is tricky. Older versions
+ *  couldn't at all, but newer ones can under strict conditions. Basically
+ *  no 2 threads can use the same handle while another thread has an open
+ *  stmt running. Once the sqlite3_stmt is finalized, another thread can then
+ *  use the database handle.
+ *
+ *  We use monitors to protect against trying to use a database before
+ *  it's sqlite3_stmt is finalized. This is preferable to the opening and
+ *  closing the database each operation because there is significant overhead
+ *  in the open and close. Also continually opening and closing the database
+ *  defeats the cache code as the cache table is lost on close (thus
+ *  requiring us to have to reinitialize the cache every operation).
+ * 
+ *  An execption to the shared handle is transations. All writes happen
+ *  through a transaction. When we are in  a transaction, we must use the 
+ *  same database pointer for that entire transation. In this case we save 
+ *  the transaction database and use it for all accesses on the transaction 
+ *  thread. Other threads use the common database.  
+ *
+ *  There can only be once active transaction on the database at a time.
+ *
+ *  sdb_openDBLocal() provides us with a valid database handle for whatever
+ *  state we are in (reading or in a transaction), and acquires any locks
+ *  appropriate to that state. It also decides when it's time to refresh
+ *  the cache before we start an operation. Any database handle returned
+ *  just eventually be closed with sdb_closeDBLocal().
+ *
+ *  The table returned either points to the database's physical table, or
+ *  to the cached shadow. Tranactions always return the physical table
+ *  and read operations return either the physical table or the cache
+ *  depending on whether or not the cache exists.
+ */
+static CK_RV 
+sdb_openDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB, const char **table)
+{
+    *sqlDB = NULL;
+
+    PR_EnterMonitor(sdb_p->dbMon);
+
+    if (table) {
+	*table = sdb_p->table;
+    }
+
+    /* We're in a transaction, use the transaction DB */
+    if ((sdb_p->sqlXactDB) && (sdb_p->sqlXactThread == PR_GetCurrentThread())) {
+	*sqlDB =sdb_p->sqlXactDB;
+	/* only one thread can get here, safe to unlock */
+        PR_ExitMonitor(sdb_p->dbMon);
+	return CKR_OK;
+    }
+
+    /*
+     * if we are just reading from the table, we may have the table
+     * cached in a temporary table (especially if it's on a shared FS).
+     * In that case we want to see updates to the table, the the granularity
+     * is on order of human scale, not computer scale.
+     */
+    if (table && sdb_p->cacheTable) {
+	PRIntervalTime now = PR_IntervalNow();
+	if ((now - sdb_p->lastUpdateTime) > sdb_p->updateInterval) {
+	       sdb_updateCache(sdb_p);
+        }
+	*table = sdb_p->cacheTable;
+    }
+
+    *sqlDB = sdb_p->sqlReadDB;
+
+    /* leave holding the lock. only one thread can actually use a given
+     * database connection at once */
+	
+    return CKR_OK;
+}
+
+/* closing the local database currenly means unlocking the monitor */
+static CK_RV 
+sdb_closeDBLocal(SDBPrivate *sdb_p, sqlite3 *sqlDB) 
+{
+   if (sdb_p->sqlXactDB != sqlDB) {
+	/* if we weren't in a transaction, we got a lock */
+        PR_ExitMonitor(sdb_p->dbMon);
+   }
+   return CKR_OK;
+}
+
+
+/*
+ * wrapper to sqlite3_open which also sets the busy_timeout
+ */
+static int
+sdb_openDB(const char *name, sqlite3 **sqlDB, int flags)
+{
+    int sqlerr;
+    /*
+     * in sqlite3 3.5.0, there is a new open call that allows us
+     * to specify read only. Most new OS's are still on 3.3.x (including
+     * NSS's internal version and the version shipped with Firefox).
+     */
+    *sqlDB = NULL;
+    sqlerr = sqlite3_open(name, sqlDB);
+    if (sqlerr != SQLITE_OK) {
+	return sqlerr;
+    }
+
+    sqlerr = sqlite3_busy_timeout(*sqlDB, SDB_SQLITE_BUSY_TIMEOUT);
+    if (sqlerr != SQLITE_OK) {
+	sqlite3_close(*sqlDB);
+	*sqlDB = NULL;
+	return sqlerr;
+    }
+    return SQLITE_OK;
+}
+
+/* Sigh, if we created a new table since we opened the database,
+ * the database handle will not see the new table, we need to close this
+ * database and reopen it. Caller must be in a transaction or holding
+ * the dbMon. sqlDB is changed on success. */
+static int 
+sdb_reopenDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB) {
+    sqlite3 *newDB;
+    int sqlerr;
+
+    /* open a new database */
+    sqlerr = sdb_openDB(sdb_p->sqlDBName, &newDB, SDB_RDONLY);
+    if (sqlerr != SQLITE_OK) {
+	return sqlerr;
+    }
+
+    /* if we are in a transaction, we may not be holding the monitor.
+     * grab it before we update the transaction database. This is
+     * safe since are using monitors. */
+    PR_EnterMonitor(sdb_p->dbMon);
+    /* update our view of the database */
+    if (sdb_p->sqlReadDB == *sqlDB) {
+	sdb_p->sqlReadDB = newDB;
+    } else if (sdb_p->sqlXactDB == *sqlDB) {
+	sdb_p->sqlXactDB = newDB;
+    }
+    PR_ExitMonitor(sdb_p->dbMon);
+
+    /* close the old one */
+    sqlite3_close(*sqlDB);
+
+    *sqlDB = newDB;
+    return SQLITE_OK;
+}
+
+struct SDBFindStr {
+    sqlite3 *sqlDB;
+    sqlite3_stmt *findstmt;
+};
+
+
+static const char FIND_OBJECTS_CMD[] =  "SELECT ALL * FROM %s WHERE %s;";
+static const char FIND_OBJECTS_ALL_CMD[] = "SELECT ALL * FROM %s;";
+CK_RV
+sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count, 
+				SDBFind **find)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    const char *table;
+    char *newStr, *findStr = NULL;
+    sqlite3_stmt *findstmt = NULL;
+    char *join="";
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    int i;
+
+    LOCK_SQLITE()
+    *find = NULL;
+    error = sdb_openDBLocal(sdb_p, &sqlDB, &table);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+
+    findStr = sqlite3_mprintf("");
+    for (i=0; findStr && i < count; i++) {
+	newStr = sqlite3_mprintf("%s%sa%x=$DATA%d", findStr, join,
+				template[i].type, i);
+        join=" AND ";
+	sqlite3_free(findStr);
+	findStr = newStr;
+    }
+
+    if (findStr == NULL) {
+	error = CKR_HOST_MEMORY;
+	goto loser;
+    }
+
+    if (count == 0) {
+	newStr = sqlite3_mprintf(FIND_OBJECTS_ALL_CMD, table);
+    } else {
+	newStr = sqlite3_mprintf(FIND_OBJECTS_CMD, table, findStr);
+    }
+    sqlite3_free(findStr);
+    if (newStr == NULL) {
+	error = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &findstmt, NULL);
+    sqlite3_free(newStr);
+    for (i=0; sqlerr == SQLITE_OK && i < count; i++) {
+	const void *blobData = template[i].pValue;
+	unsigned int blobSize = template[i].ulValueLen;
+	if (blobSize == 0) {
+	    blobSize = SQLITE_EXPLICIT_NULL_LEN;
+	    blobData = SQLITE_EXPLICIT_NULL;
+	}
+	sqlerr = sqlite3_bind_blob(findstmt, i+1, blobData, blobSize,
+				   SQLITE_TRANSIENT);
+    }
+    if (sqlerr == SQLITE_OK) {
+	*find = PORT_New(SDBFind);
+	if (*find == NULL) {
+	    error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	(*find)->findstmt = findstmt;
+	(*find)->sqlDB = sqlDB;
+	UNLOCK_SQLITE()  
+	return CKR_OK;
+    } 
+    error = sdb_mapSQLError(sdb_p->type, sqlerr);
+
+loser: 
+    if (findstmt) {
+	sqlite3_reset(findstmt);
+	sqlite3_finalize(findstmt);
+    }
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+    UNLOCK_SQLITE()  
+    return error;
+}
+
+
+CK_RV
+sdb_FindObjects(SDB *sdb, SDBFind *sdbFind, CK_OBJECT_HANDLE *object, 
+		CK_ULONG arraySize, CK_ULONG *count)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3_stmt *stmt = sdbFind->findstmt;
+    int sqlerr = SQLITE_OK;
+    int retry = 0;
+
+    *count = 0;
+
+    if (arraySize == 0) {
+	return CKR_OK;
+    }
+    LOCK_SQLITE()  
+
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+	if (sqlerr == SQLITE_ROW) {
+	    /* only care about the id */
+	    *object++= sqlite3_column_int(stmt, 0);
+	    arraySize--;
+	    (*count)++;
+	}
+    } while (!sdb_done(sqlerr,&retry) && (arraySize > 0));
+
+    /* we only have some of the objects, there is probably more,
+     * set the sqlerr to an OK value so we return CKR_OK */
+    if (sqlerr == SQLITE_ROW && arraySize == 0) {
+	sqlerr = SQLITE_DONE;
+    }
+    UNLOCK_SQLITE()  
+
+    return sdb_mapSQLError(sdb_p->type, sqlerr);
+}
+
+CK_RV
+sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3_stmt *stmt = sdbFind->findstmt;
+    sqlite3 *sqlDB = sdbFind->sqlDB;
+    int sqlerr = SQLITE_OK;
+
+    LOCK_SQLITE()  
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlerr = sqlite3_finalize(stmt);
+    }
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+    PORT_Free(sdbFind);
+
+    UNLOCK_SQLITE()  
+    return sdb_mapSQLError(sdb_p->type, sqlerr);
+}
+
+static const char GET_ATTRIBUTE_CMD[] = "SELECT ALL %s FROM %s WHERE id=$ID;";
+CK_RV
+sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id, 
+				CK_ATTRIBUTE *template, CK_ULONG count)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    sqlite3_stmt *stmt = NULL;
+    char *getStr = NULL;
+    char *newStr = NULL;
+    const char *table = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    int found = 0;
+    int retry = 0;
+    int i;
+
+
+    /* open a new db if necessary */
+    error = sdb_openDBLocal(sdb_p, &sqlDB, &table);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+
+    getStr = sqlite3_mprintf("");
+    for (i=0; getStr && i < count; i++) {
+	if (i==0) {
+	    newStr = sqlite3_mprintf("a%x", template[i].type);
+	} else {
+	    newStr = sqlite3_mprintf("%s, a%x", getStr, template[i].type);
+	}
+	sqlite3_free(getStr);
+	getStr = newStr;
+    }
+
+    if (getStr == NULL) {
+	error = CKR_HOST_MEMORY;
+	goto loser;
+    }
+
+    newStr = sqlite3_mprintf(GET_ATTRIBUTE_CMD, getStr, table);
+    sqlite3_free(getStr);
+    getStr = NULL;
+    if (newStr == NULL) {
+	error = CKR_HOST_MEMORY;
+	goto loser;
+    }
+
+    sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL);
+    if (sqlerr != SQLITE_OK) { goto loser; }
+    sqlerr = sqlite3_bind_int(stmt, 1, object_id);
+    if (sqlerr != SQLITE_OK) { goto loser; }
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+	if (sqlerr == SQLITE_ROW) {
+	    for (i=0; i < count; i++) {
+		int column = i;
+	    	int blobSize;
+	    	const char *blobData;
+
+	    	blobSize = sqlite3_column_bytes(stmt, column);
+		blobData = sqlite3_column_blob(stmt, column);
+		if (blobData == NULL) {
+		    template[i].ulValueLen = -1;
+		    error = CKR_ATTRIBUTE_TYPE_INVALID; 
+		    continue;
+		}
+		/* If the blob equals our explicit NULL value, then the 
+		 * attribute is a NULL. */
+		if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) &&
+		   	(PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL, 
+			      SQLITE_EXPLICIT_NULL_LEN) == 0)) {
+		    blobSize = 0;
+		}
+		if (template[i].pValue) {
+		    if (template[i].ulValueLen < blobSize) {
+			template[i].ulValueLen = -1;
+		    	error = CKR_BUFFER_TOO_SMALL;
+			continue;
+		    }
+	    	    PORT_Memcpy(template[i].pValue, blobData, blobSize);
+		}
+		template[i].ulValueLen = blobSize;
+	    }
+	    found = 1;
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+loser:
+    /* fix up the error if necessary */
+    if (error == CKR_OK) {
+	error = sdb_mapSQLError(sdb_p->type, sqlerr);
+	if (!found && error == CKR_OK) {
+	    error = CKR_OBJECT_HANDLE_INVALID;
+	}
+    }
+    if (newStr) {
+	sqlite3_free(newStr);
+    }
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+    /* if we had to open a new database, free it now */
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+    return error;
+}
+
+CK_RV
+sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, 
+				CK_ATTRIBUTE *template, CK_ULONG count)
+{
+    CK_RV crv;
+
+    if (count == 0) {
+	return CKR_OK;
+    }
+
+    LOCK_SQLITE()  
+    crv = sdb_GetAttributeValueNoLock(sdb, object_id, template, count);
+    UNLOCK_SQLITE()  
+    return crv;
+}
+   
+static const char SET_ATTRIBUTE_CMD[] = "UPDATE %s SET %s WHERE id=$ID;";
+CK_RV
+sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, 
+			const CK_ATTRIBUTE *template, CK_ULONG count)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    sqlite3_stmt *stmt = NULL;
+    char *setStr = NULL;
+    char *newStr = NULL;
+    int sqlerr = SQLITE_OK;
+    int retry = 0;
+    CK_RV error = CKR_OK;
+    int i;
+
+    if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    if (count == 0) {
+	return CKR_OK;
+    }
+
+    LOCK_SQLITE()  
+    setStr = sqlite3_mprintf("");
+    for (i=0; setStr && i < count; i++) {
+	if (i==0) {
+	    sqlite3_free(setStr);
+   	    setStr = sqlite3_mprintf("a%x=$VALUE%d", 
+				template[i].type, i);
+	    continue;
+	}
+	newStr = sqlite3_mprintf("%s,a%x=$VALUE%d", setStr, 
+				template[i].type, i);
+	sqlite3_free(setStr);
+	setStr = newStr;
+    }
+    newStr = NULL;
+
+    if (setStr == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    newStr =  sqlite3_mprintf(SET_ATTRIBUTE_CMD, sdb_p->table, setStr);
+    sqlite3_free(setStr);
+    if (newStr == NULL) {
+	UNLOCK_SQLITE()  
+	return CKR_HOST_MEMORY;
+    }
+    error = sdb_openDBLocal(sdb_p, &sqlDB, NULL);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+    sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL);
+    if (sqlerr != SQLITE_OK) goto loser;
+    for (i=0; i < count; i++) {
+	if (template[i].ulValueLen != 0) {
+	    sqlerr = sqlite3_bind_blob(stmt, i+1, template[i].pValue, 
+				template[i].ulValueLen, SQLITE_STATIC);
+	} else {
+	    sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, 
+			SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC);
+	}
+        if (sqlerr != SQLITE_OK) goto loser;
+    }
+    sqlerr = sqlite3_bind_int(stmt, i+1, object_id);
+    if (sqlerr != SQLITE_OK) goto loser;
+
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+loser:
+    if (newStr) {
+	sqlite3_free(newStr);
+    }
+    if (error == CKR_OK) {
+	error = sdb_mapSQLError(sdb_p->type, sqlerr);
+    }
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+
+    UNLOCK_SQLITE()  
+    return error;
+}
+
+/*
+ * check to see if a candidate object handle already exists.
+ */
+static PRBool
+sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate)
+{
+    CK_RV crv;
+    CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 };
+
+    crv = sdb_GetAttributeValueNoLock(sdb,candidate,&template, 1);
+    if (crv == CKR_OBJECT_HANDLE_INVALID) {
+	return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+/*
+ * if we're here, we are in a transaction, so it's safe
+ * to examine the current state of the database
+ */
+static CK_OBJECT_HANDLE
+sdb_getObjectId(SDB *sdb)
+{
+    CK_OBJECT_HANDLE candidate;
+    static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE;
+    int count;
+    /*
+     * get an initial object handle to use
+     */
+    if (next_obj == CK_INVALID_HANDLE) {
+        PRTime time;
+	time = PR_Now();
+
+	next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL);
+    }
+    candidate = next_obj++;
+    /* detect that we've looped through all the handles... */
+    for (count = 0; count < 0x40000000; count++, candidate = next_obj++) {
+	/* mask off excess bits */
+	candidate &= 0x3fffffff;
+	/* if we hit zero, go to the next entry */
+	if (candidate == CK_INVALID_HANDLE) {
+	    continue;
+	}
+	/* make sure we aren't already using */
+	if (!sdb_objectExists(sdb, candidate)) {
+	    /* this one is free */
+	    return candidate;
+	}
+    }
+
+    /* no handle is free, fail */
+    return CK_INVALID_HANDLE;
+}
+
+static const char CREATE_CMD[] = "INSERT INTO %s (id%s) VALUES($ID%s);";
+CK_RV
+sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, 
+		 const CK_ATTRIBUTE *template, CK_ULONG count)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    sqlite3_stmt *stmt = NULL;
+    char *columnStr = NULL;
+    char *valueStr = NULL;
+    char *newStr = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    CK_OBJECT_HANDLE this_object = CK_INVALID_HANDLE;
+    int retry = 0;
+    int i;
+
+    if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    LOCK_SQLITE()  
+    if ((*object_id != CK_INVALID_HANDLE) && 
+		!sdb_objectExists(sdb, *object_id)) {
+	this_object = *object_id;
+    } else {
+	this_object = sdb_getObjectId(sdb);
+    }
+    if (this_object == CK_INVALID_HANDLE) {
+	UNLOCK_SQLITE();
+	return CKR_HOST_MEMORY;
+    }
+    columnStr = sqlite3_mprintf("");
+    valueStr = sqlite3_mprintf("");
+    *object_id = this_object;
+    for (i=0; columnStr && valueStr && i < count; i++) {
+   	newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type);
+	sqlite3_free(columnStr);
+	columnStr = newStr;
+   	newStr = sqlite3_mprintf("%s,$VALUE%d", valueStr, i);
+	sqlite3_free(valueStr);
+	valueStr = newStr;
+    }
+    newStr = NULL;
+    if ((columnStr == NULL) || (valueStr == NULL)) {
+	if (columnStr) {
+	    sqlite3_free(columnStr);
+	}
+	if (valueStr) {
+	    sqlite3_free(valueStr);
+	}
+	UNLOCK_SQLITE()  
+	return CKR_HOST_MEMORY;
+    }
+    newStr =  sqlite3_mprintf(CREATE_CMD, sdb_p->table, columnStr, valueStr);
+    sqlite3_free(columnStr);
+    sqlite3_free(valueStr);
+    error = sdb_openDBLocal(sdb_p, &sqlDB, NULL);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+    sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL);
+    if (sqlerr != SQLITE_OK) goto loser;
+    sqlerr = sqlite3_bind_int(stmt, 1, *object_id);
+    if (sqlerr != SQLITE_OK) goto loser;
+    for (i=0; i < count; i++) {
+	if (template[i].ulValueLen) {
+	    sqlerr = sqlite3_bind_blob(stmt, i+2, template[i].pValue, 
+			template[i].ulValueLen, SQLITE_STATIC);
+	} else {
+	    sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, 
+			SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC);
+	}
+        if (sqlerr != SQLITE_OK) goto loser;
+    }
+
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+loser:
+    if (newStr) {
+	sqlite3_free(newStr);
+    }
+    if (error == CKR_OK) {
+	error = sdb_mapSQLError(sdb_p->type, sqlerr);
+    }
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+    UNLOCK_SQLITE()  
+
+    return error;
+}
+
+static const char DESTROY_CMD[] = "DELETE FROM %s WHERE (id=$ID);";
+CK_RV
+sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    sqlite3_stmt *stmt = NULL;
+    char *newStr = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    int retry = 0;
+
+    if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    LOCK_SQLITE()  
+    error = sdb_openDBLocal(sdb_p, &sqlDB, NULL);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+    newStr =  sqlite3_mprintf(DESTROY_CMD, sdb_p->table);
+    if (newStr == NULL) {
+	error = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    sqlerr =sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL);
+    sqlite3_free(newStr);
+    if (sqlerr != SQLITE_OK) goto loser;
+    sqlerr =sqlite3_bind_int(stmt, 1, object_id);
+    if (sqlerr != SQLITE_OK) goto loser;
+
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+loser:
+    if (error == CKR_OK) {
+	error = sdb_mapSQLError(sdb_p->type, sqlerr);
+    }
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+
+    UNLOCK_SQLITE()  
+    return error;
+}
+   
+static const char BEGIN_CMD[] = "BEGIN IMMEDIATE TRANSACTION;";
+/*
+ * start a transaction.
+ *
+ * We need to open a new database, then store that new database into
+ * the private data structure. We open the database first, then use locks
+ * to protect storing the data to prevent deadlocks.
+ */
+CK_RV
+sdb_Begin(SDB *sdb)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    sqlite3_stmt *stmt = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    int retry = 0;
+
+
+    if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+
+    LOCK_SQLITE()  
+
+    /* get a new version that we will use for the entire transaction */
+    sqlerr = sdb_openDB(sdb_p->sqlDBName, &sqlDB, SDB_RDWR);
+    if (sqlerr != SQLITE_OK) {
+	goto loser;
+    }
+
+    sqlerr =sqlite3_prepare_v2(sqlDB, BEGIN_CMD, -1, &stmt, NULL);
+
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+loser:
+    error = sdb_mapSQLError(sdb_p->type, sqlerr);
+
+    /* we are starting a new transaction, 
+     * and if we succeeded, then save this database for the rest of
+     * our transaction */
+    if (error == CKR_OK) {
+	/* we hold a 'BEGIN TRANSACTION' and a sdb_p->lock. At this point
+	 * sdb_p->sqlXactDB MUST be null */
+	PR_EnterMonitor(sdb_p->dbMon);
+	PORT_Assert(sdb_p->sqlXactDB == NULL);
+	sdb_p->sqlXactDB = sqlDB;
+	sdb_p->sqlXactThread = PR_GetCurrentThread();
+        PR_ExitMonitor(sdb_p->dbMon);
+    } else {
+	/* we failed to start our transaction,
+	 * free any databases we opened. */
+	if (sqlDB) {
+	    sqlite3_close(sqlDB);
+	}
+    }
+
+    UNLOCK_SQLITE()  
+    return error;
+}
+
+/*
+ * Complete a transaction. Basically undo everything we did in begin.
+ * There are 2 flavors Abort and Commit. Basically the only differerence between
+ * these 2 are what the database will show. (no change in to former, change in
+ * the latter).
+ */
+static CK_RV 
+sdb_complete(SDB *sdb, const char *cmd)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    sqlite3_stmt *stmt = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    int retry = 0;
+
+
+    if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    /* We must have a transation database, or we shouldn't have arrived here */
+    PR_EnterMonitor(sdb_p->dbMon);
+    PORT_Assert(sdb_p->sqlXactDB);
+    if (sdb_p->sqlXactDB == NULL) {
+        PR_ExitMonitor(sdb_p->dbMon);
+	return CKR_GENERAL_ERROR; /* shouldn't happen */
+    }
+    PORT_Assert( sdb_p->sqlXactThread == PR_GetCurrentThread());
+    if ( sdb_p->sqlXactThread != PR_GetCurrentThread()) {
+        PR_ExitMonitor(sdb_p->dbMon);
+	return CKR_GENERAL_ERROR; /* shouldn't happen */
+    }
+    sqlDB = sdb_p->sqlXactDB;
+    sdb_p->sqlXactDB = NULL; /* no one else can get to this DB, 
+			      * safe to unlock */
+    sdb_p->sqlXactThread = NULL; 
+    PR_ExitMonitor(sdb_p->dbMon);
+
+    sqlerr =sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL);
+
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+    /* Pending BEGIN TRANSACTIONS Can move forward at this point. */
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+    /* we we have a cached DB image, update it as well */
+    if (sdb_p->cacheTable) {
+	PR_EnterMonitor(sdb_p->dbMon);
+	sdb_updateCache(sdb_p);
+	PR_ExitMonitor(sdb_p->dbMon);
+    }
+
+    error = sdb_mapSQLError(sdb_p->type, sqlerr);
+
+    /* We just finished a transaction.
+     * Free the database, and remove it from the list */
+    sqlite3_close(sqlDB);
+
+    return error;
+}
+
+static const char COMMIT_CMD[] = "COMMIT TRANSACTION;";
+CK_RV
+sdb_Commit(SDB *sdb)
+{
+    CK_RV crv;
+    LOCK_SQLITE()  
+    crv = sdb_complete(sdb,COMMIT_CMD);
+    UNLOCK_SQLITE()  
+    return crv;
+}
+
+static const char ROLLBACK_CMD[] = "ROLLBACK TRANSACTION;";
+CK_RV
+sdb_Abort(SDB *sdb)
+{
+    CK_RV crv;
+    LOCK_SQLITE()  
+    crv = sdb_complete(sdb,ROLLBACK_CMD);
+    UNLOCK_SQLITE()  
+    return crv;
+}
+
+static int tableExists(sqlite3 *sqlDB, const char *tableName);
+
+static const char GET_PW_CMD[] = "SELECT ALL * FROM metaData WHERE id=$ID;";
+CK_RV
+sdb_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = sdb_p->sqlXactDB;
+    sqlite3_stmt *stmt = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    int found = 0;
+    int retry = 0;
+
+    LOCK_SQLITE()  
+    error = sdb_openDBLocal(sdb_p, &sqlDB, NULL);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+
+    /* handle 'test' versions of the sqlite db */
+    sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL);
+    /* Sigh, if we created a new table since we opened the database,
+     * the database handle will not see the new table, we need to close this
+     * database and reopen it. This is safe because we are holding the lock
+     * still. */
+    if (sqlerr == SQLITE_SCHEMA) {
+	sqlerr = sdb_reopenDBLocal(sdb_p, &sqlDB);
+	if (sqlerr != SQLITE_OK) {
+	    goto loser;
+	}
+	sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL);
+    }
+    if (sqlerr != SQLITE_OK) goto loser;
+    sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC);
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+	if (sqlerr == SQLITE_ROW) {
+	    const char *blobData;
+	    unsigned int len = item1->len;
+	    item1->len = sqlite3_column_bytes(stmt, 1);
+	    if (item1->len > len) {
+		error = CKR_BUFFER_TOO_SMALL;
+		continue;
+	    }
+	    blobData = sqlite3_column_blob(stmt, 1);
+	    PORT_Memcpy(item1->data,blobData, item1->len);
+	    if (item2) {
+		len = item2->len;
+		item2->len = sqlite3_column_bytes(stmt, 2);
+		if (item2->len > len) {
+		    error = CKR_BUFFER_TOO_SMALL;
+		    continue;
+		}
+		blobData = sqlite3_column_blob(stmt, 2);
+		PORT_Memcpy(item2->data,blobData, item2->len);
+	    }
+	    found = 1;
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+loser:
+    /* fix up the error if necessary */
+    if (error == CKR_OK) {
+	error = sdb_mapSQLError(sdb_p->type, sqlerr);
+	if (!found && error == CKR_OK) {
+	    error = CKR_OBJECT_HANDLE_INVALID;
+	}
+    }
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+    UNLOCK_SQLITE()  
+
+    return error;
+}
+
+static const char PW_CREATE_TABLE_CMD[] =
+ "CREATE TABLE metaData (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, item1, item2);";
+static const char PW_CREATE_CMD[] =
+ "INSERT INTO metaData (id,item1,item2) VALUES($ID,$ITEM1,$ITEM2);";
+static const char MD_CREATE_CMD[]  =
+ "INSERT INTO metaData (id,item1) VALUES($ID,$ITEM1);";
+CK_RV
+sdb_PutMetaData(SDB *sdb, const char *id, const SECItem *item1, 
+					   const SECItem *item2)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = sdb_p->sqlXactDB;
+    sqlite3_stmt *stmt = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    int retry = 0;
+    const char *cmd = PW_CREATE_CMD;
+
+    if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    LOCK_SQLITE()  
+    error = sdb_openDBLocal(sdb_p, &sqlDB, NULL);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+
+    if (!tableExists(sqlDB, "metaData")) {
+    	sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL);
+        if (sqlerr != SQLITE_OK) goto loser;
+    }
+    if (item2 == NULL) {
+	cmd = MD_CREATE_CMD;
+    }
+    sqlerr = sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL);
+    if (sqlerr != SQLITE_OK) goto loser;
+    sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC);
+    if (sqlerr != SQLITE_OK) goto loser;
+    sqlerr = sqlite3_bind_blob(stmt, 2, item1->data, item1->len, SQLITE_STATIC);
+    if (sqlerr != SQLITE_OK) goto loser;
+    if (item2) {
+    	sqlerr = sqlite3_bind_blob(stmt, 3, item2->data, 
+				   item2->len, SQLITE_STATIC);
+        if (sqlerr != SQLITE_OK) goto loser;
+    }
+
+    do {
+	sqlerr = sqlite3_step(stmt);
+	if (sqlerr == SQLITE_BUSY) {
+	    PR_Sleep(SDB_BUSY_RETRY_TIME);
+	}
+    } while (!sdb_done(sqlerr,&retry));
+
+loser:
+    /* fix up the error if necessary */
+    if (error == CKR_OK) {
+	error = sdb_mapSQLError(sdb_p->type, sqlerr);
+    }
+
+    if (stmt) {
+	sqlite3_reset(stmt);
+	sqlite3_finalize(stmt);
+    }
+
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+    UNLOCK_SQLITE()  
+
+    return error;
+}
+
+static const char RESET_CMD[] = "DROP TABLE IF EXISTS %s;";
+CK_RV
+sdb_Reset(SDB *sdb)
+{
+    SDBPrivate *sdb_p = sdb->private;
+    sqlite3  *sqlDB = NULL;
+    char *newStr;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+
+    /* only Key databases can be reset */
+    if (sdb_p->type != SDB_KEY) {
+	return CKR_OBJECT_HANDLE_INVALID;
+    }
+
+    LOCK_SQLITE()  
+    error = sdb_openDBLocal(sdb_p, &sqlDB, NULL);
+    if (error != CKR_OK) {
+	goto loser;
+    }
+
+    /* delete the key table */
+    newStr =  sqlite3_mprintf(RESET_CMD, sdb_p->table);
+    if (newStr == NULL) {
+	error = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+    sqlite3_free(newStr);
+
+    if (sqlerr != SQLITE_OK) goto loser;
+
+    /* delete the password entry table */
+    sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;", 
+                          NULL, 0, NULL);
+
+loser:
+    /* fix up the error if necessary */
+    if (error == CKR_OK) {
+	error = sdb_mapSQLError(sdb_p->type, sqlerr);
+    }
+
+    if (sqlDB) {
+	sdb_closeDBLocal(sdb_p, sqlDB) ;
+    }
+
+    UNLOCK_SQLITE()  
+    return error;
+}
+
+
+CK_RV 
+sdb_Close(SDB *sdb) 
+{
+    SDBPrivate *sdb_p = sdb->private;
+    int sqlerr = SQLITE_OK;
+    sdbDataType type = sdb_p->type;
+
+    sqlerr = sqlite3_close(sdb_p->sqlReadDB);
+    PORT_Free(sdb_p->sqlDBName);
+    if (sdb_p->cacheTable) {
+	sqlite3_free(sdb_p->cacheTable);
+    }
+    if (sdb_p->dbMon) {
+	PR_DestroyMonitor(sdb_p->dbMon);
+    }
+    free(sdb_p);
+    free(sdb);
+    return sdb_mapSQLError(type, sqlerr);
+}
+
+
+/*
+ * functions to support open
+ */
+
+static const char CHECK_TABLE_CMD[] = "SELECT ALL * FROM %s LIMIT 0;";
+/* return 1 if sqlDB contains table 'tableName */
+static int tableExists(sqlite3 *sqlDB, const char *tableName)
+{
+    char * cmd = sqlite3_mprintf(CHECK_TABLE_CMD, tableName);
+    int sqlerr = SQLITE_OK;
+
+    if (cmd == NULL) {
+	return 0;
+    }
+
+    sqlerr = sqlite3_exec(sqlDB, cmd, NULL, 0, 0);
+    sqlite3_free(cmd);
+
+    return (sqlerr == SQLITE_OK) ? 1 : 0;
+}
+
+void sdb_SetForkState(PRBool forked)
+{
+    /* XXXright now this is a no-op. The global fork state in the softokn3
+     * shared library is already taken care of at the PKCS#11 level.
+     * If and when we add fork state to the sqlite shared library and extern
+     * interface, we will need to set it and reset it from here */
+}
+
+/*
+ * initialize a single database
+ */
+static const char INIT_CMD[] =
+ "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)";
+static const char ALTER_CMD[] = 
+ "ALTER TABLE %s ADD COLUMN a%x";
+
+CK_RV 
+sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
+	 int *newInit, int flags, PRUint32 accessOps, SDB **pSdb)
+{
+    int i;
+    char *initStr = NULL;
+    char *newStr;
+    int inTransaction = 0;
+    SDB *sdb = NULL;
+    SDBPrivate *sdb_p = NULL;
+    sqlite3 *sqlDB = NULL;
+    int sqlerr = SQLITE_OK;
+    CK_RV error = CKR_OK;
+    char *cacheTable = NULL;
+    PRIntervalTime now = 0;
+    char *env;
+    PRBool enableCache = PR_FALSE;
+    PRBool create;
+
+    *pSdb = NULL;
+    *inUpdate = 0;
+
+    /* sqlite3 doesn't have a flag to specify that we want to 
+     * open the database read only. If the db doesn't exist,
+     * sqlite3 will always create it.
+     */
+    LOCK_SQLITE();
+    create = (PR_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS);
+    if ((flags == SDB_RDONLY) && create) {
+	error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
+	goto loser;
+    }
+    sqlerr = sdb_openDB(dbname, &sqlDB, flags);
+    if (sqlerr != SQLITE_OK) {
+	error = sdb_mapSQLError(type, sqlerr); 
+	goto loser;
+    }
+    /* sql created the file, but it doesn't set appropriate modes for
+     * a database */
+    if (create) {
+	/* NO NSPR call for this? :( */
+#ifndef WINCE
+	chmod (dbname, 0600);
+#endif
+    }
+
+    if (flags != SDB_RDONLY) {
+	sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL);
+	if (sqlerr != SQLITE_OK) {
+	    error = sdb_mapSQLError(type, sqlerr);
+	    goto loser;
+	}
+	inTransaction = 1;
+    }
+    if (!tableExists(sqlDB,table)) {
+	*newInit = 1;
+	if (flags != SDB_CREATE) {
+	    error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
+	    goto loser;
+	}
+	initStr = sqlite3_mprintf("");
+	for (i=0; initStr && i < known_attributes_size; i++) {
+	    newStr = sqlite3_mprintf("%s, a%x",initStr, known_attributes[i]);
+	    sqlite3_free(initStr);
+	    initStr = newStr;
+	}
+	if (initStr == NULL) {
+	    error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+
+	newStr = sqlite3_mprintf(INIT_CMD, table, initStr);
+	sqlite3_free(initStr);
+	if (newStr == NULL) {
+            error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+	sqlite3_free(newStr);
+	if (sqlerr != SQLITE_OK) {
+            error = sdb_mapSQLError(type, sqlerr); 
+	    goto loser;
+	}
+
+	newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, table);
+	if (newStr == NULL) {
+            error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+	sqlite3_free(newStr);
+	if (sqlerr != SQLITE_OK) {
+            error = sdb_mapSQLError(type, sqlerr); 
+	    goto loser;
+	}
+
+	newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, table);
+	if (newStr == NULL) {
+            error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+	sqlite3_free(newStr);
+	if (sqlerr != SQLITE_OK) {
+            error = sdb_mapSQLError(type, sqlerr); 
+	    goto loser;
+	}
+
+	newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, table);
+	if (newStr == NULL) {
+            error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+	sqlite3_free(newStr);
+	if (sqlerr != SQLITE_OK) {
+            error = sdb_mapSQLError(type, sqlerr); 
+	    goto loser;
+	}
+
+	newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, table);
+	if (newStr == NULL) {
+            error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+	sqlite3_free(newStr);
+	if (sqlerr != SQLITE_OK) {
+            error = sdb_mapSQLError(type, sqlerr); 
+	    goto loser;
+	}
+    }
+    /*
+     * detect the case where we have created the database, but have
+     * not yet updated it.
+     *
+     * We only check the Key database because only the key database has
+     * a metaData table. The metaData table is created when a password
+     * is set, or in the case of update, when a password is supplied.
+     * If no key database exists, then the update would have happened immediately
+     * on noticing that the cert database didn't exist (see newInit set above).
+     */
+    if (type == SDB_KEY && !tableExists(sqlDB, "metaData")) {
+	*newInit = 1;
+    }
+    
+    /* access to network filesystems are significantly slower than local ones
+     * for database operations. In those cases we need to create a cached copy
+     * of the database in a temporary location on the local disk. SQLITE
+     * already provides a way to create a temporary table and initialize it,
+     * so we use it for the cache (see sdb_buildCache for how it's done).*/
+
+     /* 
+      * we decide whether or not to use the cache based on the following input.
+      *
+      * NSS_SDB_USE_CACHE environment variable is non-existant or set to 
+      *   anything other than "no" or "yes" ("auto", for instance).
+      *   This is the normal case. NSS will measure the performance of access
+      *   to the temp database versus the access to the users passed in 
+      *   database location. If the temp database location is "significantly"
+      *   faster we will use the cache.
+      *
+      * NSS_SDB_USE_CACHE environment variable is set to "no": cache will not
+      *   be used.
+      *
+      * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will
+      *   always be used.
+      *
+      * It is expected that most applications would use the "auto" selection,
+      * the environment variable is primarily to simplify testing, and to 
+      * correct potential corner cases where  */
+
+     env = PR_GetEnv("NSS_SDB_USE_CACHE");
+
+     if (env && PORT_Strcasecmp(env,"no") == 0) {
+	enableCache = PR_FALSE;
+     } else if (env && PORT_Strcasecmp(env,"yes") == 0) {
+	enableCache = PR_TRUE;
+     } else {
+	char *tempDir = NULL;
+	PRUint32 tempOps = 0;
+	/*
+	 *  Use PR_Access to determine how expensive it
+	 * is to check for the existance of a local file compared to the same
+	 * check in the temp directory. If the temp directory is faster, cache
+	 * the database there. */
+	tempDir = sdb_getTempDir(sqlDB);
+	if (tempDir) {
+	    tempOps = sdb_measureAccess(tempDir);
+	    PORT_Free(tempDir);
+
+	    /* There is a cost to continually copying the database. 
+	     * Account for that cost  with the arbitrary factor of 10 */
+	    enableCache = (PRBool)(tempOps > accessOps * 10);
+	}
+    }
+
+    if (enableCache) {
+	/* try to set the temp store to memory.*/
+	sqlite3_exec(sqlDB, "PRAGMA temp_store=MEMORY", NULL, 0, NULL);
+	/* Failure to set the temp store to memory is not fatal,
+         * ignore the error */
+
+	cacheTable = sqlite3_mprintf("%sCache",table);
+	if (cacheTable == NULL) {
+	    error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+	/* build the cache table */
+	error = sdb_buildCache(sqlDB, type, cacheTable, table);
+	if (error != CKR_OK) {
+	    goto loser;
+	}
+	/* initialize the last cache build time */
+	now = PR_IntervalNow();
+    }
+
+    sdb = (SDB *) malloc(sizeof(SDB));
+    sdb_p = (SDBPrivate *) malloc(sizeof(SDBPrivate));
+
+    /* invariant fields */
+    sdb_p->sqlDBName = PORT_Strdup(dbname);
+    sdb_p->type = type;
+    sdb_p->table = table;
+    sdb_p->cacheTable = cacheTable;
+    sdb_p->lastUpdateTime = now;
+    /* set the cache delay time. This is how long we will wait before we
+     * decide the existing cache is stale. Currently set to 10 sec */
+    sdb_p->updateInterval = PR_SecondsToInterval(10); 
+    sdb_p->dbMon = PR_NewMonitor();
+    /* these fields are protected by the lock */
+    sdb_p->sqlXactDB = NULL;
+    sdb_p->sqlXactThread = NULL;
+    sdb->private = sdb_p;
+    sdb->sdb_type = SDB_SQL;
+    sdb->sdb_flags = flags | SDB_HAS_META;
+    sdb->sdb_FindObjectsInit = sdb_FindObjectsInit;
+    sdb->sdb_FindObjects = sdb_FindObjects;
+    sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal;
+    sdb->sdb_GetAttributeValue = sdb_GetAttributeValue;
+    sdb->sdb_SetAttributeValue = sdb_SetAttributeValue;
+    sdb->sdb_CreateObject = sdb_CreateObject;
+    sdb->sdb_DestroyObject = sdb_DestroyObject;
+    sdb->sdb_GetMetaData = sdb_GetMetaData;
+    sdb->sdb_PutMetaData = sdb_PutMetaData;
+    sdb->sdb_Begin = sdb_Begin;
+    sdb->sdb_Commit = sdb_Commit;
+    sdb->sdb_Abort = sdb_Abort;
+    sdb->sdb_Close = sdb_Close;
+    sdb->sdb_SetForkState = sdb_SetForkState;
+
+    if (inTransaction) {
+	sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL);
+	if (sqlerr != SQLITE_OK) {
+	    error = sdb_mapSQLError(sdb_p->type, sqlerr);
+	    goto loser;
+	}
+	inTransaction = 0;
+    }
+
+    sdb_p->sqlReadDB = sqlDB;
+
+    *pSdb = sdb;
+    UNLOCK_SQLITE();
+    return CKR_OK;
+
+loser:
+    /* lots of stuff to do */
+    if (inTransaction) {
+	sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL);
+    }
+    if (sdb) {
+	free(sdb);
+    }
+    if (sdb_p) {
+	free(sdb_p);
+    }
+    if (sqlDB) {
+	sqlite3_close(sqlDB);
+    }
+    UNLOCK_SQLITE();
+    return error;
+
+}
+
+
+/* sdbopen */
+CK_RV
+s_open(const char *directory, const char *certPrefix, const char *keyPrefix,
+	int cert_version, int key_version, int flags, 
+	SDB **certdb, SDB **keydb, int *newInit)
+{
+    char *cert = sdb_BuildFileName(directory, certPrefix,
+				   "cert", cert_version, flags);
+    char *key = sdb_BuildFileName(directory, keyPrefix,
+				   "key", key_version, flags);
+    CK_RV error = CKR_OK;
+    int inUpdate;
+    PRUint32 accessOps;
+
+    if (certdb) 
+	*certdb = NULL;
+    if (keydb) 
+	*keydb = NULL;
+    *newInit = 0;
+
+#ifdef SQLITE_UNSAFE_THREADS
+    if (sqlite_lock == NULL) {
+	sqlite_lock = PR_NewLock();
+	if (sqlite_lock == NULL) {
+	    error = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+    }
+#endif
+
+    /* how long does it take to test for a non-existant file in our working
+     * directory? Allows us to test if we may be on a network file system */
+    accessOps = sdb_measureAccess(directory);
+
+    /*
+     * open the cert data base
+     */
+    if (certdb) {
+	/* initialize Certificate database */
+	error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate,
+			 newInit, flags, accessOps, certdb);
+	if (error != CKR_OK) {
+	    goto loser;
+	}
+    }
+
+    /*
+     * open the key data base: 
+     *  NOTE:if we want to implement a single database, we open
+     *  the same database file as the certificate here.
+     *
+     *  cert an key db's have different tables, so they will not
+     *  conflict.
+     */
+    if (keydb) {
+	/* initialize the Key database */
+	error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, 
+			newInit, flags, accessOps, keydb);
+	if (error != CKR_OK) {
+	    goto loser;
+	} 
+    }
+
+
+loser:
+    if (cert) {
+	sqlite3_free(cert);
+    }
+    if (key) {
+	sqlite3_free(key);
+    }
+
+    if (error != CKR_OK) {
+	/* currently redundant, but could be necessary if more code is added
+	 * just before loser */
+	if (keydb && *keydb) {
+	    sdb_Close(*keydb);
+	}
+	if (certdb && *certdb) {
+	    sdb_Close(*certdb);
+	}
+    }
+
+    return error;
+}
+
+CK_RV
+s_shutdown()
+{
+#ifdef SQLITE_UNSAFE_THREADS
+    if (sqlite_lock) {
+	PR_DestroyLock(sqlite_lock);
+	sqlite_lock = NULL;
+    }
+#endif
+    return CKR_OK;
+}
diff --git a/mozilla/security/nss/lib/softoken/sdb.h b/mozilla/security/nss/lib/softoken/sdb.h
new file mode 100644
index 0000000..e4ded72
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sdb.h
@@ -0,0 +1,112 @@
+/* ***** 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 Red Hat, Inc.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert Relyea (rrelyea@redhat.com)
+ *
+ * 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 ***** */
+/*
+ * This file implements PKCS 11 on top of our existing security modules
+ *
+ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
+ *   This implementation has two slots:
+ *	slot 1 is our generic crypto support. It does not require login.
+ *   It supports Public Key ops, and all they bulk ciphers and hashes. 
+ *   It can also support Private Key ops for imported Private keys. It does 
+ *   not have any token storage.
+ *	slot 2 is our private key support. It requires a login before use. It
+ *   can store Private Keys and Certs as token objects. Currently only private
+ *   keys and their associated Certificates are saved on the token.
+ *
+ *   In this implementation, session objects are only visible to the session
+ *   that created or generated them.
+ */
+
+/*
+ * the following data structures should be moved to a 'rdb.h'.
+ */
+
+#ifndef _SDB_H
+#define _SDB_H 1
+#include "pkcs11t.h"
+#include "secitem.h"
+#include "sftkdbt.h"
+#include <sqlite3.h>
+
+#define STATIC_CMD_SIZE 2048
+
+typedef struct SDBFindStr SDBFind;
+typedef struct SDBStr SDB;
+
+struct SDBStr {
+    void *private;
+    int  version;
+    SDBType sdb_type;
+    int  sdb_flags;
+    void *app_private;
+    CK_RV (*sdb_FindObjectsInit)(SDB *sdb, const CK_ATTRIBUTE *template, 
+				 CK_ULONG count, SDBFind **find);
+    CK_RV (*sdb_FindObjects)(SDB *sdb, SDBFind *find, CK_OBJECT_HANDLE *ids, 
+				CK_ULONG arraySize, CK_ULONG *count);
+    CK_RV (*sdb_FindObjectsFinal)(SDB *sdb, SDBFind *find);
+    CK_RV (*sdb_GetAttributeValue)(SDB *sdb, CK_OBJECT_HANDLE object, 
+				CK_ATTRIBUTE *template, CK_ULONG count);
+    CK_RV (*sdb_SetAttributeValue)(SDB *sdb, CK_OBJECT_HANDLE object, 
+				const CK_ATTRIBUTE *template, CK_ULONG count);
+    CK_RV (*sdb_CreateObject)(SDB *sdb, CK_OBJECT_HANDLE *object, 
+				const CK_ATTRIBUTE *template, CK_ULONG count);
+    CK_RV (*sdb_DestroyObject)(SDB *sdb, CK_OBJECT_HANDLE object);
+    CK_RV (*sdb_GetMetaData)(SDB *sdb, const char *id, 
+				SECItem *item1, SECItem *item2);
+    CK_RV (*sdb_PutMetaData)(SDB *sdb, const char *id,
+				const SECItem *item1, const SECItem *item2);
+    CK_RV (*sdb_Begin)(SDB *sdb);
+    CK_RV (*sdb_Commit)(SDB *sdb);
+    CK_RV (*sdb_Abort)(SDB *sdb);
+    CK_RV (*sdb_Reset)(SDB *sdb);
+    CK_RV (*sdb_Close)(SDB *sdb);
+    void (*sdb_SetForkState)(PRBool forked);
+};
+
+CK_RV s_open(const char *directory, const char *certPrefix, 
+	     const char *keyPrefix,
+	     int cert_version, int key_version, 
+	     int flags, SDB **certdb, SDB **keydb, int *newInit);
+CK_RV s_shutdown();
+
+/* flags */
+#define SDB_RDONLY      1
+#define SDB_RDWR        2
+#define SDB_CREATE      4
+#define SDB_HAS_META    8
+
+#endif
diff --git a/mozilla/security/nss/lib/softoken/secmodt.h b/mozilla/security/nss/lib/softoken/secmodt.h
new file mode 100644
index 0000000..59fdca0
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/secmodt.h
@@ -0,0 +1,503 @@
+/* ***** 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 ***** */
+#ifndef _SECMODT_H_
+#define _SECMODT_H_ 1
+
+#include "nssrwlkt.h"
+#include "nssilckt.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "pkcs11t.h"
+
+/* find a better home for these... */
+extern const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[];
+extern SEC_ASN1TemplateChooser NSS_Get_SECKEY_PointerToEncryptedPrivateKeyInfoTemplate;
+extern const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[];
+extern SEC_ASN1TemplateChooser NSS_Get_SECKEY_EncryptedPrivateKeyInfoTemplate;
+extern const SEC_ASN1Template SECKEY_PrivateKeyInfoTemplate[];
+extern SEC_ASN1TemplateChooser NSS_Get_SECKEY_PrivateKeyInfoTemplate;
+extern const SEC_ASN1Template SECKEY_PointerToPrivateKeyInfoTemplate[];
+extern SEC_ASN1TemplateChooser NSS_Get_SECKEY_PointerToPrivateKeyInfoTemplate;
+
+/* PKCS11 needs to be included */
+typedef struct SECMODModuleStr SECMODModule;
+typedef struct SECMODModuleListStr SECMODModuleList;
+typedef NSSRWLock SECMODListLock;
+typedef struct PK11SlotInfoStr PK11SlotInfo; /* defined in secmodti.h */
+typedef struct PK11PreSlotInfoStr PK11PreSlotInfo; /* defined in secmodti.h */
+typedef struct PK11SymKeyStr PK11SymKey; /* defined in secmodti.h */
+typedef struct PK11ContextStr PK11Context; /* defined in secmodti.h */
+typedef struct PK11SlotListStr PK11SlotList;
+typedef struct PK11SlotListElementStr PK11SlotListElement;
+typedef struct PK11RSAGenParamsStr PK11RSAGenParams;
+typedef unsigned long SECMODModuleID;
+typedef struct PK11DefaultArrayEntryStr PK11DefaultArrayEntry;
+typedef struct PK11GenericObjectStr PK11GenericObject;
+typedef void (*PK11FreeDataFunc)(void *);
+
+struct SECMODModuleStr {
+    PLArenaPool	*arena;
+    PRBool	internal;	/* true of internally linked modules, false
+				 * for the loaded modules */
+    PRBool	loaded;		/* Set to true if module has been loaded */
+    PRBool	isFIPS;		/* Set to true if module is finst internal */
+    char	*dllName;	/* name of the shared library which implements
+				 * this module */
+    char	*commonName;	/* name of the module to display to the user */
+    void	*library;	/* pointer to the library. opaque. used only by
+				 * pk11load.c */
+    void	*functionList; /* The PKCS #11 function table */
+    PZLock	*refLock;	/* only used pk11db.c */
+    int		refCount;	/* Module reference count */
+    PK11SlotInfo **slots;	/* array of slot points attached to this mod*/
+    int		slotCount;	/* count of slot in above array */
+    PK11PreSlotInfo *slotInfo;	/* special info about slots default settings */
+    int		slotInfoCount;  /* count */
+    SECMODModuleID moduleID;	/* ID so we can find this module again */
+    PRBool	isThreadSafe;
+    unsigned long ssl[2];	/* SSL cipher enable flags */
+    char	*libraryParams;  /* Module specific parameters */
+    void *moduleDBFunc; /* function to return module configuration data*/
+    SECMODModule *parent;	/* module that loaded us */
+    PRBool	isCritical;	/* This module must load successfully */
+    PRBool	isModuleDB;	/* this module has lists of PKCS #11 modules */
+    PRBool	moduleDBOnly;	/* this module only has lists of PKCS #11 modules */
+    int		trustOrder;	/* order for this module's certificate trust rollup */
+    int		cipherOrder;	/* order for cipher operations */
+    unsigned long evControlMask; /* control the running and shutdown of slot
+				  * events (SECMOD_WaitForAnyTokenEvent) */
+    CK_VERSION  cryptokiVersion; /* version of this library */
+};
+
+/* evControlMask flags */
+/*
+ * These bits tell the current state of a SECMOD_WaitForAnyTokenEvent.
+ *
+ * SECMOD_WAIT_PKCS11_EVENT - we're waiting in the PKCS #11 module in
+ *  C_WaitForSlotEvent().
+ * SECMOD_WAIT_SIMULATED_EVENT - we're waiting in the NSS simulation code
+ *  which polls for token insertion and removal events.
+ * SECMOD_END_WAIT - SECMOD_CancelWait has been called while the module is
+ *  waiting in SECMOD_WaitForAnyTokenEvent. SECMOD_WaitForAnyTokenEvent
+ *  should return immediately to it's caller.
+ */ 
+#define SECMOD_END_WAIT 	    0x01
+#define SECMOD_WAIT_SIMULATED_EVENT 0x02 
+#define SECMOD_WAIT_PKCS11_EVENT    0x04
+
+struct SECMODModuleListStr {
+    SECMODModuleList	*next;
+    SECMODModule	*module;
+};
+
+struct PK11SlotListStr {
+    PK11SlotListElement *head;
+    PK11SlotListElement *tail;
+    PZLock *lock;
+};
+
+struct PK11SlotListElementStr {
+    PK11SlotListElement *next;
+    PK11SlotListElement *prev;
+    PK11SlotInfo *slot;
+    int refCount;
+};
+
+struct PK11RSAGenParamsStr {
+    int keySizeInBits;
+    unsigned long pe;
+};
+
+typedef enum {
+     PK11CertListUnique = 0,     /* get one instance of all certs */
+     PK11CertListUser = 1,       /* get all instances of user certs */
+     PK11CertListRootUnique = 2, /* get one instance of CA certs without a private key.
+                                  * deprecated. Use PK11CertListCAUnique
+                                  */
+     PK11CertListCA = 3,         /* get all instances of CA certs */
+     PK11CertListCAUnique = 4,   /* get one instance of CA certs */
+     PK11CertListUserUnique = 5, /* get one instance of user certs */
+     PK11CertListAll = 6         /* get all instances of all certs */
+} PK11CertListType;
+
+/*
+ * Entry into the Array which lists all the legal bits for the default flags
+ * in the slot, their definition, and the PKCS #11 mechanism the represent
+ * Always Statically allocated. 
+ */
+struct PK11DefaultArrayEntryStr {
+    char *name;
+    unsigned long flag;
+    unsigned long mechanism; /* this is a long so we don't include the 
+			      * whole pkcs 11 world to use this header */
+};
+
+
+#define SECMOD_RSA_FLAG 	0x00000001L
+#define SECMOD_DSA_FLAG 	0x00000002L
+#define SECMOD_RC2_FLAG 	0x00000004L
+#define SECMOD_RC4_FLAG 	0x00000008L
+#define SECMOD_DES_FLAG 	0x00000010L
+#define SECMOD_DH_FLAG	 	0x00000020L
+#define SECMOD_FORTEZZA_FLAG	0x00000040L
+#define SECMOD_RC5_FLAG		0x00000080L
+#define SECMOD_SHA1_FLAG	0x00000100L
+#define SECMOD_MD5_FLAG		0x00000200L
+#define SECMOD_MD2_FLAG		0x00000400L
+#define SECMOD_SSL_FLAG		0x00000800L
+#define SECMOD_TLS_FLAG		0x00001000L
+#define SECMOD_AES_FLAG 	0x00002000L
+#define SECMOD_SHA256_FLAG	0x00004000L
+#define SECMOD_SHA512_FLAG	0x00008000L	/* also for SHA384 */
+#define SECMOD_CAMELLIA_FLAG 	0x00010000L /* = PUBLIC_MECH_CAMELLIA_FLAG */
+#define SECMOD_SEED_FLAG	0x00020000L
+/* reserved bit for future, do not use */
+#define SECMOD_RESERVED_FLAG    0X08000000L
+#define SECMOD_FRIENDLY_FLAG	0x10000000L
+#define SECMOD_RANDOM_FLAG	0x80000000L
+
+/* need to make SECMOD and PK11 prefixes consistant. */
+#define PK11_OWN_PW_DEFAULTS 0x20000000L
+#define PK11_DISABLE_FLAG    0x40000000L
+
+/*
+ * PK11AttrFlags
+ *
+ * A 32-bit bitmask of PK11_ATTR_XXX flags
+ */
+typedef PRUint32 PK11AttrFlags;
+
+/*
+ * PK11_ATTR_XXX
+ *
+ * The following PK11_ATTR_XXX bitflags are used to specify
+ * PKCS #11 object attributes that have Boolean values.  Some NSS
+ * functions have a "PK11AttrFlags attrFlags" parameter whose value
+ * is the logical OR of these bitflags.  NSS use these bitflags on
+ * private keys or secret keys.  Some of these bitflags also apply
+ * to the public keys associated with the private keys.
+ *
+ * For each PKCS #11 object attribute, we need two bitflags to
+ * specify not only "true" and "false" but also "default".  For
+ * example, PK11_ATTR_PRIVATE and PK11_ATTR_PUBLIC control the
+ * CKA_PRIVATE attribute.  If PK11_ATTR_PRIVATE is set, we add
+ *     { CKA_PRIVATE, &cktrue, sizeof(CK_BBOOL) }
+ * to the template.  If PK11_ATTR_PUBLIC is set, we add
+ *     { CKA_PRIVATE, &ckfalse, sizeof(CK_BBOOL) }
+ * to the template.  If neither flag is set, we don't add any
+ * CKA_PRIVATE entry to the template.
+ */
+
+/*
+ * Attributes for PKCS #11 storage objects, which include not only
+ * keys but also certificates and domain parameters.
+ */
+
+/*
+ * PK11_ATTR_TOKEN
+ * PK11_ATTR_SESSION
+ *
+ * These two flags determine whether the object is a token or
+ * session object.
+ *
+ * These two flags are related and cannot both be set.
+ * If the PK11_ATTR_TOKEN flag is set, the object is a token
+ * object.  If the PK11_ATTR_SESSION flag is set, the object is
+ * a session object.  If neither flag is set, the object is *by
+ * default* a session object.
+ *
+ * These two flags specify the value of the PKCS #11 CKA_TOKEN
+ * attribute.
+ */
+#define PK11_ATTR_TOKEN         0x00000001L
+#define PK11_ATTR_SESSION       0x00000002L
+
+/*
+ * PK11_ATTR_PRIVATE
+ * PK11_ATTR_PUBLIC
+ *
+ * These two flags determine whether the object is a private or
+ * public object.  A user may not access a private object until the
+ * user has authenticated to the token.
+ *
+ * These two flags are related and cannot both be set.
+ * If the PK11_ATTR_PRIVATE flag is set, the object is a private
+ * object.  If the PK11_ATTR_PUBLIC flag is set, the object is a
+ * public object.  If neither flag is set, it is token-specific
+ * whether the object is private or public.
+ *
+ * These two flags specify the value of the PKCS #11 CKA_PRIVATE
+ * attribute.  NSS only uses this attribute on private and secret
+ * keys, so public keys created by NSS get the token-specific
+ * default value of the CKA_PRIVATE attribute.
+ */
+#define PK11_ATTR_PRIVATE       0x00000004L
+#define PK11_ATTR_PUBLIC        0x00000008L
+
+/*
+ * PK11_ATTR_MODIFIABLE
+ * PK11_ATTR_UNMODIFIABLE
+ *
+ * These two flags determine whether the object is modifiable or
+ * read-only.
+ *
+ * These two flags are related and cannot both be set.
+ * If the PK11_ATTR_MODIFIABLE flag is set, the object can be
+ * modified.  If the PK11_ATTR_UNMODIFIABLE flag is set, the object
+ * is read-only.  If neither flag is set, the object is *by default*
+ * modifiable.
+ *
+ * These two flags specify the value of the PKCS #11 CKA_MODIFIABLE
+ * attribute.
+ */
+#define PK11_ATTR_MODIFIABLE    0x00000010L
+#define PK11_ATTR_UNMODIFIABLE  0x00000020L
+
+/* Attributes for PKCS #11 key objects. */
+
+/*
+ * PK11_ATTR_SENSITIVE
+ * PK11_ATTR_INSENSITIVE
+ *
+ * These two flags are related and cannot both be set.
+ * If the PK11_ATTR_SENSITIVE flag is set, the key is sensitive.
+ * If the PK11_ATTR_INSENSITIVE flag is set, the key is not
+ * sensitive.  If neither flag is set, it is token-specific whether
+ * the key is sensitive or not.
+ *
+ * If a key is sensitive, certain attributes of the key cannot be
+ * revealed in plaintext outside the token.
+ *
+ * This flag specifies the value of the PKCS #11 CKA_SENSITIVE
+ * attribute.  Although the default value of the CKA_SENSITIVE
+ * attribute for secret keys is CK_FALSE per PKCS #11, some FIPS
+ * tokens set the default value to CK_TRUE because only CK_TRUE
+ * is allowed.  So in practice the default value of this attribute
+ * is token-specific, hence the need for two bitflags.
+ */
+#define PK11_ATTR_SENSITIVE     0x00000040L
+#define PK11_ATTR_INSENSITIVE   0x00000080L
+
+/*
+ * PK11_ATTR_EXTRACTABLE
+ * PK11_ATTR_UNEXTRACTABLE
+ *
+ * These two flags are related and cannot both be set.
+ * If the PK11_ATTR_EXTRACTABLE flag is set, the key is extractable
+ * and can be wrapped.  If the PK11_ATTR_UNEXTRACTABLE flag is set,
+ * the key is not extractable, and certain attributes of the key
+ * cannot be revealed in plaintext outside the token (just like a
+ * sensitive key).  If neither flag is set, it is token-specific
+ * whether the key is extractable or not.
+ *
+ * These two flags specify the value of the PKCS #11 CKA_EXTRACTABLE
+ * attribute.
+ */
+#define PK11_ATTR_EXTRACTABLE   0x00000100L
+#define PK11_ATTR_UNEXTRACTABLE 0x00000200L
+
+/* Cryptographic module types */
+#define SECMOD_EXTERNAL	0	/* external module */
+#define SECMOD_INTERNAL 1	/* internal default module */
+#define SECMOD_FIPS	2	/* internal fips module */
+
+/* default module configuration strings */
+#define SECMOD_SLOT_FLAGS "slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512]"
+
+#define SECMOD_MAKE_NSS_FLAGS(fips,slot) \
+"Flags=internal,critical"fips" slotparams=("#slot"={"SECMOD_SLOT_FLAGS"})"
+
+#define SECMOD_INT_NAME "NSS Internal PKCS #11 Module"
+#define SECMOD_INT_FLAGS SECMOD_MAKE_NSS_FLAGS("",1)
+#define SECMOD_FIPS_NAME "NSS Internal FIPS PKCS #11 Module"
+#define SECMOD_FIPS_FLAGS SECMOD_MAKE_NSS_FLAGS(",fips",3)
+
+/*
+ * What is the origin of a given Key. Normally this doesn't matter, but
+ * the fortezza code needs to know if it needs to invoke the SSL3 fortezza
+ * hack.
+ */
+typedef enum {
+    PK11_OriginNULL = 0,	/* There is not key, it's a null SymKey */
+    PK11_OriginDerive = 1,	/* Key was derived from some other key */
+    PK11_OriginGenerated = 2,	/* Key was generated (also PBE keys) */
+    PK11_OriginFortezzaHack = 3,/* Key was marked for fortezza hack */
+    PK11_OriginUnwrap = 4	/* Key was unwrapped or decrypted */
+} PK11Origin;
+
+/* PKCS #11 disable reasons */
+typedef enum {
+    PK11_DIS_NONE = 0,
+    PK11_DIS_USER_SELECTED = 1,
+    PK11_DIS_COULD_NOT_INIT_TOKEN = 2,
+    PK11_DIS_TOKEN_VERIFY_FAILED = 3,
+    PK11_DIS_TOKEN_NOT_PRESENT = 4
+} PK11DisableReasons;
+
+/* types of PKCS #11 objects 
+ * used to identify which NSS data structure is 
+ * passed to the PK11_Raw* functions. Types map as follows:
+ *   PK11_TypeGeneric            PK11GenericObject *
+ *   PK11_TypePrivKey            SECKEYPrivateKey *
+ *   PK11_TypePubKey             SECKEYPublicKey *
+ *   PK11_TypeSymKey             PK11SymKey *
+ *   PK11_TypeCert               CERTCertificate * (currently not used).
+ */
+typedef enum {
+   PK11_TypeGeneric = 0,
+   PK11_TypePrivKey = 1,
+   PK11_TypePubKey = 2,
+   PK11_TypeCert = 3,
+   PK11_TypeSymKey = 4
+} PK11ObjectType;
+
+
+
+/* function pointer type for password callback function.
+ * This type is passed in to PK11_SetPasswordFunc() 
+ */
+typedef char *(PR_CALLBACK *PK11PasswordFunc)(PK11SlotInfo *slot, PRBool retry, void *arg);
+typedef PRBool (PR_CALLBACK *PK11VerifyPasswordFunc)(PK11SlotInfo *slot, void *arg);
+typedef PRBool (PR_CALLBACK *PK11IsLoggedInFunc)(PK11SlotInfo *slot, void *arg);
+
+/*
+ * Special strings the password callback function can return only if
+ * the slot is an protected auth path slot.
+ */ 
+#define PK11_PW_RETRY		"RETRY"	/* an failed attempt to authenticate
+					 * has already been made, just retry
+					 * the operation */
+#define PK11_PW_AUTHENTICATED	"AUTH"  /* a successful attempt to authenticate
+					 * has completed. Continue without
+					 * another call to C_Login */
+/* All other non-null values mean that that NSS could call C_Login to force
+ * the authentication. The following define is to aid applications in 
+ * documenting that is what it's trying to do */
+#define PK11_PW_TRY		"TRY"   /* Default: a prompt has been presented
+					 * to the user, initiate a C_Login
+					 * to authenticate the token */
+
+/*
+ * PKCS #11 key structures
+ */
+
+/*
+** Attributes
+*/
+struct SECKEYAttributeStr {
+    SECItem attrType;
+    SECItem **attrValue;
+};
+typedef struct SECKEYAttributeStr SECKEYAttribute;
+
+/*
+** A PKCS#8 private key info object
+*/
+struct SECKEYPrivateKeyInfoStr {
+    PLArenaPool *arena;
+    SECItem version;
+    SECAlgorithmID algorithm;
+    SECItem privateKey;
+    SECKEYAttribute **attributes;
+};
+typedef struct SECKEYPrivateKeyInfoStr SECKEYPrivateKeyInfo;
+
+/*
+** A PKCS#8 private key info object
+*/
+struct SECKEYEncryptedPrivateKeyInfoStr {
+    PLArenaPool *arena;
+    SECAlgorithmID algorithm;
+    SECItem encryptedData;
+};
+typedef struct SECKEYEncryptedPrivateKeyInfoStr SECKEYEncryptedPrivateKeyInfo;
+
+/*
+ * token removal detection
+ */
+typedef enum {
+   PK11TokenNotRemovable = 0,
+   PK11TokenPresent = 1,
+   PK11TokenChanged = 2,
+   PK11TokenRemoved = 3
+} PK11TokenStatus;
+
+typedef enum {
+   PK11TokenRemovedOrChangedEvent = 0,
+   PK11TokenPresentEvent = 1
+} PK11TokenEvent;
+
+/*
+ * CRL Import Flags
+ */
+#define CRL_IMPORT_DEFAULT_OPTIONS 0x00000000
+#define CRL_IMPORT_BYPASS_CHECKS   0x00000001
+
+
+/*
+ * Merge Error Log
+ */
+typedef struct PK11MergeLogStr PK11MergeLog;
+typedef struct PK11MergeLogNodeStr PK11MergeLogNode;
+
+/* These need to be global, leave some open fields so we can 'expand'
+ * these without breaking binary compatibility */
+struct PK11MergeLogNodeStr {
+    PK11MergeLogNode *next;   /* next entry in the list */
+    PK11MergeLogNode *prev;   /* last entry in the list */
+    PK11GenericObject *object; /* object that failed */
+    int	error;		       /* what the error was */
+    CK_RV reserved1;
+    unsigned long reserved2; /* future flags */
+    unsigned long reserved3; /* future scalar */
+    void *reserved4; 	      /* future pointer */
+    void *reserved5;	      /* future expansion pointer */
+};
+
+struct PK11MergeLogStr {
+    PK11MergeLogNode *head;
+    PK11MergeLogNode *tail;
+    PLArenaPool *arena;
+    int version;
+    unsigned long reserved1;
+    unsigned long reserved2;
+    unsigned long reserved3;
+    void *reserverd4;
+    void *reserverd5;
+};
+    
+
+#endif /*_SECMODT_H_ */
diff --git a/mozilla/security/nss/lib/softoken/sftkdb.c b/mozilla/security/nss/lib/softoken/sftkdb.c
new file mode 100644
index 0000000..0a4d4d3
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkdb.c
@@ -0,0 +1,2720 @@
+/* ***** 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-2007
+ * 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 ***** */
+/* 
+ *  The following code handles the storage of PKCS 11 modules used by the
+ * NSS. For the rest of NSS, only one kind of database handle exists:
+ *
+ *     SFTKDBHandle
+ *
+ * There is one SFTKDBHandle for the each key database and one for each cert 
+ * database. These databases are opened as associated pairs, one pair per
+ * slot. SFTKDBHandles are reference counted objects.
+ *
+ * Each SFTKDBHandle points to a low level database handle (SDB). This handle
+ * represents the underlying physical database. These objects are not 
+ * reference counted, an are 'owned' by their respective SFTKDBHandles.
+ *
+ *  
+ */
+#include "sftkdb.h"
+#include "sftkdbti.h"
+#include "pkcs11t.h"
+#include "pkcs11i.h"
+#include "sdb.h"
+#include "prprf.h" 
+#include "secmodt.h"
+#include "pratom.h"
+#include "lgglue.h"
+#include "sftkpars.h"
+#include "secerr.h"
+#include "softoken.h"
+
+/*
+ * We want all databases to have the same binary representation independent of
+ * endianness or length of the host architecture. In general PKCS #11 attributes
+ * are endian/length independent except those attributes that pass CK_ULONG.
+ *
+ * The following functions fixes up the CK_ULONG type attributes so that the data
+ * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
+ * byte order values (big endian).
+ */
+#define BBP 8
+
+static PRBool
+sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type) 
+{
+    switch(type) {
+    case CKA_CERTIFICATE_CATEGORY:
+    case CKA_CERTIFICATE_TYPE:
+    case CKA_CLASS:
+    case CKA_JAVA_MIDP_SECURITY_DOMAIN:
+    case CKA_KEY_GEN_MECHANISM:
+    case CKA_KEY_TYPE:
+    case CKA_MECHANISM_TYPE:
+    case CKA_MODULUS_BITS:
+    case CKA_PRIME_BITS:
+    case CKA_SUBPRIME_BITS:
+    case CKA_VALUE_BITS:
+    case CKA_VALUE_LEN:
+
+    case CKA_TRUST_DIGITAL_SIGNATURE:
+    case CKA_TRUST_NON_REPUDIATION:
+    case CKA_TRUST_KEY_ENCIPHERMENT:
+    case CKA_TRUST_DATA_ENCIPHERMENT:
+    case CKA_TRUST_KEY_AGREEMENT:
+    case CKA_TRUST_KEY_CERT_SIGN:
+    case CKA_TRUST_CRL_SIGN:
+
+    case CKA_TRUST_SERVER_AUTH:
+    case CKA_TRUST_CLIENT_AUTH:
+    case CKA_TRUST_CODE_SIGNING:
+    case CKA_TRUST_EMAIL_PROTECTION:
+    case CKA_TRUST_IPSEC_END_SYSTEM:
+    case CKA_TRUST_IPSEC_TUNNEL:
+    case CKA_TRUST_IPSEC_USER:
+    case CKA_TRUST_TIME_STAMPING:
+    case CKA_TRUST_STEP_UP_APPROVED:
+	return PR_TRUE;
+    default:
+	break;
+    }
+    return PR_FALSE;
+    
+}
+
+/* are the attributes private? */
+static PRBool
+sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type) 
+{
+    switch(type) {
+    case CKA_VALUE:
+    case CKA_PRIVATE_EXPONENT:
+    case CKA_PRIME_1:
+    case CKA_PRIME_2:
+    case CKA_EXPONENT_1:
+    case CKA_EXPONENT_2:
+    case CKA_COEFFICIENT:
+	return PR_TRUE;
+    default:
+	break;
+    }
+    return PR_FALSE;
+}
+
+/* These attributes must be authenticated with an hmac. */
+static PRBool
+sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) 
+{
+    switch(type) {
+    case CKA_MODULUS:
+    case CKA_PUBLIC_EXPONENT:
+    case CKA_CERT_SHA1_HASH:
+    case CKA_CERT_MD5_HASH:
+    case CKA_TRUST_SERVER_AUTH:
+    case CKA_TRUST_CLIENT_AUTH:
+    case CKA_TRUST_EMAIL_PROTECTION:
+    case CKA_TRUST_CODE_SIGNING:
+    case CKA_TRUST_STEP_UP_APPROVED:
+    case CKA_NSS_OVERRIDE_EXTENSIONS:
+	return PR_TRUE;
+    default:
+	break;
+    }
+    return PR_FALSE;
+}
+
+/*
+ * convert a native ULONG to a database ulong. Database ulong's
+ * are all 4 byte big endian values.
+ */
+void
+sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value)
+{ 
+    int i;
+
+    for (i=0; i < SDB_ULONG_SIZE; i++) {
+	data[i] = (value >> (SDB_ULONG_SIZE-1-i)*BBP) & 0xff;
+    }
+}
+
+/*
+ * convert a database ulong back to a native ULONG. (reverse of the above
+ * function.
+ */
+static CK_ULONG
+sftk_SDBULong2ULong(unsigned char *data)
+{
+    int i;
+    CK_ULONG value = 0;
+
+    for (i=0; i < SDB_ULONG_SIZE; i++) {
+	value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE-1-i)*BBP);
+    }
+    return value;
+}
+
+/*
+ * fix up the input templates. Our fixed up ints are stored in data and must
+ * be freed by the caller. The new template must also be freed. If there are no
+ * CK_ULONG attributes, the orignal template is passed in as is.
+ */
+static CK_ATTRIBUTE *
+sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, 
+			unsigned char **dataOut)
+{
+    int i;
+    int ulongCount = 0;
+    unsigned char *data;
+    CK_ATTRIBUTE *ntemplate;
+
+    *dataOut = NULL;
+
+    /* first count the number of CK_ULONG attributes */
+    for (i=0; i < count; i++) {
+	/* Don't 'fixup' NULL values */
+	if (!template[i].pValue) {
+	    continue;
+	}
+	if (template[i].ulValueLen == sizeof (CK_ULONG)) {
+	    if ( sftkdb_isULONGAttribute(template[i].type)) {
+		ulongCount++;
+	    }
+	}
+    }
+    /* no attributes to fixup, just call on through */
+    if (ulongCount == 0) {
+	return (CK_ATTRIBUTE *)template;
+    }
+
+    /* allocate space for new ULONGS */
+    data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE*ulongCount);
+    if (!data) {
+	return NULL;
+    }
+
+    /* allocate new template */
+    ntemplate = PORT_NewArray(CK_ATTRIBUTE,count);
+    if (!ntemplate) {
+	PORT_Free(data);
+	return NULL;
+    }
+    *dataOut = data;
+    /* copy the old template, fixup the actual ulongs */
+    for (i=0; i < count; i++) {
+	ntemplate[i] = template[i];
+	/* Don't 'fixup' NULL values */
+	if (!template[i].pValue) {
+	    continue;
+	}
+	if (template[i].ulValueLen == sizeof (CK_ULONG)) {
+	    if ( sftkdb_isULONGAttribute(template[i].type) ) {
+		CK_ULONG value = *(CK_ULONG *) template[i].pValue;
+		sftk_ULong2SDBULong(data, value);
+		ntemplate[i].pValue = data;
+		ntemplate[i].ulValueLen = SDB_ULONG_SIZE;
+		data += SDB_ULONG_SIZE;
+	    }
+	}
+    }
+    return ntemplate;
+}
+
+
+static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x";
+
+/*
+ * return a string describing the database type (key or cert)
+ */
+const char *
+sftkdb_TypeString(SFTKDBHandle *handle)
+{
+   return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert";
+}
+
+/*
+ * Some attributes are signed with an Hmac and a pbe key generated from
+ * the password. This signature is stored indexed by object handle and
+ * attribute type in the meta data table in the key database.
+ *
+ * Signature entries are indexed by the string
+ * sig_[cert/key]_{ObjectID}_{Attribute}
+ *
+ * This function fetches that pkcs5 signature. Caller supplies a SECItem
+ * pre-allocated to the appropriate size if the SECItem is too small the
+ * function will fail with CKR_BUFFER_TOO_SMALL.
+ */
+static CK_RV
+sftkdb_getAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle, 
+		CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
+		SECItem *signText)
+{
+    SDB *db;
+    char id[30];
+    CK_RV crv;
+
+    db = SFTK_GET_SDB(keyHandle);
+
+    sprintf(id, SFTKDB_META_SIG_TEMPLATE,
+	sftkdb_TypeString(handle),
+	(unsigned int)objectID, (unsigned int)type);
+
+    crv = (*db->sdb_GetMetaData)(db, id, signText, NULL);
+    return crv;
+}
+
+/*
+ * Some attributes are signed with an Hmac and a pbe key generated from
+ * the password. This signature is stored indexed by object handle and
+ * attribute type in the meta data table in the key database.
+ *
+ * Signature entries are indexed by the string
+ * sig_[cert/key]_{ObjectID}_{Attribute}
+ *
+ * This function stores that pkcs5 signature.
+ */
+CK_RV
+sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget, 
+		CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
+		SECItem *signText)
+{
+    char id[30];
+    CK_RV crv;
+
+    sprintf(id, SFTKDB_META_SIG_TEMPLATE,
+	sftkdb_TypeString(handle),
+	(unsigned int)objectID, (unsigned int)type);
+
+    crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL);
+    return crv;
+}
+
+/*
+ * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated
+ * separate data sections for the database ULONG values.
+ */
+static CK_RV
+sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID,
+		CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle)
+{
+    int i;
+    CK_RV crv = CKR_OK;
+    SFTKDBHandle *keyHandle;
+    PRBool checkSig = PR_TRUE;
+    PRBool checkEnc = PR_TRUE;
+
+    PORT_Assert(handle);
+
+    /* find the key handle */
+    keyHandle = handle;
+    if (handle->type != SFTK_KEYDB_TYPE) {
+	checkEnc = PR_FALSE;
+	keyHandle = handle->peerDB;
+    }
+
+    if ((keyHandle == NULL) || 
+	((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0)  ||
+	(keyHandle->passwordKey.data == NULL)) {
+	checkSig = PR_FALSE;
+    }
+
+    for (i=0; i < count; i++) {
+	CK_ULONG length = template[i].ulValueLen;
+	template[i].ulValueLen = ntemplate[i].ulValueLen;
+	/* fixup ulongs */
+	if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) {
+	    if (sftkdb_isULONGAttribute(template[i].type)) {
+		if (template[i].pValue) {
+		    CK_ULONG value;
+		    unsigned char *data;
+
+		    data = (unsigned char *)ntemplate[i].pValue;
+		    value = sftk_SDBULong2ULong(ntemplate[i].pValue);
+		    if (length < sizeof(CK_ULONG)) {
+			template[i].ulValueLen = -1;
+			crv = CKR_BUFFER_TOO_SMALL;
+			continue;
+		    } 
+		    PORT_Memcpy(template[i].pValue,&value,sizeof(CK_ULONG));
+		}
+		template[i].ulValueLen = sizeof(CK_ULONG);
+	    }
+	}
+
+	/* if no data was retrieved, no need to process encrypted or signed
+	 * attributes */
+	if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) {
+	    continue;
+	}
+
+	/* fixup private attributes */
+	if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) {
+	    /* we have a private attribute */
+	    /* This code depends on the fact that the cipherText is bigger
+	     * than the plain text */
+	    SECItem cipherText;
+	    SECItem *plainText;
+	    SECStatus rv;
+
+	    cipherText.data = ntemplate[i].pValue;
+	    cipherText.len = ntemplate[i].ulValueLen;
+    	    PZ_Lock(handle->passwordLock);
+	    if (handle->passwordKey.data == NULL) {
+		PZ_Unlock(handle->passwordLock);
+		template[i].ulValueLen = -1;
+		crv = CKR_USER_NOT_LOGGED_IN;
+		continue;
+	    }
+	    rv = sftkdb_DecryptAttribute(&handle->passwordKey, 
+					&cipherText, &plainText);
+	    PZ_Unlock(handle->passwordLock);
+	    if (rv != SECSuccess) {
+		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
+		template[i].ulValueLen = -1;
+		crv = CKR_GENERAL_ERROR;
+		continue;
+	    }
+	    PORT_Assert(template[i].ulValueLen >= plainText->len);
+	    if (template[i].ulValueLen < plainText->len) {
+		SECITEM_FreeItem(plainText,PR_TRUE);
+		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
+		template[i].ulValueLen = -1;
+		crv = CKR_GENERAL_ERROR;
+		continue;
+	    }
+		
+	    /* copy the plain text back into the template */
+	    PORT_Memcpy(template[i].pValue, plainText->data, plainText->len);
+	    template[i].ulValueLen = plainText->len;
+	    SECITEM_FreeItem(plainText,PR_TRUE);
+	}
+	/* make sure signed attributes are valid */
+	if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) {
+	    SECStatus rv;
+	    SECItem signText;
+	    SECItem plainText;
+	    unsigned char signData[SDB_MAX_META_DATA_LEN];
+
+	    signText.data = signData;
+	    signText.len = sizeof(signData);
+
+	    rv = sftkdb_getAttributeSignature(handle, keyHandle, 
+				objectID, ntemplate[i].type, &signText);
+	    if (rv != SECSuccess) {
+		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
+		template[i].ulValueLen = -1;
+		crv = CKR_DATA_INVALID; /* better error code? */
+		continue;
+	    }
+
+	    plainText.data = ntemplate[i].pValue;
+	    plainText.len = ntemplate[i].ulValueLen;
+
+	    /*
+	     * we do a second check holding the lock just in case the user
+	     * loggout while we were trying to get the signature.
+	     */
+    	    PZ_Lock(keyHandle->passwordLock);
+	    if (keyHandle->passwordKey.data == NULL) {
+		/* if we are no longer logged in, no use checking the other
+		 * Signatures either. */
+		checkSig = PR_FALSE; 
+		PZ_Unlock(keyHandle->passwordLock);
+		continue;
+	    }
+
+	    rv = sftkdb_VerifyAttribute(&keyHandle->passwordKey, 
+				objectID, ntemplate[i].type,
+				&plainText, &signText);
+	    PZ_Unlock(keyHandle->passwordLock);
+	    if (rv != SECSuccess) {
+		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
+		template[i].ulValueLen = -1;
+		crv = CKR_SIGNATURE_INVALID; /* better error code? */
+	    }
+	    /* This Attribute is fine */
+	}
+    }
+    return crv;
+}
+
+/*
+ * Some attributes are signed with an HMAC and a pbe key generated from
+ * the password. This signature is stored indexed by object handle and
+ *
+ * Those attributes are:
+ * 1) Trust object hashes and trust values.
+ * 2) public key values.
+ *
+ * Certs themselves are considered properly authenticated by virtue of their
+ * signature, or their matching hash with the trust object.
+ *
+ * These signature is only checked for objects coming from shared databases. 
+ * Older dbm style databases have such no signature checks. HMACs are also 
+ * only checked when the token is logged in, as it requires a pbe generated 
+ * from the password.
+ *
+ * Tokens which have no key database (and therefore no master password) do not
+ * have any stored signature values. Signature values are stored in the key
+ * database, since the signature data is tightly coupled to the key database
+ * password. 
+ *
+ * This function takes a template of attributes that were either created or
+ * modified. These attributes are checked to see if the need to be signed.
+ * If they do, then this function signs the attributes and writes them
+ * to the meta data store.
+ *
+ * This function can fail if there are attributes that must be signed, but
+ * the token is not logged in.
+ *
+ * The caller is expected to abort any transaction he was in in the
+ * event of a failure of this function.
+ */
+static CK_RV
+sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle, 
+		  PRBool mayBeUpdateDB,
+		  CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
+		  CK_ULONG count)
+{
+    int i;
+    SFTKDBHandle *keyHandle = handle;
+    SDB *keyTarget = NULL;
+
+    PORT_Assert(handle);
+
+    if (handle->type != SFTK_KEYDB_TYPE) {
+	keyHandle = handle->peerDB;
+    }
+
+    /* no key DB defined? then no need to sign anything */
+    if (keyHandle == NULL) {
+	return CKR_OK;
+    }
+
+    /* When we are in a middle of an update, we have an update database set, 
+     * but we want to write to the real database. The bool mayBeUpdateDB is
+     * set to TRUE if it's possible that we want to write an update database
+     * rather than a primary */
+    keyTarget = (mayBeUpdateDB && keyHandle->update) ? 
+		keyHandle->update : keyHandle->db;
+
+    /* skip the the database does not support meta data */
+    if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
+	return CKR_OK;
+    }
+
+    for (i=0; i < count; i ++) {
+	if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
+	    SECStatus rv;
+	    SECItem *signText;
+	    SECItem plainText;
+
+	    plainText.data = template[i].pValue;
+	    plainText.len = template[i].ulValueLen;
+	    PZ_Lock(keyHandle->passwordLock);
+	    if (keyHandle->passwordKey.data == NULL) {
+		PZ_Unlock(keyHandle->passwordLock);
+		return CKR_USER_NOT_LOGGED_IN;
+	    }
+	    rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey, 
+				objectID, template[i].type,
+				&plainText, &signText);
+	    PZ_Unlock(keyHandle->passwordLock);
+	    if (rv != SECSuccess) {
+		return CKR_GENERAL_ERROR; /* better error code here? */
+	    }
+	    rv = sftkdb_PutAttributeSignature(handle, keyTarget, 
+				objectID, template[i].type, signText);
+	    if (rv != SECSuccess) {
+		return CKR_GENERAL_ERROR; /* better error code here? */
+	    }
+	}
+    }
+    return CKR_OK;
+}
+
+static CK_RV
+sftkdb_CreateObject(PRArenaPool *arena, SFTKDBHandle *handle, 
+	SDB *db, CK_OBJECT_HANDLE *objectID,
+        CK_ATTRIBUTE *template, CK_ULONG count)
+{
+    PRBool inTransaction = PR_FALSE;
+    CK_RV crv;
+
+    inTransaction = PR_TRUE;
+    
+    crv = (*db->sdb_CreateObject)(db, objectID, template, count);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    crv = sftk_signTemplate(arena, handle, (db == handle->update),
+					*objectID, template, count);
+loser:
+
+    return crv;
+}
+
+
+CK_ATTRIBUTE * 
+sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, 
+		     SFTKDBHandle *handle,CK_ULONG *pcount, 
+		     CK_RV *crv)
+{
+    int count;
+    CK_ATTRIBUTE *template;
+    int i, templateIndex;
+    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
+    PRBool doEnc = PR_TRUE;
+
+    *crv = CKR_OK;
+
+    if (sessObject == NULL) {
+	*crv = CKR_GENERAL_ERROR; /* internal programming error */
+	return NULL;
+    }
+
+    PORT_Assert(handle);
+    /* find the key handle */
+    if (handle->type != SFTK_KEYDB_TYPE) {
+	doEnc = PR_FALSE;
+    }
+
+    PZ_Lock(sessObject->attributeLock);
+    count = 0;
+    for (i=0; i < sessObject->hashSize; i++) {
+	SFTKAttribute *attr;
+   	for (attr=sessObject->head[i]; attr; attr=attr->next) {
+	    count++;
+	}
+    }
+    template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count);
+    if (template == NULL) {
+        PZ_Unlock(sessObject->attributeLock);
+	*crv = CKR_HOST_MEMORY;
+	return NULL;
+    }
+    templateIndex = 0;
+    for (i=0; i < sessObject->hashSize; i++) {
+	SFTKAttribute *attr;
+   	for (attr=sessObject->head[i]; attr; attr=attr->next) {
+	    CK_ATTRIBUTE *tp = &template[templateIndex++];
+	    /* copy the attribute */
+	    *tp = attr->attrib;
+
+	    /* fixup  ULONG s */
+	    if ((tp->ulValueLen == sizeof (CK_ULONG)) &&
+		(sftkdb_isULONGAttribute(tp->type)) ) {
+		CK_ULONG value = *(CK_ULONG *) tp->pValue;
+		unsigned char *data;
+
+		tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE);
+		data = (unsigned char *)tp->pValue;
+		if (data == NULL) {
+		    *crv = CKR_HOST_MEMORY;
+		    break;
+		}
+		sftk_ULong2SDBULong(data, value);
+		tp->ulValueLen = SDB_ULONG_SIZE;
+	    }
+
+	    /* encrypt private attributes */
+	    if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
+		/* we have a private attribute */
+		SECItem *cipherText;
+		SECItem plainText;
+		SECStatus rv;
+
+		plainText.data = tp->pValue;
+		plainText.len = tp->ulValueLen;
+		PZ_Lock(handle->passwordLock);
+		if (handle->passwordKey.data == NULL) {
+		    PZ_Unlock(handle->passwordLock);
+		    *crv = CKR_USER_NOT_LOGGED_IN;
+		    break;
+		}
+		rv = sftkdb_EncryptAttribute(arena, &handle->passwordKey, 
+						&plainText, &cipherText);
+		PZ_Unlock(handle->passwordLock);
+		if (rv == SECSuccess) {
+		    tp->pValue = cipherText->data;
+		    tp->ulValueLen = cipherText->len;
+		} else {
+		    *crv = CKR_GENERAL_ERROR; /* better error code here? */
+		    break;
+		}
+		PORT_Memset(plainText.data, 0, plainText.len);
+	    }
+	}
+    }
+    PORT_Assert(templateIndex <= count);
+    PZ_Unlock(sessObject->attributeLock);
+
+    if (*crv != CKR_OK) {
+	return NULL;
+    }
+    if (pcount) {
+	*pcount = count;
+    }
+    return template;
+
+}
+
+/*
+ * return a pointer to the attribute in the give template.
+ * The return value is not const, as the caller may modify
+ * the given attribute value, but such modifications will
+ * modify the actual value in the template.
+ */
+static CK_ATTRIBUTE *
+sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute, 
+			    CK_ATTRIBUTE *ptemplate, CK_ULONG len)
+{
+    CK_ULONG i;
+
+    for (i=0; i < len; i++) {
+	if (attribute == ptemplate[i].type) {
+	    return &ptemplate[i];
+	}
+    }
+    return NULL;
+}
+
+static const CK_ATTRIBUTE *
+sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute, 
+				const CK_ATTRIBUTE *ptemplate, CK_ULONG len)
+{
+    CK_ULONG i;
+
+    for (i=0; i < len; i++) {
+	if (attribute == ptemplate[i].type) {
+	    return &ptemplate[i];
+	}
+    }
+    return NULL;
+}
+
+
+/*
+ * fetch a template which identifies 'unique' entries based on object type
+ */
+static CK_RV
+sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData,
+			CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount,
+			CK_ATTRIBUTE *ptemplate, int len)
+{
+    CK_ATTRIBUTE *attr;
+    CK_ULONG count = 1;
+
+    sftk_ULong2SDBULong(objTypeData, objectType);
+    findTemplate[0].type = CKA_CLASS;
+    findTemplate[0].pValue = objTypeData;
+    findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
+
+    switch (objectType) {
+    case CKO_CERTIFICATE:
+    case CKO_NSS_TRUST:
+	attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len);
+	if (attr == NULL) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	findTemplate[1] = *attr;
+	attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER, 
+					ptemplate, len);
+	if (attr == NULL) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	findTemplate[2] = *attr;
+	count = 3;
+	break;
+	
+    case CKO_PRIVATE_KEY:
+    case CKO_PUBLIC_KEY:
+    case CKO_SECRET_KEY:
+	attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len);
+	if (attr == NULL) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	findTemplate[1] = *attr;
+	count = 2;
+	break;
+
+    case CKO_NSS_CRL:
+	attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
+	if (attr == NULL) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	findTemplate[1] = *attr;
+	count = 2;
+	break;
+
+    case CKO_NSS_SMIME:
+	attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
+	if (attr == NULL) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	findTemplate[1] = *attr;
+	attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len);
+	if (attr == NULL) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	findTemplate[2] = *attr;
+	count = 3;
+	break;
+    default:
+	attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len);
+	if (attr == NULL) {
+	    return CKR_TEMPLATE_INCOMPLETE;
+	}
+	findTemplate[1] = *attr;
+	count = 2;
+	break;
+    }
+    *findCount = count;
+
+    return CKR_OK;
+}
+
+/*
+ * look to see if this object already exists and return it's object ID if
+ * it does.
+ */
+static CK_RV
+sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType, 
+		 CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len)
+{
+    CK_ATTRIBUTE findTemplate[3];
+    CK_ULONG count = 1;
+    CK_ULONG objCount = 0;
+    SDBFind *find = NULL;
+    unsigned char objTypeData[SDB_ULONG_SIZE];
+    CK_RV crv;
+
+    *id = CK_INVALID_HANDLE;
+    if (objectType == CKO_NSS_CRL) {
+	return CKR_OK;
+    }
+    crv = sftkdb_getFindTemplate(objectType, objTypeData,
+			findTemplate, &count, ptemplate, len);
+    if (crv != CKR_OK) {
+	return crv;
+    }
+
+    /* use the raw find, so we get the correct database */
+    crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find);
+    if (crv != CKR_OK) {
+	return crv;
+    }
+    (*db->sdb_FindObjects)(db, find, id, 1, &objCount);
+    (*db->sdb_FindObjectsFinal)(db, find);
+
+    if (objCount == 0) {
+	*id = CK_INVALID_HANDLE;
+    }
+    return CKR_OK;
+}
+
+
+/*
+ * check to see if this template conflicts with others in our current database.
+ */
+static CK_RV
+sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType, 
+			const CK_ATTRIBUTE *ptemplate, CK_ULONG len, 
+			CK_OBJECT_HANDLE sourceID)
+{
+    CK_ATTRIBUTE findTemplate[2];
+    unsigned char objTypeData[SDB_ULONG_SIZE];
+    /* we may need to allocate some temporaries. Keep track of what was 
+     * allocated so we can free it in the end */
+    unsigned char *temp1 = NULL; 
+    unsigned char *temp2 = NULL;
+    CK_ULONG objCount = 0;
+    SDBFind *find = NULL;
+    CK_OBJECT_HANDLE id;
+    const CK_ATTRIBUTE *attr, *attr2;
+    CK_RV crv;
+    CK_ATTRIBUTE subject;
+
+    /* Currently the only conflict is with nicknames pointing to the same 
+     * subject when creating or modifying a certificate. */
+    /* If the object is not a cert, no problem. */
+    if (objectType != CKO_CERTIFICATE) {
+	return CKR_OK;
+    }
+    /* if not setting a nickname then there's still no problem */
+    attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len);
+    if ((attr == NULL) || (attr->ulValueLen == 0)) {
+	return CKR_OK;
+    }
+    /* fetch the subject of the source. For creation and merge, this should
+     * be found in the template */
+    attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len);
+    if (sourceID == CK_INVALID_HANDLE) {
+	if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) {
+	    crv = CKR_TEMPLATE_INCOMPLETE; 
+	    goto done;
+	}
+    } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) {
+	/* sourceID is set if we are trying to modify an existing entry instead
+	 * of creating a new one. In this case the subject may not be (probably
+	 * isn't) in the template, we have to read it from the database */
+    	subject.type = CKA_SUBJECT;
+    	subject.pValue = NULL;
+    	subject.ulValueLen = 0;
+    	crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
+	if (crv != CKR_OK) {
+	    goto done;
+	}
+	if ((CK_LONG)subject.ulValueLen < 0) {
+	    crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */
+	    goto done;
+	}
+	temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen);
+	if (temp1 == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    goto done;
+	}
+    	crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
+	if (crv != CKR_OK) {
+	    goto done;
+	}
+	attr2 = &subject;
+    }
+    
+    /* check for another cert in the database with the same nickname */
+    sftk_ULong2SDBULong(objTypeData, objectType);
+    findTemplate[0].type = CKA_CLASS;
+    findTemplate[0].pValue = objTypeData;
+    findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
+    findTemplate[1] = *attr;
+
+    crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find);
+    if (crv != CKR_OK) {
+	goto done;
+    }
+    (*db->sdb_FindObjects)(db, find, &id, 1, &objCount);
+    (*db->sdb_FindObjectsFinal)(db, find);
+
+    /* object count == 0 means no conflicting certs found, 
+     * go on with the operation */
+    if (objCount == 0) {
+	crv = CKR_OK;
+	goto done;
+    }
+
+    /* There is a least one cert that shares the nickname, make sure it also
+     * matches the subject. */
+    findTemplate[0] = *attr2;
+    /* we know how big the source subject was. Use that length to create the 
+     * space for the target. If it's not enough space, then it means the 
+     * source subject is too big, and therefore not a match. GetAttributeValue 
+     * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough 
+     * space (or enough space to be able to compare the result. */
+    temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen);
+    if (temp2 == NULL) {
+	crv = CKR_HOST_MEMORY;
+	goto done;
+    }
+    crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1);
+    if (crv != CKR_OK) {
+	if (crv == CKR_BUFFER_TOO_SMALL) {
+	    /* if our buffer is too small, then the Subjects clearly do 
+	     * not match */
+	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
+	    goto loser;
+	}
+	/* otherwise we couldn't get the value, just fail */
+	goto done;
+    }
+	
+    /* Ok, we have both subjects, make sure they are the same. 
+     * Compare the subjects */
+    if ((findTemplate[0].ulValueLen != attr2->ulValueLen) || 
+	(attr2->ulValueLen > 0 &&
+	 PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) 
+	 != 0)) {
+    	crv = CKR_ATTRIBUTE_VALUE_INVALID; 
+	goto loser;
+    }
+    crv = CKR_OK;
+    
+done:
+    /* If we've failed for some other reason than a conflict, make sure we 
+     * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID. 
+     * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should 
+     * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia).
+     */
+    if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
+	crv = CKR_GENERAL_ERROR; /* clearly a programming error */
+    }
+
+    /* exit point if we found a conflict */
+loser:
+    PORT_Free(temp1);
+    PORT_Free(temp2);
+    return crv;
+}
+
+/*
+ * try to update the template to fix any errors. This is only done 
+ * during update.
+ *
+ * NOTE: we must update the template or return an error, or the update caller 
+ * will loop forever!
+ *
+ * Two copies of the source code for this algorithm exist in NSS.  
+ * Changes must be made in both copies.
+ * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c.
+ *
+ */
+static CK_RV
+sftkdb_resolveConflicts(PRArenaPool *arena, CK_OBJECT_CLASS objectType, 
+			CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
+{
+    CK_ATTRIBUTE *attr;
+    char *nickname, *newNickname;
+    int end, digit;
+
+    /* sanity checks. We should never get here with these errors */
+    if (objectType != CKO_CERTIFICATE) {
+	return CKR_GENERAL_ERROR; /* shouldn't happen */
+    }
+    attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
+    if ((attr == NULL) || (attr->ulValueLen == 0)) {
+	return CKR_GENERAL_ERROR; /* shouldn't happen */
+    }
+
+    /* update the nickname */
+    /* is there a number at the end of the nickname already?
+     * if so just increment that number  */
+    nickname = (char *)attr->pValue;
+
+    /* does nickname end with " #n*" ? */
+    for (end = attr->ulValueLen - 1; 
+         end >= 2 && (digit = nickname[end]) <= '9' &&  digit >= '0'; 
+	 end--)  /* just scan */ ;
+    if (attr->ulValueLen >= 3 &&
+        end < (attr->ulValueLen - 1) /* at least one digit */ &&
+	nickname[end]     == '#'  && 
+	nickname[end - 1] == ' ') {
+    	/* Already has a suitable suffix string */
+    } else {
+	/* ... append " #2" to the name */
+	static const char num2[] = " #2";
+	newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2));
+	if (!newNickname) {
+	    return CKR_HOST_MEMORY;
+	}
+	PORT_Memcpy(newNickname, nickname, attr->ulValueLen);
+	PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2));
+	attr->pValue = newNickname; /* modifies ptemplate */
+	attr->ulValueLen += 3;      /* 3 is strlen(num2)  */
+	return CKR_OK;
+    }
+
+    for (end = attr->ulValueLen - 1; 
+	 end >= 0 && (digit = nickname[end]) <= '9' &&  digit >= '0'; 
+	 end--) {
+	if (digit < '9') {
+	    nickname[end]++;
+	    return CKR_OK;
+	}
+	nickname[end] = '0';
+    }
+
+    /* we overflowed, insert a new '1' for a carry in front of the number */
+    newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1);
+    if (!newNickname) {
+	return CKR_HOST_MEMORY;
+    }
+    /* PORT_Memcpy should handle len of '0' */
+    PORT_Memcpy(newNickname, nickname, ++end);
+    newNickname[end] = '1';
+    PORT_Memset(&newNickname[end+1],'0',attr->ulValueLen - end);
+    attr->pValue = newNickname;
+    attr->ulValueLen++;
+    return CKR_OK;
+}
+
+/*
+ * set an attribute and sign it if necessary
+ */
+static CK_RV
+sftkdb_setAttributeValue(PRArenaPool *arena, SFTKDBHandle *handle, 
+	SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, 
+	CK_ULONG count)
+{
+    CK_RV crv;
+    crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count);
+    if (crv != CKR_OK) {
+	return crv;
+    }
+    crv = sftk_signTemplate(arena, handle, db == handle->update, 
+				objectID, template, count);
+    return crv;
+}
+
+/*
+ * write a softoken object out to the database.
+ */
+CK_RV
+sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, 
+	     CK_OBJECT_HANDLE *objectID)
+{
+    CK_ATTRIBUTE *template;
+    PLArenaPool *arena;
+    CK_ULONG count;
+    CK_RV crv;
+    SDB *db;
+    PRBool inTransaction = PR_FALSE;
+    CK_OBJECT_HANDLE id;
+
+    *objectID = CK_INVALID_HANDLE;
+
+    if (handle == NULL) {
+	return  CKR_TOKEN_WRITE_PROTECTED;
+    }
+    db = SFTK_GET_SDB(handle);
+
+    /*
+     * we have opened a new database, but we have not yet updated it. We are
+     * still running pointing to the old database (so the application can 
+     * still read). We don't want to write to the old database at this point,
+     * however, since it leads to user confusion. So at this point we simply
+     * require a user login. Let NSS know this so it can prompt the user.
+     */
+    if (db == handle->update) {
+	return CKR_USER_NOT_LOGGED_IN;
+    }
+
+    arena = PORT_NewArena(256);
+    if (arena ==  NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    template = sftk_ExtractTemplate(arena, object, handle, &count, &crv);
+    if (!template) {
+	goto loser;
+    }
+
+    crv = (*db->sdb_Begin)(db);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    inTransaction = PR_TRUE;
+
+    /*
+     * We want to make the base database as free from object specific knowledge
+     * as possible. To maintain compatibility, keep some of the desirable
+     * object specific semantics of the old database.
+     * 
+     * These were 2 fold:
+     *  1) there were certain conflicts (like trying to set the same nickname 
+     * on two different subjects) that would return an error.
+     *  2) Importing the 'same' object would silently update that object.
+     *
+     * The following 2 functions mimic the desirable effects of these two
+     * semantics without pushing any object knowledge to the underlying database
+     * code.
+     */
+
+    /* make sure we don't have attributes that conflict with the existing DB */
+    crv = sftkdb_checkConflicts(db, object->objclass, template, count,
+				 CK_INVALID_HANDLE);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    /* Find any copies that match this particular object */
+    crv = sftkdb_lookupObject(db, object->objclass, &id, template, count);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    if (id == CK_INVALID_HANDLE) {
+        crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
+    } else {
+	/* object already exists, modify it's attributes */
+	*objectID = id;
+        crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count);
+    }
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    crv = (*db->sdb_Commit)(db);
+    inTransaction = PR_FALSE;
+
+loser:
+    if (inTransaction) {
+	(*db->sdb_Abort)(db);
+	/* It is trivial to show the following code cannot
+	 * happen unless something is horribly wrong with our compilier or
+	 * hardware */
+	PORT_Assert(crv != CKR_OK);
+	if (crv == CKR_OK) crv = CKR_GENERAL_ERROR;
+    }
+
+    if (arena) {
+	PORT_FreeArena(arena,PR_FALSE);
+    }
+    if (crv == CKR_OK) {
+	*objectID |= (handle->type | SFTK_TOKEN_TYPE);
+    } 
+    return crv;
+}
+
+
+CK_RV 
+sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template,
+				 CK_ULONG count, SDBFind **find) 
+{
+    unsigned char *data = NULL;
+    CK_ATTRIBUTE *ntemplate = NULL;
+    CK_RV crv;
+    SDB *db;
+
+    if (handle == NULL) {
+	return CKR_OK;
+    }
+    db = SFTK_GET_SDB(handle);
+
+    if (count !=  0) {
+	ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
+	if (ntemplate == NULL) {
+	    return CKR_HOST_MEMORY;
+	}
+    }
+	
+    crv = (*db->sdb_FindObjectsInit)(db, ntemplate, 
+					     count, find);
+    if (data) {
+	PORT_Free(ntemplate);
+	PORT_Free(data);
+    }
+    return crv;
+}
+
+CK_RV 
+sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, 
+			CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count)
+{
+    CK_RV crv;
+    SDB *db;
+
+    if (handle == NULL) {
+	*count = 0;
+	return CKR_OK;
+    }
+    db = SFTK_GET_SDB(handle);
+
+    crv = (*db->sdb_FindObjects)(db, find, ids, 
+					    arraySize, count);
+    if (crv == CKR_OK) {
+	int i;
+	for (i=0; i < *count; i++) {
+	    ids[i] |= (handle->type | SFTK_TOKEN_TYPE);
+	}
+    }
+    return crv;
+}
+
+CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find)
+{
+    SDB *db;
+    if (handle == NULL) {
+	return CKR_OK;
+    }
+    db = SFTK_GET_SDB(handle);
+    return (*db->sdb_FindObjectsFinal)(db, find);
+}
+
+CK_RV
+sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
+                                CK_ATTRIBUTE *template, CK_ULONG count)
+{
+    CK_RV crv,crv2;
+    CK_ATTRIBUTE *ntemplate;
+    unsigned char *data = NULL;
+    SDB *db;
+
+    if (handle == NULL) {
+	return CKR_GENERAL_ERROR;
+    }
+
+    /* short circuit common attributes */
+    if (count == 1 && 
+	  (template[0].type == CKA_TOKEN || 
+	   template[0].type == CKA_PRIVATE ||
+	   template[0].type == CKA_SENSITIVE)) {
+	CK_BBOOL boolVal = CK_TRUE;
+
+	if (template[0].pValue == NULL) {
+	    template[0].ulValueLen = sizeof(CK_BBOOL);
+	    return CKR_OK;
+	}
+	if (template[0].ulValueLen < sizeof(CK_BBOOL)) {
+	    template[0].ulValueLen = -1;
+	    return CKR_BUFFER_TOO_SMALL;
+	}
+
+	if ((template[0].type == CKA_PRIVATE) &&
+    				(handle->type != SFTK_KEYDB_TYPE)) {
+	    boolVal = CK_FALSE;
+	}
+	if ((template[0].type == CKA_SENSITIVE) &&
+    				(handle->type != SFTK_KEYDB_TYPE)) {
+	    boolVal = CK_FALSE;
+	}
+	*(CK_BBOOL *)template[0].pValue = boolVal;
+	template[0].ulValueLen = sizeof(CK_BBOOL);
+	return CKR_OK;
+    }
+
+    db = SFTK_GET_SDB(handle);
+    /* nothing to do */
+    if (count == 0) {
+	return CKR_OK;
+    }
+    ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
+    if (ntemplate == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    objectID &= SFTK_OBJ_ID_MASK;
+    crv = (*db->sdb_GetAttributeValue)(db, objectID, 
+						ntemplate, count);
+    crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate, 
+						count, handle);
+    if (crv == CKR_OK) crv = crv2;
+    if (data) {
+	PORT_Free(ntemplate);
+	PORT_Free(data);
+    }
+    return crv;
+
+}
+
+CK_RV
+sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object,
+                                const CK_ATTRIBUTE *template, CK_ULONG count)
+{
+    CK_ATTRIBUTE *ntemplate;
+    unsigned char *data = NULL;
+    PLArenaPool *arena = NULL;
+    SDB *db;
+    CK_RV crv = CKR_OK;
+    CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK);
+    PRBool inTransaction = PR_FALSE;
+
+    if (handle == NULL) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+
+    db = SFTK_GET_SDB(handle);
+    /* nothing to do */
+    if (count == 0) {
+	return CKR_OK;
+    }
+    /*
+     * we have opened a new database, but we have not yet updated it. We are
+     * still running  pointing to the old database (so the application can 
+     * still read). We don't want to write to the old database at this point,
+     * however, since it leads to user confusion. So at this point we simply
+     * require a user login. Let NSS know this so it can prompt the user.
+     */
+    if (db == handle->update) {
+	return CKR_USER_NOT_LOGGED_IN;
+    }
+
+    ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
+    if (ntemplate == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    /* make sure we don't have attributes that conflict with the existing DB */
+    crv = sftkdb_checkConflicts(db, object->objclass, template, count, objectID);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    arena = PORT_NewArena(256);
+    if (arena ==  NULL) {
+	crv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+
+    crv = (*db->sdb_Begin)(db);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    inTransaction = PR_TRUE;
+    crv = sftkdb_setAttributeValue(arena, handle, db, 
+				   objectID, template, count);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    crv = (*db->sdb_Commit)(db);
+loser:
+    if (crv != CKR_OK && inTransaction) {
+	(*db->sdb_Abort)(db);
+    }
+    if (data) {
+	PORT_Free(ntemplate);
+	PORT_Free(data);
+    }
+    if (arena) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return crv;
+}
+
+CK_RV
+sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID)
+{
+    CK_RV crv = CKR_OK;
+    SDB *db;
+
+    if (handle == NULL) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+    db = SFTK_GET_SDB(handle);
+    objectID &= SFTK_OBJ_ID_MASK;
+    crv = (*db->sdb_Begin)(db);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    crv = (*db->sdb_DestroyObject)(db, objectID);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    crv = (*db->sdb_Commit)(db);
+loser:
+    if (crv != CKR_OK) {
+	(*db->sdb_Abort)(db);
+    }
+    return crv;
+}
+
+CK_RV
+sftkdb_CloseDB(SFTKDBHandle *handle)
+{
+#ifdef NO_FORK_CHECK
+    PRBool parentForkedAfterC_Initialize = PR_FALSE;
+#endif
+    if (handle == NULL) {
+	return CKR_OK;
+    }
+    if (handle->update) {
+        if (handle->db->sdb_SetForkState) {
+            (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
+        }
+	(*handle->update->sdb_Close)(handle->update);
+    }
+    if (handle->db) {
+        if (handle->db->sdb_SetForkState) {
+            (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
+        }
+	(*handle->db->sdb_Close)(handle->db);
+    }
+    if (handle->passwordLock) {
+	SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock));
+    }
+    if (handle->updatePasswordKey) {
+	SECITEM_FreeItem(handle->updatePasswordKey, PR_TRUE);
+    }
+    if (handle->updateID) {
+	PORT_Free(handle->updateID);
+    }
+    PORT_Free(handle);
+    return CKR_OK;
+}
+
+/*
+ * reset a database to it's uninitialized state. 
+ */
+static CK_RV
+sftkdb_ResetDB(SFTKDBHandle *handle)
+{
+    CK_RV crv = CKR_OK;
+    SDB *db;
+    if (handle == NULL) {
+	return CKR_TOKEN_WRITE_PROTECTED;
+    }
+    db = SFTK_GET_SDB(handle);
+    crv = (*db->sdb_Begin)(db);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    crv = (*db->sdb_Reset)(db);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    crv = (*db->sdb_Commit)(db);
+loser:
+    if (crv != CKR_OK) {
+	(*db->sdb_Abort)(db);
+    }
+    return crv;
+}
+
+
+CK_RV
+sftkdb_Begin(SFTKDBHandle *handle)
+{
+    CK_RV crv = CKR_OK;
+    SDB *db;
+
+    if (handle == NULL) {
+	return CKR_OK;
+    }
+    db = SFTK_GET_SDB(handle);
+    if (db) {
+	crv = (*db->sdb_Begin)(db);
+    }
+    return crv;
+}
+
+CK_RV
+sftkdb_Commit(SFTKDBHandle *handle)
+{
+    CK_RV crv = CKR_OK;
+    SDB *db;
+
+    if (handle == NULL) {
+	return CKR_OK;
+    }
+    db = SFTK_GET_SDB(handle);
+    if (db) {
+	(*db->sdb_Commit)(db);
+    }
+    return crv;
+}
+
+CK_RV
+sftkdb_Abort(SFTKDBHandle *handle)
+{
+    CK_RV crv = CKR_OK;
+    SDB *db;
+
+    if (handle == NULL) {
+	return CKR_OK;
+    }
+    db = SFTK_GET_SDB(handle);
+    if (db) {
+	crv = (db->sdb_Abort)(db);
+    }
+    return crv;
+}
+
+
+/*
+ * functions to update the database from an old database
+ */
+
+/*
+ * known attributes
+ */
+static const CK_ATTRIBUTE_TYPE known_attributes[] = {
+    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
+    CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
+    CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED,
+    CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL,
+    CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY,
+    CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE,
+    CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER,
+    CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE,
+    CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
+    CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT,
+    CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, 
+    CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE,
+    CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
+    CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
+    CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+    CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE,
+    CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT,
+    CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS,
+    CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
+    CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
+    CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
+    CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL,
+    CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
+    CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
+    CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED,
+    CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC,
+    CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
+    CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
+    CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
+    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING,
+    CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM,
+    CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
+    CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
+    CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS
+};
+
+static int known_attributes_size= sizeof(known_attributes)/
+			   sizeof(known_attributes[0]);
+
+static CK_RV
+sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id,
+		CK_ATTRIBUTE *ptemplate, CK_ULONG *max)
+{
+    int i,j;
+    CK_RV crv;
+
+    if (*max < known_attributes_size) {
+	*max = known_attributes_size;
+	return CKR_BUFFER_TOO_SMALL;
+    }
+    for (i=0; i < known_attributes_size; i++) {
+	ptemplate[i].type = known_attributes[i];
+	ptemplate[i].pValue = NULL;
+	ptemplate[i].ulValueLen = 0;
+    }
+
+    crv = (*source->sdb_GetAttributeValue)(source, id, 
+					ptemplate, known_attributes_size);
+
+    if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
+	return crv;
+    }
+
+    for (i=0, j=0; i < known_attributes_size; i++, j++) {
+	while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) {
+	    i++;
+	}
+	if (i >= known_attributes_size) {
+	    break;
+	}
+	/* cheap optimization */
+	if (i == j) {
+	   continue;
+	}
+	ptemplate[j] = ptemplate[i];
+    }
+    *max = j;
+    return CKR_OK;
+}
+
+static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s";
+
+/*
+ * check to see if we have already updated this database.
+ * a NULL updateID means we are trying to do an in place 
+ * single database update. In that case we have already
+ * determined that an update was necessary.
+ */
+static PRBool 
+sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID)
+{
+    char *id;
+    CK_RV crv;
+    SECItem dummy = { 0, NULL, 0 };
+    unsigned char dummyData[SDB_MAX_META_DATA_LEN];
+
+    if (!updateID) {
+	return PR_FALSE;
+    }
+    id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
+    if (id == NULL) {
+	return PR_FALSE;
+    }
+    dummy.data = dummyData;
+    dummy.len = sizeof(dummyData);
+
+    crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL);
+    PR_smprintf_free(id);
+    return crv == CKR_OK ? PR_TRUE : PR_FALSE;
+}
+
+/*
+ * we just completed an update, store the update id
+ * so we don't need to do it again. If non was given,
+ * there is nothing to do.
+ */
+static CK_RV
+sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID)
+{
+    char *id;
+    CK_RV crv;
+    SECItem dummy = { 0, NULL, 0 };
+
+    /* if no id was given, nothing to do */
+    if (updateID == NULL) {
+	return CKR_OK;
+    }
+
+    dummy.data = (unsigned char *)updateID;
+    dummy.len = PORT_Strlen(updateID);
+
+    id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
+    if (id == NULL) {
+	return PR_FALSE;
+    }
+
+    crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL);
+    PR_smprintf_free(id);
+    return crv;
+}
+
+/*
+ * get a ULong attribute from a template:
+ * NOTE: this is a raw templated stored in database order!
+ */
+static CK_ULONG
+sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type, 
+			CK_ATTRIBUTE *ptemplate, CK_ULONG len)
+{
+    CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type,
+					ptemplate, len);
+
+    if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) {
+	return sftk_SDBULong2ULong(attr->pValue);
+    }
+    return (CK_ULONG)-1;
+}
+
+/*
+ * we need to find a unique CKA_ID.
+ *  The basic idea is to just increment the lowest byte.
+ *  This code also handles the following corner cases:
+ *   1) the single byte overflows. On overflow we increment the next byte up 
+ *    and so forth until we have overflowed the entire CKA_ID.
+ *   2) If we overflow the entire CKA_ID we expand it by one byte.
+ *   3) the CKA_ID is non-existant, we create a new one with one byte.
+ *    This means no matter what CKA_ID is passed, the result of this function 
+ *    is always a new CKA_ID, and this function will never return the same 
+ *    CKA_ID the it has returned in the passed.
+ */
+static CK_RV
+sftkdb_incrementCKAID(PRArenaPool *arena, CK_ATTRIBUTE *ptemplate)
+{
+    unsigned char *buf = ptemplate->pValue;
+    CK_ULONG len = ptemplate->ulValueLen;
+
+    if (buf == NULL || len == (CK_ULONG)-1) {
+	/* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
+	len = 0;
+    } else {
+	CK_ULONG i;
+
+	/* walk from the back to front, incrementing
+	 * the CKA_ID until we no longer have a carry,
+	 * or have hit the front of the id. */
+	for (i=len; i != 0; i--) {
+	    buf[i-1]++;
+	    if (buf[i-1] != 0) {
+		/* no more carries, the increment is complete */
+		return CKR_OK;
+	     }
+	}
+	/* we've now overflowed, fall through and expand the CKA_ID by 
+	 * one byte */
+    } 
+    buf = PORT_ArenaAlloc(arena, len+1);
+    if (!buf) {
+	return CKR_HOST_MEMORY;
+    }
+    if (len > 0) {
+	 PORT_Memcpy(buf, ptemplate->pValue, len);
+    }
+    buf[len] = 0;
+    ptemplate->pValue = buf;
+    ptemplate->ulValueLen = len+1;
+    return CKR_OK;
+}
+
+/*
+ * drop an attribute from a template.
+ */
+void
+sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate, 
+			CK_ULONG *plen)
+{
+   CK_ULONG count = *plen;
+   CK_ULONG i;
+
+   for (i=0; i < count; i++) {
+	if (attr->type == ptemplate[i].type) {
+	    break;
+	}
+   }
+
+   if (i == count) {
+	/* attribute not found */
+	return;
+   }
+
+   /* copy the remaining attributes up */
+   for ( i++; i < count; i++) {
+	ptemplate[i-1] = ptemplate[i];
+   }
+
+   /* decrement the template size */
+   *plen = count -1;
+}
+
+/*
+ * create some defines for the following functions to document the meaning
+ * of true/false. (make's it easier to remember what means what.
+ */
+typedef enum {
+	SFTKDB_DO_NOTHING = 0,
+	SFTKDB_ADD_OBJECT,
+	SFTKDB_MODIFY_OBJECT,
+	SFTKDB_DROP_ATTRIBUTE
+} sftkdbUpdateStatus;
+
+/*
+ * helper function to reconcile a single trust entry.
+ *   Identify which trust entry we want to keep.
+ *   If we don't need to do anything (the records are already equal).
+ *       return SFTKDB_DO_NOTHING.
+ *   If we want to use the source version,
+ *       return SFTKDB_MODIFY_OBJECT
+ *   If we want to use the target version,
+ *       return SFTKDB_DROP_ATTRIBUTE
+ *
+ *   In the end the caller will remove any attributes in the source
+ *   template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a 
+ *   set attributes with that template on the target if we received 
+ *   any SFTKDB_MODIFY_OBJECT returns.
+ */
+sftkdbUpdateStatus
+sftkdb_reconcileTrustEntry(PRArenaPool *arena, CK_ATTRIBUTE *target, 
+			   CK_ATTRIBUTE *source)
+{
+    CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type,
+			target, 1);
+    CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type,
+			source, 1);
+
+    /*
+     * try to pick the best solution between the source and the
+     * target. Update the source template if we want the target value
+     * to win out. Prefer cases where we don't actually update the
+     * trust entry.
+     */
+
+    /* they are the same, everything is already kosher */
+    if (targetTrust == sourceTrust) {
+	return SFTKDB_DO_NOTHING;
+    }
+
+    /* handle the case where the source Trust attribute may be a bit
+     * flakey */
+    if (sourceTrust == (CK_ULONG)-1) {
+	/*
+	 * The source Trust is invalid. We know that the target Trust
+	 * must be valid here, otherwise the above 
+	 * targetTrust == sourceTrust check would have succeeded.
+	 */
+	return SFTKDB_DROP_ATTRIBUTE;
+    }
+
+    /* target is invalid, use the source's idea of the trust value */
+    if (targetTrust == (CK_ULONG)-1) {
+	/* overwriting the target in this case is OK */
+	return SFTKDB_MODIFY_OBJECT;
+    }
+
+    /* at this point we know that both attributes exist and have the
+     * appropriate length (SDB_ULONG_SIZE). We no longer need to check
+     * ulValueLen for either attribute.
+     */
+    if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) {
+	return SFTKDB_DROP_ATTRIBUTE;
+    }
+
+    /* target has no idea, use the source's idea of the trust value */
+    if (targetTrust == CKT_NSS_TRUST_UNKNOWN) {
+	/* overwriting the target in this case is OK */
+	return SFTKDB_MODIFY_OBJECT;
+    }
+
+    /* so both the target and the source have some idea of what this 
+     * trust attribute should be, and neither agree exactly. 
+     * At this point, we prefer 'hard' attributes over 'soft' ones. 
+     * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and
+     * CKT_NSS_UNTRUTED. Soft ones are ones which don't change the
+     * actual trust of the cert (CKT_MUST_VERIFY, CKT_NSS_VALID,
+     * CKT_NSS_VALID_DELEGATOR).
+     */
+    if ((sourceTrust == CKT_NSS_MUST_VERIFY) 
+	|| (sourceTrust == CKT_NSS_VALID)
+	|| (sourceTrust == CKT_NSS_VALID_DELEGATOR)) {
+	return SFTKDB_DROP_ATTRIBUTE;
+    }
+    if ((targetTrust == CKT_NSS_MUST_VERIFY) 
+	|| (targetTrust == CKT_NSS_VALID)
+	|| (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
+	/* again, overwriting the target in this case is OK */
+	return SFTKDB_MODIFY_OBJECT;
+    }
+
+    /* both have hard attributes, we have a conflict, let the target win. */
+    return SFTKDB_DROP_ATTRIBUTE;
+}
+
+const CK_ATTRIBUTE_TYPE sftkdb_trustList[] =
+	{ CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH,
+	  CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION,
+	  CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER,
+	  CKA_TRUST_TIME_STAMPING };
+
+#define SFTK_TRUST_TEMPLATE_COUNT \
+		(sizeof(sftkdb_trustList)/sizeof(sftkdb_trustList[0]))
+/*
+ * Run through the list of known trust types, and reconcile each trust
+ * entry one by one. Keep track of we really need to write out the source
+ * trust object (overwriting the existing one).
+ */
+static sftkdbUpdateStatus
+sftkdb_reconcileTrust(PRArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, 
+		      CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
+{
+    CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT];
+    unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT*SDB_ULONG_SIZE];
+    sftkdbUpdateStatus update = SFTKDB_DO_NOTHING;
+    CK_ULONG i;
+    CK_RV crv;
+
+
+    for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT;  i++) {
+	trustTemplate[i].type = sftkdb_trustList[i];
+	trustTemplate[i].pValue = &trustData[i*SDB_ULONG_SIZE];
+	trustTemplate[i].ulValueLen = SDB_ULONG_SIZE;
+    }
+    crv = (*db->sdb_GetAttributeValue)(db, id, 
+				trustTemplate, SFTK_TRUST_TEMPLATE_COUNT);
+    if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
+	/* target trust has some problems, update it */
+	update = SFTKDB_MODIFY_OBJECT;
+	goto done;
+    }
+
+    for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) {
+	CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(
+			trustTemplate[i].type, ptemplate, *plen);
+	sftkdbUpdateStatus status;
+
+
+	/* if target trust value doesn't exist, nothing to merge */
+	if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) {
+	    /* if the source exists, then we want the source entry,
+	     * go ahead and update */
+	    if (attr && attr->ulValueLen != (CK_ULONG)-1) {
+		update = SFTKDB_MODIFY_OBJECT;
+	    }
+	    continue;
+	}
+
+	/*
+	 * the source doesn't have the attribute, go to the next attribute
+	 */
+	if (attr == NULL) {
+	    continue;
+		
+	}
+	status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr);
+	if (status == SFTKDB_MODIFY_OBJECT) {
+	    update = SFTKDB_MODIFY_OBJECT;
+	} else if (status == SFTKDB_DROP_ATTRIBUTE) {
+	    /* drop the source copy of the attribute, we are going with
+	     * the target's version */
+	    sftkdb_dropAttribute(attr, ptemplate, plen);
+	}
+    }
+
+    /* finally manage stepup */
+    if (update == SFTKDB_MODIFY_OBJECT) {
+	CK_BBOOL stepUpBool = CK_FALSE;
+	/* if we are going to write from the source, make sure we don't
+	 * overwrite the stepup bit if it's on*/
+	trustTemplate[0].type = CKA_TRUST_STEP_UP_APPROVED;
+	trustTemplate[0].pValue = &stepUpBool;
+	trustTemplate[0].ulValueLen = sizeof(stepUpBool);
+    	crv = (*db->sdb_GetAttributeValue)(db, id, trustTemplate, 1);
+	if ((crv == CKR_OK) && (stepUpBool == CK_TRUE)) {
+	    sftkdb_dropAttribute(trustTemplate, ptemplate, plen);
+	}
+    } else {
+	/* we currently aren't going to update. If the source stepup bit is
+	 * on however, do an update so the target gets it as well */
+	CK_ATTRIBUTE *attr;
+
+	attr = sftkdb_getAttributeFromTemplate(CKA_TRUST_STEP_UP_APPROVED,
+			ptemplate, *plen);
+	if (attr && (attr->ulValueLen == sizeof(CK_BBOOL)) &&  
+			(*(CK_BBOOL *)(attr->pValue) == CK_TRUE)) {
+		update = SFTKDB_MODIFY_OBJECT;
+	}
+    }
+    
+done:
+    return update;
+}
+
+static sftkdbUpdateStatus
+sftkdb_handleIDAndName(PRArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, 
+		      CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
+{
+    sftkdbUpdateStatus update = SFTKDB_DO_NOTHING;
+    CK_ATTRIBUTE *attr1, *attr2;
+    CK_ATTRIBUTE ttemplate[2] = {
+	{CKA_ID, NULL, 0},
+	{CKA_LABEL, NULL, 0}
+    };
+    CK_RV crv;
+
+    attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
+    attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen);
+
+    /* if the source has neither an id nor label, don't bother updating */
+    if ( (!attr1 || attr1->ulValueLen == 0) &&
+	 (! attr2 ||  attr2->ulValueLen == 0) ) {
+	return SFTKDB_DO_NOTHING;
+    }
+
+    /* the source has either an id or a label, see what the target has */
+    crv = (*db->sdb_GetAttributeValue)(db, id, ttemplate, 2);
+
+    /* if the target has neither, update from the source */
+    if ( ((ttemplate[0].ulValueLen == 0) || 
+	  (ttemplate[0].ulValueLen == (CK_ULONG)-1))  &&
+         ((ttemplate[1].ulValueLen == 0) || 
+	  (ttemplate[1].ulValueLen == (CK_ULONG)-1)) ) {
+	return SFTKDB_MODIFY_OBJECT;
+    }
+
+    /* check the CKA_ID */
+    if ((ttemplate[0].ulValueLen != 0) && 
+	(ttemplate[0].ulValueLen != (CK_ULONG)-1)) {
+	/* we have a CKA_ID in the target, don't overwrite
+	 * the target with an empty CKA_ID from the source*/
+	if (attr1 && attr1->ulValueLen == 0) {
+	    sftkdb_dropAttribute(attr1, ptemplate, plen);
+	}
+    } else if (attr1 && attr1->ulValueLen != 0) {
+	/* source has a CKA_ID, but the target doesn't, update the target */
+	update = SFTKDB_MODIFY_OBJECT;
+    }
+
+
+    /* check the nickname */
+    if ((ttemplate[1].ulValueLen != 0) && 
+	(ttemplate[1].ulValueLen != (CK_ULONG)-1)) {
+
+	/* we have a nickname in the target, and we don't have to update
+	 * the CKA_ID. We are done. NOTE: if we add addition attributes
+	 * in this check, this shortcut can only go on the last of them. */
+	if (update == SFTKDB_DO_NOTHING) {
+	    return update;
+	}
+	/* we have a nickname in the target, don't overwrite
+	 * the target with an empty nickname from the source */
+	if (attr2 && attr2->ulValueLen == 0) {
+	    sftkdb_dropAttribute(attr2, ptemplate, plen);
+	}
+    } else if (attr2 && attr2->ulValueLen != 0) {
+	/* source has a nickname, but the target doesn't, update the target */
+	update = SFTKDB_MODIFY_OBJECT;
+    }
+
+    return update;
+}
+
+
+		
+/*
+ * This function updates the template before we write the object out.
+ *
+ * If we are going to skip updating this object, return PR_FALSE.
+ * If it should be updated we return PR_TRUE.
+ * To help readability, these have been defined 
+ * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively.
+ */
+static PRBool
+sftkdb_updateObjectTemplate(PRArenaPool *arena, SDB *db, 
+		    CK_OBJECT_CLASS objectType, 
+		    CK_ATTRIBUTE *ptemplate, CK_ULONG *plen,
+		    CK_OBJECT_HANDLE *targetID)
+{
+    PRBool done; /* should we repeat the loop? */
+    CK_OBJECT_HANDLE id;
+    CK_RV crv = CKR_OK;
+
+    do {
+ 	crv = sftkdb_checkConflicts(db, objectType, ptemplate, 
+						*plen, CK_INVALID_HANDLE);
+	if (crv != CKR_ATTRIBUTE_VALUE_INVALID) {
+	    break;
+	}
+	crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen);
+    } while (crv == CKR_OK);
+
+    if (crv != CKR_OK) {
+	return SFTKDB_DO_NOTHING;
+    }
+
+    do {
+	done = PR_TRUE;
+	crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen);
+	if (crv != CKR_OK) {
+	    return SFTKDB_DO_NOTHING;
+	}
+
+	/* This object already exists, merge it, don't update */
+	if (id != CK_INVALID_HANDLE) {
+    	    CK_ATTRIBUTE *attr = NULL;
+	    /* special post processing for attributes */
+	    switch (objectType) {
+	    case CKO_CERTIFICATE:
+	    case CKO_PUBLIC_KEY:
+	    case CKO_PRIVATE_KEY:
+		/* update target's CKA_ID and labels if they don't already 
+		 * exist */
+		*targetID = id;
+		return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen);
+	    case CKO_NSS_TRUST:
+		/* if we have conflicting trust object types,
+		 * we need to reconcile them */
+		*targetID = id;
+		return sftkdb_reconcileTrust(arena, db, id, ptemplate, plen);
+	    case CKO_SECRET_KEY:
+		/* secret keys in the old database are all sdr keys, 
+		 * unfortunately they all appear to have the same CKA_ID, 
+		 * even though they are truly different keys, so we always 
+		 * want to update these keys, but we need to 
+		 * give them a new CKA_ID */
+		/* NOTE: this changes ptemplate */
+		attr = sftkdb_getAttributeFromTemplate(CKA_ID,ptemplate,*plen);
+		crv = attr ? sftkdb_incrementCKAID(arena, attr) 
+		           : CKR_HOST_MEMORY; 
+		/* in the extremely rare event that we needed memory and
+		 * couldn't get it, just drop the key */
+		if (crv != CKR_OK) {
+		    return SFTKDB_DO_NOTHING;
+		}
+		done = PR_FALSE; /* repeat this find loop */
+		break;
+	    default:
+		/* for all other objects, if we found the equivalent object,
+		 * don't update it */
+	        return SFTKDB_DO_NOTHING;
+	    }
+	}
+    } while (!done);
+
+    /* this object doesn't exist, update it */
+    return SFTKDB_ADD_OBJECT;
+}
+
+
+#define MAX_ATTRIBUTES 500
+static CK_RV
+sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, 
+		   SECItem *key)
+{
+    CK_ATTRIBUTE template[MAX_ATTRIBUTES];
+    CK_ATTRIBUTE *ptemplate;
+    CK_ULONG max_attributes = MAX_ATTRIBUTES;
+    CK_OBJECT_CLASS objectType;
+    SDB *source = handle->update;
+    SDB *target = handle->db;
+    int i;
+    CK_RV crv;
+    PLArenaPool *arena = NULL;
+
+    arena = PORT_NewArena(256);
+    if (arena ==  NULL) {
+	return CKR_HOST_MEMORY;
+    }
+
+    ptemplate = &template[0];
+    id &= SFTK_OBJ_ID_MASK;
+    crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes);
+    if (crv == CKR_BUFFER_TOO_SMALL) {
+	ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes);
+	if (ptemplate == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	} else {
+            crv = sftkdb_GetObjectTemplate(source, id, 
+					   ptemplate, &max_attributes);
+	}
+    }
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    for (i=0; i < max_attributes; i++) {
+	ptemplate[i].pValue = PORT_ArenaAlloc(arena,ptemplate[i].ulValueLen);
+	if (ptemplate[i].pValue == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+    }
+    crv = (*source->sdb_GetAttributeValue)(source, id, 
+					   ptemplate, max_attributes);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate,
+							 max_attributes);
+
+    /*
+     * Update Object updates the object template if necessary then returns 
+     * whether or not we need to actually write the object out to our target 
+     * database.
+     */
+    if (!handle->updateID) {
+	    crv = sftkdb_CreateObject(arena, handle, target, &id, 
+				ptemplate, max_attributes);
+    } else {
+	sftkdbUpdateStatus update_status;
+	update_status  = sftkdb_updateObjectTemplate(arena, target, 
+			objectType, ptemplate, &max_attributes, &id);
+	switch (update_status) {
+	case SFTKDB_ADD_OBJECT:
+	    crv = sftkdb_CreateObject(arena, handle, target, &id, 
+				ptemplate, max_attributes);
+	    break;
+	case SFTKDB_MODIFY_OBJECT:
+    	    crv = sftkdb_setAttributeValue(arena, handle, target, 
+				   id, ptemplate, max_attributes);
+	    break;
+	case SFTKDB_DO_NOTHING:
+	case SFTKDB_DROP_ATTRIBUTE:
+	    break;
+	}
+    } 
+
+loser:
+    if (arena) {
+	PORT_FreeArena(arena,PR_TRUE);
+    }
+    return crv;
+}
+	
+
+#define MAX_IDS 10
+/*
+ * update a new database from an old one, now that we have the key
+ */
+CK_RV
+sftkdb_Update(SFTKDBHandle *handle, SECItem *key)
+{
+    SDBFind *find = NULL;
+    CK_ULONG idCount = MAX_IDS;
+    CK_OBJECT_HANDLE ids[MAX_IDS];
+    SECItem *updatePasswordKey = NULL;
+    CK_RV crv, crv2;
+    PRBool inTransaction = PR_FALSE;
+    int i;
+
+    if (handle == NULL) {
+	return CKR_OK;
+    }
+    if (handle->update == NULL) {
+	return CKR_OK;
+    }
+
+    /*
+     * put the whole update under a transaction. This allows us to handle
+     * any possible race conditions between with the updateID check.
+     */
+    crv = (*handle->db->sdb_Begin)(handle->db);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    inTransaction = PR_TRUE;
+    
+    /* some one else has already updated this db */
+    if (sftkdb_hasUpdate(sftkdb_TypeString(handle), 
+			 handle->db, handle->updateID)) {
+	crv = CKR_OK;
+	goto done;
+    }
+
+    updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle);
+    if (updatePasswordKey) {
+	/* pass the source DB key to the legacy code, 
+	 * so it can decrypt things */
+	handle->oldKey = updatePasswordKey;
+    }
+    
+    /* find all the objects */
+    crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find);
+
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+    while ((crv == CKR_OK) && (idCount == MAX_IDS)) {
+	crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount);
+	for (i=0; (crv == CKR_OK) && (i < idCount); i++) {
+	    crv = sftkdb_mergeObject(handle, ids[i], key);
+	}
+    }
+    crv2 = sftkdb_FindObjectsFinal(handle, find);
+    if (crv == CKR_OK) crv = crv2;
+
+loser:
+    /* no longer need the old key value */
+    handle->oldKey = NULL;
+
+    /* update the password - even if we didn't update objects */
+    if (handle->type == SFTK_KEYDB_TYPE) {
+	SECItem item1, item2;
+	unsigned char data1[SDB_MAX_META_DATA_LEN];
+	unsigned char data2[SDB_MAX_META_DATA_LEN];
+
+	item1.data = data1;
+ 	item1.len = sizeof(data1);
+	item2.data = data2;
+ 	item2.len = sizeof(data2);
+
+	/* if the target db already has a password, skip this. */
+	crv = (*handle->db->sdb_GetMetaData)(handle->db, "password",
+			&item1, &item2);
+	if (crv == CKR_OK) {
+	    goto done;
+	}
+
+
+	/* nope, update it from the source */
+	crv = (*handle->update->sdb_GetMetaData)(handle->update, "password",
+			&item1, &item2);
+	if (crv != CKR_OK) {
+	    goto done;
+	}
+	crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1,
+						&item2);
+	if (crv != CKR_OK) {
+	    goto done;
+	}
+    }
+
+done:
+    /* finally mark this up to date db up to date */
+    /* some one else has already updated this db */
+    if (crv == CKR_OK) {
+	crv = sftkdb_putUpdate(sftkdb_TypeString(handle), 
+				handle->db, handle->updateID);
+    }
+
+    if (inTransaction) {
+	if (crv == CKR_OK) {
+	    crv = (*handle->db->sdb_Commit)(handle->db);
+	} else {
+	    (*handle->db->sdb_Abort)(handle->db);
+	}
+    }
+    if (handle->update) {
+	(*handle->update->sdb_Close)(handle->update);
+	handle->update = NULL;
+    }
+    if (handle->updateID) {
+	PORT_Free(handle->updateID);
+	handle->updateID = NULL;
+    }
+    sftkdb_FreeUpdatePasswordKey(handle);
+    if (updatePasswordKey) {
+	SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE);
+    }
+    handle->updateDBIsInit = PR_FALSE;
+    return crv;
+}
+
+/******************************************************************
+ * DB handle managing functions.
+ * 
+ * These functions are called by softoken to initialize, acquire,
+ * and release database handles.
+ */
+
+const char *
+sftkdb_GetUpdateID(SFTKDBHandle *handle)
+{
+    return handle->updateID;
+}
+
+/* release a database handle */
+void
+sftk_freeDB(SFTKDBHandle *handle)
+{
+    PRInt32 ref;
+
+    if (!handle) return;
+    ref = PR_AtomicDecrement(&handle->ref);
+    if (ref == 0) {
+	sftkdb_CloseDB(handle);
+    }
+    return;
+}
+
+
+/*
+ * acquire a database handle for a certificate db  
+ * (database for public objects) 
+ */
+SFTKDBHandle *
+sftk_getCertDB(SFTKSlot *slot)
+{
+    SFTKDBHandle *dbHandle;
+
+    PZ_Lock(slot->slotLock);
+    dbHandle = slot->certDB;
+    if (dbHandle) {
+        PR_AtomicIncrement(&dbHandle->ref);
+    }
+    PZ_Unlock(slot->slotLock);
+    return dbHandle;
+}
+
+/*
+ * acquire a database handle for a key database 
+ * (database for private objects)
+ */
+SFTKDBHandle *
+sftk_getKeyDB(SFTKSlot *slot)
+{
+    SFTKDBHandle *dbHandle;
+
+    SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
+    dbHandle = slot->keyDB;
+    if (dbHandle) {
+        PR_AtomicIncrement(&dbHandle->ref);
+    }
+    SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
+    return dbHandle;
+}
+
+/*
+ * acquire the database for a specific object. NOTE: objectID must point
+ * to a Token object!
+ */
+SFTKDBHandle *
+sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID)
+{
+    SFTKDBHandle *dbHandle;
+
+    PZ_Lock(slot->slotLock);
+    dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB;
+    if (dbHandle) {
+        PR_AtomicIncrement(&dbHandle->ref);
+    }
+    PZ_Unlock(slot->slotLock);
+    return dbHandle;
+}
+
+/*
+ * initialize a new database handle
+ */
+static SFTKDBHandle *
+sftk_NewDBHandle(SDB *sdb, int type)
+{
+   SFTKDBHandle *handle = PORT_New(SFTKDBHandle);
+   handle->ref = 1;
+   handle->db = sdb;
+   handle->update = NULL;
+   handle->peerDB = NULL;
+   handle->newKey = NULL;
+   handle->oldKey = NULL;
+   handle->updatePasswordKey = NULL;
+   handle->updateID = NULL;
+   handle->type = type;
+   handle->passwordKey.data = NULL;
+   handle->passwordKey.len = 0;
+   handle->passwordLock = NULL;
+   if (type == SFTK_KEYDB_TYPE) {
+	handle->passwordLock = PZ_NewLock(nssILockAttribute);
+   }
+   sdb->app_private = handle;
+   return handle;
+}
+
+/*
+ * reset the key database to it's uninitialized state. This call
+ * will clear all the key entried.
+ */
+SECStatus
+sftkdb_ResetKeyDB(SFTKDBHandle *handle)
+{
+    CK_RV crv;
+
+    /* only rest the key db */
+    if (handle->type != SFTK_KEYDB_TYPE) {
+	return SECFailure;
+    }
+    crv = sftkdb_ResetDB(handle);
+    if (crv != CKR_OK) {
+	/* set error */
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+static PRBool
+sftk_oldVersionExists(const char *dir, int version)
+{
+    int i;
+    PRStatus exists = PR_FAILURE;
+    char *file = NULL;
+
+    for (i=version; i > 1 ; i--) {
+	file = PR_smprintf("%s%d.db",dir,i);
+	if (file == NULL) {
+	    continue;
+	}
+	exists = PR_Access(file, PR_ACCESS_EXISTS);
+	PR_smprintf_free(file);
+	if (exists == PR_SUCCESS) {
+	    return PR_TRUE;
+	}
+    }
+    return PR_FALSE;
+}
+
+static PRBool
+sftk_hasLegacyDB(const char *confdir, const char *certPrefix, 
+		 const char *keyPrefix, int certVersion, int keyVersion)
+{
+    char *dir;
+    PRBool exists;
+
+    if (certPrefix == NULL) {
+	certPrefix = "";
+    }
+
+    if (keyPrefix == NULL) {
+	keyPrefix = "";
+    }
+
+    dir= PR_smprintf("%s/%scert", confdir, certPrefix);
+    if (dir == NULL) {
+	return PR_FALSE;
+    }
+
+    exists = sftk_oldVersionExists(dir, certVersion);
+    PR_smprintf_free(dir);
+    if (exists) {
+	return PR_TRUE;
+    }
+
+    dir= PR_smprintf("%s/%skey", confdir, keyPrefix);
+    if (dir == NULL) {
+	return PR_FALSE;
+    }
+
+    exists = sftk_oldVersionExists(dir, keyVersion);
+    PR_smprintf_free(dir);
+    return exists;
+}
+
+/*
+ * initialize certificate and key database handles as a pair.
+ *
+ * This function figures out what type of database we are opening and
+ * calls the appropriate low level function to open the database.
+ * It also figures out whether or not to setup up automatic update.
+ */
+CK_RV 
+sftk_DBInit(const char *configdir, const char *certPrefix,
+                const char *keyPrefix, const char *updatedir,
+		const char *updCertPrefix, const char *updKeyPrefix, 
+		const char *updateID, PRBool readOnly, PRBool noCertDB,
+                PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS,
+                SFTKDBHandle **certDB, SFTKDBHandle **keyDB)
+{
+    const char *confdir;
+    SDBType dbType;
+    char *appName = NULL;
+    SDB *keySDB, *certSDB;
+    CK_RV crv = CKR_OK;
+    int flags = SDB_RDONLY;
+    PRBool newInit = PR_FALSE;
+    PRBool needUpdate = PR_FALSE;
+
+    if (!readOnly) {
+	flags = SDB_CREATE;
+    }
+
+    *certDB = NULL;
+    *keyDB = NULL;
+
+    if (noKeyDB && noCertDB) {
+	return CKR_OK;
+    }
+    confdir = sftk_EvaluateConfigDir(configdir, &dbType, &appName);
+
+    /*
+     * now initialize the appropriate database
+     */
+    switch (dbType) {
+    case SDB_LEGACY:
+	crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
+		 isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB);
+	break;
+    case SDB_MULTIACCESS:
+	crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags,
+		isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB);
+	break;
+    case SDB_SQL:
+    case SDB_EXTERN: /* SHOULD open a loadable db */
+	crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags, 
+		noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit);
+
+        /*
+	 * if we failed to open the DB's read only, use the old ones if
+	 * the exists.
+	 */
+	if (crv != CKR_OK) {
+	    if ((flags == SDB_RDONLY)  &&
+	         sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) {
+	    /* we have legacy databases, if we failed to open the new format 
+	     * DB's read only, just use the legacy ones */
+		crv = sftkdbCall_open(confdir, certPrefix, 
+			keyPrefix, 8, 3, flags, isFIPS, 
+			noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
+	    }
+	/* Handle the database merge case.
+         *
+         * For the merge case, we need help from the application. Only
+         * the application knows where the old database is, and what unique
+         * identifier it has associated with it.
+         *
+         * If the client supplies these values, we use them to determine
+         * if we need to update.
+         */
+	} else if (
+	      /* both update params have been supplied */
+	      updatedir  && *updatedir && updateID  && *updateID
+	      /* old dbs exist? */
+	      && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3) 
+	      /* and they have not yet been updated? */
+	      && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID)) 
+	      || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) {
+	    /* we need to update */
+	    confdir = updatedir;
+	    certPrefix = updCertPrefix;
+	    keyPrefix = updKeyPrefix;
+	    needUpdate = PR_TRUE;
+	} else if (newInit) {
+	    /* if the new format DB was also a newly created DB, and we
+	     * succeeded, then need to update that new database with data
+	     * from the existing legacy DB */
+	    if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) {
+		needUpdate = PR_TRUE;
+	    }
+	}
+	break;
+    default:
+	crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST 
+				  * return one of the types we already 
+				  * specified. */
+    }
+    if (crv != CKR_OK) {
+	goto done;
+    }
+    if (!noCertDB) {
+	*certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE);
+    } else {
+	*certDB = NULL;
+    }
+    if (!noKeyDB) {
+	*keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE);
+    } else {
+	*keyDB = NULL;
+    }
+
+    /* link them together */
+    if (*certDB) {
+	(*certDB)->peerDB = *keyDB;
+    }
+    if (*keyDB) {
+	(*keyDB)->peerDB = *certDB;
+    }
+
+    /*
+     * if we need to update, open the legacy database and
+     * mark the handle as needing update.
+     */
+    if (needUpdate) {
+	SDB *updateCert = NULL;
+	SDB *updateKey = NULL;
+	CK_RV crv2;
+
+	crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
+		isFIPS, noCertDB ? NULL : &updateCert, 
+		noKeyDB ? NULL : &updateKey);
+	if (crv2 == CKR_OK) {
+	    if (*certDB) {
+		(*certDB)->update = updateCert;
+		(*certDB)->updateID = updateID && *updateID 
+				? PORT_Strdup(updateID) : NULL;
+		updateCert->app_private = (*certDB);
+	    }
+	    if (*keyDB) {
+		PRBool tokenRemoved = PR_FALSE;
+		(*keyDB)->update = updateKey;
+		(*keyDB)->updateID = updateID && *updateID ? 
+					PORT_Strdup(updateID) : NULL;
+		updateKey->app_private = (*keyDB);
+		(*keyDB)->updateDBIsInit = PR_TRUE;
+		(*keyDB)->updateDBIsInit = 
+			(sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ?
+			 PR_TRUE : PR_FALSE;
+		/* if the password on the key db is NULL, kick off our update
+		 * chain of events */
+		sftkdb_CheckPassword((*keyDB), "", &tokenRemoved);
+	    } else {
+		/* we don't have a key DB, update the certificate DB now */
+		sftkdb_Update(*certDB, NULL);
+	    }
+	}
+    }
+done:
+    if (appName) {
+	PORT_Free(appName);
+    }
+   return forceOpen ? CKR_OK : crv;
+}
+
+CK_RV 
+sftkdb_Shutdown(void)
+{
+  s_shutdown();
+  sftkdbCall_Shutdown();
+  return CKR_OK;
+}
+
diff --git a/mozilla/security/nss/lib/softoken/sftkdb.h b/mozilla/security/nss/lib/softoken/sftkdb.h
new file mode 100644
index 0000000..2806d6f
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkdb.h
@@ -0,0 +1,118 @@
+/* ***** 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
+ * Red Hat Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 "sftkdbt.h"
+#include "sdb.h"
+#include "pkcs11i.h"
+#include "pkcs11t.h"
+
+/* raw database stuff */
+CK_RV sftkdb_write(SFTKDBHandle *handle, SFTKObject *,CK_OBJECT_HANDLE *);
+CK_RV sftkdb_FindObjectsInit(SFTKDBHandle *sdb, const CK_ATTRIBUTE *template,
+				 CK_ULONG count, SDBFind **find);
+CK_RV sftkdb_FindObjects(SFTKDBHandle *sdb, SDBFind *find, 
+			CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count);
+CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *sdb, SDBFind *find);
+CK_RV sftkdb_GetAttributeValue(SFTKDBHandle *handle,
+	 CK_OBJECT_HANDLE object_id, CK_ATTRIBUTE *template, CK_ULONG count);
+CK_RV sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object, 
+	 		const CK_ATTRIBUTE *template, CK_ULONG count);
+CK_RV sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id);
+CK_RV sftkdb_closeDB(SFTKDBHandle *handle);
+
+
+/* secmod.db functions */
+char ** sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, 
+			    const char *filename, const char *dbname, 
+			    char *params, PRBool rw);
+SECStatus sftkdb_ReleaseSecmodDBData(SDBType dbType, const char *appName, 
+				     const char *filename, const char *dbname, 
+				     char **moduleSpecList, PRBool rw);
+SECStatus sftkdb_DeleteSecmodDB(SDBType dbType, const char *appName, 
+				const char *filename, const char *dbname, 
+				char *args, PRBool rw);
+SECStatus sftkdb_AddSecmodDB(SDBType dbType, const char *appName, 
+			     const char *filename, const char *dbname, 
+			     char *module, PRBool rw);
+
+/* keydb functions */
+
+SECStatus sftkdb_PWIsInitialized(SFTKDBHandle *keydb);
+SECStatus sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw,
+			       PRBool *tokenRemoved);
+SECStatus sftkdb_PWCached(SFTKDBHandle *keydb);
+SECStatus sftkdb_HasPasswordSet(SFTKDBHandle *keydb);
+SECStatus sftkdb_ResetKeyDB(SFTKDBHandle *keydb);
+SECStatus sftkdb_ChangePassword(SFTKDBHandle *keydb, 
+				char *oldPin, char *newPin,
+				PRBool *tokenRemoved);
+SECStatus sftkdb_ClearPassword(SFTKDBHandle *keydb);
+PRBool sftkdb_InUpdateMerge(SFTKDBHandle *keydb);
+PRBool sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb);
+const char *sftkdb_GetUpdateID(SFTKDBHandle *keydb);
+SECItem *sftkdb_GetUpdatePasswordKey(SFTKDBHandle *keydb);
+void sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *keydb);
+
+/* Utility functions */
+/*
+ * OK there are now lots of options here, lets go through them all:
+ *
+ * configdir - base directory where all the cert, key, and module datbases live.
+ * certPrefix - prefix added to the beginning of the cert database example: "
+ *                      "https-server1-"
+ * keyPrefix - prefix added to the beginning of the key database example: "
+ *                      "https-server1-"
+ * secmodName - name of the security module database (usually "secmod.db").
+ * readOnly - Boolean: true if the databases are to be openned read only.
+ * nocertdb - Don't open the cert DB and key DB's, just initialize the
+ *                      Volatile certdb.
+ * nomoddb - Don't open the security module DB, just initialize the
+ *                      PKCS #11 module.
+ * forceOpen - Continue to force initializations even if the databases cannot
+ *                      be opened.
+ */
+CK_RV sftk_DBInit(const char *configdir, const char *certPrefix,
+	 	const char *keyPrefix, const char *updatedir, 
+		const char *updCertPrefix, const char *updKeyPrefix,
+		const char *updateID, PRBool readOnly, PRBool noCertDB, 
+		PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS,
+		SFTKDBHandle **certDB, SFTKDBHandle **keyDB);
+CK_RV sftkdb_Shutdown(void);
+
+SFTKDBHandle *sftk_getCertDB(SFTKSlot *slot);
+SFTKDBHandle *sftk_getKeyDB(SFTKSlot *slot);
+SFTKDBHandle *sftk_getDBForTokenObject(SFTKSlot *slot, 
+                                       CK_OBJECT_HANDLE objectID);
+void sftk_freeDB(SFTKDBHandle *certHandle);
diff --git a/mozilla/security/nss/lib/softoken/sftkdbt.h b/mozilla/security/nss/lib/softoken/sftkdbt.h
new file mode 100644
index 0000000..f8cdb06
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkdbt.h
@@ -0,0 +1,51 @@
+/* ***** 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
+ * Red Hat Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 ***** */
+
+#ifndef SFTKDBT_H
+#define SFTKDBT_H 1
+typedef struct SFTKDBHandleStr SFTKDBHandle;
+
+#define SDB_MAX_META_DATA_LEN	256
+#define SDB_ULONG_SIZE 4
+
+typedef enum {
+   SDB_SQL,
+   SDB_EXTERN,
+   SDB_LEGACY,
+   SDB_MULTIACCESS
+} SDBType;
+
+#endif
diff --git a/mozilla/security/nss/lib/softoken/sftkdbti.h b/mozilla/security/nss/lib/softoken/sftkdbti.h
new file mode 100644
index 0000000..efaf842
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkdbti.h
@@ -0,0 +1,92 @@
+/* ***** 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
+ * Red Hat Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 ***** */
+
+#ifndef SFTKDBTI_H
+#define SFTKDBTI_H 1
+
+/*
+ * private defines
+ */
+struct SFTKDBHandleStr {
+    SDB   *db;
+    PRInt32 ref;
+    CK_OBJECT_HANDLE  type;
+    SECItem passwordKey;
+    SECItem *newKey;
+    SECItem *oldKey;
+    SECItem *updatePasswordKey;
+    PZLock *passwordLock;
+    SFTKDBHandle *peerDB;
+    SDB   *update;
+    char  *updateID;
+    PRBool updateDBIsInit;
+};
+
+#define SFTK_KEYDB_TYPE 0x40000000
+#define SFTK_CERTDB_TYPE 0x00000000
+#define SFTK_OBJ_TYPE_MASK 0xc0000000
+#define SFTK_OBJ_ID_MASK (~SFTK_OBJ_TYPE_MASK)
+#define SFTK_TOKEN_TYPE 0x80000000
+
+/* the following is the number of id's to handle on the stack at a time,
+ * it's not an upper limit of IDS that can be stored in the database */
+#define SFTK_MAX_IDS 10
+
+#define SFTK_GET_SDB(handle) \
+	((handle)->update ? (handle)->update : (handle)->db)
+
+SECStatus sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText,
+			SECItem **plainText);
+SECStatus sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey,
+			SECItem *plainText, SECItem **cipherText);
+SECStatus sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey,
+			CK_OBJECT_HANDLE objectID,
+			CK_ATTRIBUTE_TYPE attrType,
+			SECItem *plainText, SECItem **sigText);
+SECStatus sftkdb_VerifyAttribute(SECItem *passKey,
+			CK_OBJECT_HANDLE objectID,
+			CK_ATTRIBUTE_TYPE attrType,
+			SECItem *plainText, SECItem *sigText);
+
+void sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value);
+CK_RV sftkdb_Update(SFTKDBHandle *handle, SECItem *key);
+CK_RV sftkdb_PutAttributeSignature(SFTKDBHandle *handle, 
+		SDB *keyTarget, CK_OBJECT_HANDLE objectID, 
+		CK_ATTRIBUTE_TYPE type, SECItem *signText);
+
+
+
+#endif
diff --git a/mozilla/security/nss/lib/softoken/sftkmod.c b/mozilla/security/nss/lib/softoken/sftkmod.c
new file mode 100644
index 0000000..c89b7da
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkmod.c
@@ -0,0 +1,734 @@
+/* ***** 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-2007
+ * 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 ***** */
+/* 
+ *  The following code handles the storage of PKCS 11 modules used by the
+ * NSS. For the rest of NSS, only one kind of database handle exists:
+ *
+ *     SFTKDBHandle
+ *
+ * There is one SFTKDBHandle for the each key database and one for each cert 
+ * database. These databases are opened as associated pairs, one pair per
+ * slot. SFTKDBHandles are reference counted objects.
+ *
+ * Each SFTKDBHandle points to a low level database handle (SDB). This handle
+ * represents the underlying physical database. These objects are not 
+ * reference counted, an are 'owned' by their respective SFTKDBHandles.
+ *
+ *  
+ */
+#include "sftkdb.h"
+#include "sftkpars.h"
+#include "prprf.h" 
+#include "prsystem.h"
+#include "lgglue.h"
+#include "secmodt.h"
+#if defined (_WIN32)
+#include <io.h>
+#endif
+
+/****************************************************************
+ *
+ * Secmod database.
+ *
+ * The new secmod database is simply a text file with each of the module
+ * entries. in the following form:
+ *
+ * #
+ * # This is a comment The next line is the library to load
+ * library=libmypkcs11.so
+ * name="My PKCS#11 module"
+ * params="my library's param string"
+ * nss="NSS parameters"
+ * other="parameters for other libraries and applications"
+ * 
+ * library=libmynextpk11.so
+ * name="My other PKCS#11 module"
+ */
+
+static char *
+sftkdb_quote(const char *string, char quote)
+{
+    char *newString = 0;
+    int escapes = 0, size = 0;
+    const char *src;
+    char *dest;
+
+    size=2;
+    for (src=string; *src ; src++) {
+	if ((*src == quote) || (*src == '\\')) escapes++;
+	size++;
+    }
+
+    dest = newString = PORT_ZAlloc(escapes+size+1); 
+    if (newString == NULL) {
+	return NULL;
+    }
+
+    *dest++=quote;
+    for (src=string; *src; src++,dest++) {
+	if ((*src == '\\') || (*src == quote)) {
+	    *dest++ = '\\';
+	}
+	*dest = *src;
+    }
+    *dest=quote;
+
+    return newString;
+}
+
+/*
+ * Smart string cat functions. Automatically manage the memory.
+ * The first parameter is the source string. If it's null, we 
+ * allocate memory for it. If it's not, we reallocate memory
+ * so the the concanenated string fits.
+ */
+static char *
+sftkdb_DupnCat(char *baseString, const char *str, int str_len)
+{
+    int len = (baseString ? PORT_Strlen(baseString) : 0) + 1;
+    char *newString;
+
+    len += str_len;
+    newString = (char *) PORT_Realloc(baseString,len);
+    if (newString == NULL) {
+	PORT_Free(baseString);
+	return NULL;
+    }
+    if (baseString == NULL) *newString = 0;
+    return PORT_Strncat(newString,str, str_len);
+}
+
+/* Same as sftkdb_DupnCat except it concatenates the full string, not a
+ * partial one */
+static char *
+sftkdb_DupCat(char *baseString, const char *str)
+{
+    return sftkdb_DupnCat(baseString, str, PORT_Strlen(str));
+}
+
+/* function to free up all the memory associated with a null terminated
+ * array of module specs */
+static SECStatus
+sftkdb_releaseSpecList(char **moduleSpecList)
+{
+    if (moduleSpecList) {
+	char **index;
+	for(index = moduleSpecList; *index; index++) {
+	    PORT_Free(*index);
+	}
+	PORT_Free(moduleSpecList);
+    }
+    return SECSuccess;
+}
+
+#define SECMOD_STEP 10
+static SECStatus
+sftkdb_growList(char ***pModuleList, int *useCount, int last)
+{
+    char **newModuleList;
+
+    *useCount += SECMOD_STEP;
+    newModuleList = (char **)PORT_Realloc(*pModuleList,
+					  *useCount*sizeof(char *));
+    if (newModuleList == NULL) {
+	return SECFailure;
+    }
+    PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP);
+    *pModuleList = newModuleList;
+    return SECSuccess;
+}
+
+static 
+char *sftk_getOldSecmodName(const char *dbname,const char *filename)
+{
+    char *file = NULL;
+    char *dirPath = PORT_Strdup(dbname);
+    char *sep;
+
+    sep = PORT_Strrchr(dirPath,*PATH_SEPARATOR);
+#ifdef WINDOWS
+    if (!sep) {
+	sep = PORT_Strrchr(dirPath,'/');
+    }
+#endif
+    if (sep) {
+	*(sep)=0;
+    }
+    file= PR_smprintf("%s"PATH_SEPARATOR"%s", dirPath, filename);
+    PORT_Free(dirPath);
+    return file;
+}
+
+#ifdef XP_UNIX
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#ifndef WINCE
+/* same as fopen, except it doesn't use umask, but explicit */
+FILE *
+lfopen(const char *name, const char *mode, int flags)
+{
+    int fd;
+    FILE *file;
+
+    fd = open(name, flags, 0600);
+    if (fd < 0) {
+	return NULL;
+    }
+    file = fdopen(fd, mode);
+    if (!file) {
+	close(fd);
+    }
+    /* file inherits fd */
+    return file;
+}
+#endif
+
+#define MAX_LINE_LENGTH 2048
+#define SFTK_DEFAULT_INTERNAL_INIT1 "library= name=\"NSS Internal PKCS #11 Module\" parameters="
+#define SFTK_DEFAULT_INTERNAL_INIT2 " NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={"
+#define SFTK_DEFAULT_INTERNAL_INIT3 " askpw=any timeout=30})\""
+
+/*
+ * Read all the existing modules in out of the file.
+ */
+char **
+sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, 
+		    const char *filename, const char *dbname, 
+		    char *params, PRBool rw)
+{
+    FILE *fd = NULL;
+    char **moduleList = NULL;
+    int moduleCount = 1;
+    int useCount = SECMOD_STEP;
+    char line[MAX_LINE_LENGTH];
+    PRBool internal = PR_FALSE;
+    PRBool skipParams = PR_FALSE;
+    char *moduleString = NULL;
+    char *paramsValue=NULL;
+    PRBool failed = PR_TRUE;
+
+    if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
+	return sftkdbCall_ReadSecmodDB(appName, filename, dbname, params, rw);
+    }
+
+    moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **));
+    if (moduleList == NULL) return NULL;
+
+    /* do we really want to use streams here */
+    fd = fopen(dbname, "r");
+    if (fd == NULL) goto done;
+
+    /*
+     * the following loop takes line separated config lines and colapses
+     * the lines to a single string, escaping and quoting as necessary.
+     */
+    /* loop state variables */
+    moduleString = NULL;  /* current concatenated string */
+    internal = PR_FALSE;	     /* is this an internal module */
+    skipParams = PR_FALSE;	   /* did we find an override parameter block*/
+    paramsValue = NULL;		   /* the current parameter block value */
+    while (fgets(line, sizeof(line), fd) != NULL) { 
+	int len = PORT_Strlen(line);
+
+	/* remove the ending newline */
+	if (len && line[len-1] == '\n') {
+	    len--;
+	    line[len] = 0;
+	}
+	if (*line == '#') {
+	    continue;
+	}
+	if (*line != 0) {
+	    /*
+	     * The PKCS #11 group standard assumes blocks of strings
+	     * separated by new lines, clumped by new lines. Internally
+	     * we take strings separated by spaces, so we may need to escape
+	     * certain spaces.
+	     */
+	    char *value = PORT_Strchr(line,'=');
+
+	    /* there is no value, write out the stanza as is */
+	    if (value == NULL || value[1] == 0) {
+		if (moduleString) {
+		    moduleString = sftkdb_DupnCat(moduleString," ", 1);
+		    if (moduleString == NULL) goto loser;
+		}
+	        moduleString = sftkdb_DupCat(moduleString, line);
+		if (moduleString == NULL) goto loser;
+	    /* value is already quoted, just write it out */
+	    } else if (value[1] == '"') {
+		if (moduleString) {
+		    moduleString = sftkdb_DupnCat(moduleString," ", 1);
+		    if (moduleString == NULL) goto loser;
+		}
+	        moduleString = sftkdb_DupCat(moduleString, line);
+		if (moduleString == NULL) goto loser;
+		/* we have an override parameter section, remember that
+		 * we found this (see following comment about why this
+		 * is necessary). */
+	        if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
+			skipParams = PR_TRUE;
+		}
+	    /*
+	     * The internal token always overrides it's parameter block
+	     * from the passed in parameters, so wait until then end
+	     * before we include the parameter block in case we need to 
+	     * override it. NOTE: if the parameter block is quoted with ("),
+	     * this override does not happen. This allows you to override
+	     * the application's parameter configuration.
+	     *
+	     * parameter block state is controlled by the following variables:
+	     *  skipParams - Bool : set to true of we have an override param
+	     *    block (all other blocks, either implicit or explicit are
+	     *    ignored).
+	     *  paramsValue - char * : pointer to the current param block. In
+	     *    the absence of overrides, paramsValue is set to the first
+	     *    parameter block we find. All subsequent blocks are ignored.
+	     *    When we find an internal token, the application passed
+	     *    parameters take precident.
+	     */
+	    } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
+		/* already have parameters */
+		if (paramsValue) {
+			continue;
+		}
+		paramsValue = sftkdb_quote(&value[1], '"');
+		if (paramsValue == NULL) goto loser;
+		continue;
+	    } else {
+	    /* may need to quote */
+	        char *newLine;
+		if (moduleString) {
+		    moduleString = sftkdb_DupnCat(moduleString," ", 1);
+		    if (moduleString == NULL) goto loser;
+		}
+		moduleString = sftkdb_DupnCat(moduleString,line,value-line+1);
+		if (moduleString == NULL)  goto loser;
+	        newLine = sftkdb_quote(&value[1],'"');
+		if (newLine == NULL) goto loser;
+		moduleString = sftkdb_DupCat(moduleString,newLine);
+	        PORT_Free(newLine);
+		if (moduleString == NULL) goto loser;
+	    }
+
+	    /* check to see if it's internal? */
+	    if (PORT_Strncasecmp(line, "NSS=", 4) == 0) {
+		/* This should be case insensitive! reviewers make
+		 * me fix it if it's not */
+		if (PORT_Strstr(line,"internal")) {
+		    internal = PR_TRUE;
+		    /* override the parameters */
+		    if (paramsValue) {
+			PORT_Free(paramsValue);
+		    }
+		    paramsValue = sftkdb_quote(params, '"');
+		}
+	    }
+	    continue;
+	}
+	if ((moduleString == NULL) || (*moduleString == 0)) {
+	    continue;
+	}
+
+	/* 
+	 * if we are here, we have found a complete stanza. Now write out
+	 * any param section we may have found.
+	 */
+	if (paramsValue) {
+	    /* we had an override */
+	    if (!skipParams) {
+		moduleString = sftkdb_DupnCat(moduleString," parameters=", 12);
+		if (moduleString == NULL) goto loser;
+		moduleString = sftkdb_DupCat(moduleString, paramsValue);
+		if (moduleString == NULL) goto loser;
+	    }
+	    PORT_Free(paramsValue);
+	    paramsValue = NULL;
+	}
+
+	if ((moduleCount+1) >= useCount) {
+	    SECStatus rv;
+	    rv = sftkdb_growList(&moduleList, &useCount,  moduleCount+1);
+	    if (rv != SECSuccess) {
+		goto loser;
+	    }
+	}
+
+	if (internal) {
+	    moduleList[0] = moduleString;
+	} else {
+	    moduleList[moduleCount] = moduleString;
+	    moduleCount++;
+	}
+	moduleString = NULL;
+	internal = PR_FALSE;
+	skipParams = PR_FALSE;
+    } 
+
+    if (moduleString) {
+	PORT_Free(moduleString);
+	moduleString = NULL;
+    }
+done:
+    /* if we couldn't open a pkcs11 database, look for the old one */
+    if (fd == NULL) {
+	char *olddbname = sftk_getOldSecmodName(dbname,filename);
+	PRStatus status;
+	char **oldModuleList;
+	int i;
+
+	/* couldn't get the old name */
+	if (!olddbname) {
+	    goto bail;
+	}
+
+	/* old one doesn't exist */
+	status = PR_Access(olddbname, PR_ACCESS_EXISTS);
+	if (status != PR_SUCCESS) {
+	    goto bail;
+	}
+
+	oldModuleList = sftkdbCall_ReadSecmodDB(appName, filename, 
+					olddbname, params, rw);
+	/* old one had no modules */
+	if (!oldModuleList) {
+	    goto bail;
+	}
+
+	/* count the modules */
+	for (i=0; oldModuleList[i]; i++) { }
+
+	/* grow the moduleList if necessary */
+	if (i >= useCount) {
+	    SECStatus rv;
+	    rv = sftkdb_growList(&moduleList,&useCount,moduleCount+1);
+	    if (rv != SECSuccess) {
+		goto loser;
+	    }
+	}
+	
+	/* write each module out, and copy it */
+	for (i=0; oldModuleList[i]; i++) {
+	    if (rw) {
+		sftkdb_AddSecmodDB(dbType,appName,filename,dbname,
+				oldModuleList[i],rw);
+	    }
+	    if (moduleList[i]) {
+		PORT_Free(moduleList[i]);
+	    }
+	    moduleList[i] = PORT_Strdup(oldModuleList[i]);
+	}
+
+	/* done with the old module list */
+	sftkdbCall_ReleaseSecmodDBData(appName, filename, olddbname, 
+				  oldModuleList, rw);
+bail:
+	if (olddbname) {
+	    PR_smprintf_free(olddbname);
+	}
+    }
+	
+    if (!moduleList[0]) {
+	char * newParams;
+	moduleString = PORT_Strdup(SFTK_DEFAULT_INTERNAL_INIT1);
+	newParams = sftkdb_quote(params,'"');
+	if (newParams == NULL) goto loser;
+	moduleString = sftkdb_DupCat(moduleString, newParams);
+	PORT_Free(newParams);
+	if (moduleString == NULL) goto loser;
+	moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT2);
+	if (moduleString == NULL) goto loser;
+	moduleString = sftkdb_DupCat(moduleString, SECMOD_SLOT_FLAGS);
+	if (moduleString == NULL) goto loser;
+	moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT3);
+	if (moduleString == NULL) goto loser;
+	moduleList[0] = moduleString;
+	moduleString = NULL;
+    }
+    failed = PR_FALSE;
+
+loser:
+    /*
+     * cleanup
+     */
+    /* deal with trust cert db here */
+    if (moduleString) {
+	PORT_Free(moduleString);
+	moduleString = NULL;
+    }
+    if (paramsValue) {
+	PORT_Free(paramsValue);
+	paramsValue = NULL;
+    }
+    if (failed || (moduleList[0] == NULL)) {
+	/* This is wrong! FIXME */
+	sftkdb_releaseSpecList(moduleList);
+	moduleList = NULL;
+	failed = PR_TRUE;
+    }
+    if (fd != NULL) {
+	fclose(fd);
+    } else if (!failed && rw) {
+	/* update our internal module */
+	sftkdb_AddSecmodDB(dbType,appName,filename,dbname,moduleList[0],rw);
+    }
+    return moduleList;
+}
+
+SECStatus
+sftkdb_ReleaseSecmodDBData(SDBType dbType, const char *appName, 
+			const char *filename, const char *dbname, 
+			char **moduleSpecList, PRBool rw)
+{
+    if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
+	return sftkdbCall_ReleaseSecmodDBData(appName, filename, dbname, 
+					  moduleSpecList, rw);
+    }
+    if (moduleSpecList) {
+	sftkdb_releaseSpecList(moduleSpecList);
+    }
+    return SECSuccess;
+}
+
+
+/*
+ * Delete a module from the Data Base
+ */
+SECStatus
+sftkdb_DeleteSecmodDB(SDBType dbType, const char *appName, 
+		      const char *filename, const char *dbname, 
+		      char *args, PRBool rw)
+{
+    /* SHDB_FIXME implement */
+    FILE *fd = NULL;
+    FILE *fd2 = NULL;
+    char line[MAX_LINE_LENGTH];
+    char *dbname2 = NULL;
+    char *block = NULL;
+    char *name = NULL;
+    char *lib = NULL;
+    int name_len, lib_len;
+    PRBool skip = PR_FALSE;
+    PRBool found = PR_FALSE;
+
+    if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
+	return sftkdbCall_DeleteSecmodDB(appName, filename, dbname, args, rw);
+    }
+
+    if (!rw) {
+	return SECFailure;
+    }
+
+    dbname2 = strdup(dbname);
+    if (dbname2 == NULL) goto loser;
+    dbname2[strlen(dbname)-1]++;
+
+    /* do we really want to use streams here */
+    fd = fopen(dbname, "r");
+    if (fd == NULL) goto loser;
+#ifdef WINCE
+    fd2 = fopen(dbname2, "w+");
+#else
+    fd2 = lfopen(dbname2, "w+", O_CREAT|O_RDWR|O_TRUNC);
+#endif
+    if (fd2 == NULL) goto loser;
+
+    name = sftk_argGetParamValue("name",args);
+    if (name) {
+	name_len = PORT_Strlen(name);
+    }
+    lib = sftk_argGetParamValue("library",args);
+    if (lib) {
+	lib_len = PORT_Strlen(lib);
+    }
+
+
+    /*
+     * the following loop takes line separated config files and colapses
+     * the lines to a single string, escaping and quoting as necessary.
+     */
+    /* loop state variables */
+    block = NULL;
+    skip = PR_FALSE;
+    while (fgets(line, sizeof(line), fd) != NULL) { 
+	/* If we are processing a block (we haven't hit a blank line yet */
+	if (*line != '\n') {
+	    /* skip means we are in the middle of a block we are deleting */
+	    if (skip) {
+		continue;
+	    }
+	    /* if we haven't found the block yet, check to see if this block
+	     * matches our requirements */
+	    if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) &&
+		 (PORT_Strncmp(line+5,name,name_len) == 0))  ||
+	        (lib && (PORT_Strncasecmp(line,"library=",8) == 0) &&
+		 (PORT_Strncmp(line+8,lib,lib_len) == 0)))) {
+
+		/* yup, we don't need to save any more data, */
+		PORT_Free(block);
+		block=NULL;
+		/* we don't need to collect more of this block */
+		skip = PR_TRUE;
+		/* we don't need to continue searching for the block */
+		found =PR_TRUE;
+		continue;
+	    }
+	    /* not our match, continue to collect data in this block */
+	    block = sftkdb_DupCat(block,line);
+	    continue;
+	}
+	/* we've collected a block of data that wasn't the module we were
+	 * looking for, write it out */
+	if (block) {
+	    fwrite(block, PORT_Strlen(block), 1, fd2);
+	    PORT_Free(block);
+	    block = NULL;
+	}
+	/* If we didn't just delete the this block, keep the blank line */
+	if (!skip) {
+	    fputs(line,fd2);
+	}
+	/* we are definately not in a deleted block anymore */
+	skip = PR_FALSE;
+    } 
+    fclose(fd);
+    fclose(fd2);
+    if (found) {
+	/* rename dbname2 to dbname */
+	PR_Delete(dbname);
+	PR_Rename(dbname2,dbname);
+    } else {
+	PR_Delete(dbname2);
+    }
+    PORT_Free(dbname2);
+    PORT_Free(lib);
+    PORT_Free(name);
+    return SECSuccess;
+
+loser:
+    if (fd != NULL) {
+	fclose(fd);
+    }
+    if (fd2 != NULL) {
+	fclose(fd2);
+    }
+    if (dbname2) {
+	PR_Delete(dbname2);
+	PORT_Free(dbname2);
+    }
+    PORT_Free(lib);
+    PORT_Free(name);
+    return SECFailure;
+}
+
+/*
+ * Add a module to the Data base 
+ */
+SECStatus
+sftkdb_AddSecmodDB(SDBType dbType, const char *appName, 
+		   const char *filename, const char *dbname, 
+		   char *module, PRBool rw)
+{
+    FILE *fd = NULL;
+    char *block = NULL;
+    PRBool libFound = PR_FALSE;
+
+    if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
+	return sftkdbCall_AddSecmodDB(appName, filename, dbname, module, rw);
+    }
+
+    /* can't write to a read only module */
+    if (!rw) {
+	return SECFailure;
+    }
+
+    /* remove the previous version if it exists */
+    (void) sftkdb_DeleteSecmodDB(dbType, appName, filename, dbname, module, rw);
+
+#ifdef WINCE
+    fd = fopen(dbname, "a+");
+#else
+    fd = lfopen(dbname, "a+", O_CREAT|O_RDWR|O_APPEND);
+#endif
+    if (fd == NULL) {
+	return SECFailure;
+    }
+    module = sftk_argStrip(module);
+    while (*module) {
+	int count;
+	char *keyEnd = PORT_Strchr(module,'=');
+	char *value;
+
+	if (PORT_Strncmp(module, "library=", 8) == 0) {
+	   libFound=PR_TRUE;
+	}
+	if (keyEnd == NULL) {
+	    block = sftkdb_DupCat(block, module);
+	    break;
+	}
+	block = sftkdb_DupnCat(block, module, keyEnd-module+1);
+	if (block == NULL) { goto loser; }
+	value = sftk_argFetchValue(&keyEnd[1], &count);
+	if (value) {
+	    block = sftkdb_DupCat(block, sftk_argStrip(value));
+	    PORT_Free(value);
+	}
+	if (block == NULL) { goto loser; }
+	block = sftkdb_DupnCat(block, "\n", 1);
+	module = keyEnd + 1 + count;
+	module = sftk_argStrip(module);
+    }
+    if (block) {
+	if (!libFound) {
+	    fprintf(fd,"library=\n");
+	}
+	fwrite(block, PORT_Strlen(block), 1, fd);
+	fprintf(fd,"\n");
+	PORT_Free(block);
+	block = NULL;
+    }
+    fclose(fd);
+    return SECSuccess;
+
+loser:
+    PORT_Free(block);
+    fclose(fd);
+    return SECFailure;
+}
+  
+
diff --git a/mozilla/security/nss/lib/softoken/sftkpars.c b/mozilla/security/nss/lib/softoken/sftkpars.c
new file mode 100644
index 0000000..aefd696
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkpars.c
@@ -0,0 +1,648 @@
+/* ***** 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-2007
+ * 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 ***** */
+/* 
+ *  The following code handles the storage of PKCS 11 modules used by the
+ * NSS. This file is written to abstract away how the modules are
+ * stored so we can deside that later.
+ */
+#include "sftkpars.h"
+#include "pkcs11i.h"
+#include "sdb.h"
+#include "prprf.h" 
+#include "prenv.h"
+
+/*
+ * this file contains routines for parsing PKCS #11 module spec
+ * strings.
+ */
+
+#define SFTK_HANDLE_STRING_ARG(param,target,value,command) \
+    if (PORT_Strncasecmp(param,value,sizeof(value)-1) == 0) { \
+	param += sizeof(value)-1; \
+	target = sftk_argFetchValue(param,&next); \
+	param += next; \
+	command ;\
+    } else  
+
+#define SFTK_HANDLE_FINAL_ARG(param) \
+    { param = sftk_argSkipParameter(param); } param = sftk_argStrip(param);
+
+static PRBool sftk_argGetPair(char c) {
+    switch (c) {
+    case '\'': return c;
+    case '\"': return c;
+    case '<': return '>';
+    case '{': return '}';
+    case '[': return ']';
+    case '(': return ')';
+    default: break;
+    }
+    return ' ';
+}
+
+static PRBool sftk_argIsBlank(char c) {
+   return isspace((unsigned char )c);
+}
+
+static PRBool sftk_argIsEscape(char c) {
+    return c == '\\';
+}
+
+static PRBool sftk_argIsQuote(char c) {
+    switch (c) {
+    case '\'':
+    case '\"':
+    case '<':
+    case '{': /* } end curly to keep vi bracket matching working */
+    case '(': /* ) */
+    case '[': /* ] */ return PR_TRUE;
+    default: break;
+    }
+    return PR_FALSE;
+}
+
+char *sftk_argStrip(char *c) {
+   while (*c && sftk_argIsBlank(*c)) c++;
+   return c;
+}
+
+static char *
+sftk_argFindEnd(char *string) {
+    char endChar = ' ';
+    PRBool lastEscape = PR_FALSE;
+
+    if (sftk_argIsQuote(*string)) {
+	endChar = sftk_argGetPair(*string);
+	string++;
+    }
+
+    for (;*string; string++) {
+	if (lastEscape) {
+	    lastEscape = PR_FALSE;
+	    continue;
+	}
+	if (sftk_argIsEscape(*string) && !lastEscape) {
+	    lastEscape = PR_TRUE;
+	    continue;
+	} 
+	if ((endChar == ' ') && sftk_argIsBlank(*string)) break;
+	if (*string == endChar) {
+	    break;
+	}
+    }
+
+    return string;
+}
+
+char *
+sftk_argFetchValue(char *string, int *pcount)
+{
+    char *end = sftk_argFindEnd(string);
+    char *retString, *copyString;
+    PRBool lastEscape = PR_FALSE;
+    int len;
+
+    len = end - string;
+    if (len == 0) {
+	*pcount = 0;
+	return NULL;
+    }
+
+    copyString = retString = (char *)PORT_Alloc(len+1);
+
+    if (*end) len++;
+    *pcount = len;
+    if (retString == NULL) return NULL;
+
+
+    if (sftk_argIsQuote(*string)) string++;
+    for (; string < end; string++) {
+	if (sftk_argIsEscape(*string) && !lastEscape) {
+	    lastEscape = PR_TRUE;
+	    continue;
+	}
+	lastEscape = PR_FALSE;
+	*copyString++ = *string;
+    }
+    *copyString = 0;
+    return retString;
+}
+
+static char *
+sftk_argSkipParameter(char *string) 
+{
+     char *end;
+     /* look for the end of the <name>= */
+     for (;*string; string++) {
+	if (*string == '=') { string++; break; }
+	if (sftk_argIsBlank(*string)) return(string); 
+     }
+
+     end = sftk_argFindEnd(string);
+     if (*end) end++;
+     return end;
+}
+
+char *
+sftk_argGetParamValue(char *paramName,char *parameters)
+{
+    char searchValue[256];
+    int paramLen = strlen(paramName);
+    char *returnValue = NULL;
+    int next;
+
+    if ((parameters == NULL) || (*parameters == 0)) return NULL;
+
+    PORT_Assert(paramLen+2 < sizeof(searchValue));
+
+    PORT_Strcpy(searchValue,paramName);
+    PORT_Strcat(searchValue,"=");
+    while (*parameters) {
+	if (PORT_Strncasecmp(parameters,searchValue,paramLen+1) == 0) {
+	    parameters += paramLen+1;
+	    returnValue = sftk_argFetchValue(parameters,&next);
+	    break;
+	} else {
+	    parameters = sftk_argSkipParameter(parameters);
+	}
+	parameters = sftk_argStrip(parameters);
+   }
+   return returnValue;
+}
+    
+static char *
+sftk_argNextFlag(char *flags)
+{
+    for (; *flags ; flags++) {
+	if (*flags == ',') {
+	    flags++;
+	    break;
+	}
+    }
+    return flags;
+}
+
+static PRBool
+sftk_argHasFlag(char *label, char *flag, char *parameters)
+{
+    char *flags,*index;
+    int len = strlen(flag);
+    PRBool found = PR_FALSE;
+
+    flags = sftk_argGetParamValue(label,parameters);
+    if (flags == NULL) return PR_FALSE;
+
+    for (index=flags; *index; index=sftk_argNextFlag(index)) {
+	if (PORT_Strncasecmp(index,flag,len) == 0) {
+	    found=PR_TRUE;
+	    break;
+	}
+    }
+    PORT_Free(flags);
+    return found;
+}
+
+/*
+ * decode a number. handle octal (leading '0'), hex (leading '0x') or decimal
+ */
+static long
+sftk_argDecodeNumber(char *num)
+{
+    int	radix = 10;
+    unsigned long value = 0;
+    long retValue = 0;
+    int sign = 1;
+    int digit;
+
+    if (num == NULL) return retValue;
+
+    num = sftk_argStrip(num);
+
+    if (*num == '-') {
+	sign = -1;
+	num++;
+    }
+
+    if (*num == '0') {
+	radix = 8;
+	num++;
+	if ((*num == 'x') || (*num == 'X')) {
+	    radix = 16;
+	    num++;
+	}
+    }
+
+   
+    for ( ;*num; num++ ) {
+	if (isdigit(*num)) {
+	    digit = *num - '0';
+	} else if ((*num >= 'a') && (*num <= 'f'))  {
+	    digit = *num - 'a' + 10;
+	} else if ((*num >= 'A') && (*num <= 'F'))  {
+	    digit = *num - 'A' + 10;
+	} else {
+	    break;
+	}
+	if (digit >= radix) break;
+	value = value*radix + digit;
+    }
+
+    retValue = ((int) value) * sign;
+    return retValue;
+}
+
+static char *
+sftk_argGetName(char *inString, int *next) 
+{
+    char *name=NULL;
+    char *string;
+    int len;
+
+    /* look for the end of the <name>= */
+    for (string = inString;*string; string++) {
+	if (*string == '=') { break; }
+	if (sftk_argIsBlank(*string)) break;
+    }
+
+    len = string - inString;
+
+    *next = len; 
+    if (*string == '=') (*next) += 1;
+    if (len > 0) {
+	name = PORT_Alloc(len+1);
+	PORT_Strncpy(name,inString,len);
+	name[len] = 0;
+    }
+    return name;
+}
+
+#define FREE_CLEAR(p) if (p) { PORT_Free(p); p = NULL; }
+
+static void
+sftk_parseTokenFlags(char *tmp, sftk_token_parameters *parsed) { 
+    parsed->readOnly = sftk_argHasFlag("flags","readOnly",tmp);
+    parsed->noCertDB = sftk_argHasFlag("flags","noCertDB",tmp);
+    parsed->noKeyDB = sftk_argHasFlag("flags","noKeyDB",tmp);
+    parsed->forceOpen = sftk_argHasFlag("flags","forceOpen",tmp);
+    parsed->pwRequired = sftk_argHasFlag("flags","passwordRequired",tmp);
+    parsed->optimizeSpace = sftk_argHasFlag("flags","optimizeSpace",tmp);
+    return;
+}
+
+static void
+sftk_parseFlags(char *tmp, sftk_parameters *parsed) { 
+    parsed->noModDB = sftk_argHasFlag("flags","noModDB",tmp);
+    parsed->readOnly = sftk_argHasFlag("flags","readOnly",tmp);
+    /* keep legacy interface working */
+    parsed->noCertDB = sftk_argHasFlag("flags","noCertDB",tmp);
+    parsed->forceOpen = sftk_argHasFlag("flags","forceOpen",tmp);
+    parsed->pwRequired = sftk_argHasFlag("flags","passwordRequired",tmp);
+    parsed->optimizeSpace = sftk_argHasFlag("flags","optimizeSpace",tmp);
+    return;
+}
+
+static CK_RV
+sftk_parseTokenParameters(char *param, sftk_token_parameters *parsed) 
+{
+    int next;
+    char *tmp;
+    char *index;
+    index = sftk_argStrip(param);
+
+    while (*index) {
+	SFTK_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->updatedir,"updateDir=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->updCertPrefix,"updateCertPrefix=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->updKeyPrefix,"updateKeyPrefix=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->updateID,"updateID=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->certPrefix,"certPrefix=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->keyPrefix,"keyPrefix=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->tokdes,"tokenDescription=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->updtokdes,
+						"updateTokenDescription=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->slotdes,"slotDescription=",;)
+	SFTK_HANDLE_STRING_ARG(index,tmp,"minPWLen=", 
+			if(tmp) { parsed->minPW=atoi(tmp); PORT_Free(tmp); })
+	SFTK_HANDLE_STRING_ARG(index,tmp,"flags=", 
+	   if(tmp) { sftk_parseTokenFlags(param,parsed); PORT_Free(tmp); })
+	SFTK_HANDLE_FINAL_ARG(index)
+   }
+   return CKR_OK;
+}
+
+static void
+sftk_parseTokens(char *tokenParams, sftk_parameters *parsed)
+{
+    char *tokenIndex;
+    sftk_token_parameters *tokens = NULL;
+    int i=0,count = 0,next;
+
+    if ((tokenParams == NULL) || (*tokenParams == 0))  return;
+
+    /* first count the number of slots */
+    for (tokenIndex = sftk_argStrip(tokenParams); *tokenIndex;
+	 tokenIndex = sftk_argStrip(sftk_argSkipParameter(tokenIndex))) {
+	count++;
+    }
+
+    /* get the data structures */
+    tokens = (sftk_token_parameters *) 
+			PORT_ZAlloc(count*sizeof(sftk_token_parameters));
+    if (tokens == NULL) return;
+
+    for (tokenIndex = sftk_argStrip(tokenParams), i = 0;
+					*tokenIndex && i < count ; i++ ) {
+	char *name;
+	name = sftk_argGetName(tokenIndex,&next);
+	tokenIndex += next;
+
+	tokens[i].slotID = sftk_argDecodeNumber(name);
+        tokens[i].readOnly = PR_FALSE;
+	tokens[i].noCertDB = PR_FALSE;
+	tokens[i].noKeyDB = PR_FALSE;
+	if (!sftk_argIsBlank(*tokenIndex)) {
+	    char *args = sftk_argFetchValue(tokenIndex,&next);
+	    tokenIndex += next;
+	    if (args) {
+		sftk_parseTokenParameters(args,&tokens[i]);
+		PORT_Free(args);
+	    }
+	}
+	if (name) PORT_Free(name);
+	tokenIndex = sftk_argStrip(tokenIndex);
+    }
+    parsed->token_count = i;
+    parsed->tokens = tokens;
+    return; 
+}
+
+CK_RV
+sftk_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS) 
+{
+    int next;
+    char *tmp;
+    char *index;
+    char *certPrefix = NULL, *keyPrefix = NULL;
+    char *tokdes = NULL, *ptokdes = NULL, *pupdtokdes = NULL;
+    char *slotdes = NULL, *pslotdes = NULL;
+    char *fslotdes = NULL, *ftokdes = NULL;
+    char *minPW = NULL;
+    index = sftk_argStrip(param);
+
+    PORT_Memset(parsed, 0, sizeof(sftk_parameters));
+
+    while (*index) {
+	SFTK_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->updatedir,"updateDir=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->updateID,"updateID=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->secmodName,"secmod=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->man,"manufacturerID=",;)
+	SFTK_HANDLE_STRING_ARG(index,parsed->libdes,"libraryDescription=",;)
+	/* constructed values, used so legacy interfaces still work */
+	SFTK_HANDLE_STRING_ARG(index,certPrefix,"certPrefix=",;)
+        SFTK_HANDLE_STRING_ARG(index,keyPrefix,"keyPrefix=",;)
+        SFTK_HANDLE_STRING_ARG(index,tokdes,"cryptoTokenDescription=",;)
+        SFTK_HANDLE_STRING_ARG(index,ptokdes,"dbTokenDescription=",;)
+        SFTK_HANDLE_STRING_ARG(index,slotdes,"cryptoSlotDescription=",;)
+        SFTK_HANDLE_STRING_ARG(index,pslotdes,"dbSlotDescription=",;)
+        SFTK_HANDLE_STRING_ARG(index,fslotdes,"FIPSSlotDescription=",;)
+        SFTK_HANDLE_STRING_ARG(index,ftokdes,"FIPSTokenDescription=",;)
+	SFTK_HANDLE_STRING_ARG(index,pupdtokdes, "updateTokenDescription=",;)
+	SFTK_HANDLE_STRING_ARG(index,minPW,"minPWLen=",;)
+
+	SFTK_HANDLE_STRING_ARG(index,tmp,"flags=", 
+		if(tmp) { sftk_parseFlags(param,parsed); PORT_Free(tmp); })
+	SFTK_HANDLE_STRING_ARG(index,tmp,"tokens=", 
+		if(tmp) { sftk_parseTokens(tmp,parsed); PORT_Free(tmp); })
+	SFTK_HANDLE_FINAL_ARG(index)
+    }
+    if (parsed->tokens == NULL) {
+	int  count = isFIPS ? 1 : 2;
+	int  index = count-1;
+	sftk_token_parameters *tokens = NULL;
+
+	tokens = (sftk_token_parameters *) 
+			PORT_ZAlloc(count*sizeof(sftk_token_parameters));
+	if (tokens == NULL) {
+	    goto loser;
+	}
+	parsed->tokens = tokens;
+    	parsed->token_count = count;
+	tokens[index].slotID = isFIPS ? FIPS_SLOT_ID : PRIVATE_KEY_SLOT_ID;
+	tokens[index].certPrefix = certPrefix;
+	tokens[index].keyPrefix = keyPrefix;
+	tokens[index].minPW = minPW ? atoi(minPW) : 0;
+	tokens[index].readOnly = parsed->readOnly;
+	tokens[index].noCertDB = parsed->noCertDB;
+	tokens[index].noKeyDB = parsed->noCertDB;
+	tokens[index].forceOpen = parsed->forceOpen;
+	tokens[index].pwRequired = parsed->pwRequired;
+	tokens[index].optimizeSpace = parsed->optimizeSpace;
+	tokens[0].optimizeSpace = parsed->optimizeSpace;
+	certPrefix = NULL;
+	keyPrefix = NULL;
+	if (isFIPS) {
+	    tokens[index].tokdes = ftokdes;
+	    tokens[index].updtokdes = pupdtokdes;
+	    tokens[index].slotdes = fslotdes;
+	    fslotdes = NULL;
+	    ftokdes = NULL;
+	    pupdtokdes = NULL;
+	} else {
+	    tokens[index].tokdes = ptokdes;
+	    tokens[index].updtokdes = pupdtokdes;
+	    tokens[index].slotdes = pslotdes;
+	    tokens[0].slotID = NETSCAPE_SLOT_ID;
+	    tokens[0].tokdes = tokdes;
+	    tokens[0].slotdes = slotdes;
+	    tokens[0].noCertDB = PR_TRUE;
+	    tokens[0].noKeyDB = PR_TRUE;
+	    pupdtokdes = NULL;
+	    ptokdes = NULL;
+	    pslotdes = NULL;
+	    tokdes = NULL;
+	    slotdes = NULL;
+	}
+    }
+
+loser:
+    FREE_CLEAR(certPrefix);
+    FREE_CLEAR(keyPrefix);
+    FREE_CLEAR(tokdes);
+    FREE_CLEAR(ptokdes);
+    FREE_CLEAR(pupdtokdes);
+    FREE_CLEAR(slotdes);
+    FREE_CLEAR(pslotdes);
+    FREE_CLEAR(fslotdes);
+    FREE_CLEAR(ftokdes);
+    FREE_CLEAR(minPW);
+    return CKR_OK;
+}
+
+void
+sftk_freeParams(sftk_parameters *params)
+{
+    int i;
+
+    for (i=0; i < params->token_count; i++) {
+	FREE_CLEAR(params->tokens[i].configdir);
+	FREE_CLEAR(params->tokens[i].certPrefix);
+	FREE_CLEAR(params->tokens[i].keyPrefix);
+	FREE_CLEAR(params->tokens[i].tokdes);
+	FREE_CLEAR(params->tokens[i].slotdes);
+	FREE_CLEAR(params->tokens[i].updatedir);
+	FREE_CLEAR(params->tokens[i].updCertPrefix);
+	FREE_CLEAR(params->tokens[i].updKeyPrefix);
+	FREE_CLEAR(params->tokens[i].updateID);
+	FREE_CLEAR(params->tokens[i].updtokdes);
+    }
+
+    FREE_CLEAR(params->configdir);
+    FREE_CLEAR(params->secmodName);
+    FREE_CLEAR(params->man);
+    FREE_CLEAR(params->libdes); 
+    FREE_CLEAR(params->tokens);
+    FREE_CLEAR(params->updatedir);
+    FREE_CLEAR(params->updateID);
+}
+
+#define SQLDB "sql:"
+#define EXTERNDB "extern:"
+#define LEGACY "dbm:"
+const char *
+sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **appName)
+{
+    *appName = NULL;
+#ifdef NSS_DISABLE_DBM
+    *dbType = SDB_SQL;
+#else
+    *dbType = SDB_LEGACY;
+#endif
+    if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS)-1) == 0) {
+	char *cdir;
+	*dbType = SDB_MULTIACCESS;
+
+	*appName = PORT_Strdup(configdir+sizeof(MULTIACCESS)-1);
+	if (*appName == NULL) {
+	    return configdir;
+	}
+	cdir = *appName;
+	while (*cdir && *cdir != ':') {
+	    cdir++;
+	}
+	if (*cdir == ':') {
+	   *cdir = 0;
+	   cdir++;
+	}
+	configdir = cdir;
+    } else if (PORT_Strncmp(configdir, SQLDB, sizeof(SQLDB)-1) == 0) {
+	*dbType = SDB_SQL;
+	configdir = configdir + sizeof(SQLDB) -1;
+    } else if (PORT_Strncmp(configdir, EXTERNDB, sizeof(EXTERNDB)-1) == 0) {
+	*dbType = SDB_EXTERN;
+	configdir = configdir + sizeof(EXTERNDB) -1;
+    } else if (PORT_Strncmp(configdir, LEGACY, sizeof(LEGACY)-1) == 0) {
+	*dbType = SDB_LEGACY;
+	configdir = configdir + sizeof(LEGACY) -1;
+    } else {
+	/* look up the default from the environment */
+	char *defaultType = PR_GetEnv("NSS_DEFAULT_DB_TYPE");
+	if (defaultType == NULL) {
+	    /* none specified, go with the legacy */
+	    return configdir;
+	}
+	if (PORT_Strncmp(defaultType, SQLDB, sizeof(SQLDB)-2) == 0) {
+	    *dbType = SDB_SQL;
+	} else if (PORT_Strncmp(defaultType,EXTERNDB,sizeof(EXTERNDB)-2)==0) {
+	    *dbType = SDB_EXTERN;
+	} else if (PORT_Strncmp(defaultType, LEGACY, sizeof(LEGACY)-2) == 0) {
+	    *dbType = SDB_LEGACY;
+	}
+    }
+    return configdir;
+}
+
+char *
+sftk_getSecmodName(char *param, SDBType *dbType, char **appName,
+		   char **filename, PRBool *rw)
+{
+    int next;
+    char *configdir = NULL;
+    char *secmodName = NULL;
+    char *value = NULL;
+    char *save_params = param;
+    const char *lconfigdir;
+    param = sftk_argStrip(param);
+	
+
+    while (*param) {
+	SFTK_HANDLE_STRING_ARG(param,configdir,"configDir=",;)
+	SFTK_HANDLE_STRING_ARG(param,secmodName,"secmod=",;)
+	SFTK_HANDLE_FINAL_ARG(param)
+   }
+
+   *rw = PR_TRUE;
+   if (sftk_argHasFlag("flags","readOnly",save_params)) {
+	*rw = PR_FALSE;
+   }
+
+   if (!secmodName || *secmodName == '\0') {
+	if (secmodName) PORT_Free(secmodName);
+	secmodName = PORT_Strdup(SECMOD_DB);
+   }
+
+   *filename = secmodName;
+   lconfigdir = sftk_EvaluateConfigDir(configdir, dbType, appName);
+
+   if (sftk_argHasFlag("flags","noModDB",save_params)) {
+	/* there isn't a module db, don't load the legacy support */
+	*dbType = SDB_SQL;
+        *rw = PR_FALSE;
+   }
+
+   /* only use the renamed secmod for legacy databases */
+   if ((*dbType != SDB_LEGACY) && (*dbType != SDB_MULTIACCESS)) {
+	secmodName="pkcs11.txt";
+   }
+
+   if (lconfigdir) {
+	value = PR_smprintf("%s" PATH_SEPARATOR "%s",lconfigdir,secmodName);
+   } else {
+	value = PR_smprintf("%s",secmodName);
+   }
+   if (configdir) PORT_Free(configdir);
+   return value;
+}
diff --git a/mozilla/security/nss/lib/softoken/sftkpars.h b/mozilla/security/nss/lib/softoken/sftkpars.h
new file mode 100644
index 0000000..0086edf
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkpars.h
@@ -0,0 +1,49 @@
+/* ***** 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
+ * Red Hat Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 "pkcs11i.h"
+#include "sftkdbt.h"
+
+/* parsing functions */
+char * sftk_argFetchValue(char *string, int *pcount);
+char * sftk_getSecmodName(char *param, SDBType *dbType, char **appName, char **filename,PRBool *rw);
+char *sftk_argStrip(char *c);
+CK_RV sftk_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS);
+void sftk_freeParams(sftk_parameters *params);
+const char *sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **app);
+char * sftk_argGetParamValue(char *paramName,char *parameters);
+
+
+
diff --git a/mozilla/security/nss/lib/softoken/sftkpwd.c b/mozilla/security/nss/lib/softoken/sftkpwd.c
new file mode 100644
index 0000000..9d56f1b
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/sftkpwd.c
@@ -0,0 +1,1309 @@
+/* ***** 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-2007
+ * 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 ***** */
+/* 
+ *  The following code handles the storage of PKCS 11 modules used by the
+ * NSS. For the rest of NSS, only one kind of database handle exists:
+ *
+ *     SFTKDBHandle
+ *
+ * There is one SFTKDBHandle for the each key database and one for each cert 
+ * database. These databases are opened as associated pairs, one pair per
+ * slot. SFTKDBHandles are reference counted objects.
+ *
+ * Each SFTKDBHandle points to a low level database handle (SDB). This handle
+ * represents the underlying physical database. These objects are not 
+ * reference counted, an are 'owned' by their respective SFTKDBHandles.
+ *
+ *  
+ */
+#include "sftkdb.h"
+#include "sftkdbti.h"
+#include "pkcs11t.h"
+#include "pkcs11i.h"
+#include "sdb.h"
+#include "prprf.h" 
+#include "secmodt.h"
+#include "sftkpars.h"
+#include "pratom.h"
+#include "blapi.h"
+#include "secoid.h"
+#include "sechash.h"
+#include "lowpbe.h"
+#include "secdert.h"
+#include "prsystem.h"
+#include "lgglue.h"
+#include "secerr.h"
+#include "softoken.h"
+  
+/******************************************************************
+ * 
+ * Key DB password handling functions
+ *
+ * These functions manage the key db password (set, reset, initialize, use).
+ *
+ * The key is managed on 'this side' of the database. All private data is
+ * encrypted before it is sent to the database itself. Besides PBE's, the
+ * database management code can also mix in various fixed keys so the data
+ * in the database is no longer considered 'plain text'.
+ */
+
+
+/* take string password and turn it into a key. The key is dependent
+ * on a global salt entry acquired from the database. This salted
+ * value will be based to a pkcs5 pbe function before it is used
+ * in an actual encryption */
+static SECStatus
+sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt,
+			const char *pw, SECItem *key)
+{
+    SHA1Context *cx = NULL;
+    SECStatus rv = SECFailure;
+
+    key->data = PORT_Alloc(SHA1_LENGTH);
+    if (key->data == NULL) {
+	goto loser;
+    }
+    key->len = SHA1_LENGTH;
+
+    cx = SHA1_NewContext();
+    if ( cx == NULL) {
+	goto loser;
+    }
+    SHA1_Begin(cx);
+    if (salt  && salt->data ) {
+	SHA1_Update(cx, salt->data, salt->len);
+    }
+    SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));
+    SHA1_End(cx, key->data, &key->len, key->len);
+    rv = SECSuccess;
+    
+loser:
+    if (cx) {
+	SHA1_DestroyContext(cx, PR_TRUE);
+    }
+    if (rv != SECSuccess) {
+	if (key->data != NULL) {
+	    PORT_ZFree(key->data,key->len);
+	}
+	key->data = NULL;
+    }
+    return rv;
+}
+
+/*
+ * Cipher text stored in the database contains 3 elements:
+ * 1) an identifier describing the encryption algorithm.
+ * 2) an entry specific salt value.
+ * 3) the encrypted value.
+ *
+ * The following data structure represents the encrypted data in a decoded
+ * (but still encrypted) form.
+ */
+typedef struct sftkCipherValueStr sftkCipherValue;
+struct sftkCipherValueStr {
+    PLArenaPool *arena;
+    SECOidTag  alg;
+    NSSPKCS5PBEParameter *param;
+    SECItem    salt;
+    SECItem    value;
+};
+
+#define SFTK_CIPHERTEXT_VERSION 3
+
+struct SFTKDBEncryptedDataInfoStr {
+    SECAlgorithmID algorithm;
+    SECItem encryptedData;
+};
+typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo;
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+        0, NULL, sizeof(SFTKDBEncryptedDataInfo) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN ,
+        offsetof(SFTKDBEncryptedDataInfo,algorithm),
+        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_OCTET_STRING,
+        offsetof(SFTKDBEncryptedDataInfo,encryptedData) },
+    { 0 }
+};
+
+/*
+ * This parses the cipherText into cipher value. NOTE: cipherValue will point
+ * to data in cipherText, if cipherText is freed, cipherValue will be invalid.
+ */
+static SECStatus
+sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue)
+{
+    PLArenaPool *arena = NULL;
+    SFTKDBEncryptedDataInfo edi;
+    SECStatus rv;
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	return SECFailure;
+    }
+    cipherValue->arena = NULL;
+    cipherValue->param = NULL;
+
+    rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate,
+                            cipherText);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm);
+    cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm);
+    if (cipherValue->param == NULL) {
+	goto loser;
+    }
+    cipherValue->value = edi.encryptedData;
+    cipherValue->arena = arena;
+
+    return SECSuccess;
+loser:
+    if (cipherValue->param) {
+	nsspkcs5_DestroyPBEParameter(cipherValue->param);
+	cipherValue->param = NULL;
+    }
+    if (arena) {
+	PORT_FreeArena(arena,PR_FALSE);
+    }
+    return SECFailure;
+}
+
+
+
+/* 
+ * unlike decode, Encode actually allocates a SECItem the caller must free
+ * The caller can pass an optional arena to to indicate where to place
+ * the resultant cipherText.
+ */
+static SECStatus
+sftkdb_encodeCipherText(PLArenaPool *arena, sftkCipherValue *cipherValue, 
+                        SECItem **cipherText)
+{
+    SFTKDBEncryptedDataInfo edi;
+    SECAlgorithmID *algid;
+    SECStatus rv;
+    PLArenaPool *localArena = NULL;
+
+
+    localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (localArena == NULL) {
+	return SECFailure;
+    }
+
+    algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg, 
+					cipherValue->param);
+    if (algid == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid);
+    SECOID_DestroyAlgorithmID(algid, PR_TRUE);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    edi.encryptedData = cipherValue->value;
+
+    *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi, 
+				    sftkdb_EncryptedDataInfoTemplate);
+    if (*cipherText == NULL) {
+	rv = SECFailure;
+    }
+
+loser:
+    if (localArena) {
+	PORT_FreeArena(localArena,PR_FALSE);
+    }
+
+    return rv;
+}
+
+
+/*
+ * Use our key to decode a cipherText block from the database.
+ *
+ * plain text is allocated by nsspkcs5_CipherData and must be freed
+ * with SECITEM_FreeItem by the caller.
+ */
+SECStatus
+sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain) 
+{
+    SECStatus rv;
+    sftkCipherValue cipherValue;
+
+    /* First get the cipher type */
+    rv = sftkdb_decodeCipherText(cipherText, &cipherValue);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value, 
+				    PR_FALSE, NULL);
+    if (*plain == NULL) {
+	rv = SECFailure;
+	goto loser;
+    } 
+
+loser:
+    if (cipherValue.param) {
+	nsspkcs5_DestroyPBEParameter(cipherValue.param);
+    }
+    if (cipherValue.arena) {
+	PORT_FreeArena(cipherValue.arena,PR_FALSE);
+    }
+    return rv;
+}
+
+/*
+ * encrypt a block. This function returned the encrypted ciphertext which
+ * the caller must free. If the caller provides an arena, cipherText will
+ * be allocated out of that arena. This also generated the per entry
+ * salt automatically.
+ */
+SECStatus
+sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey, 
+		SECItem *plainText, SECItem **cipherText) 
+{
+    SECStatus rv;
+    sftkCipherValue cipherValue;
+    SECItem *cipher = NULL;
+    NSSPKCS5PBEParameter *param = NULL;
+    unsigned char saltData[HASH_LENGTH_MAX];
+
+    cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
+    cipherValue.salt.len = SHA1_LENGTH;
+    cipherValue.salt.data = saltData;
+    RNG_GenerateGlobalRandomBytes(saltData,cipherValue.salt.len);
+
+    param = nsspkcs5_NewParam(cipherValue.alg, &cipherValue.salt, 1);
+    if (param == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL);
+    if (cipher == NULL) {
+	rv = SECFailure;
+	goto loser;
+    } 
+    cipherValue.value = *cipher;
+    cipherValue.param = param;
+
+    rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+loser:
+    if (cipher) {
+	SECITEM_FreeItem(cipher, PR_TRUE);
+    }
+    if (param) {
+	nsspkcs5_DestroyPBEParameter(param);
+    }
+    return rv;
+}
+
+/*
+ * use the password and the pbe parameters to generate an HMAC for the
+ * given plain text data. This is used by sftkdb_VerifyAttribute and
+ * sftkdb_SignAttribute. Signature is returned in signData. The caller
+ * must preallocate the space in the secitem.
+ */
+static SECStatus
+sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey, 
+	       NSSPKCS5PBEParameter *param,
+	       CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
+	       SECItem *plainText, SECItem *signData)
+{
+    SECStatus rv = SECFailure;
+    SECItem *key = NULL;
+    HMACContext *hashCx = NULL;
+    HASH_HashType hashType = HASH_AlgNULL;
+    const SECHashObject *hashObj;
+    unsigned char addressData[SDB_ULONG_SIZE];
+
+    hashType = HASH_FromHMACOid(param->encAlg);
+    if (hashType == HASH_AlgNULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return SECFailure;
+    }
+
+    hashObj = HASH_GetRawHashObject(hashType);
+    if (hashObj == NULL) {
+	goto loser;
+    }
+
+    key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE);
+    if (!key) {
+	goto loser;
+    }
+
+    hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
+    if (!hashCx) {
+	goto loser;
+    }
+    HMAC_Begin(hashCx);
+    /* Tie this value to a particular object. This is most important for
+     * the trust attributes, where and attacker could copy a value for
+     * 'validCA' from another cert in the database */
+    sftk_ULong2SDBULong(addressData, objectID);
+    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
+    sftk_ULong2SDBULong(addressData, attrType);
+    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
+
+    HMAC_Update(hashCx, plainText->data, plainText->len);
+    rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len);
+
+loser:
+    if (hashCx) {
+	HMAC_Destroy(hashCx, PR_TRUE);
+    }
+    if (key) {
+	SECITEM_FreeItem(key,PR_TRUE);
+    }
+    return rv;
+}
+
+/*
+ * Use our key to verify a signText block from the database matches
+ * the plainText from the database. The signText is a PKCS 5 v2 pbe.
+ * plainText is the plainText of the attribute.
+ */
+SECStatus
+sftkdb_VerifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID, 
+	     CK_ATTRIBUTE_TYPE attrType, 
+	     SECItem *plainText, SECItem *signText) 
+{
+    SECStatus rv;
+    sftkCipherValue signValue;
+    SECItem signature;
+    unsigned char signData[HASH_LENGTH_MAX];
+    
+
+    /* First get the cipher type */
+    rv = sftkdb_decodeCipherText(signText, &signValue);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    signature.data = signData;
+    signature.len = sizeof(signData);
+
+    rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param, 
+			objectID, attrType, plainText, &signature);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    if (SECITEM_CompareItem(&signValue.value,&signature) != 0) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	rv = SECFailure;
+    }
+
+loser:
+    if (signValue.param) {
+	nsspkcs5_DestroyPBEParameter(signValue.param);
+    }
+    if (signValue.arena) {
+	PORT_FreeArena(signValue.arena,PR_FALSE);
+    }
+    return rv;
+}
+
+/*
+ * Use our key to create a signText block the plain text of an
+ * attribute. The signText is a PKCS 5 v2 pbe.
+ */
+SECStatus
+sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey, 
+	 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType, 
+	 SECItem *plainText, SECItem **signature) 
+{
+    SECStatus rv;
+    sftkCipherValue signValue;
+    NSSPKCS5PBEParameter *param = NULL;
+    unsigned char saltData[HASH_LENGTH_MAX];
+    unsigned char signData[HASH_LENGTH_MAX];
+    SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */
+    SECOidTag prfAlg = SEC_OID_HMAC_SHA256;  /* hash for pb key generation */
+    HASH_HashType prfType;
+    unsigned int hmacLength;
+    unsigned int prfLength;
+
+    /* this code allows us to fetch the lengths and hashes on the fly
+     * by simply changing the OID above */
+    prfType = HASH_FromHMACOid(prfAlg);
+    PORT_Assert(prfType != HASH_AlgNULL);
+    prfLength = HASH_GetRawHashObject(prfType)->length;
+    PORT_Assert(prfLength <= HASH_LENGTH_MAX);
+
+    hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length;
+    PORT_Assert(hmacLength <= HASH_LENGTH_MAX);
+
+    /* initialize our CipherValue structure */
+    signValue.alg = SEC_OID_PKCS5_PBMAC1;
+    signValue.salt.len = prfLength;
+    signValue.salt.data = saltData;
+    signValue.value.data = signData;
+    signValue.value.len = hmacLength;
+    RNG_GenerateGlobalRandomBytes(saltData,prfLength);
+
+    /* initialize our pkcs5 paramter */
+    param = nsspkcs5_NewParam(signValue.alg, &signValue.salt, 1);
+    if (param == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    param->keyID = pbeBitGenIntegrityKey;
+    /* set the PKCS 5 v2 parameters, not extractable from the
+     * data passed into nsspkcs5_NewParam */
+    param->encAlg = hmacAlg;
+    param->hashType = prfType;
+    param->keyLen = hmacLength;
+    rv = SECOID_SetAlgorithmID(param->poolp, &param->prfAlg, prfAlg, NULL);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+
+    /* calculate the mac */
+    rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType,
+			plainText, &signValue.value);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    signValue.param = param;
+
+    /* write it out */
+    rv = sftkdb_encodeCipherText(arena, &signValue, signature);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+loser:
+    if (param) {
+	nsspkcs5_DestroyPBEParameter(param);
+    }
+    return rv;
+}
+
+/*
+ * safely swith the passed in key for the one caches in the keydb handle
+ * 
+ * A key attached to the handle tells us the the token is logged in.
+ * We can used the key attached to the handle in sftkdb_EncryptAttribute 
+ *  and sftkdb_DecryptAttribute calls.
+ */  
+static void 
+sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey)
+{
+    unsigned char *data;
+    int len;
+
+    if (keydb->passwordLock == NULL) {
+	PORT_Assert(keydb->type != SFTK_KEYDB_TYPE);
+	return;
+    }
+
+    /* an atomic pointer set would be nice */
+    SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock));
+    data = keydb->passwordKey.data;
+    len = keydb->passwordKey.len;
+    keydb->passwordKey.data = passKey->data;
+    keydb->passwordKey.len = passKey->len;
+    passKey->data = data;
+    passKey->len = len;
+    SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock));
+}
+
+/*
+ * returns true if we are in a middle of a merge style update.
+ */
+PRBool
+sftkdb_InUpdateMerge(SFTKDBHandle *keydb)
+{
+    return keydb->updateID ? PR_TRUE : PR_FALSE;
+}
+
+/*
+ * returns true if we are looking for the password for the user's old source
+ * database as part of a merge style update.
+ */
+PRBool
+sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb)
+{
+    if (!sftkdb_InUpdateMerge(keydb)) {
+	return PR_FALSE;
+    }
+    if (keydb->updateDBIsInit && !keydb->updatePasswordKey) {
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+/*
+ * fetch an update password key from a handle.
+ */
+SECItem *
+sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle)
+{
+    SECItem *key = NULL;
+
+    /* if we're a cert db, fetch it from our peer key db */
+    if (handle->type == SFTK_CERTDB_TYPE) {
+	handle = handle->peerDB;
+    }
+
+    /* don't have one */
+    if (!handle) {
+	return NULL;
+    }
+
+    PZ_Lock(handle->passwordLock);
+    if (handle->updatePasswordKey) {
+	key = SECITEM_DupItem(handle->updatePasswordKey);
+    }
+    PZ_Unlock(handle->passwordLock);
+
+    return key;
+}
+
+/*
+ * free the update password key from a handle.
+ */
+void
+sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle)
+{
+    SECItem *key = NULL;
+
+    /* don't have one */
+    if (!handle) {
+	return;
+    }
+
+    /* if we're a cert db, we don't have one */
+    if (handle->type == SFTK_CERTDB_TYPE) {
+	return;
+    }
+
+    PZ_Lock(handle->passwordLock);
+    if (handle->updatePasswordKey) {
+	key = handle->updatePasswordKey;
+	handle->updatePasswordKey = NULL;
+    }
+    PZ_Unlock(handle->passwordLock);
+
+    if (key) {
+	SECITEM_ZfreeItem(key, PR_TRUE);
+    }
+
+    return;
+}
+
+/*
+ * what password db we use depends heavily on the update state machine
+ * 
+ *  1) no update db, return the normal database.
+ *  2) update db and no merge return the update db.
+ *  3) update db and in merge: 
+ *      return the update db if we need the update db's password, 
+ *      otherwise return our normal datbase.
+ */
+static SDB *
+sftk_getPWSDB(SFTKDBHandle *keydb)
+{
+    if (!keydb->update) {
+	return keydb->db;
+    }
+    if (!sftkdb_InUpdateMerge(keydb)) {
+	return keydb->update;
+    }
+    if (sftkdb_NeedUpdateDBPassword(keydb)) {
+	return keydb->update;
+    }
+    return keydb->db;
+}
+
+/*
+ * return success if we have a valid password entry.
+ * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT
+ * in the token flags.
+ */
+SECStatus 
+sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
+{
+    SECItem salt, value;
+    unsigned char saltData[SDB_MAX_META_DATA_LEN];
+    unsigned char valueData[SDB_MAX_META_DATA_LEN];
+    CK_RV crv;
+    SDB *db;
+
+    if (keydb == NULL) {
+	return SECFailure;
+    }
+
+    db = sftk_getPWSDB(keydb);
+    if (db == NULL) {
+	return SECFailure;
+    }
+
+    salt.data = saltData;
+    salt.len = sizeof(saltData);
+    value.data = valueData;
+    value.len = sizeof(valueData);
+    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
+
+    /* If no password is set, we can update right away */
+    if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update 
+	&& crv != CKR_OK) {
+	/* update the peer certdb if it exists */
+	if (keydb->peerDB) {
+	    sftkdb_Update(keydb->peerDB, NULL);
+	}
+	sftkdb_Update(keydb, NULL);
+    }
+    return (crv == CKR_OK) ? SECSuccess : SECFailure;
+}
+
+#define SFTK_PW_CHECK_STRING "password-check"
+#define SFTK_PW_CHECK_LEN 14
+
+/*
+ * check if the supplied password is valid
+ */
+SECStatus  
+sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
+{
+    SECStatus rv;
+    SECItem salt, value;
+    unsigned char saltData[SDB_MAX_META_DATA_LEN];
+    unsigned char valueData[SDB_MAX_META_DATA_LEN];
+    SECItem key;
+    SECItem *result = NULL;
+    SDB *db;
+    CK_RV crv;
+
+    if (keydb == NULL) {
+	return SECFailure;
+    }
+
+    db = sftk_getPWSDB(keydb);
+    if (db == NULL) {
+	return SECFailure;
+    }
+
+    key.data = NULL;
+    key.len = 0;
+
+    if (pw == NULL) pw="";
+
+    /* get the entry from the database */
+    salt.data = saltData;
+    salt.len = sizeof(saltData);
+    value.data = valueData;
+    value.len = sizeof(valueData);
+    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
+    if (crv != CKR_OK) {
+	rv = SECFailure;
+	goto done;
+    }
+
+    /* get our intermediate key based on the entry salt value */
+    rv = sftkdb_passwordToKey(keydb, &salt, pw, &key);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    /* decrypt the entry value */
+    rv = sftkdb_DecryptAttribute(&key, &value, &result);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+
+    /* if it's what we expect, update our key in the database handle and
+     * return Success */
+    if ((result->len == SFTK_PW_CHECK_LEN) &&
+      PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){
+	/*
+	 * We have a password, now lets handle any potential update cases..
+	 * 
+	 * First, the normal case: no update. In this case we only need the
+	 *  the password for our only DB, which we now have, we switch 
+	 *  the keys and fall through.
+	 * Second regular (non-merge) update: The target DB does not yet have
+	 *  a password initialized, we now have the password for the source DB,
+	 *  so we can switch the keys and simply update the target database.
+	 * Merge update case: This one is trickier.
+	 *   1) If we need the source DB password, then we just got it here.
+	 *       We need to save that password,
+	 *       then we need to check to see if we need or have the target 
+	 *         database password.
+	 *       If we have it (it's the same as the source), or don't need 
+	 *         it (it's not set or is ""), we can start the update now.
+	 *       If we don't have it, we need the application to get it from 
+	 *         the user. Clear our sessions out to simulate a token 
+	 *         removal. C_GetTokenInfo will change the token description 
+	 *         and the token will still appear to be logged out.
+	 *   2) If we already have the source DB  password, this password is 
+	 *         for the target database. We can now move forward with the 
+	 *         update, as we now have both required passwords.
+	 *
+	 */
+        PZ_Lock(keydb->passwordLock);
+	if (sftkdb_NeedUpdateDBPassword(keydb)) {
+	    /* Squirrel this special key away.
+	     * This has the side effect of turning sftkdb_NeedLegacyPW off,
+	     * as well as changing which database is returned from 
+	     * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword()
+	     * and sftkdb_HasPasswordSet()) */
+	    keydb->updatePasswordKey = SECITEM_DupItem(&key);
+	    PZ_Unlock(keydb->passwordLock);
+	    if (keydb->updatePasswordKey == NULL) {
+		/* PORT_Error set by SECITEM_DupItem */
+		rv = SECFailure;
+		goto done;
+	    }
+
+	    /* Simulate a token removal -- we need to do this any
+             * any case at this point so the token name is correct. */
+	    *tokenRemoved = PR_TRUE;
+
+	    /* 
+	     * OK, we got the update DB password, see if we need a password
+	     * for the target...
+	     */
+	    if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
+		/* We have a password, do we know what the password is?
+		 *  check 1) for the password the user supplied for the 
+		 *           update DB,
+		 *    and 2) for the null password.
+		 *
+		 * RECURSION NOTE: we are calling ourselves here. This means
+		 *  any updates, switchKeys, etc will have been completed
+		 *  if these functions return successfully, in those cases
+		 *  just exit returning Success. We don't recurse infinitely
+		 *  because we are making this call from a NeedUpdateDBPassword
+		 *  block and we've already set that update password at this
+		 *  point.  */
+		rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved);
+		if (rv == SECSuccess) {
+		    /* source and target databases have the same password, we 
+		     * are good to go */
+		    goto done;
+		}
+		sftkdb_CheckPassword(keydb, "", tokenRemoved);
+
+		/*
+		 * Important 'NULL' code here. At this point either we 
+		 * succeeded in logging in with "" or we didn't.
+                 *
+                 *  If we did succeed at login, our machine state will be set
+		 * to logged in appropriately. The application will find that 
+		 * it's logged in as soon as it opens a new session. We have 
+		 * also completed the update. Life is good.
+		 * 
+		 *  If we did not succeed, well the user still successfully
+		 * logged into the update database, since we faked the token 
+		 * removal it's just like the user logged into his smart card 
+		 * then removed it. the actual login work, so we report that 
+		 * success back to the user, but we won't actually be
+		 * logged in. The application will find this out when it
+		 * checks it's login state, thus triggering another password
+		 * prompt so we can get the real target DB password.
+		 *
+		 * summary, we exit from here with SECSuccess no matter what.
+		 */
+		rv = SECSuccess;
+		goto done;
+	    } else {
+		/* there is no password, just fall through to update.
+		 * update will write the source DB's password record
+		 * into the target DB just like it would in a non-merge
+		 * update case. */
+	    }
+	} else {
+	    PZ_Unlock(keydb->passwordLock);
+	}
+	/* load the keys, so the keydb can parse it's key set */
+	sftkdb_switchKeys(keydb, &key);
+
+	/* we need to update, do it now */
+	if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
+	    /* update the peer certdb if it exists */
+	    if (keydb->peerDB) {
+		sftkdb_Update(keydb->peerDB, &key);
+	    }
+	    sftkdb_Update(keydb, &key);
+	}
+    } else {
+        rv = SECFailure;
+	/*PORT_SetError( bad password); */
+    }
+
+done:
+    if (key.data) {
+	PORT_ZFree(key.data,key.len);
+    }
+    if (result) {
+	SECITEM_FreeItem(result,PR_TRUE);
+    }
+    return rv;
+}
+
+/*
+ * return Success if the there is a cached password key.
+ */
+SECStatus
+sftkdb_PWCached(SFTKDBHandle *keydb)
+{
+    return keydb->passwordKey.data ? SECSuccess : SECFailure;
+}
+
+
+static CK_RV
+sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
+		       CK_OBJECT_HANDLE id, SECItem *newKey)
+{
+    CK_RV crv = CKR_OK;
+    CK_RV crv2;
+    CK_ATTRIBUTE authAttrs[] = {
+	{CKA_MODULUS, NULL, 0},
+	{CKA_PUBLIC_EXPONENT, NULL, 0},
+	{CKA_CERT_SHA1_HASH, NULL, 0},
+	{CKA_CERT_MD5_HASH, NULL, 0},
+	{CKA_TRUST_SERVER_AUTH, NULL, 0},
+	{CKA_TRUST_CLIENT_AUTH, NULL, 0},
+	{CKA_TRUST_EMAIL_PROTECTION, NULL, 0},
+	{CKA_TRUST_CODE_SIGNING, NULL, 0},
+	{CKA_TRUST_STEP_UP_APPROVED, NULL, 0},
+	{CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0},
+    };
+    CK_ULONG authAttrCount = sizeof(authAttrs)/sizeof(CK_ATTRIBUTE);
+    int i, count;
+    SFTKDBHandle *keyHandle = handle;
+    SDB *keyTarget = NULL;
+
+    id &= SFTK_OBJ_ID_MASK;
+
+    if (handle->type != SFTK_KEYDB_TYPE) {
+	keyHandle = handle->peerDB;
+    }
+
+    if (keyHandle == NULL) {
+	return CKR_OK;
+    }
+
+    /* old DB's don't have meta data, finished with MACs */
+    keyTarget = SFTK_GET_SDB(keyHandle);
+    if ((keyTarget->sdb_flags &SDB_HAS_META) == 0) {
+	return CKR_OK;
+    }
+
+    /*
+     * STEP 1: find the MACed attributes of this object 
+     */
+    crv2 = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
+    count = 0;
+    /* allocate space for the attributes */
+    for (i=0; i < authAttrCount; i++) {
+	if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
+	    continue;
+	}
+	count++;
+        authAttrs[i].pValue = PORT_ArenaAlloc(arena,authAttrs[i].ulValueLen);
+	if (authAttrs[i].pValue == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+    }
+
+    /* if count was zero, none were found, finished with MACs */
+    if (count == 0) {
+	return CKR_OK;
+    }
+
+    crv = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
+    /* ignore error code, we expect some possible errors */
+
+    /* GetAttributeValue just verified the old macs, safe to write
+     * them out then... */
+    for (i=0; i < authAttrCount; i++) {
+	SECItem *signText;
+	SECItem plainText;
+	SECStatus rv;
+
+	if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
+	    continue;
+	}
+
+	plainText.data = authAttrs[i].pValue;
+	plainText.len = authAttrs[i].ulValueLen;
+	rv = sftkdb_SignAttribute(arena, newKey, id, 
+			authAttrs[i].type, &plainText, &signText);
+	if (rv != SECSuccess) {
+	    return CKR_GENERAL_ERROR;
+	}
+	rv = sftkdb_PutAttributeSignature(handle, keyTarget, id, 
+				authAttrs[i].type, signText);
+	if (rv != SECSuccess) {
+	    return CKR_GENERAL_ERROR;
+	}
+    }
+
+    return CKR_OK;
+}
+	
+static CK_RV
+sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
+		       CK_OBJECT_HANDLE id, SECItem *newKey)
+{
+    CK_RV crv = CKR_OK;
+    CK_RV crv2;
+    CK_ATTRIBUTE *first, *last;
+    CK_ATTRIBUTE privAttrs[] = {
+	{CKA_VALUE, NULL, 0},
+	{CKA_PRIVATE_EXPONENT, NULL, 0},
+	{CKA_PRIME_1, NULL, 0},
+	{CKA_PRIME_2, NULL, 0},
+	{CKA_EXPONENT_1, NULL, 0},
+	{CKA_EXPONENT_2, NULL, 0},
+	{CKA_COEFFICIENT, NULL, 0} };
+    CK_ULONG privAttrCount = sizeof(privAttrs)/sizeof(CK_ATTRIBUTE);
+    int i, count;
+
+    /*
+     * STEP 1. Read the old attributes in the clear.
+     */
+
+    /* Get the attribute sizes.
+     *  ignore the error code, we will have unknown attributes here */
+    crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount);
+
+    /*
+     * find the valid block of attributes and fill allocate space for
+     * their data */
+    first = last = NULL;
+    for (i=0; i < privAttrCount; i++) {
+         /* find the block of attributes that are appropriate for this 
+          * objects. There should only be once contiguous block, if not 
+          * there's an error.
+          *
+          * find the first and last good entry.
+          */
+	if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)){
+	    if (!first) continue;
+	    if (!last) {
+		/* previous entry was last good entry */
+		last= &privAttrs[i-1];
+	    }
+	    continue;
+	}
+	if (!first) {
+	    first = &privAttrs[i];
+	}
+	if (last) {
+	   /* OOPS, we've found another good entry beyond the end of the
+	    * last good entry, we need to fail here. */
+	   crv = CKR_GENERAL_ERROR;
+	   break;
+	}
+        privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen);
+	if (privAttrs[i].pValue == NULL) {
+	    crv = CKR_HOST_MEMORY;
+	    break;
+	}
+    }
+    if (first == NULL) {
+	/* no valid entries found, return error based on crv2 */
+	return crv2;
+    }
+    if (last == NULL) {
+	last = &privAttrs[privAttrCount-1];
+    }
+    if (crv != CKR_OK) {
+	return crv;
+    }
+    /* read the attributes */
+    count = (last-first)+1;
+    crv = sftkdb_GetAttributeValue(keydb, id, first, count);
+    if (crv != CKR_OK) {
+	return crv;
+    }
+
+    /*
+     * STEP 2: read the encrypt the attributes with the new key.
+     */
+    for (i=0; i < count; i++) {
+	SECItem plainText;
+	SECItem *result;
+	SECStatus rv;
+
+	plainText.data = first[i].pValue;
+	plainText.len = first[i].ulValueLen;
+    	rv = sftkdb_EncryptAttribute(arena, newKey, &plainText, &result);
+	if (rv != SECSuccess) {
+	   return CKR_GENERAL_ERROR;
+	}
+	first[i].pValue = result->data;
+	first[i].ulValueLen = result->len;
+	/* clear our sensitive data out */
+	PORT_Memset(plainText.data, 0, plainText.len);
+    }
+
+
+    /*
+     * STEP 3: write the newly encrypted attributes out directly
+     */
+    id &= SFTK_OBJ_ID_MASK;
+    keydb->newKey = newKey;
+    crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count);
+    keydb->newKey = NULL;
+
+    return crv;
+}
+	
+static CK_RV
+sftk_convertAttributes(SFTKDBHandle *handle, 
+			CK_OBJECT_HANDLE id, SECItem *newKey)
+{
+    CK_RV crv = CKR_OK;
+    PLArenaPool *arena = NULL;
+
+    /* get a new arena to simplify cleanup */
+    arena = PORT_NewArena(1024);
+    if (!arena) {
+	return CKR_HOST_MEMORY;
+    }
+
+    /*
+     * first handle the MACS
+     */
+    crv = sftk_updateMacs(arena, handle, id, newKey);
+    if (crv != CKR_OK) {
+	goto loser;
+    }
+
+    if (handle->type == SFTK_KEYDB_TYPE) {
+	crv = sftk_updateEncrypted(arena, handle, id, newKey);
+	if (crv != CKR_OK) {
+	    goto loser;
+	}
+    }
+
+    /* free up our mess */
+    /* NOTE: at this point we know we've cleared out any unencrypted data */
+    PORT_FreeArena(arena, PR_FALSE);
+    return CKR_OK;
+
+loser:
+    /* there may be unencrypted data, clear it out down */
+    PORT_FreeArena(arena, PR_TRUE);
+    return crv;
+}
+
+
+/*
+ * must be called with the old key active.
+ */
+CK_RV
+sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template, 
+			CK_ULONG count, SECItem *newKey)
+{
+    SDBFind *find = NULL;
+    CK_ULONG idCount = SFTK_MAX_IDS;
+    CK_OBJECT_HANDLE ids[SFTK_MAX_IDS];
+    CK_RV crv, crv2;
+    int i;
+
+    crv = sftkdb_FindObjectsInit(handle, template, count, &find);
+
+    if (crv != CKR_OK) {
+	return crv;
+    }
+    while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) {
+	crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount);
+	for (i=0; (crv == CKR_OK) && (i < idCount); i++) {
+	    crv = sftk_convertAttributes(handle, ids[i], newKey);
+	}
+    }
+    crv2 = sftkdb_FindObjectsFinal(handle, find);
+    if (crv == CKR_OK) crv = crv2;
+
+    return crv;
+}
+
+
+/*
+ * change the database password.
+ */
+SECStatus
+sftkdb_ChangePassword(SFTKDBHandle *keydb, 
+                      char *oldPin, char *newPin, PRBool *tokenRemoved)
+{
+    SECStatus rv = SECSuccess;
+    SECItem plainText;
+    SECItem newKey;
+    SECItem *result = NULL;
+    SECItem salt, value;
+    SFTKDBHandle *certdb;
+    unsigned char saltData[SDB_MAX_META_DATA_LEN];
+    unsigned char valueData[SDB_MAX_META_DATA_LEN];
+    CK_RV crv;
+    SDB *db;
+
+    if (keydb == NULL) {
+	return SECFailure;
+    }
+
+    db = SFTK_GET_SDB(keydb);
+    if (db == NULL) {
+	return SECFailure;
+    }
+
+    newKey.data = NULL;
+
+    /* make sure we have a valid old pin */
+    crv = (*keydb->db->sdb_Begin)(keydb->db);
+    if (crv != CKR_OK) {
+	rv = SECFailure;
+	goto loser;
+    }
+    salt.data = saltData;
+    salt.len = sizeof(saltData);
+    value.data = valueData;
+    value.len = sizeof(valueData);
+    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
+    if (crv == CKR_OK) {
+	rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved);
+	if (rv == SECFailure) {
+	    goto loser;
+	}
+    } else {
+	salt.len = SHA1_LENGTH;
+    	RNG_GenerateGlobalRandomBytes(salt.data,salt.len);
+    }
+
+    rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+
+    /*
+     * convert encrypted entries here.
+     */
+    crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey);
+    if (crv != CKR_OK) {
+	rv = SECFailure;
+	goto loser;
+    }
+    /* fix up certdb macs */
+    certdb = keydb->peerDB;
+    if (certdb) {
+	CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) };
+	CK_OBJECT_CLASS myClass = CKO_NETSCAPE_TRUST;
+
+	objectType.pValue = &myClass;
+	crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
+	if (crv != CKR_OK) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+	myClass = CKO_PUBLIC_KEY;
+	crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
+	if (crv != CKR_OK) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+    }
+
+
+    plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
+    plainText.len = SFTK_PW_CHECK_LEN;
+
+    rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+    value.data = result->data;
+    value.len = result->len;
+    crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value);
+    if (crv != CKR_OK) {
+	rv = SECFailure;
+	goto loser;
+    }
+    crv = (*keydb->db->sdb_Commit)(keydb->db);
+    if (crv != CKR_OK) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    keydb->newKey = NULL;
+
+    sftkdb_switchKeys(keydb, &newKey);
+
+loser:
+    if (newKey.data) {
+	PORT_ZFree(newKey.data,newKey.len);
+    }
+    if (result) {
+	SECITEM_FreeItem(result, PR_FALSE);
+    }
+    if (rv != SECSuccess) {
+        (*keydb->db->sdb_Abort)(keydb->db);
+    }
+    
+    return rv;
+}
+
+/*
+ * lose our cached password
+ */
+SECStatus
+sftkdb_ClearPassword(SFTKDBHandle *keydb)
+{
+    SECItem oldKey;
+    oldKey.data = NULL;
+    oldKey.len = 0;
+    sftkdb_switchKeys(keydb, &oldKey);
+    if (oldKey.data) {
+	PORT_ZFree(oldKey.data, oldKey.len);
+    }
+    return SECSuccess;
+}
+
+
diff --git a/mozilla/security/nss/lib/softoken/softkver.c b/mozilla/security/nss/lib/softoken/softkver.c
new file mode 100644
index 0000000..931d620
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/softkver.c
@@ -0,0 +1,56 @@
+/* ***** 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) 2002
+ * 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 ***** */
+
+/* Library identity and versioning */
+
+#include "softkver.h"
+
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
+
+/*
+ * Version information for the 'ident' and 'what commands
+ *
+ * NOTE: the first component of the concatenated rcsid string
+ * must not end in a '$' to prevent rcs keyword substitution.
+ */
+const char __nss_softokn_rcsid[] = "$Header: NSS " SOFTOKEN_VERSION _DEBUG_STRING
+        "  " __DATE__ " " __TIME__ " $";
+const char __nss_softokn_sccsid[] = "@(#)NSS " SOFTOKEN_VERSION _DEBUG_STRING
+        "  " __DATE__ " " __TIME__;
diff --git a/mozilla/security/nss/lib/softoken/softkver.h b/mozilla/security/nss/lib/softoken/softkver.h
new file mode 100644
index 0000000..c7ea068
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/softkver.h
@@ -0,0 +1,66 @@
+/*
+ * Softoken version numbers
+ *
+ * ***** 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 ***** */
+
+#ifndef _SOFTKVER_H_
+#define _SOFTKVER_H_
+
+#ifdef NSS_ENABLE_ECC
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+#define SOFTOKEN_ECC_STRING " Extended ECC"
+#else
+#define SOFTOKEN_ECC_STRING " Basic ECC"
+#endif
+#else
+#define SOFTOKEN_ECC_STRING ""
+#endif
+
+/*
+ * Softoken's major version, minor version, patch level, and whether
+ * this is a beta release.
+ *
+ * The format of the version string should be
+ *     "<major version>.<minor version>[.<patch level>][ <ECC>][ <Beta>]"
+ */
+#define SOFTOKEN_VERSION  "3.12.4.5" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VMAJOR   3
+#define SOFTOKEN_VMINOR   12
+#define SOFTOKEN_VPATCH   4
+#define SOFTOKEN_BETA     PR_FALSE
+
+#endif /* _SOFTKVER_H_ */
diff --git a/mozilla/security/nss/lib/softoken/softoken.h b/mozilla/security/nss/lib/softoken/softoken.h
new file mode 100644
index 0000000..6375f9a
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/softoken.h
@@ -0,0 +1,385 @@
+/*
+ * softoken.h - private data structures and prototypes for the softoken lib
+ *
+ * ***** 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 ***** */
+/* $Id: softoken.h,v 1.23 2009/02/26 06:57:15 nelson%bolyard.com Exp $ */
+
+#ifndef _SOFTOKEN_H_
+#define _SOFTOKEN_H_
+
+#include "blapi.h"
+#include "lowkeyti.h"
+#include "softoknt.h"
+#include "secoidt.h"
+
+#include "pkcs11t.h"     /* CK_RV Required for sftk_fipsPowerUpSelfTest(). */
+
+SEC_BEGIN_PROTOS
+
+/*
+** RSA encryption/decryption. When encrypting/decrypting the output
+** buffer must be at least the size of the public key modulus.
+*/
+
+/*
+** Format some data into a PKCS#1 encryption block, preparing the
+** data for RSA encryption.
+**	"result" where the formatted block is stored (memory is allocated)
+**	"modulusLen" the size of the formatted block
+**	"blockType" what block type to use (SEC_RSABlock*)
+**	"data" the data to format
+*/
+extern SECStatus RSA_FormatBlock(SECItem *result,
+				 unsigned int modulusLen,
+				 RSA_BlockType blockType,
+				 SECItem *data);
+/*
+** Similar, but just returns a pointer to the allocated memory, *and*
+** will *only* format one block, even if we (in the future) modify
+** RSA_FormatBlock() to loop over multiples of modulusLen.
+*/
+extern unsigned char *RSA_FormatOneBlock(unsigned int modulusLen,
+					 RSA_BlockType blockType,
+					 SECItem *data);
+
+
+
+/*
+ * convenience wrappers for doing single RSA operations. They create the
+ * RSA context internally and take care of the formatting
+ * requirements. Blinding happens automagically within RSA_Sign and
+ * RSA_DecryptBlock.
+ */
+extern
+SECStatus RSA_Sign(NSSLOWKEYPrivateKey *key, unsigned char *output,
+		       unsigned int *outputLen, unsigned int maxOutputLen,
+		       unsigned char *input, unsigned int inputLen);
+extern
+SECStatus RSA_HashSign(SECOidTag hashOid,
+			NSSLOWKEYPrivateKey *key, unsigned char *sig,
+			unsigned int *sigLen, unsigned int maxLen,
+			unsigned char *hash, unsigned int hashLen);
+extern
+SECStatus RSA_CheckSign(NSSLOWKEYPublicKey *key, unsigned char *sign,
+			    unsigned int signLength, unsigned char *hash,
+			    unsigned int hashLength);
+extern
+SECStatus RSA_HashCheckSign(SECOidTag hashOid,
+			    NSSLOWKEYPublicKey *key, unsigned char *sig,
+			    unsigned int sigLen, unsigned char *digest,
+			    unsigned int digestLen);
+extern
+SECStatus RSA_CheckSignRecover(NSSLOWKEYPublicKey *key, unsigned char *data,
+    			    unsigned int *data_len,unsigned int max_output_len, 
+			    unsigned char *sign, unsigned int sign_len);
+extern
+SECStatus RSA_EncryptBlock(NSSLOWKEYPublicKey *key, unsigned char *output,
+			   unsigned int *outputLen, unsigned int maxOutputLen,
+			   unsigned char *input, unsigned int inputLen);
+extern
+SECStatus RSA_DecryptBlock(NSSLOWKEYPrivateKey *key, unsigned char *output,
+			   unsigned int *outputLen, unsigned int maxOutputLen,
+			   unsigned char *input, unsigned int inputLen);
+
+/*
+ * added to make pkcs #11 happy
+ *   RAW is RSA_X_509
+ */
+extern
+SECStatus RSA_SignRaw( NSSLOWKEYPrivateKey *key, unsigned char *output,
+			 unsigned int *output_len, unsigned int maxOutputLen,
+			 unsigned char *input, unsigned int input_len);
+extern
+SECStatus RSA_CheckSignRaw( NSSLOWKEYPublicKey *key, unsigned char *sign, 
+			    unsigned int sign_len, unsigned char *hash, 
+			    unsigned int hash_len);
+extern
+SECStatus RSA_CheckSignRecoverRaw( NSSLOWKEYPublicKey *key, unsigned char *data,
+			    unsigned int *data_len, unsigned int max_output_len,
+			    unsigned char *sign, unsigned int sign_len);
+extern
+SECStatus RSA_EncryptRaw( NSSLOWKEYPublicKey *key, unsigned char *output,
+			    unsigned int *output_len,
+			    unsigned int max_output_len, 
+			    unsigned char *input, unsigned int input_len);
+extern
+SECStatus RSA_DecryptRaw(NSSLOWKEYPrivateKey *key, unsigned char *output,
+			     unsigned int *output_len,
+    			     unsigned int max_output_len,
+			     unsigned char *input, unsigned int input_len);
+#ifdef NSS_ENABLE_ECC
+/*
+** pepare an ECParam structure from DEREncoded params
+ */
+extern SECStatus EC_FillParams(PRArenaPool *arena,
+                               const SECItem *encodedParams, ECParams *params);
+extern SECStatus EC_DecodeParams(const SECItem *encodedParams, 
+				ECParams **ecparams);
+extern SECStatus EC_CopyParams(PRArenaPool *arena, ECParams *dstParams,
+              			const ECParams *srcParams);
+#endif
+
+
+/*
+** Prepare a buffer for padded CBC encryption, growing to the appropriate 
+** boundary, filling with the appropriate padding.
+**
+** blockSize must be a power of 2.
+**
+** We add from 1 to blockSize bytes -- we *always* grow.
+** The extra bytes contain the value of the length of the padding:
+** if we have 2 bytes of padding, then the padding is "0x02, 0x02".
+**
+** NOTE: If arena is non-NULL, we re-allocate from there, otherwise
+** we assume (and use) PR memory (re)allocation.
+*/
+extern unsigned char * CBC_PadBuffer(PRArenaPool *arena, unsigned char *inbuf, 
+                                     unsigned int inlen, unsigned int *outlen,
+				     int blockSize);
+
+
+/****************************************/
+/*
+** Power-Up selftests required for FIPS and invoked only
+** under PKCS #11 FIPS mode.
+*/
+extern CK_RV sftk_fipsPowerUpSelfTest( void ); 
+
+/*
+** make known fixed PKCS #11 key types to their sizes in bytes
+*/	
+unsigned long sftk_MapKeySize(CK_KEY_TYPE keyType);
+
+/*
+** FIPS 140-2 auditing
+*/
+extern PRBool sftk_audit_enabled;
+
+extern void sftk_LogAuditMessage(NSSAuditSeverity severity, 
+				 NSSAuditType, const char *msg);
+
+extern void sftk_AuditCreateObject(CK_SESSION_HANDLE hSession,
+			CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+			CK_OBJECT_HANDLE_PTR phObject, CK_RV rv);
+
+extern void sftk_AuditCopyObject(CK_SESSION_HANDLE hSession,
+			CK_OBJECT_HANDLE hObject,
+			CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+			CK_OBJECT_HANDLE_PTR phNewObject, CK_RV rv);
+
+extern void sftk_AuditDestroyObject(CK_SESSION_HANDLE hSession,
+			CK_OBJECT_HANDLE hObject, CK_RV rv);
+
+extern void sftk_AuditGetObjectSize(CK_SESSION_HANDLE hSession,
+			CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize,
+			CK_RV rv);
+
+extern void sftk_AuditGetAttributeValue(CK_SESSION_HANDLE hSession,
+			CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate,
+			CK_ULONG ulCount, CK_RV rv);
+
+extern void sftk_AuditSetAttributeValue(CK_SESSION_HANDLE hSession,
+			CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate,
+			CK_ULONG ulCount, CK_RV rv);
+
+extern void sftk_AuditCryptInit(const char *opName,
+			CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,
+			CK_OBJECT_HANDLE hKey, CK_RV rv);
+
+extern void sftk_AuditGenerateKey(CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,
+			CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+			CK_OBJECT_HANDLE_PTR phKey, CK_RV rv);
+
+extern void sftk_AuditGenerateKeyPair(CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,
+			CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+			CK_ULONG ulPublicKeyAttributeCount,
+			CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+			CK_ULONG ulPrivateKeyAttributeCount,
+			CK_OBJECT_HANDLE_PTR phPublicKey,
+			CK_OBJECT_HANDLE_PTR phPrivateKey, CK_RV rv);
+
+extern void sftk_AuditWrapKey(CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,
+			CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
+			CK_BYTE_PTR pWrappedKey,
+			CK_ULONG_PTR pulWrappedKeyLen, CK_RV rv);
+
+extern void sftk_AuditUnwrapKey(CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,
+			CK_OBJECT_HANDLE hUnwrappingKey,
+			CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,
+			CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
+			CK_OBJECT_HANDLE_PTR phKey, CK_RV rv);
+
+extern void sftk_AuditDeriveKey(CK_SESSION_HANDLE hSession,
+			CK_MECHANISM_PTR pMechanism,
+			CK_OBJECT_HANDLE hBaseKey,
+			CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
+			CK_OBJECT_HANDLE_PTR phKey, CK_RV rv);
+
+extern void sftk_AuditDigestKey(CK_SESSION_HANDLE hSession,
+			CK_OBJECT_HANDLE hKey, CK_RV rv);
+
+/*
+** FIPS 140-2 Error state
+*/
+extern PRBool sftk_fatalError;
+
+/*
+** macros to check for forked child process after C_Initialize
+*/
+#if defined(XP_UNIX) && !defined(NO_CHECK_FORK)
+
+#ifdef DEBUG
+
+#define FORK_ASSERT() \
+    { \
+        char* forkAssert = getenv("NSS_STRICT_NOFORK"); \
+        if ( (!forkAssert) || (0 == strcmp(forkAssert, "1")) ) { \
+            PORT_Assert(0); \
+        } \
+    }
+
+#else
+
+#define FORK_ASSERT()
+
+#endif
+
+/* we have 3 methods of implementing the fork checks :
+ * - Solaris "mixed" method
+ * - pthread_atfork method
+ * - getpid method
+ */
+
+#if !defined (CHECK_FORK_MIXED) && !defined(CHECK_FORK_PTHREAD) && \
+    !defined (CHECK_FORK_GETPID)
+
+/* Choose fork check method automatically unless specified
+ * This section should be updated as more platforms get pthread fixes
+ * to unregister fork handlers in dlclose.
+ */
+
+#ifdef SOLARIS
+
+/* Solaris 8, s9 use PID checks, s10 uses pthread_atfork */
+
+#define CHECK_FORK_MIXED
+
+#elif defined(LINUX)
+
+#define CHECK_FORK_PTHREAD
+
+#else
+
+/* Other Unix platforms use only PID checks. Even if pthread_atfork is
+ * available, the behavior of dlclose isn't guaranteed by POSIX to
+ * unregister the fork handler. */
+
+#define CHECK_FORK_GETPID
+
+#endif
+
+#endif
+
+#if defined(CHECK_FORK_MIXED)
+
+extern PRBool usePthread_atfork;
+#include <unistd.h>
+extern pid_t myPid;
+extern PRBool forked;
+
+#define PARENT_FORKED() (usePthread_atfork ? forked : (myPid && myPid != getpid()))
+
+#elif defined(CHECK_FORK_PTHREAD)
+
+extern PRBool forked;
+
+#define PARENT_FORKED() forked
+
+#elif defined(CHECK_FORK_GETPID)
+
+#include <unistd.h>
+extern pid_t myPid;
+
+#define PARENT_FORKED() (myPid && myPid != getpid())
+    
+#endif
+
+extern PRBool parentForkedAfterC_Initialize;
+extern PRBool sftkForkCheckDisabled;
+
+#define CHECK_FORK() \
+    do { \
+        if (!sftkForkCheckDisabled && PARENT_FORKED()) { \
+            FORK_ASSERT(); \
+            return CKR_DEVICE_ERROR; \
+        } \
+    } while (0)
+
+#define SKIP_AFTER_FORK(x) if (!parentForkedAfterC_Initialize) x
+
+#define ENABLE_FORK_CHECK() \
+    { \
+        char* doForkCheck = getenv("NSS_STRICT_NOFORK"); \
+        if ( doForkCheck && !strcmp(doForkCheck, "DISABLED") ) { \
+            sftkForkCheckDisabled = PR_TRUE; \
+        } \
+    }
+
+
+#else
+
+/* non-Unix platforms, or fork check disabled */
+
+#define CHECK_FORK()
+#define SKIP_AFTER_FORK(x) x
+#define ENABLE_FORK_CHECK()
+
+#ifndef NO_FORK_CHECK
+#define NO_FORK_CHECK
+#endif
+
+#endif
+
+
+SEC_END_PROTOS
+
+#endif /* _SOFTOKEN_H_ */
diff --git a/mozilla/security/nss/lib/softoken/softoknt.h b/mozilla/security/nss/lib/softoken/softoknt.h
new file mode 100644
index 0000000..0ec8992
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/softoknt.h
@@ -0,0 +1,94 @@
+/*
+ * softoknt.h - public data structures for the software token library
+ *
+ * ***** 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 ***** */
+/* $Id: softoknt.h,v 1.6 2009/08/03 16:58:28 christophe.ravel.bugs%sun.com Exp $ */
+
+#ifndef _SOFTOKNT_H_
+#define _SOFTOKNT_H_
+
+/*
+ * RSA block types
+ *
+ * The actual values are important -- they are fixed, *not* arbitrary.
+ * The explicit value assignments are not needed (because C would give
+ * us those same values anyway) but are included as a reminder...
+ */
+typedef enum {
+    RSA_BlockPrivate0 = 0,	/* unused, really */
+    RSA_BlockPrivate = 1,	/* pad for a private-key operation */
+    RSA_BlockPublic = 2,	/* pad for a public-key operation */
+    RSA_BlockOAEP = 3,		/* use OAEP padding */
+				/* XXX is this only for a public-key
+				   operation? If so, add "Public" */
+    RSA_BlockRaw = 4,		/* simply justify the block appropriately */
+    RSA_BlockTotal
+} RSA_BlockType;
+
+#define NSS_SOFTOKEN_DEFAULT_CHUNKSIZE   2048
+
+/*
+ * FIPS 140-2 auditing
+ */
+typedef enum {
+    NSS_AUDIT_ERROR = 3,    /* errors */
+    NSS_AUDIT_WARNING = 2,  /* warning messages */
+    NSS_AUDIT_INFO = 1      /* informational messages */
+} NSSAuditSeverity;
+
+typedef enum {
+    NSS_AUDIT_ACCESS_KEY = 0,
+    NSS_AUDIT_CHANGE_KEY,
+    NSS_AUDIT_COPY_KEY,
+    NSS_AUDIT_CRYPT,
+    NSS_AUDIT_DERIVE_KEY,
+    NSS_AUDIT_DESTROY_KEY,
+    NSS_AUDIT_DIGEST_KEY,
+    NSS_AUDIT_FIPS_STATE,
+    NSS_AUDIT_GENERATE_KEY,
+    NSS_AUDIT_INIT_PIN,
+    NSS_AUDIT_INIT_TOKEN,
+    NSS_AUDIT_LOAD_KEY,
+    NSS_AUDIT_LOGIN,
+    NSS_AUDIT_LOGOUT,
+    NSS_AUDIT_SELF_TEST,
+    NSS_AUDIT_SET_PIN,
+    NSS_AUDIT_UNWRAP_KEY,
+    NSS_AUDIT_WRAP_KEY
+} NSSAuditType;
+
+#endif /* _SOFTOKNT_H_ */
diff --git a/mozilla/security/nss/lib/softoken/tlsprf.c b/mozilla/security/nss/lib/softoken/tlsprf.c
new file mode 100644
index 0000000..2c100d9
--- /dev/null
+++ b/mozilla/security/nss/lib/softoken/tlsprf.c
@@ -0,0 +1,215 @@
+/* tlsprf.c - TLS Pseudo Random Function (PRF) implementation
+ *
+ * ***** 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 ***** */
+/* $Id: tlsprf.c,v 1.6 2005/08/06 09:27:28 nelsonb%netscape.com Exp $ */
+
+#include "pkcs11i.h"
+#include "blapi.h"
+
+#define SFTK_OFFSETOF(str, memb) ((PRPtrdiff)(&(((str *)0)->memb)))
+
+static void sftk_TLSPRFNull(void *data, PRBool freeit)
+{
+    return;
+} 
+
+typedef struct {
+    PRUint32	   cxSize;	/* size of allocated block, in bytes.        */
+    PRUint32       cxBufSize;   /* sizeof buffer at cxBufPtr.                */
+    unsigned char *cxBufPtr;	/* points to real buffer, may be cxBuf.      */
+    PRUint32	   cxKeyLen;	/* bytes of cxBufPtr containing key.         */
+    PRUint32	   cxDataLen;	/* bytes of cxBufPtr containing data.        */
+    SECStatus	   cxRv;	/* records failure of void functions.        */
+    PRBool	   cxIsFIPS;	/* true if conforming to FIPS 198.           */
+    unsigned char  cxBuf[512];	/* actual size may be larger than 512.       */
+} TLSPRFContext;
+
+static void
+sftk_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data, 
+                        unsigned int data_len)
+{
+    PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen;
+
+    if (cx->cxRv != SECSuccess)	/* function has previously failed. */
+    	return;
+    if (bytesUsed + data_len > cx->cxBufSize) {
+	/* We don't use realloc here because 
+	** (a) realloc doesn't zero out the old block, and 
+	** (b) if realloc fails, we lose the old block.
+	*/
+	PRUint32 newBufSize = bytesUsed + data_len + 512;
+    	unsigned char * newBuf = (unsigned char *)PORT_Alloc(newBufSize);
+	if (!newBuf) {
+	   cx->cxRv = SECFailure;
+	   return;
+	}
+	PORT_Memcpy(newBuf, cx->cxBufPtr, bytesUsed);
+	if (cx->cxBufPtr != cx->cxBuf) {
+	    PORT_ZFree(cx->cxBufPtr, bytesUsed);
+	}
+	cx->cxBufPtr  = newBuf;
+	cx->cxBufSize = newBufSize;
+    }
+    PORT_Memcpy(cx->cxBufPtr + bytesUsed, data, data_len);
+    cx->cxDataLen += data_len;
+}
+
+static void 
+sftk_TLSPRFEnd(TLSPRFContext *ctx, unsigned char *hashout,
+	 unsigned int *pDigestLen, unsigned int maxDigestLen)
+{
+    *pDigestLen = 0; /* tells Verify that no data has been input yet. */
+}
+
+/* Compute the PRF values from the data previously input. */
+static SECStatus
+sftk_TLSPRFUpdate(TLSPRFContext *cx, 
+                  unsigned char *sig,		/* output goes here. */
+		  unsigned int * sigLen, 	/* how much output.  */
+		  unsigned int   maxLen, 	/* output buffer size */
+		  unsigned char *hash, 		/* unused. */
+		  unsigned int   hashLen)	/* unused. */
+{
+    SECStatus rv;
+    SECItem sigItem;
+    SECItem seedItem;
+    SECItem secretItem;
+
+    if (cx->cxRv != SECSuccess)
+    	return cx->cxRv;
+
+    secretItem.data = cx->cxBufPtr;
+    secretItem.len  = cx->cxKeyLen;
+
+    seedItem.data = cx->cxBufPtr + cx->cxKeyLen;
+    seedItem.len  = cx->cxDataLen;
+
+    sigItem.data = sig;
+    sigItem.len  = maxLen;
+
+    rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS);
+    if (rv == SECSuccess && sigLen != NULL)
+    	*sigLen = sigItem.len;
+    return rv;
+
+}
+
+static SECStatus
+sftk_TLSPRFVerify(TLSPRFContext *cx, 
+                  unsigned char *sig, 		/* input, for comparison. */
+		  unsigned int   sigLen,	/* length of sig.         */
+		  unsigned char *hash, 		/* data to be verified.   */
+		  unsigned int   hashLen)	/* size of hash data.     */
+{
+    unsigned char * tmp    = (unsigned char *)PORT_Alloc(sigLen);
+    unsigned int    tmpLen = sigLen;
+    SECStatus       rv;
+
+    if (!tmp)
+    	return SECFailure;
+    if (hashLen) {
+    	/* hashLen is non-zero when the user does a one-step verify.
+	** In this case, none of the data has been input yet.
+	*/
+    	sftk_TLSPRFHashUpdate(cx, hash, hashLen);
+    }
+    rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
+    if (rv == SECSuccess) {
+    	rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen));
+    }
+    PORT_ZFree(tmp, sigLen);
+    return rv;
+}
+
+static void
+sftk_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit)
+{
+    if (freeit) {
+	if (cx->cxBufPtr != cx->cxBuf) 
+	    PORT_ZFree(cx->cxBufPtr, cx->cxBufSize);
+	PORT_ZFree(cx, cx->cxSize);
+    }
+}
+
+CK_RV
+sftk_TLSPRFInit(SFTKSessionContext *context, 
+		  SFTKObject *        key, 
+		  CK_KEY_TYPE         key_type)
+{
+    SFTKAttribute * keyVal;
+    TLSPRFContext * prf_cx;
+    CK_RV           crv = CKR_HOST_MEMORY;
+    PRUint32        keySize;
+    PRUint32        blockSize;
+
+    if (key_type != CKK_GENERIC_SECRET)
+    	return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */
+
+    context->multi = PR_TRUE;
+
+    keyVal = sftk_FindAttribute(key, CKA_VALUE);
+    keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen;
+    blockSize = keySize + sizeof(TLSPRFContext);
+    prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize);
+    if (!prf_cx) 
+    	goto done;
+    prf_cx->cxSize    = blockSize;
+    prf_cx->cxKeyLen  = keySize;
+    prf_cx->cxDataLen = 0;
+    prf_cx->cxBufSize = blockSize - SFTK_OFFSETOF(TLSPRFContext, cxBuf);
+    prf_cx->cxRv      = SECSuccess;
+    prf_cx->cxIsFIPS  = (key->slot->slotID == FIPS_SLOT_ID);
+    prf_cx->cxBufPtr  = prf_cx->cxBuf;
+    if (keySize)
+	PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize);
+
+    context->hashInfo    = (void *) prf_cx;
+    context->cipherInfo  = (void *) prf_cx;
+    context->hashUpdate  = (SFTKHash)    sftk_TLSPRFHashUpdate;
+    context->end         = (SFTKEnd)     sftk_TLSPRFEnd;
+    context->update      = (SFTKCipher)  sftk_TLSPRFUpdate;
+    context->verify      = (SFTKVerify)  sftk_TLSPRFVerify;
+    context->destroy     = (SFTKDestroy) sftk_TLSPRFNull;
+    context->hashdestroy = (SFTKDestroy) sftk_TLSPRFHashDestroy;
+    crv = CKR_OK;
+
+done:
+    if (keyVal) 
+	sftk_FreeAttribute(keyVal);
+    return crv;
+}
+
diff --git a/mozilla/security/nss/lib/ssl/sslerr.h b/mozilla/security/nss/lib/ssl/sslerr.h
new file mode 100644
index 0000000..c132ab9
--- /dev/null
+++ b/mozilla/security/nss/lib/ssl/sslerr.h
@@ -0,0 +1,205 @@
+/*
+ * Enumeration of all SSL-specific error codes.
+ *
+ * ***** 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 ***** */
+/* $Id: sslerr.h,v 1.8 2009/11/06 20:11:28 nelson%bolyard.com Exp $ */
+#ifndef __SSL_ERR_H_
+#define __SSL_ERR_H_
+
+
+#define SSL_ERROR_BASE				(-0x3000)
+#define SSL_ERROR_LIMIT				(SSL_ERROR_BASE + 1000)
+
+#define IS_SSL_ERROR(code) \
+    (((code) >= SSL_ERROR_BASE) && ((code) < SSL_ERROR_LIMIT))
+
+#ifndef NO_SECURITY_ERROR_ENUM
+typedef enum {
+SSL_ERROR_EXPORT_ONLY_SERVER 		= (SSL_ERROR_BASE +  0),
+SSL_ERROR_US_ONLY_SERVER 		= (SSL_ERROR_BASE +  1),
+SSL_ERROR_NO_CYPHER_OVERLAP 		= (SSL_ERROR_BASE +  2),
+/* 
+ * Received an alert reporting what we did wrong.  (more alerts below)
+ */
+SSL_ERROR_NO_CERTIFICATE /*_ALERT */	= (SSL_ERROR_BASE +  3),
+SSL_ERROR_BAD_CERTIFICATE            	= (SSL_ERROR_BASE +  4),
+					/* error 5 is obsolete */
+SSL_ERROR_BAD_CLIENT 			= (SSL_ERROR_BASE +  6),
+SSL_ERROR_BAD_SERVER 			= (SSL_ERROR_BASE +  7),
+SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE	= (SSL_ERROR_BASE +  8),
+SSL_ERROR_UNSUPPORTED_VERSION 		= (SSL_ERROR_BASE +  9),
+					/* error 10 is obsolete */
+SSL_ERROR_WRONG_CERTIFICATE		= (SSL_ERROR_BASE + 11),
+SSL_ERROR_BAD_CERT_DOMAIN 		= (SSL_ERROR_BASE + 12),
+SSL_ERROR_POST_WARNING 			= (SSL_ERROR_BASE + 13),
+SSL_ERROR_SSL2_DISABLED 		= (SSL_ERROR_BASE + 14),
+SSL_ERROR_BAD_MAC_READ 			= (SSL_ERROR_BASE + 15),
+/* 
+ * Received an alert reporting what we did wrong.
+ * (two more alerts above, and many more below)
+ */
+SSL_ERROR_BAD_MAC_ALERT 		= (SSL_ERROR_BASE + 16),
+SSL_ERROR_BAD_CERT_ALERT                = (SSL_ERROR_BASE + 17),
+SSL_ERROR_REVOKED_CERT_ALERT 		= (SSL_ERROR_BASE + 18),
+SSL_ERROR_EXPIRED_CERT_ALERT 		= (SSL_ERROR_BASE + 19),
+
+SSL_ERROR_SSL_DISABLED 			= (SSL_ERROR_BASE + 20),
+SSL_ERROR_FORTEZZA_PQG 			= (SSL_ERROR_BASE + 21),
+SSL_ERROR_UNKNOWN_CIPHER_SUITE		= (SSL_ERROR_BASE + 22),
+SSL_ERROR_NO_CIPHERS_SUPPORTED		= (SSL_ERROR_BASE + 23),
+SSL_ERROR_BAD_BLOCK_PADDING		= (SSL_ERROR_BASE + 24),
+SSL_ERROR_RX_RECORD_TOO_LONG		= (SSL_ERROR_BASE + 25),
+SSL_ERROR_TX_RECORD_TOO_LONG		= (SSL_ERROR_BASE + 26),
+/* 
+ * Received a malformed (too long or short) SSL handshake.
+ */
+SSL_ERROR_RX_MALFORMED_HELLO_REQUEST	= (SSL_ERROR_BASE + 27),
+SSL_ERROR_RX_MALFORMED_CLIENT_HELLO	= (SSL_ERROR_BASE + 28),
+SSL_ERROR_RX_MALFORMED_SERVER_HELLO	= (SSL_ERROR_BASE + 29),
+SSL_ERROR_RX_MALFORMED_CERTIFICATE	= (SSL_ERROR_BASE + 30),
+SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH	= (SSL_ERROR_BASE + 31),
+SSL_ERROR_RX_MALFORMED_CERT_REQUEST	= (SSL_ERROR_BASE + 32),
+SSL_ERROR_RX_MALFORMED_HELLO_DONE	= (SSL_ERROR_BASE + 33),
+SSL_ERROR_RX_MALFORMED_CERT_VERIFY	= (SSL_ERROR_BASE + 34),
+SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH	= (SSL_ERROR_BASE + 35),
+SSL_ERROR_RX_MALFORMED_FINISHED 	= (SSL_ERROR_BASE + 36),
+/* 
+ * Received a malformed (too long or short) SSL record.
+ */
+SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER 	= (SSL_ERROR_BASE + 37),
+SSL_ERROR_RX_MALFORMED_ALERT	 	= (SSL_ERROR_BASE + 38),
+SSL_ERROR_RX_MALFORMED_HANDSHAKE 	= (SSL_ERROR_BASE + 39),
+SSL_ERROR_RX_MALFORMED_APPLICATION_DATA	= (SSL_ERROR_BASE + 40),
+/*
+ * Received an SSL handshake that was inappropriate for the state we're in.
+ * E.g. Server received message from server, or wrong state in state machine.
+ */
+SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST	= (SSL_ERROR_BASE + 41),
+SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO	= (SSL_ERROR_BASE + 42),
+SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO	= (SSL_ERROR_BASE + 43),
+SSL_ERROR_RX_UNEXPECTED_CERTIFICATE	= (SSL_ERROR_BASE + 44),
+SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH	= (SSL_ERROR_BASE + 45),
+SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST	= (SSL_ERROR_BASE + 46),
+SSL_ERROR_RX_UNEXPECTED_HELLO_DONE	= (SSL_ERROR_BASE + 47),
+SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY	= (SSL_ERROR_BASE + 48),
+SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH	= (SSL_ERROR_BASE + 49),
+SSL_ERROR_RX_UNEXPECTED_FINISHED 	= (SSL_ERROR_BASE + 50),
+/*
+ * Received an SSL record that was inappropriate for the state we're in.
+ */
+SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER 	= (SSL_ERROR_BASE + 51),
+SSL_ERROR_RX_UNEXPECTED_ALERT	 	= (SSL_ERROR_BASE + 52),
+SSL_ERROR_RX_UNEXPECTED_HANDSHAKE 	= (SSL_ERROR_BASE + 53),
+SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA= (SSL_ERROR_BASE + 54),
+/*
+ * Received record/message with unknown discriminant.
+ */
+SSL_ERROR_RX_UNKNOWN_RECORD_TYPE	= (SSL_ERROR_BASE + 55),
+SSL_ERROR_RX_UNKNOWN_HANDSHAKE 		= (SSL_ERROR_BASE + 56),
+SSL_ERROR_RX_UNKNOWN_ALERT 		= (SSL_ERROR_BASE + 57),
+/* 
+ * Received an alert reporting what we did wrong.  (more alerts above)
+ */
+SSL_ERROR_CLOSE_NOTIFY_ALERT 		= (SSL_ERROR_BASE + 58),
+SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT 	= (SSL_ERROR_BASE + 59),
+SSL_ERROR_DECOMPRESSION_FAILURE_ALERT 	= (SSL_ERROR_BASE + 60),
+SSL_ERROR_HANDSHAKE_FAILURE_ALERT 	= (SSL_ERROR_BASE + 61),
+SSL_ERROR_ILLEGAL_PARAMETER_ALERT 	= (SSL_ERROR_BASE + 62),
+SSL_ERROR_UNSUPPORTED_CERT_ALERT 	= (SSL_ERROR_BASE + 63),
+SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT 	= (SSL_ERROR_BASE + 64),
+
+SSL_ERROR_GENERATE_RANDOM_FAILURE	= (SSL_ERROR_BASE + 65),
+SSL_ERROR_SIGN_HASHES_FAILURE		= (SSL_ERROR_BASE + 66),
+SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE	= (SSL_ERROR_BASE + 67),
+SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE	= (SSL_ERROR_BASE + 68),
+SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE	= (SSL_ERROR_BASE + 69),
+
+SSL_ERROR_ENCRYPTION_FAILURE		= (SSL_ERROR_BASE + 70),
+SSL_ERROR_DECRYPTION_FAILURE		= (SSL_ERROR_BASE + 71),
+SSL_ERROR_SOCKET_WRITE_FAILURE		= (SSL_ERROR_BASE + 72),
+
+SSL_ERROR_MD5_DIGEST_FAILURE		= (SSL_ERROR_BASE + 73),
+SSL_ERROR_SHA_DIGEST_FAILURE		= (SSL_ERROR_BASE + 74),
+SSL_ERROR_MAC_COMPUTATION_FAILURE	= (SSL_ERROR_BASE + 75),
+SSL_ERROR_SYM_KEY_CONTEXT_FAILURE	= (SSL_ERROR_BASE + 76),
+SSL_ERROR_SYM_KEY_UNWRAP_FAILURE	= (SSL_ERROR_BASE + 77),
+SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED	= (SSL_ERROR_BASE + 78),
+SSL_ERROR_IV_PARAM_FAILURE		= (SSL_ERROR_BASE + 79),
+SSL_ERROR_INIT_CIPHER_SUITE_FAILURE	= (SSL_ERROR_BASE + 80),
+SSL_ERROR_SESSION_KEY_GEN_FAILURE	= (SSL_ERROR_BASE + 81),
+SSL_ERROR_NO_SERVER_KEY_FOR_ALG		= (SSL_ERROR_BASE + 82),
+SSL_ERROR_TOKEN_INSERTION_REMOVAL	= (SSL_ERROR_BASE + 83),
+SSL_ERROR_TOKEN_SLOT_NOT_FOUND		= (SSL_ERROR_BASE + 84),
+SSL_ERROR_NO_COMPRESSION_OVERLAP	= (SSL_ERROR_BASE + 85),
+SSL_ERROR_HANDSHAKE_NOT_COMPLETED	= (SSL_ERROR_BASE + 86),
+SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE	= (SSL_ERROR_BASE + 87),
+SSL_ERROR_CERT_KEA_MISMATCH		= (SSL_ERROR_BASE + 88),
+SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA	= (SSL_ERROR_BASE + 89),
+SSL_ERROR_SESSION_NOT_FOUND		= (SSL_ERROR_BASE + 90),
+
+SSL_ERROR_DECRYPTION_FAILED_ALERT	= (SSL_ERROR_BASE + 91),
+SSL_ERROR_RECORD_OVERFLOW_ALERT		= (SSL_ERROR_BASE + 92),
+SSL_ERROR_UNKNOWN_CA_ALERT		= (SSL_ERROR_BASE + 93),
+SSL_ERROR_ACCESS_DENIED_ALERT		= (SSL_ERROR_BASE + 94),
+SSL_ERROR_DECODE_ERROR_ALERT		= (SSL_ERROR_BASE + 95),
+SSL_ERROR_DECRYPT_ERROR_ALERT		= (SSL_ERROR_BASE + 96),
+SSL_ERROR_EXPORT_RESTRICTION_ALERT	= (SSL_ERROR_BASE + 97),
+SSL_ERROR_PROTOCOL_VERSION_ALERT	= (SSL_ERROR_BASE + 98),
+SSL_ERROR_INSUFFICIENT_SECURITY_ALERT	= (SSL_ERROR_BASE + 99),
+SSL_ERROR_INTERNAL_ERROR_ALERT		= (SSL_ERROR_BASE + 100),
+SSL_ERROR_USER_CANCELED_ALERT		= (SSL_ERROR_BASE + 101),
+SSL_ERROR_NO_RENEGOTIATION_ALERT	= (SSL_ERROR_BASE + 102),
+
+SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED	= (SSL_ERROR_BASE + 103),
+
+SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT		= (SSL_ERROR_BASE + 104),
+SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT	= (SSL_ERROR_BASE + 105),
+SSL_ERROR_UNRECOGNIZED_NAME_ALERT		= (SSL_ERROR_BASE + 106),
+SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT	= (SSL_ERROR_BASE + 107),
+SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT		= (SSL_ERROR_BASE + 108),
+
+SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 109),
+SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET  = (SSL_ERROR_BASE + 110),
+
+SSL_ERROR_DECOMPRESSION_FAILURE		= (SSL_ERROR_BASE + 111),
+SSL_ERROR_RENEGOTIATION_NOT_ALLOWED     = (SSL_ERROR_BASE + 112),
+
+SSL_ERROR_END_OF_LIST	/* let the c compiler determine the value of this. */
+} SSLErrorCodes;
+#endif /* NO_SECURITY_ERROR_ENUM */
+
+#endif /* __SSL_ERR_H_ */
diff --git a/mozilla/security/nss/lib/util/base64.h b/mozilla/security/nss/lib/util/base64.h
new file mode 100644
index 0000000..9682b8c
--- /dev/null
+++ b/mozilla/security/nss/lib/util/base64.h
@@ -0,0 +1,75 @@
+/* ***** 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 ***** */
+
+/*
+ * base64.h - prototypes for base64 encoding/decoding
+ * Note: These functions are deprecated; see nssb64.h for new routines.
+ *
+ * $Id: base64.h,v 1.3 2007/10/12 01:44:50 julien.pierre.boogz%sun.com Exp $
+ */
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+#include "utilrename.h"
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Return an PORT_Alloc'd ascii string which is the base64 encoded
+** version of the input string.
+*/
+extern char *BTOA_DataToAscii(const unsigned char *data, unsigned int len);
+
+/*
+** Return an PORT_Alloc'd string which is the base64 decoded version
+** of the input string; set *lenp to the length of the returned data.
+*/
+extern unsigned char *ATOB_AsciiToData(const char *string, unsigned int *lenp);
+ 
+/*
+** Convert from ascii to binary encoding of an item.
+*/
+extern SECStatus ATOB_ConvertAsciiToItem(SECItem *binary_item, char *ascii);
+
+/*
+** Convert from binary encoding of an item to ascii.
+*/
+extern char *BTOA_ConvertItemToAscii(SECItem *binary_item);
+
+SEC_END_PROTOS
+
+#endif /* _BASE64_H_ */
diff --git a/mozilla/security/nss/lib/util/ciferfam.h b/mozilla/security/nss/lib/util/ciferfam.h
new file mode 100644
index 0000000..f5d87f7
--- /dev/null
+++ b/mozilla/security/nss/lib/util/ciferfam.h
@@ -0,0 +1,92 @@
+/* ***** 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 ***** */
+
+/*
+ * ciferfam.h - cipher familie IDs used for configuring ciphers for export
+ *              control
+ *
+ * $Id: ciferfam.h,v 1.4 2007/10/12 01:44:50 julien.pierre.boogz%sun.com Exp $
+ */
+
+#ifndef _CIFERFAM_H_
+#define _CIFERFAM_H_
+
+#include "utilrename.h"
+/* Cipher Suite "Families" */
+#define CIPHER_FAMILY_PKCS12			"PKCS12"
+#define CIPHER_FAMILY_SMIME			"SMIME"
+#define CIPHER_FAMILY_SSL2			"SSLv2"
+#define CIPHER_FAMILY_SSL3			"SSLv3"
+#define CIPHER_FAMILY_SSL			"SSL"
+#define CIPHER_FAMILY_ALL			""
+#define CIPHER_FAMILY_UNKNOWN			"UNKNOWN"
+
+#define CIPHER_FAMILYID_MASK			0xFFFF0000L
+#define CIPHER_FAMILYID_SSL			0x00000000L
+#define CIPHER_FAMILYID_SMIME			0x00010000L
+#define CIPHER_FAMILYID_PKCS12			0x00020000L
+
+/* SMIME "Cipher Suites" */
+/*
+ * Note that it is assumed that the cipher number itself can be used
+ * as a bit position in a mask, and that mask is currently 32 bits wide.
+ * So, if you want to add a cipher that is greater than 0037, secmime.c
+ * needs to be made smarter at the same time.
+ */
+#define	SMIME_RC2_CBC_40		(CIPHER_FAMILYID_SMIME | 0001)
+#define	SMIME_RC2_CBC_64		(CIPHER_FAMILYID_SMIME | 0002)
+#define	SMIME_RC2_CBC_128		(CIPHER_FAMILYID_SMIME | 0003)
+#define	SMIME_DES_CBC_56		(CIPHER_FAMILYID_SMIME | 0011)
+#define	SMIME_DES_EDE3_168		(CIPHER_FAMILYID_SMIME | 0012)
+#define	SMIME_AES_CBC_128		(CIPHER_FAMILYID_SMIME | 0013)
+#define	SMIME_RC5PAD_64_16_40		(CIPHER_FAMILYID_SMIME | 0021)
+#define	SMIME_RC5PAD_64_16_64		(CIPHER_FAMILYID_SMIME | 0022)
+#define	SMIME_RC5PAD_64_16_128		(CIPHER_FAMILYID_SMIME | 0023)
+#define	SMIME_FORTEZZA			(CIPHER_FAMILYID_SMIME | 0031)
+
+/* PKCS12 "Cipher Suites" */
+
+#define	PKCS12_RC2_CBC_40		(CIPHER_FAMILYID_PKCS12 | 0001)
+#define	PKCS12_RC2_CBC_128		(CIPHER_FAMILYID_PKCS12 | 0002)
+#define	PKCS12_RC4_40			(CIPHER_FAMILYID_PKCS12 | 0011)
+#define	PKCS12_RC4_128			(CIPHER_FAMILYID_PKCS12 | 0012)
+#define	PKCS12_DES_56			(CIPHER_FAMILYID_PKCS12 | 0021)
+#define	PKCS12_DES_EDE3_168		(CIPHER_FAMILYID_PKCS12 | 0022)
+
+/* SMIME version numbers are negative, to avoid colliding with SSL versions */
+#define SMIME_LIBRARY_VERSION_1_0			-0x0100
+
+#endif /* _CIFERFAM_H_ */
diff --git a/mozilla/security/nss/lib/util/derdec.c b/mozilla/security/nss/lib/util/derdec.c
new file mode 100644
index 0000000..4faa680
--- /dev/null
+++ b/mozilla/security/nss/lib/util/derdec.c
@@ -0,0 +1,221 @@
+/* ***** 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 "secder.h"
+#include "secerr.h"
+
+static PRUint32
+der_indefinite_length(unsigned char *buf, unsigned char *end)
+{
+    PRUint32 len, ret, dataLen;
+    unsigned char tag, lenCode;
+    int dataLenLen;
+
+    len = 0;
+    while ( 1 ) {
+	if ((buf + 2) > end) {
+	    return(0);
+	}
+	
+	tag = *buf++;
+	lenCode = *buf++;
+	len += 2;
+	
+	if ( ( tag == 0 ) && ( lenCode == 0 ) ) {
+	    return(len);
+	}
+	
+	if ( lenCode == 0x80 ) {	/* indefinite length */
+	    ret = der_indefinite_length(buf, end); /* recurse to find length */
+	    if (ret == 0)
+		return 0;
+	    len += ret;
+	    buf += ret;
+	} else {			/* definite length */
+	    if (lenCode & 0x80) {
+		/* Length of data is in multibyte format */
+		dataLenLen = lenCode & 0x7f;
+		switch (dataLenLen) {
+		  case 1:
+		    dataLen = buf[0];
+		    break;
+		  case 2:
+		    dataLen = (buf[0]<<8)|buf[1];
+		    break;
+		  case 3:
+		    dataLen = ((unsigned long)buf[0]<<16)|(buf[1]<<8)|buf[2];
+		    break;
+		  case 4:
+		    dataLen = ((unsigned long)buf[0]<<24)|
+			((unsigned long)buf[1]<<16)|(buf[2]<<8)|buf[3];
+		    break;
+		  default:
+		    PORT_SetError(SEC_ERROR_BAD_DER);
+		    return SECFailure;
+		}
+	    } else {
+		/* Length of data is in single byte */
+		dataLen = lenCode;
+		dataLenLen = 0;
+	    }
+
+	    /* skip this item */
+	    buf = buf + dataLenLen + dataLen;
+	    len = len + dataLenLen + dataLen;
+	}
+    }
+}
+
+/*
+** Capture the next thing in the buffer.
+** Returns the length of the header and the length of the contents.
+*/
+static SECStatus
+der_capture(unsigned char *buf, unsigned char *end,
+	    int *header_len_p, PRUint32 *contents_len_p)
+{
+    unsigned char *bp;
+    unsigned char whole_tag;
+    PRUint32 contents_len;
+    int tag_number;
+
+    if ((buf + 2) > end) {
+	*header_len_p = 0;
+	*contents_len_p = 0;
+	if (buf == end)
+	    return SECSuccess;
+	return SECFailure;
+    }
+
+    bp = buf;
+
+    /* Get tag and verify that it is ok. */
+    whole_tag = *bp++;
+    tag_number = whole_tag & DER_TAGNUM_MASK;
+
+    /*
+     * XXX This code does not (yet) handle the high-tag-number form!
+     */
+    if (tag_number == DER_HIGH_TAG_NUMBER) {
+	PORT_SetError(SEC_ERROR_BAD_DER);
+	return SECFailure;
+    }
+
+    if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
+	/* Check that the universal tag number is one we implement.  */
+	switch (tag_number) {
+	  case DER_BOOLEAN:
+	  case DER_INTEGER:
+	  case DER_BIT_STRING:
+	  case DER_OCTET_STRING:
+	  case DER_NULL:
+	  case DER_OBJECT_ID:
+	  case DER_SEQUENCE:
+	  case DER_SET:
+	  case DER_PRINTABLE_STRING:
+	  case DER_T61_STRING:
+	  case DER_IA5_STRING:
+	  case DER_VISIBLE_STRING:
+	  case DER_UTC_TIME:
+	  case 0:			/* end-of-contents tag */
+	    break;
+	  default:
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return SECFailure;
+	}
+    }
+
+    /*
+     * Get first byte of length code (might contain entire length, might not).
+     */
+    contents_len = *bp++;
+
+    /*
+     * If the high bit is set, then the length is in multibyte format,
+     * or the thing has an indefinite-length.
+     */
+    if (contents_len & 0x80) {
+	int bytes_of_encoded_len;
+
+	bytes_of_encoded_len = contents_len & 0x7f;
+	contents_len = 0;
+
+	switch (bytes_of_encoded_len) {
+	  case 4:
+	    contents_len |= *bp++;
+	    contents_len <<= 8;
+	    /* fallthru */
+	  case 3:
+	    contents_len |= *bp++;
+	    contents_len <<= 8;
+	    /* fallthru */
+	  case 2:
+	    contents_len |= *bp++;
+	    contents_len <<= 8;
+	    /* fallthru */
+	  case 1:
+	    contents_len |= *bp++;
+	    break;
+
+	  case 0:
+	    contents_len = der_indefinite_length (bp, end);
+	    if (contents_len)
+		break;
+	    /* fallthru */
+	  default:
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return SECFailure;
+	}
+    }
+
+    if ((bp + contents_len) > end) {
+	/* Ran past end of buffer */
+	PORT_SetError(SEC_ERROR_BAD_DER);
+	return SECFailure;
+    }
+
+    *header_len_p = bp - buf;
+    *contents_len_p = contents_len;
+
+    return SECSuccess;
+}
+
+SECStatus
+DER_Lengths(SECItem *item, int *header_len_p, PRUint32 *contents_len_p)
+{
+    return(der_capture(item->data, &item->data[item->len], header_len_p,
+		       contents_len_p));
+}
diff --git a/mozilla/security/nss/lib/util/derenc.c b/mozilla/security/nss/lib/util/derenc.c
new file mode 100644
index 0000000..c14c6a8
--- /dev/null
+++ b/mozilla/security/nss/lib/util/derenc.c
@@ -0,0 +1,505 @@
+/* ***** 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 "secder.h"
+#include "secerr.h"
+
+#if 0
+/*
+ * Generic templates for individual/simple items.
+ */
+
+DERTemplate SECAnyTemplate[] = {
+    { DER_ANY,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECBitStringTemplate[] = {
+    { DER_BIT_STRING,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECBooleanTemplate[] = {
+    { DER_BOOLEAN,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECIA5StringTemplate[] = {
+    { DER_IA5_STRING,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECIntegerTemplate[] = {
+    { DER_INTEGER,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECNullTemplate[] = {
+    { DER_NULL,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECObjectIDTemplate[] = {
+    { DER_OBJECT_ID,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECOctetStringTemplate[] = {
+    { DER_OCTET_STRING,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECPrintableStringTemplate[] = {
+    { DER_PRINTABLE_STRING,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECT61StringTemplate[] = {
+    { DER_T61_STRING,
+	  0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECUTCTimeTemplate[] = {
+    { DER_UTC_TIME,
+	  0, NULL, sizeof(SECItem) }
+};
+
+#endif
+
+static int
+header_length(DERTemplate *dtemplate, PRUint32 contents_len)
+{
+    PRUint32 len;
+    unsigned long encode_kind, under_kind;
+    PRBool explicit, optional, universal;
+
+    encode_kind = dtemplate->kind;
+
+    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
+    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
+    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+		? PR_TRUE : PR_FALSE;
+
+    PORT_Assert (!(explicit && universal));	/* bad templates */
+
+    if (encode_kind & DER_POINTER) {
+	if (dtemplate->sub != NULL) {
+	    under_kind = dtemplate->sub->kind;
+	    if (universal) {
+		encode_kind = under_kind;
+	    }
+	} else if (universal) {
+	    under_kind = encode_kind & ~DER_POINTER;
+	} else {
+	    under_kind = dtemplate->arg;
+	}
+    } else if (encode_kind & DER_INLINE) {
+	PORT_Assert (dtemplate->sub != NULL);
+	under_kind = dtemplate->sub->kind;
+	if (universal) {
+	    encode_kind = under_kind;
+	}
+    } else if (universal) {
+	under_kind = encode_kind;
+    } else {
+	under_kind = dtemplate->arg;
+    }
+
+    /* This is only used in decoding; it plays no part in encoding.  */
+    if (under_kind & DER_DERPTR)
+	return 0;
+
+    /* No header at all for an "empty" optional.  */
+    if ((contents_len == 0) && optional)
+	return 0;
+
+    /* And no header for a full DER_ANY.  */
+    if (encode_kind & DER_ANY)
+	return 0;
+
+    /*
+     * The common case: one octet for identifier and as many octets
+     * as necessary to hold the content length.
+     */
+    len = 1 + DER_LengthLength(contents_len);
+
+    /* Account for the explicit wrapper, if necessary.  */
+    if (explicit) {
+#if 0		/*
+		 * Well, I was trying to do something useful, but these
+		 * assertions are too restrictive on valid templates.
+		 * I wanted to make sure that the top-level "kind" of
+		 * a template does not also specify DER_EXPLICIT, which
+		 * should only modify a component field.  Maybe later
+		 * I can figure out a better way to detect such a problem,
+		 * but for now I must remove these checks altogether.
+		 */
+	/*
+	 * This modifier applies only to components of a set or sequence;
+	 * it should never be used on a set/sequence itself -- confirm.
+	 */
+	PORT_Assert (under_kind != DER_SEQUENCE);
+	PORT_Assert (under_kind != DER_SET);
+#endif
+
+	len += 1 + DER_LengthLength(len + contents_len);
+    }
+
+    return len;
+}
+
+
+static PRUint32
+contents_length(DERTemplate *dtemplate, void *src)
+{
+    PRUint32 len;
+    unsigned long encode_kind, under_kind;
+    PRBool universal;
+
+
+    PORT_Assert (src != NULL);
+
+    encode_kind = dtemplate->kind;
+
+    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+		? PR_TRUE : PR_FALSE;
+    encode_kind &= ~DER_OPTIONAL;
+
+    if (encode_kind & DER_POINTER) {
+	src = *(void **)src;
+	if (src == NULL) {
+	    return 0;
+	}
+	if (dtemplate->sub != NULL) {
+	    dtemplate = dtemplate->sub;
+	    under_kind = dtemplate->kind;
+	    src = (void *)((char *)src + dtemplate->offset);
+	} else if (universal) {
+	    under_kind = encode_kind & ~DER_POINTER;
+	} else {
+	    under_kind = dtemplate->arg;
+	}
+    } else if (encode_kind & DER_INLINE) {
+	PORT_Assert (dtemplate->sub != NULL);
+	dtemplate = dtemplate->sub;
+	under_kind = dtemplate->kind;
+	src = (void *)((char *)src + dtemplate->offset);
+    } else if (universal) {
+	under_kind = encode_kind;
+    } else {
+	under_kind = dtemplate->arg;
+    }
+
+    /* Having any of these bits is not expected here...  */
+    PORT_Assert ((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL
+				| DER_POINTER | DER_SKIP)) == 0);
+
+    /* This is only used in decoding; it plays no part in encoding.  */
+    if (under_kind & DER_DERPTR)
+	return 0;
+
+    if (under_kind & DER_INDEFINITE) {
+	PRUint32 sub_len;
+	void   **indp = *(void ***)src;
+
+	if (indp == NULL)
+	    return 0;
+
+	len = 0;
+	under_kind &= ~DER_INDEFINITE;
+
+	if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
+	    DERTemplate *tmpt = dtemplate->sub;
+	    PORT_Assert (tmpt != NULL);
+
+	    for (; *indp != NULL; indp++) {
+		void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
+		sub_len = contents_length (tmpt, sub_src);
+		len += sub_len + header_length (tmpt, sub_len);
+	    }
+	} else {
+	    /*
+	     * XXX Lisa is not sure this code (for handling, for example,
+	     * DER_INDEFINITE | DER_OCTET_STRING) is right.
+	     */
+	    for (; *indp != NULL; indp++) {
+		SECItem *item = (SECItem *)(*indp);
+		sub_len = item->len;
+		if (under_kind == DER_BIT_STRING) {
+		    sub_len = (sub_len + 7) >> 3;
+		    /* bit string contents involve an extra octet */
+		    if (sub_len)
+			sub_len++;
+		}
+		if (under_kind != DER_ANY)
+		    len += 1 + DER_LengthLength (sub_len);
+	    }
+	}
+
+	return len;
+    }
+
+    switch (under_kind) {
+      case DER_SEQUENCE:
+      case DER_SET:
+	{
+	    DERTemplate *tmpt;
+	    void *sub_src;
+	    PRUint32 sub_len;
+
+	    len = 0;
+	    for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
+		sub_src = (void *)((char *)src + tmpt->offset);
+		sub_len = contents_length (tmpt, sub_src);
+		len += sub_len + header_length (tmpt, sub_len);
+	    }
+	}
+	break;
+
+      case DER_BIT_STRING:
+	len = (((SECItem *)src)->len + 7) >> 3;
+	/* bit string contents involve an extra octet */
+	if (len)
+	    len++;
+	break;
+
+      default:
+	len = ((SECItem *)src)->len;
+	break;
+    }
+
+    return len;
+}
+
+
+static unsigned char *
+der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
+{
+    int header_len;
+    PRUint32 contents_len;
+    unsigned long encode_kind, under_kind;
+    PRBool explicit, optional, universal;
+
+
+    /*
+     * First figure out how long the encoding will be.  Do this by
+     * traversing the template from top to bottom and accumulating
+     * the length of each leaf item.
+     */
+    contents_len = contents_length (dtemplate, src);
+    header_len = header_length (dtemplate, contents_len);
+
+    /*
+     * Enough smarts was involved already, so that if both the
+     * header and the contents have a length of zero, then we
+     * are not doing any encoding for this element.
+     */
+    if (header_len == 0 && contents_len == 0)
+	return buf;
+
+    encode_kind = dtemplate->kind;
+
+    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
+    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~DER_OPTIONAL;
+    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+		? PR_TRUE : PR_FALSE;
+
+    if (encode_kind & DER_POINTER) {
+	if (contents_len) {
+	    src = *(void **)src;
+	    PORT_Assert (src != NULL);
+	}
+	if (dtemplate->sub != NULL) {
+	    dtemplate = dtemplate->sub;
+	    under_kind = dtemplate->kind;
+	    if (universal) {
+		encode_kind = under_kind;
+	    }
+	    src = (void *)((char *)src + dtemplate->offset);
+	} else if (universal) {
+	    under_kind = encode_kind & ~DER_POINTER;
+	} else {
+	    under_kind = dtemplate->arg;
+	}
+    } else if (encode_kind & DER_INLINE) {
+	dtemplate = dtemplate->sub;
+	under_kind = dtemplate->kind;
+	if (universal) {
+	    encode_kind = under_kind;
+	}
+	src = (void *)((char *)src + dtemplate->offset);
+    } else if (universal) {
+	under_kind = encode_kind;
+    } else {
+	under_kind = dtemplate->arg;
+    }
+
+    if (explicit) {
+	buf = DER_StoreHeader (buf, encode_kind,
+			       (1 + DER_LengthLength(contents_len)
+				+ contents_len));
+	encode_kind = under_kind;
+    }
+
+    if ((encode_kind & DER_ANY) == 0) {	/* DER_ANY already contains header */
+	buf = DER_StoreHeader (buf, encode_kind, contents_len);
+    }
+
+    /* If no real contents to encode, then we are done.  */
+    if (contents_len == 0)
+	return buf;
+
+    if (under_kind & DER_INDEFINITE) {
+	void **indp;
+
+	indp = *(void ***)src;
+	PORT_Assert (indp != NULL);
+
+	under_kind &= ~DER_INDEFINITE;
+	if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
+	    DERTemplate *tmpt = dtemplate->sub;
+	    PORT_Assert (tmpt != NULL);
+	    for (; *indp != NULL; indp++) {
+		void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
+		buf = der_encode (buf, tmpt, sub_src);
+	    }
+	} else {
+	    for (; *indp != NULL; indp++) {
+		SECItem *item;
+		int sub_len;
+
+		item = (SECItem *)(*indp);
+		sub_len = item->len;
+		if (under_kind == DER_BIT_STRING) {
+		    if (sub_len) {
+			int rem;
+
+			sub_len = (sub_len + 7) >> 3;
+			buf = DER_StoreHeader (buf, under_kind, sub_len + 1);
+			rem = (sub_len << 3) - item->len;
+			*buf++ = rem;		/* remaining bits */
+		    } else {
+			buf = DER_StoreHeader (buf, under_kind, 0);
+		    }
+		} else if (under_kind != DER_ANY) {
+		    buf = DER_StoreHeader (buf, under_kind, sub_len);
+		}
+		PORT_Memcpy (buf, item->data, sub_len);
+		buf += sub_len;
+	    }
+	}
+	return buf;
+    }
+
+    switch (under_kind) {
+      case DER_SEQUENCE:
+      case DER_SET:
+	{
+	    DERTemplate *tmpt;
+	    void *sub_src;
+
+	    for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
+		sub_src = (void *)((char *)src + tmpt->offset);
+		buf = der_encode (buf, tmpt, sub_src);
+	    }
+	}
+	break;
+
+      case DER_BIT_STRING:
+	{
+	    SECItem *item;
+	    int rem;
+
+	    /*
+	     * The contents length includes our extra octet; subtract
+	     * it off so we just have the real string length there.
+	     */
+	    contents_len--;
+	    item = (SECItem *)src;
+	    PORT_Assert (contents_len == ((item->len + 7) >> 3));
+	    rem = (contents_len << 3) - item->len;
+	    *buf++ = rem;		/* remaining bits */
+	    PORT_Memcpy (buf, item->data, contents_len);
+	    buf += contents_len;
+	}
+	break;
+
+      default:
+	{
+	    SECItem *item;
+
+	    item = (SECItem *)src;
+	    PORT_Assert (contents_len == item->len);
+	    PORT_Memcpy (buf, item->data, contents_len);
+	    buf += contents_len;
+	}
+	break;
+    }
+
+    return buf;
+}
+
+
+SECStatus
+DER_Encode(PRArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
+{
+    unsigned int contents_len, header_len;
+
+    src = (void **)((char *)src + dtemplate->offset);
+
+    /*
+     * First figure out how long the encoding will be. Do this by
+     * traversing the template from top to bottom and accumulating
+     * the length of each leaf item.
+     */
+    contents_len = contents_length (dtemplate, src);
+    header_len = header_length (dtemplate, contents_len);
+
+    dest->len = contents_len + header_len;
+
+    /* Allocate storage to hold the encoding */
+    dest->data = (unsigned char*) PORT_ArenaAlloc(arena, dest->len);
+    if (dest->data == NULL) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+
+    /* Now encode into the buffer */
+    (void) der_encode (dest->data, dtemplate, src);
+
+    return SECSuccess;
+}
diff --git a/mozilla/security/nss/lib/util/dersubr.c b/mozilla/security/nss/lib/util/dersubr.c
new file mode 100644
index 0000000..3aa0db8
--- /dev/null
+++ b/mozilla/security/nss/lib/util/dersubr.c
@@ -0,0 +1,266 @@
+/* ***** 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 "secder.h"
+#include <limits.h>
+#include "secerr.h"
+
+int
+DER_LengthLength(PRUint32 len)
+{
+    if (len > 127) {
+	if (len > 255) {
+	    if (len > 65535L) {
+		if (len > 16777215L) {
+		    return 5;
+		} else {
+		    return 4;
+		}
+	    } else {
+		return 3;
+	    }
+	} else {
+	    return 2;
+	}
+    } else {
+	return 1;
+    }
+}
+
+unsigned char *
+DER_StoreHeader(unsigned char *buf, unsigned int code, PRUint32 len)
+{
+    unsigned char b[4];
+
+    b[0] = (unsigned char)(len >> 24);
+    b[1] = (unsigned char)(len >> 16);
+    b[2] = (unsigned char)(len >> 8);
+    b[3] = (unsigned char)len;
+    if ((code & DER_TAGNUM_MASK) == DER_SET
+	|| (code & DER_TAGNUM_MASK) == DER_SEQUENCE)
+	code |= DER_CONSTRUCTED;
+    *buf++ = code;
+    if (len > 127) {
+	if (len > 255) {
+	    if (len > 65535) {
+		if (len > 16777215) {
+		    *buf++ = 0x84;
+		    *buf++ = b[0];
+		    *buf++ = b[1];
+		    *buf++ = b[2];
+		    *buf++ = b[3];
+		} else {
+		    *buf++ = 0x83;
+		    *buf++ = b[1];
+		    *buf++ = b[2];
+		    *buf++ = b[3];
+		}
+	    } else {
+		*buf++ = 0x82;
+		*buf++ = b[2];
+		*buf++ = b[3];
+	    }
+	} else {
+	    *buf++ = 0x81;
+	    *buf++ = b[3];
+	}
+    } else {
+	*buf++ = b[3];
+    }
+    return buf;
+}
+
+/*
+ * XXX This should be rewritten, generalized, to take a long instead
+ * of a PRInt32.
+ */
+SECStatus
+DER_SetInteger(PRArenaPool *arena, SECItem *it, PRInt32 i)
+{
+    unsigned char bb[4];
+    unsigned len;
+
+    bb[0] = (unsigned char) (i >> 24);
+    bb[1] = (unsigned char) (i >> 16);
+    bb[2] = (unsigned char) (i >> 8);
+    bb[3] = (unsigned char) (i);
+
+    /*
+    ** Small integers are encoded in a single byte. Larger integers
+    ** require progressively more space.
+    */
+    if (i < -128) {
+	if (i < -32768L) {
+	    if (i < -8388608L) {
+		len = 4;
+	    } else {
+		len = 3;
+	    }
+	} else {
+	    len = 2;
+	}
+    } else if (i > 127) {
+	if (i > 32767L) {
+	    if (i > 8388607L) {
+		len = 4;
+	    } else {
+		len = 3;
+	    }
+	} else {
+	    len = 2;
+	}
+    } else {
+	len = 1;
+    }
+    it->data = (unsigned char*) PORT_ArenaAlloc(arena, len);
+    if (!it->data) {
+	return SECFailure;
+    }
+    it->len = len;
+    PORT_Memcpy(it->data, bb + (4 - len), len);
+    return SECSuccess;
+}
+
+/*
+ * XXX This should be rewritten, generalized, to take an unsigned long instead
+ * of a PRUint32.
+ */
+SECStatus
+DER_SetUInteger(PRArenaPool *arena, SECItem *it, PRUint32 ui)
+{
+    unsigned char bb[5];
+    int len;
+
+    bb[0] = 0;
+    bb[1] = (unsigned char) (ui >> 24);
+    bb[2] = (unsigned char) (ui >> 16);
+    bb[3] = (unsigned char) (ui >> 8);
+    bb[4] = (unsigned char) (ui);
+
+    /*
+    ** Small integers are encoded in a single byte. Larger integers
+    ** require progressively more space.
+    */
+    if (ui > 0x7f) {
+	if (ui > 0x7fff) {
+	    if (ui > 0x7fffffL) {
+		if (ui >= 0x80000000L) {
+		    len = 5;
+		} else {
+		    len = 4;
+		}
+	    } else {
+		len = 3;
+	    }
+	} else {
+	    len = 2;
+	}
+    } else {
+	len = 1;
+    }
+
+    it->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
+    if (it->data == NULL) {
+	return SECFailure;
+    }
+
+    it->len = len;
+    PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len);
+
+    return SECSuccess;
+}
+
+/*
+** Convert a der encoded *signed* integer into a machine integral value.
+** If an underflow/overflow occurs, sets error code and returns min/max.
+*/
+long
+DER_GetInteger(SECItem *it)
+{
+    long ival = 0;
+    unsigned len = it->len;
+    unsigned char *cp = it->data;
+    unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1);
+    unsigned long ofloinit;
+
+    if (*cp & 0x80)
+    	ival = -1L;
+    ofloinit = ival & overflow;
+
+    while (len) {
+	if ((ival & overflow) != ofloinit) {
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    if (ival < 0) {
+		return LONG_MIN;
+	    }
+	    return LONG_MAX;
+	}
+	ival = ival << 8;
+	ival |= *cp++;
+	--len;
+    }
+    return ival;
+}
+
+/*
+** Convert a der encoded *unsigned* integer into a machine integral value.
+** If an underflow/overflow occurs, sets error code and returns min/max.
+*/
+unsigned long
+DER_GetUInteger(SECItem *it)
+{
+    unsigned long ival = 0;
+    unsigned len = it->len;
+    unsigned char *cp = it->data;
+    unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8);
+
+    /* Cannot put a negative value into an unsigned container. */
+    if (*cp & 0x80) {
+	PORT_SetError(SEC_ERROR_BAD_DER);
+	return 0;
+    }
+
+    while (len) {
+	if (ival & overflow) {
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return ULONG_MAX;
+	}
+	ival = ival << 8;
+	ival |= *cp++;
+	--len;
+    }
+    return ival;
+}
diff --git a/mozilla/security/nss/lib/util/dertime.c b/mozilla/security/nss/lib/util/dertime.c
new file mode 100644
index 0000000..ce80dae
--- /dev/null
+++ b/mozilla/security/nss/lib/util/dertime.c
@@ -0,0 +1,342 @@
+/* ***** 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 "prtypes.h"
+#include "prtime.h"
+#include "secder.h"
+#include "prlong.h"
+#include "secerr.h"
+
+#define HIDIGIT(v) (((v) / 10) + '0')
+#define LODIGIT(v) (((v) % 10) + '0')
+
+#define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
+#define CAPTURE(var,p,label)				  \
+{							  \
+    if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
+    (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0');	  \
+    p += 2; \
+}
+
+static const PRTime January1st1     = (PRTime) LL_INIT(0xff234001U, 0x00d44000U);
+static const PRTime January1st1950  = (PRTime) LL_INIT(0xfffdc1f8U, 0x793da000U);
+static const PRTime January1st2050  = LL_INIT(0x0008f81e, 0x1b098000);
+static const PRTime January1st10000 = LL_INIT(0x0384440c, 0xcc736000);
+
+/* gmttime must contains UTC time in micro-seconds unit */
+SECStatus
+DER_TimeToUTCTimeArena(PRArenaPool* arenaOpt, SECItem *dst, int64 gmttime)
+{
+    PRExplodedTime printableTime;
+    unsigned char *d;
+
+    if ( (gmttime < January1st1950) || (gmttime >= January1st2050) ) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    dst->len = 13;
+    if (arenaOpt) {
+        dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len);
+    } else {
+        dst->data = d = (unsigned char*) PORT_Alloc(dst->len);
+    }
+    dst->type = siUTCTime;
+    if (!d) {
+	return SECFailure;
+    }
+
+    /* Convert an int64 time to a printable format.  */
+    PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
+
+    /* The month in UTC time is base one */
+    printableTime.tm_month++;
+
+    /* remove the century since it's added to the tm_year by the 
+       PR_ExplodeTime routine, but is not needed for UTC time */
+    printableTime.tm_year %= 100; 
+
+    d[0] = HIDIGIT(printableTime.tm_year);
+    d[1] = LODIGIT(printableTime.tm_year);
+    d[2] = HIDIGIT(printableTime.tm_month);
+    d[3] = LODIGIT(printableTime.tm_month);
+    d[4] = HIDIGIT(printableTime.tm_mday);
+    d[5] = LODIGIT(printableTime.tm_mday);
+    d[6] = HIDIGIT(printableTime.tm_hour);
+    d[7] = LODIGIT(printableTime.tm_hour);
+    d[8] = HIDIGIT(printableTime.tm_min);
+    d[9] = LODIGIT(printableTime.tm_min);
+    d[10] = HIDIGIT(printableTime.tm_sec);
+    d[11] = LODIGIT(printableTime.tm_sec);
+    d[12] = 'Z';
+    return SECSuccess;
+}
+
+SECStatus
+DER_TimeToUTCTime(SECItem *dst, int64 gmttime)
+{
+    return DER_TimeToUTCTimeArena(NULL, dst, gmttime);
+}
+
+static SECStatus /* forward */
+der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
+                     const char **endptr);
+
+#define GEN_STRING 2 /* TimeString is a GeneralizedTime */
+#define UTC_STRING 0 /* TimeString is a UTCTime         */
+
+/* The caller of DER_AsciiToItem MUST ENSURE that either
+** a) "string" points to a null-terminated ASCII string, or
+** b) "string" points to a buffer containing a valid UTCTime, 
+**     whether null terminated or not, or
+** c) "string" contains at least 19 characters, with or without null char.
+** otherwise, this function may UMR and/or crash.
+** It suffices to ensure that the input "string" is at least 17 bytes long.
+*/
+SECStatus
+DER_AsciiToTime(int64 *dst, const char *string)
+{
+    return der_TimeStringToTime(dst, string, UTC_STRING, NULL);
+}
+
+SECStatus
+DER_UTCTimeToTime(int64 *dst, const SECItem *time)
+{
+    /* Minimum valid UTCTime is yymmddhhmmZ       which is 11 bytes. 
+    ** Maximum valid UTCTime is yymmddhhmmss+0000 which is 17 bytes.
+    ** 20 should be large enough for all valid encoded times. 
+    */
+    unsigned int i;
+    char localBuf[20];
+    const char *end = NULL;
+    SECStatus rv;
+
+    if (!time || !time->data || time->len < 11 || time->len > 17) {
+	PORT_SetError(SEC_ERROR_INVALID_TIME);
+	return SECFailure;
+    }
+
+    for (i = 0; i < time->len; i++) {
+	if (time->data[i] == '\0') {
+	    PORT_SetError(SEC_ERROR_INVALID_TIME);
+	    return SECFailure;
+	}
+	localBuf[i] = time->data[i];
+    }
+    localBuf[i] = '\0';
+
+    rv = der_TimeStringToTime(dst, localBuf, UTC_STRING, &end);
+    if (rv == SECSuccess && *end != '\0') {
+	PORT_SetError(SEC_ERROR_INVALID_TIME);
+	return SECFailure;
+    }
+    return rv;
+}
+
+/*
+   gmttime must contains UTC time in micro-seconds unit.
+   Note: the caller should make sure that Generalized time
+   should only be used for certifiate validities after the
+   year 2049.  Otherwise, UTC time should be used.  This routine
+   does not check this case, since it can be used to encode
+   certificate extension, which does not have this restriction. 
+ */
+SECStatus
+DER_TimeToGeneralizedTimeArena(PRArenaPool* arenaOpt, SECItem *dst, int64 gmttime)
+{
+    PRExplodedTime printableTime;
+    unsigned char *d;
+
+    if ( (gmttime<January1st1) || (gmttime>=January1st10000) ) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    dst->len = 15;
+    if (arenaOpt) {
+        dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len);
+    } else {
+        dst->data = d = (unsigned char*) PORT_Alloc(dst->len);
+    }
+    dst->type = siGeneralizedTime;
+    if (!d) {
+	return SECFailure;
+    }
+
+    /* Convert an int64 time to a printable format.  */
+    PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
+
+    /* The month in Generalized time is base one */
+    printableTime.tm_month++;
+
+    d[0] = (printableTime.tm_year /1000) + '0';
+    d[1] = ((printableTime.tm_year % 1000) / 100) + '0';
+    d[2] = ((printableTime.tm_year % 100) / 10) + '0';
+    d[3] = (printableTime.tm_year % 10) + '0';
+    d[4] = HIDIGIT(printableTime.tm_month);
+    d[5] = LODIGIT(printableTime.tm_month);
+    d[6] = HIDIGIT(printableTime.tm_mday);
+    d[7] = LODIGIT(printableTime.tm_mday);
+    d[8] = HIDIGIT(printableTime.tm_hour);
+    d[9] = LODIGIT(printableTime.tm_hour);
+    d[10] = HIDIGIT(printableTime.tm_min);
+    d[11] = LODIGIT(printableTime.tm_min);
+    d[12] = HIDIGIT(printableTime.tm_sec);
+    d[13] = LODIGIT(printableTime.tm_sec);
+    d[14] = 'Z';
+    return SECSuccess;
+}
+
+SECStatus
+DER_TimeToGeneralizedTime(SECItem *dst, int64 gmttime)
+{
+    return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime);
+}
+
+
+SECStatus
+DER_GeneralizedTimeToTime(int64 *dst, const SECItem *time)
+{
+    /* Minimum valid GeneralizedTime is ccyymmddhhmmZ       which is 13 bytes.
+    ** Maximum valid GeneralizedTime is ccyymmddhhmmss+0000 which is 19 bytes.
+    ** 20 should be large enough for all valid encoded times. 
+    */
+    unsigned int i;
+    char localBuf[20];
+    const char *end = NULL;
+    SECStatus rv;
+
+    if (!time || !time->data || time->len < 13 || time->len > 19) {
+	PORT_SetError(SEC_ERROR_INVALID_TIME);
+	return SECFailure;
+    }
+
+    for (i = 0; i < time->len; i++) {
+	if (time->data[i] == '\0') {
+	    PORT_SetError(SEC_ERROR_INVALID_TIME);
+	    return SECFailure;
+	}
+	localBuf[i] = time->data[i];
+    }
+    localBuf[i] = '\0';
+
+    rv = der_TimeStringToTime(dst, localBuf, GEN_STRING, &end);
+    if (rv == SECSuccess && *end != '\0') {
+	PORT_SetError(SEC_ERROR_INVALID_TIME);
+	return SECFailure;
+    }
+    return rv;
+}
+
+static SECStatus
+der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
+                     const char **endptr)
+{
+    PRExplodedTime genTime;
+    long hourOff = 0, minOff = 0;
+    uint16 century;
+    char signum;
+
+    if (string == NULL || dst == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    /* Verify time is formatted properly and capture information */
+    memset(&genTime, 0, sizeof genTime);
+
+    if (generalized == UTC_STRING) {
+	CAPTURE(genTime.tm_year, string, loser);
+	century = (genTime.tm_year < 50) ? 20 : 19;
+    } else {
+	CAPTURE(century, string, loser);
+	CAPTURE(genTime.tm_year, string, loser);
+    }
+    genTime.tm_year += century * 100;
+
+    CAPTURE(genTime.tm_month, string, loser);
+    if ((genTime.tm_month == 0) || (genTime.tm_month > 12)) 
+    	goto loser;
+
+    /* NSPR month base is 0 */
+    --genTime.tm_month;
+    
+    CAPTURE(genTime.tm_mday, string, loser);
+    if ((genTime.tm_mday == 0) || (genTime.tm_mday > 31)) 
+    	goto loser;
+    
+    CAPTURE(genTime.tm_hour, string, loser);
+    if (genTime.tm_hour > 23) 
+    	goto loser;
+    
+    CAPTURE(genTime.tm_min, string, loser);
+    if (genTime.tm_min > 59) 
+    	goto loser;
+    
+    if (ISDIGIT(string[0])) {
+	CAPTURE(genTime.tm_sec, string, loser);
+	if (genTime.tm_sec > 59) 
+	    goto loser;
+    }
+    signum = *string++;
+    if (signum == '+' || signum == '-') {
+	CAPTURE(hourOff, string, loser);
+	if (hourOff > 23) 
+	    goto loser;
+	CAPTURE(minOff, string, loser);
+	if (minOff > 59) 
+	    goto loser;
+	if (signum == '-') {
+	    hourOff = -hourOff;
+	    minOff  = -minOff;
+	}
+    } else if (signum != 'Z') {
+	goto loser;
+    }
+
+    if (endptr)
+    	*endptr = string;
+
+    /* Convert the GMT offset to seconds and save it in genTime
+     * for the implode time call.
+     */
+    genTime.tm_params.tp_gmt_offset = (PRInt32)((hourOff * 60L + minOff) * 60L);
+    *dst = PR_ImplodeTime(&genTime);
+    return SECSuccess;
+
+loser:
+    PORT_SetError(SEC_ERROR_INVALID_TIME);
+    return SECFailure;
+}
diff --git a/mozilla/security/nss/lib/util/nssb64.h b/mozilla/security/nss/lib/util/nssb64.h
new file mode 100644
index 0000000..8250245
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssb64.h
@@ -0,0 +1,128 @@
+/* ***** 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 ***** */
+
+/*
+ * Public prototypes for base64 encoding/decoding.
+ *
+ * $Id: nssb64.h,v 1.5 2008/06/14 14:20:38 wtc%google.com Exp $
+ */
+#ifndef _NSSB64_H_
+#define _NSSB64_H_
+
+#include "utilrename.h"
+#include "seccomon.h"
+#include "nssb64t.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+ * Functions to start a base64 decoding/encoding context.
+ */
+
+extern NSSBase64Decoder *
+NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
+					       PRInt32),
+			 void *output_arg);
+
+extern NSSBase64Encoder *
+NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+			 void *output_arg);
+
+/*
+ * Push data through the decoder/encoder, causing the output_fn (provided
+ * to Create) to be called with the decoded/encoded data.
+ */
+
+extern SECStatus
+NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
+			 PRUint32 size);
+
+extern SECStatus
+NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
+			 PRUint32 size);
+
+/*
+ * When you're done processing, call this to close the context.
+ * If "abort_p" is false, then calling this may cause the output_fn
+ * to be called one last time (as the last buffered data is flushed out).
+ */
+
+extern SECStatus
+NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p);
+
+extern SECStatus
+NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p);
+
+/*
+ * Perform base64 decoding from an ascii string "inStr" to an Item.
+ * The length of the input must be provided as "inLen".  The Item
+ * may be provided (as "outItemOpt"); you can also pass in a NULL
+ * and the Item will be allocated for you.
+ *
+ * In any case, the data within the Item will be allocated for you.
+ * All allocation will happen out of the passed-in "arenaOpt", if non-NULL.
+ * If "arenaOpt" is NULL, standard allocation (heap) will be used and
+ * you will want to free the result via SECITEM_FreeItem.
+ *
+ * Return value is NULL on error, the Item (allocated or provided) otherwise.
+ */
+extern SECItem *
+NSSBase64_DecodeBuffer (PLArenaPool *arenaOpt, SECItem *outItemOpt,
+			const char *inStr, unsigned int inLen);
+
+/*
+ * Perform base64 encoding of binary data "inItem" to an ascii string.
+ * The output buffer may be provided (as "outStrOpt"); you can also pass
+ * in a NULL and the buffer will be allocated for you.  The result will
+ * be null-terminated, and if the buffer is provided, "maxOutLen" must
+ * specify the maximum length of the buffer and will be checked to
+ * supply sufficient space space for the encoded result.  (If "outStrOpt"
+ * is NULL, "maxOutLen" is ignored.)
+ *
+ * If "outStrOpt" is NULL, allocation will happen out of the passed-in
+ * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap)
+ * will be used.
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+extern char *
+NSSBase64_EncodeItem (PLArenaPool *arenaOpt, char *outStrOpt,
+		      unsigned int maxOutLen, SECItem *inItem);
+
+SEC_END_PROTOS
+
+#endif /* _NSSB64_H_ */
diff --git a/mozilla/security/nss/lib/util/nssb64d.c b/mozilla/security/nss/lib/util/nssb64d.c
new file mode 100644
index 0000000..51426f0
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssb64d.c
@@ -0,0 +1,864 @@
+/* ***** 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 ***** */
+
+/*
+ * Base64 decoding (ascii to binary).
+ *
+ * $Id: nssb64d.c,v 1.7 2008/10/05 20:59:26 nelson%bolyard.com Exp $
+ */
+
+#include "nssb64.h"
+#include "nspr.h"
+#include "secitem.h"
+#include "secerr.h"
+
+/*
+ * XXX We want this basic support to go into NSPR (the PL part).
+ * Until that can happen, the PL interface is going to be kept entirely
+ * internal here -- all static functions and opaque data structures.
+ * When someone can get it moved over into NSPR, that should be done:
+ *    - giving everything names that are accepted by the NSPR module owners
+ *	(though I tried to choose ones that would work without modification)
+ *    - exporting the functions (remove static declarations and add
+ *	to nssutil.def as necessary)
+ *    - put prototypes into appropriate header file (probably replacing
+ *	the entire current lib/libc/include/plbase64.h in NSPR)
+ *	along with a typedef for the context structure (which should be
+ *	kept opaque -- definition in the source file only, but typedef
+ *	ala "typedef struct PLBase64FooStr PLBase64Foo;" in header file)
+ *    - modify anything else as necessary to conform to NSPR required style
+ *	(I looked but found no formatting guide to follow)
+ *
+ * You will want to move over everything from here down to the comment
+ * which says "XXX End of base64 decoding code to be moved into NSPR",
+ * into a new file in NSPR.
+ */
+
+/*
+ **************************************************************
+ * XXX Beginning of base64 decoding code to be moved into NSPR.
+ */
+
+/*
+ * This typedef would belong in the NSPR header file (i.e. plbase64.h).
+ */
+typedef struct PLBase64DecoderStr PLBase64Decoder;
+
+/*
+ * The following implementation of base64 decoding was based on code
+ * found in libmime (specifically, in mimeenc.c).  It has been adapted to
+ * use PR types and naming as well as to provide other necessary semantics
+ * (like buffer-in/buffer-out in addition to "streaming" without undue
+ * performance hit of extra copying if you made the buffer versions
+ * use the output_fn).  It also incorporates some aspects of the current
+ * NSPR base64 decoding code.  As such, you may find similarities to
+ * both of those implementations.  I tried to use names that reflected
+ * the original code when possible.  For this reason you may find some
+ * inconsistencies -- libmime used lots of "in" and "out" whereas the
+ * NSPR version uses "src" and "dest"; sometimes I changed one to the other
+ * and sometimes I left them when I thought the subroutines were at least
+ * self-consistent.
+ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Opaque object used by the decoder to store state.
+ */
+struct PLBase64DecoderStr {
+    /* Current token (or portion, if token_size < 4) being decoded. */
+    unsigned char token[4];
+    int token_size;
+
+    /*
+     * Where to write the decoded data (used when streaming, not when
+     * doing all in-memory (buffer) operations).
+     *
+     * Note that this definition is chosen to be compatible with PR_Write.
+     */
+    PRInt32 (*output_fn) (void *output_arg, const unsigned char *buf,
+			  PRInt32 size);
+    void *output_arg;
+
+    /*
+     * Where the decoded output goes -- either temporarily (in the streaming
+     * case, staged here before it goes to the output function) or what will
+     * be the entire buffered result for users of the buffer version.
+     */
+    unsigned char *output_buffer;
+    PRUint32 output_buflen;	/* the total length of allocated buffer */
+    PRUint32 output_length;	/* the length that is currently populated */
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Table to convert an ascii "code" to its corresponding binary value.
+ * For ease of use, the binary values in the table are the actual values
+ * PLUS ONE.  This is so that the special value of zero can denote an
+ * invalid mapping; that was much easier than trying to fill in the other
+ * values with some value other than zero, and to check for it.
+ * Just remember to SUBTRACT ONE when using the value retrieved.
+ */
+static unsigned char base64_codetovaluep1[256] = {
+/*   0: */	  0,	  0,	  0,	  0,	  0,	  0,	  0,	  0,
+/*   8: */	  0,	  0,	  0,	  0,	  0,	  0,	  0,	  0,
+/*  16: */	  0,	  0,	  0,	  0,	  0,	  0,	  0,	  0,
+/*  24: */	  0,	  0,	  0,	  0,	  0,	  0,	  0,	  0,
+/*  32: */	  0,	  0,	  0,	  0,	  0,	  0,	  0,	  0,
+/*  40: */	  0,	  0,	  0,	 63,	  0,	  0,	  0,	 64,
+/*  48: */	 53,	 54,	 55,	 56,	 57,	 58,	 59,	 60,
+/*  56: */	 61,	 62,	  0,	  0,	  0,	  0,	  0,	  0,
+/*  64: */	  0,	  1,	  2,	  3,	  4,	  5,	  6,	  7,
+/*  72: */	  8,	  9,	 10,	 11,	 12,	 13,	 14,	 15,
+/*  80: */	 16,	 17,	 18,	 19,	 20,	 21,	 22,	 23,
+/*  88: */	 24,	 25,	 26,	  0,	  0,	  0,	  0,	  0,
+/*  96: */	  0,	 27,	 28,	 29,	 30,	 31,	 32,	 33,
+/* 104: */	 34,	 35,	 36,	 37,	 38,	 39,	 40,	 41,
+/* 112: */	 42,	 43,	 44,	 45,	 46,	 47,	 48,	 49,
+/* 120: */	 50,	 51,	 52,	  0,	  0,	  0,	  0,	  0,
+/* 128: */	  0,	  0,	  0,	  0,	  0,	  0,	  0,	  0
+/* and rest are all zero as well */
+};
+
+#define B64_PAD	'='
+
+
+/*
+ * Reads 4; writes 3 (known, or expected, to have no trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_4to3 (const unsigned char *in, unsigned char *out)
+{
+    int j;
+    PRUint32 num = 0;
+    unsigned char bits;
+
+    for (j = 0; j < 4; j++) {
+	bits = base64_codetovaluep1[in[j]];
+	if (bits == 0)
+	    return -1;
+	num = (num << 6) | (bits - 1);
+    }
+
+    out[0] = (unsigned char) (num >> 16);
+    out[1] = (unsigned char) ((num >> 8) & 0xFF);
+    out[2] = (unsigned char) (num & 0xFF);
+
+    return 3;
+}
+
+/*
+ * Reads 3; writes 2 (caller already confirmed EOF or trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_3to2 (const unsigned char *in, unsigned char *out)
+{
+    PRUint32 num = 0;
+    unsigned char bits1, bits2, bits3;
+
+    bits1 = base64_codetovaluep1[in[0]];
+    bits2 = base64_codetovaluep1[in[1]];
+    bits3 = base64_codetovaluep1[in[2]];
+
+    if ((bits1 == 0) || (bits2 == 0) || (bits3 == 0))
+	return -1;
+
+    num = ((PRUint32)(bits1 - 1)) << 10;
+    num |= ((PRUint32)(bits2 - 1)) << 4;
+    num |= ((PRUint32)(bits3 - 1)) >> 2;
+
+    out[0] = (unsigned char) (num >> 8);
+    out[1] = (unsigned char) (num & 0xFF);
+
+    return 2;
+}
+
+/*
+ * Reads 2; writes 1 (caller already confirmed EOF or trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_2to1 (const unsigned char *in, unsigned char *out)
+{
+    PRUint32 num = 0;
+    unsigned char bits1, bits2;
+
+    bits1 = base64_codetovaluep1[in[0]];
+    bits2 = base64_codetovaluep1[in[1]];
+
+    if ((bits1 == 0) || (bits2 == 0))
+	return -1;
+
+    num = ((PRUint32)(bits1 - 1)) << 2;
+    num |= ((PRUint32)(bits2 - 1)) >> 4;
+
+    out[0] = (unsigned char) num;
+
+    return 1;
+}
+
+/*
+ * Reads 4; writes 0-3.  Returns bytes written or -1 on error.
+ * (Writes less than 3 only at (presumed) EOF.)
+ */
+static int
+pl_base64_decode_token (const unsigned char *in, unsigned char *out)
+{
+    if (in[3] != B64_PAD)
+	return pl_base64_decode_4to3 (in, out);
+
+    if (in[2] == B64_PAD)
+	return pl_base64_decode_2to1 (in, out);
+
+    return pl_base64_decode_3to2 (in, out);
+}
+
+static PRStatus
+pl_base64_decode_buffer (PLBase64Decoder *data, const unsigned char *in,
+			 PRUint32 length)
+{
+    unsigned char *out = data->output_buffer;
+    unsigned char *token = data->token;
+    int i, n = 0;
+
+    i = data->token_size;
+    data->token_size = 0;
+
+    while (length > 0) {
+	while (i < 4 && length > 0) {
+	    /*
+	     * XXX Note that the following simply ignores any unexpected
+	     * characters.  This is exactly what the original code in
+	     * libmime did, and I am leaving it.  We certainly want to skip
+	     * over whitespace (we must); this does much more than that.
+	     * I am not confident changing it, and I don't want to slow
+	     * the processing down doing more complicated checking, but
+	     * someone else might have different ideas in the future.
+	     */
+	    if (base64_codetovaluep1[*in] > 0 || *in == B64_PAD)
+		token[i++] = *in;
+	    in++;
+	    length--;
+	}
+
+	if (i < 4) {
+	    /* Didn't get enough for a complete token. */
+	    data->token_size = i;
+	    break;
+	}
+	i = 0;
+
+	PR_ASSERT((out - data->output_buffer + 3) <= data->output_buflen);
+
+	/*
+	 * Assume we are not at the end; the following function only works
+	 * for an internal token (no trailing padding characters) but is
+	 * faster that way.  If it hits an invalid character (padding) it
+	 * will return an error; we break out of the loop and try again
+	 * calling the routine that will handle a final token.
+	 * Note that we intentionally do it this way rather than explicitly
+	 * add a check for padding here (because that would just slow down
+	 * the normal case) nor do we rely on checking whether we have more
+	 * input to process (because that would also slow it down but also
+	 * because we want to allow trailing garbage, especially white space
+	 * and cannot tell that without read-ahead, also a slow proposition).
+	 * Whew.  Understand?
+	 */
+	n = pl_base64_decode_4to3 (token, out);
+	if (n < 0)
+	    break;
+
+	/* Advance "out" by the number of bytes just written to it. */
+	out += n;
+	n = 0;
+    }
+
+    /*
+     * See big comment above, before call to pl_base64_decode_4to3.
+     * Here we check if we error'd out of loop, and allow for the case
+     * that we are processing the last interesting token.  If the routine
+     * which should handle padding characters also fails, then we just
+     * have bad input and give up.
+     */
+    if (n < 0) {
+	n = pl_base64_decode_token (token, out);
+	if (n < 0)
+	    return PR_FAILURE;
+
+	out += n;
+    }
+
+    /*
+     * As explained above, we can get here with more input remaining, but
+     * it should be all characters we do not care about (i.e. would be
+     * ignored when transferring from "in" to "token" in loop above,
+     * except here we choose to ignore extraneous pad characters, too).
+     * Swallow it, performing that check.  If we find more characters that
+     * we would expect to decode, something is wrong.
+     */
+    while (length > 0) {
+	if (base64_codetovaluep1[*in] > 0)
+	    return PR_FAILURE;
+	in++;
+	length--;
+    }
+
+    /* Record the length of decoded data we have left in output_buffer. */
+    data->output_length = (PRUint32) (out - data->output_buffer);
+    return PR_SUCCESS;
+}
+
+/*
+ * Flush any remaining buffered characters.  Given well-formed input,
+ * this will have nothing to do.  If the input was missing the padding
+ * characters at the end, though, there could be 1-3 characters left
+ * behind -- we will tolerate that by adding the padding for them.
+ */
+static PRStatus
+pl_base64_decode_flush (PLBase64Decoder *data)
+{
+    int count;
+
+    /*
+     * If no remaining characters, or all are padding (also not well-formed
+     * input, but again, be tolerant), then nothing more to do.  (And, that
+     * is considered successful.)
+     */
+    if (data->token_size == 0 || data->token[0] == B64_PAD)
+	return PR_SUCCESS;
+
+    /*
+     * Assume we have all the interesting input except for some expected
+     * padding characters.  Add them and decode the resulting token.
+     */
+    while (data->token_size < 4)
+	data->token[data->token_size++] = B64_PAD;
+
+    data->token_size = 0;	/* so a subsequent flush call is a no-op */
+
+    count = pl_base64_decode_token (data->token,
+				    data->output_buffer + data->output_length);
+    if (count < 0)
+	return PR_FAILURE;
+
+    /*
+     * If there is an output function, call it with this last bit of data.
+     * Otherwise we are doing all buffered output, and the decoded bytes
+     * are now there, we just need to reflect that in the length.
+     */
+    if (data->output_fn != NULL) {
+	PRInt32 output_result;
+
+	PR_ASSERT(data->output_length == 0);
+	output_result = data->output_fn (data->output_arg,
+					 data->output_buffer,
+					 (PRInt32) count);
+	if (output_result < 0)
+	    return  PR_FAILURE;
+    } else {
+	data->output_length += count;
+    }
+
+    return PR_SUCCESS;
+}
+
+
+/*
+ * The maximum space needed to hold the output of the decoder given
+ * input data of length "size".
+ */
+static PRUint32
+PL_Base64MaxDecodedLength (PRUint32 size)
+{
+    return ((size * 3) / 4);
+}
+
+
+/*
+ * A distinct internal creation function for the buffer version to use.
+ * (It does not want to specify an output_fn, and we want the normal
+ * Create function to require that.)  If more common initialization
+ * of the decoding context needs to be done, it should be done *here*.
+ */
+static PLBase64Decoder *
+pl_base64_create_decoder (void)
+{
+    return PR_NEWZAP(PLBase64Decoder);
+}
+
+/*
+ * Function to start a base64 decoding context.
+ * An "output_fn" is required; the "output_arg" parameter to that is optional.
+ */
+static PLBase64Decoder *
+PL_CreateBase64Decoder (PRInt32 (*output_fn) (void *, const unsigned char *,
+					      PRInt32),
+			void *output_arg)
+{
+    PLBase64Decoder *data;
+
+    if (output_fn == NULL) {
+	PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+	return NULL;
+    }
+
+    data = pl_base64_create_decoder ();
+    if (data != NULL) {
+	data->output_fn = output_fn;
+	data->output_arg = output_arg;
+    }
+    return data;
+}
+
+
+/*
+ * Push data through the decoder, causing the output_fn (provided to Create)
+ * to be called with the decoded data.
+ */
+static PRStatus
+PL_UpdateBase64Decoder (PLBase64Decoder *data, const char *buffer,
+			PRUint32 size)
+{
+    PRUint32 need_length;
+    PRStatus status;
+
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL || buffer == NULL || size == 0) {
+	PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+	return PR_FAILURE;
+    }
+
+    /*
+     * How much space could this update need for decoding?
+     */
+    need_length = PL_Base64MaxDecodedLength (size + data->token_size);
+
+    /*
+     * Make sure we have at least that much.  If not, (re-)allocate.
+     */
+    if (need_length > data->output_buflen) {
+	unsigned char *output_buffer = data->output_buffer;
+
+	if (output_buffer != NULL)
+	    output_buffer = (unsigned char *) PR_Realloc(output_buffer,
+							 need_length);
+	else
+	    output_buffer = (unsigned char *) PR_Malloc(need_length);
+
+	if (output_buffer == NULL)
+	    return PR_FAILURE;
+
+	data->output_buffer = output_buffer;
+	data->output_buflen = need_length;
+    }
+
+    /* There should not have been any leftover output data in the buffer. */
+    PR_ASSERT(data->output_length == 0);
+    data->output_length = 0;
+
+    status = pl_base64_decode_buffer (data, (const unsigned char *) buffer,
+				      size);
+
+    /* Now that we have some decoded data, write it. */
+    if (status == PR_SUCCESS && data->output_length > 0) {
+	PRInt32 output_result;
+
+	PR_ASSERT(data->output_fn != NULL);
+	output_result = data->output_fn (data->output_arg,
+					 data->output_buffer,
+					 (PRInt32) data->output_length);
+	if (output_result < 0)
+	    status = PR_FAILURE;
+    }
+
+    data->output_length = 0;
+    return status;
+}
+
+
+/*
+ * When you're done decoding, call this to free the data.  If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+static PRStatus
+PL_DestroyBase64Decoder (PLBase64Decoder *data, PRBool abort_p)
+{
+    PRStatus status = PR_SUCCESS;
+
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL) {
+	PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+	return PR_FAILURE;
+    }
+
+    /* Flush out the last few buffered characters. */
+    if (!abort_p)
+	status = pl_base64_decode_flush (data);
+
+    if (data->output_buffer != NULL)
+	PR_Free(data->output_buffer);
+    PR_Free(data);
+
+    return status;
+}
+
+
+/*
+ * Perform base64 decoding from an input buffer to an output buffer.
+ * The output buffer can be provided (as "dest"); you can also pass in
+ * a NULL and this function will allocate a buffer large enough for you,
+ * and return it.  If you do provide the output buffer, you must also
+ * provide the maximum length of that buffer (as "maxdestlen").
+ * The actual decoded length of output will be returned to you in
+ * "output_destlen".
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+static unsigned char *
+PL_Base64DecodeBuffer (const char *src, PRUint32 srclen, unsigned char *dest,
+		       PRUint32 maxdestlen, PRUint32 *output_destlen)
+{
+    PRUint32 need_length;
+    unsigned char *output_buffer = NULL;
+    PLBase64Decoder *data = NULL;
+    PRStatus status;
+
+    PR_ASSERT(srclen > 0);
+    if (srclen == 0)
+	return dest;
+
+    /*
+     * How much space could we possibly need for decoding this input?
+     */
+    need_length = PL_Base64MaxDecodedLength (srclen);
+
+    /*
+     * Make sure we have at least that much, if output buffer provided.
+     * If no output buffer provided, then we allocate that much.
+     */
+    if (dest != NULL) {
+	PR_ASSERT(maxdestlen >= need_length);
+	if (maxdestlen < need_length) {
+	    PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+	    goto loser;
+	}
+	output_buffer = dest;
+    } else {
+	output_buffer = (unsigned char *) PR_Malloc(need_length);
+	if (output_buffer == NULL)
+	    goto loser;
+	maxdestlen = need_length;
+    }
+
+    data = pl_base64_create_decoder();
+    if (data == NULL)
+	goto loser;
+
+    data->output_buflen = maxdestlen;
+    data->output_buffer = output_buffer;
+
+    status = pl_base64_decode_buffer (data, (const unsigned char *) src,
+				      srclen);
+
+    /*
+     * We do not wait for Destroy to flush, because Destroy will also
+     * get rid of our decoder context, which we need to look at first!
+     */
+    if (status == PR_SUCCESS)
+	status = pl_base64_decode_flush (data);
+
+    /* Must clear this or Destroy will free it. */
+    data->output_buffer = NULL;
+
+    if (status == PR_SUCCESS) {
+	*output_destlen = data->output_length;
+	status = PL_DestroyBase64Decoder (data, PR_FALSE);
+	data = NULL;
+	if (status == PR_FAILURE)
+	    goto loser;
+	return output_buffer;
+    }
+
+loser:
+    if (dest == NULL && output_buffer != NULL)
+	PR_Free(output_buffer);
+    if (data != NULL)
+	(void) PL_DestroyBase64Decoder (data, PR_TRUE);
+    return NULL;
+}
+
+
+/*
+ * XXX End of base64 decoding code to be moved into NSPR.
+ ********************************************************
+ */
+
+/*
+ * This is the beginning of the NSS cover functions.  These will
+ * provide the interface we want to expose as NSS-ish.  For example,
+ * they will operate on our Items, do any special handling or checking
+ * we want to do, etc.
+ */
+
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A boring cover structure for now.  Perhaps someday it will include
+ * some more interesting fields.
+ */
+struct NSSBase64DecoderStr {
+    PLBase64Decoder *pl_data;
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Function to start a base64 decoding context.
+ */
+NSSBase64Decoder *
+NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
+					       PRInt32),
+			 void *output_arg)
+{
+    PLBase64Decoder *pl_data;
+    NSSBase64Decoder *nss_data;
+
+    nss_data = PORT_ZNew(NSSBase64Decoder);
+    if (nss_data == NULL)
+	return NULL;
+
+    pl_data = PL_CreateBase64Decoder (output_fn, output_arg);
+    if (pl_data == NULL) {
+	PORT_Free(nss_data);
+	return NULL;
+    }
+
+    nss_data->pl_data = pl_data;
+    return nss_data;
+}
+
+
+/*
+ * Push data through the decoder, causing the output_fn (provided to Create)
+ * to be called with the decoded data.
+ */
+SECStatus
+NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
+			 PRUint32 size)
+{
+    PRStatus pr_status;
+
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL) {
+	PORT_SetError (SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    pr_status = PL_UpdateBase64Decoder (data->pl_data, buffer, size);
+    if (pr_status == PR_FAILURE)
+	return SECFailure;
+
+    return SECSuccess;
+}
+
+
+/*
+ * When you're done decoding, call this to free the data.  If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+SECStatus
+NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p)
+{
+    PRStatus pr_status;
+
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL) {
+	PORT_SetError (SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    pr_status = PL_DestroyBase64Decoder (data->pl_data, abort_p);
+
+    PORT_Free(data);
+
+    if (pr_status == PR_FAILURE)
+	return SECFailure;
+
+    return SECSuccess;
+}
+
+
+/*
+ * Perform base64 decoding from an ascii string "inStr" to an Item.
+ * The length of the input must be provided as "inLen".  The Item
+ * may be provided (as "outItemOpt"); you can also pass in a NULL
+ * and the Item will be allocated for you.
+ *
+ * In any case, the data within the Item will be allocated for you.
+ * All allocation will happen out of the passed-in "arenaOpt", if non-NULL.
+ * If "arenaOpt" is NULL, standard allocation (heap) will be used and
+ * you will want to free the result via SECITEM_FreeItem.
+ *
+ * Return value is NULL on error, the Item (allocated or provided) otherwise.
+ */
+SECItem *
+NSSBase64_DecodeBuffer (PRArenaPool *arenaOpt, SECItem *outItemOpt,
+			const char *inStr, unsigned int inLen)
+{
+    SECItem *out_item = outItemOpt;
+    PRUint32 max_out_len = PL_Base64MaxDecodedLength (inLen);
+    PRUint32 out_len;
+    void *mark = NULL;
+    unsigned char *dummy;
+
+    PORT_Assert(outItemOpt == NULL || outItemOpt->data == NULL);
+
+    if (arenaOpt != NULL)
+	mark = PORT_ArenaMark (arenaOpt);
+
+    out_item = SECITEM_AllocItem (arenaOpt, outItemOpt, max_out_len);
+    if (out_item == NULL) {
+	if (arenaOpt != NULL)
+	    PORT_ArenaRelease (arenaOpt, mark);
+	return NULL;
+    }
+
+    dummy = PL_Base64DecodeBuffer (inStr, inLen, out_item->data,
+				   max_out_len, &out_len);
+    if (dummy == NULL) {
+	if (arenaOpt != NULL) {
+	    PORT_ArenaRelease (arenaOpt, mark);
+	    if (outItemOpt != NULL) {
+		outItemOpt->data = NULL;
+		outItemOpt->len = 0;
+	    }
+	} else {
+	    SECITEM_FreeItem (out_item,
+			      (outItemOpt == NULL) ? PR_TRUE : PR_FALSE);
+	}
+	return NULL;
+    }
+
+    if (arenaOpt != NULL)
+	PORT_ArenaUnmark (arenaOpt, mark);
+    out_item->len = out_len;
+    return out_item;
+}
+
+
+/*
+ * XXX Everything below is deprecated.  If you add new stuff, put it
+ * *above*, not below.
+ */
+
+/*
+ * XXX The following "ATOB" functions are provided for backward compatibility
+ * with current code.  They should be considered strongly deprecated.
+ * When we can convert all our code over to using the new NSSBase64Decoder_
+ * functions defined above, we should get rid of these altogether.  (Remove
+ * protoypes from base64.h as well -- actually, remove that file completely).
+ * If someone thinks either of these functions provides such a very useful
+ * interface (though, as shown, the same functionality can already be
+ * obtained by calling NSSBase64_DecodeBuffer directly), fine -- but then
+ * that API should be provided with a nice new NSSFoo name and using
+ * appropriate types, etc.
+ */
+
+#include "base64.h"
+
+/*
+** Return an PORT_Alloc'd string which is the base64 decoded version
+** of the input string; set *lenp to the length of the returned data.
+*/
+unsigned char *
+ATOB_AsciiToData(const char *string, unsigned int *lenp)
+{
+    SECItem binary_item, *dummy;
+
+    binary_item.data = NULL;
+    binary_item.len = 0;
+
+    dummy = NSSBase64_DecodeBuffer (NULL, &binary_item, string,
+				    (PRUint32) PORT_Strlen(string));
+    if (dummy == NULL)
+	return NULL;
+
+    PORT_Assert(dummy == &binary_item);
+
+    *lenp = dummy->len;
+    return dummy->data;
+}
+ 
+/*
+** Convert from ascii to binary encoding of an item.
+*/
+SECStatus
+ATOB_ConvertAsciiToItem(SECItem *binary_item, char *ascii)
+{
+    SECItem *dummy;
+
+    if (binary_item == NULL) {
+	PORT_SetError (SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    /*
+     * XXX Would prefer to assert here if data is non-null (actually,
+     * don't need to, just let NSSBase64_DecodeBuffer do it), so as to
+     * to catch unintended memory leaks, but callers are not clean in
+     * this respect so we need to explicitly clear here to avoid the
+     * assert in NSSBase64_DecodeBuffer.
+     */
+    binary_item->data = NULL;
+    binary_item->len = 0;
+
+    dummy = NSSBase64_DecodeBuffer (NULL, binary_item, ascii,
+				    (PRUint32) PORT_Strlen(ascii));
+
+    if (dummy == NULL)
+	return SECFailure;
+
+    return SECSuccess;
+}
diff --git a/mozilla/security/nss/lib/util/nssb64e.c b/mozilla/security/nss/lib/util/nssb64e.c
new file mode 100644
index 0000000..44932ce
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssb64e.c
@@ -0,0 +1,765 @@
+/* ***** 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 ***** */
+
+/*
+ * Base64 encoding (binary to ascii).
+ *
+ * $Id: nssb64e.c,v 1.3 2004/04/25 15:03:17 gerv%gerv.net Exp $
+ */
+
+#include "nssb64.h"
+#include "nspr.h"
+#include "secitem.h"
+#include "secerr.h"
+
+/*
+ * XXX See the big comment at the top of nssb64d.c about moving the
+ * bulk of this code over into NSPR (the PL part).  It all applies
+ * here but I didn't want to duplicate it, to avoid divergence problems.
+ */ 
+
+/*
+ **************************************************************
+ * XXX Beginning of base64 encoding code to be moved into NSPR.
+ */
+
+
+struct PLBase64EncodeStateStr {
+    unsigned chunks;
+    unsigned saved;
+    unsigned char buf[3];
+};
+
+/*
+ * This typedef would belong in the NSPR header file (i.e. plbase64.h).
+ */
+typedef struct PLBase64EncoderStr PLBase64Encoder;
+
+/*
+ * The following implementation of base64 encoding was based on code
+ * found in libmime (specifically, in mimeenc.c).  It has been adapted to
+ * use PR types and naming as well as to provide other necessary semantics
+ * (like buffer-in/buffer-out in addition to "streaming" without undue
+ * performance hit of extra copying if you made the buffer versions
+ * use the output_fn).  It also incorporates some aspects of the current
+ * NSPR base64 encoding code.  As such, you may find similarities to
+ * both of those implementations.  I tried to use names that reflected
+ * the original code when possible.  For this reason you may find some
+ * inconsistencies -- libmime used lots of "in" and "out" whereas the
+ * NSPR version uses "src" and "dest"; sometimes I changed one to the other
+ * and sometimes I left them when I thought the subroutines were at least
+ * self-consistent.
+ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Opaque object used by the encoder to store state.
+ */
+struct PLBase64EncoderStr {
+    /*
+     * The one or two bytes pending.  (We need 3 to create a "token",
+     * and hold the leftovers here.  in_buffer_count is *only* ever
+     * 0, 1, or 2.
+     */
+    unsigned char in_buffer[2];
+    int in_buffer_count;
+
+    /*
+     * If the caller wants linebreaks added, line_length specifies
+     * where they come out.  It must be a multiple of 4; if the caller
+     * provides one that isn't, we round it down to the nearest
+     * multiple of 4.
+     *
+     * The value of current_column counts how many characters have been
+     * added since the last linebreaks (or since the beginning, on the
+     * first line).  It is also always a multiple of 4; it is unused when
+     * line_length is 0.
+     */ 
+    PRUint32 line_length;
+    PRUint32 current_column;
+
+    /*
+     * Where to write the encoded data (used when streaming, not when
+     * doing all in-memory (buffer) operations).
+     *
+     * Note that this definition is chosen to be compatible with PR_Write.
+     */
+    PRInt32 (*output_fn) (void *output_arg, const char *buf, PRInt32 size);
+    void *output_arg;
+
+    /*
+     * Where the encoded output goes -- either temporarily (in the streaming
+     * case, staged here before it goes to the output function) or what will
+     * be the entire buffered result for users of the buffer version.
+     */
+    char *output_buffer;
+    PRUint32 output_buflen;	/* the total length of allocated buffer */
+    PRUint32 output_length;	/* the length that is currently populated */
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Table to convert a binary value to its corresponding ascii "code".
+ */
+static unsigned char base64_valuetocode[64] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define B64_PAD	'='
+#define B64_CR	'\r'
+#define B64_LF	'\n'
+
+static PRStatus
+pl_base64_encode_buffer (PLBase64Encoder *data, const unsigned char *in,
+			 PRUint32 size)
+{
+    const unsigned char *end = in + size;
+    char *out = data->output_buffer + data->output_length;
+    unsigned int i = data->in_buffer_count;
+    PRUint32 n = 0;
+    int off;
+    PRUint32 output_threshold;
+
+    /* If this input buffer is too small, wait until next time. */
+    if (size < (3 - i)) {
+	data->in_buffer[i++] = in[0];
+	if (size > 1)
+	    data->in_buffer[i++] = in[1];
+	PR_ASSERT(i < 3);
+	data->in_buffer_count = i;
+	return PR_SUCCESS;
+    }
+
+    /* If there are bytes that were put back last time, take them now. */
+    if (i > 0) {
+	n = data->in_buffer[0];
+	if (i > 1)
+	    n = (n << 8) | data->in_buffer[1];
+	data->in_buffer_count = 0;
+    }
+
+    /* If our total is not a multiple of three, put one or two bytes back. */
+    off = (size + i) % 3;
+    if (off > 0) {
+	size -= off;
+	data->in_buffer[0] = in[size];
+	if (off > 1)
+	    data->in_buffer[1] = in[size + 1];
+	data->in_buffer_count = off;
+	end -= off;
+    }
+
+    output_threshold = data->output_buflen - 3;
+
+    /*
+     * Populate the output buffer with base64 data, one line (or buffer)
+     * at a time.
+     */
+    while (in < end) {
+	int j, k;
+
+	while (i < 3) {
+	    n = (n << 8) | *in++;
+	    i++;
+	}
+	i = 0;
+
+	if (data->line_length > 0) {
+	    if (data->current_column >= data->line_length) {
+		data->current_column = 0;
+		*out++ = B64_CR;
+		*out++ = B64_LF;
+		data->output_length += 2;
+	    }
+	    data->current_column += 4;	/* the bytes we are about to add */
+	}
+
+	for (j = 18; j >= 0; j -= 6) {
+	    k = (n >> j) & 0x3F;
+	    *out++ = base64_valuetocode[k];
+	}
+	n = 0;
+	data->output_length += 4;
+
+	if (data->output_length >= output_threshold) {
+	    PR_ASSERT(data->output_length <= data->output_buflen);
+	    if (data->output_fn != NULL) {
+		PRInt32 output_result;
+
+		output_result = data->output_fn (data->output_arg,
+						 data->output_buffer,
+						 (PRInt32) data->output_length);
+		if (output_result < 0)
+		    return PR_FAILURE;
+
+		out = data->output_buffer;
+		data->output_length = 0;
+	    } else {
+		/*
+		 * Check that we are about to exit the loop.  (Since we
+		 * are over the threshold, there isn't enough room in the
+		 * output buffer for another trip around.)
+		 */
+		PR_ASSERT(in == end);
+		if (in < end) {
+		    PR_SetError (PR_BUFFER_OVERFLOW_ERROR, 0);
+		    return PR_FAILURE;
+		}
+	    }
+	}
+    }
+
+    return PR_SUCCESS;
+}
+
+static PRStatus
+pl_base64_encode_flush (PLBase64Encoder *data)
+{
+    int i = data->in_buffer_count;
+
+    if (i == 0 && data->output_length == 0)
+	return PR_SUCCESS;
+
+    if (i > 0) {
+	char *out = data->output_buffer + data->output_length;
+	PRUint32 n;
+	int j, k;
+
+	n = ((PRUint32) data->in_buffer[0]) << 16;
+	if (i > 1)
+	    n |= ((PRUint32) data->in_buffer[1] << 8);
+
+	data->in_buffer_count = 0;
+
+	if (data->line_length > 0) {
+	    if (data->current_column >= data->line_length) {
+		data->current_column = 0;
+		*out++ = B64_CR;
+		*out++ = B64_LF;
+		data->output_length += 2;
+	    }
+	}
+
+	/*
+	 * This will fill in more than we really have data for, but the
+	 * valid parts will end up in the correct position and the extras
+	 * will be over-written with pad characters below.
+	 */
+	for (j = 18; j >= 0; j -= 6) {
+	    k = (n >> j) & 0x3F;
+	    *out++ = base64_valuetocode[k];
+	}
+
+	/* Pad with equal-signs. */
+	if (i == 1)
+	    out[-2] = B64_PAD;
+	out[-1] = B64_PAD;
+
+	data->output_length += 4;
+    }
+
+    if (data->output_fn != NULL) {
+	PRInt32 output_result;
+
+	output_result = data->output_fn (data->output_arg, data->output_buffer,
+					 (PRInt32) data->output_length);
+	data->output_length = 0;
+
+	if (output_result < 0)
+	    return PR_FAILURE;
+    }
+
+    return PR_SUCCESS;
+}
+
+
+/*
+ * The maximum space needed to hold the output of the encoder given input
+ * data of length "size", and allowing for CRLF added at least every
+ * line_length bytes (we will add it at nearest lower multiple of 4).
+ * There is no trailing CRLF.
+ */
+static PRUint32
+PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length)
+{
+    PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder;
+
+    tokens = (size + 2) / 3;
+
+    if (line_length == 0)
+	return tokens * 4;
+
+    if (line_length < 4)	/* too small! */
+	line_length = 4;
+
+    tokens_per_line = line_length / 4;
+    full_lines = tokens / tokens_per_line;
+    remainder = (tokens - (full_lines * tokens_per_line)) * 4;
+    line_break_chars = full_lines * 2;
+    if (remainder == 0)
+	line_break_chars -= 2;
+
+    return (full_lines * tokens_per_line * 4) + line_break_chars + remainder;
+}
+
+
+/*
+ * A distinct internal creation function for the buffer version to use.
+ * (It does not want to specify an output_fn, and we want the normal
+ * Create function to require that.)  All common initialization of the
+ * encoding context should be done *here*.
+ *
+ * Save "line_length", rounded down to nearest multiple of 4 (if not
+ * already even multiple).  Allocate output_buffer, if not provided --
+ * based on given size if specified, otherwise based on line_length.
+ */
+static PLBase64Encoder *
+pl_base64_create_encoder (PRUint32 line_length, char *output_buffer,
+			  PRUint32 output_buflen)
+{
+    PLBase64Encoder *data;
+    PRUint32 line_tokens;
+
+    data = PR_NEWZAP(PLBase64Encoder);
+    if (data == NULL)
+	return NULL;
+
+    if (line_length > 0 && line_length < 4)	/* too small! */
+	line_length = 4;
+
+    line_tokens = line_length / 4;
+    data->line_length = line_tokens * 4;
+
+    if (output_buffer == NULL) {
+	if (output_buflen == 0) {
+	    if (data->line_length > 0)	/* need to include room for CRLF */
+		output_buflen = data->line_length + 2;
+	    else
+		output_buflen = 64;		/* XXX what is a good size? */
+	}
+
+	output_buffer = (char *) PR_Malloc(output_buflen);
+	if (output_buffer == NULL) {
+	    PR_Free(data);
+	    return NULL;
+	}
+    }
+
+    data->output_buffer = output_buffer;
+    data->output_buflen = output_buflen;
+    return data;
+}
+
+/*
+ * Function to start a base64 encoding context.
+ * An "output_fn" is required; the "output_arg" parameter to that is optional.
+ * If linebreaks in the encoded output are desired, "line_length" specifies
+ * where to place them -- it will be rounded down to the nearest multiple of 4
+ * (if it is not already an even multiple of 4).  If it is zero, no linebreaks
+ * will be added.  (FYI, a linebreak is CRLF -- two characters.)
+ */
+static PLBase64Encoder *
+PL_CreateBase64Encoder (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+			void *output_arg, PRUint32 line_length)
+{
+    PLBase64Encoder *data;
+
+    if (output_fn == NULL) {
+	PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+	return NULL;
+    }
+
+    data = pl_base64_create_encoder (line_length, NULL, 0);
+    if (data == NULL)
+	return NULL;
+
+    data->output_fn = output_fn;
+    data->output_arg = output_arg;
+
+    return data;
+}
+
+
+/*
+ * Push data through the encoder, causing the output_fn (provided to Create)
+ * to be called with the encoded data.
+ */
+static PRStatus
+PL_UpdateBase64Encoder (PLBase64Encoder *data, const unsigned char *buffer,
+			PRUint32 size)
+{
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL || buffer == NULL || size == 0) {
+	PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+	return PR_FAILURE;
+    }
+
+    return pl_base64_encode_buffer (data, buffer, size);
+}
+
+
+/*
+ * When you're done encoding, call this to free the data.  If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+static PRStatus
+PL_DestroyBase64Encoder (PLBase64Encoder *data, PRBool abort_p)
+{
+    PRStatus status = PR_SUCCESS;
+
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL) {
+	PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+	return PR_FAILURE;
+    }
+
+    /* Flush out the last few buffered characters. */
+    if (!abort_p)
+	status = pl_base64_encode_flush (data);
+
+    if (data->output_buffer != NULL)
+	PR_Free(data->output_buffer);
+    PR_Free(data);
+
+    return status;
+}
+
+
+/*
+ * Perform base64 encoding from an input buffer to an output buffer.
+ * The output buffer can be provided (as "dest"); you can also pass in
+ * a NULL and this function will allocate a buffer large enough for you,
+ * and return it.  If you do provide the output buffer, you must also
+ * provide the maximum length of that buffer (as "maxdestlen").
+ * The actual encoded length of output will be returned to you in
+ * "output_destlen".
+ *
+ * If linebreaks in the encoded output are desired, "line_length" specifies
+ * where to place them -- it will be rounded down to the nearest multiple of 4
+ * (if it is not already an even multiple of 4).  If it is zero, no linebreaks
+ * will be added.  (FYI, a linebreak is CRLF -- two characters.)
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+static char *
+PL_Base64EncodeBuffer (const unsigned char *src, PRUint32 srclen,
+		       PRUint32 line_length, char *dest, PRUint32 maxdestlen,
+		       PRUint32 *output_destlen)
+{
+    PRUint32 need_length;
+    PLBase64Encoder *data = NULL;
+    PRStatus status;
+
+    PR_ASSERT(srclen > 0);
+    if (srclen == 0)
+	return dest;
+
+    /*
+     * How much space could we possibly need for encoding this input?
+     */
+    need_length = PL_Base64MaxEncodedLength (srclen, line_length);
+
+    /*
+     * Make sure we have at least that much, if output buffer provided.
+     */
+    if (dest != NULL) {
+	PR_ASSERT(maxdestlen >= need_length);
+	if (maxdestlen < need_length) {
+	    PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+	    return NULL;
+	}
+    } else {
+	maxdestlen = need_length;
+    }
+
+    data = pl_base64_create_encoder(line_length, dest, maxdestlen);
+    if (data == NULL)
+	return NULL;
+
+    status = pl_base64_encode_buffer (data, src, srclen);
+
+    /*
+     * We do not wait for Destroy to flush, because Destroy will also
+     * get rid of our encoder context, which we need to look at first!
+     */
+    if (status == PR_SUCCESS)
+	status = pl_base64_encode_flush (data);
+
+    if (status != PR_SUCCESS) {
+	(void) PL_DestroyBase64Encoder (data, PR_TRUE);
+	return NULL;
+    }
+
+    dest = data->output_buffer;
+
+    /* Must clear this or Destroy will free it. */
+    data->output_buffer = NULL;
+
+    *output_destlen = data->output_length;
+    status = PL_DestroyBase64Encoder (data, PR_FALSE);
+    if (status == PR_FAILURE) {
+	PR_Free(dest);
+	return NULL;
+    }
+
+    return dest;
+}
+
+/*
+ * XXX End of base64 encoding code to be moved into NSPR.
+ ********************************************************
+ */
+
+/*
+ * This is the beginning of the NSS cover functions.  These will
+ * provide the interface we want to expose as NSS-ish.  For example,
+ * they will operate on our Items, do any special handling or checking
+ * we want to do, etc.
+ */
+
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A boring cover structure for now.  Perhaps someday it will include
+ * some more interesting fields.
+ */
+struct NSSBase64EncoderStr {
+    PLBase64Encoder *pl_data;
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Function to start a base64 encoding context.
+ */
+NSSBase64Encoder *
+NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+			 void *output_arg)
+{
+    PLBase64Encoder *pl_data;
+    NSSBase64Encoder *nss_data;
+
+    nss_data = PORT_ZNew(NSSBase64Encoder);
+    if (nss_data == NULL)
+	return NULL;
+
+    pl_data = PL_CreateBase64Encoder (output_fn, output_arg, 64);
+    if (pl_data == NULL) {
+	PORT_Free(nss_data);
+	return NULL;
+    }
+
+    nss_data->pl_data = pl_data;
+    return nss_data;
+}
+
+
+/*
+ * Push data through the encoder, causing the output_fn (provided to Create)
+ * to be called with the encoded data.
+ */
+SECStatus
+NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
+			 PRUint32 size)
+{
+    PRStatus pr_status;
+
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL) {
+	PORT_SetError (SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    pr_status = PL_UpdateBase64Encoder (data->pl_data, buffer, size);
+    if (pr_status == PR_FAILURE)
+	return SECFailure;
+
+    return SECSuccess;
+}
+
+
+/*
+ * When you're done encoding, call this to free the data.  If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+SECStatus
+NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p)
+{
+    PRStatus pr_status;
+
+    /* XXX Should we do argument checking only in debug build? */
+    if (data == NULL) {
+	PORT_SetError (SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    pr_status = PL_DestroyBase64Encoder (data->pl_data, abort_p);
+
+    PORT_Free(data);
+
+    if (pr_status == PR_FAILURE)
+	return SECFailure;
+
+    return SECSuccess;
+}
+
+
+/*
+ * Perform base64 encoding of binary data "inItem" to an ascii string.
+ * The output buffer may be provided (as "outStrOpt"); you can also pass
+ * in a NULL and the buffer will be allocated for you.  The result will
+ * be null-terminated, and if the buffer is provided, "maxOutLen" must
+ * specify the maximum length of the buffer and will be checked to
+ * supply sufficient space space for the encoded result.  (If "outStrOpt"
+ * is NULL, "maxOutLen" is ignored.)
+ *
+ * If "outStrOpt" is NULL, allocation will happen out of the passed-in
+ * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap)
+ * will be used.
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+char *
+NSSBase64_EncodeItem (PRArenaPool *arenaOpt, char *outStrOpt,
+		      unsigned int maxOutLen, SECItem *inItem)
+{
+    char *out_string = outStrOpt;
+    PRUint32 max_out_len;
+    PRUint32 out_len;
+    void *mark = NULL;
+    char *dummy;
+
+    PORT_Assert(inItem != NULL && inItem->data != NULL && inItem->len != 0);
+    if (inItem == NULL || inItem->data == NULL || inItem->len == 0) {
+	PORT_SetError (SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    max_out_len = PL_Base64MaxEncodedLength (inItem->len, 64);
+
+    if (arenaOpt != NULL)
+	mark = PORT_ArenaMark (arenaOpt);
+
+    if (out_string == NULL) {
+	if (arenaOpt != NULL)
+	    out_string = PORT_ArenaAlloc (arenaOpt, max_out_len + 1);
+	else
+	    out_string = PORT_Alloc (max_out_len + 1);
+
+	if (out_string == NULL) {
+	    if (arenaOpt != NULL)
+		PORT_ArenaRelease (arenaOpt, mark);
+	    return NULL;
+	}
+    } else {
+	if ((max_out_len + 1) > maxOutLen) {
+	    PORT_SetError (SEC_ERROR_OUTPUT_LEN);
+	    return NULL;
+	}
+	max_out_len = maxOutLen;
+    }
+
+
+    dummy = PL_Base64EncodeBuffer (inItem->data, inItem->len, 64,
+				   out_string, max_out_len, &out_len);
+    if (dummy == NULL) {
+	if (arenaOpt != NULL) {
+	    PORT_ArenaRelease (arenaOpt, mark);
+	} else {
+	    PORT_Free (out_string);
+	}
+	return NULL;
+    }
+
+    if (arenaOpt != NULL)
+	PORT_ArenaUnmark (arenaOpt, mark);
+
+    out_string[out_len] = '\0';
+    return out_string;
+}
+
+
+/*
+ * XXX Everything below is deprecated.  If you add new stuff, put it
+ * *above*, not below.
+ */
+
+/*
+ * XXX The following "BTOA" functions are provided for backward compatibility
+ * with current code.  They should be considered strongly deprecated.
+ * When we can convert all our code over to using the new NSSBase64Encoder_
+ * functions defined above, we should get rid of these altogether.  (Remove
+ * protoypes from base64.h as well -- actually, remove that file completely).
+ * If someone thinks either of these functions provides such a very useful
+ * interface (though, as shown, the same functionality can already be
+ * obtained by calling NSSBase64_EncodeItem directly), fine -- but then
+ * that API should be provided with a nice new NSSFoo name and using
+ * appropriate types, etc.
+ */
+
+#include "base64.h"
+
+/*
+** Return an PORT_Alloc'd ascii string which is the base64 encoded
+** version of the input string.
+*/
+char *
+BTOA_DataToAscii(const unsigned char *data, unsigned int len)
+{
+    SECItem binary_item;
+
+    binary_item.data = (unsigned char *)data;
+    binary_item.len = len;
+
+    return NSSBase64_EncodeItem (NULL, NULL, 0, &binary_item);
+}
+
+/*
+** Convert from binary encoding of an item to ascii.
+*/
+char *
+BTOA_ConvertItemToAscii (SECItem *binary_item)
+{
+    return NSSBase64_EncodeItem (NULL, NULL, 0, binary_item);
+}
diff --git a/mozilla/security/nss/lib/util/nssb64t.h b/mozilla/security/nss/lib/util/nssb64t.h
new file mode 100644
index 0000000..3debf81
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssb64t.h
@@ -0,0 +1,49 @@
+/* ***** 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 ***** */
+
+/*
+ * Public data structures for base64 encoding/decoding.
+ *
+ * $Id: nssb64t.h,v 1.3 2007/10/12 01:44:51 julien.pierre.boogz%sun.com Exp $
+ */
+#ifndef _NSSB64T_H_
+#define _NSSB64T_H_
+
+#include "utilrename.h"
+typedef struct NSSBase64DecoderStr NSSBase64Decoder;
+typedef struct NSSBase64EncoderStr NSSBase64Encoder;
+
+#endif /* _NSSB64T_H_ */
diff --git a/mozilla/security/nss/lib/util/nssilckt.h b/mozilla/security/nss/lib/util/nssilckt.h
new file mode 100644
index 0000000..797b4e1
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssilckt.h
@@ -0,0 +1,223 @@
+/* ***** 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 ***** */
+
+/*
+** nssilock.h - Instrumented locking functions for NSS
+**
+** Description:
+**    nssilock provides instrumentation for locks and monitors in
+**    the NSS libraries. The instrumentation, when enabled, causes
+**    each call to the instrumented function to record data about
+**    the call to an external file. The external file
+**    subsequently used to extract performance data and other
+**    statistical information about the operation of locks used in
+**    the nss library.
+**     
+**    To enable compilation with instrumentation, build NSS with 
+**    the compile time switch NEED_NSS_ILOCK defined.
+**
+**    say:  "gmake OS_CFLAGS+=-DNEED_NSS_ILOCK" at make time.
+**
+**    At runtime, to enable recording from nssilock, one or more
+**    environment variables must be set. For each nssILockType to
+**    be recorded, an environment variable of the form NSS_ILOCK_x
+**    must be set to 1. For example:
+**
+**       set NSS_ILOCK_Cert=1
+**
+**    nssilock uses PRLOG is used to record to trace data. The
+**    PRLogModule name associated with nssilock data is: "nssilock".
+**    To enable recording of nssilock data you will need to set the
+**    environment variable NSPR_LOG_MODULES to enable
+**    recording for the nssilock log module. Similarly, you will
+**    need to set the environment variable NSPR_LOG_FILE to specify
+**    the filename to receive the recorded data. See prlog.h for usage.
+**    Example:
+**
+**        export NSPR_LOG_MODULES=nssilock:6
+**        export NSPR_LOG_FILE=xxxLogfile
+**
+** Operation:
+**    nssilock wraps calls to NSPR's PZLock and PZMonitor functions
+**    with similarly named functions: PZ_NewLock(), etc. When NSS is
+**    built with lock instrumentation enabled, the PZ* functions are
+**    compiled into NSS; when lock instrumentation is disabled,
+**    calls to PZ* functions are directly mapped to PR* functions
+**    and the instrumentation arguments to the PZ* functions are
+**    compiled away.
+**
+**
+** File Format:
+**    The format of the external file is implementation
+**    dependent. Where NSPR's PR_LOG() function is used, the file
+**    contains data defined for PR_LOG() plus the data written by
+**    the wrapped function. On some platforms and under some
+**    circumstances, platform dependent logging or
+**    instrumentation probes may be used. In any case, the
+**    relevant data provided by the lock instrumentation is:
+**    
+**      lockType, func, address, duration, line, file [heldTime]
+** 
+**    where:
+**    
+**       lockType: a character representation of nssILockType for the
+**       call. e.g. ... "cert"
+**    
+**       func: the function doing the tracing. e.g. "NewLock"
+**    
+**       address: address of the instrumented lock or monitor
+**    
+**       duration: is how long was spent in the instrumented function,
+**       in PRIntervalTime "ticks".
+**    
+**       line: the line number within the calling function
+**    
+**       file: the file from which the call was made
+**    
+**       heldTime: how long the lock/monitor was held. field
+**       present only for PZ_Unlock() and PZ_ExitMonitor().
+**    
+** Design Notes:
+**    The design for lock instrumentation was influenced by the
+**    need to gather performance data on NSS 3.x. It is intended
+**    that the effort to modify NSS to use lock instrumentation
+**    be minimized. Existing calls to locking functions need only
+**    have their names changed to the instrumentation function
+**    names.
+**    
+** Private NSS Interface:
+**    nssilock.h defines a private interface for use by NSS.
+**    nssilock.h is experimental in nature and is subject to
+**    change or revocation without notice. ... Don't mess with
+**    it.
+**    
+*/
+
+/*
+ * $Id:
+ */
+
+#ifndef _NSSILCKT_H_
+#define _NSSILCKT_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "prmon.h"
+#include "prlock.h"
+#include "prcvar.h"
+
+typedef enum {
+    nssILockArena = 0,
+    nssILockSession = 1,
+    nssILockObject = 2,
+    nssILockRefLock = 3,
+    nssILockCert = 4,
+    nssILockCertDB = 5,
+    nssILockDBM = 6,
+    nssILockCache = 7,
+    nssILockSSL = 8,
+    nssILockList = 9,
+    nssILockSlot = 10,
+    nssILockFreelist = 11,
+    nssILockOID = 12,
+    nssILockAttribute = 13,
+    nssILockPK11cxt = 14,  /* pk11context */
+    nssILockRWLock = 15,
+    nssILockOther = 16,
+    nssILockSelfServ = 17,
+    nssILockKeyDB = 18,
+    nssILockLast  /* don't use this one! */
+} nssILockType;
+
+/*
+** conditionally compile in nssilock features
+*/
+#if defined(NEED_NSS_ILOCK)
+
+/*
+** Declare operation type enumerator
+** enumerations identify the function being performed
+*/
+typedef enum  {
+    FlushTT = 0,
+    NewLock = 1,
+    Lock = 2,
+    Unlock = 3,
+    DestroyLock = 4,
+    NewCondVar = 5,
+    WaitCondVar = 6,
+    NotifyCondVar = 7,
+    NotifyAllCondVar = 8,
+    DestroyCondVar = 9,
+    NewMonitor = 10,
+    EnterMonitor = 11,
+    ExitMonitor = 12,
+    Notify = 13,
+    NotifyAll = 14,
+    Wait = 15,
+    DestroyMonitor = 16
+} nssILockOp;
+
+/*
+** Declare the trace record
+*/
+struct pzTrace_s {
+    PRUint32        threadID; /* PR_GetThreadID() */
+    nssILockOp      op;       /* operation being performed */
+    nssILockType    ltype;    /* lock type identifier */
+    PRIntervalTime  callTime; /* time spent in function */
+    PRIntervalTime  heldTime; /* lock held time, or -1 */
+    void            *lock;    /* address of lock structure */    
+    PRIntn          line;     /* line number */
+    char            file[24]; /* filename */
+};
+
+/*
+** declare opaque types. See: nssilock.c
+*/
+typedef struct pzlock_s PZLock;
+typedef struct pzcondvar_s PZCondVar;
+typedef struct pzmonitor_s PZMonitor;
+
+#else /* NEED_NSS_ILOCK */
+
+#define PZLock                  PRLock
+#define PZCondVar               PRCondVar
+#define PZMonitor               PRMonitor
+    
+#endif /* NEED_NSS_ILOCK */
+
+#endif /* _NSSILCKT_H_ */
diff --git a/mozilla/security/nss/lib/util/nssilock.c b/mozilla/security/nss/lib/util/nssilock.c
new file mode 100644
index 0000000..afeb8dd
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssilock.c
@@ -0,0 +1,530 @@
+/* ***** 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 ***** */
+
+/*
+ * nssilock.c - NSS lock instrumentation wrapper functions
+ *
+ * NOTE - These are not public interfaces
+ *
+ * Implementation Notes:
+ * I've tried to make the instrumentation relatively non-intrusive.
+ * To do this, I have used a single PR_LOG() call in each
+ * instrumented function. There's room for improvement.
+ *
+ *
+ */
+
+#include "prinit.h"
+#include "prerror.h"
+#include "prlock.h"
+#include "prmem.h"
+#include "prenv.h"
+#include "prcvar.h"
+#include "prio.h"
+
+#if defined(NEED_NSS_ILOCK)
+#include "prlog.h"
+#include "nssilock.h"
+
+/*
+** Declare the instrumented PZLock 
+*/
+struct pzlock_s {
+    PRLock *lock;  /* the PZLock to be instrumented */
+    PRIntervalTime time; /* timestamp when the lock was aquired */
+    nssILockType ltype;
+};
+
+/*
+** Declare the instrumented PZMonitor 
+*/
+struct pzmonitor_s {
+    PRMonitor *mon;   /* the PZMonitor to be instrumented */
+    PRIntervalTime time; /* timestamp when the monitor was aquired */
+    nssILockType ltype;
+};
+
+/*
+** Declare the instrumented PZCondVar
+*/
+struct pzcondvar_s  {
+    PRCondVar   *cvar;  /* the PZCondVar to be instrumented */
+    nssILockType ltype;
+};
+
+
+/*
+** Define a CallOnce type to ensure serialized self-initialization
+*/
+static PRCallOnceType coNssILock;     /* CallOnce type */
+static PRIntn  nssILockInitialized;   /* initialization done when 1 */
+static PRLogModuleInfo *nssILog;      /* Log instrumentation to this handle */
+
+
+#define NUM_TT_ENTRIES 6000000
+static PRInt32  traceIndex = -1;      /* index into trace table */
+static struct pzTrace_s *tt;          /* pointer to trace table */
+static PRInt32  ttBufSize = (NUM_TT_ENTRIES * sizeof(struct pzTrace_s ));
+static PRCondVar *ttCVar;
+static PRLock    *ttLock;
+static PRFileDesc *ttfd;              /* trace table file */
+
+/*
+** Vtrace() -- Trace events, write events to external media
+**
+** Vtrace() records traced events in an in-memory trace table
+** when the trace table fills, Vtrace writes the entire table
+** to a file.
+**
+** data can be lost!
+**
+*/
+static void Vtrace(
+    nssILockOp      op,
+    nssILockType    ltype,
+    PRIntervalTime  callTime,
+    PRIntervalTime  heldTime,
+    void            *lock,
+    PRIntn          line,
+    char            *file
+)  {
+    PRInt32 idx;
+    struct pzTrace_s *tp;
+
+RetryTrace:
+    idx = PR_AtomicIncrement( &traceIndex );
+    while( NUM_TT_ENTRIES <= idx || op == FlushTT ) {
+        if( NUM_TT_ENTRIES == idx  || op == FlushTT )  {
+            int writeSize = idx * sizeof(struct pzTrace_s);
+            PR_Lock(ttLock);
+            PR_Write( ttfd, tt, writeSize );
+            traceIndex = -1;
+            PR_NotifyAllCondVar( ttCVar );
+            PR_Unlock(ttLock);
+            goto RetryTrace;
+        } else {
+            PR_Lock(ttLock);
+            while( NUM_TT_ENTRIES < idx )
+                PR_WaitCondVar(ttCVar, PR_INTERVAL_NO_WAIT);
+            PR_Unlock(ttLock);
+            goto RetryTrace;
+        }
+    } /* end while() */
+
+    /* create the trace entry */
+    tp = tt + idx;
+    tp->threadID = PR_GetThreadID(PR_GetCurrentThread());
+    tp->op = op;
+    tp->ltype = ltype;
+    tp->callTime = callTime;
+    tp->heldTime = heldTime;
+    tp->lock = lock;
+    tp ->line = line;
+    strcpy(tp->file, file );
+    return;
+} /* --- end Vtrace() --- */
+
+/*
+** pz_TraceFlush() -- Force trace table write to file
+**
+*/
+extern void pz_TraceFlush( void )
+{
+    Vtrace( FlushTT, nssILockSelfServ, 0, 0, NULL, 0, "" );
+    return;
+} /* --- end pz_TraceFlush() --- */
+
+/*
+** nssILockInit() -- Initialization for nssilock
+**
+** This function is called from the CallOnce mechanism.
+*/
+static PRStatus
+    nssILockInit( void ) 
+{   
+    int i;
+    nssILockInitialized = 1;
+
+    /* new log module */
+    nssILog = PR_NewLogModule("nssilock");
+    if ( NULL == nssILog )  {
+        return(PR_FAILURE);
+    }
+
+    tt = PR_Calloc( NUM_TT_ENTRIES, sizeof(struct pzTrace_s));
+    if (NULL == tt ) {
+        fprintf(stderr, "nssilock: can't allocate trace table\n");
+        exit(1);
+    }
+
+    ttfd = PR_Open( "xxxTTLog", PR_CREATE_FILE | PR_WRONLY, 0666 );
+    if ( NULL == ttfd )  {
+        fprintf( stderr, "Oh Drat! Can't open 'xxxTTLog'\n");
+        exit(1);
+    }
+
+    ttLock = PR_NewLock();
+    ttCVar = PR_NewCondVar(ttLock);
+
+    return(PR_SUCCESS);
+} /* --- end nssILockInit() --- */
+
+extern PZLock * pz_NewLock( 
+    nssILockType ltype,
+    char *file,  
+    PRIntn line )
+{
+    PRStatus rc;
+    PZLock  *lock;
+    
+    /* Self Initialize the nssILock feature */
+    if (!nssILockInitialized)  {
+        rc = PR_CallOnce( &coNssILock, nssILockInit );
+        if ( PR_FAILURE == rc ) {
+            PR_SetError( PR_UNKNOWN_ERROR, 0 );
+            return( NULL );
+        }
+    }
+
+    lock = PR_NEWZAP( PZLock );
+    if ( NULL != lock )  {
+        lock->ltype = ltype;
+        lock->lock = PR_NewLock();
+        if ( NULL == lock->lock )  {
+            PR_DELETE( lock );
+            PORT_SetError(SEC_ERROR_NO_MEMORY);
+        }
+    } else {
+            PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+
+    Vtrace( NewLock, ltype, 0, 0, lock, line, file );
+    return(lock);
+} /* --- end pz_NewLock() --- */
+
+extern void
+    pz_Lock(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    )
+{            
+    PRIntervalTime callTime;
+
+    callTime = PR_IntervalNow();
+    PR_Lock( lock->lock );
+    lock->time = PR_IntervalNow();
+    callTime = lock->time - callTime;
+
+    Vtrace( Lock, lock->ltype, callTime, 0, lock, line, file );
+    return;
+} /* --- end  pz_Lock() --- */
+
+extern PRStatus
+    pz_Unlock(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    ) 
+{
+    PRStatus rc;
+    PRIntervalTime callTime, now, heldTime;
+
+    callTime = PR_IntervalNow();
+    rc = PR_Unlock( lock->lock );
+    now = PR_IntervalNow(); 
+    callTime = now - callTime;
+    heldTime = now - lock->time;
+    Vtrace( Unlock, lock->ltype, callTime, heldTime, lock, line, file );
+    return( rc );
+} /* --- end  pz_Unlock() --- */
+
+extern void
+    pz_DestroyLock(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    )
+{
+    Vtrace( DestroyLock, lock->ltype, 0, 0, lock, line, file );
+    PR_DestroyLock( lock->lock );
+    PR_DELETE( lock );
+    return;
+} /* --- end  pz_DestroyLock() --- */
+
+
+
+extern PZCondVar *
+    pz_NewCondVar(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    )
+{
+    PZCondVar *cvar;
+
+    cvar = PR_NEWZAP( PZCondVar );
+    if ( NULL == cvar ) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+    } else {
+        cvar->ltype = lock->ltype; 
+        cvar->cvar = PR_NewCondVar( lock->lock );
+        if ( NULL == cvar->cvar )  {
+            PR_DELETE( cvar );
+            PORT_SetError(SEC_ERROR_NO_MEMORY);
+        }
+
+    }
+    Vtrace( NewCondVar, lock->ltype, 0, 0, cvar, line, file );
+    return( cvar );
+} /* --- end  pz_NewCondVar() --- */
+
+extern void
+    pz_DestroyCondVar(
+        PZCondVar *cvar,
+        char *file,
+        PRIntn line
+    )
+{
+    Vtrace( DestroyCondVar, cvar->ltype, 0, 0, cvar, line, file );
+    PR_DestroyCondVar( cvar->cvar );
+    PR_DELETE( cvar );
+} /* --- end  pz_DestroyCondVar() --- */
+
+extern PRStatus
+    pz_WaitCondVar(
+        PZCondVar *cvar,
+        PRIntervalTime timeout,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus    rc;
+    PRIntervalTime callTime;
+
+    callTime = PR_IntervalNow();
+    rc = PR_WaitCondVar( cvar->cvar, timeout );
+    callTime = PR_IntervalNow() - callTime;
+    
+    Vtrace( WaitCondVar, cvar->ltype, callTime, 0, cvar, line, file );
+    return(rc);
+} /* --- end  pz_WaitCondVar() --- */
+
+extern PRStatus
+    pz_NotifyCondVar(
+        PZCondVar *cvar,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus    rc;
+    
+    rc = PR_NotifyCondVar( cvar->cvar );
+    
+    Vtrace( NotifyCondVar, cvar->ltype, 0, 0, cvar, line, file );
+    return(rc);
+} /* --- end  pz_NotifyCondVar() --- */
+
+extern PRStatus
+    pz_NotifyAllCondVar(
+        PZCondVar *cvar,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus    rc;
+    
+    rc = PR_NotifyAllCondVar( cvar->cvar );
+    
+    Vtrace( NotifyAllCondVar, cvar->ltype, 0, 0, cvar, line, file );
+    return(rc);
+} /* --- end  pz_NotifyAllCondVar() --- */
+
+extern PZMonitor *
+    pz_NewMonitor( 
+        nssILockType ltype,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus rc;
+    PZMonitor   *mon;
+
+    /* Self Initialize the nssILock feature */
+    if (!nssILockInitialized)  {
+        rc = PR_CallOnce( &coNssILock, nssILockInit );
+        if ( PR_FAILURE == rc ) {
+            PR_SetError( PR_UNKNOWN_ERROR, 0 );
+            return( NULL );
+        }
+    }
+
+    mon = PR_NEWZAP( PZMonitor );
+    if ( NULL != mon )  {
+        mon->ltype = ltype;
+        mon->mon = PR_NewMonitor();
+        if ( NULL == mon->mon )  {
+            PR_DELETE( mon );
+            PORT_SetError(SEC_ERROR_NO_MEMORY);
+        }
+    } else {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+
+    Vtrace( NewMonitor, ltype, 0, 0, mon, line, file );
+    return(mon);
+} /* --- end  pz_NewMonitor() --- */
+
+extern void
+    pz_DestroyMonitor(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    )
+{
+    Vtrace( DestroyMonitor, mon->ltype, 0, 0, mon, line, file );
+    PR_DestroyMonitor( mon->mon );
+    PR_DELETE( mon );
+    return;                
+} /* --- end  pz_DestroyMonitor() --- */
+
+extern void
+    pz_EnterMonitor(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    )
+{
+    PRIntervalTime callTime, now;
+
+    callTime = PR_IntervalNow();
+    PR_EnterMonitor( mon->mon );
+    now = PR_IntervalNow();
+    callTime = now - callTime;
+    if ( PR_GetMonitorEntryCount(mon->mon) == 1 )  {
+        mon->time = now;
+    }
+    Vtrace( EnterMonitor, mon->ltype, callTime, 0, mon, line, file );
+    return;
+} /* --- end  pz_EnterMonitor() --- */
+
+extern PRStatus
+    pz_ExitMonitor(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus rc;
+    PRIntervalTime callTime, now, heldTime;
+    PRIntn  mec = PR_GetMonitorEntryCount( mon->mon );
+   
+    heldTime = (PRIntervalTime)-1; 
+    callTime = PR_IntervalNow();
+    rc = PR_ExitMonitor( mon->mon );
+    now = PR_IntervalNow();
+    callTime = now - callTime;
+    if ( mec == 1 )
+        heldTime = now - mon->time;
+    Vtrace( ExitMonitor, mon->ltype, callTime, heldTime, mon, line, file );
+    return( rc );
+} /* --- end  pz_ExitMonitor() --- */
+
+extern PRIntn
+    pz_GetMonitorEntryCount(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    )
+{
+    return( PR_GetMonitorEntryCount(mon->mon));
+} /* --- end pz_GetMonitorEntryCount() --- */
+
+
+extern PRStatus
+    pz_Wait(
+        PZMonitor *mon,
+        PRIntervalTime ticks,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus rc;
+    PRIntervalTime callTime;
+
+    callTime = PR_IntervalNow();
+    rc = PR_Wait( mon->mon, ticks );
+    callTime = PR_IntervalNow() - callTime;
+    Vtrace( Wait, mon->ltype, callTime, 0, mon, line, file );
+    return( rc );
+} /* --- end  pz_Wait() --- */
+
+extern PRStatus
+    pz_Notify(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus rc;
+    PRIntervalTime callTime;
+
+    callTime = PR_IntervalNow();
+    rc = PR_Notify( mon->mon );
+    callTime = PR_IntervalNow() - callTime;
+    Vtrace( Notify, mon->ltype, callTime, 0, mon, line, file );
+    return( rc );
+} /* --- end  pz_Notify() --- */
+
+extern PRStatus
+    pz_NotifyAll(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    )
+{
+    PRStatus rc;
+    PRIntervalTime callTime;
+
+    callTime = PR_IntervalNow();
+    rc = PR_NotifyAll( mon->mon );
+    callTime = PR_IntervalNow() - callTime;
+    Vtrace( NotifyAll, mon->ltype, callTime, 0, mon, line, file );
+    return( rc );
+} /* --- end  pz_NotifyAll() --- */
+
+#endif /* NEED_NSS_ILOCK */
+/* --- end nssilock.c --------------------------------- */
diff --git a/mozilla/security/nss/lib/util/nssilock.h b/mozilla/security/nss/lib/util/nssilock.h
new file mode 100644
index 0000000..c99abf2
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssilock.h
@@ -0,0 +1,320 @@
+/* ***** 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 ***** */
+
+/*
+** nssilock.h - Instrumented locking functions for NSS
+**
+** Description:
+**    nssilock provides instrumentation for locks and monitors in
+**    the NSS libraries. The instrumentation, when enabled, causes
+**    each call to the instrumented function to record data about
+**    the call to an external file. The external file
+**    subsequently used to extract performance data and other
+**    statistical information about the operation of locks used in
+**    the nss library.
+**     
+**    To enable compilation with instrumentation, build NSS with 
+**    the compile time switch NEED_NSS_ILOCK defined.
+**
+**    say:  "gmake OS_CFLAGS+=-DNEED_NSS_ILOCK" at make time.
+**
+**    At runtime, to enable recording from nssilock, one or more
+**    environment variables must be set. For each nssILockType to
+**    be recorded, an environment variable of the form NSS_ILOCK_x
+**    must be set to 1. For example:
+**
+**       set NSS_ILOCK_Cert=1
+**
+**    nssilock uses PRLOG is used to record to trace data. The
+**    PRLogModule name associated with nssilock data is: "nssilock".
+**    To enable recording of nssilock data you will need to set the
+**    environment variable NSPR_LOG_MODULES to enable
+**    recording for the nssilock log module. Similarly, you will
+**    need to set the environment variable NSPR_LOG_FILE to specify
+**    the filename to receive the recorded data. See prlog.h for usage.
+**    Example:
+**
+**        export NSPR_LOG_MODULES=nssilock:6
+**        export NSPR_LOG_FILE=xxxLogfile
+**
+** Operation:
+**    nssilock wraps calls to NSPR's PZLock and PZMonitor functions
+**    with similarly named functions: PZ_NewLock(), etc. When NSS is
+**    built with lock instrumentation enabled, the PZ* functions are
+**    compiled into NSS; when lock instrumentation is disabled,
+**    calls to PZ* functions are directly mapped to PR* functions
+**    and the instrumentation arguments to the PZ* functions are
+**    compiled away.
+**
+**
+** File Format:
+**    The format of the external file is implementation
+**    dependent. Where NSPR's PR_LOG() function is used, the file
+**    contains data defined for PR_LOG() plus the data written by
+**    the wrapped function. On some platforms and under some
+**    circumstances, platform dependent logging or
+**    instrumentation probes may be used. In any case, the
+**    relevant data provided by the lock instrumentation is:
+**    
+**      lockType, func, address, duration, line, file [heldTime]
+** 
+**    where:
+**    
+**       lockType: a character representation of nssILockType for the
+**       call. e.g. ... "cert"
+**    
+**       func: the function doing the tracing. e.g. "NewLock"
+**    
+**       address: address of the instrumented lock or monitor
+**    
+**       duration: is how long was spent in the instrumented function,
+**       in PRIntervalTime "ticks".
+**    
+**       line: the line number within the calling function
+**    
+**       file: the file from which the call was made
+**    
+**       heldTime: how long the lock/monitor was held. field
+**       present only for PZ_Unlock() and PZ_ExitMonitor().
+**    
+** Design Notes:
+**    The design for lock instrumentation was influenced by the
+**    need to gather performance data on NSS 3.x. It is intended
+**    that the effort to modify NSS to use lock instrumentation
+**    be minimized. Existing calls to locking functions need only
+**    have their names changed to the instrumentation function
+**    names.
+**    
+** Private NSS Interface:
+**    nssilock.h defines a private interface for use by NSS.
+**    nssilock.h is experimental in nature and is subject to
+**    change or revocation without notice. ... Don't mess with
+**    it.
+**    
+*/
+
+/*
+ * $Id:
+ */
+
+#ifndef _NSSILOCK_H_
+#define _NSSILOCK_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "prmon.h"
+#include "prlock.h"
+#include "prcvar.h"
+
+#include "nssilckt.h"
+
+PR_BEGIN_EXTERN_C
+
+#if defined(NEED_NSS_ILOCK)
+
+#define PZ_NewLock(t) pz_NewLock((t),__FILE__,__LINE__)
+extern PZLock * 
+    pz_NewLock(
+        nssILockType ltype,
+        char *file,
+        PRIntn  line
+    );
+
+#define PZ_Lock(k)  pz_Lock((k),__FILE__,__LINE__)
+extern void
+    pz_Lock(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_Unlock(k) pz_Unlock((k),__FILE__,__LINE__)
+extern PRStatus
+    pz_Unlock(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_DestroyLock(k) pz_DestroyLock((k),__FILE__,__LINE__)
+extern void
+    pz_DestroyLock(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    );
+
+
+#define PZ_NewCondVar(l)        pz_NewCondVar((l),__FILE__,__LINE__)
+extern PZCondVar *
+    pz_NewCondVar(
+        PZLock *lock,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_DestroyCondVar(v)    pz_DestroyCondVar((v),__FILE__,__LINE__)
+extern void
+    pz_DestroyCondVar(
+        PZCondVar *cvar,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_WaitCondVar(v,t)       pz_WaitCondVar((v),(t),__FILE__,__LINE__)
+extern PRStatus
+    pz_WaitCondVar(
+        PZCondVar *cvar,
+        PRIntervalTime timeout,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_NotifyCondVar(v)     pz_NotifyCondVar((v),__FILE__,__LINE__)
+extern PRStatus
+    pz_NotifyCondVar(
+        PZCondVar *cvar,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_NotifyAllCondVar(v)  pz_NotifyAllCondVar((v),__FILE__,__LINE__)
+extern PRStatus
+    pz_NotifyAllCondVar(
+        PZCondVar *cvar,
+        char *file,
+        PRIntn line
+    );
+
+
+#define PZ_NewMonitor(t) pz_NewMonitor((t),__FILE__,__LINE__)
+extern PZMonitor *
+    pz_NewMonitor( 
+        nssILockType ltype,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_DestroyMonitor(m) pz_DestroyMonitor((m),__FILE__,__LINE__)
+extern void
+    pz_DestroyMonitor(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_EnterMonitor(m) pz_EnterMonitor((m),__FILE__,__LINE__)
+extern void
+    pz_EnterMonitor(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    );
+
+
+#define PZ_ExitMonitor(m) pz_ExitMonitor((m),__FILE__,__LINE__)
+extern PRStatus
+    pz_ExitMonitor(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_InMonitor(m)  (PZ_GetMonitorEntryCount(m) > 0 )
+#define PZ_GetMonitorEntryCount(m) pz_GetMonitorEntryCount((m),__FILE__,__LINE__)
+extern PRIntn
+    pz_GetMonitorEntryCount(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_Wait(m,i) pz_Wait((m),((i)),__FILE__,__LINE__)
+extern PRStatus
+    pz_Wait(
+        PZMonitor *mon,
+        PRIntervalTime ticks,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_Notify(m) pz_Notify((m),__FILE__,__LINE__)
+extern PRStatus
+    pz_Notify(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_NotifyAll(m) pz_NotifyAll((m),__FILE__,__LINE__)
+extern PRStatus
+    pz_NotifyAll(
+        PZMonitor *mon,
+        char *file,
+        PRIntn line
+    );
+
+#define PZ_TraceFlush() pz_TraceFlush()
+extern void pz_TraceFlush( void );
+
+#else /* NEED_NSS_ILOCK */
+
+#define PZ_NewLock(t)           PR_NewLock()
+#define PZ_DestroyLock(k)       PR_DestroyLock((k))
+#define PZ_Lock(k)              PR_Lock((k))
+#define PZ_Unlock(k)            PR_Unlock((k))
+
+#define PZ_NewCondVar(l)        PR_NewCondVar((l))
+#define PZ_DestroyCondVar(v)    PR_DestroyCondVar((v))
+#define PZ_WaitCondVar(v,t)     PR_WaitCondVar((v),(t))
+#define PZ_NotifyCondVar(v)     PR_NotifyCondVar((v))
+#define PZ_NotifyAllCondVar(v)  PR_NotifyAllCondVar((v))
+
+#define PZ_NewMonitor(t)        PR_NewMonitor()
+#define PZ_DestroyMonitor(m)    PR_DestroyMonitor((m))
+#define PZ_EnterMonitor(m)      PR_EnterMonitor((m))
+#define PZ_ExitMonitor(m)       PR_ExitMonitor((m))
+#define PZ_InMonitor(m)         PR_InMonitor((m))
+#define PZ_Wait(m,t)            PR_Wait(((m)),((t)))
+#define PZ_Notify(m)            PR_Notify((m))
+#define PZ_NotifyAll(m)         PR_Notify((m))
+#define PZ_TraceFlush()         /* nothing */
+
+    
+#endif /* NEED_NSS_ILOCK */
+
+PR_END_EXTERN_C
+#endif /* _NSSILOCK_H_ */
diff --git a/mozilla/security/nss/lib/util/nsslocks.h b/mozilla/security/nss/lib/util/nsslocks.h
new file mode 100644
index 0000000..0b48b71
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nsslocks.h
@@ -0,0 +1,45 @@
+/* ***** 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 ***** */
+
+/*
+ * nsslocks.h - threadsafe functions to initialize lock pointers.
+ *
+ * NOTE - The interfaces formerly in this header were private and are now all
+ *        obsolete.
+ *
+ * $Id: nsslocks.h,v 1.5 2008/02/16 04:38:09 julien.pierre.boogz%sun.com Exp $
+ */
+
diff --git a/mozilla/security/nss/lib/util/nssrwlk.c b/mozilla/security/nss/lib/util/nssrwlk.c
new file mode 100644
index 0000000..c46e366
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssrwlk.c
@@ -0,0 +1,479 @@
+/* ***** 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 "nssrwlk.h"
+#include "nspr.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Reader-writer lock
+ */
+struct nssRWLockStr {
+    PZLock *        rw_lock;
+    char   *        rw_name;            /* lock name                    */
+    PRUint32        rw_rank;            /* rank of the lock             */
+    PRInt32         rw_writer_locks;    /* ==  0, if unlocked           */
+    PRInt32         rw_reader_locks;    /* ==  0, if unlocked           */
+                                        /* > 0  , # of read locks       */
+    PRUint32        rw_waiting_readers; /* number of waiting readers    */
+    PRUint32        rw_waiting_writers; /* number of waiting writers    */
+    PZCondVar *     rw_reader_waitq;    /* cvar for readers             */
+    PZCondVar *     rw_writer_waitq;    /* cvar for writers             */
+    PRThread  *     rw_owner;           /* lock owner for write-lock    */
+                                        /* Non-null if write lock held. */
+};
+
+PR_END_EXTERN_C
+
+#include <string.h>
+
+#ifdef DEBUG_RANK_ORDER
+#define NSS_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using
+                                       rank-order for locks
+                                    */
+#endif
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+static PRUintn  nss_thread_rwlock_initialized;
+static PRUintn  nss_thread_rwlock;               /* TPD key for lock stack */
+static PRUintn  nss_thread_rwlock_alloc_failed;
+
+#define _NSS_RWLOCK_RANK_ORDER_LIMIT 10
+
+typedef struct thread_rwlock_stack {
+    PRInt32     trs_index;                                  /* top of stack */
+    NSSRWLock    *trs_stack[_NSS_RWLOCK_RANK_ORDER_LIMIT];  /* stack of lock
+                                                               pointers */
+} thread_rwlock_stack;
+
+/* forward static declarations. */
+static PRUint32 nssRWLock_GetThreadRank(PRThread *me);
+static void     nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock);
+static void     nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock);
+static void     nssRWLock_ReleaseLockStack(void *lock_stack);
+
+#endif
+
+#define UNTIL(x) while(!(x))
+
+/*
+ * Reader/Writer Locks
+ */
+
+/*
+ * NSSRWLock_New
+ *      Create a reader-writer lock, with the given lock rank and lock name
+ *
+ */
+
+NSSRWLock *
+NSSRWLock_New(PRUint32 lock_rank, const char *lock_name)
+{
+    NSSRWLock *rwlock;
+
+    rwlock = PR_NEWZAP(NSSRWLock);
+    if (rwlock == NULL)
+        return NULL;
+
+    rwlock->rw_lock = PZ_NewLock(nssILockRWLock);
+    if (rwlock->rw_lock == NULL) {
+	goto loser;
+    }
+    rwlock->rw_reader_waitq = PZ_NewCondVar(rwlock->rw_lock);
+    if (rwlock->rw_reader_waitq == NULL) {
+	goto loser;
+    }
+    rwlock->rw_writer_waitq = PZ_NewCondVar(rwlock->rw_lock);
+    if (rwlock->rw_writer_waitq == NULL) {
+	goto loser;
+    }
+    if (lock_name != NULL) {
+        rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
+        if (rwlock->rw_name == NULL) {
+	    goto loser;
+        }
+        strcpy(rwlock->rw_name, lock_name);
+    } else {
+        rwlock->rw_name = NULL;
+    }
+    rwlock->rw_rank            = lock_rank;
+    rwlock->rw_waiting_readers = 0;
+    rwlock->rw_waiting_writers = 0;
+    rwlock->rw_reader_locks    = 0;
+    rwlock->rw_writer_locks    = 0;
+
+    return rwlock;
+
+loser:
+    NSSRWLock_Destroy(rwlock);
+    return(NULL);
+}
+
+/*
+** Destroy the given RWLock "lock".
+*/
+void
+NSSRWLock_Destroy(NSSRWLock *rwlock)
+{
+    PR_ASSERT(rwlock != NULL);
+    PR_ASSERT(rwlock->rw_waiting_readers == 0);
+
+    /* XXX Shouldn't we lock the PZLock before destroying this?? */
+
+    if (rwlock->rw_name)
+    	PR_Free(rwlock->rw_name);
+    if (rwlock->rw_reader_waitq)
+    	PZ_DestroyCondVar(rwlock->rw_reader_waitq);
+    if (rwlock->rw_writer_waitq)
+	PZ_DestroyCondVar(rwlock->rw_writer_waitq);
+    if (rwlock->rw_lock)
+	PZ_DestroyLock(rwlock->rw_lock);
+    PR_DELETE(rwlock);
+}
+
+/*
+** Read-lock the RWLock.
+*/
+void
+NSSRWLock_LockRead(NSSRWLock *rwlock)
+{
+    PRThread *me = PR_GetCurrentThread();
+
+    PZ_Lock(rwlock->rw_lock);
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+    /*
+     * assert that rank ordering is not violated; the rank of 'rwlock' should
+     * be equal to or greater than the highest rank of all the locks held by
+     * the thread.
+     */
+    PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
+              (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
+#endif
+    /*
+     * wait if write-locked or if a writer is waiting; preference for writers
+     */
+    UNTIL ( (rwlock->rw_owner == me) ||		  /* I own it, or        */
+	   ((rwlock->rw_owner == NULL) &&	  /* no-one owns it, and */
+	    (rwlock->rw_waiting_writers == 0))) { /* no-one is waiting to own */
+
+	rwlock->rw_waiting_readers++;
+	PZ_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
+	rwlock->rw_waiting_readers--;
+    }
+    rwlock->rw_reader_locks++; 		/* Increment read-lock count */
+
+    PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+    nssRWLock_SetThreadRank(me, rwlock);/* update thread's lock rank */
+#endif
+}
+
+/* Unlock a Read lock held on this RW lock.
+*/
+void
+NSSRWLock_UnlockRead(NSSRWLock *rwlock)
+{
+    PZ_Lock(rwlock->rw_lock);
+
+    PR_ASSERT(rwlock->rw_reader_locks > 0); /* lock must be read locked */
+
+    if ((  rwlock->rw_reader_locks  > 0)  &&	/* caller isn't screwey */
+        (--rwlock->rw_reader_locks == 0)  &&	/* not read locked any more */
+	(  rwlock->rw_owner        == NULL) &&	/* not write locked */
+	(  rwlock->rw_waiting_writers > 0)) {	/* someone's waiting. */
+
+	PZ_NotifyCondVar(rwlock->rw_writer_waitq); /* wake him up. */
+    }
+
+    PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+    /*
+     * update thread's lock rank
+     */
+    nssRWLock_UnsetThreadRank(me, rwlock);
+#endif
+    return;
+}
+
+/*
+** Write-lock the RWLock.
+*/
+void
+NSSRWLock_LockWrite(NSSRWLock *rwlock)
+{
+    PRThread *me = PR_GetCurrentThread();
+
+    PZ_Lock(rwlock->rw_lock);
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+    /*
+     * assert that rank ordering is not violated; the rank of 'rwlock' should
+     * be equal to or greater than the highest rank of all the locks held by
+     * the thread.
+     */
+    PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
+                    (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
+#endif
+    /*
+     * wait if read locked or write locked.
+     */
+    PR_ASSERT(rwlock->rw_reader_locks >= 0);
+    PR_ASSERT(me != NULL);
+
+    UNTIL ( (rwlock->rw_owner == me) ||           /* I own write lock, or */
+	   ((rwlock->rw_owner == NULL) &&	  /* no writer   and */
+	    (rwlock->rw_reader_locks == 0))) {    /* no readers, either. */
+
+        rwlock->rw_waiting_writers++;
+        PZ_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
+        rwlock->rw_waiting_writers--;
+	PR_ASSERT(rwlock->rw_reader_locks >= 0);
+    }
+
+    PR_ASSERT(rwlock->rw_reader_locks == 0);
+    /*
+     * apply write lock
+     */
+    rwlock->rw_owner = me;
+    rwlock->rw_writer_locks++; 		/* Increment write-lock count */
+
+    PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+    /*
+     * update thread's lock rank
+     */
+    nssRWLock_SetThreadRank(me,rwlock);
+#endif
+}
+
+/* Unlock a Read lock held on this RW lock.
+*/
+void
+NSSRWLock_UnlockWrite(NSSRWLock *rwlock)
+{
+    PRThread *me = PR_GetCurrentThread();
+
+    PZ_Lock(rwlock->rw_lock);
+    PR_ASSERT(rwlock->rw_owner == me); /* lock must be write-locked by me.  */
+    PR_ASSERT(rwlock->rw_writer_locks > 0); /* lock must be write locked */
+
+    if (  rwlock->rw_owner        == me  &&	/* I own it, and            */
+          rwlock->rw_writer_locks  > 0   &&	/* I own it, and            */
+        --rwlock->rw_writer_locks == 0) {	/* I'm all done with it     */
+
+	rwlock->rw_owner = NULL;		/* I don't own it any more. */
+
+	/* Give preference to waiting writers. */
+	if (rwlock->rw_waiting_writers > 0) {
+	    if (rwlock->rw_reader_locks == 0)
+		PZ_NotifyCondVar(rwlock->rw_writer_waitq);
+	} else if (rwlock->rw_waiting_readers > 0) {
+	    PZ_NotifyAllCondVar(rwlock->rw_reader_waitq);
+	}
+    }
+    PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+    /*
+     * update thread's lock rank
+     */
+    nssRWLock_UnsetThreadRank(me, rwlock);
+#endif
+    return;
+}
+
+/* This is primarily for debugging, i.e. for inclusion in ASSERT calls. */
+PRBool
+NSSRWLock_HaveWriteLock(NSSRWLock *rwlock) {
+    PRBool ownWriteLock;
+    PRThread *me = PR_GetCurrentThread();
+
+    /* This lock call isn't really necessary.
+    ** If this thread is the owner, that fact cannot change during this call,
+    ** because this thread is in this call.
+    ** If this thread is NOT the owner, the owner could change, but it 
+    ** could not become this thread.  
+    */
+#if UNNECESSARY
+    PZ_Lock(rwlock->rw_lock);	
+#endif
+    ownWriteLock = (PRBool)(me == rwlock->rw_owner);
+#if UNNECESSARY
+    PZ_Unlock(rwlock->rw_lock);
+#endif
+    return ownWriteLock;
+}
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+/*
+ * nssRWLock_SetThreadRank
+ *      Set a thread's lock rank, which is the highest of the ranks of all
+ *      the locks held by the thread. Pointers to the locks are added to a
+ *      per-thread list, which is anchored off a thread-private data key.
+ */
+
+static void
+nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock)
+{
+    thread_rwlock_stack *lock_stack;
+    PRStatus rv;
+
+    /*
+     * allocated thread-private-data for rwlock list, if not already allocated
+     */
+    if (!nss_thread_rwlock_initialized) {
+        /*
+         * allocate tpd, only if not failed already
+         */
+        if (!nss_thread_rwlock_alloc_failed) {
+            if (PR_NewThreadPrivateIndex(&nss_thread_rwlock,
+                                        nssRWLock_ReleaseLockStack)
+                                                == PR_FAILURE) {
+                nss_thread_rwlock_alloc_failed = 1;
+                return;
+            }
+        } else
+            return;
+    }
+    /*
+     * allocate a lock stack
+     */
+    if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL) {
+        lock_stack = (thread_rwlock_stack *)
+                        PR_CALLOC(1 * sizeof(thread_rwlock_stack));
+        if (lock_stack) {
+            rv = PR_SetThreadPrivate(nss_thread_rwlock, lock_stack);
+            if (rv == PR_FAILURE) {
+                PR_DELETE(lock_stack);
+                nss_thread_rwlock_alloc_failed = 1;
+                return;
+            }
+        } else {
+            nss_thread_rwlock_alloc_failed = 1;
+            return;
+        }
+    }
+    /*
+     * add rwlock to lock stack, if limit is not exceeded
+     */
+    if (lock_stack) {
+        if (lock_stack->trs_index < _NSS_RWLOCK_RANK_ORDER_LIMIT)
+            lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;
+    }
+    nss_thread_rwlock_initialized = 1;
+}
+
+static void
+nssRWLock_ReleaseLockStack(void *lock_stack)
+{
+    PR_ASSERT(lock_stack);
+    PR_DELETE(lock_stack);
+}
+
+/*
+ * nssRWLock_GetThreadRank
+ *
+ *      return thread's lock rank. If thread-private-data for the lock
+ *      stack is not allocated, return NSS_RWLOCK_RANK_NONE.
+ */
+
+static PRUint32
+nssRWLock_GetThreadRank(PRThread *me)
+{
+    thread_rwlock_stack *lock_stack;
+
+    if (nss_thread_rwlock_initialized) {
+        if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL)
+            return (NSS_RWLOCK_RANK_NONE);
+        else
+            return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
+
+    } else
+            return (NSS_RWLOCK_RANK_NONE);
+}
+
+/*
+ * nssRWLock_UnsetThreadRank
+ *
+ *      remove the rwlock from the lock stack. Since locks may not be
+ *      unlocked in a FIFO order, the entire lock stack is searched.
+ */
+
+static void
+nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock)
+{
+    thread_rwlock_stack *lock_stack;
+    int new_index = 0, index, done = 0;
+
+    if (!nss_thread_rwlock_initialized)
+        return;
+
+    lock_stack = PR_GetThreadPrivate(nss_thread_rwlock);
+
+    PR_ASSERT(lock_stack != NULL);
+
+    index = lock_stack->trs_index - 1;
+    while (index-- >= 0) {
+        if ((lock_stack->trs_stack[index] == rwlock) && !done)  {
+            /*
+             * reset the slot for rwlock
+             */
+            lock_stack->trs_stack[index] = NULL;
+            done = 1;
+        }
+        /*
+         * search for the lowest-numbered empty slot, above which there are
+         * no non-empty slots
+         */
+        if ((lock_stack->trs_stack[index] != NULL) && !new_index)
+            new_index = index + 1;
+        if (done && new_index)
+            break;
+    }
+    /*
+     * set top of stack to highest numbered empty slot
+     */
+    lock_stack->trs_index = new_index;
+
+}
+
+#endif  /* NSS_RWLOCK_RANK_ORDER_DEBUG */
diff --git a/mozilla/security/nss/lib/util/nssrwlk.h b/mozilla/security/nss/lib/util/nssrwlk.h
new file mode 100644
index 0000000..914bf3a
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssrwlk.h
@@ -0,0 +1,164 @@
+/* ***** 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 ***** */
+
+/*
+** File:		nsrwlock.h
+** Description:	API to basic reader-writer lock functions of NSS.
+**	These are re-entrant reader writer locks; that is,
+**	If I hold the write lock, I can ask for it and get it again.
+**	If I hold the write lock, I can also ask for and get a read lock.
+**      I can then release the locks in any order (read or write).
+**	I must release each lock type as many times as I acquired it.
+**	Otherwise, these are normal reader/writer locks.
+**
+** For deadlock detection, locks should be ranked, and no lock may be aquired
+** while I hold a lock of higher rank number.
+** If you don't want that feature, always use NSS_RWLOCK_RANK_NONE.
+** Lock name is for debugging, and is optional (may be NULL)
+**/
+
+#ifndef nssrwlk_h___
+#define nssrwlk_h___
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "nssrwlkt.h"
+
+#define	NSS_RWLOCK_RANK_NONE	0
+
+/* SEC_BEGIN_PROTOS */
+PR_BEGIN_EXTERN_C
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_New
+** DESCRIPTION:
+**  Returns a pointer to a newly created reader-writer lock object.
+** INPUTS:      Lock rank
+**		Lock name
+** OUTPUTS:     void
+** RETURN:      NSSRWLock*
+**   If the lock cannot be created because of resource constraints, NULL
+**   is returned.
+**  
+***********************************************************************/
+extern NSSRWLock* NSSRWLock_New(PRUint32 lock_rank, const char *lock_name);
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_AtomicCreate
+** DESCRIPTION:
+**  Given the address of a NULL pointer to a NSSRWLock, 
+**  atomically initializes that pointer to a newly created NSSRWLock.
+**  Returns the value placed into that pointer, or NULL.
+**
+** INPUTS:      address of NSRWLock pointer
+**              Lock rank
+**		Lock name
+** OUTPUTS:     NSSRWLock*
+** RETURN:      NSSRWLock*
+**   If the lock cannot be created because of resource constraints, 
+**   the pointer will be left NULL.
+**  
+***********************************************************************/
+extern NSSRWLock *
+nssRWLock_AtomicCreate( NSSRWLock  ** prwlock, 
+			PRUint32      lock_rank, 
+			const char *  lock_name);
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_Destroy
+** DESCRIPTION:
+**  Destroys a given RW lock object.
+** INPUTS:      NSSRWLock *lock - Lock to be freed.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+extern void NSSRWLock_Destroy(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_LockRead
+** DESCRIPTION:
+**  Apply a read lock (non-exclusive) on a RWLock
+** INPUTS:      NSSRWLock *lock - Lock to be read-locked.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+extern void NSSRWLock_LockRead(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_LockWrite
+** DESCRIPTION:
+**  Apply a write lock (exclusive) on a RWLock
+** INPUTS:      NSSRWLock *lock - Lock to write-locked.
+** OUTPUTS:     void
+** RETURN:      None
+***********************************************************************/
+extern void NSSRWLock_LockWrite(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_UnlockRead
+** DESCRIPTION:
+**  Release a Read lock. Unlocking an unlocked lock has undefined results.
+** INPUTS:      NSSRWLock *lock - Lock to unlocked.
+** OUTPUTS:     void
+** RETURN:      void
+***********************************************************************/
+extern void NSSRWLock_UnlockRead(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_UnlockWrite
+** DESCRIPTION:
+**  Release a Write lock. Unlocking an unlocked lock has undefined results.
+** INPUTS:      NSSRWLock *lock - Lock to unlocked.
+** OUTPUTS:     void
+** RETURN:      void
+***********************************************************************/
+extern void NSSRWLock_UnlockWrite(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION:    NSSRWLock_HaveWriteLock
+** DESCRIPTION:
+**  Tells caller whether the current thread holds the write lock, or not.
+** INPUTS:      NSSRWLock *lock - Lock to test.
+** OUTPUTS:     void
+** RETURN:      PRBool	PR_TRUE IFF the current thread holds the write lock.
+***********************************************************************/
+
+extern PRBool NSSRWLock_HaveWriteLock(NSSRWLock *rwlock);
+
+/* SEC_END_PROTOS */
+PR_END_EXTERN_C
+
+#endif /* nsrwlock_h___ */
diff --git a/mozilla/security/nss/lib/util/nssrwlkt.h b/mozilla/security/nss/lib/util/nssrwlkt.h
new file mode 100644
index 0000000..bb98c0e
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssrwlkt.h
@@ -0,0 +1,52 @@
+/* ***** 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 ***** */
+
+#ifndef nssrwlkt_h___
+#define nssrwlkt_h___
+
+#include "utilrename.h"
+#include "nssilock.h"
+/*
+ * NSSRWLock --
+ *
+ *	The reader writer lock, NSSRWLock, is an opaque object to the clients
+ *	of NSS.  All routines operate on a pointer to this opaque entity.
+ */
+
+typedef struct nssRWLockStr NSSRWLock;
+
+
+#endif /* nsrwlock_h___ */
diff --git a/mozilla/security/nss/lib/util/nssutil.h b/mozilla/security/nss/lib/util/nssutil.h
new file mode 100644
index 0000000..aab1473
--- /dev/null
+++ b/mozilla/security/nss/lib/util/nssutil.h
@@ -0,0 +1,61 @@
+/*
+ * NSS utility functions
+ *
+ * ***** 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 Network Security Services.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 ***** */
+
+#ifndef __nssutil_h_
+#define __nssutil_h_
+
+#ifndef RC_INVOKED
+#include "seccomon.h"
+#endif
+
+/*
+ * NSS utilities's major version, minor version, patch level, build number,
+ * and whether this is a beta release.
+ *
+ * The format of the version string should be
+ *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
+ */
+#define NSSUTIL_VERSION  "3.12.6.0 Beta"
+#define NSSUTIL_VMAJOR   3
+#define NSSUTIL_VMINOR   12
+#define NSSUTIL_VPATCH   6
+#define NSSUTIL_VBUILD   0
+#define NSSUTIL_BETA     PR_TRUE
+
+#endif /* __nssutil_h_ */
diff --git a/mozilla/security/nss/lib/util/oidstring.c b/mozilla/security/nss/lib/util/oidstring.c
new file mode 100644
index 0000000..c7ad090
--- /dev/null
+++ b/mozilla/security/nss/lib/util/oidstring.c
@@ -0,0 +1,145 @@
+/* ***** 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 Network Security Services.
+ *
+ * The Initial Developer of the Original Code is Nelson B Bolyard
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 <string.h>
+#include "secitem.h"
+#include "secport.h"
+#include "secerr.h"
+
+/* if to->data is not NULL, and to->len is large enough to hold the result,
+ * then the resultant OID will be copyed into to->data, and to->len will be
+ * changed to show the actual OID length.
+ * Otherwise, memory for the OID will be allocated (from the caller's 
+ * PLArenaPool, if pool is non-NULL) and to->data will receive the address
+ * of the allocated data, and to->len will receive the OID length.
+ * The original value of to->data is not freed when a new buffer is allocated.
+ * 
+ * The input string may begin with "OID." and this still be ignored.
+ * The length of the input string is given in len.  If len == 0, then 
+ * len will be computed as strlen(from), meaning it must be NUL terminated.
+ * It is an error if from == NULL, or if *from == '\0'.
+ */
+
+SECStatus
+SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len)
+{
+    PRUint32 decimal_numbers = 0;
+    PRUint32 result_bytes = 0;
+    SECStatus rv;
+    PRUint8 result[1024];
+
+    static const PRUint32 max_decimal = (0xffffffff / 10);
+    static const char OIDstring[] = {"OID."};
+
+    if (!from || !to) {
+    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    if (!len) {
+    	len = PL_strlen(from);
+    }
+    if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
+    	from += 4; /* skip leading "OID." if present */
+	len  -= 4;
+    }
+    if (!len) {
+bad_data:
+    	PORT_SetError(SEC_ERROR_BAD_DATA);
+	return SECFailure;
+    }
+    do {
+	PRUint32 decimal = 0;
+        while (len > 0 && isdigit(*from)) {
+	    PRUint32 addend = (*from++ - '0');
+	    --len;
+	    if (decimal > max_decimal)  /* overflow */
+		goto bad_data;
+	    decimal = (decimal * 10) + addend;
+	    if (decimal < addend)	/* overflow */
+		goto bad_data;
+	}
+	if (len != 0 && *from != '.') {
+	    goto bad_data;
+	}
+	if (decimal_numbers == 0) {
+	    if (decimal > 2)
+	    	goto bad_data;
+	    result[0] = decimal * 40;
+	    result_bytes = 1;
+	} else if (decimal_numbers == 1) {
+	    if (decimal > 40)
+	    	goto bad_data;
+	    result[0] += decimal;
+	} else {
+	    /* encode the decimal number,  */
+	    PRUint8 * rp;
+	    PRUint32 num_bytes = 0;
+	    PRUint32 tmp = decimal;
+	    while (tmp) {
+	        num_bytes++;
+		tmp >>= 7;
+	    }
+	    if (!num_bytes )
+	    	++num_bytes;  /* use one byte for a zero value */
+	    if (num_bytes + result_bytes > sizeof result)
+	    	goto bad_data;
+	    tmp = num_bytes;
+	    rp = result + result_bytes - 1;
+	    rp[tmp] = (PRUint8)(decimal & 0x7f);
+	    decimal >>= 7;
+	    while (--tmp > 0) {
+		rp[tmp] = (PRUint8)(decimal | 0x80);
+		decimal >>= 7;
+	    }
+	    result_bytes += num_bytes;
+	}
+	++decimal_numbers;
+	if (len > 0) { /* skip trailing '.' */
+	    ++from;
+	    --len;
+	}
+    } while (len > 0);
+    /* now result contains result_bytes of data */
+    if (to->data && to->len >= result_bytes) {
+    	PORT_Memcpy(to->data, result, to->len = result_bytes);
+	rv = SECSuccess;
+    } else {
+    	SECItem result_item = {siBuffer, NULL, 0 };
+	result_item.data = result;
+	result_item.len  = result_bytes;
+	rv = SECITEM_CopyItem(pool, to, &result_item);
+    }
+    return rv;
+}
diff --git a/mozilla/security/nss/lib/util/pkcs11.h b/mozilla/security/nss/lib/util/pkcs11.h
new file mode 100644
index 0000000..68c9c8b
--- /dev/null
+++ b/mozilla/security/nss/lib/util/pkcs11.h
@@ -0,0 +1,290 @@
+/* ***** 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):
+ *   RSA Labs
+ *
+ * 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 ***** */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security In.c Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ *
+ * The latest version of this header can be found at:
+ *    http://www.rsalabs.com/pkcs/pkcs-11/index.html
+ */
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined.  These
+ * macros are described below, and typical definitions for them
+ * are also given.  Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a PKCS #11 library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for PKCS #11 structures should be set.  The PKCS #11
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * In a Win32 environment, this might be done by using the
+ * following preprocessor directive before including pkcs11.h
+ * or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * In a UNIX environment, you're on your own here.  You might
+ * not need to do anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object.  It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * In a Win32 environment, it might be defined by
+ *
+ * #define CK_PTR *
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable PKCS #11 library function definition out of a
+ * return type and a function name.  It should be used in the
+ * following fashion to define the exposed PKCS #11 functions in
+ * a PKCS #11 library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ *   CK_VOID_PTR pReserved
+ * )
+ * {
+ *   ...
+ * }
+ *
+ * For defining a function in a Win32 PKCS #11 .dll, it might be
+ * defined by
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType __declspec(dllexport) name
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable PKCS #11 library function declaration out of a
+ * return type and a function name.  It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ *   CK_VOID_PTR pReserved
+ * );
+ *
+ * For declaring a function in a Win32 PKCS #11 .dll, it might
+ * be defined by
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType __declspec(dllimport) name
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a PKCS #11 API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name.  It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a PKCS #11 API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // PKCS #11 API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * For accessing functions in a Win32 PKCS #11 .dll, in might be
+ * defined by
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType __declspec(dllimport) (* name)
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV.  It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * In a Win32 environment, it might be defined by
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various PKCS #11 types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y)      x##y
+
+
+/* packing defines */
+#include "pkcs11p.h"
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the PKCS #11
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points.  That is, for
+ * each PKCS #11 function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the PKCS #11
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points.  A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's PKCS #11 version
+ * and then a whole slew of function pointers to the routines in
+ * the library.  This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  __PASTE(CK_,name) name;
+  
+struct CK_FUNCTION_LIST {
+
+  CK_VERSION    version;  /* PKCS #11 version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the PKCS #11
+ * function prototypes. */
+#include "pkcs11f.h" 
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+/* unpack */
+#include "pkcs11u.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mozilla/security/nss/lib/util/pkcs11f.h b/mozilla/security/nss/lib/util/pkcs11f.h
new file mode 100644
index 0000000..a6bc91f
--- /dev/null
+++ b/mozilla/security/nss/lib/util/pkcs11f.h
@@ -0,0 +1,937 @@
+/* ***** 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
+ * RSA Security INC.
+ * 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 ***** */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security In.c Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ */
+/* This function contains pretty much everything about all the */
+/* PKCS #11  function prototypes.  Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+
+
+/* General-purpose */
+
+/* C_Initialize initializes the PKCS #11 library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pInitArgs  /* if this is not NULL_PTR, it gets
+                            * cast to CK_C_INITIALIZE_ARGS_PTR
+                            * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * PKCS #11 library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pReserved  /* reserved.  Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about PKCS #11. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_INFO_PTR   pInfo  /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FUNCTION_LIST_PTR_PTR ppFunctionList  /* receives pointer to
+                                            * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_BBOOL       tokenPresent,  /* only slots with tokens? */
+  CK_SLOT_ID_PTR pSlotList,     /* receives array of slot IDs */
+  CK_ULONG_PTR   pulCount       /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID       slotID,  /* the ID of the slot */
+  CK_SLOT_INFO_PTR pInfo    /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID        slotID,  /* ID of the token's slot */
+  CK_TOKEN_INFO_PTR pInfo    /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,          /* ID of token's slot */
+  CK_MECHANISM_TYPE_PTR pMechanismList,  /* gets mech. array */
+  CK_ULONG_PTR          pulCount         /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,  /* ID of the token's slot */
+  CK_MECHANISM_TYPE     type,    /* type of mechanism */
+  CK_MECHANISM_INFO_PTR pInfo    /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+  CK_SLOT_ID         slotID,    /* ID of the token's slot */
+  CK_UTF8CHAR_PTR    pPin,      /* the SO's initial PIN */
+  CK_ULONG           ulPinLen,  /* length in bytes of the PIN */
+  CK_UTF8CHAR_PTR    pLabel     /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pPin,      /* the normal user's PIN */
+  CK_ULONG          ulPinLen   /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pOldPin,   /* the old PIN */
+  CK_ULONG          ulOldLen,  /* length of the old PIN */
+  CK_UTF8CHAR_PTR   pNewPin,   /* the new PIN */
+  CK_ULONG          ulNewLen   /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,        /* the slot's ID */
+  CK_FLAGS              flags,         /* from CK_SESSION_INFO */
+  CK_VOID_PTR           pApplication,  /* passed to callback */
+  CK_NOTIFY             Notify,        /* callback function */
+  CK_SESSION_HANDLE_PTR phSession      /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID     slotID  /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE   hSession,  /* the session's handle */
+  CK_SESSION_INFO_PTR pInfo      /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,             /* session's handle */
+  CK_BYTE_PTR       pOperationState,      /* gets state */
+  CK_ULONG_PTR      pulOperationStateLen  /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR      pOperationState,      /* holds state */
+  CK_ULONG         ulOperationStateLen,  /* holds state length */
+  CK_OBJECT_HANDLE hEncryptionKey,       /* en/decryption key */
+  CK_OBJECT_HANDLE hAuthenticationKey    /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_USER_TYPE      userType,  /* the user type */
+  CK_UTF8CHAR_PTR   pPin,      /* the user's PIN */
+  CK_ULONG          ulPinLen   /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,   /* the object's template */
+  CK_ULONG          ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phObject  /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_OBJECT_HANDLE     hObject,     /* the object's handle */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new object */
+  CK_ULONG             ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phNewObject  /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject    /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,   /* the object's handle */
+  CK_ULONG_PTR      pulSize    /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs; gets vals */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs and values */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* attribute values to match */
+  CK_ULONG          ulCount     /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE    hSession,          /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject,          /* gets obj. handles */
+ CK_ULONG             ulMaxObjectCount,  /* max handles to get */
+ CK_ULONG_PTR         pulObjectCount     /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the encryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pData,               /* the plaintext data */
+  CK_ULONG          ulDataLen,           /* bytes of plaintext */
+  CK_BYTE_PTR       pEncryptedData,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedDataLen  /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pPart,              /* the plaintext data */
+  CK_ULONG          ulPartLen,          /* plaintext data len */
+  CK_BYTE_PTR       pEncryptedPart,     /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,                /* session handle */
+  CK_BYTE_PTR       pLastEncryptedPart,      /* last c-text */
+  CK_ULONG_PTR      pulLastEncryptedPartLen  /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the decryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pEncryptedData,     /* ciphertext */
+  CK_ULONG          ulEncryptedDataLen, /* ciphertext length */
+  CK_BYTE_PTR       pData,              /* gets plaintext */
+  CK_ULONG_PTR      pulDataLen          /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* encrypted data */
+  CK_ULONG          ulEncryptedPartLen,  /* input length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pLastPart,      /* gets plaintext */
+  CK_ULONG_PTR      pulLastPartLen  /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism  /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pData,        /* data to be digested */
+  CK_ULONG          ulDataLen,    /* bytes of data to digest */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* data to be digested */
+  CK_ULONG          ulPartLen  /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hKey       /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* the data to sign */
+  CK_ULONG          ulPartLen  /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation, 
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism, /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey        /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ *  cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */ 
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation, 
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pData,          /* signed data */
+  CK_ULONG          ulDataLen,      /* length of signed data */
+  CK_BYTE_PTR       pSignature,     /* signature */
+  CK_ULONG          ulSignatureLen  /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* signed data */
+  CK_ULONG          ulPartLen  /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pSignature,     /* signature to verify */
+  CK_ULONG          ulSignatureLen  /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* signature to verify */
+  CK_ULONG          ulSignatureLen,  /* signature length */
+  CK_BYTE_PTR       pData,           /* gets signed data */
+  CK_ULONG_PTR      pulDataLen       /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_MECHANISM_PTR     pMechanism,  /* key generation mech. */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new key */
+  CK_ULONG             ulCount,     /* # of attrs in template */
+  CK_OBJECT_HANDLE_PTR phKey        /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair, 
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,                    /* session
+                                                     * handle */
+  CK_MECHANISM_PTR     pMechanism,                  /* key-gen
+                                                     * mech. */
+  CK_ATTRIBUTE_PTR     pPublicKeyTemplate,          /* template
+                                                     * for pub.
+                                                     * key */
+  CK_ULONG             ulPublicKeyAttributeCount,   /* # pub.
+                                                     * attrs. */
+  CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,         /* template
+                                                     * for priv.
+                                                     * key */
+  CK_ULONG             ulPrivateKeyAttributeCount,  /* # priv.
+                                                     * attrs. */
+  CK_OBJECT_HANDLE_PTR phPublicKey,                 /* gets pub.
+                                                     * key
+                                                     * handle */
+  CK_OBJECT_HANDLE_PTR phPrivateKey                 /* gets
+                                                     * priv. key
+                                                     * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,      /* the wrapping mechanism */
+  CK_OBJECT_HANDLE  hWrappingKey,    /* wrapping key */
+  CK_OBJECT_HANDLE  hKey,            /* key to be wrapped */
+  CK_BYTE_PTR       pWrappedKey,     /* gets wrapped key */
+  CK_ULONG_PTR      pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* unwrapping mech. */
+  CK_OBJECT_HANDLE     hUnwrappingKey,    /* unwrapping key */
+  CK_BYTE_PTR          pWrappedKey,       /* the wrapped key */
+  CK_ULONG             ulWrappedKeyLen,   /* wrapped key len */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* key deriv. mech. */
+  CK_OBJECT_HANDLE     hBaseKey,          /* base key */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pSeed,     /* the seed material */
+  CK_ULONG          ulSeedLen  /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_BYTE_PTR       RandomData,  /* receives the random data */
+  CK_ULONG          ulRandomLen  /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for PKCS #11 Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FLAGS flags,        /* blocking/nonblocking flag */
+  CK_SLOT_ID_PTR pSlot,  /* location that receives the slot ID */
+  CK_VOID_PTR pRserved   /* reserved.  Should be NULL_PTR */
+);
+#endif
diff --git a/mozilla/security/nss/lib/util/pkcs11n.h b/mozilla/security/nss/lib/util/pkcs11n.h
new file mode 100644
index 0000000..c4d1564
--- /dev/null
+++ b/mozilla/security/nss/lib/util/pkcs11n.h
@@ -0,0 +1,289 @@
+/* ***** 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):
+ *   Dr Stephen Henson <stephen.henson@gemplus.com>
+ *
+ * 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 ***** */
+
+#ifndef _PKCS11N_H_
+#define _PKCS11N_H_
+
+#ifdef DEBUG
+static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.19 $ $Date: 2009/03/25 05:21:03 $";
+#endif /* DEBUG */
+
+/*
+ * pkcs11n.h
+ *
+ * This file contains the NSS-specific type definitions for Cryptoki
+ * (PKCS#11).
+ */
+
+/*
+ * NSSCK_VENDOR_NSS
+ *
+ * Cryptoki reserves the high half of all the number spaces for
+ * vendor-defined use.  I'd like to keep all of our NSS-
+ * specific values together, but not in the oh-so-obvious
+ * 0x80000001, 0x80000002, etc. area.  So I've picked an offset,
+ * and constructed values for the beginnings of our spaces.
+ *
+ * Note that some "historical" Netscape values don't fall within
+ * this range.
+ */
+#define NSSCK_VENDOR_NSS 0x4E534350 /* NSCP */
+
+/*
+ * NSS-defined object classes
+ * 
+ */
+#define CKO_NSS (CKO_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKO_NSS_CRL                (CKO_NSS + 1)
+#define CKO_NSS_SMIME              (CKO_NSS + 2)
+#define CKO_NSS_TRUST              (CKO_NSS + 3)
+#define CKO_NSS_BUILTIN_ROOT_LIST  (CKO_NSS + 4)
+#define CKO_NSS_NEWSLOT            (CKO_NSS + 5)
+#define CKO_NSS_DELSLOT            (CKO_NSS + 6)
+
+
+/*
+ * NSS-defined key types
+ *
+ */
+#define CKK_NSS (CKK_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKK_NSS_PKCS8              (CKK_NSS + 1)
+/*
+ * NSS-defined certificate types
+ *
+ */
+#define CKC_NSS (CKC_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+/* FAKE PKCS #11 defines */
+#define CKA_DIGEST            0x81000000L
+#define CKA_FLAGS_ONLY        0 /* CKA_CLASS */
+
+/*
+ * NSS-defined object attributes
+ *
+ */
+#define CKA_NSS (CKA_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKA_NSS_URL                (CKA_NSS +  1)
+#define CKA_NSS_EMAIL              (CKA_NSS +  2)
+#define CKA_NSS_SMIME_INFO         (CKA_NSS +  3)
+#define CKA_NSS_SMIME_TIMESTAMP    (CKA_NSS +  4)
+#define CKA_NSS_PKCS8_SALT         (CKA_NSS +  5)
+#define CKA_NSS_PASSWORD_CHECK     (CKA_NSS +  6)
+#define CKA_NSS_EXPIRES            (CKA_NSS +  7)
+#define CKA_NSS_KRL                (CKA_NSS +  8)
+
+#define CKA_NSS_PQG_COUNTER        (CKA_NSS +  20)
+#define CKA_NSS_PQG_SEED           (CKA_NSS +  21)
+#define CKA_NSS_PQG_H              (CKA_NSS +  22)
+#define CKA_NSS_PQG_SEED_BITS      (CKA_NSS +  23)
+#define CKA_NSS_MODULE_SPEC        (CKA_NSS +  24)
+#define CKA_NSS_OVERRIDE_EXTENSIONS (CKA_NSS +  25)
+
+/*
+ * Trust attributes:
+ *
+ * If trust goes standard, these probably will too.  So I'll
+ * put them all in one place.
+ */
+
+#define CKA_TRUST (CKA_NSS + 0x2000)
+
+/* "Usage" key information */
+#define CKA_TRUST_DIGITAL_SIGNATURE     (CKA_TRUST +  1)
+#define CKA_TRUST_NON_REPUDIATION       (CKA_TRUST +  2)
+#define CKA_TRUST_KEY_ENCIPHERMENT      (CKA_TRUST +  3)
+#define CKA_TRUST_DATA_ENCIPHERMENT     (CKA_TRUST +  4)
+#define CKA_TRUST_KEY_AGREEMENT         (CKA_TRUST +  5)
+#define CKA_TRUST_KEY_CERT_SIGN         (CKA_TRUST +  6)
+#define CKA_TRUST_CRL_SIGN              (CKA_TRUST +  7)
+
+/* "Purpose" trust information */
+#define CKA_TRUST_SERVER_AUTH           (CKA_TRUST +  8)
+#define CKA_TRUST_CLIENT_AUTH           (CKA_TRUST +  9)
+#define CKA_TRUST_CODE_SIGNING          (CKA_TRUST + 10)
+#define CKA_TRUST_EMAIL_PROTECTION      (CKA_TRUST + 11)
+#define CKA_TRUST_IPSEC_END_SYSTEM      (CKA_TRUST + 12)
+#define CKA_TRUST_IPSEC_TUNNEL          (CKA_TRUST + 13)
+#define CKA_TRUST_IPSEC_USER            (CKA_TRUST + 14)
+#define CKA_TRUST_TIME_STAMPING         (CKA_TRUST + 15)
+#define CKA_TRUST_STEP_UP_APPROVED      (CKA_TRUST + 16)
+
+#define CKA_CERT_SHA1_HASH	        (CKA_TRUST + 100)
+#define CKA_CERT_MD5_HASH		(CKA_TRUST + 101)
+
+/* NSS trust stuff */
+/* XXX fgmr new ones here-- step-up, etc. */
+
+/* HISTORICAL: define used to pass in the database key for DSA private keys */
+#define CKA_NETSCAPE_DB                 0xD5A0DB00L
+#define CKA_NETSCAPE_TRUST              0x80000001L
+
+/* FAKE PKCS #11 defines */
+#define CKM_FAKE_RANDOM       0x80000efeUL
+#define CKM_INVALID_MECHANISM 0xffffffffUL
+
+/*
+ * NSS-defined crypto mechanisms
+ *
+ */
+#define CKM_NSS (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKM_NSS_AES_KEY_WRAP      (CKM_NSS + 1)
+#define CKM_NSS_AES_KEY_WRAP_PAD  (CKM_NSS + 2)
+
+/*
+ * HISTORICAL:
+ * Do not attempt to use these. They are only used by NETSCAPE's internal
+ * PKCS #11 interface. Most of these are place holders for other mechanism
+ * and will change in the future.
+ */
+#define CKM_NETSCAPE_PBE_SHA1_DES_CBC           0x80000002UL
+#define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC    0x80000003UL
+#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC    0x80000004UL
+#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC   0x80000005UL
+#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4        0x80000006UL
+#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4       0x80000007UL
+#define CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC   0x80000008UL
+#define CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN      0x80000009UL
+#define CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN       0x8000000aUL
+#define CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN       0x8000000bUL
+
+#define CKM_TLS_PRF_GENERAL                     0x80000373UL
+
+/*
+ * NSS-defined return values
+ *
+ */
+#define CKR_NSS (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKR_NSS_CERTDB_FAILED      (CKR_NSS + 1)
+#define CKR_NSS_KEYDB_FAILED       (CKR_NSS + 2)
+
+/*
+ * Trust info
+ *
+ * This isn't part of the Cryptoki standard (yet), so I'm putting
+ * all the definitions here.  Some of this would move to nssckt.h
+ * if trust info were made part of the standard.  In view of this
+ * possibility, I'm putting my (NSS) values in the NSS
+ * vendor space, like everything else.
+ */
+
+typedef CK_ULONG          CK_TRUST;
+
+/* The following trust types are defined: */
+#define CKT_VENDOR_DEFINED     0x80000000
+
+#define CKT_NSS (CKT_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+/* If trust goes standard, these'll probably drop out of vendor space. */
+#define CKT_NSS_TRUSTED            (CKT_NSS + 1)
+#define CKT_NSS_TRUSTED_DELEGATOR  (CKT_NSS + 2)
+#define CKT_NSS_UNTRUSTED          (CKT_NSS + 3)
+#define CKT_NSS_MUST_VERIFY        (CKT_NSS + 4)
+#define CKT_NSS_TRUST_UNKNOWN      (CKT_NSS + 5) /* default */
+
+/* 
+ * These may well remain NSS-specific; I'm only using them
+ * to cache resolution data.
+ */
+#define CKT_NSS_VALID              (CKT_NSS + 10)
+#define CKT_NSS_VALID_DELEGATOR    (CKT_NSS + 11)
+
+/* don't leave old programs in a lurch just yet, give them the old NETSCAPE
+ * synonym */
+#define CKO_NETSCAPE_CRL                CKO_NSS_CRL
+#define CKO_NETSCAPE_SMIME              CKO_NSS_SMIME
+#define CKO_NETSCAPE_TRUST              CKO_NSS_TRUST
+#define CKO_NETSCAPE_BUILTIN_ROOT_LIST  CKO_NSS_BUILTIN_ROOT_LIST
+#define CKO_NETSCAPE_NEWSLOT            CKO_NSS_NEWSLOT
+#define CKO_NETSCAPE_DELSLOT            CKO_NSS_DELSLOT
+#define CKK_NETSCAPE_PKCS8              CKK_NSS_PKCS8
+#define CKA_NETSCAPE_URL                CKA_NSS_URL
+#define CKA_NETSCAPE_EMAIL              CKA_NSS_EMAIL
+#define CKA_NETSCAPE_SMIME_INFO         CKA_NSS_SMIME_INFO
+#define CKA_NETSCAPE_SMIME_TIMESTAMP    CKA_NSS_SMIME_TIMESTAMP
+#define CKA_NETSCAPE_PKCS8_SALT         CKA_NSS_PKCS8_SALT
+#define CKA_NETSCAPE_PASSWORD_CHECK     CKA_NSS_PASSWORD_CHECK
+#define CKA_NETSCAPE_EXPIRES            CKA_NSS_EXPIRES
+#define CKA_NETSCAPE_KRL                CKA_NSS_KRL
+#define CKA_NETSCAPE_PQG_COUNTER        CKA_NSS_PQG_COUNTER
+#define CKA_NETSCAPE_PQG_SEED           CKA_NSS_PQG_SEED
+#define CKA_NETSCAPE_PQG_H              CKA_NSS_PQG_H
+#define CKA_NETSCAPE_PQG_SEED_BITS      CKA_NSS_PQG_SEED_BITS
+#define CKA_NETSCAPE_MODULE_SPEC        CKA_NSS_MODULE_SPEC
+#define CKM_NETSCAPE_AES_KEY_WRAP	CKM_NSS_AES_KEY_WRAP
+#define CKM_NETSCAPE_AES_KEY_WRAP_PAD	CKM_NSS_AES_KEY_WRAP_PAD
+#define CKR_NETSCAPE_CERTDB_FAILED      CKR_NSS_CERTDB_FAILED
+#define CKR_NETSCAPE_KEYDB_FAILED       CKR_NSS_KEYDB_FAILED
+#define CKT_NETSCAPE_TRUSTED            CKT_NSS_TRUSTED
+#define CKT_NETSCAPE_TRUSTED_DELEGATOR  CKT_NSS_TRUSTED_DELEGATOR
+#define CKT_NETSCAPE_UNTRUSTED          CKT_NSS_UNTRUSTED
+#define CKT_NETSCAPE_MUST_VERIFY        CKT_NSS_MUST_VERIFY
+#define CKT_NETSCAPE_TRUST_UNKNOWN      CKT_NSS_TRUST_UNKNOWN
+#define CKT_NETSCAPE_VALID              CKT_NSS_VALID
+#define CKT_NETSCAPE_VALID_DELEGATOR    CKT_NSS_VALID_DELEGATOR
+
+/*
+ * These are not really PKCS #11 values specifically. They are the 'loadable'
+ * module spec NSS uses. The are available for others to use as well, but not
+ * part of the formal PKCS #11 spec.
+ *
+ * The function 'FIND' returns an array of PKCS #11 initialization strings
+ * The function 'ADD' takes a PKCS #11 initialization string and stores it.
+ * The function 'DEL' takes a 'name= library=' value and deletes the associated
+ *  string.
+ * The function 'RELEASE' frees the array returned by 'FIND'
+ */
+#define SECMOD_MODULE_DB_FUNCTION_FIND  0
+#define SECMOD_MODULE_DB_FUNCTION_ADD   1
+#define SECMOD_MODULE_DB_FUNCTION_DEL   2
+#define SECMOD_MODULE_DB_FUNCTION_RELEASE 3 
+typedef char ** (PR_CALLBACK *SECMODModuleDBFunc)(unsigned long function,
+                                        char *parameters, void *moduleSpec);
+
+/* softoken slot ID's */
+#define SFTK_MIN_USER_SLOT_ID 4
+#define SFTK_MAX_USER_SLOT_ID 100
+#define SFTK_MIN_FIPS_USER_SLOT_ID 101
+#define SFTK_MAX_FIPS_USER_SLOT_ID 127
+
+
+#endif /* _PKCS11N_H_ */
diff --git a/mozilla/security/nss/lib/util/pkcs11p.h b/mozilla/security/nss/lib/util/pkcs11p.h
new file mode 100644
index 0000000..f1ea258
--- /dev/null
+++ b/mozilla/security/nss/lib/util/pkcs11p.h
@@ -0,0 +1,54 @@
+/* ***** 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 ***** */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security Inc. Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ */
+/* these data types are platform/implementation dependent. */
+/*
+ * Packing was removed from the shipped RSA header files, even
+ * though it's still needed. put in a central file to help merging..
+ */
+
+#if defined(_WIN32)
+#ifdef _MSC_VER
+#pragma warning(disable:4103)
+#endif
+#pragma pack(push, cryptoki, 1)
+#endif
+
diff --git a/mozilla/security/nss/lib/util/pkcs11t.h b/mozilla/security/nss/lib/util/pkcs11t.h
new file mode 100644
index 0000000..044ec51
--- /dev/null
+++ b/mozilla/security/nss/lib/util/pkcs11t.h
@@ -0,0 +1,1785 @@
+/* ***** 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
+ * RSA Security, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#include "prtypes.h"
+
+#define CK_PTR *
+#define CK_NULL_PTR 0
+#define CK_CALLBACK_FUNCTION(rtype,func) rtype (PR_CALLBACK * func)
+#define CK_DECLARE_FUNCTION(rtype,func) extern rtype func
+#define CK_DECLARE_FUNCTION_POINTER(rtype,func) rtype (PR_CALLBACK * func)
+
+#define CK_INVALID_SESSION    0
+
+/* an unsigned 8-bit value */
+typedef unsigned char     CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE           CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE           CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE           CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+/* CK_LONG is new for v2.0 */
+typedef long int          CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG          CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE    0
+
+
+typedef CK_BYTE     CK_PTR   CK_BYTE_PTR;
+typedef CK_CHAR     CK_PTR   CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR   CK_UTF8CHAR_PTR;
+typedef CK_ULONG    CK_PTR   CK_ULONG_PTR;
+typedef void        CK_PTR   CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+/* pack */
+#include "pkcs11p.h"
+
+typedef struct CK_VERSION {
+  CK_BYTE       major;  /* integer portion of version number */
+  CK_BYTE       minor;  /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+  /* manufacturerID and libraryDecription have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_VERSION    cryptokiVersion;     /* PKCS #11 interface ver */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_FLAGS      flags;               /* must be zero */
+
+  /* libraryDescription and libraryVersion are new for v2.0 */
+  CK_UTF8CHAR   libraryDescription[32];  /* blank padded */
+  CK_VERSION    libraryVersion;          /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR    CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * PKCS #11 provides to an application */
+/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER       0
+
+
+typedef CK_ULONG          CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+  /* slotDescription and manufacturerID have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_UTF8CHAR   slotDescription[64];  /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];   /* blank padded */
+  CK_FLAGS      flags;
+
+  /* hardwareVersion and firmwareVersion are new for v2.0 */
+  CK_VERSION    hardwareVersion;  /* version of hardware */
+  CK_VERSION    firmwareVersion;  /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag              Mask        Meaning
+ */
+#define CKF_TOKEN_PRESENT     0x00000001  /* a token is there */
+#define CKF_REMOVABLE_DEVICE  0x00000002  /* removable devices*/
+#define CKF_HW_SLOT           0x00000004  /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+  /* label, manufacturerID, and model have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_UTF8CHAR   label[32];           /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_UTF8CHAR   model[16];           /* blank padded */
+  CK_CHAR       serialNumber[16];    /* blank padded */
+  CK_FLAGS      flags;               /* see below */
+
+  /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
+   * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
+   * changed from CK_USHORT to CK_ULONG for v2.0 */
+  CK_ULONG      ulMaxSessionCount;     /* max open sessions */
+  CK_ULONG      ulSessionCount;        /* sess. now open */
+  CK_ULONG      ulMaxRwSessionCount;   /* max R/W sessions */
+  CK_ULONG      ulRwSessionCount;      /* R/W sess. now open */
+  CK_ULONG      ulMaxPinLen;           /* in bytes */
+  CK_ULONG      ulMinPinLen;           /* in bytes */
+  CK_ULONG      ulTotalPublicMemory;   /* in bytes */
+  CK_ULONG      ulFreePublicMemory;    /* in bytes */
+  CK_ULONG      ulTotalPrivateMemory;  /* in bytes */
+  CK_ULONG      ulFreePrivateMemory;   /* in bytes */
+
+  /* hardwareVersion, firmwareVersion, and time are new for
+   * v2.0 */
+  CK_VERSION    hardwareVersion;       /* version of hardware */
+  CK_VERSION    firmwareVersion;       /* version of firmware */
+  CK_CHAR       utcTime[16];           /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ *      Bit Flag                    Mask        Meaning
+ */
+#define CKF_RNG                     0x00000001  /* has random #
+                                                 * generator */
+#define CKF_WRITE_PROTECTED         0x00000002  /* token is
+                                                 * write-
+                                                 * protected */
+#define CKF_LOGIN_REQUIRED          0x00000004  /* user must
+                                                 * login */
+#define CKF_USER_PIN_INITIALIZED    0x00000008  /* normal user's
+                                                 * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0.  If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED  0x00000020
+
+/* CKF_CLOCK_ON_TOKEN is new for v2.0.  If it is set, that means
+ * that the token has some sort of clock.  The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN          0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0.  If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the PKCS #11 library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0.  If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS  0x00000200
+
+/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED       0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is
+ * true, the token supports secondary authentication for
+ * private key objects. This flag is deprecated in v2.11 and
+   onwards. */
+#define CKF_SECONDARY_AUTHENTICATION  0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW       0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY       0x00020000
+
+/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible. */
+#define CKF_USER_PIN_LOCKED          0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED   0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW         0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY         0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED            0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED     0x00800000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a PKCS #11-assigned value that
+ * identifies a session */
+typedef CK_ULONG          CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of PKCS #11 users */
+/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO    0
+/* Normal user */
+#define CKU_USER  1
+/* Context specific (added in v2.20) */
+#define CKU_CONTEXT_SPECIFIC   2
+
+/* CK_STATE enumerates the session states */
+/* CK_STATE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_STATE;
+#define CKS_RO_PUBLIC_SESSION  0
+#define CKS_RO_USER_FUNCTIONS  1
+#define CKS_RW_PUBLIC_SESSION  2
+#define CKS_RW_USER_FUNCTIONS  3
+#define CKS_RW_SO_FUNCTIONS    4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+  CK_SLOT_ID    slotID;
+  CK_STATE      state;
+  CK_FLAGS      flags;          /* see below */
+
+  /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG      ulDeviceError;  /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ *      Bit Flag                Mask        Meaning
+ */
+#define CKF_RW_SESSION          0x00000002  /* session is r/w */
+#define CKF_SERIAL_SESSION      0x00000004  /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object  */
+typedef CK_ULONG          CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that PKCS #11 recognizes.  It is defined
+ * as follows: */
+/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+/* CKO_HW_FEATURE is new for v2.10 */
+/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
+/* CKO_MECHANISM is new for v2.20 */
+#define CKO_DATA              0x00000000
+#define CKO_CERTIFICATE       0x00000001
+#define CKO_PUBLIC_KEY        0x00000002
+#define CKO_PRIVATE_KEY       0x00000003
+#define CKO_SECRET_KEY        0x00000004
+#define CKO_HW_FEATURE        0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_MECHANISM         0x00000007
+#define CKO_VENDOR_DEFINED    0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG          CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+/* CKH_USER_INTERFACE is new for v2.20 */
+#define CKH_MONOTONIC_COUNTER  0x00000001
+#define CKH_CLOCK           0x00000002
+#define CKH_USER_INTERFACE  0x00000003
+#define CKH_VENDOR_DEFINED  0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG          CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA             0x00000000
+#define CKK_DSA             0x00000001
+#define CKK_DH              0x00000002
+
+/* CKK_ECDSA and CKK_KEA are new for v2.0 */
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA           0x00000003
+#define CKK_EC              0x00000003
+#define CKK_X9_42_DH        0x00000004
+#define CKK_KEA             0x00000005
+
+#define CKK_GENERIC_SECRET  0x00000010
+#define CKK_RC2             0x00000011
+#define CKK_RC4             0x00000012
+#define CKK_DES             0x00000013
+#define CKK_DES2            0x00000014
+#define CKK_DES3            0x00000015
+
+/* all these key types are new for v2.0 */
+#define CKK_CAST            0x00000016
+#define CKK_CAST3           0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5           0x00000018
+#define CKK_CAST128         0x00000018
+#define CKK_RC5             0x00000019
+#define CKK_IDEA            0x0000001A
+#define CKK_SKIPJACK        0x0000001B
+#define CKK_BATON           0x0000001C
+#define CKK_JUNIPER         0x0000001D
+#define CKK_CDMF            0x0000001E
+#define CKK_AES             0x0000001F
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKK_BLOWFISH        0x00000020
+#define CKK_TWOFISH         0x00000021
+
+/* Camellia is proposed for v2.20 Amendment 3 */
+#define CKK_CAMELLIA        0x00000025
+
+#define CKK_SEED	    0x00000026
+
+#define CKK_VENDOR_DEFINED  0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG          CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+/* CKC_X_509_ATTR_CERT is new for v2.10 */
+/* CKC_WTLS is new for v2.20 */
+#define CKC_X_509           0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_WTLS            0x00000002
+#define CKC_VENDOR_DEFINED  0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+   consists of an array of values. */
+#define CKF_ARRAY_ATTRIBUTE    0x40000000
+
+/* The following attribute types are defined: */
+#define CKA_CLASS              0x00000000
+#define CKA_TOKEN              0x00000001
+#define CKA_PRIVATE            0x00000002
+#define CKA_LABEL              0x00000003
+#define CKA_APPLICATION        0x00000010
+#define CKA_VALUE              0x00000011
+
+/* CKA_OBJECT_ID is new for v2.10 */
+#define CKA_OBJECT_ID          0x00000012
+
+#define CKA_CERTIFICATE_TYPE   0x00000080
+#define CKA_ISSUER             0x00000081
+#define CKA_SERIAL_NUMBER      0x00000082
+
+/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new
+ * for v2.10 */
+#define CKA_AC_ISSUER          0x00000083
+#define CKA_OWNER              0x00000084
+#define CKA_ATTR_TYPES         0x00000085
+
+/* CKA_TRUSTED is new for v2.11 */
+#define CKA_TRUSTED            0x00000086
+
+/* CKA_CERTIFICATE_CATEGORY ...
+ * CKA_CHECK_VALUE are new for v2.20 */
+#define CKA_CERTIFICATE_CATEGORY        0x00000087
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN   0x00000088
+#define CKA_URL                         0x00000089
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008A
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008B
+#define CKA_CHECK_VALUE                 0x00000090
+
+#define CKA_KEY_TYPE           0x00000100
+#define CKA_SUBJECT            0x00000101
+#define CKA_ID                 0x00000102
+#define CKA_SENSITIVE          0x00000103
+#define CKA_ENCRYPT            0x00000104
+#define CKA_DECRYPT            0x00000105
+#define CKA_WRAP               0x00000106
+#define CKA_UNWRAP             0x00000107
+#define CKA_SIGN               0x00000108
+#define CKA_SIGN_RECOVER       0x00000109
+#define CKA_VERIFY             0x0000010A
+#define CKA_VERIFY_RECOVER     0x0000010B
+#define CKA_DERIVE             0x0000010C
+#define CKA_START_DATE         0x00000110
+#define CKA_END_DATE           0x00000111
+#define CKA_MODULUS            0x00000120
+#define CKA_MODULUS_BITS       0x00000121
+#define CKA_PUBLIC_EXPONENT    0x00000122
+#define CKA_PRIVATE_EXPONENT   0x00000123
+#define CKA_PRIME_1            0x00000124
+#define CKA_PRIME_2            0x00000125
+#define CKA_EXPONENT_1         0x00000126
+#define CKA_EXPONENT_2         0x00000127
+#define CKA_COEFFICIENT        0x00000128
+#define CKA_PRIME              0x00000130
+#define CKA_SUBPRIME           0x00000131
+#define CKA_BASE               0x00000132
+
+/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
+#define CKA_PRIME_BITS         0x00000133
+#define CKA_SUBPRIME_BITS      0x00000134
+#define CKA_SUB_PRIME_BITS     CKA_SUBPRIME_BITS
+/* (To retain backwards-compatibility) */
+
+#define CKA_VALUE_BITS         0x00000160
+#define CKA_VALUE_LEN          0x00000161
+
+/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
+ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
+ * and CKA_EC_POINT are new for v2.0 */
+#define CKA_EXTRACTABLE        0x00000162
+#define CKA_LOCAL              0x00000163
+#define CKA_NEVER_EXTRACTABLE  0x00000164
+#define CKA_ALWAYS_SENSITIVE   0x00000165
+
+/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
+#define CKA_KEY_GEN_MECHANISM  0x00000166
+
+#define CKA_MODIFIABLE         0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS       0x00000180
+#define CKA_EC_PARAMS          0x00000180
+
+#define CKA_EC_POINT           0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+ * are new for v2.10. Deprecated in v2.11 and onwards. */
+#define CKA_SECONDARY_AUTH     0x00000200
+#define CKA_AUTH_PIN_FLAGS     0x00000201
+
+/* CKA_ALWAYS_AUTHENTICATE ...
+ * CKA_UNWRAP_TEMPLATE are new for v2.20 */
+#define CKA_ALWAYS_AUTHENTICATE  0x00000202
+
+#define CKA_WRAP_WITH_TRUSTED    0x00000210
+#define CKA_WRAP_TEMPLATE        (CKF_ARRAY_ATTRIBUTE|0x00000211)
+#define CKA_UNWRAP_TEMPLATE      (CKF_ARRAY_ATTRIBUTE|0x00000212)
+
+/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_HW_FEATURE_TYPE    0x00000300
+#define CKA_RESET_ON_INIT      0x00000301
+#define CKA_HAS_RESET          0x00000302
+
+/* The following attributes are new for v2.20 */
+#define CKA_PIXEL_X                     0x00000400
+#define CKA_PIXEL_Y                     0x00000401
+#define CKA_RESOLUTION                  0x00000402
+#define CKA_CHAR_ROWS                   0x00000403
+#define CKA_CHAR_COLUMNS                0x00000404
+#define CKA_COLOR                       0x00000405
+#define CKA_BITS_PER_PIXEL              0x00000406
+#define CKA_CHAR_SETS                   0x00000480
+#define CKA_ENCODING_METHODS            0x00000481
+#define CKA_MIME_TYPES                  0x00000482
+#define CKA_MECHANISM_TYPE              0x00000500
+#define CKA_REQUIRED_CMS_ATTRIBUTES     0x00000501
+#define CKA_DEFAULT_CMS_ATTRIBUTES      0x00000502
+#define CKA_SUPPORTED_CMS_ATTRIBUTES    0x00000503
+#define CKA_ALLOWED_MECHANISMS          (CKF_ARRAY_ATTRIBUTE|0x00000600)
+
+#define CKA_VENDOR_DEFINED     0x80000000
+
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+  CK_ATTRIBUTE_TYPE type;
+  CK_VOID_PTR       pValue;
+
+  /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
+  CK_ULONG          ulValueLen;  /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+  CK_CHAR       year[4];   /* the year ("1900" - "9999") */
+  CK_CHAR       month[2];  /* the month ("01" - "12") */
+  CK_CHAR       day[2];    /* the day   ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN      0x00000000
+#define CKM_RSA_PKCS                   0x00000001
+#define CKM_RSA_9796                   0x00000002
+#define CKM_RSA_X_509                  0x00000003
+
+/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
+ * are new for v2.0.  They are mechanisms which hash and sign */
+#define CKM_MD2_RSA_PKCS               0x00000004
+#define CKM_MD5_RSA_PKCS               0x00000005
+#define CKM_SHA1_RSA_PKCS              0x00000006
+
+/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
+ * CKM_RSA_PKCS_OAEP are new for v2.10 */
+#define CKM_RIPEMD128_RSA_PKCS         0x00000007
+#define CKM_RIPEMD160_RSA_PKCS         0x00000008
+#define CKM_RSA_PKCS_OAEP              0x00000009
+
+/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
+ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
+#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000A
+#define CKM_RSA_X9_31                  0x0000000B
+#define CKM_SHA1_RSA_X9_31             0x0000000C
+#define CKM_RSA_PKCS_PSS               0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS          0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN           0x00000010
+#define CKM_DSA                        0x00000011
+#define CKM_DSA_SHA1                   0x00000012
+#define CKM_DH_PKCS_KEY_PAIR_GEN       0x00000020
+#define CKM_DH_PKCS_DERIVE             0x00000021
+
+/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
+ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
+ * v2.11 */
+#define CKM_X9_42_DH_KEY_PAIR_GEN      0x00000030
+#define CKM_X9_42_DH_DERIVE            0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE     0x00000032
+#define CKM_X9_42_MQV_DERIVE           0x00000033
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_RSA_PKCS            0x00000040
+#define CKM_SHA384_RSA_PKCS            0x00000041
+#define CKM_SHA512_RSA_PKCS            0x00000042
+#define CKM_SHA256_RSA_PKCS_PSS        0x00000043
+#define CKM_SHA384_RSA_PKCS_PSS        0x00000044
+#define CKM_SHA512_RSA_PKCS_PSS        0x00000045
+
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224_RSA_PKCS            0x00000046
+#define CKM_SHA224_RSA_PKCS_PSS        0x00000047
+
+#define CKM_RC2_KEY_GEN                0x00000100
+#define CKM_RC2_ECB                    0x00000101
+#define CKM_RC2_CBC                    0x00000102
+#define CKM_RC2_MAC                    0x00000103
+
+/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
+#define CKM_RC2_MAC_GENERAL            0x00000104
+#define CKM_RC2_CBC_PAD                0x00000105
+
+#define CKM_RC4_KEY_GEN                0x00000110
+#define CKM_RC4                        0x00000111
+#define CKM_DES_KEY_GEN                0x00000120
+#define CKM_DES_ECB                    0x00000121
+#define CKM_DES_CBC                    0x00000122
+#define CKM_DES_MAC                    0x00000123
+
+/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
+#define CKM_DES_MAC_GENERAL            0x00000124
+#define CKM_DES_CBC_PAD                0x00000125
+
+#define CKM_DES2_KEY_GEN               0x00000130
+#define CKM_DES3_KEY_GEN               0x00000131
+#define CKM_DES3_ECB                   0x00000132
+#define CKM_DES3_CBC                   0x00000133
+#define CKM_DES3_MAC                   0x00000134
+
+/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
+ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
+ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
+#define CKM_DES3_MAC_GENERAL           0x00000135
+#define CKM_DES3_CBC_PAD               0x00000136
+#define CKM_CDMF_KEY_GEN               0x00000140
+#define CKM_CDMF_ECB                   0x00000141
+#define CKM_CDMF_CBC                   0x00000142
+#define CKM_CDMF_MAC                   0x00000143
+#define CKM_CDMF_MAC_GENERAL           0x00000144
+#define CKM_CDMF_CBC_PAD               0x00000145
+
+/* the following four DES mechanisms are new for v2.20 */
+#define CKM_DES_OFB64                  0x00000150
+#define CKM_DES_OFB8                   0x00000151
+#define CKM_DES_CFB64                  0x00000152
+#define CKM_DES_CFB8                   0x00000153
+
+#define CKM_MD2                        0x00000200
+
+/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD2_HMAC                   0x00000201
+#define CKM_MD2_HMAC_GENERAL           0x00000202
+
+#define CKM_MD5                        0x00000210
+
+/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD5_HMAC                   0x00000211
+#define CKM_MD5_HMAC_GENERAL           0x00000212
+
+#define CKM_SHA_1                      0x00000220
+
+/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
+#define CKM_SHA_1_HMAC                 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL         0x00000222
+
+/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC,
+ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
+ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
+#define CKM_RIPEMD128                  0x00000230
+#define CKM_RIPEMD128_HMAC             0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL     0x00000232
+#define CKM_RIPEMD160                  0x00000240
+#define CKM_RIPEMD160_HMAC             0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL     0x00000242
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256                     0x00000250
+#define CKM_SHA256_HMAC                0x00000251
+#define CKM_SHA256_HMAC_GENERAL        0x00000252
+#define CKM_SHA384                     0x00000260
+#define CKM_SHA384_HMAC                0x00000261
+#define CKM_SHA384_HMAC_GENERAL        0x00000262
+#define CKM_SHA512                     0x00000270
+#define CKM_SHA512_HMAC                0x00000271
+#define CKM_SHA512_HMAC_GENERAL        0x00000272
+
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224                     0x00000255
+#define CKM_SHA224_HMAC                0x00000256
+#define CKM_SHA224_HMAC_GENERAL        0x00000257
+
+/* All of the following mechanisms are new for v2.0 */
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST_KEY_GEN               0x00000300
+#define CKM_CAST_ECB                   0x00000301
+#define CKM_CAST_CBC                   0x00000302
+#define CKM_CAST_MAC                   0x00000303
+#define CKM_CAST_MAC_GENERAL           0x00000304
+#define CKM_CAST_CBC_PAD               0x00000305
+#define CKM_CAST3_KEY_GEN              0x00000310
+#define CKM_CAST3_ECB                  0x00000311
+#define CKM_CAST3_CBC                  0x00000312
+#define CKM_CAST3_MAC                  0x00000313
+#define CKM_CAST3_MAC_GENERAL          0x00000314
+#define CKM_CAST3_CBC_PAD              0x00000315
+#define CKM_CAST5_KEY_GEN              0x00000320
+#define CKM_CAST128_KEY_GEN            0x00000320
+#define CKM_CAST5_ECB                  0x00000321
+#define CKM_CAST128_ECB                0x00000321
+#define CKM_CAST5_CBC                  0x00000322
+#define CKM_CAST128_CBC                0x00000322
+#define CKM_CAST5_MAC                  0x00000323
+#define CKM_CAST128_MAC                0x00000323
+#define CKM_CAST5_MAC_GENERAL          0x00000324
+#define CKM_CAST128_MAC_GENERAL        0x00000324
+#define CKM_CAST5_CBC_PAD              0x00000325
+#define CKM_CAST128_CBC_PAD            0x00000325
+#define CKM_RC5_KEY_GEN                0x00000330
+#define CKM_RC5_ECB                    0x00000331
+#define CKM_RC5_CBC                    0x00000332
+#define CKM_RC5_MAC                    0x00000333
+#define CKM_RC5_MAC_GENERAL            0x00000334
+#define CKM_RC5_CBC_PAD                0x00000335
+#define CKM_IDEA_KEY_GEN               0x00000340
+#define CKM_IDEA_ECB                   0x00000341
+#define CKM_IDEA_CBC                   0x00000342
+#define CKM_IDEA_MAC                   0x00000343
+#define CKM_IDEA_MAC_GENERAL           0x00000344
+#define CKM_IDEA_CBC_PAD               0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN     0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY   0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA  0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE  0x00000363
+#define CKM_XOR_BASE_AND_DATA          0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY       0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN    0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE     0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE    0x00000372
+
+/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
+ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
+ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH  0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN     0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE      0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE     0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH   0x00000377
+
+/* CKM_TLS_PRF is new for v2.20 */
+#define CKM_TLS_PRF                    0x00000378
+
+#define CKM_SSL3_MD5_MAC               0x00000380
+#define CKM_SSL3_SHA1_MAC              0x00000381
+#define CKM_MD5_KEY_DERIVATION         0x00000390
+#define CKM_MD2_KEY_DERIVATION         0x00000391
+#define CKM_SHA1_KEY_DERIVATION        0x00000392
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_KEY_DERIVATION      0x00000393
+#define CKM_SHA384_KEY_DERIVATION      0x00000394
+#define CKM_SHA512_KEY_DERIVATION      0x00000395
+
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224_KEY_DERIVATION      0x00000396
+
+#define CKM_PBE_MD2_DES_CBC            0x000003A0
+#define CKM_PBE_MD5_DES_CBC            0x000003A1
+#define CKM_PBE_MD5_CAST_CBC           0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC          0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC          0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC        0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC         0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC       0x000003A5
+#define CKM_PBE_SHA1_RC4_128           0x000003A6
+#define CKM_PBE_SHA1_RC4_40            0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC       0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC        0x000003AB
+
+/* CKM_PKCS5_PBKD2 is new for v2.10 */
+#define CKM_PKCS5_PBKD2                0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003C0
+
+/* WTLS mechanisms are new for v2.20 */
+#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003D0
+#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003D1
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003D2
+#define CKM_WTLS_PRF                        0x000003D3
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003D4
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003D5
+
+#define CKM_KEY_WRAP_LYNKS             0x00000400
+#define CKM_KEY_WRAP_SET_OAEP          0x00000401
+
+/* CKM_CMS_SIG is new for v2.20 */
+#define CKM_CMS_SIG                    0x00000500
+
+/* Fortezza mechanisms */
+#define CKM_SKIPJACK_KEY_GEN           0x00001000
+#define CKM_SKIPJACK_ECB64             0x00001001
+#define CKM_SKIPJACK_CBC64             0x00001002
+#define CKM_SKIPJACK_OFB64             0x00001003
+#define CKM_SKIPJACK_CFB64             0x00001004
+#define CKM_SKIPJACK_CFB32             0x00001005
+#define CKM_SKIPJACK_CFB16             0x00001006
+#define CKM_SKIPJACK_CFB8              0x00001007
+#define CKM_SKIPJACK_WRAP              0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP      0x00001009
+#define CKM_SKIPJACK_RELAYX            0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN           0x00001010
+#define CKM_KEA_KEY_DERIVE             0x00001011
+#define CKM_FORTEZZA_TIMESTAMP         0x00001020
+#define CKM_BATON_KEY_GEN              0x00001030
+#define CKM_BATON_ECB128               0x00001031
+#define CKM_BATON_ECB96                0x00001032
+#define CKM_BATON_CBC128               0x00001033
+#define CKM_BATON_COUNTER              0x00001034
+#define CKM_BATON_SHUFFLE              0x00001035
+#define CKM_BATON_WRAP                 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN         0x00001040
+#define CKM_EC_KEY_PAIR_GEN            0x00001040
+
+#define CKM_ECDSA                      0x00001041
+#define CKM_ECDSA_SHA1                 0x00001042
+
+/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
+ * are new for v2.11 */
+#define CKM_ECDH1_DERIVE               0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE      0x00001051
+#define CKM_ECMQV_DERIVE               0x00001052
+
+#define CKM_JUNIPER_KEY_GEN            0x00001060
+#define CKM_JUNIPER_ECB128             0x00001061
+#define CKM_JUNIPER_CBC128             0x00001062
+#define CKM_JUNIPER_COUNTER            0x00001063
+#define CKM_JUNIPER_SHUFFLE            0x00001064
+#define CKM_JUNIPER_WRAP               0x00001065
+#define CKM_FASTHASH                   0x00001070
+
+/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
+ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
+ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
+ * new for v2.11 */
+#define CKM_AES_KEY_GEN                0x00001080
+#define CKM_AES_ECB                    0x00001081
+#define CKM_AES_CBC                    0x00001082
+#define CKM_AES_MAC                    0x00001083
+#define CKM_AES_MAC_GENERAL            0x00001084
+#define CKM_AES_CBC_PAD                0x00001085
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKM_BLOWFISH_KEY_GEN           0x00001090
+#define CKM_BLOWFISH_CBC               0x00001091
+#define CKM_TWOFISH_KEY_GEN            0x00001092
+#define CKM_TWOFISH_CBC                0x00001093
+
+/* Camellia is proposed for v2.20 Amendment 3 */
+#define CKM_CAMELLIA_KEY_GEN           0x00000550
+#define CKM_CAMELLIA_ECB               0x00000551
+#define CKM_CAMELLIA_CBC               0x00000552
+#define CKM_CAMELLIA_MAC               0x00000553
+#define CKM_CAMELLIA_MAC_GENERAL       0x00000554
+#define CKM_CAMELLIA_CBC_PAD           0x00000555
+#define CKM_CAMELLIA_ECB_ENCRYPT_DATA  0x00000556
+#define CKM_CAMELLIA_CBC_ENCRYPT_DATA  0x00000557
+
+#define CKM_SEED_KEY_GEN	       0x00000650    
+#define CKM_SEED_ECB		       0x00000651
+#define CKM_SEED_CBC		       0x00000652
+#define CKM_SEED_MAC		       0x00000653
+#define CKM_SEED_MAC_GENERAL	       0x00000654
+#define CKM_SEED_CBC_PAD	       0x00000655
+#define CKM_SEED_ECB_ENCRYPT_DATA      0x00000656
+#define CKM_SEED_CBC_ENCRYPT_DATA      0x00000657
+
+/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */
+#define CKM_DES_ECB_ENCRYPT_DATA       0x00001100
+#define CKM_DES_CBC_ENCRYPT_DATA       0x00001101
+#define CKM_DES3_ECB_ENCRYPT_DATA      0x00001102
+#define CKM_DES3_CBC_ENCRYPT_DATA      0x00001103
+#define CKM_AES_ECB_ENCRYPT_DATA       0x00001104
+#define CKM_AES_CBC_ENCRYPT_DATA       0x00001105
+
+#define CKM_DSA_PARAMETER_GEN          0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN      0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN     0x00002002
+
+#define CKM_VENDOR_DEFINED             0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism  */
+typedef struct CK_MECHANISM {
+  CK_MECHANISM_TYPE mechanism;
+  CK_VOID_PTR       pParameter;
+
+  /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG          ulParameterLen;  /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+    CK_ULONG    ulMinKeySize;
+    CK_ULONG    ulMaxKeySize;
+    CK_FLAGS    flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ *      Bit Flag               Mask        Meaning */
+#define CKF_HW                 0x00000001  /* performed by HW */
+
+/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
+ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
+ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
+ * and CKF_DERIVE are new for v2.0.  They specify whether or not
+ * a mechanism can be used for a particular task */
+#define CKF_ENCRYPT            0x00000100
+#define CKF_DECRYPT            0x00000200
+#define CKF_DIGEST             0x00000400
+#define CKF_SIGN               0x00000800
+#define CKF_SIGN_RECOVER       0x00001000
+#define CKF_VERIFY             0x00002000
+#define CKF_VERIFY_RECOVER     0x00004000
+#define CKF_GENERATE           0x00008000
+#define CKF_GENERATE_KEY_PAIR  0x00010000
+#define CKF_WRAP               0x00020000
+#define CKF_UNWRAP             0x00040000
+#define CKF_DERIVE             0x00080000
+
+/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
+ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
+ * describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P             0x00100000
+#define CKF_EC_F_2M            0x00200000
+#define CKF_EC_ECPARAMETERS    0x00400000
+#define CKF_EC_NAMEDCURVE      0x00800000
+#define CKF_EC_UNCOMPRESS      0x01000000
+#define CKF_EC_COMPRESS        0x02000000
+
+#define CKF_EXTENSION          0x80000000 /* FALSE for this version */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * PKCS #11 function */
+/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG          CK_RV;
+
+#define CKR_OK                                0x00000000
+#define CKR_CANCEL                            0x00000001
+#define CKR_HOST_MEMORY                       0x00000002
+#define CKR_SLOT_ID_INVALID                   0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
+#define CKR_GENERAL_ERROR                     0x00000005
+#define CKR_FUNCTION_FAILED                   0x00000006
+
+/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
+ * and CKR_CANT_LOCK are new for v2.01 */
+#define CKR_ARGUMENTS_BAD                     0x00000007
+#define CKR_NO_EVENT                          0x00000008
+#define CKR_NEED_TO_CREATE_THREADS            0x00000009
+#define CKR_CANT_LOCK                         0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY               0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE               0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID            0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID           0x00000013
+#define CKR_DATA_INVALID                      0x00000020
+#define CKR_DATA_LEN_RANGE                    0x00000021
+#define CKR_DEVICE_ERROR                      0x00000030
+#define CKR_DEVICE_MEMORY                     0x00000031
+#define CKR_DEVICE_REMOVED                    0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID            0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE          0x00000041
+#define CKR_FUNCTION_CANCELED                 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL             0x00000051
+
+/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
+#define CKR_FUNCTION_NOT_SUPPORTED            0x00000054
+
+#define CKR_KEY_HANDLE_INVALID                0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE                    0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT             0x00000063
+
+/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
+ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
+ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
+ * v2.0 */
+#define CKR_KEY_NOT_NEEDED                    0x00000064
+#define CKR_KEY_CHANGED                       0x00000065
+#define CKR_KEY_NEEDED                        0x00000066
+#define CKR_KEY_INDIGESTIBLE                  0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED        0x00000068
+#define CKR_KEY_NOT_WRAPPABLE                 0x00000069
+#define CKR_KEY_UNEXTRACTABLE                 0x0000006A
+
+#define CKR_MECHANISM_INVALID                 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID           0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID             0x00000082
+#define CKR_OPERATION_ACTIVE                  0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED         0x00000091
+#define CKR_PIN_INCORRECT                     0x000000A0
+#define CKR_PIN_INVALID                       0x000000A1
+#define CKR_PIN_LEN_RANGE                     0x000000A2
+
+/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
+#define CKR_PIN_EXPIRED                       0x000000A3
+#define CKR_PIN_LOCKED                        0x000000A4
+
+#define CKR_SESSION_CLOSED                    0x000000B0
+#define CKR_SESSION_COUNT                     0x000000B1
+#define CKR_SESSION_HANDLE_INVALID            0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED    0x000000B4
+#define CKR_SESSION_READ_ONLY                 0x000000B5
+#define CKR_SESSION_EXISTS                    0x000000B6
+
+/* CKR_SESSION_READ_ONLY_EXISTS and
+ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
+#define CKR_SESSION_READ_ONLY_EXISTS          0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS      0x000000B8
+
+#define CKR_SIGNATURE_INVALID                 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE               0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE               0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT             0x000000D1
+#define CKR_TOKEN_NOT_PRESENT                 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED              0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED             0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID     0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE         0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT  0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN            0x00000100
+#define CKR_USER_NOT_LOGGED_IN                0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED          0x00000102
+#define CKR_USER_TYPE_INVALID                 0x00000103
+
+/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
+ * are new to v2.01 */
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN    0x00000104
+#define CKR_USER_TOO_MANY_TYPES               0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID               0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE             0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID       0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE           0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT    0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED         0x00000120
+
+/* These are new to v2.0 */
+#define CKR_RANDOM_NO_RNG                     0x00000121
+
+/* These are new to v2.11 */
+#define CKR_DOMAIN_PARAMS_INVALID             0x00000130
+
+/* These are new to v2.0 */
+#define CKR_BUFFER_TOO_SMALL                  0x00000150
+#define CKR_SAVED_STATE_INVALID               0x00000160
+#define CKR_INFORMATION_SENSITIVE             0x00000170
+#define CKR_STATE_UNSAVEABLE                  0x00000180
+
+/* These are new to v2.01 */
+#define CKR_CRYPTOKI_NOT_INITIALIZED          0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED      0x00000191
+#define CKR_MUTEX_BAD                         0x000001A0
+#define CKR_MUTEX_NOT_LOCKED                  0x000001A1
+
+/* This is new to v2.20 */
+#define CKR_FUNCTION_REJECTED                 0x00000200
+
+#define CKR_VENDOR_DEFINED                    0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_NOTIFICATION   event,
+  CK_VOID_PTR       pApplication  /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a PKCS #11 spec
+ * version and pointers of appropriate types to all the
+ * PKCS #11 functions */
+/* CK_FUNCTION_LIST is new for v2.0 */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+  CK_VOID_PTR_PTR ppMutex  /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+  CK_CREATEMUTEX CreateMutex;
+  CK_DESTROYMUTEX DestroyMutex;
+  CK_LOCKMUTEX LockMutex;
+  CK_UNLOCKMUTEX UnlockMutex;
+  CK_FLAGS flags;
+  /* The official PKCS #11 spec does not have a 'LibraryParameters' field, but
+   * a reserved field. NSS needs a way to pass instance-specific information
+   * to the library (like where to find its config files, etc). This
+   * information is usually provided by the installer and passed uninterpreted
+   * by NSS to the library, though NSS does know the specifics of the softoken
+   * version of this parameter. Most compliant PKCS#11 modules expect this 
+   * parameter to be NULL, and will return CKR_ARGUMENTS_BAD from
+   * C_Initialize if Library parameters is supplied. */
+  CK_CHAR_PTR *LibraryParameters;
+  /* This field is only present if the LibraryParameters is not NULL. It must
+   * be NULL in all cases */
+  CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag                           Mask       Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK                  0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK     1
+
+/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_MGF_TYPE  is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512
+ * are new for v2.20 */
+#define CKG_MGF1_SHA1         0x00000001
+#define CKG_MGF1_SHA256       0x00000002
+#define CKG_MGF1_SHA384       0x00000003
+#define CKG_MGF1_SHA512       0x00000004
+
+/* v2.20 amendment 3 */
+#define CKG_MGF1_SHA224	      0x00000005
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE  is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED    0x00000001
+
+/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+        CK_MECHANISM_TYPE hashAlg;
+        CK_RSA_PKCS_MGF_TYPE mgf;
+        CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+        CK_VOID_PTR pSourceData;
+        CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+        CK_MECHANISM_TYPE    hashAlg;
+        CK_RSA_PKCS_MGF_TYPE mgf;
+        CK_ULONG             sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+/* CK_EC_KDF_TYPE is new for v2.11. */
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL                 0x00000001
+#define CKD_SHA1_KDF             0x00000002
+
+/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+
+/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+  CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* The following X9.42 DH key derivation functions are defined
+   (besides CKD_NULL already defined : */
+#define CKD_SHA1_KDF_ASN1        0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+
+/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+  CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
+typedef struct CK_KEA_DERIVE_PARAMS {
+  CK_BBOOL      isSender;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pRandomB;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms.  An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG          CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+  /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+
+  CK_BYTE       iv[8];            /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+  CK_ULONG      ulMacLength;      /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+/* CK_RC5_PARAMS is new for v2.0 */
+typedef struct CK_RC5_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+/* CK_RC5_CBC_PARAMS is new for v2.0 */
+typedef struct CK_RC5_CBC_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+  CK_BYTE_PTR   pIv;         /* pointer to IV */
+  CK_ULONG      ulIvLen;     /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulWordsize;   /* wordsize in bits */
+  CK_ULONG      ulRounds;     /* number of rounds */
+  CK_ULONG      ulMacLength;  /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms.  Its value is the length of
+ * the MAC */
+/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef CK_ULONG          CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+  CK_BYTE      iv[8];
+  CK_BYTE_PTR  pData;
+  CK_ULONG     length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+  CK_BYTE      iv[16];
+  CK_BYTE_PTR  pData;
+  CK_ULONG     length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+  CK_ULONG      ulPasswordLen;
+  CK_BYTE_PTR   pPassword;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+  CK_ULONG      ulPAndGLen;
+  CK_ULONG      ulQLen;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pPrimeP;
+  CK_BYTE_PTR   pBaseG;
+  CK_BYTE_PTR   pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+  CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+  CK_ULONG      ulOldWrappedXLen;
+  CK_BYTE_PTR   pOldWrappedX;
+  CK_ULONG      ulOldPasswordLen;
+  CK_BYTE_PTR   pOldPassword;
+  CK_ULONG      ulOldPublicDataLen;
+  CK_BYTE_PTR   pOldPublicData;
+  CK_ULONG      ulOldRandomLen;
+  CK_BYTE_PTR   pOldRandomA;
+  CK_ULONG      ulNewPasswordLen;
+  CK_BYTE_PTR   pNewPassword;
+  CK_ULONG      ulNewPublicDataLen;
+  CK_BYTE_PTR   pNewPublicData;
+  CK_ULONG      ulNewRandomLen;
+  CK_BYTE_PTR   pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+  CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+  CK_BYTE_PTR      pInitVector;
+  CK_UTF8CHAR_PTR  pPassword;
+  CK_ULONG         ulPasswordLen;
+  CK_BYTE_PTR      pSalt;
+  CK_ULONG         ulSaltLen;
+  CK_ULONG         ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+  CK_BYTE       bBC;     /* block contents byte */
+  CK_BYTE_PTR   pX;      /* extra data */
+  CK_ULONG      ulXLen;  /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+  CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+  CK_BYTE_PTR  pClientRandom;
+  CK_ULONG     ulClientRandomLen;
+  CK_BYTE_PTR  pServerRandom;
+  CK_ULONG     ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+  CK_SSL3_RANDOM_DATA RandomInfo;
+  CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+  CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+  CK_OBJECT_HANDLE hClientMacSecret;
+  CK_OBJECT_HANDLE hServerMacSecret;
+  CK_OBJECT_HANDLE hClientKey;
+  CK_OBJECT_HANDLE hServerKey;
+  CK_BYTE_PTR      pIVClient;
+  CK_BYTE_PTR      pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+  CK_ULONG                ulMacSizeInBits;
+  CK_ULONG                ulKeySizeInBits;
+  CK_ULONG                ulIVSizeInBits;
+  CK_BBOOL                bIsExport;
+  CK_SSL3_RANDOM_DATA     RandomInfo;
+  CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+/* CK_TLS_PRF_PARAMS is new for version 2.20 */
+typedef struct CK_TLS_PRF_PARAMS {
+  CK_BYTE_PTR  pSeed;
+  CK_ULONG     ulSeedLen;
+  CK_BYTE_PTR  pLabel;
+  CK_ULONG     ulLabelLen;
+  CK_BYTE_PTR  pOutput;
+  CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+/* WTLS is new for version 2.20 */
+typedef struct CK_WTLS_RANDOM_DATA {
+  CK_BYTE_PTR pClientRandom;
+  CK_ULONG    ulClientRandomLen;
+  CK_BYTE_PTR pServerRandom;
+  CK_ULONG    ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+  CK_MECHANISM_TYPE   DigestMechanism;
+  CK_WTLS_RANDOM_DATA RandomInfo;
+  CK_BYTE_PTR         pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+  CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+  CK_MECHANISM_TYPE DigestMechanism;
+  CK_BYTE_PTR       pSeed;
+  CK_ULONG          ulSeedLen;
+  CK_BYTE_PTR       pLabel;
+  CK_ULONG          ulLabelLen;
+  CK_BYTE_PTR       pOutput;
+  CK_ULONG_PTR      pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+  CK_OBJECT_HANDLE hMacSecret;
+  CK_OBJECT_HANDLE hKey;
+  CK_BYTE_PTR      pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+  CK_MECHANISM_TYPE       DigestMechanism;
+  CK_ULONG                ulMacSizeInBits;
+  CK_ULONG                ulKeySizeInBits;
+  CK_ULONG                ulIVSizeInBits;
+  CK_ULONG                ulSequenceNumber;
+  CK_BBOOL                bIsExport;
+  CK_WTLS_RANDOM_DATA     RandomInfo;
+  CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+/* CMS is new for version 2.20 */
+typedef struct CK_CMS_SIG_PARAMS {
+  CK_OBJECT_HANDLE      certificateHandle;
+  CK_MECHANISM_PTR      pSigningMechanism;
+  CK_MECHANISM_PTR      pDigestMechanism;
+  CK_UTF8CHAR_PTR       pContentType;
+  CK_BYTE_PTR           pRequestedAttributes;
+  CK_ULONG              ulRequestedAttributesLen;
+  CK_BYTE_PTR           pRequiredAttributes;
+  CK_ULONG              ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+  CK_BYTE_PTR pData;
+  CK_ULONG    ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+  CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism.  It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+/* CK_EXTRACT_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+/* The following PRFs are defined in PKCS #5 v2.0. */
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED        0x00000001
+
+/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+        CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE           saltSource;
+        CK_VOID_PTR                                pSaltSourceData;
+        CK_ULONG                                   ulSaltSourceDataLen;
+        CK_ULONG                                   iterations;
+        CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+        CK_VOID_PTR                                pPrfData;
+        CK_ULONG                                   ulPrfDataLen;
+        CK_UTF8CHAR_PTR                            pPassword;
+        CK_ULONG_PTR                               ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+/* NSS Specific defines */
+
+/* defines that have been deprecated in 2.20, but maintained in our
+ * header file for backward compatibility */
+#define CKO_KG_PARAMETERS     CKO_DOMAIN_PARAMETERS
+#define CKF_EC_FP             CKF_EC_F_P
+/* new in v2.11 deprecated by 2.20 */
+#define CKR_KEY_PARAMS_INVALID                0x0000006B
+
+/* stuff that for historic reasons is in this header file but should have
+ * been in pkcs11n.h */
+#define CKK_INVALID_KEY_TYPE  0xffffffff
+
+#include "pkcs11n.h"
+
+/* undo packing */
+#include "pkcs11u.h"
+
+#endif
diff --git a/mozilla/security/nss/lib/util/pkcs11u.h b/mozilla/security/nss/lib/util/pkcs11u.h
new file mode 100644
index 0000000..8383b47
--- /dev/null
+++ b/mozilla/security/nss/lib/util/pkcs11u.h
@@ -0,0 +1,52 @@
+/* ***** 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 ***** */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security Inc. Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ */
+/*
+ * reset any packing set by pkcs11p.h
+ */
+
+#if defined (_WIN32)
+#ifdef _MSC_VER
+#pragma warning(disable:4103)
+#endif
+#pragma pack(pop, cryptoki)
+#endif
+
diff --git a/mozilla/security/nss/lib/util/portreg.c b/mozilla/security/nss/lib/util/portreg.c
new file mode 100644
index 0000000..1853bdc
--- /dev/null
+++ b/mozilla/security/nss/lib/util/portreg.c
@@ -0,0 +1,412 @@
+/* ***** 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):
+ *      Rob McCool  (original author)
+ * 	Ken Key <key+mozilla@ksquared.net>
+ *      Nelson Bolyard <nelson@bolyard.me>
+ *
+ * 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 ***** */
+
+/* 
+ * shexp.c: shell-like wildcard match routines
+ *
+ * See shexp.h for public documentation.
+ */
+
+#include "seccomon.h"
+#include "portreg.h"
+
+/* ----------------------------- shexp_valid ------------------------------ */
+
+
+static int 
+_valid_subexp(const char *exp, char stop1, char stop2) 
+{
+    register int x;
+    int nsc = 0;     /* Number of special characters */
+    int np;          /* Number of pipe characters in union */
+    int tld = 0;     /* Number of tilde characters */
+
+    for (x = 0; exp[x] && (exp[x] != stop1) && (exp[x] != stop2); ++x) {
+        switch(exp[x]) {
+	case '~':
+            if(tld)                 /* at most one exclusion */
+                return INVALID_SXP;
+            if (stop1)              /* no exclusions within unions */
+                return INVALID_SXP;
+            if (!exp[x+1])          /* exclusion cannot be last character */
+                return INVALID_SXP;
+            if (!x)                 /* exclusion cannot be first character */
+                return INVALID_SXP;
+            ++tld;
+	    /* fall through */
+	case '*':
+	case '?':
+	case '$':
+            ++nsc;
+            break;
+	case '[':
+            ++nsc;
+            if((!exp[++x]) || (exp[x] == ']'))
+                return INVALID_SXP;
+            for(; exp[x] && (exp[x] != ']'); ++x) {
+                if(exp[x] == '\\' && !exp[++x])
+                    return INVALID_SXP;
+            }
+            if(!exp[x])
+                return INVALID_SXP;
+            break;
+	case '(':
+            ++nsc;
+	    if (stop1)			/* no nested unions */
+		return INVALID_SXP;
+            np = -1;
+            do {
+                int t = _valid_subexp(&exp[++x], ')', '|');
+                if(t == 0 || t == INVALID_SXP)
+                    return INVALID_SXP;
+                x+=t;
+		if(!exp[x])
+		    return INVALID_SXP;
+		++np;
+            } while (exp[x] == '|' );
+	    if(np < 1)  /* must be at least one pipe */
+		return INVALID_SXP;
+            break;
+	case ')':
+	case '|':
+	case ']':
+            return INVALID_SXP;
+	case '\\':
+	    ++nsc;
+            if(!exp[++x])
+                return INVALID_SXP;
+            break;
+	default:
+            break;
+        }
+    }
+    if((!stop1) && (!nsc)) /* must be at least one special character */
+        return NON_SXP;
+    return ((exp[x] == stop1 || exp[x] == stop2) ? x : INVALID_SXP);
+}
+
+int 
+PORT_RegExpValid(const char *exp) 
+{
+    int x;
+
+    x = _valid_subexp(exp, '\0', '\0');
+    return (x < 0 ? x : VALID_SXP);
+}
+
+
+/* ----------------------------- shexp_match ----------------------------- */
+
+
+#define MATCH 0
+#define NOMATCH 1
+#define ABORTED -1
+
+static int 
+_shexp_match(const char *str, const char *exp, PRBool case_insensitive,
+             unsigned int level);
+
+/* Count characters until we reach a NUL character or either of the 
+ * two delimiter characters, stop1 or stop2.  If we encounter a bracketed 
+ * expression, look only for NUL or ']' inside it.  Do not look for stop1 
+ * or stop2 inside it. Return ABORTED if bracketed expression is unterminated.
+ * Handle all escaping.
+ * Return index in input string of first stop found, or ABORTED if not found.
+ * If "dest" is non-NULL, copy counted characters to it and NUL terminate.
+ */
+static int 
+_scan_and_copy(const char *exp, char stop1, char stop2, char *dest)
+{
+    register int sx;     /* source index */
+    register char cc;
+
+    for (sx = 0; (cc = exp[sx]) && cc != stop1 && cc != stop2; sx++) {
+	if (cc == '\\') {
+	    if (!exp[++sx])
+		return ABORTED; /* should be impossible */
+	} else if (cc == '[') {
+	    while ((cc = exp[++sx]) && cc != ']') {
+		if(cc == '\\' && !exp[++sx])
+		    return ABORTED;
+	    }
+	    if (!cc) 
+		return ABORTED; /* should be impossible */
+	}
+    }
+    if (dest && sx) {
+	/* Copy all but the closing delimiter. */
+	memcpy(dest, exp, sx);
+	dest[sx] = 0;
+    }
+    return cc ? sx : ABORTED; /* index of closing delimiter */
+}
+
+/* On input, exp[0] is the opening parenthesis of a union.
+ * See if any of the alternatives in the union matches as a pattern.
+ * The strategy is to take each of the alternatives, in turn, and append
+ * the rest of the expression (after the closing ')' that marks the end of 
+ * this union) to that alternative, and then see if the resultant expression
+ * matches the input string.  Repeat this until some alternative matches, 
+ * or we have an abort. 
+ */
+static int 
+_handle_union(const char *str, const char *exp, PRBool case_insensitive,
+              unsigned int level) 
+{
+    register int sx;     /* source index */
+    int cp;              /* source index of closing parenthesis */
+    int count;
+    int ret   = NOMATCH;
+    char *e2;
+
+    /* Find the closing parenthesis that ends this union in the expression */
+    cp = _scan_and_copy(exp, ')', '\0', NULL);
+    if (cp == ABORTED || cp < 4) /* must be at least "(a|b" before ')' */
+    	return ABORTED;
+    ++cp;                /* now index of char after closing parenthesis */
+    e2 = (char *) PORT_Alloc(1 + strlen(exp));
+    if (!e2)
+    	return ABORTED;
+    for (sx = 1; ; ++sx) {
+	/* Here, exp[sx] is one character past the preceeding '(' or '|'. */
+	/* Copy everything up to the next delimiter to e2 */
+	count = _scan_and_copy(exp + sx, ')', '|', e2);
+	if (count == ABORTED || !count) {
+	    ret = ABORTED;
+	    break;
+	}
+	sx += count;
+	/* Append everything after closing parenthesis to e2. This is safe. */
+	strcpy(e2+count, exp+cp);
+        ret = _shexp_match(str, e2, case_insensitive, level + 1);
+	if (ret != NOMATCH || !exp[sx] || exp[sx] == ')')
+            break;
+    }
+    PORT_Free(e2);
+    if (sx < 2)
+    	ret = ABORTED;
+    return ret;
+}
+
+/* returns 1 if val is in range from start..end, case insensitive. */
+static int
+_is_char_in_range(int start, int end, int val)
+{
+    char map[256];
+    memset(map, 0, sizeof map);
+    while (start <= end)
+	map[tolower(start++)] = 1;
+    return map[tolower(val)];
+}
+
+static int 
+_shexp_match(const char *str, const char *exp, PRBool case_insensitive, 
+             unsigned int level) 
+{
+    register int x;   /* input string index */
+    register int y;   /* expression index */
+    int ret,neg;
+
+    if (level > 20)      /* Don't let the stack get too deep. */
+    	return ABORTED;
+    for(x = 0, y = 0; exp[y]; ++y, ++x) {
+        if((!str[x]) && (exp[y] != '$') && (exp[y] != '*')) {
+            return NOMATCH;
+	}
+	switch(exp[y]) {
+	case '$':
+	    if(str[x])
+		return NOMATCH;
+	    --x;                 /* we don't want loop to increment x */
+	    break;
+	case '*':
+	    while(exp[++y] == '*'){}
+	    if(!exp[y])
+		return MATCH;
+	    while(str[x]) {
+	        ret = _shexp_match(&str[x++], &exp[y], case_insensitive, 
+				   level + 1);
+		switch(ret) {
+		case NOMATCH:
+		    continue;
+		case ABORTED:
+		    return ABORTED;
+		default:
+		    return MATCH;
+		}
+	    }
+	    if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
+		return MATCH;
+	    else
+		return NOMATCH;
+	case '[': {
+	    int start, end = 0, i;
+	    neg = ((exp[++y] == '^') && (exp[y+1] != ']'));
+	    if (neg)
+		++y;
+	    i = y;
+	    start = (unsigned char)(exp[i++]);
+	    if (start == '\\')
+	    	start = (unsigned char)(exp[i++]);
+	    if (isalnum(start) && exp[i++] == '-') {
+		end = (unsigned char)(exp[i++]); 
+		if (end == '\\')
+		    end = (unsigned char)(exp[i++]);
+	    }
+	    if (isalnum(end) && exp[i] == ']') {
+		/* This is a range form: a-b */
+		int val   = (unsigned char)(str[x]);
+		if (end < start) { /* swap them */
+		    start ^= end;
+		    end ^= start;
+		    start ^= end;
+		}
+		if (case_insensitive && isalpha(val)) {
+		    val = _is_char_in_range(start, end, val);
+		    if (neg == val)
+			return NOMATCH;
+		} else if (neg != ((val < start) || (val > end))) {
+		    return NOMATCH;
+		}
+		y = i;
+	    } else {
+		/* Not range form */
+		int matched = 0;
+		for (; exp[y] != ']'; y++) {
+		    if (exp[y] == '\\')
+			++y;
+		    if(case_insensitive) {
+			matched |= (toupper(str[x]) == toupper(exp[y]));
+		    } else {
+			matched |= (str[x] == exp[y]);
+		    }
+		}
+		if (neg == matched)
+		    return NOMATCH;
+	    }
+	}
+	break;
+	case '(':
+	    if (!exp[y+1])
+	    	return ABORTED;
+	    return _handle_union(&str[x], &exp[y], case_insensitive, level);
+	case '?':
+	    break;
+	case '|':
+	case ']':
+	case ')':
+	    return ABORTED;
+	case '\\':
+	    ++y;
+	    /* fall through */
+	default:
+	    if(case_insensitive) {
+		if(toupper(str[x]) != toupper(exp[y]))
+		    return NOMATCH;
+	    } else {
+		if(str[x] != exp[y])
+		    return NOMATCH;
+	    }
+	    break;
+	}
+    }
+    return (str[x] ? NOMATCH : MATCH);
+}
+
+static int 
+port_RegExpMatch(const char *str, const char *xp, PRBool case_insensitive) 
+{
+    char *exp = 0;
+    int x, ret = MATCH;
+
+    if (!strchr(xp, '~'))
+    	return _shexp_match(str, xp, case_insensitive, 0);
+
+    exp = PORT_Strdup(xp);
+    if(!exp)
+	return NOMATCH;
+
+    x = _scan_and_copy(exp, '~', '\0', NULL);
+    if (x != ABORTED && exp[x] == '~') {
+	exp[x++] = '\0';
+	ret = _shexp_match(str, &exp[x], case_insensitive, 0);
+	switch (ret) {
+	case NOMATCH: ret = MATCH;   break;
+	case MATCH:   ret = NOMATCH; break;
+	default:                     break;
+        }
+    }
+    if (ret == MATCH)
+	ret = _shexp_match(str, exp, case_insensitive, 0);
+
+    PORT_Free(exp);
+    return ret;
+}
+
+
+/* ------------------------------ shexp_cmp ------------------------------- */
+
+int 
+PORT_RegExpSearch(const char *str, const char *exp)
+{
+    switch(PORT_RegExpValid(exp)) 
+	  {
+        case INVALID_SXP:
+            return -1;
+        case NON_SXP:
+            return (strcmp(exp,str) ? 1 : 0);
+        default:
+            return port_RegExpMatch(str, exp, PR_FALSE);
+      }
+}
+
+int
+PORT_RegExpCaseSearch(const char *str, const char *exp)
+{
+    switch(PORT_RegExpValid(exp))
+      {
+        case INVALID_SXP:
+            return -1;
+        case NON_SXP:
+            return (PORT_Strcasecmp(exp,str) ? 1 : 0);
+        default:
+            return port_RegExpMatch(str, exp, PR_TRUE);
+      }
+}
+
diff --git a/mozilla/security/nss/lib/util/portreg.h b/mozilla/security/nss/lib/util/portreg.h
new file mode 100644
index 0000000..bfce983
--- /dev/null
+++ b/mozilla/security/nss/lib/util/portreg.h
@@ -0,0 +1,117 @@
+/* ***** 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):
+ *      Rob McCool  (original author)
+ *      Nelson Bolyard <nelson@bolyard.me>
+ *
+ * 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 ***** */
+
+/*
+ * shexp.h: Defines and prototypes for shell exp. match routines
+ * 
+ * This routine will match a string with a shell expression. The expressions
+ * accepted are based loosely on the expressions accepted by zsh.
+ * 
+ * o * matches anything
+ * o ? matches one character
+ * o \ will escape a special character
+ * o $ matches the end of the string
+ * Bracketed expressions:
+ * o [abc] matches one occurence of a, b, or c.  
+ * o [^abc] matches any character except a, b, or c.
+ *     To be matched between [ and ], these characters must be escaped: \ ]
+ *     No other characters need be escaped between brackets. 
+ *     Unnecessary escaping is permitted.
+ * o [a-z] matches any character between a and z, inclusive.
+ *     The two range-definition characters must be alphanumeric ASCII.
+ *     If one is upper case and the other is lower case, then the ASCII
+ *     non-alphanumeric characters between Z and a will also be in range.
+ * o [^a-z] matches any character except those between a and z, inclusive.
+ *     These forms cannot be combined, e.g [a-gp-z] does not work.
+ * o Exclusions:
+ *   As a top level, outter-most expression only, the expression
+ *   foo~bar will match the expression foo, provided it does not also 
+ *     match the expression bar.  Either expression or both may be a union.
+ *     Except between brackets, any unescaped ~ is an exclusion. 
+ *     At most one exclusion is permitted.
+ *     Exclusions cannot be nested (contain other exclusions).
+ *     example: *~abc will match any string except abc
+ * o Unions:
+ *   (foo|bar) will match either the expression foo, or the expression bar.
+ *     At least one '|' separator is required.  More are permitted.
+ *     Expressions inside unions may not include unions or exclusions.
+ *     Inside a union, to be matched and not treated as a special character,
+ *     these characters must be escaped: \ ( | ) [ ~ except when they occur
+ *     inside a bracketed expression, where only \ and ] require escaping.
+ *
+ * The public interface to these routines is documented below.
+ * 
+ */
+ 
+#ifndef SHEXP_H
+#define SHEXP_H
+
+#include "utilrename.h"
+/*
+ * Requires that the macro MALLOC be set to a "safe" malloc that will 
+ * exit if no memory is available. 
+ */
+
+
+/* --------------------------- Public routines ---------------------------- */
+
+
+/*
+ * shexp_valid takes a shell expression exp as input. It returns:
+ * 
+ *  NON_SXP      if exp is a standard string
+ *  INVALID_SXP  if exp is a shell expression, but invalid
+ *  VALID_SXP    if exp is a valid shell expression
+ */
+
+#define NON_SXP -1
+#define INVALID_SXP -2
+#define VALID_SXP 1
+
+SEC_BEGIN_PROTOS
+
+extern int PORT_RegExpValid(const char *exp);
+
+extern int PORT_RegExpSearch(const char *str, const char *exp);
+
+/* same as above but uses case insensitive search */
+extern int PORT_RegExpCaseSearch(const char *str, const char *exp);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/mozilla/security/nss/lib/util/quickder.c b/mozilla/security/nss/lib/util/quickder.c
new file mode 100644
index 0000000..29a5821
--- /dev/null
+++ b/mozilla/security/nss/lib/util/quickder.c
@@ -0,0 +1,912 @@
+/* ***** 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 ***** */
+
+/*
+    Optimized ASN.1 DER decoder
+    
+*/
+
+#include "secerr.h"
+#include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
+#include "secitem.h"
+
+/*
+ * simple definite-length ASN.1 decoder
+ */
+
+static unsigned char* definite_length_decoder(const unsigned char *buf,
+                                              const unsigned int length,
+                                              unsigned int *data_length,
+                                              PRBool includeTag)
+{
+    unsigned char tag;
+    unsigned int used_length= 0;
+    unsigned int data_len;
+
+    if (used_length >= length)
+    {
+        return NULL;
+    }
+    tag = buf[used_length++];
+
+    /* blow out when we come to the end */
+    if (tag == 0)
+    {
+        return NULL;
+    }
+
+    if (used_length >= length)
+    {
+        return NULL;
+    }
+    data_len = buf[used_length++];
+
+    if (data_len&0x80)
+    {
+        int  len_count = data_len & 0x7f;
+
+        data_len = 0;
+
+        while (len_count-- > 0)
+        {
+            if (used_length >= length)
+            {
+                return NULL;
+            }
+            data_len = (data_len << 8) | buf[used_length++];
+        }
+    }
+
+    if (data_len > (length-used_length) )
+    {
+        return NULL;
+    }
+    if (includeTag) data_len += used_length;
+
+    *data_length = data_len;
+    return ((unsigned char*)buf + (includeTag ? 0 : used_length));
+}
+
+static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
+{
+    if ( (!src) || (!dest) || (!src->data) )
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (!src->len)
+    {
+        /* reaching the end of the buffer is not an error */
+        dest->data = NULL;
+        dest->len = 0;
+        return SECSuccess;
+    }
+
+    dest->data = definite_length_decoder(src->data,  src->len, &dest->len,
+        includeTag);
+    if (dest->data == NULL)
+    {
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        return SECFailure;
+    }
+    src->len -= (dest->data - src->data) + dest->len;
+    src->data = dest->data + dest->len;
+    return SECSuccess;
+}
+
+/* check if the actual component's type matches the type in the template */
+
+static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
+                                    SECItem* item, PRBool* match, void* dest)
+{
+    unsigned long kind = 0;
+    unsigned char tag = 0;
+
+    if ( (!item) || (!templateEntry) || (!match) )
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (!item->len || !item->data)
+    {
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    kind = templateEntry->kind;
+    tag = *(unsigned char*) item->data;
+
+    if ( ( (kind & SEC_ASN1_INLINE) ||
+           (kind & SEC_ASN1_POINTER) ) &&
+           (0 == (kind & SEC_ASN1_TAG_MASK) ) )
+    {
+        /* These cases are special because the template's "kind" does not
+           give us the information for the ASN.1 tag of the next item. It can
+           only be figured out from the subtemplate. */
+        if (!(kind & SEC_ASN1_OPTIONAL))
+        {
+            /* This is a required component. If there is a type mismatch,
+               the decoding of the subtemplate will fail, so assume this
+               is a match at the parent level and let it fail later. This
+               avoids a redundant check in matching cases */
+            *match = PR_TRUE;
+            return SECSuccess;
+        }
+        else
+        {
+            /* optional component. This is the hard case. Now we need to
+               look at the subtemplate to get the expected kind */
+            const SEC_ASN1Template* subTemplate = 
+                SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+            if (!subTemplate)
+            {
+                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+                return SECFailure;
+            }
+            if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
+                 (subTemplate->kind & SEC_ASN1_POINTER) )
+            {
+                /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
+                   otherwise you may get a false positive due to the recursion
+                   optimization above that always matches the type if the
+                   component is required . Nesting these should never be
+                   required, so that no one should miss this ability */
+                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+                return SECFailure;
+            }
+            return MatchComponentType(subTemplate, item, match,
+                                      (void*)((char*)dest + templateEntry->offset));
+        }
+    }
+
+    if (kind & SEC_ASN1_CHOICE)
+    {
+        /* we need to check the component's tag against each choice's tag */
+        /* XXX it would be nice to save the index of the choice here so that
+           DecodeChoice wouldn't have to do this again. However, due to the
+           recursivity of MatchComponentType, we don't know if we are in a
+           required or optional component, so we can't write anywhere in
+           the destination within this function */
+        unsigned choiceIndex = 1;
+        const SEC_ASN1Template* choiceEntry;
+        while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
+        {
+            if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
+                                (void*)((char*)dest + choiceEntry->offset))) &&
+                 (PR_TRUE == *match) )
+            {
+                return SECSuccess;
+            }
+        }
+	/* no match, caller must decide if this is BAD DER, or not. */
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    if (kind & SEC_ASN1_ANY)
+    {
+        /* SEC_ASN1_ANY always matches */
+        *match = PR_TRUE;
+        return SECSuccess;
+    }
+
+    if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
+         (!(kind & SEC_ASN1_EXPLICIT)) &&
+         ( ( (kind & SEC_ASN1_SAVE) ||
+             (kind & SEC_ASN1_SKIP) ) &&
+           (!(kind & SEC_ASN1_OPTIONAL)) 
+         )
+       )
+    {
+        /* when saving or skipping a required component,  a type is not
+           required in the template. This is for legacy support of
+           SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
+           deprecate these usages and always require a type, as this
+           disables type checking, and effectively forbids us from
+           transparently ignoring optional components we aren't aware of */
+        *match = PR_TRUE;
+        return SECSuccess;
+    }
+
+    /* first, do a class check */
+    if ( (tag & SEC_ASN1_CLASS_MASK) !=
+         (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
+    {
+#ifdef DEBUG
+        /* this is only to help debugging of the decoder in case of problems */
+        unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
+        unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
+        tagclass = tagclass;
+        expectedclass = expectedclass;
+#endif
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    /* now do a tag check */
+    if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
+         (tag & SEC_ASN1_TAGNUM_MASK))
+    {
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    /* now, do a method check. This depends on the class */
+    switch (tag & SEC_ASN1_CLASS_MASK)
+    {
+    case SEC_ASN1_UNIVERSAL:
+        /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
+           primitive or constructed based on the tag */
+        switch (tag & SEC_ASN1_TAGNUM_MASK)
+        {
+        case SEC_ASN1_SEQUENCE:
+        case SEC_ASN1_SET:
+        case SEC_ASN1_EMBEDDED_PDV:
+            /* this component must be a constructed type */
+            /* XXX add any new universal constructed type here */
+            if (tag & SEC_ASN1_CONSTRUCTED)
+            {
+                *match = PR_TRUE;
+                return SECSuccess;
+            }
+            break;
+
+        default:
+            /* this component must be a primitive type */
+            if (! (tag & SEC_ASN1_CONSTRUCTED))
+            {
+                *match = PR_TRUE;
+                return SECSuccess;
+            }
+            break;
+        }
+        break;
+
+    default:
+        /* for all other classes, we check the method based on the template */
+        if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
+             (tag & SEC_ASN1_METHOD_MASK) )
+        {
+            *match = PR_TRUE;
+            return SECSuccess;
+        }
+        /* method does not match between template and component */
+        break;
+    }
+
+    *match = PR_FALSE;
+    return SECSuccess;
+}
+
+#ifdef DEBUG
+
+static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
+{
+    SECStatus rv = SECSuccess;
+    const SEC_ASN1Template* sequenceEntry = NULL;
+    unsigned long seqIndex = 0;
+    unsigned long lastEntryIndex = 0;
+    unsigned long ambiguityIndex = 0;
+    PRBool foundAmbiguity = PR_FALSE;
+
+    do
+    {
+        sequenceEntry = &sequenceTemplate[seqIndex++];
+        if (sequenceEntry->kind)
+        {
+            /* ensure that we don't have an optional component of SEC_ASN1_ANY
+               in the middle of the sequence, since we could not handle it */
+            /* XXX this function needs to dig into the subtemplates to find
+               the next tag */
+            if ( (PR_FALSE == foundAmbiguity) &&
+                 (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
+                 (sequenceEntry->kind & SEC_ASN1_ANY) )
+            {
+                foundAmbiguity = PR_TRUE;
+                ambiguityIndex = seqIndex - 1;
+            }
+        }
+    } while (sequenceEntry->kind);
+
+    lastEntryIndex = seqIndex - 2;
+
+    if (PR_FALSE != foundAmbiguity)
+    {
+        if (ambiguityIndex < lastEntryIndex)
+        {
+            /* ambiguity can only be tolerated on the last entry */
+            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+            rv = SECFailure;
+        }
+    }
+
+    /* XXX also enforce ASN.1 requirement that tags be
+       distinct for consecutive optional components */
+
+    return rv;
+}
+
+#endif
+
+static SECStatus DecodeItem(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena, PRBool checkTag);
+
+static SECStatus DecodeSequence(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem source;
+    SECItem sequence;
+    const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
+    const SEC_ASN1Template* sequenceEntry = NULL;
+    unsigned long seqindex = 0;
+
+#ifdef DEBUG
+    /* for a sequence, we need to validate the template. */
+    rv = CheckSequenceTemplate(sequenceTemplate);
+#endif
+
+    source = *src;
+
+    /* get the sequence */
+    if (SECSuccess == rv)
+    {
+        rv = GetItem(&source, &sequence, PR_FALSE);
+    }
+
+    /* process it */
+    if (SECSuccess == rv)
+    do
+    {
+        sequenceEntry = &sequenceTemplate[seqindex++];
+        if ( (sequenceEntry && sequenceEntry->kind) &&
+             (sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
+        {
+            rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
+        }
+    } while ( (SECSuccess == rv) &&
+              (sequenceEntry->kind &&
+               sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
+    /* we should have consumed all the bytes in the sequence by now
+       unless the caller doesn't care about the rest of the sequence */
+    if (SECSuccess == rv && sequence.len &&
+        sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
+    {
+        /* it isn't 100% clear whether this is a bad DER or a bad template.
+           The problem is that logically, they don't match - there is extra
+           data in the DER that the template doesn't know about */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        rv = SECFailure;
+    }
+
+    return rv;
+}
+
+static SECStatus DecodeInline(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+    const SEC_ASN1Template* inlineTemplate = 
+        SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+    return DecodeItem((void*)((char*)dest + templateEntry->offset),
+                            inlineTemplate, src, arena, checkTag);
+}
+
+static SECStatus DecodePointer(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+    const SEC_ASN1Template* ptrTemplate = 
+        SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+    void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
+    *(void**)((char*)dest + templateEntry->offset) = subdata;
+    if (subdata)
+    {
+        return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
+    }
+    else
+    {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return SECFailure;
+    }
+}
+
+static SECStatus DecodeImplicit(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena)
+{
+    if (templateEntry->kind & SEC_ASN1_POINTER)
+    {
+        return DecodePointer((void*)((char*)dest ),
+                             templateEntry, src, arena, PR_FALSE);
+    }
+    else
+    {
+        return DecodeInline((void*)((char*)dest ),
+                             templateEntry, src, arena, PR_FALSE);
+    }
+}
+
+static SECStatus DecodeChoice(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem choice;
+    const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
+    const SEC_ASN1Template* choiceEntry = NULL;
+    unsigned long choiceindex = 0;
+
+    /* XXX for a choice component, we should validate the template to make
+       sure the tags are distinct, in debug builds. This hasn't been
+       implemented yet */
+    /* rv = CheckChoiceTemplate(sequenceTemplate); */
+
+    /* process it */
+    do
+    {
+        choice = *src;
+        choiceEntry = &choiceTemplate[choiceindex++];
+        if (choiceEntry->kind)
+        {
+            rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
+        }
+    } while ( (SECFailure == rv) && (choiceEntry->kind));
+
+    if (SECFailure == rv)
+    {
+        /* the component didn't match any of the choices */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+    }
+    else
+    {
+        /* set the type in the union here */
+        int *which = (int *)((char *)dest + templateEntry->offset);
+        *which = (int)choiceEntry->size;
+    }
+
+    /* we should have consumed all the bytes by now */
+    /* fail if we have not */
+    if (SECSuccess == rv && choice.len)
+    {
+        /* there is extra data that isn't listed in the template */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        rv = SECFailure;
+    }
+    return rv;
+}
+
+static SECStatus DecodeGroup(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem source;
+    SECItem group;
+    PRUint32 totalEntries = 0;
+    PRUint32 entryIndex = 0;
+    void** entries = NULL;
+
+    const SEC_ASN1Template* subTemplate =
+        SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+
+    source = *src;
+
+    /* get the group */
+    if (SECSuccess == rv)
+    {
+        rv = GetItem(&source, &group, PR_FALSE);
+    }
+
+    /* XXX we should check the subtemplate in debug builds */
+    if (SECSuccess == rv)
+    {
+        /* first, count the number of entries. Benchmarking showed that this
+           counting pass is more efficient than trying to allocate entries as
+           we read the DER, even if allocating many entries at a time
+        */
+        SECItem counter = group;
+        do
+        {
+            SECItem anitem;
+            rv = GetItem(&counter, &anitem, PR_TRUE);
+            if (SECSuccess == rv && (anitem.len) )
+            {
+                totalEntries++;
+            }
+        }  while ( (SECSuccess == rv) && (counter.len) );
+
+        if (SECSuccess == rv)
+        {
+            /* allocate room for pointer array and entries */
+            /* we want to allocate the array even if there is 0 entry */
+            entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
+                                          (totalEntries + 1 ) + /* the extra one is for NULL termination */
+                                          subTemplate->size*totalEntries); 
+
+            if (entries)
+            {
+                entries[totalEntries] = NULL; /* terminate the array */
+            }
+            else
+            {
+                PORT_SetError(SEC_ERROR_NO_MEMORY);
+                rv = SECFailure;
+            }
+            if (SECSuccess == rv)
+            {
+                void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
+                /* and fix the pointers in the array */
+                PRUint32 entriesIndex = 0;
+                for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
+                {
+                    entries[entriesIndex] =
+                        (char*)entriesData + (subTemplate->size*entriesIndex);
+                }
+            }
+        }
+    }
+
+    if (SECSuccess == rv && totalEntries)
+    do
+    {
+        if (!(entryIndex<totalEntries))
+        {
+            rv = SECFailure;
+            break;
+        }
+        rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
+    } while ( (SECSuccess == rv) && (group.len) );
+    /* we should be at the end of the set by now */    
+    /* save the entries where requested */
+    memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
+
+    return rv;
+}
+
+static SECStatus DecodeExplicit(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem subItem;
+    SECItem constructed = *src;
+
+    rv = GetItem(&constructed, &subItem, PR_FALSE);
+
+    if (SECSuccess == rv)
+    {
+        if (templateEntry->kind & SEC_ASN1_POINTER)
+        {
+            rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
+        }
+        else
+        {
+            rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
+        }
+    }
+
+    return rv;
+}
+
+/* new decoder implementation. This is a recursive function */
+
+static SECStatus DecodeItem(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+    SECStatus rv = SECSuccess;
+    SECItem temp;
+    SECItem mark;
+    PRBool pop = PR_FALSE;
+    PRBool decode = PR_TRUE;
+    PRBool save = PR_FALSE;
+    unsigned long kind;
+    PRBool match = PR_TRUE;
+    PRBool optional = PR_FALSE;
+
+    PR_ASSERT(src && dest && templateEntry && arena);
+#if 0
+    if (!src || !dest || !templateEntry || !arena)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        rv = SECFailure;
+    }
+#endif
+
+    if (SECSuccess == rv)
+    {
+        /* do the template validation */
+        kind = templateEntry->kind;
+        optional = (0 != (kind & SEC_ASN1_OPTIONAL));
+        if (!kind)
+        {
+            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+            rv = SECFailure;
+        }
+    }
+
+    if (SECSuccess == rv)
+    {
+#ifdef DEBUG
+        if (kind & SEC_ASN1_DEBUG_BREAK)
+        {
+            /* when debugging the decoder or a template that fails to
+            decode, put SEC_ASN1_DEBUG in the component that gives you
+            trouble. The decoder will then get to this block and assert.
+            If you want to debug the rest of the code, you can set a
+            breakpoint and set dontassert to PR_TRUE, which will let
+            you skip over the assert and continue the debugging session
+            past it. */
+            PRBool dontassert = PR_FALSE;
+            PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
+        }
+#endif
+
+        if ((kind & SEC_ASN1_SKIP) ||
+            (kind & SEC_ASN1_SAVE))
+        {
+            /* if skipping or saving this component, don't decode it */
+            decode = PR_FALSE;
+        }
+    
+        if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
+        {
+            /* if saving this component, or if it is optional, we may not want to
+               move past it, so save the position in case we have to rewind */
+            mark = *src;
+            if (kind & SEC_ASN1_SAVE)
+            {
+                save = PR_TRUE;
+                if (0 == (kind & SEC_ASN1_SKIP))
+                {
+                    /* we will for sure have to rewind when saving this
+                       component and not skipping it. This is true for all
+                       legacy uses of SEC_ASN1_SAVE where the following entry
+                       in the template would causes the same component to be
+                       processed again */
+                    pop = PR_TRUE;
+                }
+            }
+        }
+
+        rv = GetItem(src, &temp, PR_TRUE);
+    }
+
+    if (SECSuccess == rv)
+    {
+        /* now check if the component matches what we expect in the template */
+
+        if (PR_TRUE == checkTag)
+
+        {
+            rv = MatchComponentType(templateEntry, &temp, &match, dest);
+        }
+
+        if ( (SECSuccess == rv) && (PR_TRUE != match) )
+        {
+            if (kind & SEC_ASN1_OPTIONAL)
+            {
+
+                /* the optional component is missing. This is not fatal. */
+                /* Rewind, don't decode, and don't save */
+                pop = PR_TRUE;
+                decode = PR_FALSE;
+                save = PR_FALSE;
+            }
+            else
+            {
+                /* a required component is missing. abort */
+                PORT_SetError(SEC_ERROR_BAD_DER);
+                rv = SECFailure;
+            }
+        }
+    }
+
+    if ((SECSuccess == rv) && (PR_TRUE == decode))
+    {
+        /* the order of processing here is is the tricky part */
+        /* we start with our special cases */
+        /* first, check the component class */
+        if (kind & SEC_ASN1_INLINE)
+        {
+            /* decode inline template */
+            rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
+        }
+
+        else
+        if (kind & SEC_ASN1_EXPLICIT)
+        {
+            rv = DecodeExplicit(dest, templateEntry, &temp, arena);
+        }
+        else
+        if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
+
+              (!(kind & SEC_ASN1_EXPLICIT)))
+        {
+
+            /* decode implicitly tagged components */
+            rv = DecodeImplicit(dest, templateEntry, &temp , arena);
+        }
+        else
+        if (kind & SEC_ASN1_POINTER)
+        {
+            rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
+        }
+        else
+        if (kind & SEC_ASN1_CHOICE)
+        {
+            rv = DecodeChoice(dest, templateEntry, &temp, arena);
+        }
+        else
+        if (kind & SEC_ASN1_ANY)
+        {
+            /* catch-all ANY type, don't decode */
+            save = PR_TRUE;
+            if (kind & SEC_ASN1_INNER)
+            {
+                /* skip the tag and length */
+                SECItem newtemp = temp;
+                rv = GetItem(&newtemp, &temp, PR_FALSE);
+            }
+        }
+        else
+        if (kind & SEC_ASN1_GROUP)
+        {
+            if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
+                 (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
+            {
+                rv = DecodeGroup(dest, templateEntry, &temp , arena);
+            }
+            else
+            {
+                /* a group can only be a SET OF or SEQUENCE OF */
+                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+                rv = SECFailure;
+            }
+        }
+        else
+        if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
+        {
+            /* plain SEQUENCE */
+            rv = DecodeSequence(dest, templateEntry, &temp , arena);
+        }
+        else
+        {
+            /* handle all other types as "save" */
+            /* we should only get here for primitive universal types */
+            SECItem newtemp = temp;
+            rv = GetItem(&newtemp, &temp, PR_FALSE);
+            save = PR_TRUE;
+            if ((SECSuccess == rv) && SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
+            switch (kind & SEC_ASN1_TAGNUM_MASK)
+            {
+            /* special cases of primitive types */
+            case SEC_ASN1_INTEGER:
+                {
+                    /* remove leading zeroes if the caller requested siUnsignedInteger
+                       This is to allow RSA key operations to work */
+                    SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
+                    if (destItem && (siUnsignedInteger == destItem->type))
+                    {
+                        while (temp.len > 1 && temp.data[0] == 0)
+                        {              /* leading 0 */
+                            temp.data++;
+                            temp.len--;
+                        }
+                    }
+                    break;
+                }
+
+            case SEC_ASN1_BIT_STRING:
+                {
+                    /* change the length in the SECItem to be the number of bits */
+                    if (temp.len && temp.data)
+                    {
+                        temp.len = (temp.len-1)*8 - ((*(unsigned char*)temp.data) & 0x7);
+                        temp.data = (unsigned char*)(temp.data+1);
+                    }
+                    break;
+                }
+
+            default:
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    if ((SECSuccess == rv) && (PR_TRUE == save))
+    {
+        SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
+        if (destItem)
+        {
+            /* we leave the type alone in the destination SECItem.
+               If part of the destination was allocated by the decoder, in
+               cases of POINTER, SET OF and SEQUENCE OF, then type is set to
+               siBuffer due to the use of PORT_ArenaZAlloc*/
+            destItem->data = temp.data;
+            destItem->len = temp.len;
+        }
+        else
+        {
+            PORT_SetError(SEC_ERROR_INVALID_ARGS);
+            rv = SECFailure;
+        }
+    }
+
+    if (PR_TRUE == pop)
+    {
+        /* we don't want to move ahead, so restore the position */
+        *src = mark;
+    }
+    return rv;
+}
+
+/* the function below is the public one */
+
+SECStatus SEC_QuickDERDecodeItem(PRArenaPool* arena, void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     const SECItem* src)
+{
+    SECStatus rv = SECSuccess;
+    SECItem newsrc;
+
+    if (!arena || !templateEntry || !src)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        rv = SECFailure;
+    }
+
+    if (SECSuccess == rv)
+    {
+        newsrc = *src;
+        rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
+        if (SECSuccess == rv && newsrc.len)
+        {
+            rv = SECFailure;
+            PORT_SetError(SEC_ERROR_EXTRA_INPUT);
+        }
+    }
+
+    return rv;
+}
+
diff --git a/mozilla/security/nss/lib/util/secalgid.c b/mozilla/security/nss/lib/util/secalgid.c
new file mode 100644
index 0000000..dc6c563
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secalgid.c
@@ -0,0 +1,157 @@
+/* ***** 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 "secoid.h"
+#include "secder.h"	/* XXX remove this when remove the DERTemplate */
+#include "secasn1.h"
+#include "secitem.h"
+#include "secerr.h"
+
+SECOidTag
+SECOID_GetAlgorithmTag(SECAlgorithmID *id)
+{
+    if (id == NULL || id->algorithm.data == NULL)
+	return SEC_OID_UNKNOWN;
+
+    return SECOID_FindOIDTag (&(id->algorithm));
+}
+
+SECStatus
+SECOID_SetAlgorithmID(PRArenaPool *arena, SECAlgorithmID *id, SECOidTag which,
+		      SECItem *params)
+{
+    SECOidData *oiddata;
+    PRBool add_null_param;
+
+    oiddata = SECOID_FindOIDByTag(which);
+    if ( !oiddata ) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return SECFailure;
+    }
+
+    if (SECITEM_CopyItem(arena, &id->algorithm, &oiddata->oid))
+	return SECFailure;
+
+    switch (which) {
+      case SEC_OID_MD2:
+      case SEC_OID_MD4:
+      case SEC_OID_MD5:
+      case SEC_OID_SHA1:
+      case SEC_OID_SHA256:
+      case SEC_OID_SHA384:
+      case SEC_OID_SHA512:
+      case SEC_OID_PKCS1_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
+      case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
+	add_null_param = PR_TRUE;
+	break;
+      default:
+	add_null_param = PR_FALSE;
+	break;
+    }
+
+    if (params) {
+	/*
+	 * I am specifically *not* enforcing the following assertion
+	 * (by following it up with an error and a return of failure)
+	 * because I do not want to introduce any change in the current
+	 * behavior.  But I do want for us to notice if the following is
+	 * ever true, because I do not think it should be so and probably
+	 * signifies an error/bug somewhere.
+	 */
+	PORT_Assert(!add_null_param || (params->len == 2
+					&& params->data[0] == SEC_ASN1_NULL
+					&& params->data[1] == 0)); 
+	if (SECITEM_CopyItem(arena, &id->parameters, params)) {
+	    return SECFailure;
+	}
+    } else {
+	/*
+	 * Again, this is not considered an error.  But if we assume
+	 * that nobody tries to set the parameters field themselves
+	 * (but always uses this routine to do that), then we should
+	 * not hit the following assertion.  Unless they forgot to zero
+	 * the structure, which could also be a bad (and wrong) thing.
+	 */
+	PORT_Assert(id->parameters.data == NULL);
+
+	if (add_null_param) {
+	    (void) SECITEM_AllocItem(arena, &id->parameters, 2);
+	    if (id->parameters.data == NULL) {
+		return SECFailure;
+	    }
+	    id->parameters.data[0] = SEC_ASN1_NULL;
+	    id->parameters.data[1] = 0;
+	}
+    }
+
+    return SECSuccess;
+}
+
+SECStatus
+SECOID_CopyAlgorithmID(PRArenaPool *arena, SECAlgorithmID *to, SECAlgorithmID *from)
+{
+    SECStatus rv;
+
+    rv = SECITEM_CopyItem(arena, &to->algorithm, &from->algorithm);
+    if (rv) return rv;
+    rv = SECITEM_CopyItem(arena, &to->parameters, &from->parameters);
+    return rv;
+}
+
+void SECOID_DestroyAlgorithmID(SECAlgorithmID *algid, PRBool freeit)
+{
+    SECITEM_FreeItem(&algid->parameters, PR_FALSE);
+    SECITEM_FreeItem(&algid->algorithm, PR_FALSE);
+    if(freeit == PR_TRUE)
+        PORT_Free(algid);
+}
+
+SECComparison
+SECOID_CompareAlgorithmID(SECAlgorithmID *a, SECAlgorithmID *b)
+{
+    SECComparison rv;
+
+    rv = SECITEM_CompareItem(&a->algorithm, &b->algorithm);
+    if (rv) return rv;
+    rv = SECITEM_CompareItem(&a->parameters, &b->parameters);
+    return rv;
+}
diff --git a/mozilla/security/nss/lib/util/secasn1.h b/mozilla/security/nss/lib/util/secasn1.h
new file mode 100644
index 0000000..fc2dceb
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secasn1.h
@@ -0,0 +1,326 @@
+/* ***** 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 ***** */
+
+/*
+ * Support for encoding/decoding of ASN.1 using BER/DER (Basic/Distinguished
+ * Encoding Rules).  The routines are found in and used extensively by the
+ * security library, but exported for other use.
+ *
+ * $Id: secasn1.h,v 1.17 2009/09/19 00:03:17 wtc%google.com Exp $
+ */
+
+#ifndef _SECASN1_H_
+#define _SECASN1_H_
+
+#include "utilrename.h"
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secasn1t.h"
+
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/*
+ * XXX These function prototypes need full, explanatory comments.
+ */
+
+/*
+** Decoding.
+*/
+
+extern SEC_ASN1DecoderContext *SEC_ASN1DecoderStart(PLArenaPool *pool,
+						    void *dest,
+						    const SEC_ASN1Template *t);
+
+/* XXX char or unsigned char? */
+extern SECStatus SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
+				       const char *buf,
+				       unsigned long len);
+
+extern SECStatus SEC_ASN1DecoderFinish(SEC_ASN1DecoderContext *cx);
+
+/* Higher level code detected an error, abort the rest of the processing */
+extern void SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error);
+
+extern void SEC_ASN1DecoderSetFilterProc(SEC_ASN1DecoderContext *cx,
+					 SEC_ASN1WriteProc fn,
+					 void *arg, PRBool no_store);
+
+extern void SEC_ASN1DecoderClearFilterProc(SEC_ASN1DecoderContext *cx);
+
+extern void SEC_ASN1DecoderSetNotifyProc(SEC_ASN1DecoderContext *cx,
+					 SEC_ASN1NotifyProc fn,
+					 void *arg);
+
+extern void SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx);
+
+extern SECStatus SEC_ASN1Decode(PLArenaPool *pool, void *dest,
+				const SEC_ASN1Template *t,
+				const char *buf, long len);
+
+/* Both classic ASN.1 and QuickDER have a feature that removes leading zeroes
+   out of SEC_ASN1_INTEGER if the caller sets siUnsignedInteger in the type
+   field of the target SECItem prior to calling the decoder. Otherwise, the
+   type field is ignored and untouched. For SECItem that are dynamically
+   allocated (from POINTER, SET OF, SEQUENCE OF) the decoder sets the type
+   field to siBuffer. */
+
+extern SECStatus SEC_ASN1DecodeItem(PLArenaPool *pool, void *dest,
+				    const SEC_ASN1Template *t,
+				    const SECItem *src);
+
+extern SECStatus SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     const SECItem* src);
+
+/*
+** Encoding.
+*/
+
+extern SEC_ASN1EncoderContext *SEC_ASN1EncoderStart(const void *src,
+						    const SEC_ASN1Template *t,
+						    SEC_ASN1WriteProc fn,
+						    void *output_arg);
+
+/* XXX char or unsigned char? */
+extern SECStatus SEC_ASN1EncoderUpdate(SEC_ASN1EncoderContext *cx,
+				       const char *buf,
+				       unsigned long len);
+
+extern void SEC_ASN1EncoderFinish(SEC_ASN1EncoderContext *cx);
+
+/* Higher level code detected an error, abort the rest of the processing */
+extern void SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error);
+
+extern void SEC_ASN1EncoderSetNotifyProc(SEC_ASN1EncoderContext *cx,
+					 SEC_ASN1NotifyProc fn,
+					 void *arg);
+
+extern void SEC_ASN1EncoderClearNotifyProc(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderSetStreaming(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderClearStreaming(SEC_ASN1EncoderContext *cx);
+
+extern void sec_ASN1EncoderSetDER(SEC_ASN1EncoderContext *cx);
+
+extern void sec_ASN1EncoderClearDER(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderSetTakeFromBuf(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderClearTakeFromBuf(SEC_ASN1EncoderContext *cx);
+
+extern SECStatus SEC_ASN1Encode(const void *src, const SEC_ASN1Template *t,
+				SEC_ASN1WriteProc output_proc,
+				void *output_arg);
+
+/*
+ * If both pool and dest are NULL, the caller should free the returned SECItem
+ * with a SECITEM_FreeItem(..., PR_TRUE) call.  If pool is NULL but dest is
+ * not NULL, the caller should free the data buffer pointed to by dest with a
+ * SECITEM_FreeItem(dest, PR_FALSE) or PORT_Free(dest->data) call.
+ */
+extern SECItem * SEC_ASN1EncodeItem(PLArenaPool *pool, SECItem *dest,
+				    const void *src, const SEC_ASN1Template *t);
+
+extern SECItem * SEC_ASN1EncodeInteger(PLArenaPool *pool,
+				       SECItem *dest, long value);
+
+extern SECItem * SEC_ASN1EncodeUnsignedInteger(PLArenaPool *pool,
+					       SECItem *dest,
+					       unsigned long value);
+
+extern SECStatus SEC_ASN1DecodeInteger(SECItem *src,
+				       unsigned long *value);
+
+/*
+** Utilities.
+*/
+
+/*
+ * We have a length that needs to be encoded; how many bytes will the
+ * encoding take?
+ */
+extern int SEC_ASN1LengthLength (unsigned long len);
+
+/* encode the length and return the number of bytes we encoded. Buffer
+ * must be pre allocated  */
+extern int SEC_ASN1EncodeLength(unsigned char *buf,int value);
+
+/*
+ * Find the appropriate subtemplate for the given template.
+ * This may involve calling a "chooser" function, or it may just
+ * be right there.  In either case, it is expected to *have* a
+ * subtemplate; this is asserted in debug builds (in non-debug
+ * builds, NULL will be returned).
+ *
+ * "thing" is a pointer to the structure being encoded/decoded
+ * "encoding", when true, means that we are in the process of encoding
+ *	(as opposed to in the process of decoding)
+ */
+extern const SEC_ASN1Template *
+SEC_ASN1GetSubtemplate (const SEC_ASN1Template *inTemplate, void *thing,
+			PRBool encoding);
+
+/* whether the template is for a primitive type or a choice of
+ * primitive types
+ */
+extern PRBool SEC_ASN1IsTemplateSimple(const SEC_ASN1Template *theTemplate);
+
+/************************************************************************/
+
+/*
+ * Generic Templates
+ * One for each of the simple types, plus a special one for ANY, plus:
+ *	- a pointer to each one of those
+ *	- a set of each one of those
+ *	- a sequence of each one of those
+ *
+ * Note that these are alphabetical (case insensitive); please add new
+ * ones in the appropriate place.
+ */
+
+extern const SEC_ASN1Template SEC_AnyTemplate[];
+extern const SEC_ASN1Template SEC_BitStringTemplate[];
+extern const SEC_ASN1Template SEC_BMPStringTemplate[];
+extern const SEC_ASN1Template SEC_BooleanTemplate[];
+extern const SEC_ASN1Template SEC_EnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_GeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_IA5StringTemplate[];
+extern const SEC_ASN1Template SEC_IntegerTemplate[];
+extern const SEC_ASN1Template SEC_NullTemplate[];
+extern const SEC_ASN1Template SEC_ObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_OctetStringTemplate[];
+extern const SEC_ASN1Template SEC_PrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_T61StringTemplate[];
+extern const SEC_ASN1Template SEC_UniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_UTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_UTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_VisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_PointerToAnyTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBitStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBooleanTemplate[];
+extern const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_PointerToIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToIntegerTemplate[];
+extern const SEC_ASN1Template SEC_PointerToNullTemplate[];
+extern const SEC_ASN1Template SEC_PointerToObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_PointerToOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToT61StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToVisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_SequenceOfAnyTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBitStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBooleanTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfIntegerTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfNullTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfT61StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_SetOfAnyTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBitStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBooleanTemplate[];
+extern const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_SetOfIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfIntegerTemplate[];
+extern const SEC_ASN1Template SEC_SetOfNullTemplate[];
+extern const SEC_ASN1Template SEC_SetOfObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_SetOfOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfT61StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfVisibleStringTemplate[];
+
+/*
+ * Template for skipping a subitem; this only makes sense when decoding.
+ */
+extern const SEC_ASN1Template SEC_SkipTemplate[];
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs.  Sigh.
+*/
+SEC_ASN1_CHOOSER_DECLARE(SEC_AnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BMPStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BooleanTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BitStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_GeneralizedTimeTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_IA5StringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_IntegerTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_NullTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_ObjectIDTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_OctetStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UTCTimeTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UTF8StringTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToAnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToOctetStringTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_SetOfAnyTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_EnumeratedTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToEnumeratedTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SequenceOfAnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SequenceOfObjectIDTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SkipTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UniversalStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PrintableStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_T61StringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToGeneralizedTimeTemplate)
+SEC_END_PROTOS
+#endif /* _SECASN1_H_ */
diff --git a/mozilla/security/nss/lib/util/secasn1d.c b/mozilla/security/nss/lib/util/secasn1d.c
new file mode 100644
index 0000000..a1323f2
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secasn1d.c
@@ -0,0 +1,3269 @@
+/* ***** 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 ***** */
+
+/*
+ * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id: secasn1d.c,v 1.39 2009/04/07 23:52:10 julien.pierre.boogz%sun.com Exp $
+ */
+
+/* #define DEBUG_ASN1D_STATES 1 */
+
+#ifdef DEBUG_ASN1D_STATES
+#include <stdio.h>
+#define PR_Assert sec_asn1d_Assert
+#endif
+
+#include "secasn1.h"
+#include "secerr.h"
+
+typedef enum {
+    beforeIdentifier,
+    duringIdentifier,
+    afterIdentifier,
+    beforeLength,
+    duringLength,
+    afterLength,
+    beforeBitString,
+    duringBitString,
+    duringConstructedString,
+    duringGroup,
+    duringLeaf,
+    duringSaveEncoding,
+    duringSequence,
+    afterConstructedString,
+    afterGroup,
+    afterExplicit,
+    afterImplicit,
+    afterInline,
+    afterPointer,
+    afterSaveEncoding,
+    beforeEndOfContents,
+    duringEndOfContents,
+    afterEndOfContents,
+    beforeChoice,
+    duringChoice,
+    afterChoice,
+    notInUse
+} sec_asn1d_parse_place;
+
+#ifdef DEBUG_ASN1D_STATES
+static const char * const place_names[] = {
+    "beforeIdentifier",
+    "duringIdentifier",
+    "afterIdentifier",
+    "beforeLength",
+    "duringLength",
+    "afterLength",
+    "beforeBitString",
+    "duringBitString",
+    "duringConstructedString",
+    "duringGroup",
+    "duringLeaf",
+    "duringSaveEncoding",
+    "duringSequence",
+    "afterConstructedString",
+    "afterGroup",
+    "afterExplicit",
+    "afterImplicit",
+    "afterInline",
+    "afterPointer",
+    "afterSaveEncoding",
+    "beforeEndOfContents",
+    "duringEndOfContents",
+    "afterEndOfContents",
+    "beforeChoice",
+    "duringChoice",
+    "afterChoice",
+    "notInUse"
+};
+
+static const char * const class_names[] = {
+    "UNIVERSAL",
+    "APPLICATION",
+    "CONTEXT_SPECIFIC",
+    "PRIVATE"
+};
+
+static const char * const method_names[] = { "PRIMITIVE", "CONSTRUCTED" };
+
+static const char * const type_names[] = {
+    "END_OF_CONTENTS",
+    "BOOLEAN",
+    "INTEGER",
+    "BIT_STRING",
+    "OCTET_STRING",
+    "NULL",
+    "OBJECT_ID",
+    "OBJECT_DESCRIPTOR",
+    "(type 08)",
+    "REAL",
+    "ENUMERATED",
+    "EMBEDDED",
+    "UTF8_STRING",
+    "(type 0d)",
+    "(type 0e)",
+    "(type 0f)",
+    "SEQUENCE",
+    "SET",
+    "NUMERIC_STRING",
+    "PRINTABLE_STRING",
+    "T61_STRING",
+    "VIDEOTEXT_STRING",
+    "IA5_STRING",
+    "UTC_TIME",
+    "GENERALIZED_TIME",
+    "GRAPHIC_STRING",
+    "VISIBLE_STRING",
+    "GENERAL_STRING",
+    "UNIVERSAL_STRING",
+    "(type 1d)",
+    "BMP_STRING",
+    "HIGH_TAG_VALUE"
+};
+
+static const char * const flag_names[] = { /* flags, right to left */
+    "OPTIONAL",
+    "EXPLICIT",
+    "ANY",
+    "INLINE",
+    "POINTER",
+    "GROUP",
+    "DYNAMIC",
+    "SKIP",
+    "INNER",
+    "SAVE",
+    "",            /* decoder ignores "MAY_STREAM", */
+    "SKIP_REST",
+    "CHOICE",
+    "NO_STREAM",
+    "DEBUG_BREAK",
+    "unknown 08",
+    "unknown 10",
+    "unknown 20",
+    "unknown 40",
+    "unknown 80"
+};
+
+static int /* bool */
+formatKind(unsigned long kind, char * buf)
+{
+    int i;
+    unsigned long k = kind & SEC_ASN1_TAGNUM_MASK;
+    unsigned long notag = kind & (SEC_ASN1_CHOICE | SEC_ASN1_POINTER |
+        SEC_ASN1_INLINE | SEC_ASN1_ANY | SEC_ASN1_SAVE);
+
+    buf[0] = 0;
+    if ((kind & SEC_ASN1_CLASS_MASK) != SEC_ASN1_UNIVERSAL) {
+        sprintf(buf, " %s", class_names[(kind & SEC_ASN1_CLASS_MASK) >> 6] );
+        buf += strlen(buf);
+    }
+    if (kind & SEC_ASN1_METHOD_MASK) {
+        sprintf(buf, " %s", method_names[1]);
+        buf += strlen(buf);
+    }
+    if ((kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL) {
+        if (k || !notag) {
+            sprintf(buf, " %s", type_names[k] );
+            if ((k == SEC_ASN1_SET || k == SEC_ASN1_SEQUENCE) &&
+                (kind & SEC_ASN1_GROUP)) {
+                buf += strlen(buf);
+                sprintf(buf, "_OF");
+            }
+        }
+    } else {
+        sprintf(buf, " [%d]", k);
+    }
+    buf += strlen(buf);
+
+    for (k = kind >> 8, i = 0; k; k >>= 1, ++i) {
+        if (k & 1) {
+            sprintf(buf, " %s", flag_names[i]);
+            buf += strlen(buf);
+        }
+    }
+    return notag != 0;
+}
+
+#endif /* DEBUG_ASN1D_STATES */
+
+typedef enum {
+    allDone,
+    decodeError,
+    keepGoing,
+    needBytes
+} sec_asn1d_parse_status;
+
+struct subitem {
+    const void *data;
+    unsigned long len;		/* only used for substrings */
+    struct subitem *next;
+};
+
+typedef struct sec_asn1d_state_struct {
+    SEC_ASN1DecoderContext *top;
+    const SEC_ASN1Template *theTemplate;
+    void *dest;
+
+    void *our_mark;	/* free on completion */
+
+    struct sec_asn1d_state_struct *parent;	/* aka prev */
+    struct sec_asn1d_state_struct *child;	/* aka next */
+
+    sec_asn1d_parse_place place;
+
+    /*
+     * XXX explain the next fields as clearly as possible...
+     */
+    unsigned char found_tag_modifiers;
+    unsigned char expect_tag_modifiers;
+    unsigned long check_tag_mask;
+    unsigned long found_tag_number;
+    unsigned long expect_tag_number;
+    unsigned long underlying_kind;
+
+    unsigned long contents_length;
+    unsigned long pending;
+    unsigned long consumed;
+
+    int depth;
+
+    /*
+     * Bit strings have their length adjusted -- the first octet of the
+     * contents contains a value between 0 and 7 which says how many bits
+     * at the end of the octets are not actually part of the bit string;
+     * when parsing bit strings we put that value here because we need it
+     * later, for adjustment of the length (when the whole string is done).
+     */
+    unsigned int bit_string_unused_bits;
+
+    /*
+     * The following are used for indefinite-length constructed strings.
+     */
+    struct subitem *subitems_head;
+    struct subitem *subitems_tail;
+
+    PRPackedBool
+	allocate,	/* when true, need to allocate the destination */
+	endofcontents,	/* this state ended up parsing end-of-contents octets */
+	explicit,	/* we are handling an explicit header */
+	indefinite,	/* the current item has indefinite-length encoding */
+	missing,	/* an optional field that was not present */
+	optional,	/* the template says this field may be omitted */
+	substring;	/* this is a substring of a constructed string */
+
+} sec_asn1d_state;
+
+#define IS_HIGH_TAG_NUMBER(n)	((n) == SEC_ASN1_HIGH_TAG_NUMBER)
+#define LAST_TAG_NUMBER_BYTE(b)	(((b) & 0x80) == 0)
+#define TAG_NUMBER_BITS		7
+#define TAG_NUMBER_MASK		0x7f
+
+#define LENGTH_IS_SHORT_FORM(b)	(((b) & 0x80) == 0)
+#define LONG_FORM_LENGTH(b)	((b) & 0x7f)
+
+#define HIGH_BITS(field,cnt)	((field) >> ((sizeof(field) * 8) - (cnt)))
+
+
+/*
+ * An "outsider" will have an opaque pointer to this, created by calling
+ * SEC_ASN1DecoderStart().  It will be passed back in to all subsequent
+ * calls to SEC_ASN1DecoderUpdate(), and when done it is passed to
+ * SEC_ASN1DecoderFinish().
+ */
+struct sec_DecoderContext_struct {
+    PRArenaPool *our_pool;		/* for our internal allocs */
+    PRArenaPool *their_pool;		/* for destination structure allocs */
+#ifdef SEC_ASN1D_FREE_ON_ERROR		/*
+					 * XXX see comment below (by same
+					 * ifdef) that explains why this
+					 * does not work (need more smarts
+					 * in order to free back to mark)
+					 */
+    /*
+     * XXX how to make their_mark work in the case where they do NOT
+     * give us a pool pointer?
+     */
+    void *their_mark;			/* free on error */
+#endif
+
+    sec_asn1d_state *current;
+    sec_asn1d_parse_status status;
+
+    SEC_ASN1NotifyProc notify_proc;	/* call before/after handling field */
+    void *notify_arg;			/* argument to notify_proc */
+    PRBool during_notify;		/* true during call to notify_proc */
+
+    SEC_ASN1WriteProc filter_proc;	/* pass field bytes to this  */
+    void *filter_arg;			/* argument to that function */
+    PRBool filter_only;			/* do not allocate/store fields */
+};
+
+
+/*
+ * XXX this is a fairly generic function that may belong elsewhere
+ */
+static void *
+sec_asn1d_alloc (PRArenaPool *poolp, unsigned long len)
+{
+    void *thing;
+
+    if (poolp != NULL) {
+	/*
+	 * Allocate from the pool.
+	 */
+	thing = PORT_ArenaAlloc (poolp, len);
+    } else {
+	/*
+	 * Allocate generically.
+	 */
+	thing = PORT_Alloc (len);
+    }
+
+    return thing;
+}
+
+
+/*
+ * XXX this is a fairly generic function that may belong elsewhere
+ */
+static void *
+sec_asn1d_zalloc (PRArenaPool *poolp, unsigned long len)
+{
+    void *thing;
+
+    thing = sec_asn1d_alloc (poolp, len);
+    if (thing != NULL)
+	PORT_Memset (thing, 0, len);
+    return thing;
+}
+
+
+static sec_asn1d_state *
+sec_asn1d_push_state (SEC_ASN1DecoderContext *cx,
+		      const SEC_ASN1Template *theTemplate,
+		      void *dest, PRBool new_depth)
+{
+    sec_asn1d_state *state, *new_state;
+
+    state = cx->current;
+
+    PORT_Assert (state == NULL || state->child == NULL);
+
+    if (state != NULL) {
+	PORT_Assert (state->our_mark == NULL);
+	state->our_mark = PORT_ArenaMark (cx->our_pool);
+    }
+
+    new_state = (sec_asn1d_state*)sec_asn1d_zalloc (cx->our_pool, 
+						    sizeof(*new_state));
+    if (new_state == NULL) {
+	goto loser;
+    }
+
+    new_state->top         = cx;
+    new_state->parent      = state;
+    new_state->theTemplate = theTemplate;
+    new_state->place       = notInUse;
+    if (dest != NULL)
+	new_state->dest = (char *)dest + theTemplate->offset;
+
+    if (state != NULL) {
+	new_state->depth = state->depth;
+	if (new_depth) {
+	    if (++new_state->depth > SEC_ASN1D_MAX_DEPTH) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		goto loser;
+	    }
+	}
+	state->child = new_state;
+    }
+
+    cx->current = new_state;
+    return new_state;
+
+loser:
+    cx->status = decodeError;
+    if (state != NULL) {
+	PORT_ArenaRelease(cx->our_pool, state->our_mark);
+	state->our_mark = NULL;
+    }
+    return NULL;
+}
+
+
+static void
+sec_asn1d_scrub_state (sec_asn1d_state *state)
+{
+    /*
+     * Some default "scrubbing".
+     * XXX right set of initializations?
+     */
+    state->place = beforeIdentifier;
+    state->endofcontents = PR_FALSE;
+    state->indefinite = PR_FALSE;
+    state->missing = PR_FALSE;
+    PORT_Assert (state->consumed == 0);
+}
+
+
+static void
+sec_asn1d_notify_before (SEC_ASN1DecoderContext *cx, void *dest, int depth)
+{
+    if (cx->notify_proc == NULL)
+	return;
+
+    cx->during_notify = PR_TRUE;
+    (* cx->notify_proc) (cx->notify_arg, PR_TRUE, dest, depth);
+    cx->during_notify = PR_FALSE;
+}
+
+
+static void
+sec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth)
+{
+    if (cx->notify_proc == NULL)
+	return;
+
+    cx->during_notify = PR_TRUE;
+    (* cx->notify_proc) (cx->notify_arg, PR_FALSE, dest, depth);
+    cx->during_notify = PR_FALSE;
+}
+
+
+static sec_asn1d_state *
+sec_asn1d_init_state_based_on_template (sec_asn1d_state *state)
+{
+    PRBool explicit, optional, universal;
+    unsigned char expect_tag_modifiers;
+    unsigned long encode_kind, under_kind;
+    unsigned long check_tag_mask, expect_tag_number;
+
+
+    /* XXX Check that both of these tests are really needed/appropriate. */
+    if (state == NULL || state->top->status == decodeError)
+	return state;
+
+    encode_kind = state->theTemplate->kind;
+
+    if (encode_kind & SEC_ASN1_SAVE) {
+	/*
+	 * This is a "magic" field that saves away all bytes, allowing
+	 * the immediately following field to still be decoded from this
+	 * same spot -- sort of a fork.
+	 */
+	/* check that there are no extraneous bits */
+	PORT_Assert (encode_kind == SEC_ASN1_SAVE);
+	if (state->top->filter_only) {
+	    /*
+	     * If we are not storing, then we do not do the SAVE field
+	     * at all.  Just move ahead to the "real" field instead,
+	     * doing the appropriate notify calls before and after.
+	     */
+	    sec_asn1d_notify_after (state->top, state->dest, state->depth);
+	    /*
+	     * Since we are not storing, allow for our current dest value
+	     * to be NULL.  (This might not actually occur, but right now I
+	     * cannot convince myself one way or the other.)  If it is NULL,
+	     * assume that our parent dest can help us out.
+	     */
+	    if (state->dest == NULL)
+		state->dest = state->parent->dest;
+	    else
+		state->dest = (char *)state->dest - state->theTemplate->offset;
+	    state->theTemplate++;
+	    if (state->dest != NULL)
+		state->dest = (char *)state->dest + state->theTemplate->offset;
+	    sec_asn1d_notify_before (state->top, state->dest, state->depth);
+	    encode_kind = state->theTemplate->kind;
+	    PORT_Assert ((encode_kind & SEC_ASN1_SAVE) == 0);
+	} else {
+	    sec_asn1d_scrub_state (state);
+	    state->place = duringSaveEncoding;
+	    state = sec_asn1d_push_state (state->top, SEC_AnyTemplate,
+					  state->dest, PR_FALSE);
+	    if (state != NULL)
+		state = sec_asn1d_init_state_based_on_template (state);
+	    return state;
+	}
+    }
+
+
+    universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+		? PR_TRUE : PR_FALSE;
+
+    explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+    optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+    PORT_Assert (!(explicit && universal));	/* bad templates */
+
+    encode_kind &= ~SEC_ASN1_DYNAMIC;
+    encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+    if (encode_kind & SEC_ASN1_CHOICE) {
+#if 0	/* XXX remove? */
+      sec_asn1d_state *child = sec_asn1d_push_state(state->top, state->theTemplate, state->dest, PR_FALSE);
+      if ((sec_asn1d_state *)NULL == child) {
+        return (sec_asn1d_state *)NULL;
+      }
+
+      child->allocate = state->allocate;
+      child->place = beforeChoice;
+      return child;
+#else
+      state->place = beforeChoice;
+      return state;
+#endif
+    }
+
+    if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
+							      && !explicit)) {
+	const SEC_ASN1Template *subt;
+	void *dest;
+	PRBool child_allocate;
+
+	PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
+
+	sec_asn1d_scrub_state (state);
+	child_allocate = PR_FALSE;
+
+	if (encode_kind & SEC_ASN1_POINTER) {
+	    /*
+	     * A POINTER means we need to allocate the destination for
+	     * this field.  But, since it may also be an optional field,
+	     * we defer the allocation until later; we just record that
+	     * it needs to be done.
+	     *
+	     * There are two possible scenarios here -- one is just a
+	     * plain POINTER (kind of like INLINE, except with allocation)
+	     * and the other is an implicitly-tagged POINTER.  We don't
+	     * need to do anything special here for the two cases, but
+	     * since the template definition can be tricky, we do check
+	     * that there are no extraneous bits set in encode_kind.
+	     *
+	     * XXX The same conditions which assert should set an error.
+	     */
+	    if (universal) {
+		/*
+		 * "universal" means this entry is a standalone POINTER;
+		 * there should be no other bits set in encode_kind.
+		 */
+		PORT_Assert (encode_kind == SEC_ASN1_POINTER);
+	    } else {
+		/*
+		 * If we get here we have an implicitly-tagged field
+		 * that needs to be put into a POINTER.  The subtemplate
+		 * will determine how to decode the field, but encode_kind
+		 * describes the (implicit) tag we are looking for.
+		 * The non-tag bits of encode_kind will be ignored by
+		 * the code below; none of them should be set, however,
+		 * except for the POINTER bit itself -- so check that.
+		 */
+		PORT_Assert ((encode_kind & ~SEC_ASN1_TAG_MASK)
+			     == SEC_ASN1_POINTER);
+	    }
+	    if (!state->top->filter_only)
+		child_allocate = PR_TRUE;
+	    dest = NULL;
+	    state->place = afterPointer;
+	} else {
+	    dest = state->dest;
+	    if (encode_kind & SEC_ASN1_INLINE) {
+		/* check that there are no extraneous bits */
+		PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
+		state->place = afterInline;
+	    } else {
+		state->place = afterImplicit;
+	    }
+	}
+
+	state->optional = optional;
+	subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest, PR_FALSE);
+	state = sec_asn1d_push_state (state->top, subt, dest, PR_FALSE);
+	if (state == NULL)
+	    return NULL;
+
+	state->allocate = child_allocate;
+
+	if (universal) {
+	    state = sec_asn1d_init_state_based_on_template (state);
+	    if (state != NULL) {
+		/*
+		 * If this field is optional, we need to record that on
+		 * the pushed child so it won't fail if the field isn't
+		 * found.  I can't think of a way that this new state
+		 * could already have optional set (which we would wipe
+		 * out below if our local optional is not set) -- but
+		 * just to be sure, assert that it isn't set.
+		 */
+		PORT_Assert (!state->optional);
+		state->optional = optional;
+	    }
+	    return state;
+	}
+
+	under_kind = state->theTemplate->kind;
+	under_kind &= ~SEC_ASN1_MAY_STREAM;
+    } else if (explicit) {
+	/*
+	 * For explicit, we only need to match the encoding tag next,
+	 * then we will push another state to handle the entire inner
+	 * part.  In this case, there is no underlying kind which plays
+	 * any part in the determination of the outer, explicit tag.
+	 * So we just set under_kind to 0, which is not a valid tag,
+	 * and the rest of the tag matching stuff should be okay.
+	 */
+	under_kind = 0;
+    } else {
+	/*
+	 * Nothing special; the underlying kind and the given encoding
+	 * information are the same.
+	 */
+	under_kind = encode_kind;
+    }
+
+    /* XXX is this the right set of bits to test here? */
+    PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
+				| SEC_ASN1_MAY_STREAM
+				| SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);
+
+    if (encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) {
+	PORT_Assert (encode_kind == under_kind);
+	if (encode_kind & SEC_ASN1_SKIP) {
+	    PORT_Assert (!optional);
+	    PORT_Assert (encode_kind == SEC_ASN1_SKIP);
+	    state->dest = NULL;
+	}
+	check_tag_mask = 0;
+	expect_tag_modifiers = 0;
+	expect_tag_number = 0;
+    } else {
+	check_tag_mask = SEC_ASN1_TAG_MASK;
+	expect_tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK
+				& ~SEC_ASN1_TAGNUM_MASK;
+	/*
+	 * XXX This assumes only single-octet identifiers.  To handle
+	 * the HIGH TAG form we would need to do some more work, especially
+	 * in how to specify them in the template, because right now we
+	 * do not provide a way to specify more *tag* bits in encode_kind.
+	 */
+	expect_tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
+
+	switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
+	  case SEC_ASN1_SET:
+	    /*
+	     * XXX A plain old SET (as opposed to a SET OF) is not implemented.
+	     * If it ever is, remove this assert...
+	     */
+	    PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
+	    /* fallthru */
+	  case SEC_ASN1_SEQUENCE:
+	    expect_tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+	    break;
+	  case SEC_ASN1_BIT_STRING:
+	  case SEC_ASN1_BMP_STRING:
+	  case SEC_ASN1_GENERALIZED_TIME:
+	  case SEC_ASN1_IA5_STRING:
+	  case SEC_ASN1_OCTET_STRING:
+	  case SEC_ASN1_PRINTABLE_STRING:
+	  case SEC_ASN1_T61_STRING:
+	  case SEC_ASN1_UNIVERSAL_STRING:
+	  case SEC_ASN1_UTC_TIME:
+	  case SEC_ASN1_UTF8_STRING:
+	  case SEC_ASN1_VISIBLE_STRING:
+	    check_tag_mask &= ~SEC_ASN1_CONSTRUCTED;
+	    break;
+	}
+    }
+
+    state->check_tag_mask = check_tag_mask;
+    state->expect_tag_modifiers = expect_tag_modifiers;
+    state->expect_tag_number = expect_tag_number;
+    state->underlying_kind = under_kind;
+    state->explicit = explicit;
+    state->optional = optional;
+
+    sec_asn1d_scrub_state (state);
+
+    return state;
+}
+
+static sec_asn1d_state *
+sec_asn1d_get_enclosing_construct(sec_asn1d_state *state)
+{
+    for (state = state->parent; state; state = state->parent) {
+	sec_asn1d_parse_place place = state->place;
+	if (place != afterImplicit      &&
+	    place != afterPointer       &&
+	    place != afterInline        &&
+	    place != afterSaveEncoding  &&
+	    place != duringSaveEncoding &&
+	    place != duringChoice) {
+
+            /* we've walked up the stack to a state that represents
+            ** the enclosing construct.  
+	    */
+            break;
+	}
+    }
+    return state;
+}
+
+static PRBool
+sec_asn1d_parent_allows_EOC(sec_asn1d_state *state)
+{
+    /* get state of enclosing construct. */
+    state = sec_asn1d_get_enclosing_construct(state);
+    if (state) {
+	sec_asn1d_parse_place place = state->place;
+        /* Is it one of the types that permits an unexpected EOC? */
+	int eoc_permitted = 
+	    (place == duringGroup ||
+	     place == duringConstructedString ||
+	     state->child->optional);
+	return (state->indefinite && eoc_permitted) ? PR_TRUE : PR_FALSE;
+    }
+    return PR_FALSE;
+}
+
+static unsigned long
+sec_asn1d_parse_identifier (sec_asn1d_state *state,
+			    const char *buf, unsigned long len)
+{
+    unsigned char byte;
+    unsigned char tag_number;
+
+    PORT_Assert (state->place == beforeIdentifier);
+
+    if (len == 0) {
+	state->top->status = needBytes;
+	return 0;
+    }
+
+    byte = (unsigned char) *buf;
+#ifdef DEBUG_ASN1D_STATES
+    {
+        char kindBuf[256];
+        formatKind(byte, kindBuf);
+        printf("Found tag %02x %s\n", byte, kindBuf);
+    }
+#endif
+    tag_number = byte & SEC_ASN1_TAGNUM_MASK;
+
+    if (IS_HIGH_TAG_NUMBER (tag_number)) {
+	state->place = duringIdentifier;
+	state->found_tag_number = 0;
+	/*
+	 * Actually, we have no idea how many bytes are pending, but we
+	 * do know that it is at least 1.  That is all we know; we have
+	 * to look at each byte to know if there is another, etc.
+	 */
+	state->pending = 1;
+    } else {
+	if (byte == 0 && sec_asn1d_parent_allows_EOC(state)) {
+	    /*
+	     * Our parent has indefinite-length encoding, and the
+	     * entire tag found is 0, so it seems that we have hit the
+	     * end-of-contents octets.  To handle this, we just change
+	     * our state to that which expects to get the bytes of the
+	     * end-of-contents octets and let that code re-read this byte
+	     * so that our categorization of field types is correct.
+	     * After that, our parent will then deal with everything else.
+	     */
+	    state->place = duringEndOfContents;
+	    state->pending = 2;
+	    state->found_tag_number = 0;
+	    state->found_tag_modifiers = 0;
+	    /*
+	     * We might be an optional field that is, as we now find out,
+	     * missing.  Give our parent a clue that this happened.
+	     */
+	    if (state->optional)
+		state->missing = PR_TRUE;
+	    return 0;
+	}
+	state->place = afterIdentifier;
+	state->found_tag_number = tag_number;
+    }
+    state->found_tag_modifiers = byte & ~SEC_ASN1_TAGNUM_MASK;
+
+    return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_identifier (sec_asn1d_state *state,
+				 const char *buf, unsigned long len)
+{
+    unsigned char byte;
+    int count;
+
+    PORT_Assert (state->pending == 1);
+    PORT_Assert (state->place == duringIdentifier);
+
+    if (len == 0) {
+	state->top->status = needBytes;
+	return 0;
+    }
+
+    count = 0;
+
+    while (len && state->pending) {
+	if (HIGH_BITS (state->found_tag_number, TAG_NUMBER_BITS) != 0) {
+	    /*
+	     * The given high tag number overflows our container;
+	     * just give up.  This is not likely to *ever* happen.
+	     */
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return 0;
+	}
+
+	state->found_tag_number <<= TAG_NUMBER_BITS;
+
+	byte = (unsigned char) buf[count++];
+	state->found_tag_number |= (byte & TAG_NUMBER_MASK);
+
+	len--;
+	if (LAST_TAG_NUMBER_BYTE (byte))
+	    state->pending = 0;
+    }
+
+    if (state->pending == 0)
+	state->place = afterIdentifier;
+
+    return count;
+}
+
+
+static void
+sec_asn1d_confirm_identifier (sec_asn1d_state *state)
+{
+    PRBool match;
+
+    PORT_Assert (state->place == afterIdentifier);
+
+    match = (PRBool)(((state->found_tag_modifiers & state->check_tag_mask)
+	     == state->expect_tag_modifiers)
+	    && ((state->found_tag_number & state->check_tag_mask)
+		== state->expect_tag_number));
+    if (match) {
+	state->place = beforeLength;
+    } else {
+	if (state->optional) {
+	    state->missing = PR_TRUE;
+	    state->place = afterEndOfContents;
+	} else {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	}
+    }
+}
+
+
+static unsigned long
+sec_asn1d_parse_length (sec_asn1d_state *state,
+			const char *buf, unsigned long len)
+{
+    unsigned char byte;
+
+    PORT_Assert (state->place == beforeLength);
+
+    if (len == 0) {
+	state->top->status = needBytes;
+	return 0;
+    }
+
+    /*
+     * The default/likely outcome.  It may get adjusted below.
+     */
+    state->place = afterLength;
+
+    byte = (unsigned char) *buf;
+
+    if (LENGTH_IS_SHORT_FORM (byte)) {
+	state->contents_length = byte;
+    } else {
+	state->contents_length = 0;
+	state->pending = LONG_FORM_LENGTH (byte);
+	if (state->pending == 0) {
+	    state->indefinite = PR_TRUE;
+	} else {
+	    state->place = duringLength;
+	}
+    }
+
+    /* If we're parsing an ANY, SKIP, or SAVE template, and 
+    ** the object being saved is definite length encoded and constructed, 
+    ** there's no point in decoding that construct's members.
+    ** So, just forget it's constructed and treat it as primitive.
+    ** (SAVE appears as an ANY at this point)
+    */
+    if (!state->indefinite &&
+	(state->underlying_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP))) {
+	state->found_tag_modifiers &= ~SEC_ASN1_CONSTRUCTED;
+    }
+
+    return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_length (sec_asn1d_state *state,
+			     const char *buf, unsigned long len)
+{
+    int count;
+
+    PORT_Assert (state->pending > 0);
+    PORT_Assert (state->place == duringLength);
+
+    if (len == 0) {
+	state->top->status = needBytes;
+	return 0;
+    }
+
+    count = 0;
+
+    while (len && state->pending) {
+	if (HIGH_BITS (state->contents_length, 9) != 0) {
+	    /*
+	     * The given full content length overflows our container;
+	     * just give up.
+	     */
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return 0;
+	}
+
+	state->contents_length <<= 8;
+	state->contents_length |= (unsigned char) buf[count++];
+
+	len--;
+	state->pending--;
+    }
+
+    if (state->pending == 0)
+	state->place = afterLength;
+
+    return count;
+}
+
+
+static void
+sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
+{
+    SECItem *item;
+    PRArenaPool *poolp;
+    unsigned long alloc_len;
+
+#ifdef DEBUG_ASN1D_STATES
+    {
+        printf("Found Length %d %s\n", state->contents_length,
+               state->indefinite ? "indefinite" : "");
+    }
+#endif
+
+    /*
+     * XXX I cannot decide if this allocation should exclude the case
+     *     where state->endofcontents is true -- figure it out!
+     */
+    if (state->allocate) {
+	void *dest;
+
+	PORT_Assert (state->dest == NULL);
+	/*
+	 * We are handling a POINTER or a member of a GROUP, and need to
+	 * allocate for the data structure.
+	 */
+	dest = sec_asn1d_zalloc (state->top->their_pool,
+				 state->theTemplate->size);
+	if (dest == NULL) {
+	    state->top->status = decodeError;
+	    return;
+	}
+	state->dest = (char *)dest + state->theTemplate->offset;
+
+	/*
+	 * For a member of a GROUP, our parent will later put the
+	 * pointer wherever it belongs.  But for a POINTER, we need
+	 * to record the destination now, in case notify or filter
+	 * procs need access to it -- they cannot find it otherwise,
+	 * until it is too late (for one-pass processing).
+	 */
+	if (state->parent->place == afterPointer) {
+	    void **placep;
+
+	    placep = state->parent->dest;
+	    *placep = dest;
+	}
+    }
+
+    /*
+     * Remember, length may be indefinite here!  In that case,
+     * both contents_length and pending will be zero.
+     */
+    state->pending = state->contents_length;
+
+    /* If this item has definite length encoding, and 
+    ** is enclosed by a definite length constructed type,
+    ** make sure it isn't longer than the remaining space in that 
+    ** constructed type.  
+    */
+    if (state->contents_length > 0) {
+	sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state);
+	if (parent && !parent->indefinite && 
+	    state->consumed + state->contents_length > parent->pending) {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return;
+	}
+    }
+
+    /*
+     * An EXPLICIT is nothing but an outer header, which we have
+     * already parsed and accepted.  Now we need to do the inner
+     * header and its contents.
+     */
+    if (state->explicit) {
+	state->place = afterExplicit;
+	state = sec_asn1d_push_state (state->top,
+				      SEC_ASN1GetSubtemplate(state->theTemplate,
+							     state->dest,
+							     PR_FALSE),
+				      state->dest, PR_TRUE);
+	if (state != NULL)
+	    state = sec_asn1d_init_state_based_on_template (state);
+	return;
+    }
+
+    /*
+     * For GROUP (SET OF, SEQUENCE OF), even if we know the length here
+     * we cannot tell how many items we will end up with ... so push a
+     * state that can keep track of "children" (the individual members
+     * of the group; we will allocate as we go and put them all together
+     * at the end.
+     */
+    if (state->underlying_kind & SEC_ASN1_GROUP) {
+	/* XXX If this assertion holds (should be able to confirm it via
+	 * inspection, too) then move this code into the switch statement
+	 * below under cases SET_OF and SEQUENCE_OF; it will be cleaner.
+	 */
+	PORT_Assert (state->underlying_kind == SEC_ASN1_SET_OF
+	   || state->underlying_kind == SEC_ASN1_SEQUENCE_OF
+	   || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
+	   || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
+		     );
+	if (state->contents_length != 0 || state->indefinite) {
+	    const SEC_ASN1Template *subt;
+
+	    state->place = duringGroup;
+	    subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest,
+					   PR_FALSE);
+	    state = sec_asn1d_push_state (state->top, subt, NULL, PR_TRUE);
+	    if (state != NULL) {
+		if (!state->top->filter_only)
+		    state->allocate = PR_TRUE;	/* XXX propogate this? */
+		/*
+		 * Do the "before" field notification for next in group.
+		 */
+		sec_asn1d_notify_before (state->top, state->dest, state->depth);
+		state = sec_asn1d_init_state_based_on_template (state);
+	    }
+	} else {
+	    /*
+	     * A group of zero; we are done.
+	     * Set state to afterGroup and let that code plant the NULL.
+	     */
+	    state->place = afterGroup;
+	}
+	return;
+    }
+
+    switch (state->underlying_kind) {
+      case SEC_ASN1_SEQUENCE:
+	/*
+	 * We need to push a child to handle the individual fields.
+	 */
+	state->place = duringSequence;
+	state = sec_asn1d_push_state (state->top, state->theTemplate + 1,
+				      state->dest, PR_TRUE);
+	if (state != NULL) {
+	    /*
+	     * Do the "before" field notification.
+	     */
+	    sec_asn1d_notify_before (state->top, state->dest, state->depth);
+	    state = sec_asn1d_init_state_based_on_template (state);
+	}
+	break;
+
+      case SEC_ASN1_SET:	/* XXX SET is not really implemented */
+	/*
+	 * XXX A plain SET requires special handling; scanning of a
+	 * template to see where a field should go (because by definition,
+	 * they are not in any particular order, and you have to look at
+	 * each tag to disambiguate what the field is).  We may never
+	 * implement this because in practice, it seems to be unused.
+	 */
+	PORT_Assert(0);
+	PORT_SetError (SEC_ERROR_BAD_DER); /* XXX */
+	state->top->status = decodeError;
+	break;
+
+      case SEC_ASN1_NULL:
+	/*
+	 * The NULL type, by definition, is "nothing", content length of zero.
+	 * An indefinite-length encoding is not alloweed.
+	 */
+	if (state->contents_length || state->indefinite) {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    break;
+	}
+	if (state->dest != NULL) {
+	    item = (SECItem *)(state->dest);
+	    item->data = NULL;
+	    item->len = 0;
+	}
+	state->place = afterEndOfContents;
+	break;
+
+      case SEC_ASN1_BMP_STRING:
+	/* Error if length is not divisable by 2 */
+	if (state->contents_length % 2) {
+	   PORT_SetError (SEC_ERROR_BAD_DER);
+	   state->top->status = decodeError;
+	   break;
+	}   
+	/* otherwise, handle as other string types */
+	goto regular_string_type;
+
+      case SEC_ASN1_UNIVERSAL_STRING:
+	/* Error if length is not divisable by 4 */
+	if (state->contents_length % 4) {
+	   PORT_SetError (SEC_ERROR_BAD_DER);
+	   state->top->status = decodeError;
+	   break;
+	}   
+	/* otherwise, handle as other string types */
+	goto regular_string_type;
+
+      case SEC_ASN1_SKIP:
+      case SEC_ASN1_ANY:
+      case SEC_ASN1_ANY_CONTENTS:
+	/*
+	 * These are not (necessarily) strings, but they need nearly
+	 * identical handling (especially when we need to deal with
+	 * constructed sub-pieces), so we pretend they are.
+	 */
+	/* fallthru */
+regular_string_type:
+      case SEC_ASN1_BIT_STRING:
+      case SEC_ASN1_IA5_STRING:
+      case SEC_ASN1_OCTET_STRING:
+      case SEC_ASN1_PRINTABLE_STRING:
+      case SEC_ASN1_T61_STRING:
+      case SEC_ASN1_UTC_TIME:
+      case SEC_ASN1_UTF8_STRING:
+      case SEC_ASN1_VISIBLE_STRING:
+	/*
+	 * We are allocating for a primitive or a constructed string.
+	 * If it is a constructed string, it may also be indefinite-length.
+	 * If it is primitive, the length can (legally) be zero.
+	 * Our first order of business is to allocate the memory for
+	 * the string, if we can (if we know the length).
+	 */
+	item = (SECItem *)(state->dest);
+
+	/*
+	 * If the item is a definite-length constructed string, then
+	 * the contents_length is actually larger than what we need
+	 * (because it also counts each intermediate header which we
+	 * will be throwing away as we go), but it is a perfectly good
+	 * upper bound that we just allocate anyway, and then concat
+	 * as we go; we end up wasting a few extra bytes but save a
+	 * whole other copy.
+	 */
+	alloc_len = state->contents_length;
+	poolp = NULL;	/* quiet compiler warnings about unused... */
+
+	if (item == NULL || state->top->filter_only) {
+	    if (item != NULL) {
+		item->data = NULL;
+		item->len = 0;
+	    }
+	    alloc_len = 0;
+	} else if (state->substring) {
+	    /*
+	     * If we are a substring of a constructed string, then we may
+	     * not have to allocate anything (because our parent, the
+	     * actual constructed string, did it for us).  If we are a
+	     * substring and we *do* have to allocate, that means our
+	     * parent is an indefinite-length, so we allocate from our pool;
+	     * later our parent will copy our string into the aggregated
+	     * whole and free our pool allocation.
+	     */
+	    if (item->data == NULL) {
+		PORT_Assert (item->len == 0);
+		poolp = state->top->our_pool;
+	    } else {
+		alloc_len = 0;
+	    }
+	} else {
+	    item->len = 0;
+	    item->data = NULL;
+	    poolp = state->top->their_pool;
+	}
+
+	if (alloc_len || ((! state->indefinite)
+			  && (state->subitems_head != NULL))) {
+	    struct subitem *subitem;
+	    int len;
+
+	    PORT_Assert (item);
+	    if (!item) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+		return;
+	    }
+	    PORT_Assert (item->len == 0 && item->data == NULL);
+	    /*
+	     * Check for and handle an ANY which has stashed aside the
+	     * header (identifier and length) bytes for us to include
+	     * in the saved contents.
+	     */
+	    if (state->subitems_head != NULL) {
+		PORT_Assert (state->underlying_kind == SEC_ASN1_ANY);
+		for (subitem = state->subitems_head;
+		     subitem != NULL; subitem = subitem->next)
+		    alloc_len += subitem->len;
+	    }
+
+	    item->data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len);
+	    if (item->data == NULL) {
+		state->top->status = decodeError;
+		break;
+	    }
+
+	    len = 0;
+	    for (subitem = state->subitems_head;
+		 subitem != NULL; subitem = subitem->next) {
+		PORT_Memcpy (item->data + len, subitem->data, subitem->len);
+		len += subitem->len;
+	    }
+	    item->len = len;
+
+	    /*
+	     * Because we use arenas and have a mark set, we later free
+	     * everything we have allocated, so this does *not* present
+	     * a memory leak (it is just temporarily left dangling).
+	     */
+	    state->subitems_head = state->subitems_tail = NULL;
+	}
+
+	if (state->contents_length == 0 && (! state->indefinite)) {
+	    /*
+	     * A zero-length simple or constructed string; we are done.
+	     */
+	    state->place = afterEndOfContents;
+	} else if (state->found_tag_modifiers & SEC_ASN1_CONSTRUCTED) {
+	    const SEC_ASN1Template *sub;
+
+	    switch (state->underlying_kind) {
+	      case SEC_ASN1_ANY:
+	      case SEC_ASN1_ANY_CONTENTS:
+		sub = SEC_AnyTemplate;
+		break;
+	      case SEC_ASN1_BIT_STRING:
+		sub = SEC_BitStringTemplate;
+		break;
+	      case SEC_ASN1_BMP_STRING:
+		sub = SEC_BMPStringTemplate;
+		break;
+	      case SEC_ASN1_GENERALIZED_TIME:
+		sub = SEC_GeneralizedTimeTemplate;
+		break;
+	      case SEC_ASN1_IA5_STRING:
+		sub = SEC_IA5StringTemplate;
+		break;
+	      case SEC_ASN1_OCTET_STRING:
+		sub = SEC_OctetStringTemplate;
+		break;
+	      case SEC_ASN1_PRINTABLE_STRING:
+		sub = SEC_PrintableStringTemplate;
+		break;
+	      case SEC_ASN1_T61_STRING:
+		sub = SEC_T61StringTemplate;
+		break;
+	      case SEC_ASN1_UNIVERSAL_STRING:
+		sub = SEC_UniversalStringTemplate;
+		break;
+	      case SEC_ASN1_UTC_TIME:
+		sub = SEC_UTCTimeTemplate;
+		break;
+	      case SEC_ASN1_UTF8_STRING:
+		sub = SEC_UTF8StringTemplate;
+		break;
+	      case SEC_ASN1_VISIBLE_STRING:
+		sub = SEC_VisibleStringTemplate;
+		break;
+	      case SEC_ASN1_SKIP:
+		sub = SEC_SkipTemplate;
+		break;
+	      default:		/* redundant given outer switch cases, but */
+		PORT_Assert(0);	/* the compiler does not seem to know that, */
+		sub = NULL;	/* so just do enough to quiet it. */
+		break;
+	    }
+
+	    state->place = duringConstructedString;
+	    state = sec_asn1d_push_state (state->top, sub, item, PR_TRUE);
+	    if (state != NULL) {
+		state->substring = PR_TRUE;	/* XXX propogate? */
+		state = sec_asn1d_init_state_based_on_template (state);
+	    }
+	} else if (state->indefinite) {
+	    /*
+	     * An indefinite-length string *must* be constructed!
+	     */
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	} else {
+	    /*
+	     * A non-zero-length simple string.
+	     */
+	    if (state->underlying_kind == SEC_ASN1_BIT_STRING)
+		state->place = beforeBitString;
+	    else
+		state->place = duringLeaf;
+	}
+	break;
+
+      default:
+	/*
+	 * We are allocating for a simple leaf item.
+	 */
+	if (state->contents_length) {
+	    if (state->dest != NULL) {
+		item = (SECItem *)(state->dest);
+		item->len = 0;
+		if (state->top->filter_only) {
+		    item->data = NULL;
+		} else {
+		    item->data = (unsigned char*)
+		                  sec_asn1d_zalloc (state->top->their_pool,
+						   state->contents_length);
+		    if (item->data == NULL) {
+			state->top->status = decodeError;
+			return;
+		    }
+		}
+	    }
+	    state->place = duringLeaf;
+	} else {
+	    /*
+	     * An indefinite-length or zero-length item is not allowed.
+	     * (All legal cases of such were handled above.)
+	     */
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	}
+    }
+}
+
+
+static void
+sec_asn1d_free_child (sec_asn1d_state *state, PRBool error)
+{
+    if (state->child != NULL) {
+	PORT_Assert (error || state->child->consumed == 0);
+	PORT_Assert (state->our_mark != NULL);
+	PORT_ArenaZRelease (state->top->our_pool, state->our_mark);
+	if (error && state->top->their_pool == NULL) {
+	    /*
+	     * XXX We need to free anything allocated.
+             * At this point, we failed in the middle of decoding. But we
+             * can't free the data we previously allocated with PR_Malloc
+             * unless we keep track of every pointer. So instead we have a
+             * memory leak when decoding fails half-way, unless an arena is
+             * used. See bug 95311 .
+	     */
+	}
+	state->child = NULL;
+	state->our_mark = NULL;
+    } else {
+	/*
+	 * It is important that we do not leave a mark unreleased/unmarked.
+	 * But I do not think we should ever have one set in this case, only
+	 * if we had a child (handled above).  So check for that.  If this
+	 * assertion should ever get hit, then we probably need to add code
+	 * here to release back to our_mark (and then set our_mark to NULL).
+	 */
+	PORT_Assert (state->our_mark == NULL);
+    }
+    state->place = beforeEndOfContents;
+}
+
+/* We have just saved an entire encoded ASN.1 object (type) for a SAVE 
+** template, and now in the next template, we are going to decode that 
+** saved data  by calling SEC_ASN1DecoderUpdate recursively.
+** If that recursive call fails with needBytes, it is a fatal error,
+** because the encoded object should have been complete.
+** If that recursive call fails with decodeError, it will have already
+** cleaned up the state stack, so we must bail out quickly.
+**
+** These checks of the status returned by the recursive call are now
+** done in the caller of this function, immediately after it returns.
+*/
+static void
+sec_asn1d_reuse_encoding (sec_asn1d_state *state)
+{
+    sec_asn1d_state *child;
+    unsigned long consumed;
+    SECItem *item;
+    void *dest;
+
+
+    child = state->child;
+    PORT_Assert (child != NULL);
+
+    consumed = child->consumed;
+    child->consumed = 0;
+
+    item = (SECItem *)(state->dest);
+    PORT_Assert (item != NULL);
+
+    PORT_Assert (item->len == consumed);
+
+    /*
+     * Free any grandchild.
+     */
+    sec_asn1d_free_child (child, PR_FALSE);
+
+    /*
+     * Notify after the SAVE field.
+     */
+    sec_asn1d_notify_after (state->top, state->dest, state->depth);
+
+    /*
+     * Adjust to get new dest and move forward.
+     */
+    dest = (char *)state->dest - state->theTemplate->offset;
+    state->theTemplate++;
+    child->dest = (char *)dest + state->theTemplate->offset;
+    child->theTemplate = state->theTemplate;
+
+    /*
+     * Notify before the "real" field.
+     */
+    PORT_Assert (state->depth == child->depth);
+    sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+    /*
+     * This will tell DecoderUpdate to return when it is done.
+     */
+    state->place = afterSaveEncoding;
+
+    /*
+     * We already have a child; "push" it by making it current.
+     */
+    state->top->current = child;
+
+    /*
+     * And initialize it so it is ready to parse.
+     */
+    (void) sec_asn1d_init_state_based_on_template(child);
+
+    /*
+     * Now parse that out of our data.
+     */
+    if (SEC_ASN1DecoderUpdate (state->top,
+			       (char *) item->data, item->len) != SECSuccess)
+	return;
+    if (state->top->status == needBytes) {
+	return;
+    }
+
+    PORT_Assert (state->top->current == state);
+    PORT_Assert (state->child == child);
+
+    /*
+     * That should have consumed what we consumed before.
+     */
+    PORT_Assert (consumed == child->consumed);
+    child->consumed = 0;
+
+    /*
+     * Done.
+     */
+    state->consumed += consumed;
+    child->place = notInUse;
+    state->place = afterEndOfContents;
+}
+
+
+static unsigned long
+sec_asn1d_parse_leaf (sec_asn1d_state *state,
+		      const char *buf, unsigned long len)
+{
+    SECItem *item;
+    unsigned long bufLen;
+
+    if (len == 0) {
+	state->top->status = needBytes;
+	return 0;
+    }
+
+    if (state->pending < len)
+	len = state->pending;
+
+    bufLen = len;
+
+    item = (SECItem *)(state->dest);
+    if (item != NULL && item->data != NULL) {
+	/* Strip leading zeroes when target is unsigned integer */
+	if (state->underlying_kind == SEC_ASN1_INTEGER && /* INTEGER   */
+	    item->len == 0 &&                             /* MSB       */
+	    item->type == siUnsignedInteger)              /* unsigned  */
+	{
+	    while (len > 1 && buf[0] == 0) {              /* leading 0 */
+		buf++;
+		len--;
+	    }
+	}
+	PORT_Memcpy (item->data + item->len, buf, len);
+	item->len += len;
+    }
+    state->pending -= bufLen;
+    if (state->pending == 0)
+	state->place = beforeEndOfContents;
+
+    return bufLen;
+}
+
+
+static unsigned long
+sec_asn1d_parse_bit_string (sec_asn1d_state *state,
+			    const char *buf, unsigned long len)
+{
+    unsigned char byte;
+
+    /*PORT_Assert (state->pending > 0); */
+    PORT_Assert (state->place == beforeBitString);
+
+    if (state->pending == 0) {
+	if (state->dest != NULL) {
+	    SECItem *item = (SECItem *)(state->dest);
+	    item->data = NULL;
+	    item->len = 0;
+	    state->place = beforeEndOfContents;
+	    return 0;
+	}
+    }
+
+    if (len == 0) {
+	state->top->status = needBytes;
+	return 0;
+    }
+
+    byte = (unsigned char) *buf;
+    if (byte > 7) {
+	PORT_SetError (SEC_ERROR_BAD_DER);
+	state->top->status = decodeError;
+	return 0;
+    }
+
+    state->bit_string_unused_bits = byte;
+    state->place = duringBitString;
+    state->pending -= 1;
+
+    return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_bit_string (sec_asn1d_state *state,
+				 const char *buf, unsigned long len)
+{
+    PORT_Assert (state->place == duringBitString);
+    if (state->pending == 0) {
+	/* An empty bit string with some unused bits is invalid. */
+	if (state->bit_string_unused_bits) {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	} else {
+	    /* An empty bit string with no unused bits is OK. */
+	    state->place = beforeEndOfContents;
+	}
+	return 0;
+    }
+
+    len = sec_asn1d_parse_leaf (state, buf, len);
+    if (state->place == beforeEndOfContents && state->dest != NULL) {
+	SECItem *item;
+
+	item = (SECItem *)(state->dest);
+	if (item->len)
+	    item->len = (item->len << 3) - state->bit_string_unused_bits;
+    }
+
+    return len;
+}
+
+
+/*
+ * XXX All callers should be looking at return value to detect
+ * out-of-memory errors (and stop!).
+ */
+static struct subitem *
+sec_asn1d_add_to_subitems (sec_asn1d_state *state,
+			   const void *data, unsigned long len,
+			   PRBool copy_data)
+{
+    struct subitem *thing;
+
+    thing = (struct subitem*)sec_asn1d_zalloc (state->top->our_pool,
+				sizeof (struct subitem));
+    if (thing == NULL) {
+	state->top->status = decodeError;
+	return NULL;
+    }
+
+    if (copy_data) {
+	void *copy;
+	copy = sec_asn1d_alloc (state->top->our_pool, len);
+	if (copy == NULL) {
+	    state->top->status = decodeError;
+	    if (!state->top->our_pool)
+	    	PORT_Free(thing);
+	    return NULL;
+	}
+	PORT_Memcpy (copy, data, len);
+	thing->data = copy;
+    } else {
+	thing->data = data;
+    }
+    thing->len = len;
+    thing->next = NULL;
+
+    if (state->subitems_head == NULL) {
+	PORT_Assert (state->subitems_tail == NULL);
+	state->subitems_head = state->subitems_tail = thing;
+    } else {
+	state->subitems_tail->next = thing;
+	state->subitems_tail = thing;
+    }
+
+    return thing;
+}
+
+
+static void
+sec_asn1d_record_any_header (sec_asn1d_state *state,
+			     const char *buf,
+			     unsigned long len)
+{
+    SECItem *item;
+
+    item = (SECItem *)(state->dest);
+    if (item != NULL && item->data != NULL) {
+	PORT_Assert (state->substring);
+	PORT_Memcpy (item->data + item->len, buf, len);
+	item->len += len;
+    } else {
+	sec_asn1d_add_to_subitems (state, buf, len, PR_TRUE);
+    }
+}
+
+
+/*
+ * We are moving along through the substrings of a constructed string,
+ * and have just finished parsing one -- we need to save our child data
+ * (if the child was not already writing directly into the destination)
+ * and then move forward by one.
+ *
+ * We also have to detect when we are done:
+ *	- a definite-length encoding stops when our pending value hits 0
+ *	- an indefinite-length encoding stops when our child is empty
+ *	  (which means it was the end-of-contents octets)
+ */
+static void
+sec_asn1d_next_substring (sec_asn1d_state *state)
+{
+    sec_asn1d_state *child;
+    SECItem *item;
+    unsigned long child_consumed;
+    PRBool done;
+
+    PORT_Assert (state->place == duringConstructedString);
+    PORT_Assert (state->child != NULL);
+
+    child = state->child;
+
+    child_consumed = child->consumed;
+    child->consumed = 0;
+    state->consumed += child_consumed;
+
+    done = PR_FALSE;
+
+    if (state->pending) {
+	PORT_Assert (!state->indefinite);
+	if (child_consumed > state->pending) {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return;
+	}
+
+	state->pending -= child_consumed;
+	if (state->pending == 0)
+	    done = PR_TRUE;
+    } else {
+	PORT_Assert (state->indefinite);
+
+	item = (SECItem *)(child->dest);
+	if (item != NULL && item->data != NULL) {
+	    /*
+	     * Save the string away for later concatenation.
+	     */
+	    PORT_Assert (item->data != NULL);
+	    sec_asn1d_add_to_subitems (state, item->data, item->len, PR_FALSE);
+	    /*
+	     * Clear the child item for the next round.
+	     */
+	    item->data = NULL;
+	    item->len = 0;
+	}
+
+	/*
+	 * If our child was just our end-of-contents octets, we are done.
+	 */
+	if (child->endofcontents)
+	    done = PR_TRUE;
+    }
+
+    /*
+     * Stop or do the next one.
+     */
+    if (done) {
+	child->place = notInUse;
+	state->place = afterConstructedString;
+    } else {
+	sec_asn1d_scrub_state (child);
+	state->top->current = child;
+    }
+}
+
+
+/*
+ * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
+ */
+static void
+sec_asn1d_next_in_group (sec_asn1d_state *state)
+{
+    sec_asn1d_state *child;
+    unsigned long child_consumed;
+
+    PORT_Assert (state->place == duringGroup);
+    PORT_Assert (state->child != NULL);
+
+    child = state->child;
+
+    child_consumed = child->consumed;
+    child->consumed = 0;
+    state->consumed += child_consumed;
+
+    /*
+     * If our child was just our end-of-contents octets, we are done.
+     */
+    if (child->endofcontents) {
+	/* XXX I removed the PORT_Assert (child->dest == NULL) because there
+	 * was a bug in that a template that was a sequence of which also had
+	 * a child of a sequence of, in an indefinite group was not working 
+	 * properly.  This fix seems to work, (added the if statement below),
+	 * and nothing appears broken, but I am putting this note here just
+	 * in case. */
+	/*
+	 * XXX No matter how many times I read that comment,
+	 * I cannot figure out what case he was fixing.  I believe what he
+	 * did was deliberate, so I am loathe to touch it.  I need to
+	 * understand how it could ever be that child->dest != NULL but
+	 * child->endofcontents is true, and why it is important to check
+	 * that state->subitems_head is NULL.  This really needs to be
+	 * figured out, as I am not sure if the following code should be
+	 * compensating for "offset", as is done a little farther below
+	 * in the more normal case.
+	 */
+	PORT_Assert (state->indefinite);
+	PORT_Assert (state->pending == 0);
+	if(child->dest && !state->subitems_head) {
+	    sec_asn1d_add_to_subitems (state, child->dest, 0, PR_FALSE);
+	    child->dest = NULL;
+	}
+
+	child->place = notInUse;
+	state->place = afterGroup;
+	return;
+    }
+
+    /* 
+     * Do the "after" field notification for next in group.
+     */
+    sec_asn1d_notify_after (state->top, child->dest, child->depth);
+
+    /*
+     * Save it away (unless we are not storing).
+     */
+    if (child->dest != NULL) {
+	void *dest;
+
+	dest = child->dest;
+	dest = (char *)dest - child->theTemplate->offset;
+	sec_asn1d_add_to_subitems (state, dest, 0, PR_FALSE);
+	child->dest = NULL;
+    }
+
+    /*
+     * Account for those bytes; see if we are done.
+     */
+    if (state->pending) {
+	PORT_Assert (!state->indefinite);
+	if (child_consumed > state->pending) {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return;
+	}
+
+	state->pending -= child_consumed;
+	if (state->pending == 0) {
+	    child->place = notInUse;
+	    state->place = afterGroup;
+	    return;
+	}
+    }
+
+    /*
+     * Do the "before" field notification for next item in group.
+     */
+    sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+    /*
+     * Now we do the next one.
+     */
+    sec_asn1d_scrub_state (child);
+
+    /* Initialize child state from the template */
+    sec_asn1d_init_state_based_on_template(child);
+
+    state->top->current = child;
+}
+
+
+/*
+ * We are moving along through a sequence; move forward by one,
+ * (detecting end-of-sequence when it happens).
+ * XXX The handling of "missing" is ugly.  Fix it.
+ */
+static void
+sec_asn1d_next_in_sequence (sec_asn1d_state *state)
+{
+    sec_asn1d_state *child;
+    unsigned long child_consumed;
+    PRBool child_missing;
+
+    PORT_Assert (state->place == duringSequence);
+    PORT_Assert (state->child != NULL);
+
+    child = state->child;
+
+    /*
+     * Do the "after" field notification.
+     */
+    sec_asn1d_notify_after (state->top, child->dest, child->depth);
+
+    child_missing = (PRBool) child->missing;
+    child_consumed = child->consumed;
+    child->consumed = 0;
+
+    /*
+     * Take care of accounting.
+     */
+    if (child_missing) {
+	PORT_Assert (child->optional);
+    } else {
+	state->consumed += child_consumed;
+	/*
+	 * Free any grandchild.
+	 */
+	sec_asn1d_free_child (child, PR_FALSE);
+	if (state->pending) {
+	    PORT_Assert (!state->indefinite);
+	    if (child_consumed > state->pending) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+		return;
+	    }
+	    state->pending -= child_consumed;
+	    if (state->pending == 0) {
+		child->theTemplate++;
+		while (child->theTemplate->kind != 0) {
+		    if ((child->theTemplate->kind & SEC_ASN1_OPTIONAL) == 0) {
+			PORT_SetError (SEC_ERROR_BAD_DER);
+			state->top->status = decodeError;
+			return;
+		    }
+		    child->theTemplate++;
+		}
+		child->place = notInUse;
+		state->place = afterEndOfContents;
+		return;
+	    }
+	}
+    }
+
+    /*
+     * Move forward.
+     */
+    child->theTemplate++;
+    if (child->theTemplate->kind == 0) {
+	/*
+	 * We are done with this sequence.
+	 */
+	child->place = notInUse;
+	if (state->pending) {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	} else if (child_missing) {
+	    /*
+	     * We got to the end, but have a child that started parsing
+	     * and ended up "missing".  The only legitimate reason for
+	     * this is that we had one or more optional fields at the
+	     * end of our sequence, and we were encoded indefinite-length,
+	     * so when we went looking for those optional fields we
+	     * found our end-of-contents octets instead.
+	     * (Yes, this is ugly; dunno a better way to handle it.)
+	     * So, first confirm the situation, and then mark that we
+	     * are done.
+	     */
+	    if (state->indefinite && child->endofcontents) {
+		PORT_Assert (child_consumed == 2);
+		if (child_consumed != 2) {
+		    PORT_SetError (SEC_ERROR_BAD_DER);
+		    state->top->status = decodeError;
+		} else {
+		    state->consumed += child_consumed;
+		    state->place = afterEndOfContents;
+		}
+	    } else {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+	    }
+	} else {
+	    /*
+	     * We have to finish out, maybe reading end-of-contents octets;
+	     * let the normal logic do the right thing.
+	     */
+	    state->place = beforeEndOfContents;
+	}
+    } else {
+	unsigned char child_found_tag_modifiers = 0;
+	unsigned long child_found_tag_number = 0;
+
+	/*
+	 * Reset state and push.
+	 */
+	if (state->dest != NULL)
+	    child->dest = (char *)state->dest + child->theTemplate->offset;
+
+	/*
+	 * Do the "before" field notification.
+	 */
+	sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+	if (child_missing) { /* if previous child was missing, copy the tag data we already have */
+	    child_found_tag_modifiers = child->found_tag_modifiers;
+	    child_found_tag_number = child->found_tag_number;
+	}
+	state->top->current = child;
+	child = sec_asn1d_init_state_based_on_template (child);
+	if (child_missing && child) {
+	    child->place = afterIdentifier;
+	    child->found_tag_modifiers = child_found_tag_modifiers;
+	    child->found_tag_number = child_found_tag_number;
+	    child->consumed = child_consumed;
+	    if (child->underlying_kind == SEC_ASN1_ANY
+		&& !child->top->filter_only) {
+		/*
+		 * If the new field is an ANY, and we are storing, then
+		 * we need to save the tag out.  We would have done this
+		 * already in the normal case, but since we were looking
+		 * for an optional field, and we did not find it, we only
+		 * now realize we need to save the tag.
+		 */
+		unsigned char identifier;
+
+		/*
+		 * Check that we did not end up with a high tag; for that
+		 * we need to re-encode the tag into multiple bytes in order
+		 * to store it back to look like what we parsed originally.
+		 * In practice this does not happen, but for completeness
+		 * sake it should probably be made to work at some point.
+		 */
+		PORT_Assert (child_found_tag_number < SEC_ASN1_HIGH_TAG_NUMBER);
+		identifier = (unsigned char)(child_found_tag_modifiers | child_found_tag_number);
+		sec_asn1d_record_any_header (child, (char *) &identifier, 1);
+	    }
+	}
+    }
+}
+
+
+static void
+sec_asn1d_concat_substrings (sec_asn1d_state *state)
+{
+    PORT_Assert (state->place == afterConstructedString);
+
+    if (state->subitems_head != NULL) {
+	struct subitem *substring;
+	unsigned long alloc_len, item_len;
+	unsigned char *where;
+	SECItem *item;
+	PRBool is_bit_string;
+
+	item_len = 0;
+	is_bit_string = (state->underlying_kind == SEC_ASN1_BIT_STRING)
+			? PR_TRUE : PR_FALSE;
+
+	substring = state->subitems_head;
+	while (substring != NULL) {
+	    /*
+	     * All bit-string substrings except the last one should be
+	     * a clean multiple of 8 bits.
+	     */
+	    if (is_bit_string && (substring->next == NULL)
+			      && (substring->len & 0x7)) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+		return;
+	    }
+	    item_len += substring->len;
+	    substring = substring->next;
+	}
+
+	if (is_bit_string) {
+	    alloc_len = ((item_len + 7) >> 3);
+	} else {
+	    /*
+	     * Add 2 for the end-of-contents octets of an indefinite-length
+	     * ANY that is *not* also an INNER.  Because we zero-allocate
+	     * below, all we need to do is increase the length here.
+	     */
+	    if (state->underlying_kind == SEC_ASN1_ANY && state->indefinite)
+		item_len += 2; 
+	    alloc_len = item_len;
+	}
+
+	item = (SECItem *)(state->dest);
+	PORT_Assert (item != NULL);
+	PORT_Assert (item->data == NULL);
+	item->data = (unsigned char*)sec_asn1d_zalloc (state->top->their_pool, 
+						       alloc_len);
+	if (item->data == NULL) {
+	    state->top->status = decodeError;
+	    return;
+	}
+	item->len = item_len;
+
+	where = item->data;
+	substring = state->subitems_head;
+	while (substring != NULL) {
+	    if (is_bit_string)
+		item_len = (substring->len + 7) >> 3;
+	    else
+		item_len = substring->len;
+	    PORT_Memcpy (where, substring->data, item_len);
+	    where += item_len;
+	    substring = substring->next;
+	}
+
+	/*
+	 * Because we use arenas and have a mark set, we later free
+	 * everything we have allocated, so this does *not* present
+	 * a memory leak (it is just temporarily left dangling).
+	 */
+	state->subitems_head = state->subitems_tail = NULL;
+    }
+
+    state->place = afterEndOfContents;
+}
+
+
+static void
+sec_asn1d_concat_group (sec_asn1d_state *state)
+{
+    const void ***placep;
+
+    PORT_Assert (state->place == afterGroup);
+
+    placep = (const void***)state->dest;
+    PORT_Assert(state->subitems_head == NULL || placep != NULL);
+    if (placep != NULL) {
+	struct subitem *item;
+	const void **group;
+	int count;
+
+	count = 0;
+	item = state->subitems_head;
+	while (item != NULL) {
+	    PORT_Assert (item->next != NULL || item == state->subitems_tail);
+	    count++;
+	    item = item->next;
+	}
+
+	group = (const void**)sec_asn1d_zalloc (state->top->their_pool,
+				  (count + 1) * (sizeof(void *)));
+	if (group == NULL) {
+	    state->top->status = decodeError;
+	    return;
+	}
+
+	*placep = group;
+
+	item = state->subitems_head;
+	while (item != NULL) {
+	    *group++ = item->data;
+	    item = item->next;
+	}
+	*group = NULL;
+
+	/*
+	 * Because we use arenas and have a mark set, we later free
+	 * everything we have allocated, so this does *not* present
+	 * a memory leak (it is just temporarily left dangling).
+	 */
+	state->subitems_head = state->subitems_tail = NULL;
+    }
+
+    state->place = afterEndOfContents;
+}
+
+
+/*
+ * For those states that push a child to handle a subtemplate,
+ * "absorb" that child (transfer necessary information).
+ */
+static void
+sec_asn1d_absorb_child (sec_asn1d_state *state)
+{
+    /*
+     * There is absolutely supposed to be a child there.
+     */
+    PORT_Assert (state->child != NULL);
+
+    /*
+     * Inherit the missing status of our child, and do the ugly
+     * backing-up if necessary.
+     */
+    state->missing = state->child->missing;
+    if (state->missing) {
+	state->found_tag_number = state->child->found_tag_number;
+	state->found_tag_modifiers = state->child->found_tag_modifiers;
+	state->endofcontents = state->child->endofcontents;
+    }
+
+    /*
+     * Add in number of bytes consumed by child.
+     * (Only EXPLICIT should have already consumed bytes itself.)
+     */
+    PORT_Assert (state->place == afterExplicit || state->consumed == 0);
+    state->consumed += state->child->consumed;
+
+    /*
+     * Subtract from bytes pending; this only applies to a definite-length
+     * EXPLICIT field.
+     */
+    if (state->pending) {
+	PORT_Assert (!state->indefinite);
+	PORT_Assert (state->place == afterExplicit);
+
+	/*
+	 * If we had a definite-length explicit, then what the child
+	 * consumed should be what was left pending.
+	 */
+	if (state->pending != state->child->consumed) {
+	    if (state->pending < state->child->consumed) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+		return;
+	    }
+	    /*
+	     * Okay, this is a hack.  It *should* be an error whether
+	     * pending is too big or too small, but it turns out that
+	     * we had a bug in our *old* DER encoder that ended up
+	     * counting an explicit header twice in the case where
+	     * the underlying type was an ANY.  So, because we cannot
+	     * prevent receiving these (our own certificate server can
+	     * send them to us), we need to be lenient and accept them.
+	     * To do so, we need to pretend as if we read all of the
+	     * bytes that the header said we would find, even though
+	     * we actually came up short.
+	     */
+	    state->consumed += (state->pending - state->child->consumed);
+	}
+	state->pending = 0;
+    }
+
+    /*
+     * Indicate that we are done with child.
+     */
+    state->child->consumed = 0;
+
+    /*
+     * And move on to final state.
+     * (Technically everybody could move to afterEndOfContents except
+     * for an indefinite-length EXPLICIT; for simplicity though we assert
+     * that but let the end-of-contents code do the real determination.)
+     */
+    PORT_Assert (state->place == afterExplicit || (! state->indefinite));
+    state->place = beforeEndOfContents;
+}
+
+
+static void
+sec_asn1d_prepare_for_end_of_contents (sec_asn1d_state *state)
+{
+    PORT_Assert (state->place == beforeEndOfContents);
+
+    if (state->indefinite) {
+	state->place = duringEndOfContents;
+	state->pending = 2;
+    } else {
+	state->place = afterEndOfContents;
+    }
+}
+
+
+static unsigned long
+sec_asn1d_parse_end_of_contents (sec_asn1d_state *state,
+				 const char *buf, unsigned long len)
+{
+    unsigned int i;
+
+    PORT_Assert (state->pending <= 2);
+    PORT_Assert (state->place == duringEndOfContents);
+
+    if (len == 0) {
+	state->top->status = needBytes;
+	return 0;
+    }
+
+    if (state->pending < len)
+	len = state->pending;
+
+    for (i = 0; i < len; i++) {
+	if (buf[i] != 0) {
+	    /*
+	     * We expect to find only zeros; if not, just give up.
+	     */
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return 0;
+	}
+    }
+
+    state->pending -= len;
+
+    if (state->pending == 0) {
+	state->place = afterEndOfContents;
+	state->endofcontents = PR_TRUE;
+    }
+
+    return len;
+}
+
+
+static void
+sec_asn1d_pop_state (sec_asn1d_state *state)
+{
+#if 0	/* XXX I think this should always be handled explicitly by parent? */
+    /*
+     * Account for our child.
+     */
+    if (state->child != NULL) {
+	state->consumed += state->child->consumed;
+	if (state->pending) {
+	    PORT_Assert (!state->indefinite);
+	    if (state->child->consumed > state->pending) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+	    } else {
+		state->pending -= state->child->consumed;
+	    }
+	}
+	state->child->consumed = 0;
+    }
+#endif	/* XXX */
+
+    /*
+     * Free our child.
+     */
+    sec_asn1d_free_child (state, PR_FALSE);
+
+    /*
+     * Just make my parent be the current state.  It will then clean
+     * up after me and free me (or reuse me).
+     */
+    state->top->current = state->parent;
+}
+
+static sec_asn1d_state *
+sec_asn1d_before_choice (sec_asn1d_state *state)
+{
+    sec_asn1d_state *child;
+
+    if (state->allocate) {
+	void *dest;
+
+	dest = sec_asn1d_zalloc(state->top->their_pool, state->theTemplate->size);
+	if ((void *)NULL == dest) {
+	    state->top->status = decodeError;
+	    return (sec_asn1d_state *)NULL;
+	}
+
+	state->dest = (char *)dest + state->theTemplate->offset;
+    }
+
+    child = sec_asn1d_push_state(state->top, state->theTemplate + 1, 
+				 (char *)state->dest - state->theTemplate->offset, 
+				 PR_FALSE);
+    if ((sec_asn1d_state *)NULL == child) {
+	return (sec_asn1d_state *)NULL;
+    }
+
+    sec_asn1d_scrub_state(child);
+    child = sec_asn1d_init_state_based_on_template(child);
+    if ((sec_asn1d_state *)NULL == child) {
+	return (sec_asn1d_state *)NULL;
+    }
+
+    child->optional = PR_TRUE;
+
+    state->place = duringChoice;
+
+    return child;
+}
+
+static sec_asn1d_state *
+sec_asn1d_during_choice (sec_asn1d_state *state)
+{
+    sec_asn1d_state *child = state->child;
+    
+    PORT_Assert((sec_asn1d_state *)NULL != child);
+
+    if (child->missing) {
+	unsigned char child_found_tag_modifiers = 0;
+	unsigned long child_found_tag_number = 0;
+	void *        dest;
+
+	state->consumed += child->consumed;
+
+	if (child->endofcontents) {
+	    /* This choice is probably the first item in a GROUP
+	    ** (e.g. SET_OF) that was indefinite-length encoded.
+	    ** We're actually at the end of that GROUP.
+	    ** We look up the stack to be sure that we find
+	    ** a state with indefinite length encoding before we
+	    ** find a state (like a SEQUENCE) that is definite.
+	    */
+	    child->place = notInUse;
+	    state->place = afterChoice;
+	    state->endofcontents = PR_TRUE;  /* propagate this up */
+	    if (sec_asn1d_parent_allows_EOC(state))
+		return state;
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return NULL;
+	}
+
+	dest = (char *)child->dest - child->theTemplate->offset;
+	child->theTemplate++;
+
+	if (0 == child->theTemplate->kind) {
+	    /* Ran out of choices */
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    state->top->status = decodeError;
+	    return (sec_asn1d_state *)NULL;
+	}
+	child->dest = (char *)dest + child->theTemplate->offset;
+
+	/* cargo'd from next_in_sequence innards */
+	if (state->pending) {
+	    PORT_Assert(!state->indefinite);
+	    if (child->consumed > state->pending) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+		return NULL;
+	    }
+	    state->pending -= child->consumed;
+	    if (0 == state->pending) {
+		/* XXX uh.. not sure if I should have stopped this
+		 * from happening before. */
+		PORT_Assert(0);
+		PORT_SetError(SEC_ERROR_BAD_DER);
+		state->top->status = decodeError;
+		return (sec_asn1d_state *)NULL;
+	    }
+	}
+
+	child->consumed = 0;
+	sec_asn1d_scrub_state(child);
+
+	/* move it on top again */
+	state->top->current = child;
+
+	child_found_tag_modifiers = child->found_tag_modifiers;
+	child_found_tag_number = child->found_tag_number;
+
+	child = sec_asn1d_init_state_based_on_template(child);
+	if ((sec_asn1d_state *)NULL == child) {
+	    return (sec_asn1d_state *)NULL;
+	}
+
+	/* copy our findings to the new top */
+	child->found_tag_modifiers = child_found_tag_modifiers;
+	child->found_tag_number = child_found_tag_number;
+
+	child->optional = PR_TRUE;
+	child->place = afterIdentifier;
+
+	return child;
+    } 
+    if ((void *)NULL != state->dest) {
+	/* Store the enum */
+	int *which = (int *)state->dest;
+	*which = (int)child->theTemplate->size;
+    }
+
+    child->place = notInUse;
+
+    state->place = afterChoice;
+    return state;
+}
+
+static void
+sec_asn1d_after_choice (sec_asn1d_state *state)
+{
+    state->consumed += state->child->consumed;
+    state->child->consumed = 0;
+    state->place = afterEndOfContents;
+    sec_asn1d_pop_state(state);
+}
+
+unsigned long
+sec_asn1d_uinteger(SECItem *src)
+{
+    unsigned long value;
+    int len;
+
+    if (src->len > 5 || (src->len > 4 && src->data[0] == 0))
+	return 0;
+
+    value = 0;
+    len = src->len;
+    while (len) {
+	value <<= 8;
+	value |= src->data[--len];
+    }
+    return value;
+}
+
+SECStatus
+SEC_ASN1DecodeInteger(SECItem *src, unsigned long *value)
+{
+    unsigned long v;
+    unsigned int i;
+    
+    if (src == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    if (src->len > sizeof(unsigned long)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    if (src->data == NULL) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    	return SECFailure;
+    }
+
+    if (src->data[0] & 0x80)
+	v = -1;		/* signed and negative - start with all 1's */
+    else
+	v = 0;
+
+    for (i= 0; i < src->len; i++) {
+	/* shift in next byte */
+	v <<= 8;
+	v |= src->data[i];
+    }
+    *value = v;
+    return SECSuccess;
+}
+
+#ifdef DEBUG_ASN1D_STATES
+static void
+dump_states(SEC_ASN1DecoderContext *cx)
+{
+    sec_asn1d_state *state;
+    char kindBuf[256];
+
+    for (state = cx->current; state->parent; state = state->parent) {
+        ;
+    }
+
+    for (; state; state = state->child) {
+        int i;
+        for (i = 0; i < state->depth; i++) {
+            printf("  ");
+        }
+
+        i = formatKind(state->theTemplate->kind, kindBuf);
+        printf("%s: tmpl %08x, kind%s",
+               (state == cx->current) ? "STATE" : "State",
+               state->theTemplate,
+               kindBuf);
+        printf(" %s", (state->place >= 0 && state->place <= notInUse)
+                       ? place_names[ state->place ]
+                       : "(undefined)");
+        if (!i)
+            printf(", expect 0x%02x",
+                   state->expect_tag_number | state->expect_tag_modifiers);
+
+        printf("%s%s%s %d\n",
+               state->indefinite    ? ", indef"   : "",
+               state->missing       ? ", miss"    : "",
+               state->endofcontents ? ", EOC"     : "",
+               state->pending
+               );
+    }
+
+    return;
+}
+#endif /* DEBUG_ASN1D_STATES */
+
+SECStatus
+SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx,
+		       const char *buf, unsigned long len)
+{
+    sec_asn1d_state *state = NULL;
+    unsigned long consumed;
+    SEC_ASN1EncodingPart what;
+    sec_asn1d_state *stateEnd = cx->current;
+
+    if (cx->status == needBytes)
+	cx->status = keepGoing;
+
+    while (cx->status == keepGoing) {
+	state = cx->current;
+	what = SEC_ASN1_Contents;
+	consumed = 0;
+#ifdef DEBUG_ASN1D_STATES
+        printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
+               (state->place >= 0 && state->place <= notInUse) ?
+               place_names[ state->place ] : "(undefined)",
+               (unsigned int)((unsigned char *)buf)[ consumed ],
+               buf, consumed);
+        dump_states(cx);
+#endif /* DEBUG_ASN1D_STATES */
+	switch (state->place) {
+	  case beforeIdentifier:
+	    consumed = sec_asn1d_parse_identifier (state, buf, len);
+	    what = SEC_ASN1_Identifier;
+	    break;
+	  case duringIdentifier:
+	    consumed = sec_asn1d_parse_more_identifier (state, buf, len);
+	    what = SEC_ASN1_Identifier;
+	    break;
+	  case afterIdentifier:
+	    sec_asn1d_confirm_identifier (state);
+	    break;
+	  case beforeLength:
+	    consumed = sec_asn1d_parse_length (state, buf, len);
+	    what = SEC_ASN1_Length;
+	    break;
+	  case duringLength:
+	    consumed = sec_asn1d_parse_more_length (state, buf, len);
+	    what = SEC_ASN1_Length;
+	    break;
+	  case afterLength:
+	    sec_asn1d_prepare_for_contents (state);
+	    break;
+	  case beforeBitString:
+	    consumed = sec_asn1d_parse_bit_string (state, buf, len);
+	    break;
+	  case duringBitString:
+	    consumed = sec_asn1d_parse_more_bit_string (state, buf, len);
+	    break;
+	  case duringConstructedString:
+	    sec_asn1d_next_substring (state);
+	    break;
+	  case duringGroup:
+	    sec_asn1d_next_in_group (state);
+	    break;
+	  case duringLeaf:
+	    consumed = sec_asn1d_parse_leaf (state, buf, len);
+	    break;
+	  case duringSaveEncoding:
+	    sec_asn1d_reuse_encoding (state);
+	    if (cx->status == decodeError) {
+		/* recursive call has already popped all states from stack.
+		** Bail out quickly.
+		*/
+		return SECFailure;
+	    }
+	    if (cx->status == needBytes) {
+		/* recursive call wanted more data. Fatal. Clean up below. */
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		cx->status = decodeError;
+	    }
+	    break;
+	  case duringSequence:
+	    sec_asn1d_next_in_sequence (state);
+	    break;
+	  case afterConstructedString:
+	    sec_asn1d_concat_substrings (state);
+	    break;
+	  case afterExplicit:
+	  case afterImplicit:
+	  case afterInline:
+	  case afterPointer:
+	    sec_asn1d_absorb_child (state);
+	    break;
+	  case afterGroup:
+	    sec_asn1d_concat_group (state);
+	    break;
+	  case afterSaveEncoding:
+	    /* SEC_ASN1DecoderUpdate has called itself recursively to 
+	    ** decode SAVEd encoded data, and now is done decoding that.
+	    ** Return to the calling copy of SEC_ASN1DecoderUpdate.
+	    */
+	    return SECSuccess;
+	  case beforeEndOfContents:
+	    sec_asn1d_prepare_for_end_of_contents (state);
+	    break;
+	  case duringEndOfContents:
+	    consumed = sec_asn1d_parse_end_of_contents (state, buf, len);
+	    what = SEC_ASN1_EndOfContents;
+	    break;
+	  case afterEndOfContents:
+	    sec_asn1d_pop_state (state);
+	    break;
+          case beforeChoice:
+            state = sec_asn1d_before_choice(state);
+            break;
+          case duringChoice:
+            state = sec_asn1d_during_choice(state);
+            break;
+          case afterChoice:
+            sec_asn1d_after_choice(state);
+            break;
+	  case notInUse:
+	  default:
+	    /* This is not an error, but rather a plain old BUG! */
+	    PORT_Assert (0);
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    cx->status = decodeError;
+	    break;
+	}
+
+	if (cx->status == decodeError)
+	    break;
+
+	/* We should not consume more than we have.  */
+	PORT_Assert (consumed <= len);
+	if (consumed > len) {
+	    PORT_SetError (SEC_ERROR_BAD_DER);
+	    cx->status = decodeError;
+	    break;
+	}
+
+	/* It might have changed, so we have to update our local copy.  */
+	state = cx->current;
+
+	/* If it is NULL, we have popped all the way to the top.  */
+	if (state == NULL) {
+	    PORT_Assert (consumed == 0);
+#if 0	/* XXX I want this here, but it seems that we have situations (like
+	 * downloading a pkcs7 cert chain from some issuers) that give us a
+	 * length which is greater than the entire encoding.  So, we cannot
+	 * have this be an error.
+	 */
+	    if (len > 0) {
+		PORT_SetError (SEC_ERROR_BAD_DER);
+		cx->status = decodeError;
+	    } else
+#endif
+		cx->status = allDone;
+	    break;
+	}
+	else if (state->theTemplate->kind == SEC_ASN1_SKIP_REST) {
+	    cx->status = allDone;
+	    break;
+	}
+	  
+	if (consumed == 0)
+	    continue;
+
+	/*
+	 * The following check is specifically looking for an ANY
+	 * that is *not* also an INNER, because we need to save aside
+	 * all bytes in that case -- the contents parts will get
+	 * handled like all other contents, and the end-of-contents
+	 * bytes are added by the concat code, but the outer header
+	 * bytes need to get saved too, so we do them explicitly here.
+	 */
+	if (state->underlying_kind == SEC_ASN1_ANY
+	    && !cx->filter_only && (what == SEC_ASN1_Identifier
+				    || what == SEC_ASN1_Length)) {
+	    sec_asn1d_record_any_header (state, buf, consumed);
+	}
+
+	/*
+	 * We had some number of good, accepted bytes.  If the caller
+	 * has registered to see them, pass them along.
+	 */
+	if (state->top->filter_proc != NULL) {
+	    int depth;
+
+	    depth = state->depth;
+	    if (what == SEC_ASN1_EndOfContents && !state->indefinite) {
+		PORT_Assert (state->parent != NULL
+			     && state->parent->indefinite);
+		depth--;
+		PORT_Assert (depth == state->parent->depth);
+	    }
+	    (* state->top->filter_proc) (state->top->filter_arg,
+					 buf, consumed, depth, what);
+	}
+
+	state->consumed += consumed;
+	buf += consumed;
+	len -= consumed;
+    }
+
+    if (cx->status == decodeError) {
+	while (state != NULL && stateEnd->parent!=state) {
+	    sec_asn1d_free_child (state, PR_TRUE);
+	    state = state->parent;
+	}
+#ifdef SEC_ASN1D_FREE_ON_ERROR	/*
+				 * XXX This does not work because we can
+				 * end up leaving behind dangling pointers
+				 * to stuff that was allocated.  In order
+				 * to make this really work (which would
+				 * be a good thing, I think), we need to
+				 * keep track of every place/pointer that
+				 * was allocated and make sure to NULL it
+				 * out before we then free back to the mark.	
+				 */
+	if (cx->their_pool != NULL) {
+	    PORT_Assert (cx->their_mark != NULL);
+	    PORT_ArenaRelease (cx->their_pool, cx->their_mark);
+	}
+#endif
+	return SECFailure;
+    }
+
+#if 0	/* XXX This is what I want, but cannot have because it seems we
+	 * have situations (like when downloading a pkcs7 cert chain from
+	 * some issuers) that give us a total length which is greater than
+	 * the entire encoding.  So, we have to allow allDone to have a
+	 * remaining length greater than zero.  I wanted to catch internal
+	 * bugs with this, noticing when we do not have the right length.
+	 * Oh well.
+	 */
+    PORT_Assert (len == 0
+		 && (cx->status == needBytes || cx->status == allDone));
+#else
+    PORT_Assert ((len == 0 && cx->status == needBytes)
+		 || cx->status == allDone);
+#endif
+    return SECSuccess;
+}
+
+
+SECStatus
+SEC_ASN1DecoderFinish (SEC_ASN1DecoderContext *cx)
+{
+    SECStatus rv;
+
+    if (cx->status == needBytes) {
+	PORT_SetError (SEC_ERROR_BAD_DER);
+	rv = SECFailure;
+    } else {
+	rv = SECSuccess;
+    }
+
+    /*
+     * XXX anything else that needs to be finished?
+     */
+
+    PORT_FreeArena (cx->our_pool, PR_TRUE);
+
+    return rv;
+}
+
+
+SEC_ASN1DecoderContext *
+SEC_ASN1DecoderStart (PRArenaPool *their_pool, void *dest,
+		      const SEC_ASN1Template *theTemplate)
+{
+    PRArenaPool *our_pool;
+    SEC_ASN1DecoderContext *cx;
+
+    our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (our_pool == NULL)
+	return NULL;
+
+    cx = (SEC_ASN1DecoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
+    if (cx == NULL) {
+	PORT_FreeArena (our_pool, PR_FALSE);
+	return NULL;
+    }
+
+    cx->our_pool = our_pool;
+    if (their_pool != NULL) {
+	cx->their_pool = their_pool;
+#ifdef SEC_ASN1D_FREE_ON_ERROR
+	cx->their_mark = PORT_ArenaMark (their_pool);
+#endif
+    }
+
+    cx->status = needBytes;
+
+    if (sec_asn1d_push_state(cx, theTemplate, dest, PR_FALSE) == NULL
+	|| sec_asn1d_init_state_based_on_template (cx->current) == NULL) {
+	/*
+	 * Trouble initializing (probably due to failed allocations)
+	 * requires that we just give up.
+	 */
+	PORT_FreeArena (our_pool, PR_FALSE);
+	return NULL;
+    }
+
+    return cx;
+}
+
+
+void
+SEC_ASN1DecoderSetFilterProc (SEC_ASN1DecoderContext *cx,
+			      SEC_ASN1WriteProc fn, void *arg,
+			      PRBool only)
+{
+    /* check that we are "between" fields here */
+    PORT_Assert (cx->during_notify);
+
+    cx->filter_proc = fn;
+    cx->filter_arg = arg;
+    cx->filter_only = only;
+}
+
+
+void
+SEC_ASN1DecoderClearFilterProc (SEC_ASN1DecoderContext *cx)
+{
+    /* check that we are "between" fields here */
+    PORT_Assert (cx->during_notify);
+
+    cx->filter_proc = NULL;
+    cx->filter_arg = NULL;
+    cx->filter_only = PR_FALSE;
+}
+
+
+void
+SEC_ASN1DecoderSetNotifyProc (SEC_ASN1DecoderContext *cx,
+			      SEC_ASN1NotifyProc fn, void *arg)
+{
+    cx->notify_proc = fn;
+    cx->notify_arg = arg;
+}
+
+
+void
+SEC_ASN1DecoderClearNotifyProc (SEC_ASN1DecoderContext *cx)
+{
+    cx->notify_proc = NULL;
+    cx->notify_arg = NULL;	/* not necessary; just being clean */
+}
+
+void
+SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error)
+{
+    PORT_Assert(cx);
+    PORT_SetError(error);
+    cx->status = decodeError;
+}
+
+
+SECStatus
+SEC_ASN1Decode (PRArenaPool *poolp, void *dest,
+		const SEC_ASN1Template *theTemplate,
+		const char *buf, long len)
+{
+    SEC_ASN1DecoderContext *dcx;
+    SECStatus urv, frv;
+
+    dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate);
+    if (dcx == NULL)
+	return SECFailure;
+
+    urv = SEC_ASN1DecoderUpdate (dcx, buf, len);
+    frv = SEC_ASN1DecoderFinish (dcx);
+
+    if (urv != SECSuccess)
+	return urv;
+
+    return frv;
+}
+
+
+SECStatus
+SEC_ASN1DecodeItem (PRArenaPool *poolp, void *dest,
+		    const SEC_ASN1Template *theTemplate,
+		    const SECItem *src)
+{
+    return SEC_ASN1Decode (poolp, dest, theTemplate,
+			   (const char *)src->data, src->len);
+}
+
+#ifdef DEBUG_ASN1D_STATES
+void sec_asn1d_Assert(const char *s, const char *file, PRIntn ln)
+{
+    printf("Assertion failed, \"%s\", file %s, line %d\n", s, file, ln);
+    fflush(stdout);
+}
+#endif
+
+/*
+ * Generic templates for individual/simple items and pointers to
+ * and sets of same.
+ *
+ * If you need to add a new one, please note the following:
+ *	 - For each new basic type you should add *four* templates:
+ *	one plain, one PointerTo, one SequenceOf and one SetOf.
+ *	 - If the new type can be constructed (meaning, it is a
+ *	*string* type according to BER/DER rules), then you should
+ *	or-in SEC_ASN1_MAY_STREAM to the type in the basic template.
+ *	See the definition of the OctetString template for an example.
+ *	 - It may not be obvious, but these are in *alphabetical*
+ *	order based on the SEC_ASN1_XXX name; so put new ones in
+ *	the appropriate place.
+ */
+
+const SEC_ASN1Template SEC_SequenceOfAnyTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToBitStringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBitStringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBitStringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToBMPStringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBMPStringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToBooleanTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_BooleanTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBooleanTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_BooleanTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBooleanTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_BooleanTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_EnumeratedTemplate[] = {
+    { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) }
+};
+
+const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_EnumeratedTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_EnumeratedTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_EnumeratedTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_GeneralizedTimeTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_GeneralizedTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_GeneralizedTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToIA5StringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfIA5StringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToIntegerTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfIntegerTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfIntegerTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToNullTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfNullTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfNullTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToObjectIDTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_ObjectIDTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_ObjectIDTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SetOfObjectIDTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_ObjectIDTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_OctetStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfOctetStringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_OctetStringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_PrintableStringTemplate[] = {
+    { SEC_ASN1_PRINTABLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToPrintableStringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_PrintableStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_PrintableStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfPrintableStringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_PrintableStringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_T61StringTemplate[] = {
+    { SEC_ASN1_T61_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToT61StringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_T61StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfT61StringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_T61StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfT61StringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_T61StringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_UniversalStringTemplate[] = {
+    { SEC_ASN1_UNIVERSAL_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToUniversalStringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUniversalStringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToUTCTimeTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUTCTimeTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToUTF8StringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_UTF8StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTF8StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUTF8StringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_UTF8StringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_VisibleStringTemplate[] = {
+    { SEC_ASN1_VISIBLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToVisibleStringTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_VisibleStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate[] = {
+    { SEC_ASN1_SEQUENCE_OF, 0, SEC_VisibleStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfVisibleStringTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_VisibleStringTemplate }
+};
+
+#endif
+
+/*
+ * Template for skipping a subitem.
+ *
+ * Note that it only makes sense to use this for decoding (when you want
+ * to decode something where you are only interested in one or two of
+ * the fields); you cannot encode a SKIP!
+ */
+const SEC_ASN1Template SEC_SkipTemplate[] = {
+    { SEC_ASN1_SKIP }
+};
+
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs.  Sigh.
+*/
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_EnumeratedTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToEnumeratedTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfAnyTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfObjectIDTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SkipTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UniversalStringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PrintableStringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_T61StringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToGeneralizedTimeTemplate)
+
diff --git a/mozilla/security/nss/lib/util/secasn1e.c b/mozilla/security/nss/lib/util/secasn1e.c
new file mode 100644
index 0000000..3a4413f
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secasn1e.c
@@ -0,0 +1,1647 @@
+/* ***** 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 ***** */
+
+/*
+ * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id: secasn1e.c,v 1.21 2006/04/07 11:41:18 kaie%kuix.de Exp $
+ */
+
+#include "secasn1.h"
+
+typedef enum {
+    beforeHeader,
+    duringContents,
+    duringGroup,
+    duringSequence,
+    afterContents,
+    afterImplicit,
+    afterInline,
+    afterPointer,
+    afterChoice,
+    notInUse
+} sec_asn1e_parse_place;
+
+typedef enum {
+    allDone,
+    encodeError,
+    keepGoing,
+    needBytes
+} sec_asn1e_parse_status;
+
+typedef enum {
+    hdr_normal      = 0,  /* encode header normally */
+    hdr_any         = 1,  /* header already encoded in content */
+    hdr_decoder     = 2,  /* template only used by decoder. skip it. */
+    hdr_optional    = 3,  /* optional component, to be omitted */
+    hdr_placeholder = 4   /* place holder for from_buf content */
+} sec_asn1e_hdr_encoding;
+
+typedef struct sec_asn1e_state_struct {
+    SEC_ASN1EncoderContext *top;
+    const SEC_ASN1Template *theTemplate;
+    void *src;
+
+    struct sec_asn1e_state_struct *parent;	/* aka prev */
+    struct sec_asn1e_state_struct *child;	/* aka next */
+
+    sec_asn1e_parse_place place;	/* where we are in encoding process */
+
+    /*
+     * XXX explain the next fields as clearly as possible...
+     */
+    unsigned char tag_modifiers;
+    unsigned char tag_number;
+    unsigned long underlying_kind;
+
+    int depth;
+
+    PRBool isExplicit,		/* we are handling an isExplicit header */
+	   indefinite,		/* need end-of-contents */
+	   is_string,		/* encoding a simple string or an ANY */
+	   may_stream,		/* when streaming, do indefinite encoding */
+	   optional,		/* omit field if it has no contents */
+	   disallowStreaming;	/* disallow streaming in all sub-templates */	
+} sec_asn1e_state;
+
+/*
+ * An "outsider" will have an opaque pointer to this, created by calling
+ * SEC_ASN1EncoderStart().  It will be passed back in to all subsequent
+ * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
+ * it is passed to SEC_ASN1EncoderFinish().
+ */
+struct sec_EncoderContext_struct {
+    PRArenaPool *our_pool;		/* for our internal allocs */
+
+    sec_asn1e_state *current;
+    sec_asn1e_parse_status status;
+
+    PRBool streaming;
+    PRBool from_buf;
+
+    SEC_ASN1NotifyProc notify_proc;	/* call before/after handling field */
+    void *notify_arg;			/* argument to notify_proc */
+    PRBool during_notify;		/* true during call to notify_proc */
+
+    SEC_ASN1WriteProc output_proc;	/* pass encoded bytes to this  */
+    void *output_arg;			/* argument to that function */
+};
+
+
+static sec_asn1e_state *
+sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
+		      const SEC_ASN1Template *theTemplate,
+		      const void *src, PRBool new_depth)
+{
+    sec_asn1e_state *state, *new_state;
+
+    state = cx->current;
+
+    new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool, 
+						    sizeof(*new_state));
+    if (new_state == NULL) {
+	cx->status = encodeError;
+	return NULL;
+    }
+
+    new_state->top = cx;
+    new_state->parent = state;
+    new_state->theTemplate = theTemplate;
+    new_state->place = notInUse;
+    if (src != NULL)
+	new_state->src = (char *)src + theTemplate->offset;
+
+    if (state != NULL) {
+	new_state->depth = state->depth;
+	if (new_depth)
+	    new_state->depth++;
+	state->child = new_state;
+    }
+
+    cx->current = new_state;
+    return new_state;
+}
+
+
+static void
+sec_asn1e_scrub_state (sec_asn1e_state *state)
+{
+    /*
+     * Some default "scrubbing".
+     * XXX right set of initializations?
+     */
+    state->place = beforeHeader;
+    state->indefinite = PR_FALSE;
+}
+
+
+static void
+sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
+{
+    if (cx->notify_proc == NULL)
+	return;
+
+    cx->during_notify = PR_TRUE;
+    (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
+    cx->during_notify = PR_FALSE;
+}
+
+
+static void
+sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
+{
+    if (cx->notify_proc == NULL)
+	return;
+
+    cx->during_notify = PR_TRUE;
+    (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
+    cx->during_notify = PR_FALSE;
+}
+
+
+static sec_asn1e_state *
+sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
+{
+    PRBool isExplicit, is_string, may_stream, optional, universal; 
+    PRBool disallowStreaming;
+    unsigned char tag_modifiers;
+    unsigned long encode_kind, under_kind;
+    unsigned long tag_number;
+    PRBool isInline = PR_FALSE;
+
+
+    encode_kind = state->theTemplate->kind;
+
+    universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+		? PR_TRUE : PR_FALSE;
+
+    isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+    optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+    PORT_Assert (!(isExplicit && universal));	/* bad templates */
+
+    may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+    disallowStreaming = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_NO_STREAM;
+
+    /* Just clear this to get it out of the way; we do not need it here */
+    encode_kind &= ~SEC_ASN1_DYNAMIC;
+
+    if( encode_kind & SEC_ASN1_CHOICE ) {
+      under_kind = SEC_ASN1_CHOICE;
+    } else if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || 
+        (!universal && !isExplicit)) {
+	const SEC_ASN1Template *subt;
+	void *src = NULL;
+
+	PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
+
+	sec_asn1e_scrub_state (state);
+
+	if (encode_kind & SEC_ASN1_POINTER) {
+	    src = *(void **)state->src;
+	    state->place = afterPointer;
+
+	    if (src == NULL) {
+		/*
+		 * If this is optional, but NULL, then the field does
+		 * not need to be encoded.  In this case we are done;
+		 * we do not want to push a subtemplate.
+		 */
+		if (optional)
+		    return state;
+
+		/*
+		 * XXX this is an error; need to figure out
+		 * how to handle this
+		 */
+	    }
+	} else {
+	    src = state->src;
+	    if (encode_kind & SEC_ASN1_INLINE) {
+		/* check that there are no extraneous bits */
+		/* PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); */
+		state->place = afterInline;
+		isInline = PR_TRUE;
+	    } else {
+		/*
+		 * Save the tag modifiers and tag number here before moving
+		 * on to the next state in case this is a member of a
+		 * SEQUENCE OF
+		 */
+		state->tag_modifiers = (unsigned char)
+		    (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
+		state->tag_number = (unsigned char)
+		    (encode_kind & SEC_ASN1_TAGNUM_MASK);
+		
+		state->place = afterImplicit;
+		state->optional = optional;
+	    }
+	}
+
+	subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE);
+	if (isInline && optional) {
+	    /* we only handle a very limited set of optional inline cases at
+	       this time */
+	    if (PR_FALSE != SEC_ASN1IsTemplateSimple(subt)) {
+		/* we now know that the target is a SECItem*, so we can check
+		   if the source contains one */
+		SECItem* target = (SECItem*)state->src;
+		if (!target || !target->data || !target->len) {
+		    /* no valid data to encode subtemplate */
+		    return state;
+		}
+	    } else {
+		PORT_Assert(0); /* complex templates are not handled as
+				   inline optional */
+	    }
+	}
+	state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);
+	if (state == NULL)
+	    return state;
+
+	if (universal) {
+	    /*
+	     * This is a POINTER or INLINE; just init based on that
+	     * and we are done.
+	     */
+	    return sec_asn1e_init_state_based_on_template (state);
+	}
+
+	/*
+	 * This is an implicit, non-universal (meaning, application-private
+	 * or context-specific) field.  This results in a "magic" tag but
+	 * encoding based on the underlying type.  We pushed a new state
+	 * that is based on the subtemplate (the underlying type), but
+	 * now we will sort of alias it to give it some of our properties
+	 * (tag, optional status, etc.).
+	 *
+	 * NB: ALL the following flags in the subtemplate are disallowed
+	 *     and/or ignored: EXPLICIT, OPTIONAL, INNER, INLINE, POINTER.
+	 */
+
+	under_kind = state->theTemplate->kind;
+	if ((under_kind & SEC_ASN1_MAY_STREAM) && !disallowStreaming) {
+	    may_stream = PR_TRUE;
+	}
+	under_kind &= ~(SEC_ASN1_MAY_STREAM | SEC_ASN1_DYNAMIC);
+    } else {
+	under_kind = encode_kind;
+    }
+
+    /*
+     * Sanity check that there are no unwanted bits marked in under_kind.
+     * These bits were either removed above (after we recorded them) or
+     * they simply should not be found (signalling a bad/broken template).
+     * XXX is this the right set of bits to test here? (i.e. need to add
+     * or remove any?)
+     */
+#define UNEXPECTED_FLAGS \
+ (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_SKIP | SEC_ASN1_INNER | \
+  SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_INLINE | SEC_ASN1_POINTER)
+
+    PORT_Assert ((under_kind & UNEXPECTED_FLAGS) == 0);
+    under_kind &= ~UNEXPECTED_FLAGS;
+#undef UNEXPECTED_FLAGS
+
+    if (encode_kind & SEC_ASN1_ANY) {
+	PORT_Assert (encode_kind == under_kind);
+	tag_modifiers = 0;
+	tag_number = 0;
+	is_string = PR_TRUE;
+    } else {
+	tag_modifiers = (unsigned char)
+		(encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
+	/*
+	 * XXX This assumes only single-octet identifiers.  To handle
+	 * the HIGH TAG form we would need to do some more work, especially
+	 * in how to specify them in the template, because right now we
+	 * do not provide a way to specify more *tag* bits in encode_kind.
+	 */
+	tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
+
+	is_string = PR_FALSE;
+	switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
+	  case SEC_ASN1_SET:
+	    /*
+	     * XXX A plain old SET (as opposed to a SET OF) is not implemented.
+	     * If it ever is, remove this assert...
+	     */
+	    PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
+	    /* fallthru */
+	  case SEC_ASN1_SEQUENCE:
+	    tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+	    break;
+	  case SEC_ASN1_BIT_STRING:
+	  case SEC_ASN1_BMP_STRING: 
+	  case SEC_ASN1_GENERALIZED_TIME:
+	  case SEC_ASN1_IA5_STRING:
+	  case SEC_ASN1_OCTET_STRING:
+	  case SEC_ASN1_PRINTABLE_STRING:
+	  case SEC_ASN1_T61_STRING:
+	  case SEC_ASN1_UNIVERSAL_STRING: 
+	  case SEC_ASN1_UTC_TIME:
+	  case SEC_ASN1_UTF8_STRING:
+	  case SEC_ASN1_VISIBLE_STRING: 
+	    /*
+	     * We do not yet know if we will be constructing the string,
+	     * so we have to wait to do this final tag modification.
+	     */
+	    is_string = PR_TRUE;
+	    break;
+	}
+    }
+
+    state->tag_modifiers = tag_modifiers;
+    state->tag_number = (unsigned char)tag_number;
+    state->underlying_kind = under_kind;
+    state->isExplicit = isExplicit;
+    state->may_stream = may_stream;
+    state->is_string = is_string;
+    state->optional = optional;
+    state->disallowStreaming = disallowStreaming;
+
+    sec_asn1e_scrub_state (state);
+
+    return state;
+}
+
+
+static void
+sec_asn1e_write_part (sec_asn1e_state *state,
+		      const char *buf, unsigned long len,
+		      SEC_ASN1EncodingPart part)
+{
+    SEC_ASN1EncoderContext *cx;
+
+    cx = state->top;
+    (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
+}
+
+
+/*
+ * XXX This assumes only single-octet identifiers.  To handle
+ * the HIGH TAG form we would need to modify this interface and
+ * teach it to properly encode the special form.
+ */
+static void
+sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
+{
+    char byte;
+
+    byte = (char) value;
+    sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
+}
+
+int
+SEC_ASN1EncodeLength(unsigned char *buf,int value) {
+    int lenlen;
+
+    lenlen = SEC_ASN1LengthLength (value);
+    if (lenlen == 1) {
+	buf[0] = value;
+    } else {
+	int i;
+
+	i = lenlen - 1;
+	buf[0] = 0x80 | i;
+	while (i) {
+	    buf[i--] = value;
+	    value >>= 8;
+	}
+        PORT_Assert (value == 0);
+    }
+    return lenlen;
+}
+
+static void
+sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
+			      PRBool indefinite)
+{
+    int lenlen;
+    unsigned char buf[sizeof(unsigned long) + 1];
+
+    if (indefinite) {
+	PORT_Assert (value == 0);
+	buf[0] = 0x80;
+	lenlen = 1;
+    } else {
+	lenlen = SEC_ASN1EncodeLength(buf,value);
+    }
+
+    sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
+}
+
+
+static void
+sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
+				const char *buf, unsigned long len)
+{
+    sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
+}
+
+
+static void
+sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
+{
+    const char eoc[2] = {0, 0};
+
+    sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
+}
+
+static int
+sec_asn1e_which_choice
+(
+  void *src,
+  const SEC_ASN1Template *theTemplate
+)
+{
+  int rv;
+  unsigned int which = *(unsigned int *)src;
+
+  for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
+    if( which == theTemplate->size ) {
+      return rv;
+    }
+  }
+
+  return 0;
+}
+
+static unsigned long
+sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src,
+			   PRBool disallowStreaming, PRBool insideIndefinite,
+			   sec_asn1e_hdr_encoding *pHdrException)
+{
+    unsigned long encode_kind, underlying_kind;
+    PRBool isExplicit, optional, universal, may_stream;
+    unsigned long len;
+
+    /*
+     * This function currently calculates the length in all cases
+     * except the following: when writing out the contents of a 
+     * template that belongs to a state where it was a sub-template
+     * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
+     * optional bit set.  The information that the parent is optional
+     * and that we should return the length of 0 when that length is 
+     * present since that means the optional field is no longer present.
+     * So we add the disallowStreaming flag which is passed in when
+     * writing the contents, but for all recursive calls to 
+     * sec_asn1e_contents_length, we pass PR_FALSE, because this
+     * function correctly calculates the length for children templates
+     * from that point on.  Confused yet?  At least you didn't have
+     * to figure it out.  ;)  -javi
+     */
+    encode_kind = theTemplate->kind;
+
+    universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+		? PR_TRUE : PR_FALSE;
+
+    isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+    optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+    PORT_Assert (!(isExplicit && universal));	/* bad templates */
+
+    may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
+    encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+    /* Just clear this to get it out of the way; we do not need it here */
+    encode_kind &= ~SEC_ASN1_DYNAMIC;
+
+    if (encode_kind & SEC_ASN1_NO_STREAM) {
+	disallowStreaming = PR_TRUE;
+    }
+    encode_kind &= ~SEC_ASN1_NO_STREAM;
+
+    if (encode_kind & SEC_ASN1_CHOICE) {
+	void *src2;
+	int indx = sec_asn1e_which_choice(src, theTemplate);
+	if (0 == indx) {
+	    /* XXX set an error? "choice not found" */
+	    /* state->top->status = encodeError; */
+	    return 0;
+	}
+
+        src2 = (void *)
+	        ((char *)src - theTemplate->offset + theTemplate[indx].offset);
+
+        return sec_asn1e_contents_length(&theTemplate[indx], src2, 
+					 disallowStreaming, insideIndefinite,
+					 pHdrException);
+    }
+
+    if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
+	/* XXX any bits we want to disallow (PORT_Assert against) here? */
+	theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
+	if (encode_kind & SEC_ASN1_POINTER) {
+	    src = *(void **)src;
+	    if (src == NULL) {
+		*pHdrException = optional ? hdr_optional : hdr_normal;
+		return 0;
+	    }
+	} else if (encode_kind & SEC_ASN1_INLINE) {
+	    /* check that there are no extraneous bits */
+	    if (optional) {
+		if (PR_FALSE != SEC_ASN1IsTemplateSimple(theTemplate)) {
+		    /* we now know that the target is a SECItem*, so we can check
+		       if the source contains one */
+		    SECItem* target = (SECItem*)src;
+		    if (!target || !target->data || !target->len) {
+			/* no valid data to encode subtemplate */
+			*pHdrException = hdr_optional;
+			return 0;
+		    }
+		} else {
+		    PORT_Assert(0); /* complex templates not handled as inline
+                                       optional */
+		}
+	    }
+	}
+
+	src = (char *)src + theTemplate->offset;
+
+	/* recurse to find the length of the subtemplate */
+	len = sec_asn1e_contents_length (theTemplate, src, disallowStreaming, 
+	                                 insideIndefinite, pHdrException);
+	if (len == 0 && optional) {
+	    *pHdrException = hdr_optional;
+	} else if (isExplicit) {
+	    if (*pHdrException == hdr_any) {
+		/* *we* do not want to add in a header, 
+		** but our caller still does. 
+		*/
+		*pHdrException = hdr_normal;
+	    } else if (*pHdrException == hdr_normal) {
+		/* if the inner content exists, our length is
+		 * len(identifier) + len(length) + len(innercontent)
+		 * XXX we currently assume len(identifier) == 1;
+		 * to support a high-tag-number this would need to be smarter.
+		 */
+		len += 1 + SEC_ASN1LengthLength (len);
+	    }
+	}
+	return len;
+    }
+    underlying_kind = encode_kind;
+
+    /* This is only used in decoding; it plays no part in encoding.  */
+    if (underlying_kind & SEC_ASN1_SAVE) {
+	/* check that there are no extraneous bits */
+	PORT_Assert (underlying_kind == SEC_ASN1_SAVE);
+	*pHdrException = hdr_decoder;
+	return 0;
+    }
+
+#define UNEXPECTED_FLAGS \
+ (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_INLINE | SEC_ASN1_POINTER |\
+  SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_SAVE | SEC_ASN1_SKIP)
+
+    /* Having any of these bits is not expected here...  */
+    PORT_Assert ((underlying_kind & UNEXPECTED_FLAGS) == 0);
+    underlying_kind &= ~UNEXPECTED_FLAGS;
+#undef UNEXPECTED_FLAGS
+
+    if (underlying_kind & SEC_ASN1_CHOICE) {
+	void *src2;
+	int indx = sec_asn1e_which_choice(src, theTemplate);
+	if (0 == indx) {
+	    /* XXX set an error? "choice not found" */
+	    /* state->top->status = encodeError; */
+	    return 0;
+	}
+
+        src2 = (void *)
+		((char *)src - theTemplate->offset + theTemplate[indx].offset);
+        len = sec_asn1e_contents_length(&theTemplate[indx], src2, 
+	                                disallowStreaming, insideIndefinite, 
+					pHdrException);
+    } else {
+      switch (underlying_kind) {
+      case SEC_ASN1_SEQUENCE_OF:
+      case SEC_ASN1_SET_OF:
+	{
+	    const SEC_ASN1Template *tmpt;
+	    void *sub_src;
+	    unsigned long sub_len;
+	    void **group;
+
+	    len = 0;
+
+	    group = *(void ***)src;
+	    if (group == NULL)
+		break;
+
+	    tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
+
+	    for (; *group != NULL; group++) {
+		sub_src = (char *)(*group) + tmpt->offset;
+		sub_len = sec_asn1e_contents_length (tmpt, sub_src, 
+		                                     disallowStreaming,
+						     insideIndefinite,
+                                                     pHdrException);
+		len += sub_len;
+		/*
+		 * XXX The 1 below is the presumed length of the identifier;
+		 * to support a high-tag-number this would need to be smarter.
+		 */
+		if (*pHdrException == hdr_normal)
+		    len += 1 + SEC_ASN1LengthLength (sub_len);
+	    }
+	}
+	break;
+
+      case SEC_ASN1_SEQUENCE:
+      case SEC_ASN1_SET:
+	{
+	    const SEC_ASN1Template *tmpt;
+	    void *sub_src;
+	    unsigned long sub_len;
+
+	    len = 0;
+	    for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {
+		sub_src = (char *)src + tmpt->offset;
+		sub_len = sec_asn1e_contents_length (tmpt, sub_src, 
+		                                     disallowStreaming,
+						     insideIndefinite,
+                                                     pHdrException);
+		len += sub_len;
+		/*
+		 * XXX The 1 below is the presumed length of the identifier;
+		 * to support a high-tag-number this would need to be smarter.
+		 */
+		if (*pHdrException == hdr_normal)
+		    len += 1 + SEC_ASN1LengthLength (sub_len);
+	    }
+	}
+	break;
+
+      case SEC_ASN1_BIT_STRING:
+	/* convert bit length to byte */
+	len = (((SECItem *)src)->len + 7) >> 3;
+	/* bit string contents involve an extra octet */
+	if (len)
+	    len++;
+	break;
+
+      case SEC_ASN1_INTEGER:
+	/* ASN.1 INTEGERs are signed.
+	 * If the source is an unsigned integer, the encoder will need 
+	 * to handle the conversion here.
+	 */
+	{
+	    unsigned char *buf = ((SECItem *)src)->data;
+	    SECItemType integerType = ((SECItem *)src)->type;
+	    len = ((SECItem *)src)->len;
+	    while (len > 0) {
+		if (*buf != 0) {
+		    if (*buf & 0x80 && integerType == siUnsignedInteger) {
+			len++; /* leading zero needed to make number signed */
+		    }
+		    break; /* reached beginning of number */
+		}
+		if (len == 1) {
+		    break; /* the number 0 */
+		}
+		if (buf[1] & 0x80) {
+		    break; /* leading zero already present */
+		} 
+		/* extraneous leading zero, keep going */
+		buf++;
+		len--;
+	    }
+	}
+	break;
+
+      default:
+	len = ((SECItem *)src)->len;
+	break;
+      }  /* end switch */
+
+#ifndef WHAT_PROBLEM_DOES_THIS_SOLVE
+      /* if we're streaming, we may have a secitem w/len 0 as placeholder */
+      if (!len && insideIndefinite && may_stream && !disallowStreaming) {
+	  len = 1;
+      }
+#endif
+    }    /* end else */
+
+    if (len == 0 && optional)
+	*pHdrException = hdr_optional;
+    else if (underlying_kind == SEC_ASN1_ANY)
+	*pHdrException = hdr_any;
+    else 
+	*pHdrException = hdr_normal;
+
+    return len;
+}
+
+
+static void
+sec_asn1e_write_header (sec_asn1e_state *state)
+{
+    unsigned long contents_length;
+    unsigned char tag_number, tag_modifiers;
+    sec_asn1e_hdr_encoding hdrException = hdr_normal;
+    PRBool indefinite = PR_FALSE;
+
+    PORT_Assert (state->place == beforeHeader);
+
+    tag_number = state->tag_number;
+    tag_modifiers = state->tag_modifiers;
+
+    if (state->underlying_kind == SEC_ASN1_ANY) {
+	state->place = duringContents;
+	return;
+    }
+
+    if (state->underlying_kind & SEC_ASN1_CHOICE) {
+	int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
+	if( 0 == indx ) {
+	    /* XXX set an error? "choice not found" */
+	    state->top->status = encodeError;
+	    return;
+	}
+	state->place = afterChoice;
+	state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
+			       (char *)state->src - state->theTemplate->offset, 
+			       PR_TRUE);
+	if (state) {
+	    /*
+	     * Do the "before" field notification.
+	     */
+	    sec_asn1e_notify_before (state->top, state->src, state->depth);
+	    state = sec_asn1e_init_state_based_on_template (state);
+	}
+	return;
+    }
+
+    /* The !isString test below is apparently intended to ensure that all 
+    ** constructed types receive indefinite length encoding.
+    */
+   indefinite = (PRBool) 
+	(state->top->streaming && state->may_stream && 
+	 (state->top->from_buf || !state->is_string));
+
+    /*
+     * If we are doing a definite-length encoding, first we have to
+     * walk the data structure to calculate the entire contents length.
+     * If we are doing an indefinite-length encoding, we still need to 
+     * know if the contents is:
+     *    optional and to be omitted, or 
+     *    an ANY (header is pre-encoded), or 
+     *    a SAVE or some other kind of template used only by the decoder.
+     * So, we call this function either way.
+     */
+    contents_length = sec_asn1e_contents_length (state->theTemplate,
+						 state->src, 
+                                                 state->disallowStreaming,
+						 indefinite,
+                                                 &hdrException);
+    /*
+     * We might be told explicitly not to put out a header.
+     * But it can also be the case, via a pushed subtemplate, that
+     * sec_asn1e_contents_length could not know that this field is
+     * really optional.  So check for that explicitly, too.
+     */
+    if (hdrException != hdr_normal || 
+	(contents_length == 0 && state->optional)) {
+	state->place = afterContents;
+	if (state->top->streaming && 
+	    state->may_stream && 
+	    state->top->from_buf) {
+	    /* we did not find an optional indefinite string, so we 
+	     * don't encode it.  However, if TakeFromBuf is on, we stop 
+	     * here anyway to give our caller a chance to intercept at the 
+	     * same point where we would stop if the field were present. 
+	     */
+	    state->top->status = needBytes;
+	}
+	return;
+    }
+
+    if (indefinite) {
+	/*
+	 * We need to put out an indefinite-length encoding.
+	 * The only universal types that can be constructed are SETs,
+	 * SEQUENCEs, and strings; so check that it is one of those,
+	 * or that it is not universal (e.g. context-specific).
+	 */
+	state->indefinite = PR_TRUE;
+	PORT_Assert ((tag_number == SEC_ASN1_SET)
+		     || (tag_number == SEC_ASN1_SEQUENCE)
+		     || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
+		     || state->is_string);
+	tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+	contents_length = 0;
+    }
+
+    sec_asn1e_write_identifier_bytes (state, 
+                                (unsigned char)(tag_number | tag_modifiers));
+    sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
+
+    if (contents_length == 0 && !state->indefinite) {
+	/*
+	 * If no real contents to encode, then we are done with this field.
+	 */
+	state->place = afterContents;
+	return;
+    }
+
+    /*
+     * An EXPLICIT is nothing but an outer header, which we have already
+     * written.  Now we need to do the inner header and contents.
+     */
+    if (state->isExplicit) {
+	const SEC_ASN1Template *subt =
+	      SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE);
+	state->place = afterContents;
+	state = sec_asn1e_push_state (state->top, subt, state->src, PR_TRUE);
+	if (state != NULL)
+	    state = sec_asn1e_init_state_based_on_template (state);
+	return;
+    }
+
+    switch (state->underlying_kind) {
+      case SEC_ASN1_SET_OF:
+      case SEC_ASN1_SEQUENCE_OF:
+	/*
+	 * We need to push a child to handle each member.
+	 */
+	{
+	    void **group;
+	    const SEC_ASN1Template *subt;
+
+	    group = *(void ***)state->src;
+	    if (group == NULL || *group == NULL) {
+		/*
+		 * Group is empty; we are done.
+		 */
+		state->place = afterContents;
+		return;
+	    }
+	    state->place = duringGroup;
+	    subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
+					   PR_TRUE);
+	    state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
+	    if (state != NULL)
+		state = sec_asn1e_init_state_based_on_template (state);
+	}
+	break;
+
+      case SEC_ASN1_SEQUENCE:
+      case SEC_ASN1_SET:
+	/*
+	 * We need to push a child to handle the individual fields.
+	 */
+	state->place = duringSequence;
+	state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
+				      state->src, PR_TRUE);
+	if (state != NULL) {
+	    /*
+	     * Do the "before" field notification.
+	     */
+	    sec_asn1e_notify_before (state->top, state->src, state->depth);
+	    state = sec_asn1e_init_state_based_on_template (state);
+	}
+	break;
+
+      default:
+	/*
+	 * I think we do not need to do anything else.
+	 * XXX Correct?
+	 */
+	state->place = duringContents;
+	break;
+    }
+}
+
+
+static void
+sec_asn1e_write_contents_from_buf (sec_asn1e_state *state,
+			  const char *buf, unsigned long len)
+{
+    PORT_Assert (state->place == duringContents);
+    PORT_Assert (state->top->from_buf);
+    PORT_Assert (state->may_stream && !state->disallowStreaming);
+
+    /*
+     * Probably they just turned on "take from buf", but have not
+     * yet given us any bytes.  If there is nothing in the buffer
+     * then we have nothing to do but return and wait.
+     */
+    if (buf == NULL || len == 0) {
+	state->top->status = needBytes;
+	return;
+    }
+    /*
+     * We are streaming, reading from a passed-in buffer.
+     * This means we are encoding a simple string or an ANY.
+     * For the former, we need to put out a substring, with its
+     * own identifier and length.  For an ANY, we just write it
+     * out as is (our caller is required to ensure that it
+     * is a properly encoded entity).
+     */
+    PORT_Assert (state->is_string);		/* includes ANY */
+    if (state->underlying_kind != SEC_ASN1_ANY) {
+	unsigned char identifier;
+
+	/*
+	 * Create the identifier based on underlying_kind.  We cannot
+	 * use tag_number and tag_modifiers because this can be an
+	 * implicitly encoded field.  In that case, the underlying
+	 * substrings *are* encoded with their real tag.
+	 */
+	identifier = (unsigned char)
+	                    (state->underlying_kind & SEC_ASN1_TAG_MASK);
+	/*
+	 * The underlying kind should just be a simple string; there
+	 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
+	 */
+	PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
+	/*
+	 * Write out the tag and length for the substring.
+	 */
+	sec_asn1e_write_identifier_bytes (state, identifier);
+	if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
+	    char byte;
+	    /*
+	     * Assume we have a length in bytes but we need to output
+	     * a proper bit string.  This interface only works for bit
+	     * strings that are full multiples of 8.  If support for
+	     * real, variable length bit strings is needed then the
+	     * caller will have to know to pass in a bit length instead
+	     * of a byte length and then this code will have to
+	     * perform the encoding necessary (length written is length
+	     * in bytes plus 1, and the first octet of string is the
+	     * number of bits remaining between the end of the bit
+	     * string and the next byte boundary).
+	     */
+	    sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
+	    byte = 0;
+	    sec_asn1e_write_contents_bytes (state, &byte, 1);
+	} else {
+	    sec_asn1e_write_length_bytes (state, len, PR_FALSE);
+	}
+    }
+    sec_asn1e_write_contents_bytes (state, buf, len);
+    state->top->status = needBytes;
+}
+
+static void
+sec_asn1e_write_contents (sec_asn1e_state *state)
+{
+    unsigned long len = 0;
+
+    PORT_Assert (state->place == duringContents);
+
+    switch (state->underlying_kind) {
+      case SEC_ASN1_SET:
+      case SEC_ASN1_SEQUENCE:
+	PORT_Assert (0);
+	break;
+
+      case SEC_ASN1_BIT_STRING:
+	{
+	    SECItem *item;
+	    char rem;
+
+	    item = (SECItem *)state->src;
+	    len = (item->len + 7) >> 3;
+	    rem = (unsigned char)((len << 3) - item->len); /* remaining bits */
+	    sec_asn1e_write_contents_bytes (state, &rem, 1);
+	    sec_asn1e_write_contents_bytes (state, (char *) item->data, len);
+	}
+	break;
+
+      case SEC_ASN1_BMP_STRING:
+	/* The number of bytes must be divisable by 2 */
+	if ((((SECItem *)state->src)->len) % 2) {
+	    SEC_ASN1EncoderContext *cx;
+
+	    cx = state->top;
+	    cx->status = encodeError;
+	    break;
+	}
+	/* otherwise, fall through to write the content */
+	goto process_string;
+
+      case SEC_ASN1_UNIVERSAL_STRING:
+	/* The number of bytes must be divisable by 4 */
+	if ((((SECItem *)state->src)->len) % 4) {
+	    SEC_ASN1EncoderContext *cx;
+
+	    cx = state->top;
+	    cx->status = encodeError;
+	    break;
+	}
+	/* otherwise, fall through to write the content */
+	goto process_string;
+
+      case SEC_ASN1_INTEGER:
+       /* ASN.1 INTEGERs are signed.  If the source is an unsigned
+	* integer, the encoder will need to handle the conversion here.
+	*/
+	{
+	    unsigned int blen;
+	    unsigned char *buf;
+	    SECItemType integerType;
+	    blen = ((SECItem *)state->src)->len;
+	    buf = ((SECItem *)state->src)->data;
+	    integerType = ((SECItem *)state->src)->type;
+	    while (blen > 0) {
+		if (*buf & 0x80 && integerType == siUnsignedInteger) {
+		    char zero = 0; /* write a leading 0 */
+		    sec_asn1e_write_contents_bytes(state, &zero, 1);
+		    /* and then the remaining buffer */
+		    sec_asn1e_write_contents_bytes(state, 
+						   (char *)buf, blen); 
+		    break;
+		} 
+		/* Check three possibilities:
+		 * 1.  No leading zeros, msb of MSB is not 1;
+		 * 2.  The number is zero itself;
+		 * 3.  Encoding a signed integer with a leading zero,
+		 *     keep the zero so that the number is positive.
+		 */
+		if (*buf != 0 || 
+		     blen == 1 || 
+		     (buf[1] & 0x80 && integerType != siUnsignedInteger) ) 
+		{
+		    sec_asn1e_write_contents_bytes(state, 
+						   (char *)buf, blen); 
+		    break;
+		}
+		/* byte is 0, continue */
+		buf++;
+		blen--;
+	    }
+	}
+	/* done with this content */
+	break;
+			
+process_string:			
+      default:
+	{
+	    SECItem *item;
+
+	    item = (SECItem *)state->src;
+	    sec_asn1e_write_contents_bytes (state, (char *) item->data,
+					    item->len);
+	}
+	break;
+    }
+    state->place = afterContents;
+}
+
+/*
+ * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
+ */
+static void
+sec_asn1e_next_in_group (sec_asn1e_state *state)
+{
+    sec_asn1e_state *child;
+    void **group;
+    void *member;
+
+    PORT_Assert (state->place == duringGroup);
+    PORT_Assert (state->child != NULL);
+
+    child = state->child;
+
+    group = *(void ***)state->src;
+
+    /*
+     * Find placement of current item.
+     */
+    member = (char *)(state->child->src) - child->theTemplate->offset;
+    while (*group != member)
+	group++;
+
+    /*
+     * Move forward to next item.
+     */
+    group++;
+    if (*group == NULL) {
+	/*
+	 * That was our last one; we are done now.
+	 */
+	child->place = notInUse;
+	state->place = afterContents;
+	return;
+    }
+    child->src = (char *)(*group) + child->theTemplate->offset;
+
+    /*
+     * Re-"push" child.
+     */
+    sec_asn1e_scrub_state (child);
+    state->top->current = child;
+}
+
+
+/*
+ * We are moving along through a sequence; move forward by one,
+ * (detecting end-of-sequence when it happens).
+ */
+static void
+sec_asn1e_next_in_sequence (sec_asn1e_state *state)
+{
+    sec_asn1e_state *child;
+
+    PORT_Assert (state->place == duringSequence);
+    PORT_Assert (state->child != NULL);
+
+    child = state->child;
+
+    /*
+     * Do the "after" field notification.
+     */
+    sec_asn1e_notify_after (state->top, child->src, child->depth);
+
+    /*
+     * Move forward.
+     */
+    child->theTemplate++;
+    if (child->theTemplate->kind == 0) {
+	/*
+	 * We are done with this sequence.
+	 */
+	child->place = notInUse;
+	state->place = afterContents;
+	return;
+    }
+
+    /*
+     * Reset state and push.
+     */
+
+    child->src = (char *)state->src + child->theTemplate->offset;
+
+    /*
+     * Do the "before" field notification.
+     */
+    sec_asn1e_notify_before (state->top, child->src, child->depth);
+
+    state->top->current = child;
+    (void) sec_asn1e_init_state_based_on_template (child);
+}
+
+
+static void
+sec_asn1e_after_contents (sec_asn1e_state *state)
+{
+    PORT_Assert (state->place == afterContents);
+
+    if (state->indefinite)
+	sec_asn1e_write_end_of_contents_bytes (state);
+
+    /*
+     * Just make my parent be the current state.  It will then clean
+     * up after me and free me (or reuse me).
+     */
+    state->top->current = state->parent;
+}
+
+
+/*
+ * This function is called whether or not we are streaming; if we
+ * *are* streaming, our caller can also instruct us to take bytes
+ * from the passed-in buffer (at buf, for length len, which is likely
+ * bytes but could even mean bits if the current field is a bit string).
+ * If we have been so instructed, we will gobble up bytes from there
+ * (rather than from our src structure) and output them, and then
+ * we will just return, expecting to be called again -- either with
+ * more bytes or after our caller has instructed us that we are done
+ * (for now) with the buffer.
+ */
+SECStatus
+SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
+		       const char *buf, unsigned long len)
+{
+    sec_asn1e_state *state;
+
+    if (cx->status == needBytes) {
+	cx->status = keepGoing;
+    }
+
+    while (cx->status == keepGoing) {
+	state = cx->current;
+	switch (state->place) {
+	  case beforeHeader:
+	    sec_asn1e_write_header (state);
+	    break;
+	  case duringContents:
+	    if (cx->from_buf)
+		sec_asn1e_write_contents_from_buf (state, buf, len);
+	    else
+		sec_asn1e_write_contents (state);
+	    break;
+	  case duringGroup:
+	    sec_asn1e_next_in_group (state);
+	    break;
+	  case duringSequence:
+	    sec_asn1e_next_in_sequence (state);
+	    break;
+	  case afterContents:
+	    sec_asn1e_after_contents (state);
+	    break;
+	  case afterImplicit:
+	  case afterInline:
+	  case afterPointer:
+	  case afterChoice:
+	    /*
+	     * These states are more documentation than anything.
+	     * They just need to force a pop.
+	     */
+	    PORT_Assert (!state->indefinite);
+	    state->place = afterContents;
+	    break;
+	  case notInUse:
+	  default:
+	    /* This is not an error, but rather a plain old BUG! */
+	    PORT_Assert (0);
+	    cx->status = encodeError;
+	    break;
+	}
+
+	if (cx->status == encodeError)
+	    break;
+
+	/* It might have changed, so we have to update our local copy.  */
+	state = cx->current;
+
+	/* If it is NULL, we have popped all the way to the top.  */
+	if (state == NULL) {
+	    cx->status = allDone;
+	    break;
+	}
+    }
+
+    if (cx->status == encodeError) {
+	return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+
+void
+SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
+{
+    /*
+     * XXX anything else that needs to be finished?
+     */
+
+    PORT_FreeArena (cx->our_pool, PR_FALSE);
+}
+
+
+SEC_ASN1EncoderContext *
+SEC_ASN1EncoderStart (const void *src, const SEC_ASN1Template *theTemplate,
+		      SEC_ASN1WriteProc output_proc, void *output_arg)
+{
+    PRArenaPool *our_pool;
+    SEC_ASN1EncoderContext *cx;
+
+    our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (our_pool == NULL)
+	return NULL;
+
+    cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
+    if (cx == NULL) {
+	PORT_FreeArena (our_pool, PR_FALSE);
+	return NULL;
+    }
+
+    cx->our_pool = our_pool;
+    cx->output_proc = output_proc;
+    cx->output_arg = output_arg;
+
+    cx->status = keepGoing;
+
+    if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
+	|| sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
+	/*
+	 * Trouble initializing (probably due to failed allocations)
+	 * requires that we just give up.
+	 */
+	PORT_FreeArena (our_pool, PR_FALSE);
+	return NULL;
+    }
+
+    return cx;
+}
+
+
+/*
+ * XXX Do we need a FilterProc, too?
+ */
+
+
+void
+SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
+			      SEC_ASN1NotifyProc fn, void *arg)
+{
+    cx->notify_proc = fn;
+    cx->notify_arg = arg;
+}
+
+
+void
+SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
+{
+    cx->notify_proc = NULL;
+    cx->notify_arg = NULL;	/* not necessary; just being clean */
+}
+
+void
+SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
+{
+    PORT_Assert(cx);
+    PORT_SetError(error);
+    cx->status = encodeError;
+}
+
+void
+SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
+{
+    /* XXX is there a way to check that we are "between" fields here? */
+
+    cx->streaming = PR_TRUE;
+}
+
+
+void
+SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
+{
+    /* XXX is there a way to check that we are "between" fields here? */
+
+    cx->streaming = PR_FALSE;
+}
+
+
+void
+SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
+{
+    /* 
+     * XXX is there a way to check that we are "between" fields here?  this
+     * needs to include a check for being in between groups of items in
+     * a SET_OF or SEQUENCE_OF.
+     */
+    PORT_Assert (cx->streaming);
+
+    cx->from_buf = PR_TRUE;
+}
+
+
+void
+SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
+{
+    /* we should actually be taking from buf *now* */
+    PORT_Assert (cx->from_buf);
+    if (! cx->from_buf)		/* if not, just do nothing */
+	return;
+
+    cx->from_buf = PR_FALSE;
+
+    if (cx->status == needBytes) {
+	cx->status = keepGoing;
+	cx->current->place = afterContents;
+    }
+}
+
+
+SECStatus
+SEC_ASN1Encode (const void *src, const SEC_ASN1Template *theTemplate,
+		SEC_ASN1WriteProc output_proc, void *output_arg)
+{
+    SEC_ASN1EncoderContext *ecx;
+    SECStatus rv;
+
+    ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
+    if (ecx == NULL)
+	return SECFailure;
+
+    rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
+
+    SEC_ASN1EncoderFinish (ecx);
+    return rv;
+}
+
+
+/*
+ * XXX depth and data_kind are unused; is there a PC way to silence warnings?
+ * (I mean "politically correct", not anything to do with intel/win platform) 
+ */
+static void
+sec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len,
+			     int depth, SEC_ASN1EncodingPart data_kind)
+{
+    unsigned long *count;
+
+    count = (unsigned long*)arg;
+    PORT_Assert (count != NULL);
+
+    *count += len;
+}
+
+
+/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
+static void
+sec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len,
+			     int depth, SEC_ASN1EncodingPart data_kind)
+{
+    SECItem *dest;
+
+    dest = (SECItem*)arg;
+    PORT_Assert (dest != NULL);
+
+    PORT_Memcpy (dest->data + dest->len, buf, len);
+    dest->len += len;
+}
+
+
+/*
+ * Allocate an entire SECItem, or just the data part of it, to hold
+ * "len" bytes of stuff.  Allocate from the given pool, if specified,
+ * otherwise just do a vanilla PORT_Alloc.
+ *
+ * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
+ */
+static SECItem *
+sec_asn1e_allocate_item (PRArenaPool *poolp, SECItem *dest, unsigned long len)
+{
+    if (poolp != NULL) {
+	void *release;
+
+	release = PORT_ArenaMark (poolp);
+	if (dest == NULL)
+	    dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
+	if (dest != NULL) {
+	    dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
+	    if (dest->data == NULL) {
+		dest = NULL;
+	    }
+	}
+	if (dest == NULL) {
+	    /* one or both allocations failed; release everything */
+	    PORT_ArenaRelease (poolp, release);
+	} else {
+	    /* everything okay; unmark the arena */
+	    PORT_ArenaUnmark (poolp, release);
+	}
+    } else {
+	SECItem *indest;
+
+	indest = dest;
+	if (dest == NULL)
+	    dest = (SECItem*)PORT_Alloc (sizeof(SECItem));
+	if (dest != NULL) {
+	    dest->type = siBuffer;
+	    dest->data = (unsigned char*)PORT_Alloc (len);
+	    if (dest->data == NULL) {
+		if (indest == NULL)
+		    PORT_Free (dest);
+		dest = NULL;
+	    }
+	}
+    }
+
+    return dest;
+}
+
+
+SECItem *
+SEC_ASN1EncodeItem (PRArenaPool *poolp, SECItem *dest, const void *src,
+		    const SEC_ASN1Template *theTemplate)
+{
+    unsigned long encoding_length;
+    SECStatus rv;
+
+    PORT_Assert (dest == NULL || dest->data == NULL);
+
+    encoding_length = 0;
+    rv = SEC_ASN1Encode (src, theTemplate,
+			 sec_asn1e_encode_item_count, &encoding_length);
+    if (rv != SECSuccess)
+	return NULL;
+
+    dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
+    if (dest == NULL)
+	return NULL;
+
+    /* XXX necessary?  This really just checks for a bug in the allocate fn */
+    PORT_Assert (dest->data != NULL);
+    if (dest->data == NULL)
+	return NULL;
+
+    dest->len = 0;
+    (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
+
+    PORT_Assert (encoding_length == dest->len);
+    return dest;
+}
+
+
+static SECItem *
+sec_asn1e_integer(PRArenaPool *poolp, SECItem *dest, unsigned long value,
+		  PRBool make_unsigned)
+{
+    unsigned long copy;
+    unsigned char sign;
+    int len = 0;
+
+    /*
+     * Determine the length of the encoded value (minimum of 1).
+     */
+    copy = value;
+    do {
+	len++;
+	sign = (unsigned char)(copy & 0x80);
+	copy >>= 8;
+    } while (copy);
+
+    /*
+     * If this is an unsigned encoding, and the high bit of the last
+     * byte we counted was set, we need to add one to the length so
+     * we put a high-order zero byte in the encoding.
+     */
+    if (sign && make_unsigned)
+	len++;
+
+    /*
+     * Allocate the item (if necessary) and the data pointer within.
+     */
+    dest = sec_asn1e_allocate_item (poolp, dest, len);
+    if (dest == NULL)
+	return NULL;
+
+    /*
+     * Store the value, byte by byte, in the item.
+     */
+    dest->len = len;
+    while (len) {
+	dest->data[--len] = (unsigned char)value;
+	value >>= 8;
+    }
+    PORT_Assert (value == 0);
+
+    return dest;
+}
+
+
+SECItem *
+SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value)
+{
+    return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
+}
+
+
+SECItem *
+SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
+			      SECItem *dest, unsigned long value)
+{
+    return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
+}
diff --git a/mozilla/security/nss/lib/util/secasn1t.h b/mozilla/security/nss/lib/util/secasn1t.h
new file mode 100644
index 0000000..0c26fb6
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secasn1t.h
@@ -0,0 +1,302 @@
+/* ***** 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 ***** */
+
+/*
+ * Types for encoding/decoding of ASN.1 using BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id: secasn1t.h,v 1.10 2007/10/12 01:44:51 julien.pierre.boogz%sun.com Exp $
+ */
+
+#ifndef _SECASN1T_H_
+#define _SECASN1T_H_
+
+#include "utilrename.h"
+
+/*
+** An array of these structures defines a BER/DER encoding for an object.
+**
+** The array usually starts with a dummy entry whose kind is SEC_ASN1_SEQUENCE;
+** such an array is terminated with an entry where kind == 0.  (An array
+** which consists of a single component does not require a second dummy
+** entry -- the array is only searched as long as previous component(s)
+** instruct it.)
+*/
+typedef struct sec_ASN1Template_struct {
+    /*
+    ** Kind of item being decoded/encoded, including tags and modifiers.
+    */
+    unsigned long kind;
+
+    /*
+    ** The value is the offset from the base of the structure to the
+    ** field that holds the value being decoded/encoded.
+    */
+    unsigned long offset;
+
+    /*
+    ** When kind suggests it (SEC_ASN1_POINTER, SEC_ASN1_GROUP, SEC_ASN1_INLINE,
+    ** or a component that is *not* a SEC_ASN1_UNIVERSAL), this points to
+    ** a sub-template for nested encoding/decoding,
+    ** OR, iff SEC_ASN1_DYNAMIC is set, then this is a pointer to a pointer
+    ** to a function which will return the appropriate template when called
+    ** at runtime.  NOTE! that explicit level of indirection, which is
+    ** necessary because ANSI does not allow you to store a function
+    ** pointer directly as a "void *" so we must store it separately and
+    ** dereference it to get at the function pointer itself.
+    */
+    const void *sub;
+
+    /*
+    ** In the first element of a template array, the value is the size
+    ** of the structure to allocate when this template is being referenced
+    ** by another template via SEC_ASN1_POINTER or SEC_ASN1_GROUP.
+    ** In all other cases, the value is ignored.
+    */
+    unsigned int size;
+} SEC_ASN1Template;
+
+
+/* default size used for allocation of encoding/decoding stuff */
+/* XXX what is the best value here? */
+#define SEC_ASN1_DEFAULT_ARENA_SIZE	(2048)
+
+/*
+** BER/DER values for ASN.1 identifier octets.
+*/
+#define SEC_ASN1_TAG_MASK		0xff
+
+/*
+ * BER/DER universal type tag numbers.
+ * The values are defined by the X.208 standard; do not change them!
+ * NOTE: if you add anything to this list, you must add code to secasn1d.c
+ * to accept the tag, and probably also to secasn1e.c to encode it.
+ * XXX It appears some have been added recently without being added to
+ * the code; so need to go through the list now and double-check them all.
+ * (Look especially at those added in revision 1.10.)
+ */
+#define SEC_ASN1_TAGNUM_MASK		0x1f
+#define SEC_ASN1_BOOLEAN		0x01
+#define SEC_ASN1_INTEGER		0x02
+#define SEC_ASN1_BIT_STRING		0x03
+#define SEC_ASN1_OCTET_STRING		0x04
+#define SEC_ASN1_NULL			0x05
+#define SEC_ASN1_OBJECT_ID		0x06
+#define SEC_ASN1_OBJECT_DESCRIPTOR      0x07
+/* External type and instance-of type   0x08 */
+#define SEC_ASN1_REAL                   0x09
+#define SEC_ASN1_ENUMERATED		0x0a
+#define SEC_ASN1_EMBEDDED_PDV           0x0b
+#define SEC_ASN1_UTF8_STRING		0x0c
+/*                                      0x0d */
+/*                                      0x0e */
+/*                                      0x0f */
+#define SEC_ASN1_SEQUENCE		0x10
+#define SEC_ASN1_SET			0x11
+#define SEC_ASN1_NUMERIC_STRING         0x12
+#define SEC_ASN1_PRINTABLE_STRING	0x13
+#define SEC_ASN1_T61_STRING		0x14
+#define SEC_ASN1_VIDEOTEX_STRING        0x15
+#define SEC_ASN1_IA5_STRING		0x16
+#define SEC_ASN1_UTC_TIME		0x17
+#define SEC_ASN1_GENERALIZED_TIME	0x18
+#define SEC_ASN1_GRAPHIC_STRING         0x19
+#define SEC_ASN1_VISIBLE_STRING		0x1a
+#define SEC_ASN1_GENERAL_STRING         0x1b
+#define SEC_ASN1_UNIVERSAL_STRING	0x1c
+/*                                      0x1d */
+#define SEC_ASN1_BMP_STRING		0x1e
+#define SEC_ASN1_HIGH_TAG_NUMBER	0x1f
+#define SEC_ASN1_TELETEX_STRING 	SEC_ASN1_T61_STRING
+
+/*
+** Modifiers to type tags.  These are also specified by a/the
+** standard, and must not be changed.
+*/
+
+#define SEC_ASN1_METHOD_MASK		0x20
+#define SEC_ASN1_PRIMITIVE		0x00
+#define SEC_ASN1_CONSTRUCTED		0x20
+
+#define SEC_ASN1_CLASS_MASK		0xc0
+#define SEC_ASN1_UNIVERSAL		0x00
+#define SEC_ASN1_APPLICATION		0x40
+#define SEC_ASN1_CONTEXT_SPECIFIC	0x80
+#define SEC_ASN1_PRIVATE		0xc0
+
+/*
+** Our additions, used for templates.
+** These are not defined by any standard; the values are used internally only.
+** Just be careful to keep them out of the low 8 bits.
+** XXX finish comments
+*/
+#define SEC_ASN1_OPTIONAL	0x00100
+#define SEC_ASN1_EXPLICIT	0x00200
+#define SEC_ASN1_ANY		0x00400
+#define SEC_ASN1_INLINE		0x00800
+#define SEC_ASN1_POINTER	0x01000
+#define SEC_ASN1_GROUP		0x02000	/* with SET or SEQUENCE means
+					 * SET OF or SEQUENCE OF */
+#define SEC_ASN1_DYNAMIC	0x04000 /* subtemplate is found by calling
+					 * a function at runtime */
+#define SEC_ASN1_SKIP		0x08000 /* skip a field; only for decoding */
+#define SEC_ASN1_INNER		0x10000	/* with ANY means capture the
+					 * contents only (not the id, len,
+					 * or eoc); only for decoding */
+#define SEC_ASN1_SAVE		0x20000 /* stash away the encoded bytes first;
+					 * only for decoding */
+#define SEC_ASN1_MAY_STREAM	0x40000	/* field or one of its sub-fields may
+					 * stream in and so should encode as
+					 * indefinite-length when streaming
+					 * has been indicated; only for
+					 * encoding */
+#define SEC_ASN1_SKIP_REST	0x80000	/* skip all following fields;
+					   only for decoding */
+#define SEC_ASN1_CHOICE        0x100000 /* pick one from a template */
+#define SEC_ASN1_NO_STREAM     0X200000 /* This entry will not stream
+                                           even if the sub-template says
+                                           streaming is possible.  Helps
+                                           to solve ambiguities with potential
+                                           streaming entries that are 
+                                           optional */
+#define SEC_ASN1_DEBUG_BREAK   0X400000 /* put this in your template and the
+                                           decoder will assert when it
+                                           processes it. Only for use with
+                                           SEC_QuickDERDecodeItem */
+
+                                          
+
+/* Shorthand/Aliases */
+#define SEC_ASN1_SEQUENCE_OF	(SEC_ASN1_GROUP | SEC_ASN1_SEQUENCE)
+#define SEC_ASN1_SET_OF		(SEC_ASN1_GROUP | SEC_ASN1_SET)
+#define SEC_ASN1_ANY_CONTENTS	(SEC_ASN1_ANY | SEC_ASN1_INNER)
+
+/* Maximum depth of nested SEQUENCEs and SETs */
+#define SEC_ASN1D_MAX_DEPTH 32
+
+/*
+** Function used for SEC_ASN1_DYNAMIC.
+** "arg" is a pointer to the structure being encoded/decoded
+** "enc", when true, means that we are encoding (false means decoding)
+*/
+typedef const SEC_ASN1Template * SEC_ASN1TemplateChooser(void *arg, PRBool enc);
+typedef SEC_ASN1TemplateChooser * SEC_ASN1TemplateChooserPtr;
+
+#if defined(_WIN32)
+#define SEC_ASN1_GET(x)        NSS_Get_##x(NULL, PR_FALSE)
+#define SEC_ASN1_SUB(x)        &p_NSS_Get_##x
+#define SEC_ASN1_XTRN          SEC_ASN1_DYNAMIC
+#define SEC_ASN1_MKSUB(x) \
+static const SEC_ASN1TemplateChooserPtr p_NSS_Get_##x = &NSS_Get_##x;
+#else
+#define SEC_ASN1_GET(x)        x
+#define SEC_ASN1_SUB(x)        x
+#define SEC_ASN1_XTRN          0
+#define SEC_ASN1_MKSUB(x) 
+#endif
+
+#define SEC_ASN1_CHOOSER_DECLARE(x) \
+extern const SEC_ASN1Template * NSS_Get_##x (void *arg, PRBool enc);
+
+#define SEC_ASN1_CHOOSER_IMPLEMENT(x) \
+const SEC_ASN1Template * NSS_Get_##x(void * arg, PRBool enc) \
+{ return x; }
+
+/*
+** Opaque object used by the decoder to store state.
+*/
+typedef struct sec_DecoderContext_struct SEC_ASN1DecoderContext;
+
+/*
+** Opaque object used by the encoder to store state.
+*/
+typedef struct sec_EncoderContext_struct SEC_ASN1EncoderContext;
+
+/*
+ * This is used to describe to a filter function the bytes that are
+ * being passed to it.  This is only useful when the filter is an "outer"
+ * one, meaning it expects to get *all* of the bytes not just the
+ * contents octets.
+ */
+typedef enum {
+    SEC_ASN1_Identifier = 0,
+    SEC_ASN1_Length = 1,
+    SEC_ASN1_Contents = 2,
+    SEC_ASN1_EndOfContents = 3
+} SEC_ASN1EncodingPart;
+
+/*
+ * Type of the function pointer used either for decoding or encoding,
+ * when doing anything "funny" (e.g. manipulating the data stream)
+ */ 
+typedef void (* SEC_ASN1NotifyProc)(void *arg, PRBool before,
+				    void *dest, int real_depth);
+
+/*
+ * Type of the function pointer used for grabbing encoded bytes.
+ * This can be used during either encoding or decoding, as follows...
+ *
+ * When decoding, this can be used to filter the encoded bytes as they
+ * are parsed.  This is what you would do if you wanted to process the data
+ * along the way (like to decrypt it, or to perform a hash on it in order
+ * to do a signature check later).  See SEC_ASN1DecoderSetFilterProc().
+ * When processing only part of the encoded bytes is desired, you "watch"
+ * for the field(s) you are interested in with a "notify proc" (see
+ * SEC_ASN1DecoderSetNotifyProc()) and for even finer granularity (e.g. to
+ * ignore all by the contents bytes) you pay attention to the "data_kind"
+ * parameter.
+ *
+ * When encoding, this is the specification for the output function which
+ * will receive the bytes as they are encoded.  The output function can
+ * perform any postprocessing necessary (like hashing (some of) the data
+ * to create a digest that gets included at the end) as well as shoving
+ * the data off wherever it needs to go.  (In order to "tune" any processing,
+ * you can set a "notify proc" as described above in the decoding case.)
+ *
+ * The parameters:
+ * - "arg" is an opaque pointer that you provided at the same time you
+ *   specified a function of this type
+ * - "data" is a buffer of length "len", containing the encoded bytes
+ * - "depth" is how deep in a nested encoding we are (it is not usually
+ *   valuable, but can be useful sometimes so I included it)
+ * - "data_kind" tells you if these bytes are part of the ASN.1 encoded
+ *   octets for identifier, length, contents, or end-of-contents
+ */ 
+typedef void (* SEC_ASN1WriteProc)(void *arg,
+				   const char *data, unsigned long len,
+				   int depth, SEC_ASN1EncodingPart data_kind);
+
+#endif /* _SECASN1T_H_ */
diff --git a/mozilla/security/nss/lib/util/secasn1u.c b/mozilla/security/nss/lib/util/secasn1u.c
new file mode 100644
index 0000000..11eba59
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secasn1u.c
@@ -0,0 +1,131 @@
+/* ***** 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 ***** */
+
+/*
+ * Utility routines to complement the ASN.1 encoding and decoding functions.
+ *
+ * $Id: secasn1u.c,v 1.4 2005/04/09 05:06:34 julien.pierre.bugs%sun.com Exp $
+ */
+
+#include "secasn1.h"
+
+
+/*
+ * We have a length that needs to be encoded; how many bytes will the
+ * encoding take?
+ *
+ * The rules are that 0 - 0x7f takes one byte (the length itself is the
+ * entire encoding); everything else takes one plus the number of bytes
+ * in the length.
+ */
+int
+SEC_ASN1LengthLength (unsigned long len)
+{
+    int lenlen = 1;
+
+    if (len > 0x7f) {
+	do {
+	    lenlen++;
+	    len >>= 8;
+	} while (len);
+    }
+
+    return lenlen;
+}
+
+
+/*
+ * XXX Move over (and rewrite as appropriate) the rest of the
+ * stuff in dersubr.c!
+ */
+
+
+/*
+ * Find the appropriate subtemplate for the given template.
+ * This may involve calling a "chooser" function, or it may just
+ * be right there.  In either case, it is expected to *have* a
+ * subtemplate; this is asserted in debug builds (in non-debug
+ * builds, NULL will be returned).
+ *
+ * "thing" is a pointer to the structure being encoded/decoded
+ * "encoding", when true, means that we are in the process of encoding
+ *	(as opposed to in the process of decoding)
+ */
+const SEC_ASN1Template *
+SEC_ASN1GetSubtemplate (const SEC_ASN1Template *theTemplate, void *thing,
+			PRBool encoding)
+{
+    const SEC_ASN1Template *subt = NULL;
+
+    PORT_Assert (theTemplate->sub != NULL);
+    if (theTemplate->sub != NULL) {
+	if (theTemplate->kind & SEC_ASN1_DYNAMIC) {
+	    SEC_ASN1TemplateChooserPtr chooserp;
+
+	    chooserp = *(SEC_ASN1TemplateChooserPtr *) theTemplate->sub;
+	    if (chooserp) {
+		if (thing != NULL)
+		    thing = (char *)thing - theTemplate->offset;
+		subt = (* chooserp)(thing, encoding);
+	    }
+	} else {
+	    subt = (SEC_ASN1Template*)theTemplate->sub;
+	}
+    }
+    return subt;
+}
+
+PRBool SEC_ASN1IsTemplateSimple(const SEC_ASN1Template *theTemplate)
+{
+    if (!theTemplate) {
+	return PR_TRUE; /* it doesn't get any simpler than NULL */
+    }
+    /* only templates made of one primitive type or a choice of primitive
+       types are considered simple */
+    if (! (theTemplate->kind & (~SEC_ASN1_TAGNUM_MASK))) {
+	return PR_TRUE; /* primitive type */
+    }
+    if (!theTemplate->kind & SEC_ASN1_CHOICE) {
+	return PR_FALSE; /* no choice means not simple */
+    }
+    while (++theTemplate && theTemplate->kind) {
+	if (theTemplate->kind & (~SEC_ASN1_TAGNUM_MASK)) {
+	    return PR_FALSE; /* complex type */
+	}
+    }
+    return PR_TRUE; /* choice of primitive types */
+}
+
diff --git a/mozilla/security/nss/lib/util/seccomon.h b/mozilla/security/nss/lib/util/seccomon.h
new file mode 100644
index 0000000..ebcae64
--- /dev/null
+++ b/mozilla/security/nss/lib/util/seccomon.h
@@ -0,0 +1,119 @@
+/* ***** 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 ***** */
+
+/*
+ * seccomon.h - common data structures for security libraries
+ *
+ * This file should have lowest-common-denominator datastructures
+ * for security libraries.  It should not be dependent on any other
+ * headers, and should not require linking with any libraries.
+ *
+ * $Id: seccomon.h,v 1.7 2007/10/12 01:44:51 julien.pierre.boogz%sun.com Exp $
+ */
+
+#ifndef _SECCOMMON_H_
+#define _SECCOMMON_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+
+
+#ifdef __cplusplus 
+# define SEC_BEGIN_PROTOS extern "C" {
+# define SEC_END_PROTOS }
+#else
+# define SEC_BEGIN_PROTOS
+# define SEC_END_PROTOS
+#endif
+
+#include "secport.h"
+
+typedef enum {
+    siBuffer = 0,
+    siClearDataBuffer = 1,
+    siCipherDataBuffer = 2,
+    siDERCertBuffer = 3,
+    siEncodedCertBuffer = 4,
+    siDERNameBuffer = 5,
+    siEncodedNameBuffer = 6,
+    siAsciiNameString = 7,
+    siAsciiString = 8,
+    siDEROID = 9,
+    siUnsignedInteger = 10,
+    siUTCTime = 11,
+    siGeneralizedTime = 12,
+    siVisibleString = 13,
+    siUTF8String = 14,
+    siBMPString = 15
+} SECItemType;
+
+typedef struct SECItemStr SECItem;
+
+struct SECItemStr {
+    SECItemType type;
+    unsigned char *data;
+    unsigned int len;
+};
+
+/*
+** A status code. Status's are used by procedures that return status
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong. Correct testing of status codes:
+**
+**	SECStatus rv;
+**	rv = some_function (some_argument);
+**	if (rv != SECSuccess)
+**		do_an_error_thing();
+**
+*/
+typedef enum _SECStatus {
+    SECWouldBlock = -2,
+    SECFailure = -1,
+    SECSuccess = 0
+} SECStatus;
+
+/*
+** A comparison code. Used for procedures that return comparision
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong.
+*/
+typedef enum _SECComparison {
+    SECLessThan = -1,
+    SECEqual = 0,
+    SECGreaterThan = 1
+} SECComparison;
+
+#endif /* _SECCOMMON_H_ */
diff --git a/mozilla/security/nss/lib/util/secder.h b/mozilla/security/nss/lib/util/secder.h
new file mode 100644
index 0000000..ed03337
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secder.h
@@ -0,0 +1,211 @@
+/* ***** 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 ***** */
+
+#ifndef _SECDER_H_
+#define _SECDER_H_
+
+#include "utilrename.h"
+
+/*
+ * secder.h - public data structures and prototypes for the DER encoding and
+ *	      decoding utilities library
+ *
+ * $Id: secder.h,v 1.13 2008/06/18 01:04:23 wtc%google.com Exp $
+ */
+
+#if defined(_WIN32_WCE)
+#else
+#include <time.h>
+#endif
+
+#include "plarena.h"
+#include "prlong.h"
+
+#include "seccomon.h"
+#include "secdert.h"
+#include "prtime.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Encode a data structure into DER.
+**	"dest" will be filled in (and memory allocated) to hold the der
+**	   encoded structure in "src"
+**	"t" is a template structure which defines the shape of the
+**	   stored data
+**	"src" is a pointer to the structure that will be encoded
+*/
+extern SECStatus DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *t,
+			   void *src);
+
+extern SECStatus DER_Lengths(SECItem *item, int *header_len_p,
+                             PRUint32 *contents_len_p);
+
+/*
+** Lower level der subroutine that stores the standard header into "to".
+** The header is of variable length, based on encodingLen.
+** The return value is the new value of "to" after skipping over the header.
+**	"to" is where the header will be stored
+**	"code" is the der code to write
+**	"encodingLen" is the number of bytes of data that will follow
+**	   the header
+*/
+extern unsigned char *DER_StoreHeader(unsigned char *to, unsigned int code,
+				      PRUint32 encodingLen);
+
+/*
+** Return the number of bytes it will take to hold a der encoded length.
+*/
+extern int DER_LengthLength(PRUint32 len);
+
+/*
+** Store a der encoded *signed* integer (whose value is "src") into "dst".
+** XXX This should really be enhanced to take a long.
+*/
+extern SECStatus DER_SetInteger(PLArenaPool *arena, SECItem *dst, PRInt32 src);
+
+/*
+** Store a der encoded *unsigned* integer (whose value is "src") into "dst".
+** XXX This should really be enhanced to take an unsigned long.
+*/
+extern SECStatus DER_SetUInteger(PLArenaPool *arena, SECItem *dst, PRUint32 src);
+
+/*
+** Decode a der encoded *signed* integer that is stored in "src".
+** If "-1" is returned, then the caller should check the error in
+** XP_GetError() to see if an overflow occurred (SEC_ERROR_BAD_DER).
+*/
+extern long DER_GetInteger(SECItem *src);
+
+/*
+** Decode a der encoded *unsigned* integer that is stored in "src".
+** If the ULONG_MAX is returned, then the caller should check the error
+** in XP_GetError() to see if an overflow occurred (SEC_ERROR_BAD_DER).
+*/
+extern unsigned long DER_GetUInteger(SECItem *src);
+
+/*
+** Convert an NSPR time value to a der encoded time value.
+**	"result" is the der encoded time (memory is allocated)
+**	"time" is the NSPR time value (Since Jan 1st, 1970).
+**      time must be on or after January 1, 1950, and
+**      before January 1, 2050
+** The caller is responsible for freeing up the buffer which
+** result->data points to upon a successful operation.
+*/
+extern SECStatus DER_TimeToUTCTime(SECItem *result, PRTime time);
+extern SECStatus DER_TimeToUTCTimeArena(PLArenaPool* arenaOpt,
+                                        SECItem *dst, PRTime gmttime);
+
+
+/*
+** Convert an ascii encoded time value (according to DER rules) into
+** an NSPR time value.
+**	"result" the resulting NSPR time
+**	"string" the der notation ascii value to decode
+*/
+extern SECStatus DER_AsciiToTime(PRTime *result, const char *string);
+
+/*
+** Same as DER_AsciiToTime except takes an SECItem instead of a string
+*/
+extern SECStatus DER_UTCTimeToTime(PRTime *result, const SECItem *time);
+
+/*
+** Convert a DER encoded UTC time to an ascii time representation
+** "utctime" is the DER encoded UTC time to be converted. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *DER_UTCTimeToAscii(SECItem *utcTime);
+
+/*
+** Convert a DER encoded UTC time to an ascii time representation, but only
+** include the day, not the time.
+**	"utctime" is the DER encoded UTC time to be converted.
+** The caller is responsible for deallocating the returned buffer.
+*/
+extern char *DER_UTCDayToAscii(SECItem *utctime);
+/* same thing for DER encoded GeneralizedTime */
+extern char *DER_GeneralizedDayToAscii(SECItem *gentime);
+/* same thing for either DER UTCTime or GeneralizedTime */
+extern char *DER_TimeChoiceDayToAscii(SECItem *timechoice);
+
+/*
+** Convert a PRTime time to a DER encoded Generalized time
+** gmttime must be on or after January 1, year 1 and
+** before January 1, 10000.
+*/
+extern SECStatus DER_TimeToGeneralizedTime(SECItem *dst, PRTime gmttime);
+extern SECStatus DER_TimeToGeneralizedTimeArena(PLArenaPool* arenaOpt,
+                                                SECItem *dst, PRTime gmttime);
+
+/*
+** Convert a DER encoded Generalized time value into an NSPR time value.
+**	"dst" the resulting NSPR time
+**	"string" the der notation ascii value to decode
+*/
+extern SECStatus DER_GeneralizedTimeToTime(PRTime *dst, const SECItem *time);
+
+/*
+** Convert from a PRTime UTC time value to a formatted ascii value. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *CERT_UTCTime2FormattedAscii (PRTime utcTime, char *format);
+#define CERT_GeneralizedTime2FormattedAscii CERT_UTCTime2FormattedAscii
+
+/*
+** Convert from a PRTime Generalized time value to a formatted ascii value. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *CERT_GenTime2FormattedAscii (PRTime genTime, char *format);
+
+/*
+** decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME 
+** or a SEC_ASN1_UTC_TIME
+*/
+
+extern SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input);
+
+/* encode a PRTime to an ASN.1 DER SECItem containing either a
+   SEC_ASN1_GENERALIZED_TIME or a SEC_ASN1_UTC_TIME */
+
+extern SECStatus DER_EncodeTimeChoice(PLArenaPool* arena, SECItem* output,
+                                       PRTime input);
+
+SEC_END_PROTOS
+
+#endif /* _SECDER_H_ */
+
diff --git a/mozilla/security/nss/lib/util/secdert.h b/mozilla/security/nss/lib/util/secdert.h
new file mode 100644
index 0000000..e8cc641
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secdert.h
@@ -0,0 +1,163 @@
+/* ***** 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 ***** */
+
+#ifndef _SECDERT_H_
+#define _SECDERT_H_
+/*
+ * secdert.h - public data structures for the DER encoding and
+ *	       decoding utilities library
+ *
+ * $Id: secdert.h,v 1.5 2007/10/12 01:44:51 julien.pierre.boogz%sun.com Exp $
+ */
+
+#include "utilrename.h"
+#include "seccomon.h"
+
+typedef struct DERTemplateStr DERTemplate;
+
+/*
+** An array of these structures defines an encoding for an object using DER.
+** The array usually starts with a dummy entry whose kind is DER_SEQUENCE;
+** such an array is terminated with an entry where kind == 0.  (An array
+** which consists of a single component does not require a second dummy
+** entry -- the array is only searched as long as previous component(s)
+** instruct it.)
+*/
+struct DERTemplateStr {
+    /*
+    ** Kind of item being decoded/encoded, including tags and modifiers.
+    */
+    unsigned long kind;
+
+    /*
+    ** Offset from base of structure to field that holds the value
+    ** being decoded/encoded.
+    */
+    unsigned int offset;
+
+    /*
+    ** When kind suggests it (DER_POINTER, DER_INDEFINITE, DER_INLINE),
+    ** this points to a sub-template for nested encoding/decoding.
+    */
+    DERTemplate *sub;
+
+    /*
+    ** Argument value, dependent on "kind" and/or template placement
+    ** within an array of templates:
+    **	- In the first element of a template array, the value is the
+    **	  size of the structure to allocate when this template is being
+    **	  referenced by another template via DER_POINTER or DER_INDEFINITE.
+    **  - In a component of a DER_SET or DER_SEQUENCE which is *not* a
+    **	  DER_UNIVERSAL type (that is, it has a class tag for either
+    **	  DER_APPLICATION, DER_CONTEXT_SPECIFIC, or DER_PRIVATE), the
+    **	  value is the underlying type of item being decoded/encoded.
+    */
+    unsigned long arg;
+};
+
+/************************************************************************/
+
+/* default chunksize for arenas used for DER stuff */
+#define DER_DEFAULT_CHUNKSIZE (2048)
+
+/*
+** BER/DER values for ASN.1 identifier octets.
+*/
+#define DER_TAG_MASK		0xff
+
+/*
+ * BER/DER universal type tag numbers.
+ * The values are defined by the X.208 standard; do not change them!
+ * NOTE: if you add anything to this list, you must add code to derdec.c
+ * to accept the tag, and probably also to derenc.c to encode it.
+ */
+#define DER_TAGNUM_MASK		0x1f
+#define DER_BOOLEAN		0x01
+#define DER_INTEGER		0x02
+#define DER_BIT_STRING		0x03
+#define DER_OCTET_STRING	0x04
+#define DER_NULL		0x05
+#define DER_OBJECT_ID		0x06
+#define DER_SEQUENCE		0x10
+#define DER_SET			0x11
+#define DER_PRINTABLE_STRING	0x13
+#define DER_T61_STRING		0x14
+#define DER_IA5_STRING		0x16
+#define DER_UTC_TIME		0x17
+#define DER_VISIBLE_STRING	0x1a
+#define DER_HIGH_TAG_NUMBER	0x1f
+
+/*
+** Modifiers to type tags.  These are also specified by a/the
+** standard, and must not be changed.
+*/
+
+#define DER_METHOD_MASK		0x20
+#define DER_PRIMITIVE		0x00
+#define DER_CONSTRUCTED		0x20
+
+#define DER_CLASS_MASK		0xc0
+#define DER_UNIVERSAL		0x00
+#define DER_APPLICATION		0x40
+#define DER_CONTEXT_SPECIFIC	0x80
+#define DER_PRIVATE		0xc0
+
+/*
+** Our additions, used for templates.
+** These are not defined by any standard; the values are used internally only.
+** Just be careful to keep them out of the low 8 bits.
+*/
+#define DER_OPTIONAL		0x00100
+#define DER_EXPLICIT		0x00200
+#define DER_ANY			0x00400
+#define DER_INLINE		0x00800
+#define DER_POINTER		0x01000
+#define DER_INDEFINITE		0x02000
+#define DER_DERPTR		0x04000
+#define DER_SKIP		0x08000
+#define DER_FORCE		0x10000
+#define DER_OUTER		0x40000 /* for DER_DERPTR */
+
+/*
+** Macro to convert der decoded bit string into a decoded octet
+** string. All it needs to do is fiddle with the length code.
+*/
+#define DER_ConvertBitString(item)	  \
+{					  \
+    (item)->len = ((item)->len + 7) >> 3; \
+}
+
+#endif /* _SECDERT_H_ */
diff --git a/mozilla/security/nss/lib/util/secdig.c b/mozilla/security/nss/lib/util/secdig.c
new file mode 100644
index 0000000..85f5dac
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secdig.c
@@ -0,0 +1,212 @@
+/* ***** 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 ***** */
+/* $Id: secdig.c,v 1.9 2007/11/07 02:37:22 julien.pierre.boogz%sun.com Exp $ */
+#include "secdig.h"
+
+#include "secoid.h"
+#include "secasn1.h" 
+#include "secerr.h"
+
+/*
+ * XXX Want to have a SGN_DecodeDigestInfo, like:
+ *	SGNDigestInfo *SGN_DecodeDigestInfo(SECItem *didata);
+ * that creates a pool and allocates from it and decodes didata into
+ * the newly allocated DigestInfo structure.  Then fix secvfy.c (it
+ * will no longer need an arena itself) to call this and then call
+ * DestroyDigestInfo when it is done, then can remove the old template
+ * above and keep our new template static and "hidden".
+ */
+
+/*
+ * XXX It might be nice to combine the following two functions (create
+ * and encode).  I think that is all anybody ever wants to do anyway.
+ */
+
+SECItem *
+SGN_EncodeDigestInfo(PRArenaPool *poolp, SECItem *dest, SGNDigestInfo *diginfo)
+{
+    return SEC_ASN1EncodeItem (poolp, dest, diginfo, sgn_DigestInfoTemplate);
+}
+
+SGNDigestInfo *
+SGN_CreateDigestInfo(SECOidTag algorithm, unsigned char *sig, unsigned len)
+{
+    SGNDigestInfo *di;
+    SECStatus rv;
+    PRArenaPool *arena;
+    SECItem *null_param;
+    SECItem dummy_value;
+
+    switch (algorithm) {
+      case SEC_OID_MD2:
+      case SEC_OID_MD5:
+      case SEC_OID_SHA1:
+      case SEC_OID_SHA256:
+      case SEC_OID_SHA384:
+      case SEC_OID_SHA512:
+	break;
+      default:
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return NULL;
+    }
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+	return NULL;
+    }
+
+    di = (SGNDigestInfo *) PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
+    if (di == NULL) {
+	PORT_FreeArena(arena, PR_FALSE);
+	return NULL;
+    }
+
+    di->arena = arena;
+
+    /*
+     * PKCS #1 specifies that the AlgorithmID must have a NULL parameter
+     * (as opposed to no parameter at all).
+     */
+    dummy_value.data = NULL;
+    dummy_value.len = 0;
+    null_param = SEC_ASN1EncodeItem(NULL, NULL, &dummy_value, SEC_NullTemplate);
+    if (null_param == NULL) {
+	goto loser;
+    }
+
+    rv = SECOID_SetAlgorithmID(arena, &di->digestAlgorithm, algorithm,
+			       null_param);
+
+    SECITEM_FreeItem(null_param, PR_TRUE);
+
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    di->digest.data = (unsigned char *) PORT_ArenaAlloc(arena, len);
+    if (di->digest.data == NULL) {
+	goto loser;
+    }
+
+    di->digest.len = len;
+    PORT_Memcpy(di->digest.data, sig, len);
+    return di;
+
+  loser:
+    SGN_DestroyDigestInfo(di);
+    return NULL;
+}
+
+SGNDigestInfo *
+SGN_DecodeDigestInfo(SECItem *didata)
+{
+    PRArenaPool *arena;
+    SGNDigestInfo *di;
+    SECStatus rv = SECFailure;
+    SECItem      diCopy   = {siBuffer, NULL, 0};
+
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if(arena == NULL)
+	return NULL;
+
+    rv = SECITEM_CopyItem(arena, &diCopy, didata);
+    if (rv != SECSuccess) {
+	PORT_FreeArena(arena, PR_FALSE);
+    	return NULL;
+    }
+
+    di = (SGNDigestInfo *)PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
+    if (di != NULL) {
+	di->arena = arena;
+	rv = SEC_QuickDERDecodeItem(arena, di, sgn_DigestInfoTemplate, &diCopy);
+    }
+	
+    if ((di == NULL) || (rv != SECSuccess)) {
+	PORT_FreeArena(arena, PR_FALSE);
+	di = NULL;
+    }
+
+    return di;
+}
+
+void
+SGN_DestroyDigestInfo(SGNDigestInfo *di)
+{
+    if (di && di->arena) {
+	PORT_FreeArena(di->arena, PR_FALSE);
+    }
+
+    return;
+}
+
+SECStatus 
+SGN_CopyDigestInfo(PRArenaPool *poolp, SGNDigestInfo *a, SGNDigestInfo *b)
+{
+    SECStatus rv;
+    void *mark;
+
+    if((poolp == NULL) || (a == NULL) || (b == NULL))
+	return SECFailure;
+
+    mark = PORT_ArenaMark(poolp);
+    a->arena = poolp;
+    rv = SECOID_CopyAlgorithmID(poolp, &a->digestAlgorithm, 
+	&b->digestAlgorithm);
+    if (rv == SECSuccess)
+	rv = SECITEM_CopyItem(poolp, &a->digest, &b->digest);
+
+    if (rv != SECSuccess) {
+	PORT_ArenaRelease(poolp, mark);
+    } else {
+	PORT_ArenaUnmark(poolp, mark);
+    }
+
+    return rv;
+}
+
+SECComparison
+SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b)
+{
+    SECComparison rv;
+
+    /* Check signature algorithm's */
+    rv = SECOID_CompareAlgorithmID(&a->digestAlgorithm, &b->digestAlgorithm);
+    if (rv) return rv;
+
+    /* Compare signature block length's */
+    rv = SECITEM_CompareItem(&a->digest, &b->digest);
+    return rv;
+}
diff --git a/mozilla/security/nss/lib/util/secdig.h b/mozilla/security/nss/lib/util/secdig.h
new file mode 100644
index 0000000..0d97a16
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secdig.h
@@ -0,0 +1,136 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * ***** 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 ***** */
+/* $Id: secdig.h,v 1.8 2008/06/14 14:20:38 wtc%google.com Exp $ */
+
+#ifndef _SECDIG_H_
+#define _SECDIG_H_
+
+#include "utilrename.h"
+#include "secdigt.h"
+
+#include "seccomon.h"
+#include "secasn1t.h" 
+#include "secdert.h"
+
+SEC_BEGIN_PROTOS
+
+
+extern const SEC_ASN1Template sgn_DigestInfoTemplate[];
+
+SEC_ASN1_CHOOSER_DECLARE(sgn_DigestInfoTemplate)
+
+/****************************************/
+/*
+** Digest-info functions
+*/
+
+/*
+** Create a new digest-info object
+** 	"algorithm" one of SEC_OID_MD2, SEC_OID_MD5, or SEC_OID_SHA1
+** 	"sig" the raw signature data (from MD2 or MD5)
+** 	"sigLen" the length of the signature data
+**
+** NOTE: this is a low level routine used to prepare some data for PKCS#1
+** digital signature formatting.
+**
+** XXX It might be nice to combine the create and encode functions.
+** I think that is all anybody ever wants to do anyway.
+*/
+extern SGNDigestInfo *SGN_CreateDigestInfo(SECOidTag algorithm,
+					   unsigned char *sig,
+					   unsigned int sigLen);
+
+/*
+** Destroy a digest-info object
+*/
+extern void SGN_DestroyDigestInfo(SGNDigestInfo *info);
+
+/*
+** Encode a digest-info object
+**	"poolp" is where to allocate the result from; it can be NULL in
+**		which case generic heap allocation (XP_ALLOC) will be used
+**	"dest" is where to store the result; it can be NULL, in which case
+**		it will be allocated (from poolp or heap, as explained above)
+**	"diginfo" is the object to be encoded
+** The return value is NULL if any error occurred, otherwise it is the
+** resulting SECItem (either allocated or the same as the "dest" parameter).
+**
+** XXX It might be nice to combine the create and encode functions.
+** I think that is all anybody ever wants to do anyway.
+*/
+extern SECItem *SGN_EncodeDigestInfo(PLArenaPool *poolp, SECItem *dest,
+				     SGNDigestInfo *diginfo);
+
+/*
+** Decode a DER encoded digest info objct.
+**  didata is thr source of the encoded digest.  
+** The return value is NULL if an error occurs.  Otherwise, a
+** digest info object which is allocated within it's own
+** pool is returned.  The digest info should be deleted
+** by later calling SGN_DestroyDigestInfo.
+*/
+extern SGNDigestInfo *SGN_DecodeDigestInfo(SECItem *didata);
+
+
+/*
+** Copy digest info.
+**  poolp is the arena to which the digest will be copied.
+**  a is the destination digest, it must be non-NULL.
+**  b is the source digest
+** This function is for copying digests.  It allows digests
+** to be copied into a specified pool.  If the digest is in
+** the same pool as other data, you do not want to delete
+** the digest by calling SGN_DestroyDigestInfo.  
+** A return value of SECFailure indicates an error.  A return
+** of SECSuccess indicates no error occured.
+*/
+extern SECStatus  SGN_CopyDigestInfo(PLArenaPool *poolp,
+					SGNDigestInfo *a, 
+					SGNDigestInfo *b);
+
+/*
+** Compare two digest-info objects, returning the difference between
+** them.
+*/
+extern SECComparison SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b);
+
+
+SEC_END_PROTOS
+
+#endif /* _SECDIG_H_ */
diff --git a/mozilla/security/nss/lib/util/secdigt.h b/mozilla/security/nss/lib/util/secdigt.h
new file mode 100644
index 0000000..222ce03
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secdigt.h
@@ -0,0 +1,61 @@
+/*
+ * secdigt.h - public data structures for digestinfos from the util lib.
+ *
+ * ***** 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 ***** */
+/* $Id: secdigt.h,v 1.4 2007/10/12 01:44:51 julien.pierre.boogz%sun.com Exp $ */
+
+#ifndef _SECDIGT_H_
+#define _SECDIGT_H_
+
+#include "utilrename.h"
+#include "plarena.h"
+#include "secoidt.h"
+#include "secitem.h"
+
+/*
+** A PKCS#1 digest-info object
+*/
+struct SGNDigestInfoStr {
+    PLArenaPool *  arena;
+    SECAlgorithmID digestAlgorithm;
+    SECItem        digest;
+};
+typedef struct SGNDigestInfoStr SGNDigestInfo;
+
+
+
+#endif /* _SECDIGT_H_ */
diff --git a/mozilla/security/nss/lib/util/secerr.h b/mozilla/security/nss/lib/util/secerr.h
new file mode 100644
index 0000000..c1ce246
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secerr.h
@@ -0,0 +1,236 @@
+/* ***** 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 ***** */
+
+#ifndef __SEC_ERR_H_
+#define __SEC_ERR_H_
+
+#include "utilrename.h"
+
+#define SEC_ERROR_BASE				(-0x2000)
+#define SEC_ERROR_LIMIT				(SEC_ERROR_BASE + 1000)
+
+#define IS_SEC_ERROR(code) \
+    (((code) >= SEC_ERROR_BASE) && ((code) < SEC_ERROR_LIMIT))
+
+#ifndef NO_SECURITY_ERROR_ENUM
+typedef enum {
+SEC_ERROR_IO 				    =	SEC_ERROR_BASE + 0,
+SEC_ERROR_LIBRARY_FAILURE 		    =	SEC_ERROR_BASE + 1,
+SEC_ERROR_BAD_DATA 			    =	SEC_ERROR_BASE + 2,
+SEC_ERROR_OUTPUT_LEN 			    =	SEC_ERROR_BASE + 3,
+SEC_ERROR_INPUT_LEN 			    =	SEC_ERROR_BASE + 4,
+SEC_ERROR_INVALID_ARGS 			    =	SEC_ERROR_BASE + 5,
+SEC_ERROR_INVALID_ALGORITHM 		    =	SEC_ERROR_BASE + 6,
+SEC_ERROR_INVALID_AVA 			    =	SEC_ERROR_BASE + 7,
+SEC_ERROR_INVALID_TIME 			    =	SEC_ERROR_BASE + 8,
+SEC_ERROR_BAD_DER 			    =	SEC_ERROR_BASE + 9,
+SEC_ERROR_BAD_SIGNATURE 		    =	SEC_ERROR_BASE + 10,
+SEC_ERROR_EXPIRED_CERTIFICATE 		    =	SEC_ERROR_BASE + 11,
+SEC_ERROR_REVOKED_CERTIFICATE 		    =	SEC_ERROR_BASE + 12,
+SEC_ERROR_UNKNOWN_ISSUER 		    =	SEC_ERROR_BASE + 13,
+SEC_ERROR_BAD_KEY 			    =	SEC_ERROR_BASE + 14,
+SEC_ERROR_BAD_PASSWORD 			    =	SEC_ERROR_BASE + 15,
+SEC_ERROR_RETRY_PASSWORD 		    =	SEC_ERROR_BASE + 16,
+SEC_ERROR_NO_NODELOCK 			    =	SEC_ERROR_BASE + 17,
+SEC_ERROR_BAD_DATABASE 			    =	SEC_ERROR_BASE + 18,
+SEC_ERROR_NO_MEMORY 			    =	SEC_ERROR_BASE + 19,
+SEC_ERROR_UNTRUSTED_ISSUER 		    =	SEC_ERROR_BASE + 20,
+SEC_ERROR_UNTRUSTED_CERT 		    =	SEC_ERROR_BASE + 21,
+SEC_ERROR_DUPLICATE_CERT 		    =	(SEC_ERROR_BASE + 22),
+SEC_ERROR_DUPLICATE_CERT_NAME 		    =	(SEC_ERROR_BASE + 23),
+SEC_ERROR_ADDING_CERT 			    =	(SEC_ERROR_BASE + 24),
+SEC_ERROR_FILING_KEY 			    =	(SEC_ERROR_BASE + 25),
+SEC_ERROR_NO_KEY 			    =	(SEC_ERROR_BASE + 26),
+SEC_ERROR_CERT_VALID 			    =	(SEC_ERROR_BASE + 27),
+SEC_ERROR_CERT_NOT_VALID 		    =	(SEC_ERROR_BASE + 28),
+SEC_ERROR_CERT_NO_RESPONSE 		    =	(SEC_ERROR_BASE + 29),
+SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE 	    =	(SEC_ERROR_BASE + 30),
+SEC_ERROR_CRL_EXPIRED 			    =	(SEC_ERROR_BASE + 31),
+SEC_ERROR_CRL_BAD_SIGNATURE 		    =	(SEC_ERROR_BASE + 32),
+SEC_ERROR_CRL_INVALID 			    =	(SEC_ERROR_BASE + 33),
+SEC_ERROR_EXTENSION_VALUE_INVALID 	    = 	(SEC_ERROR_BASE + 34),
+SEC_ERROR_EXTENSION_NOT_FOUND 		    = 	(SEC_ERROR_BASE + 35),
+SEC_ERROR_CA_CERT_INVALID 		    = 	(SEC_ERROR_BASE + 36),
+SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID 	    = 	(SEC_ERROR_BASE + 37),
+SEC_ERROR_CERT_USAGES_INVALID 		    = 	(SEC_ERROR_BASE + 38),
+SEC_INTERNAL_ONLY 			    =	(SEC_ERROR_BASE + 39),
+SEC_ERROR_INVALID_KEY 			    =	(SEC_ERROR_BASE + 40),
+SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION 	    = 	(SEC_ERROR_BASE + 41),
+SEC_ERROR_OLD_CRL 			    =	(SEC_ERROR_BASE + 42),
+SEC_ERROR_NO_EMAIL_CERT 		    =	(SEC_ERROR_BASE + 43),
+SEC_ERROR_NO_RECIPIENT_CERTS_QUERY 	    =	(SEC_ERROR_BASE + 44),
+SEC_ERROR_NOT_A_RECIPIENT 		    =	(SEC_ERROR_BASE + 45),
+SEC_ERROR_PKCS7_KEYALG_MISMATCH 	    =	(SEC_ERROR_BASE + 46),
+SEC_ERROR_PKCS7_BAD_SIGNATURE 		    =	(SEC_ERROR_BASE + 47),
+SEC_ERROR_UNSUPPORTED_KEYALG 		    =	(SEC_ERROR_BASE + 48),
+SEC_ERROR_DECRYPTION_DISALLOWED 	    =	(SEC_ERROR_BASE + 49),
+/* Fortezza Alerts */
+XP_SEC_FORTEZZA_BAD_CARD 		    =	(SEC_ERROR_BASE + 50),
+XP_SEC_FORTEZZA_NO_CARD 		    =	(SEC_ERROR_BASE + 51),
+XP_SEC_FORTEZZA_NONE_SELECTED 		    =	(SEC_ERROR_BASE + 52),
+XP_SEC_FORTEZZA_MORE_INFO 		    =	(SEC_ERROR_BASE + 53),
+XP_SEC_FORTEZZA_PERSON_NOT_FOUND 	    =	(SEC_ERROR_BASE + 54),
+XP_SEC_FORTEZZA_NO_MORE_INFO 		    =	(SEC_ERROR_BASE + 55),
+XP_SEC_FORTEZZA_BAD_PIN 		    =	(SEC_ERROR_BASE + 56),
+XP_SEC_FORTEZZA_PERSON_ERROR 		    =	(SEC_ERROR_BASE + 57),
+SEC_ERROR_NO_KRL 			    =	(SEC_ERROR_BASE + 58),
+SEC_ERROR_KRL_EXPIRED 			    =	(SEC_ERROR_BASE + 59),
+SEC_ERROR_KRL_BAD_SIGNATURE 		    =	(SEC_ERROR_BASE + 60),
+SEC_ERROR_REVOKED_KEY 			    =	(SEC_ERROR_BASE + 61),
+SEC_ERROR_KRL_INVALID 			    =	(SEC_ERROR_BASE + 62),
+SEC_ERROR_NEED_RANDOM 			    =	(SEC_ERROR_BASE + 63),
+SEC_ERROR_NO_MODULE 			    =	(SEC_ERROR_BASE + 64),
+SEC_ERROR_NO_TOKEN 			    =	(SEC_ERROR_BASE + 65),
+SEC_ERROR_READ_ONLY 			    =	(SEC_ERROR_BASE + 66),
+SEC_ERROR_NO_SLOT_SELECTED 		    =	(SEC_ERROR_BASE + 67),
+SEC_ERROR_CERT_NICKNAME_COLLISION 	    =	(SEC_ERROR_BASE + 68),
+SEC_ERROR_KEY_NICKNAME_COLLISION 	    =	(SEC_ERROR_BASE + 69),
+SEC_ERROR_SAFE_NOT_CREATED 		    =	(SEC_ERROR_BASE + 70),
+SEC_ERROR_BAGGAGE_NOT_CREATED 		    =	(SEC_ERROR_BASE + 71),
+XP_JAVA_REMOVE_PRINCIPAL_ERROR 		    =	(SEC_ERROR_BASE + 72),
+XP_JAVA_DELETE_PRIVILEGE_ERROR 		    =	(SEC_ERROR_BASE + 73),
+XP_JAVA_CERT_NOT_EXISTS_ERROR 		    =	(SEC_ERROR_BASE + 74),
+SEC_ERROR_BAD_EXPORT_ALGORITHM 		    =	(SEC_ERROR_BASE + 75),
+SEC_ERROR_EXPORTING_CERTIFICATES 	    =	(SEC_ERROR_BASE + 76),
+SEC_ERROR_IMPORTING_CERTIFICATES 	    =	(SEC_ERROR_BASE + 77),
+SEC_ERROR_PKCS12_DECODING_PFX 		    =	(SEC_ERROR_BASE + 78),
+SEC_ERROR_PKCS12_INVALID_MAC 		    =	(SEC_ERROR_BASE + 79),
+SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM  =	(SEC_ERROR_BASE + 80),
+SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE =	(SEC_ERROR_BASE + 81),
+SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE 	    =	(SEC_ERROR_BASE + 82),
+SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM  = 	(SEC_ERROR_BASE + 83),
+SEC_ERROR_PKCS12_UNSUPPORTED_VERSION 	    =	(SEC_ERROR_BASE + 84),
+SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT =	(SEC_ERROR_BASE + 85),
+SEC_ERROR_PKCS12_CERT_COLLISION 	    =	(SEC_ERROR_BASE + 86),
+SEC_ERROR_USER_CANCELLED 		    =	(SEC_ERROR_BASE + 87),
+SEC_ERROR_PKCS12_DUPLICATE_DATA 	    =	(SEC_ERROR_BASE + 88),
+SEC_ERROR_MESSAGE_SEND_ABORTED 		    =	(SEC_ERROR_BASE + 89),
+SEC_ERROR_INADEQUATE_KEY_USAGE 		    =	(SEC_ERROR_BASE + 90),
+SEC_ERROR_INADEQUATE_CERT_TYPE 		    =	(SEC_ERROR_BASE + 91),
+SEC_ERROR_CERT_ADDR_MISMATCH 		    =	(SEC_ERROR_BASE + 92),
+SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY 	    =	(SEC_ERROR_BASE + 93),
+SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN 	    =	(SEC_ERROR_BASE + 94),
+SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME = (SEC_ERROR_BASE + 95),
+SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY 	    =	(SEC_ERROR_BASE + 96),
+SEC_ERROR_PKCS12_UNABLE_TO_WRITE 	    = 	(SEC_ERROR_BASE + 97),
+SEC_ERROR_PKCS12_UNABLE_TO_READ 	    =	(SEC_ERROR_BASE + 98),
+SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED 	 = (SEC_ERROR_BASE + 99),
+SEC_ERROR_KEYGEN_FAIL 			    =	(SEC_ERROR_BASE + 100),
+SEC_ERROR_INVALID_PASSWORD 		    =	(SEC_ERROR_BASE + 101),
+SEC_ERROR_RETRY_OLD_PASSWORD 		    =	(SEC_ERROR_BASE + 102),
+SEC_ERROR_BAD_NICKNAME 			    =	(SEC_ERROR_BASE + 103),
+SEC_ERROR_NOT_FORTEZZA_ISSUER 		    = 	(SEC_ERROR_BASE + 104),
+SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY         =   (SEC_ERROR_BASE + 105),
+SEC_ERROR_JS_INVALID_MODULE_NAME 	    =	(SEC_ERROR_BASE + 106),
+SEC_ERROR_JS_INVALID_DLL 		    =	(SEC_ERROR_BASE + 107),
+SEC_ERROR_JS_ADD_MOD_FAILURE 		    =	(SEC_ERROR_BASE + 108),
+SEC_ERROR_JS_DEL_MOD_FAILURE 		    =	(SEC_ERROR_BASE + 109),
+SEC_ERROR_OLD_KRL 			    =	(SEC_ERROR_BASE + 110),
+SEC_ERROR_CKL_CONFLICT 			    =	(SEC_ERROR_BASE + 111),
+SEC_ERROR_CERT_NOT_IN_NAME_SPACE 	    =	(SEC_ERROR_BASE + 112),
+SEC_ERROR_KRL_NOT_YET_VALID 		    =	(SEC_ERROR_BASE + 113),
+SEC_ERROR_CRL_NOT_YET_VALID 		    =	(SEC_ERROR_BASE + 114),
+SEC_ERROR_UNKNOWN_CERT 			    =	(SEC_ERROR_BASE + 115),
+SEC_ERROR_UNKNOWN_SIGNER 		    =	(SEC_ERROR_BASE + 116),
+SEC_ERROR_CERT_BAD_ACCESS_LOCATION 	    =	(SEC_ERROR_BASE + 117),
+SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE 	    =	(SEC_ERROR_BASE + 118),
+SEC_ERROR_OCSP_BAD_HTTP_RESPONSE 	    =	(SEC_ERROR_BASE + 119),
+SEC_ERROR_OCSP_MALFORMED_REQUEST 	    =	(SEC_ERROR_BASE + 120),
+SEC_ERROR_OCSP_SERVER_ERROR 		    =	(SEC_ERROR_BASE + 121),
+SEC_ERROR_OCSP_TRY_SERVER_LATER 	    =	(SEC_ERROR_BASE + 122),
+SEC_ERROR_OCSP_REQUEST_NEEDS_SIG 	    =	(SEC_ERROR_BASE + 123),
+SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST 	    =	(SEC_ERROR_BASE + 124),
+SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS 	    =	(SEC_ERROR_BASE + 125),
+SEC_ERROR_OCSP_UNKNOWN_CERT 		    =	(SEC_ERROR_BASE + 126),
+SEC_ERROR_OCSP_NOT_ENABLED 		    =	(SEC_ERROR_BASE + 127),
+SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER 	    =	(SEC_ERROR_BASE + 128),
+SEC_ERROR_OCSP_MALFORMED_RESPONSE 	    =	(SEC_ERROR_BASE + 129),
+SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE 	    =	(SEC_ERROR_BASE + 130),
+SEC_ERROR_OCSP_FUTURE_RESPONSE 		    =	(SEC_ERROR_BASE + 131),
+SEC_ERROR_OCSP_OLD_RESPONSE 		    =	(SEC_ERROR_BASE + 132),
+/* smime stuff */
+SEC_ERROR_DIGEST_NOT_FOUND		    =	(SEC_ERROR_BASE + 133),
+SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE	    =	(SEC_ERROR_BASE + 134),
+SEC_ERROR_MODULE_STUCK			    =	(SEC_ERROR_BASE + 135),
+SEC_ERROR_BAD_TEMPLATE			    =	(SEC_ERROR_BASE + 136),
+SEC_ERROR_CRL_NOT_FOUND 		    =	(SEC_ERROR_BASE + 137),
+SEC_ERROR_REUSED_ISSUER_AND_SERIAL          =   (SEC_ERROR_BASE + 138),
+SEC_ERROR_BUSY                              =   (SEC_ERROR_BASE + 139),
+SEC_ERROR_EXTRA_INPUT                       =   (SEC_ERROR_BASE + 140),
+/* error codes used by elliptic curve code */
+SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE	    =	(SEC_ERROR_BASE + 141),
+SEC_ERROR_UNSUPPORTED_EC_POINT_FORM	    =	(SEC_ERROR_BASE + 142),
+SEC_ERROR_UNRECOGNIZED_OID		    =	(SEC_ERROR_BASE + 143),
+SEC_ERROR_OCSP_INVALID_SIGNING_CERT	    =   (SEC_ERROR_BASE + 144),
+/* new revocation errors */
+SEC_ERROR_REVOKED_CERTIFICATE_CRL	    =	(SEC_ERROR_BASE + 145),
+SEC_ERROR_REVOKED_CERTIFICATE_OCSP	    =	(SEC_ERROR_BASE + 146),
+SEC_ERROR_CRL_INVALID_VERSION               =	(SEC_ERROR_BASE + 147),
+SEC_ERROR_CRL_V1_CRITICAL_EXTENSION         =	(SEC_ERROR_BASE + 148),
+SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION    =	(SEC_ERROR_BASE + 149),
+SEC_ERROR_UNKNOWN_OBJECT_TYPE               =	(SEC_ERROR_BASE + 150),
+SEC_ERROR_INCOMPATIBLE_PKCS11               =	(SEC_ERROR_BASE + 151),
+SEC_ERROR_NO_EVENT                          = 	(SEC_ERROR_BASE + 152),
+SEC_ERROR_CRL_ALREADY_EXISTS                = 	(SEC_ERROR_BASE + 153),
+SEC_ERROR_NOT_INITIALIZED                   = 	(SEC_ERROR_BASE + 154),
+SEC_ERROR_TOKEN_NOT_LOGGED_IN               = 	(SEC_ERROR_BASE + 155),
+SEC_ERROR_OCSP_RESPONDER_CERT_INVALID      =	(SEC_ERROR_BASE + 156),
+SEC_ERROR_OCSP_BAD_SIGNATURE               =	(SEC_ERROR_BASE + 157),
+
+SEC_ERROR_OUT_OF_SEARCH_LIMITS             =	(SEC_ERROR_BASE + 158),
+SEC_ERROR_INVALID_POLICY_MAPPING           =	(SEC_ERROR_BASE + 159),
+SEC_ERROR_POLICY_VALIDATION_FAILED         =	(SEC_ERROR_BASE + 160),
+SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE        =	(SEC_ERROR_BASE + 161),
+SEC_ERROR_BAD_HTTP_RESPONSE                =	(SEC_ERROR_BASE + 162),
+SEC_ERROR_BAD_LDAP_RESPONSE                =	(SEC_ERROR_BASE + 163),
+SEC_ERROR_FAILED_TO_ENCODE_DATA            =	(SEC_ERROR_BASE + 164),
+SEC_ERROR_BAD_INFO_ACCESS_LOCATION         =	(SEC_ERROR_BASE + 165), 
+
+SEC_ERROR_LIBPKIX_INTERNAL                 =	(SEC_ERROR_BASE + 166),
+
+SEC_ERROR_PKCS11_GENERAL_ERROR             =	(SEC_ERROR_BASE + 167),
+SEC_ERROR_PKCS11_FUNCTION_FAILED           =	(SEC_ERROR_BASE + 168),
+SEC_ERROR_PKCS11_DEVICE_ERROR              =	(SEC_ERROR_BASE + 169),
+
+SEC_ERROR_BAD_INFO_ACCESS_METHOD           =    (SEC_ERROR_BASE + 170),
+SEC_ERROR_CRL_IMPORT_FAILED                =    (SEC_ERROR_BASE + 171),
+
+/* Add new error codes above here. */
+SEC_ERROR_END_OF_LIST 
+} SECErrorCodes;
+#endif /* NO_SECURITY_ERROR_ENUM */
+
+#endif /* __SEC_ERR_H_ */
diff --git a/mozilla/security/nss/lib/util/secinit.c b/mozilla/security/nss/lib/util/secinit.c
new file mode 100644
index 0000000..c62d83a
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secinit.c
@@ -0,0 +1,53 @@
+/* ***** 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 "secport.h"
+
+static int sec_inited = 0;
+
+void 
+SEC_Init(void)
+{
+    /* PR_Init() must be called before SEC_Init() */
+#if !defined(SERVER_BUILD)
+    PORT_Assert(PR_Initialized() == PR_TRUE);
+#endif
+    if (sec_inited)
+	return;
+
+    sec_inited = 1;
+}
diff --git a/mozilla/security/nss/lib/util/secitem.c b/mozilla/security/nss/lib/util/secitem.c
new file mode 100644
index 0000000..382f3c3
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secitem.c
@@ -0,0 +1,324 @@
+/* ***** 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 ***** */
+
+/*
+ * Support routines for SECItem data structure.
+ *
+ * $Id: secitem.c,v 1.15 2008/11/19 16:04:38 nelson%bolyard.com Exp $
+ */
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "base64.h"
+#include "secerr.h"
+
+SECItem *
+SECITEM_AllocItem(PRArenaPool *arena, SECItem *item, unsigned int len)
+{
+    SECItem *result = NULL;
+    void *mark = NULL;
+
+    if (arena != NULL) {
+	mark = PORT_ArenaMark(arena);
+    }
+
+    if (item == NULL) {
+	if (arena != NULL) {
+	    result = PORT_ArenaZAlloc(arena, sizeof(SECItem));
+	} else {
+	    result = PORT_ZAlloc(sizeof(SECItem));
+	}
+	if (result == NULL) {
+	    goto loser;
+	}
+    } else {
+	PORT_Assert(item->data == NULL);
+	result = item;
+    }
+
+    result->len = len;
+    if (len) {
+	if (arena != NULL) {
+	    result->data = PORT_ArenaAlloc(arena, len);
+	} else {
+	    result->data = PORT_Alloc(len);
+	}
+	if (result->data == NULL) {
+	    goto loser;
+	}
+    } else {
+	result->data = NULL;
+    }
+
+    if (mark) {
+	PORT_ArenaUnmark(arena, mark);
+    }
+    return(result);
+
+loser:
+    if ( arena != NULL ) {
+	if (mark) {
+	    PORT_ArenaRelease(arena, mark);
+	}
+	if (item != NULL) {
+	    item->data = NULL;
+	    item->len = 0;
+	}
+    } else {
+	if (result != NULL) {
+	    SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
+	}
+	/*
+	 * If item is not NULL, the above has set item->data and
+	 * item->len to 0.
+	 */
+    }
+    return(NULL);
+}
+
+SECStatus
+SECITEM_ReallocItem(PRArenaPool *arena, SECItem *item, unsigned int oldlen,
+		    unsigned int newlen)
+{
+    PORT_Assert(item != NULL);
+    if (item == NULL) {
+	/* XXX Set error.  But to what? */
+	return SECFailure;
+    }
+
+    /*
+     * If no old length, degenerate to just plain alloc.
+     */
+    if (oldlen == 0) {
+	PORT_Assert(item->data == NULL || item->len == 0);
+	if (newlen == 0) {
+	    /* Nothing to do.  Weird, but not a failure.  */
+	    return SECSuccess;
+	}
+	item->len = newlen;
+	if (arena != NULL) {
+	    item->data = PORT_ArenaAlloc(arena, newlen);
+	} else {
+	    item->data = PORT_Alloc(newlen);
+	}
+    } else {
+	if (arena != NULL) {
+	    item->data = PORT_ArenaGrow(arena, item->data, oldlen, newlen);
+	} else {
+	    item->data = PORT_Realloc(item->data, newlen);
+	}
+    }
+
+    if (item->data == NULL) {
+	return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+SECComparison
+SECITEM_CompareItem(const SECItem *a, const SECItem *b)
+{
+    unsigned m;
+    SECComparison rv;
+
+    if (a == b)
+    	return SECEqual;
+    if (!a || !a->len || !a->data) 
+        return (!b || !b->len || !b->data) ? SECEqual : SECLessThan;
+    if (!b || !b->len || !b->data) 
+    	return SECGreaterThan;
+
+    m = ( ( a->len < b->len ) ? a->len : b->len );
+    
+    rv = (SECComparison) PORT_Memcmp(a->data, b->data, m);
+    if (rv) {
+	return rv;
+    }
+    if (a->len < b->len) {
+	return SECLessThan;
+    }
+    if (a->len == b->len) {
+	return SECEqual;
+    }
+    return SECGreaterThan;
+}
+
+PRBool
+SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
+{
+    if (a->len != b->len)
+        return PR_FALSE;
+    if (!a->len)
+    	return PR_TRUE;
+    if (!a->data || !b->data) {
+        /* avoid null pointer crash. */
+	return (PRBool)(a->data == b->data);
+    }
+    return (PRBool)!PORT_Memcmp(a->data, b->data, a->len);
+}
+
+SECItem *
+SECITEM_DupItem(const SECItem *from)
+{
+    return SECITEM_ArenaDupItem(NULL, from);
+}
+
+SECItem *
+SECITEM_ArenaDupItem(PRArenaPool *arena, const SECItem *from)
+{
+    SECItem *to;
+    
+    if ( from == NULL ) {
+	return(NULL);
+    }
+    
+    if ( arena != NULL ) {
+	to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
+    } else {
+	to = (SECItem *)PORT_Alloc(sizeof(SECItem));
+    }
+    if ( to == NULL ) {
+	return(NULL);
+    }
+
+    if ( arena != NULL ) {
+	to->data = (unsigned char *)PORT_ArenaAlloc(arena, from->len);
+    } else {
+	to->data = (unsigned char *)PORT_Alloc(from->len);
+    }
+    if ( to->data == NULL ) {
+	PORT_Free(to);
+	return(NULL);
+    }
+
+    to->len = from->len;
+    to->type = from->type;
+    if ( to->len ) {
+	PORT_Memcpy(to->data, from->data, to->len);
+    }
+    
+    return(to);
+}
+
+SECStatus
+SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, const SECItem *from)
+{
+    to->type = from->type;
+    if (from->data && from->len) {
+	if ( arena ) {
+	    to->data = (unsigned char*) PORT_ArenaAlloc(arena, from->len);
+	} else {
+	    to->data = (unsigned char*) PORT_Alloc(from->len);
+	}
+	
+	if (!to->data) {
+	    return SECFailure;
+	}
+	PORT_Memcpy(to->data, from->data, from->len);
+	to->len = from->len;
+    } else {
+	to->data = 0;
+	to->len = 0;
+    }
+    return SECSuccess;
+}
+
+void
+SECITEM_FreeItem(SECItem *zap, PRBool freeit)
+{
+    if (zap) {
+	PORT_Free(zap->data);
+	zap->data = 0;
+	zap->len = 0;
+	if (freeit) {
+	    PORT_Free(zap);
+	}
+    }
+}
+
+void
+SECITEM_ZfreeItem(SECItem *zap, PRBool freeit)
+{
+    if (zap) {
+	PORT_ZFree(zap->data, zap->len);
+	zap->data = 0;
+	zap->len = 0;
+	if (freeit) {
+	    PORT_ZFree(zap, sizeof(SECItem));
+	}
+    }
+}
+/* these reroutines were taken from pkix oid.c, which is supposed to
+ * replace this file some day */
+/*
+ * This is the hash function.  We simply XOR the encoded form with
+ * itself in sizeof(PLHashNumber)-byte chunks.  Improving this
+ * routine is left as an excercise for the more mathematically
+ * inclined student.
+ */
+PLHashNumber PR_CALLBACK
+SECITEM_Hash ( const void *key)
+{
+    const SECItem *item = (const SECItem *)key;
+    PLHashNumber rv = 0;
+
+    PRUint8 *data = (PRUint8 *)item->data;
+    PRUint32 i;
+    PRUint8 *rvc = (PRUint8 *)&rv;
+
+    for( i = 0; i < item->len; i++ ) {
+        rvc[ i % sizeof(rv) ] ^= *data;
+        data++;
+    }
+
+    return rv;
+}
+
+/*
+ * This is the key-compare function.  It simply does a lexical
+ * comparison on the item data.  This does not result in
+ * quite the same ordering as the "sequence of numbers" order,
+ * but heck it's only used internally by the hash table anyway.
+ */
+PRIntn PR_CALLBACK
+SECITEM_HashCompare ( const void *k1, const void *k2)
+{
+    const SECItem *i1 = (const SECItem *)k1;
+    const SECItem *i2 = (const SECItem *)k2;
+
+    return SECITEM_ItemsAreEqual(i1,i2);
+}
diff --git a/mozilla/security/nss/lib/util/secitem.h b/mozilla/security/nss/lib/util/secitem.h
new file mode 100644
index 0000000..8ec11d0
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secitem.h
@@ -0,0 +1,128 @@
+/* ***** 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 ***** */
+
+#ifndef _SECITEM_H_
+#define _SECITEM_H_
+
+#include "utilrename.h"
+
+/*
+ * secitem.h - public data structures and prototypes for handling
+ *	       SECItems
+ *
+ * $Id: secitem.h,v 1.8 2008/06/14 14:20:38 wtc%google.com Exp $
+ */
+
+#include "plarena.h"
+#include "plhash.h"
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Allocate an item.  If "arena" is not NULL, then allocate from there,
+** otherwise allocate from the heap.  If "item" is not NULL, allocate
+** only the data buffer for the item, not the item itself.  If "len" is
+** 0, do not allocate the data buffer for the item; simply set the data
+** field to NULL and the len field to 0.  The item structure is allocated
+** zero-filled; the data buffer is not zeroed.  The caller is responsible
+** for initializing the type field of the item.
+**
+** The resulting item is returned; NULL if any error occurs.
+**
+** XXX This probably should take a SECItemType, but since that is mostly
+** unused and our improved APIs (aka Stan) are looming, I left it out.
+*/
+extern SECItem *SECITEM_AllocItem(PLArenaPool *arena, SECItem *item,
+				  unsigned int len);
+
+/*
+** Reallocate the data for the specified "item".  If "arena" is not NULL,
+** then reallocate from there, otherwise reallocate from the heap.
+** In the case where oldlen is 0, the data is allocated (not reallocated).
+** In any case, "item" is expected to be a valid SECItem pointer;
+** SECFailure is returned if it is not.  If the allocation succeeds,
+** SECSuccess is returned.
+*/
+extern SECStatus SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item,
+				     unsigned int oldlen, unsigned int newlen);
+
+/*
+** Compare two items returning the difference between them.
+*/
+extern SECComparison SECITEM_CompareItem(const SECItem *a, const SECItem *b);
+
+/*
+** Compare two items -- if they are the same, return true; otherwise false.
+*/
+extern PRBool SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b);
+
+/*
+** Copy "from" to "to"
+*/
+extern SECStatus SECITEM_CopyItem(PLArenaPool *arena, SECItem *to, 
+                                  const SECItem *from);
+
+/*
+** Allocate an item and copy "from" into it.
+*/
+extern SECItem *SECITEM_DupItem(const SECItem *from);
+
+/*
+** Allocate an item and copy "from" into it.  The item itself and the 
+** data it points to are both allocated from the arena.  If arena is
+** NULL, this function is equivalent to SECITEM_DupItem.
+*/
+extern SECItem *SECITEM_ArenaDupItem(PLArenaPool *arena, const SECItem *from);
+
+/*
+** Free "zap". If freeit is PR_TRUE then "zap" itself is freed.
+*/
+extern void SECITEM_FreeItem(SECItem *zap, PRBool freeit);
+
+/*
+** Zero and then free "zap". If freeit is PR_TRUE then "zap" itself is freed.
+*/
+extern void SECITEM_ZfreeItem(SECItem *zap, PRBool freeit);
+
+PLHashNumber PR_CALLBACK SECITEM_Hash ( const void *key);
+
+PRIntn PR_CALLBACK SECITEM_HashCompare ( const void *k1, const void *k2);
+
+
+SEC_END_PROTOS
+
+#endif /* _SECITEM_H_ */
diff --git a/mozilla/security/nss/lib/util/secload.c b/mozilla/security/nss/lib/util/secload.c
new file mode 100644
index 0000000..6f9b527
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secload.c
@@ -0,0 +1,217 @@
+/*
+ * ***** 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) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *   Kai Engert <kengert@redhat.com>
+ *
+ * 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 "secport.h"
+#include "nspr.h"
+
+#ifdef XP_UNIX
+#include <unistd.h>
+#define BL_MAXSYMLINKS 20
+
+/*
+ * If 'link' is a symbolic link, this function follows the symbolic links
+ * and returns the pathname of the ultimate source of the symbolic links.
+ * If 'link' is not a symbolic link, this function returns NULL.
+ * The caller should call PR_Free to free the string returned by this
+ * function.
+ */
+static char* loader_GetOriginalPathname(const char* link)
+{
+    char* resolved = NULL;
+    char* input = NULL;
+    PRUint32 iterations = 0;
+    PRInt32 len = 0, retlen = 0;
+    if (!link) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return NULL;
+    }
+    len = PR_MAX(1024, strlen(link) + 1);
+    resolved = PR_Malloc(len);
+    input = PR_Malloc(len);
+    if (!resolved || !input) {
+        if (resolved) {
+            PR_Free(resolved);
+        }
+        if (input) {
+            PR_Free(input);
+        }
+        return NULL;
+    }
+    strcpy(input, link);
+    while ( (iterations++ < BL_MAXSYMLINKS) &&
+            ( (retlen = readlink(input, resolved, len - 1)) > 0) ) {
+        char* tmp = input;
+        resolved[retlen] = '\0'; /* NULL termination */
+        input = resolved;
+        resolved = tmp;
+    }
+    PR_Free(resolved);
+    if (iterations == 1 && retlen < 0) {
+        PR_Free(input);
+        input = NULL;
+    }
+    return input;
+}
+#endif /* XP_UNIX */
+
+/*
+ * Load the library with the file name 'name' residing in the same
+ * directory as the reference library, whose pathname is 'referencePath'.
+ */
+static PRLibrary *
+loader_LoadLibInReferenceDir(const char *referencePath, const char *name)
+{
+    PRLibrary *dlh = NULL;
+    char *fullName = NULL;
+    char* c;
+    PRLibSpec libSpec;
+
+    /* Remove the trailing filename from referencePath and add the new one */
+    c = strrchr(referencePath, PR_GetDirectorySeparator());
+    if (c) {
+        size_t referencePathSize = 1 + c - referencePath;
+        fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1);
+        if (fullName) {
+            memcpy(fullName, referencePath, referencePathSize);
+            strcpy(fullName + referencePathSize, name); 
+#ifdef DEBUG_LOADER
+            PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", 
+                       fullName);
+#endif
+            libSpec.type = PR_LibSpec_Pathname;
+            libSpec.value.pathname = fullName;
+            dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL
+#ifdef PR_LD_ALT_SEARCH_PATH
+            /* allow library's dependencies to be found in the same directory
+             * on Windows even if PATH is not set. Requires NSPR 4.8.1 . */
+                                          | PR_LD_ALT_SEARCH_PATH 
+#endif
+                                          );
+            PORT_Free(fullName);
+        }
+    }
+    return dlh;
+}
+
+/*
+ * Load a shared library called "newShLibName" in the same directory as
+ * a shared library that is already loaded, called existingShLibName.
+ * A pointer to a static function in that shared library,
+ * staticShLibFunc, is required.
+ *
+ * existingShLibName:
+ *   The file name of the shared library that shall be used as the 
+ *   "reference library". The loader will attempt to load the requested
+ *   library from the same directory as the reference library.
+ *
+ * staticShLibFunc:
+ *   Pointer to a static function in the "reference library".
+ *
+ * newShLibName:
+ *   The simple file name of the new shared library to be loaded.
+ *
+ * We use PR_GetLibraryFilePathname to get the pathname of the loaded 
+ * shared lib that contains this function, and then do a
+ * PR_LoadLibraryWithFlags with an absolute pathname for the shared
+ * library to be loaded.
+ *
+ * On Windows, the "alternate search path" strategy is employed, if available.
+ * On Unix, if existingShLibName is a symbolic link, and no link exists for the
+ * new library, the original link will be resolved, and the new library loaded
+ * from the resolved location.
+ *
+ * If the new shared library is not found in the same location as the reference
+ * library, it will then be loaded from the normal system library path.
+ *
+ */
+
+PRLibrary *
+PORT_LoadLibraryFromOrigin(const char* existingShLibName,
+                 PRFuncPtr staticShLibFunc,
+                 const char *newShLibName)
+{
+    PRLibrary *lib = NULL;
+    char* fullPath = NULL;
+    PRLibSpec libSpec;
+
+    /* Get the pathname for existingShLibName, e.g. /usr/lib/libnss3.so
+     * PR_GetLibraryFilePathname works with either the base library name or a
+     * function pointer, depending on the platform.
+     * We require the address of a function in the "reference library",
+     * provided by the caller. To avoid getting the address of the stub/thunk
+     * of an exported function by accident, use the address of a static
+     * function rather than an exported function.
+     */
+    fullPath = PR_GetLibraryFilePathname(existingShLibName,
+                                         staticShLibFunc);
+
+    if (fullPath) {
+        lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
+#ifdef XP_UNIX
+        if (!lib) {
+            /*
+             * If fullPath is a symbolic link, resolve the symbolic
+             * link and try again.
+             */
+            char* originalfullPath = loader_GetOriginalPathname(fullPath);
+            if (originalfullPath) {
+                PR_Free(fullPath);
+                fullPath = originalfullPath;
+                lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
+            }
+        }
+#endif
+        PR_Free(fullPath);
+    }
+    if (!lib) {
+#ifdef DEBUG_LOADER
+        PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", newShLibName);
+#endif
+        libSpec.type = PR_LibSpec_Pathname;
+        libSpec.value.pathname = newShLibName;
+        lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
+    }
+    if (NULL == lib) {
+#ifdef DEBUG_LOADER
+        PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", newShLibName);
+#endif
+    }
+    return lib;
+}
+
diff --git a/mozilla/security/nss/lib/util/secoid.c b/mozilla/security/nss/lib/util/secoid.c
new file mode 100644
index 0000000..7e8c1b6
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secoid.c
@@ -0,0 +1,2129 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 "secoid.h"
+#include "pkcs11t.h"
+#include "secitem.h"
+#include "secerr.h"
+#include "prenv.h"
+#include "plhash.h"
+#include "nssrwlk.h"
+
+/* MISSI Mosaic Object ID space */
+#define USGOV                   0x60, 0x86, 0x48, 0x01, 0x65
+#define MISSI	                USGOV, 0x02, 0x01, 0x01
+#define MISSI_OLD_KEA_DSS	MISSI, 0x0c
+#define MISSI_OLD_DSS		MISSI, 0x02
+#define MISSI_KEA_DSS		MISSI, 0x14
+#define MISSI_DSS		MISSI, 0x13
+#define MISSI_KEA               MISSI, 0x0a
+#define MISSI_ALT_KEA           MISSI, 0x16
+
+#define NISTALGS    USGOV, 3, 4
+#define AES         NISTALGS, 1
+#define SHAXXX      NISTALGS, 2
+
+/**
+ ** The Netscape OID space is allocated by Terry Hayes.  If you need
+ ** a piece of the space, contact him at thayes@netscape.com.
+ **/
+
+/* Netscape Communications Corporation Object ID space */
+/* { 2 16 840 1 113730 } */
+#define NETSCAPE_OID	          0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42
+#define NETSCAPE_CERT_EXT 	  NETSCAPE_OID, 0x01
+#define NETSCAPE_DATA_TYPE 	  NETSCAPE_OID, 0x02
+/* netscape directory oid - owned by Mark Smith (mcs@netscape.com) */
+#define NETSCAPE_DIRECTORY 	  NETSCAPE_OID, 0x03
+#define NETSCAPE_POLICY 	  NETSCAPE_OID, 0x04
+#define NETSCAPE_CERT_SERVER 	  NETSCAPE_OID, 0x05
+#define NETSCAPE_ALGS 		  NETSCAPE_OID, 0x06 /* algorithm OIDs */
+#define NETSCAPE_NAME_COMPONENTS  NETSCAPE_OID, 0x07
+
+#define NETSCAPE_CERT_EXT_AIA     NETSCAPE_CERT_EXT, 0x10
+#define NETSCAPE_CERT_SERVER_CRMF NETSCAPE_CERT_SERVER, 0x01
+
+/* these are old and should go away soon */
+#define OLD_NETSCAPE		0x60, 0x86, 0x48, 0xd8, 0x6a
+#define NS_CERT_EXT		OLD_NETSCAPE, 0x01
+#define NS_FILE_TYPE		OLD_NETSCAPE, 0x02
+#define NS_IMAGE_TYPE		OLD_NETSCAPE, 0x03
+
+/* RSA OID name space */
+#define RSADSI			0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d
+#define PKCS			RSADSI, 0x01
+#define DIGEST			RSADSI, 0x02
+#define CIPHER			RSADSI, 0x03
+#define PKCS1			PKCS, 0x01
+#define PKCS5			PKCS, 0x05
+#define PKCS7			PKCS, 0x07
+#define PKCS9			PKCS, 0x09
+#define PKCS12			PKCS, 0x0c
+
+/* Fortezza algorithm OID space: { 2 16 840 1 101 2 1 1 } */
+/* ### mwelch -- Is this just for algorithms, or all of Fortezza? */
+#define FORTEZZA_ALG 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x01
+
+/* Other OID name spaces */
+#define ALGORITHM		0x2b, 0x0e, 0x03, 0x02
+#define X500			0x55
+#define X520_ATTRIBUTE_TYPE	X500, 0x04
+#define X500_ALG		X500, 0x08
+#define X500_ALG_ENCRYPTION	X500_ALG, 0x01
+
+/** X.509 v3 Extension OID 
+ ** {joint-iso-ccitt (2) ds(5) 29}
+ **/
+#define	ID_CE_OID 		X500, 0x1d
+
+#define RFC1274_ATTR_TYPE  0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x1
+/* #define RFC2247_ATTR_TYPE  0x09, 0x92, 0x26, 0xf5, 0x98, 0x1e, 0x64, 0x1 this is WRONG! */
+
+/* PKCS #12 name spaces */
+#define PKCS12_MODE_IDS		PKCS12, 0x01
+#define PKCS12_ESPVK_IDS	PKCS12, 0x02
+#define PKCS12_BAG_IDS		PKCS12, 0x03
+#define PKCS12_CERT_BAG_IDS	PKCS12, 0x04
+#define PKCS12_OIDS		PKCS12, 0x05
+#define PKCS12_PBE_IDS		PKCS12_OIDS, 0x01
+#define PKCS12_ENVELOPING_IDS	PKCS12_OIDS, 0x02
+#define PKCS12_SIGNATURE_IDS	PKCS12_OIDS, 0x03
+#define PKCS12_V2_PBE_IDS	PKCS12, 0x01
+#define PKCS9_CERT_TYPES	PKCS9, 0x16
+#define PKCS9_CRL_TYPES		PKCS9, 0x17
+#define PKCS9_SMIME_IDS		PKCS9, 0x10
+#define PKCS9_SMIME_ATTRS	PKCS9_SMIME_IDS, 2
+#define PKCS9_SMIME_ALGS	PKCS9_SMIME_IDS, 3
+#define PKCS12_VERSION1		PKCS12, 0x0a
+#define PKCS12_V1_BAG_IDS	PKCS12_VERSION1, 1
+
+/* for DSA algorithm */
+/* { iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) } */
+#define ANSI_X9_ALGORITHM  0x2a, 0x86, 0x48, 0xce, 0x38, 0x4
+
+/* for DH algorithm */
+/* { iso(1) member-body(2) us(840) x9-57(10046) number-type(2) } */
+/* need real OID person to look at this, copied the above line
+ * and added 6 to second to last value (and changed '4' to '2' */
+#define ANSI_X942_ALGORITHM  0x2a, 0x86, 0x48, 0xce, 0x3e, 0x2
+
+#define VERISIGN 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45
+
+#define PKIX 			0x2b, 0x06, 0x01, 0x05, 0x05, 0x07
+#define PKIX_CERT_EXTENSIONS    PKIX, 1
+#define PKIX_POLICY_QUALIFIERS  PKIX, 2
+#define PKIX_KEY_USAGE 		PKIX, 3
+#define PKIX_ACCESS_DESCRIPTION PKIX, 0x30
+#define PKIX_OCSP 		PKIX_ACCESS_DESCRIPTION, 1
+#define PKIX_CA_ISSUERS		PKIX_ACCESS_DESCRIPTION, 2
+
+#define PKIX_ID_PKIP     	PKIX, 5
+#define PKIX_ID_REGCTRL  	PKIX_ID_PKIP, 1 
+#define PKIX_ID_REGINFO  	PKIX_ID_PKIP, 2
+
+/* Microsoft Object ID space */
+/* { 1.3.6.1.4.1.311 } */
+#define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37
+
+#define CERTICOM_OID            0x2b, 0x81, 0x04
+#define SECG_OID                CERTICOM_OID, 0x00
+
+#define ANSI_X962_OID           0x2a, 0x86, 0x48, 0xce, 0x3d
+#define ANSI_X962_CURVE_OID     ANSI_X962_OID, 0x03
+#define ANSI_X962_GF2m_OID      ANSI_X962_CURVE_OID, 0x00
+#define ANSI_X962_GFp_OID       ANSI_X962_CURVE_OID, 0x01
+#define ANSI_X962_SIGNATURE_OID ANSI_X962_OID, 0x04
+#define ANSI_X962_SPECIFY_OID   ANSI_X962_SIGNATURE_OID, 0x03
+
+/* for Camellia: iso(1) member-body(2) jisc(392)
+ *    mitsubishi(200011) isl(61) security(1) algorithm(1)
+ */
+#define MITSUBISHI_ALG 0x2a,0x83,0x08,0x8c,0x9a,0x4b,0x3d,0x01,0x01
+#define CAMELLIA_ENCRYPT_OID MITSUBISHI_ALG,1
+#define CAMELLIA_WRAP_OID    MITSUBISHI_ALG,3
+
+/* for SEED : iso(1) member-body(2) korea(410)
+ *    kisa(200004) algorithm(1)
+ */
+#define SEED_OID		 0x2a,0x83,0x1a,0x8c,0x9a,0x44,0x01
+
+#define CONST_OID static const unsigned char
+
+CONST_OID md2[]        				= { DIGEST, 0x02 };
+CONST_OID md4[]        				= { DIGEST, 0x04 };
+CONST_OID md5[]        				= { DIGEST, 0x05 };
+CONST_OID hmac_sha1[]   			= { DIGEST, 7 };
+CONST_OID hmac_sha224[]				= { DIGEST, 8 };
+CONST_OID hmac_sha256[]				= { DIGEST, 9 };
+CONST_OID hmac_sha384[]				= { DIGEST, 10 };
+CONST_OID hmac_sha512[]				= { DIGEST, 11 };
+
+CONST_OID rc2cbc[]     				= { CIPHER, 0x02 };
+CONST_OID rc4[]        				= { CIPHER, 0x04 };
+CONST_OID desede3cbc[] 				= { CIPHER, 0x07 };
+CONST_OID rc5cbcpad[]  				= { CIPHER, 0x09 };
+
+CONST_OID desecb[]                           = { ALGORITHM, 0x06 };
+CONST_OID descbc[]                           = { ALGORITHM, 0x07 };
+CONST_OID desofb[]                           = { ALGORITHM, 0x08 };
+CONST_OID descfb[]                           = { ALGORITHM, 0x09 };
+CONST_OID desmac[]                           = { ALGORITHM, 0x0a };
+CONST_OID sdn702DSASignature[]               = { ALGORITHM, 0x0c };
+CONST_OID isoSHAWithRSASignature[]           = { ALGORITHM, 0x0f };
+CONST_OID desede[]                           = { ALGORITHM, 0x11 };
+CONST_OID sha1[]                             = { ALGORITHM, 0x1a };
+CONST_OID bogusDSASignaturewithSHA1Digest[]  = { ALGORITHM, 0x1b };
+CONST_OID isoSHA1WithRSASignature[]          = { ALGORITHM, 0x1d };
+
+CONST_OID pkcs1RSAEncryption[]         		= { PKCS1, 0x01 };
+CONST_OID pkcs1MD2WithRSAEncryption[]  		= { PKCS1, 0x02 };
+CONST_OID pkcs1MD4WithRSAEncryption[]  		= { PKCS1, 0x03 };
+CONST_OID pkcs1MD5WithRSAEncryption[]  		= { PKCS1, 0x04 };
+CONST_OID pkcs1SHA1WithRSAEncryption[] 		= { PKCS1, 0x05 };
+CONST_OID pkcs1SHA256WithRSAEncryption[] 	= { PKCS1, 11 };
+CONST_OID pkcs1SHA384WithRSAEncryption[] 	= { PKCS1, 12 };
+CONST_OID pkcs1SHA512WithRSAEncryption[] 	= { PKCS1, 13 };
+
+CONST_OID pkcs5PbeWithMD2AndDEScbc[]  		= { PKCS5, 0x01 };
+CONST_OID pkcs5PbeWithMD5AndDEScbc[]  		= { PKCS5, 0x03 };
+CONST_OID pkcs5PbeWithSha1AndDEScbc[] 		= { PKCS5, 0x0a };
+CONST_OID pkcs5Pbkdf2[]  			= { PKCS5, 12 };
+CONST_OID pkcs5Pbes2[]  			= { PKCS5, 13 };
+CONST_OID pkcs5Pbmac1[]				= { PKCS5, 14 };
+
+CONST_OID pkcs7[]                     		= { PKCS7 };
+CONST_OID pkcs7Data[]                 		= { PKCS7, 0x01 };
+CONST_OID pkcs7SignedData[]           		= { PKCS7, 0x02 };
+CONST_OID pkcs7EnvelopedData[]        		= { PKCS7, 0x03 };
+CONST_OID pkcs7SignedEnvelopedData[]  		= { PKCS7, 0x04 };
+CONST_OID pkcs7DigestedData[]         		= { PKCS7, 0x05 };
+CONST_OID pkcs7EncryptedData[]        		= { PKCS7, 0x06 };
+
+CONST_OID pkcs9EmailAddress[]                  = { PKCS9, 0x01 };
+CONST_OID pkcs9UnstructuredName[]              = { PKCS9, 0x02 };
+CONST_OID pkcs9ContentType[]                   = { PKCS9, 0x03 };
+CONST_OID pkcs9MessageDigest[]                 = { PKCS9, 0x04 };
+CONST_OID pkcs9SigningTime[]                   = { PKCS9, 0x05 };
+CONST_OID pkcs9CounterSignature[]              = { PKCS9, 0x06 };
+CONST_OID pkcs9ChallengePassword[]             = { PKCS9, 0x07 };
+CONST_OID pkcs9UnstructuredAddress[]           = { PKCS9, 0x08 };
+CONST_OID pkcs9ExtendedCertificateAttributes[] = { PKCS9, 0x09 };
+CONST_OID pkcs9ExtensionRequest[]              = { PKCS9, 14 };
+CONST_OID pkcs9SMIMECapabilities[]             = { PKCS9, 15 };
+CONST_OID pkcs9FriendlyName[]                  = { PKCS9, 20 };
+CONST_OID pkcs9LocalKeyID[]                    = { PKCS9, 21 };
+
+CONST_OID pkcs9X509Certificate[]        	= { PKCS9_CERT_TYPES, 1 };
+CONST_OID pkcs9SDSICertificate[]        	= { PKCS9_CERT_TYPES, 2 };
+CONST_OID pkcs9X509CRL[]                	= { PKCS9_CRL_TYPES, 1 };
+
+/* RFC2630 (CMS) OIDs */
+CONST_OID cmsESDH[]     			= { PKCS9_SMIME_ALGS, 5 };
+CONST_OID cms3DESwrap[] 			= { PKCS9_SMIME_ALGS, 6 };
+CONST_OID cmsRC2wrap[]  			= { PKCS9_SMIME_ALGS, 7 };
+
+/* RFC2633 SMIME message attributes */
+CONST_OID smimeEncryptionKeyPreference[] 	= { PKCS9_SMIME_ATTRS, 11 };
+CONST_OID ms_smimeEncryptionKeyPreference[] 	= { MICROSOFT_OID, 0x10, 0x4 };
+
+CONST_OID x520CommonName[]                      = { X520_ATTRIBUTE_TYPE, 3 };
+CONST_OID x520SurName[]                         = { X520_ATTRIBUTE_TYPE, 4 };
+CONST_OID x520SerialNumber[]                    = { X520_ATTRIBUTE_TYPE, 5 };
+CONST_OID x520CountryName[]                     = { X520_ATTRIBUTE_TYPE, 6 };
+CONST_OID x520LocalityName[]                    = { X520_ATTRIBUTE_TYPE, 7 };
+CONST_OID x520StateOrProvinceName[]             = { X520_ATTRIBUTE_TYPE, 8 };
+CONST_OID x520StreetAddress[]                   = { X520_ATTRIBUTE_TYPE, 9 };
+CONST_OID x520OrgName[]                         = { X520_ATTRIBUTE_TYPE, 10 };
+CONST_OID x520OrgUnitName[]                     = { X520_ATTRIBUTE_TYPE, 11 };
+CONST_OID x520Title[]                           = { X520_ATTRIBUTE_TYPE, 12 };
+CONST_OID x520PostalAddress[]                   = { X520_ATTRIBUTE_TYPE, 16 };
+CONST_OID x520PostalCode[]                      = { X520_ATTRIBUTE_TYPE, 17 };
+CONST_OID x520PostOfficeBox[]                   = { X520_ATTRIBUTE_TYPE, 18 };
+CONST_OID x520GivenName[]                       = { X520_ATTRIBUTE_TYPE, 42 };
+CONST_OID x520Initials[]                        = { X520_ATTRIBUTE_TYPE, 43 };
+CONST_OID x520GenerationQualifier[]             = { X520_ATTRIBUTE_TYPE, 44 };
+CONST_OID x520DnQualifier[]                     = { X520_ATTRIBUTE_TYPE, 46 };
+CONST_OID x520HouseIdentifier[]                 = { X520_ATTRIBUTE_TYPE, 51 };
+CONST_OID x520Pseudonym[]                       = { X520_ATTRIBUTE_TYPE, 65 };
+
+CONST_OID nsTypeGIF[]          			= { NETSCAPE_DATA_TYPE, 0x01 };
+CONST_OID nsTypeJPEG[]         			= { NETSCAPE_DATA_TYPE, 0x02 };
+CONST_OID nsTypeURL[]          			= { NETSCAPE_DATA_TYPE, 0x03 };
+CONST_OID nsTypeHTML[]         			= { NETSCAPE_DATA_TYPE, 0x04 };
+CONST_OID nsTypeCertSeq[]      			= { NETSCAPE_DATA_TYPE, 0x05 };
+
+CONST_OID missiCertKEADSSOld[] 			= { MISSI_OLD_KEA_DSS };
+CONST_OID missiCertDSSOld[]    			= { MISSI_OLD_DSS };
+CONST_OID missiCertKEADSS[]    			= { MISSI_KEA_DSS };
+CONST_OID missiCertDSS[]       			= { MISSI_DSS };
+CONST_OID missiCertKEA[]       			= { MISSI_KEA };
+CONST_OID missiCertAltKEA[]    			= { MISSI_ALT_KEA };
+CONST_OID x500RSAEncryption[]  			= { X500_ALG_ENCRYPTION, 0x01 };
+
+/* added for alg 1485 */
+CONST_OID rfc1274Uid[]             		= { RFC1274_ATTR_TYPE, 1 };
+CONST_OID rfc1274Mail[]            		= { RFC1274_ATTR_TYPE, 3 };
+CONST_OID rfc2247DomainComponent[] 		= { RFC1274_ATTR_TYPE, 25 };
+
+/* Netscape private certificate extensions */
+CONST_OID nsCertExtNetscapeOK[]  		= { NS_CERT_EXT, 1 };
+CONST_OID nsCertExtIssuerLogo[]  		= { NS_CERT_EXT, 2 };
+CONST_OID nsCertExtSubjectLogo[] 		= { NS_CERT_EXT, 3 };
+CONST_OID nsExtCertType[]        		= { NETSCAPE_CERT_EXT, 0x01 };
+CONST_OID nsExtBaseURL[]         		= { NETSCAPE_CERT_EXT, 0x02 };
+CONST_OID nsExtRevocationURL[]   		= { NETSCAPE_CERT_EXT, 0x03 };
+CONST_OID nsExtCARevocationURL[] 		= { NETSCAPE_CERT_EXT, 0x04 };
+CONST_OID nsExtCACRLURL[]        		= { NETSCAPE_CERT_EXT, 0x05 };
+CONST_OID nsExtCACertURL[]       		= { NETSCAPE_CERT_EXT, 0x06 };
+CONST_OID nsExtCertRenewalURL[]  		= { NETSCAPE_CERT_EXT, 0x07 };
+CONST_OID nsExtCAPolicyURL[]     		= { NETSCAPE_CERT_EXT, 0x08 };
+CONST_OID nsExtHomepageURL[]     		= { NETSCAPE_CERT_EXT, 0x09 };
+CONST_OID nsExtEntityLogo[]      		= { NETSCAPE_CERT_EXT, 0x0a };
+CONST_OID nsExtUserPicture[]     		= { NETSCAPE_CERT_EXT, 0x0b };
+CONST_OID nsExtSSLServerName[]   		= { NETSCAPE_CERT_EXT, 0x0c };
+CONST_OID nsExtComment[]         		= { NETSCAPE_CERT_EXT, 0x0d };
+
+/* the following 2 extensions are defined for and used by Cartman(NSM) */
+CONST_OID nsExtLostPasswordURL[] 		= { NETSCAPE_CERT_EXT, 0x0e };
+CONST_OID nsExtCertRenewalTime[] 		= { NETSCAPE_CERT_EXT, 0x0f };
+
+CONST_OID nsExtAIACertRenewal[]    	= { NETSCAPE_CERT_EXT_AIA, 0x01 };
+CONST_OID nsExtCertScopeOfUse[]    	= { NETSCAPE_CERT_EXT, 0x11 };
+/* Reserved Netscape (2 16 840 1 113730 1 18) = { NETSCAPE_CERT_EXT, 0x12 }; */
+
+/* Netscape policy values */
+CONST_OID nsKeyUsageGovtApproved[] 	= { NETSCAPE_POLICY, 0x01 };
+
+/* Netscape other name types */
+CONST_OID netscapeNickname[] 		= { NETSCAPE_NAME_COMPONENTS, 0x01 };
+CONST_OID netscapeAOLScreenname[] 	= { NETSCAPE_NAME_COMPONENTS, 0x02 };
+
+/* OIDs needed for cert server */
+CONST_OID netscapeRecoveryRequest[] 	= { NETSCAPE_CERT_SERVER_CRMF, 0x01 };
+
+
+/* Standard x.509 v3 Certificate & CRL Extensions */
+CONST_OID x509SubjectDirectoryAttr[]  		= { ID_CE_OID,  9 };
+CONST_OID x509SubjectKeyID[]          		= { ID_CE_OID, 14 };
+CONST_OID x509KeyUsage[]              		= { ID_CE_OID, 15 };
+CONST_OID x509PrivateKeyUsagePeriod[] 		= { ID_CE_OID, 16 };
+CONST_OID x509SubjectAltName[]        		= { ID_CE_OID, 17 };
+CONST_OID x509IssuerAltName[]         		= { ID_CE_OID, 18 };
+CONST_OID x509BasicConstraints[]      		= { ID_CE_OID, 19 };
+CONST_OID x509CRLNumber[]                    	= { ID_CE_OID, 20 };
+CONST_OID x509ReasonCode[]                   	= { ID_CE_OID, 21 };
+CONST_OID x509HoldInstructionCode[]             = { ID_CE_OID, 23 };
+CONST_OID x509InvalidDate[]                     = { ID_CE_OID, 24 };
+CONST_OID x509DeltaCRLIndicator[]               = { ID_CE_OID, 27 };
+CONST_OID x509IssuingDistributionPoint[]        = { ID_CE_OID, 28 };
+CONST_OID x509CertIssuer[]                      = { ID_CE_OID, 29 };
+CONST_OID x509NameConstraints[]       		= { ID_CE_OID, 30 };
+CONST_OID x509CRLDistPoints[]         		= { ID_CE_OID, 31 };
+CONST_OID x509CertificatePolicies[]   		= { ID_CE_OID, 32 };
+CONST_OID x509PolicyMappings[]        		= { ID_CE_OID, 33 };
+CONST_OID x509AuthKeyID[]             		= { ID_CE_OID, 35 };
+CONST_OID x509PolicyConstraints[]     		= { ID_CE_OID, 36 };
+CONST_OID x509ExtKeyUsage[]           		= { ID_CE_OID, 37 };
+CONST_OID x509FreshestCRL[]           		= { ID_CE_OID, 46 };
+CONST_OID x509InhibitAnyPolicy[]           	= { ID_CE_OID, 54 };
+
+CONST_OID x509CertificatePoliciesAnyPolicy[]    = { ID_CE_OID, 32, 0 };
+
+CONST_OID x509AuthInfoAccess[]        		= { PKIX_CERT_EXTENSIONS,  1 };
+CONST_OID x509SubjectInfoAccess[]               = { PKIX_CERT_EXTENSIONS, 11 };
+
+CONST_OID x509SIATimeStamping[]                 = {PKIX_ACCESS_DESCRIPTION, 0x03};
+CONST_OID x509SIACaRepository[]                 = {PKIX_ACCESS_DESCRIPTION, 0x05};
+
+/* pkcs 12 additions */
+CONST_OID pkcs12[]                           = { PKCS12 };
+CONST_OID pkcs12ModeIDs[]                    = { PKCS12_MODE_IDS };
+CONST_OID pkcs12ESPVKIDs[]                   = { PKCS12_ESPVK_IDS };
+CONST_OID pkcs12BagIDs[]                     = { PKCS12_BAG_IDS };
+CONST_OID pkcs12CertBagIDs[]                 = { PKCS12_CERT_BAG_IDS };
+CONST_OID pkcs12OIDs[]                       = { PKCS12_OIDS };
+CONST_OID pkcs12PBEIDs[]                     = { PKCS12_PBE_IDS };
+CONST_OID pkcs12EnvelopingIDs[]              = { PKCS12_ENVELOPING_IDS };
+CONST_OID pkcs12SignatureIDs[]               = { PKCS12_SIGNATURE_IDS };
+CONST_OID pkcs12PKCS8KeyShrouding[]          = { PKCS12_ESPVK_IDS, 0x01 };
+CONST_OID pkcs12KeyBagID[]                   = { PKCS12_BAG_IDS, 0x01 };
+CONST_OID pkcs12CertAndCRLBagID[]            = { PKCS12_BAG_IDS, 0x02 };
+CONST_OID pkcs12SecretBagID[]                = { PKCS12_BAG_IDS, 0x03 };
+CONST_OID pkcs12X509CertCRLBag[]             = { PKCS12_CERT_BAG_IDS, 0x01 };
+CONST_OID pkcs12SDSICertBag[]                = { PKCS12_CERT_BAG_IDS, 0x02 };
+CONST_OID pkcs12PBEWithSha1And128BitRC4[]    = { PKCS12_PBE_IDS, 0x01 };
+CONST_OID pkcs12PBEWithSha1And40BitRC4[]     = { PKCS12_PBE_IDS, 0x02 };
+CONST_OID pkcs12PBEWithSha1AndTripleDESCBC[] = { PKCS12_PBE_IDS, 0x03 };
+CONST_OID pkcs12PBEWithSha1And128BitRC2CBC[] = { PKCS12_PBE_IDS, 0x04 };
+CONST_OID pkcs12PBEWithSha1And40BitRC2CBC[]  = { PKCS12_PBE_IDS, 0x05 };
+CONST_OID pkcs12RSAEncryptionWith128BitRC4[] = { PKCS12_ENVELOPING_IDS, 0x01 };
+CONST_OID pkcs12RSAEncryptionWith40BitRC4[]  = { PKCS12_ENVELOPING_IDS, 0x02 };
+CONST_OID pkcs12RSAEncryptionWithTripleDES[] = { PKCS12_ENVELOPING_IDS, 0x03 }; 
+CONST_OID pkcs12RSASignatureWithSHA1Digest[] = { PKCS12_SIGNATURE_IDS, 0x01 };
+
+/* pkcs 12 version 1.0 ids */
+CONST_OID pkcs12V2PBEWithSha1And128BitRC4[]       = { PKCS12_V2_PBE_IDS, 0x01 };
+CONST_OID pkcs12V2PBEWithSha1And40BitRC4[]        = { PKCS12_V2_PBE_IDS, 0x02 };
+CONST_OID pkcs12V2PBEWithSha1And3KeyTripleDEScbc[]= { PKCS12_V2_PBE_IDS, 0x03 };
+CONST_OID pkcs12V2PBEWithSha1And2KeyTripleDEScbc[]= { PKCS12_V2_PBE_IDS, 0x04 };
+CONST_OID pkcs12V2PBEWithSha1And128BitRC2cbc[]    = { PKCS12_V2_PBE_IDS, 0x05 };
+CONST_OID pkcs12V2PBEWithSha1And40BitRC2cbc[]     = { PKCS12_V2_PBE_IDS, 0x06 };
+
+CONST_OID pkcs12SafeContentsID[]                  = { PKCS12_BAG_IDS, 0x04 };
+CONST_OID pkcs12PKCS8ShroudedKeyBagID[]           = { PKCS12_BAG_IDS, 0x05 };
+
+CONST_OID pkcs12V1KeyBag[]              	= { PKCS12_V1_BAG_IDS, 0x01 };
+CONST_OID pkcs12V1PKCS8ShroudedKeyBag[] 	= { PKCS12_V1_BAG_IDS, 0x02 };
+CONST_OID pkcs12V1CertBag[]             	= { PKCS12_V1_BAG_IDS, 0x03 };
+CONST_OID pkcs12V1CRLBag[]              	= { PKCS12_V1_BAG_IDS, 0x04 };
+CONST_OID pkcs12V1SecretBag[]           	= { PKCS12_V1_BAG_IDS, 0x05 };
+CONST_OID pkcs12V1SafeContentsBag[]     	= { PKCS12_V1_BAG_IDS, 0x06 };
+
+/* The following encoding is INCORRECT, but correcting it would create a
+ * duplicate OID in the table.  So, we will leave it alone.
+ */
+CONST_OID pkcs12KeyUsageAttr[]          	= { 2, 5, 29, 15 };
+
+CONST_OID ansix9DSASignature[]               	= { ANSI_X9_ALGORITHM, 0x01 };
+CONST_OID ansix9DSASignaturewithSHA1Digest[] 	= { ANSI_X9_ALGORITHM, 0x03 };
+
+/* verisign OIDs */
+CONST_OID verisignUserNotices[]     		= { VERISIGN, 1, 7, 1, 1 };
+
+/* pkix OIDs */
+CONST_OID pkixCPSPointerQualifier[] 		= { PKIX_POLICY_QUALIFIERS, 1 };
+CONST_OID pkixUserNoticeQualifier[] 		= { PKIX_POLICY_QUALIFIERS, 2 };
+
+CONST_OID pkixOCSP[]				= { PKIX_OCSP };
+CONST_OID pkixOCSPBasicResponse[]		= { PKIX_OCSP, 1 };
+CONST_OID pkixOCSPNonce[]			= { PKIX_OCSP, 2 };
+CONST_OID pkixOCSPCRL[] 			= { PKIX_OCSP, 3 };
+CONST_OID pkixOCSPResponse[]			= { PKIX_OCSP, 4 };
+CONST_OID pkixOCSPNoCheck[]			= { PKIX_OCSP, 5 };
+CONST_OID pkixOCSPArchiveCutoff[]		= { PKIX_OCSP, 6 };
+CONST_OID pkixOCSPServiceLocator[]		= { PKIX_OCSP, 7 };
+
+CONST_OID pkixCAIssuers[]			= { PKIX_CA_ISSUERS };
+
+CONST_OID pkixRegCtrlRegToken[]       		= { PKIX_ID_REGCTRL, 1};
+CONST_OID pkixRegCtrlAuthenticator[]  		= { PKIX_ID_REGCTRL, 2};
+CONST_OID pkixRegCtrlPKIPubInfo[]     		= { PKIX_ID_REGCTRL, 3};
+CONST_OID pkixRegCtrlPKIArchOptions[] 		= { PKIX_ID_REGCTRL, 4};
+CONST_OID pkixRegCtrlOldCertID[]      		= { PKIX_ID_REGCTRL, 5};
+CONST_OID pkixRegCtrlProtEncKey[]     		= { PKIX_ID_REGCTRL, 6};
+CONST_OID pkixRegInfoUTF8Pairs[]      		= { PKIX_ID_REGINFO, 1};
+CONST_OID pkixRegInfoCertReq[]        		= { PKIX_ID_REGINFO, 2};
+
+CONST_OID pkixExtendedKeyUsageServerAuth[]    	= { PKIX_KEY_USAGE, 1 };
+CONST_OID pkixExtendedKeyUsageClientAuth[]    	= { PKIX_KEY_USAGE, 2 };
+CONST_OID pkixExtendedKeyUsageCodeSign[]      	= { PKIX_KEY_USAGE, 3 };
+CONST_OID pkixExtendedKeyUsageEMailProtect[]  	= { PKIX_KEY_USAGE, 4 };
+CONST_OID pkixExtendedKeyUsageTimeStamp[]     	= { PKIX_KEY_USAGE, 8 };
+CONST_OID pkixOCSPResponderExtendedKeyUsage[] 	= { PKIX_KEY_USAGE, 9 };
+
+/* OIDs for Netscape defined algorithms */
+CONST_OID netscapeSMimeKEA[] 			= { NETSCAPE_ALGS, 0x01 };
+
+/* Fortezza algorithm OIDs */
+CONST_OID skipjackCBC[] 			= { FORTEZZA_ALG, 0x04 };
+CONST_OID dhPublicKey[] 			= { ANSI_X942_ALGORITHM, 0x1 };
+
+CONST_OID aes128_ECB[] 				= { AES, 1 };
+CONST_OID aes128_CBC[] 				= { AES, 2 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes128_OFB[] 				= { AES, 3 };
+CONST_OID aes128_CFB[] 				= { AES, 4 };
+#endif
+CONST_OID aes128_KEY_WRAP[]			= { AES, 5 };
+
+CONST_OID aes192_ECB[] 				= { AES, 21 };
+CONST_OID aes192_CBC[] 				= { AES, 22 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes192_OFB[] 				= { AES, 23 };
+CONST_OID aes192_CFB[] 				= { AES, 24 };
+#endif
+CONST_OID aes192_KEY_WRAP[]			= { AES, 25 };
+
+CONST_OID aes256_ECB[] 				= { AES, 41 };
+CONST_OID aes256_CBC[] 				= { AES, 42 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes256_OFB[] 				= { AES, 43 };
+CONST_OID aes256_CFB[] 				= { AES, 44 };
+#endif
+CONST_OID aes256_KEY_WRAP[]			= { AES, 45 };
+
+CONST_OID camellia128_CBC[]			= { CAMELLIA_ENCRYPT_OID, 2};
+CONST_OID camellia192_CBC[]			= { CAMELLIA_ENCRYPT_OID, 3};
+CONST_OID camellia256_CBC[]			= { CAMELLIA_ENCRYPT_OID, 4};
+CONST_OID camellia128_KEY_WRAP[]		= { CAMELLIA_WRAP_OID, 2};
+CONST_OID camellia192_KEY_WRAP[]		= { CAMELLIA_WRAP_OID, 3};
+CONST_OID camellia256_KEY_WRAP[]		= { CAMELLIA_WRAP_OID, 4};
+
+CONST_OID sha256[]                              = { SHAXXX, 1 };
+CONST_OID sha384[]                              = { SHAXXX, 2 };
+CONST_OID sha512[]                              = { SHAXXX, 3 };
+
+CONST_OID ansix962ECPublicKey[]             = { ANSI_X962_OID, 0x02, 0x01 };
+CONST_OID ansix962SignaturewithSHA1Digest[] = { ANSI_X962_SIGNATURE_OID, 0x01 };
+CONST_OID ansix962SignatureRecommended[]    = { ANSI_X962_SIGNATURE_OID, 0x02 };
+CONST_OID ansix962SignatureSpecified[]      = { ANSI_X962_SPECIFY_OID };
+CONST_OID ansix962SignaturewithSHA224Digest[] = { ANSI_X962_SPECIFY_OID, 0x01 };
+CONST_OID ansix962SignaturewithSHA256Digest[] = { ANSI_X962_SPECIFY_OID, 0x02 };
+CONST_OID ansix962SignaturewithSHA384Digest[] = { ANSI_X962_SPECIFY_OID, 0x03 };
+CONST_OID ansix962SignaturewithSHA512Digest[] = { ANSI_X962_SPECIFY_OID, 0x04 };
+
+/* ANSI X9.62 prime curve OIDs */
+/* NOTE: prime192v1 is the same as secp192r1, prime256v1 is the
+ * same as secp256r1
+ */
+CONST_OID ansiX962prime192v1[] = { ANSI_X962_GFp_OID, 0x01 };
+CONST_OID ansiX962prime192v2[] = { ANSI_X962_GFp_OID, 0x02 };
+CONST_OID ansiX962prime192v3[] = { ANSI_X962_GFp_OID, 0x03 };
+CONST_OID ansiX962prime239v1[] = { ANSI_X962_GFp_OID, 0x04 };
+CONST_OID ansiX962prime239v2[] = { ANSI_X962_GFp_OID, 0x05 };
+CONST_OID ansiX962prime239v3[] = { ANSI_X962_GFp_OID, 0x06 };
+CONST_OID ansiX962prime256v1[] = { ANSI_X962_GFp_OID, 0x07 };
+
+/* SECG prime curve OIDs */
+CONST_OID secgECsecp112r1[] = { SECG_OID, 0x06 };
+CONST_OID secgECsecp112r2[] = { SECG_OID, 0x07 };
+CONST_OID secgECsecp128r1[] = { SECG_OID, 0x1c };
+CONST_OID secgECsecp128r2[] = { SECG_OID, 0x1d };
+CONST_OID secgECsecp160k1[] = { SECG_OID, 0x09 };
+CONST_OID secgECsecp160r1[] = { SECG_OID, 0x08 };
+CONST_OID secgECsecp160r2[] = { SECG_OID, 0x1e };
+CONST_OID secgECsecp192k1[] = { SECG_OID, 0x1f };
+CONST_OID secgECsecp224k1[] = { SECG_OID, 0x20 };
+CONST_OID secgECsecp224r1[] = { SECG_OID, 0x21 };
+CONST_OID secgECsecp256k1[] = { SECG_OID, 0x0a };
+CONST_OID secgECsecp384r1[] = { SECG_OID, 0x22 };
+CONST_OID secgECsecp521r1[] = { SECG_OID, 0x23 };
+
+/* ANSI X9.62 characteristic two curve OIDs */
+CONST_OID ansiX962c2pnb163v1[] = { ANSI_X962_GF2m_OID, 0x01 };
+CONST_OID ansiX962c2pnb163v2[] = { ANSI_X962_GF2m_OID, 0x02 };
+CONST_OID ansiX962c2pnb163v3[] = { ANSI_X962_GF2m_OID, 0x03 };
+CONST_OID ansiX962c2pnb176v1[] = { ANSI_X962_GF2m_OID, 0x04 };
+CONST_OID ansiX962c2tnb191v1[] = { ANSI_X962_GF2m_OID, 0x05 };
+CONST_OID ansiX962c2tnb191v2[] = { ANSI_X962_GF2m_OID, 0x06 };
+CONST_OID ansiX962c2tnb191v3[] = { ANSI_X962_GF2m_OID, 0x07 };
+CONST_OID ansiX962c2onb191v4[] = { ANSI_X962_GF2m_OID, 0x08 };
+CONST_OID ansiX962c2onb191v5[] = { ANSI_X962_GF2m_OID, 0x09 };
+CONST_OID ansiX962c2pnb208w1[] = { ANSI_X962_GF2m_OID, 0x0a };
+CONST_OID ansiX962c2tnb239v1[] = { ANSI_X962_GF2m_OID, 0x0b };
+CONST_OID ansiX962c2tnb239v2[] = { ANSI_X962_GF2m_OID, 0x0c };
+CONST_OID ansiX962c2tnb239v3[] = { ANSI_X962_GF2m_OID, 0x0d };
+CONST_OID ansiX962c2onb239v4[] = { ANSI_X962_GF2m_OID, 0x0e };
+CONST_OID ansiX962c2onb239v5[] = { ANSI_X962_GF2m_OID, 0x0f };
+CONST_OID ansiX962c2pnb272w1[] = { ANSI_X962_GF2m_OID, 0x10 };
+CONST_OID ansiX962c2pnb304w1[] = { ANSI_X962_GF2m_OID, 0x11 };
+CONST_OID ansiX962c2tnb359v1[] = { ANSI_X962_GF2m_OID, 0x12 };
+CONST_OID ansiX962c2pnb368w1[] = { ANSI_X962_GF2m_OID, 0x13 };
+CONST_OID ansiX962c2tnb431r1[] = { ANSI_X962_GF2m_OID, 0x14 };
+
+/* SECG characterisitic two curve OIDs */
+CONST_OID secgECsect113r1[] = {SECG_OID, 0x04 };
+CONST_OID secgECsect113r2[] = {SECG_OID, 0x05 };
+CONST_OID secgECsect131r1[] = {SECG_OID, 0x16 };
+CONST_OID secgECsect131r2[] = {SECG_OID, 0x17 };
+CONST_OID secgECsect163k1[] = {SECG_OID, 0x01 };
+CONST_OID secgECsect163r1[] = {SECG_OID, 0x02 };
+CONST_OID secgECsect163r2[] = {SECG_OID, 0x0f };
+CONST_OID secgECsect193r1[] = {SECG_OID, 0x18 };
+CONST_OID secgECsect193r2[] = {SECG_OID, 0x19 };
+CONST_OID secgECsect233k1[] = {SECG_OID, 0x1a };
+CONST_OID secgECsect233r1[] = {SECG_OID, 0x1b };
+CONST_OID secgECsect239k1[] = {SECG_OID, 0x03 };
+CONST_OID secgECsect283k1[] = {SECG_OID, 0x10 };
+CONST_OID secgECsect283r1[] = {SECG_OID, 0x11 };
+CONST_OID secgECsect409k1[] = {SECG_OID, 0x24 };
+CONST_OID secgECsect409r1[] = {SECG_OID, 0x25 };
+CONST_OID secgECsect571k1[] = {SECG_OID, 0x26 };
+CONST_OID secgECsect571r1[] = {SECG_OID, 0x27 };
+
+CONST_OID seed_CBC[]				= { SEED_OID, 4 };
+
+#define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
+#ifndef SECOID_NO_STRINGS
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext }
+#else
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, 0, mech, ext }
+#endif
+
+#if defined(NSS_ALLOW_UNSUPPORTED_CRITICAL)
+#define FAKE_SUPPORTED_CERT_EXTENSION   SUPPORTED_CERT_EXTENSION
+#else
+#define FAKE_SUPPORTED_CERT_EXTENSION UNSUPPORTED_CERT_EXTENSION
+#endif
+
+/*
+ * NOTE: the order of these entries must mach the SECOidTag enum in secoidt.h!
+ */
+const static SECOidData oids[SEC_OID_TOTAL] = {
+    { { siDEROID, NULL, 0 }, SEC_OID_UNKNOWN,
+	"Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+    OD( md2, SEC_OID_MD2, "MD2", CKM_MD2, INVALID_CERT_EXTENSION ),
+    OD( md4, SEC_OID_MD4,
+	"MD4", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( md5, SEC_OID_MD5, "MD5", CKM_MD5, INVALID_CERT_EXTENSION ),
+    OD( sha1, SEC_OID_SHA1, "SHA-1", CKM_SHA_1, INVALID_CERT_EXTENSION ),
+    OD( rc2cbc, SEC_OID_RC2_CBC,
+	"RC2-CBC", CKM_RC2_CBC, INVALID_CERT_EXTENSION ),
+    OD( rc4, SEC_OID_RC4, "RC4", CKM_RC4, INVALID_CERT_EXTENSION ),
+    OD( desede3cbc, SEC_OID_DES_EDE3_CBC,
+	"DES-EDE3-CBC", CKM_DES3_CBC, INVALID_CERT_EXTENSION ),
+    OD( rc5cbcpad, SEC_OID_RC5_CBC_PAD,
+	"RC5-CBCPad", CKM_RC5_CBC, INVALID_CERT_EXTENSION ),
+    OD( desecb, SEC_OID_DES_ECB,
+	"DES-ECB", CKM_DES_ECB, INVALID_CERT_EXTENSION ),
+    OD( descbc, SEC_OID_DES_CBC,
+	"DES-CBC", CKM_DES_CBC, INVALID_CERT_EXTENSION ),
+    OD( desofb, SEC_OID_DES_OFB,
+	"DES-OFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( descfb, SEC_OID_DES_CFB,
+	"DES-CFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( desmac, SEC_OID_DES_MAC,
+	"DES-MAC", CKM_DES_MAC, INVALID_CERT_EXTENSION ),
+    OD( desede, SEC_OID_DES_EDE,
+	"DES-EDE", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( isoSHAWithRSASignature, SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE,
+	"ISO SHA with RSA Signature", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs1RSAEncryption, SEC_OID_PKCS1_RSA_ENCRYPTION,
+	"PKCS #1 RSA Encryption", CKM_RSA_PKCS, INVALID_CERT_EXTENSION ),
+
+    /* the following Signing mechanisms should get new CKM_ values when
+     * values for CKM_RSA_WITH_MDX and CKM_RSA_WITH_SHA_1 get defined in
+     * PKCS #11.
+     */
+    OD( pkcs1MD2WithRSAEncryption, SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION,
+	"PKCS #1 MD2 With RSA Encryption", CKM_MD2_RSA_PKCS,
+	INVALID_CERT_EXTENSION ),
+    OD( pkcs1MD4WithRSAEncryption, SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION,
+	"PKCS #1 MD4 With RSA Encryption", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs1MD5WithRSAEncryption, SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
+	"PKCS #1 MD5 With RSA Encryption", CKM_MD5_RSA_PKCS,
+	INVALID_CERT_EXTENSION ),
+    OD( pkcs1SHA1WithRSAEncryption, SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION,
+	"PKCS #1 SHA-1 With RSA Encryption", CKM_SHA1_RSA_PKCS,
+	INVALID_CERT_EXTENSION ),
+
+    OD( pkcs5PbeWithMD2AndDEScbc, SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC,
+	"PKCS #5 Password Based Encryption with MD2 and DES-CBC",
+	CKM_PBE_MD2_DES_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs5PbeWithMD5AndDEScbc, SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC,
+	"PKCS #5 Password Based Encryption with MD5 and DES-CBC",
+	CKM_PBE_MD5_DES_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs5PbeWithSha1AndDEScbc, SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC,
+	"PKCS #5 Password Based Encryption with SHA-1 and DES-CBC", 
+	CKM_NETSCAPE_PBE_SHA1_DES_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs7, SEC_OID_PKCS7,
+	"PKCS #7", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs7Data, SEC_OID_PKCS7_DATA,
+	"PKCS #7 Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs7SignedData, SEC_OID_PKCS7_SIGNED_DATA,
+	"PKCS #7 Signed Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs7EnvelopedData, SEC_OID_PKCS7_ENVELOPED_DATA,
+	"PKCS #7 Enveloped Data", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs7SignedEnvelopedData, SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA,
+	"PKCS #7 Signed And Enveloped Data", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs7DigestedData, SEC_OID_PKCS7_DIGESTED_DATA,
+	"PKCS #7 Digested Data", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs7EncryptedData, SEC_OID_PKCS7_ENCRYPTED_DATA,
+	"PKCS #7 Encrypted Data", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9EmailAddress, SEC_OID_PKCS9_EMAIL_ADDRESS,
+	"PKCS #9 Email Address", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9UnstructuredName, SEC_OID_PKCS9_UNSTRUCTURED_NAME,
+	"PKCS #9 Unstructured Name", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9ContentType, SEC_OID_PKCS9_CONTENT_TYPE,
+	"PKCS #9 Content Type", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9MessageDigest, SEC_OID_PKCS9_MESSAGE_DIGEST,
+	"PKCS #9 Message Digest", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9SigningTime, SEC_OID_PKCS9_SIGNING_TIME,
+	"PKCS #9 Signing Time", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9CounterSignature, SEC_OID_PKCS9_COUNTER_SIGNATURE,
+	"PKCS #9 Counter Signature", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9ChallengePassword, SEC_OID_PKCS9_CHALLENGE_PASSWORD,
+	"PKCS #9 Challenge Password", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9UnstructuredAddress, SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS,
+	"PKCS #9 Unstructured Address", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9ExtendedCertificateAttributes,
+	SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES,
+	"PKCS #9 Extended Certificate Attributes", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9SMIMECapabilities, SEC_OID_PKCS9_SMIME_CAPABILITIES,
+	"PKCS #9 S/MIME Capabilities", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520CommonName, SEC_OID_AVA_COMMON_NAME,
+	"X520 Common Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520CountryName, SEC_OID_AVA_COUNTRY_NAME,
+	"X520 Country Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520LocalityName, SEC_OID_AVA_LOCALITY,
+	"X520 Locality Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520StateOrProvinceName, SEC_OID_AVA_STATE_OR_PROVINCE,
+	"X520 State Or Province Name", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520OrgName, SEC_OID_AVA_ORGANIZATION_NAME,
+	"X520 Organization Name", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520OrgUnitName, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
+	"X520 Organizational Unit Name", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520DnQualifier, SEC_OID_AVA_DN_QUALIFIER,
+	"X520 DN Qualifier", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( rfc2247DomainComponent, SEC_OID_AVA_DC,
+	"RFC 2247 Domain Component", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    OD( nsTypeGIF, SEC_OID_NS_TYPE_GIF,
+	"GIF", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( nsTypeJPEG, SEC_OID_NS_TYPE_JPEG,
+	"JPEG", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( nsTypeURL, SEC_OID_NS_TYPE_URL,
+	"URL", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( nsTypeHTML, SEC_OID_NS_TYPE_HTML,
+	"HTML", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( nsTypeCertSeq, SEC_OID_NS_TYPE_CERT_SEQUENCE,
+	"Certificate Sequence", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( missiCertKEADSSOld, SEC_OID_MISSI_KEA_DSS_OLD, 
+	"MISSI KEA and DSS Algorithm (Old)",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( missiCertDSSOld, SEC_OID_MISSI_DSS_OLD, 
+	"MISSI DSS Algorithm (Old)",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( missiCertKEADSS, SEC_OID_MISSI_KEA_DSS, 
+	"MISSI KEA and DSS Algorithm",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( missiCertDSS, SEC_OID_MISSI_DSS, 
+	"MISSI DSS Algorithm",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( missiCertKEA, SEC_OID_MISSI_KEA, 
+	"MISSI KEA Algorithm",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( missiCertAltKEA, SEC_OID_MISSI_ALT_KEA, 
+	"MISSI Alternate KEA Algorithm",
+          CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* Netscape private extensions */
+    OD( nsCertExtNetscapeOK, SEC_OID_NS_CERT_EXT_NETSCAPE_OK,
+	"Netscape says this cert is OK",
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsCertExtIssuerLogo, SEC_OID_NS_CERT_EXT_ISSUER_LOGO,
+	"Certificate Issuer Logo",
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsCertExtSubjectLogo, SEC_OID_NS_CERT_EXT_SUBJECT_LOGO,
+	"Certificate Subject Logo",
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsExtCertType, SEC_OID_NS_CERT_EXT_CERT_TYPE,
+	"Certificate Type",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtBaseURL, SEC_OID_NS_CERT_EXT_BASE_URL,
+	"Certificate Extension Base URL",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtRevocationURL, SEC_OID_NS_CERT_EXT_REVOCATION_URL,
+	"Certificate Revocation URL",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtCARevocationURL, SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL,
+	"Certificate Authority Revocation URL",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtCACRLURL, SEC_OID_NS_CERT_EXT_CA_CRL_URL,
+	"Certificate Authority CRL Download URL",
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsExtCACertURL, SEC_OID_NS_CERT_EXT_CA_CERT_URL,
+	"Certificate Authority Certificate Download URL",
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsExtCertRenewalURL, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL,
+	"Certificate Renewal URL", 
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ), 
+    OD( nsExtCAPolicyURL, SEC_OID_NS_CERT_EXT_CA_POLICY_URL,
+	"Certificate Authority Policy URL",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtHomepageURL, SEC_OID_NS_CERT_EXT_HOMEPAGE_URL,
+	"Certificate Homepage URL", 
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsExtEntityLogo, SEC_OID_NS_CERT_EXT_ENTITY_LOGO,
+	"Certificate Entity Logo", 
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsExtUserPicture, SEC_OID_NS_CERT_EXT_USER_PICTURE,
+	"Certificate User Picture", 
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( nsExtSSLServerName, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME,
+	"Certificate SSL Server Name", 
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtComment, SEC_OID_NS_CERT_EXT_COMMENT,
+	"Certificate Comment", 
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtLostPasswordURL, SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL,
+        "Lost Password URL", 
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsExtCertRenewalTime, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME, 
+	"Certificate Renewal Time", 
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( nsKeyUsageGovtApproved, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED,
+	"Strong Crypto Export Approved",
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+
+
+    /* x.509 v3 certificate extensions */
+    OD( x509SubjectDirectoryAttr, SEC_OID_X509_SUBJECT_DIRECTORY_ATTR,
+	"Certificate Subject Directory Attributes",
+	CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION),
+    OD( x509SubjectKeyID, SEC_OID_X509_SUBJECT_KEY_ID, 
+	"Certificate Subject Key ID",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509KeyUsage, SEC_OID_X509_KEY_USAGE, 
+	"Certificate Key Usage",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509PrivateKeyUsagePeriod, SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD,
+	"Certificate Private Key Usage Period",
+        CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( x509SubjectAltName, SEC_OID_X509_SUBJECT_ALT_NAME, 
+	"Certificate Subject Alt Name",
+        CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509IssuerAltName, SEC_OID_X509_ISSUER_ALT_NAME, 
+	"Certificate Issuer Alt Name",
+        CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509BasicConstraints, SEC_OID_X509_BASIC_CONSTRAINTS, 
+	"Certificate Basic Constraints",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509NameConstraints, SEC_OID_X509_NAME_CONSTRAINTS, 
+	"Certificate Name Constraints",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509CRLDistPoints, SEC_OID_X509_CRL_DIST_POINTS, 
+	"CRL Distribution Points",
+	CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509CertificatePolicies, SEC_OID_X509_CERTIFICATE_POLICIES,
+ 	"Certificate Policies",
+        CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509PolicyMappings, SEC_OID_X509_POLICY_MAPPINGS, 
+ 	"Certificate Policy Mappings",
+        CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+    OD( x509PolicyConstraints, SEC_OID_X509_POLICY_CONSTRAINTS, 
+ 	"Certificate Policy Constraints",
+        CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509AuthKeyID, SEC_OID_X509_AUTH_KEY_ID, 
+	"Certificate Authority Key Identifier",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509ExtKeyUsage, SEC_OID_X509_EXT_KEY_USAGE, 
+	"Extended Key Usage",
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509AuthInfoAccess, SEC_OID_X509_AUTH_INFO_ACCESS, 
+	"Authority Information Access",
+        CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+
+    /* x.509 v3 CRL extensions */
+    OD( x509CRLNumber, SEC_OID_X509_CRL_NUMBER, 
+	"CRL Number", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509ReasonCode, SEC_OID_X509_REASON_CODE, 
+	"CRL reason code", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( x509InvalidDate, SEC_OID_X509_INVALID_DATE, 
+	"Invalid Date", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+	
+    OD( x500RSAEncryption, SEC_OID_X500_RSA_ENCRYPTION,
+	"X500 RSA Encryption", CKM_RSA_X_509, INVALID_CERT_EXTENSION ),
+
+    /* added for alg 1485 */
+    OD( rfc1274Uid, SEC_OID_RFC1274_UID,
+	"RFC1274 User Id", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( rfc1274Mail, SEC_OID_RFC1274_MAIL,
+	"RFC1274 E-mail Address", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* pkcs 12 additions */
+    OD( pkcs12, SEC_OID_PKCS12,
+	"PKCS #12", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12ModeIDs, SEC_OID_PKCS12_MODE_IDS,
+	"PKCS #12 Mode IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12ESPVKIDs, SEC_OID_PKCS12_ESPVK_IDS,
+	"PKCS #12 ESPVK IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12BagIDs, SEC_OID_PKCS12_BAG_IDS,
+	"PKCS #12 Bag IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12CertBagIDs, SEC_OID_PKCS12_CERT_BAG_IDS,
+	"PKCS #12 Cert Bag IDs", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12OIDs, SEC_OID_PKCS12_OIDS,
+	"PKCS #12 OIDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PBEIDs, SEC_OID_PKCS12_PBE_IDS,
+	"PKCS #12 PBE IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12SignatureIDs, SEC_OID_PKCS12_SIGNATURE_IDS,
+	"PKCS #12 Signature IDs", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12EnvelopingIDs, SEC_OID_PKCS12_ENVELOPING_IDS,
+	"PKCS #12 Enveloping IDs", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PKCS8KeyShrouding, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING,
+	"PKCS #12 Key Shrouding", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12KeyBagID, SEC_OID_PKCS12_KEY_BAG_ID,
+	"PKCS #12 Key Bag ID", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12CertAndCRLBagID, SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
+	"PKCS #12 Cert And CRL Bag ID", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12SecretBagID, SEC_OID_PKCS12_SECRET_BAG_ID,
+	"PKCS #12 Secret Bag ID", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12X509CertCRLBag, SEC_OID_PKCS12_X509_CERT_CRL_BAG,
+	"PKCS #12 X509 Cert CRL Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12SDSICertBag, SEC_OID_PKCS12_SDSI_CERT_BAG,
+	"PKCS #12 SDSI Cert Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PBEWithSha1And128BitRC4,
+	SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4,
+	"PKCS #12 PBE With SHA-1 and 128 Bit RC4", 
+	CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PBEWithSha1And40BitRC4,
+	SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4,
+	"PKCS #12 PBE With SHA-1 and 40 Bit RC4", 
+	CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PBEWithSha1AndTripleDESCBC,
+	SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC,
+	"PKCS #12 PBE With SHA-1 and Triple DES-CBC", 
+	CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PBEWithSha1And128BitRC2CBC,
+	SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC,
+	"PKCS #12 PBE With SHA-1 and 128 Bit RC2 CBC", 
+	CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PBEWithSha1And40BitRC2CBC,
+	SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC,
+	"PKCS #12 PBE With SHA-1 and 40 Bit RC2 CBC", 
+	CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs12RSAEncryptionWith128BitRC4,
+	SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4,
+	"PKCS #12 RSA Encryption with 128 Bit RC4",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12RSAEncryptionWith40BitRC4,
+	SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4,
+	"PKCS #12 RSA Encryption with 40 Bit RC4",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12RSAEncryptionWithTripleDES,
+	SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES,
+	"PKCS #12 RSA Encryption with Triple DES",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12RSASignatureWithSHA1Digest,
+	SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST,
+	"PKCS #12 RSA Encryption with Triple DES",
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* DSA signatures */
+    OD( ansix9DSASignature, SEC_OID_ANSIX9_DSA_SIGNATURE,
+	"ANSI X9.57 DSA Signature", CKM_DSA, INVALID_CERT_EXTENSION ),
+    OD( ansix9DSASignaturewithSHA1Digest,
+        SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST,
+	"ANSI X9.57 DSA Signature with SHA-1 Digest", 
+	CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+    OD( bogusDSASignaturewithSHA1Digest,
+        SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST,
+	"FORTEZZA DSA Signature with SHA-1 Digest", 
+	CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+
+    /* verisign oids */
+    OD( verisignUserNotices, SEC_OID_VERISIGN_USER_NOTICES,
+	"Verisign User Notices", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* pkix oids */
+    OD( pkixCPSPointerQualifier, SEC_OID_PKIX_CPS_POINTER_QUALIFIER,
+	"PKIX CPS Pointer Qualifier", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixUserNoticeQualifier, SEC_OID_PKIX_USER_NOTICE_QUALIFIER,
+	"PKIX User Notice Qualifier", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    OD( pkixOCSP, SEC_OID_PKIX_OCSP,
+	"PKIX Online Certificate Status Protocol", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixOCSPBasicResponse, SEC_OID_PKIX_OCSP_BASIC_RESPONSE,
+	"OCSP Basic Response", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixOCSPNonce, SEC_OID_PKIX_OCSP_NONCE,
+	"OCSP Nonce Extension", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixOCSPCRL, SEC_OID_PKIX_OCSP_CRL,
+	"OCSP CRL Reference Extension", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixOCSPResponse, SEC_OID_PKIX_OCSP_RESPONSE,
+	"OCSP Response Types Extension", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixOCSPNoCheck, SEC_OID_PKIX_OCSP_NO_CHECK,
+	"OCSP No Check Extension", 
+	CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+    OD( pkixOCSPArchiveCutoff, SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF,
+	"OCSP Archive Cutoff Extension", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixOCSPServiceLocator, SEC_OID_PKIX_OCSP_SERVICE_LOCATOR,
+	"OCSP Service Locator Extension", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    OD( pkixRegCtrlRegToken, SEC_OID_PKIX_REGCTRL_REGTOKEN,
+        "PKIX CRMF Registration Control, Registration Token", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixRegCtrlAuthenticator, SEC_OID_PKIX_REGCTRL_AUTHENTICATOR,
+        "PKIX CRMF Registration Control, Registration Authenticator", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkixRegCtrlPKIPubInfo, SEC_OID_PKIX_REGCTRL_PKIPUBINFO,
+        "PKIX CRMF Registration Control, PKI Publication Info", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixRegCtrlPKIArchOptions,
+        SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
+        "PKIX CRMF Registration Control, PKI Archive Options", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixRegCtrlOldCertID, SEC_OID_PKIX_REGCTRL_OLD_CERT_ID,
+        "PKIX CRMF Registration Control, Old Certificate ID", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixRegCtrlProtEncKey, SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY,
+        "PKIX CRMF Registration Control, Protocol Encryption Key", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixRegInfoUTF8Pairs, SEC_OID_PKIX_REGINFO_UTF8_PAIRS,
+        "PKIX CRMF Registration Info, UTF8 Pairs", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixRegInfoCertReq, SEC_OID_PKIX_REGINFO_CERT_REQUEST,
+        "PKIX CRMF Registration Info, Certificate Request", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixExtendedKeyUsageServerAuth,
+        SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
+        "TLS Web Server Authentication Certificate",
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixExtendedKeyUsageClientAuth,
+        SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH,
+        "TLS Web Client Authentication Certificate",
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixExtendedKeyUsageCodeSign, SEC_OID_EXT_KEY_USAGE_CODE_SIGN,
+        "Code Signing Certificate",
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixExtendedKeyUsageEMailProtect,
+        SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT,
+        "E-Mail Protection Certificate",
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixExtendedKeyUsageTimeStamp,
+        SEC_OID_EXT_KEY_USAGE_TIME_STAMP,
+        "Time Stamping Certifcate",
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD( pkixOCSPResponderExtendedKeyUsage, SEC_OID_OCSP_RESPONDER,
+          "OCSP Responder Certificate",
+          CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+
+    /* Netscape Algorithm OIDs */
+
+    OD( netscapeSMimeKEA, SEC_OID_NETSCAPE_SMIME_KEA,
+	"Netscape S/MIME KEA", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+      /* Skipjack OID -- ### mwelch temporary */
+    OD( skipjackCBC, SEC_OID_FORTEZZA_SKIPJACK,
+	"Skipjack CBC64", CKM_SKIPJACK_CBC64, INVALID_CERT_EXTENSION ),
+
+    /* pkcs12 v2 oids */
+    OD( pkcs12V2PBEWithSha1And128BitRC4,
+        SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4,
+	"PKCS #12 V2 PBE With SHA-1 And 128 Bit RC4", 
+	CKM_PBE_SHA1_RC4_128, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V2PBEWithSha1And40BitRC4,
+        SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4,
+	"PKCS #12 V2 PBE With SHA-1 And 40 Bit RC4", 
+	CKM_PBE_SHA1_RC4_40, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V2PBEWithSha1And3KeyTripleDEScbc,
+        SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
+	"PKCS #12 V2 PBE With SHA-1 And 3KEY Triple DES-CBC", 
+	CKM_PBE_SHA1_DES3_EDE_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V2PBEWithSha1And2KeyTripleDEScbc,
+        SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC,
+	"PKCS #12 V2 PBE With SHA-1 And 2KEY Triple DES-CBC", 
+	CKM_PBE_SHA1_DES2_EDE_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V2PBEWithSha1And128BitRC2cbc,
+        SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC,
+	"PKCS #12 V2 PBE With SHA-1 And 128 Bit RC2 CBC", 
+	CKM_PBE_SHA1_RC2_128_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V2PBEWithSha1And40BitRC2cbc,
+        SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC,
+	"PKCS #12 V2 PBE With SHA-1 And 40 Bit RC2 CBC", 
+	CKM_PBE_SHA1_RC2_40_CBC, INVALID_CERT_EXTENSION ),
+    OD( pkcs12SafeContentsID, SEC_OID_PKCS12_SAFE_CONTENTS_ID,
+	"PKCS #12 Safe Contents ID", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12PKCS8ShroudedKeyBagID,
+	SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID,
+	"PKCS #12 Safe Contents ID", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V1KeyBag, SEC_OID_PKCS12_V1_KEY_BAG_ID,
+	"PKCS #12 V1 Key Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V1PKCS8ShroudedKeyBag,
+	SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID,
+	"PKCS #12 V1 PKCS8 Shrouded Key Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V1CertBag, SEC_OID_PKCS12_V1_CERT_BAG_ID,
+	"PKCS #12 V1 Cert Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V1CRLBag, SEC_OID_PKCS12_V1_CRL_BAG_ID,
+	"PKCS #12 V1 CRL Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V1SecretBag, SEC_OID_PKCS12_V1_SECRET_BAG_ID,
+	"PKCS #12 V1 Secret Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs12V1SafeContentsBag, SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
+	"PKCS #12 V1 Safe Contents Bag", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    OD( pkcs9X509Certificate, SEC_OID_PKCS9_X509_CERT,
+	"PKCS #9 X509 Certificate", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9SDSICertificate, SEC_OID_PKCS9_SDSI_CERT,
+	"PKCS #9 SDSI Certificate", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9X509CRL, SEC_OID_PKCS9_X509_CRL,
+	"PKCS #9 X509 CRL", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9FriendlyName, SEC_OID_PKCS9_FRIENDLY_NAME,
+	"PKCS #9 Friendly Name", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9LocalKeyID, SEC_OID_PKCS9_LOCAL_KEY_ID,
+	"PKCS #9 Local Key ID", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), 
+    OD( pkcs12KeyUsageAttr, SEC_OID_BOGUS_KEY_USAGE,
+	"Bogus Key Usage", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( dhPublicKey, SEC_OID_X942_DIFFIE_HELMAN_KEY,
+	"Diffie-Helman Public Key", CKM_DH_PKCS_DERIVE,
+	INVALID_CERT_EXTENSION ),
+    OD( netscapeNickname, SEC_OID_NETSCAPE_NICKNAME,
+	"Netscape Nickname", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* Cert Server specific OIDs */
+    OD( netscapeRecoveryRequest, SEC_OID_NETSCAPE_RECOVERY_REQUEST,
+        "Recovery Request OID", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    OD( nsExtAIACertRenewal, SEC_OID_CERT_RENEWAL_LOCATOR,
+        "Certificate Renewal Locator OID", CKM_INVALID_MECHANISM,
+        INVALID_CERT_EXTENSION ), 
+
+    OD( nsExtCertScopeOfUse, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
+        "Certificate Scope-of-Use Extension", CKM_INVALID_MECHANISM,
+        SUPPORTED_CERT_EXTENSION ),
+
+    /* CMS stuff */
+    OD( cmsESDH, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN,
+        "Ephemeral-Static Diffie-Hellman", CKM_INVALID_MECHANISM /* XXX */,
+        INVALID_CERT_EXTENSION ),
+    OD( cms3DESwrap, SEC_OID_CMS_3DES_KEY_WRAP,
+        "CMS Triple DES Key Wrap", CKM_INVALID_MECHANISM /* XXX */,
+        INVALID_CERT_EXTENSION ),
+    OD( cmsRC2wrap, SEC_OID_CMS_RC2_KEY_WRAP,
+        "CMS RC2 Key Wrap", CKM_INVALID_MECHANISM /* XXX */,
+        INVALID_CERT_EXTENSION ),
+    OD( smimeEncryptionKeyPreference, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE,
+	"S/MIME Encryption Key Preference", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* AES algorithm OIDs */
+    OD( aes128_ECB, SEC_OID_AES_128_ECB,
+	"AES-128-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+    OD( aes128_CBC, SEC_OID_AES_128_CBC,
+	"AES-128-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+    OD( aes192_ECB, SEC_OID_AES_192_ECB,
+	"AES-192-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+    OD( aes192_CBC, SEC_OID_AES_192_CBC,
+	"AES-192-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+    OD( aes256_ECB, SEC_OID_AES_256_ECB,
+	"AES-256-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+    OD( aes256_CBC, SEC_OID_AES_256_CBC,
+	"AES-256-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+
+    /* More bogus DSA OIDs */
+    OD( sdn702DSASignature, SEC_OID_SDN702_DSA_SIGNATURE, 
+	"SDN.702 DSA Signature", CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+
+    OD( ms_smimeEncryptionKeyPreference, 
+        SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE,
+	"Microsoft S/MIME Encryption Key Preference", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    OD( sha256, SEC_OID_SHA256, "SHA-256", CKM_SHA256, INVALID_CERT_EXTENSION),
+    OD( sha384, SEC_OID_SHA384, "SHA-384", CKM_SHA384, INVALID_CERT_EXTENSION),
+    OD( sha512, SEC_OID_SHA512, "SHA-512", CKM_SHA512, INVALID_CERT_EXTENSION),
+
+    OD( pkcs1SHA256WithRSAEncryption, SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION,
+	"PKCS #1 SHA-256 With RSA Encryption", CKM_SHA256_RSA_PKCS,
+	INVALID_CERT_EXTENSION ),
+    OD( pkcs1SHA384WithRSAEncryption, SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION,
+	"PKCS #1 SHA-384 With RSA Encryption", CKM_SHA384_RSA_PKCS,
+	INVALID_CERT_EXTENSION ),
+    OD( pkcs1SHA512WithRSAEncryption, SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION,
+	"PKCS #1 SHA-512 With RSA Encryption", CKM_SHA512_RSA_PKCS,
+	INVALID_CERT_EXTENSION ),
+
+    OD( aes128_KEY_WRAP, SEC_OID_AES_128_KEY_WRAP,
+	"AES-128 Key Wrap", CKM_NSS_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+    OD( aes192_KEY_WRAP, SEC_OID_AES_192_KEY_WRAP,
+	"AES-192 Key Wrap", CKM_NSS_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+    OD( aes256_KEY_WRAP, SEC_OID_AES_256_KEY_WRAP,
+	"AES-256 Key Wrap", CKM_NSS_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+
+    /* Elliptic Curve Cryptography (ECC) OIDs */
+    OD( ansix962ECPublicKey, SEC_OID_ANSIX962_EC_PUBLIC_KEY,
+	"X9.62 elliptic curve public key", CKM_ECDH1_DERIVE,
+	INVALID_CERT_EXTENSION ),
+    OD( ansix962SignaturewithSHA1Digest, 
+	SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE,
+	"X9.62 ECDSA signature with SHA-1", CKM_ECDSA_SHA1,
+	INVALID_CERT_EXTENSION ),
+
+    /* Named curves */
+
+    /* ANSI X9.62 named elliptic curves (prime field) */
+    OD( ansiX962prime192v1, SEC_OID_ANSIX962_EC_PRIME192V1,
+	"ANSI X9.62 elliptic curve prime192v1 (aka secp192r1, NIST P-192)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962prime192v2, SEC_OID_ANSIX962_EC_PRIME192V2,
+	"ANSI X9.62 elliptic curve prime192v2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962prime192v3, SEC_OID_ANSIX962_EC_PRIME192V3,
+	"ANSI X9.62 elliptic curve prime192v3", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962prime239v1, SEC_OID_ANSIX962_EC_PRIME239V1,
+	"ANSI X9.62 elliptic curve prime239v1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962prime239v2, SEC_OID_ANSIX962_EC_PRIME239V2,
+	"ANSI X9.62 elliptic curve prime239v2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962prime239v3, SEC_OID_ANSIX962_EC_PRIME239V3,
+	"ANSI X9.62 elliptic curve prime239v3", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962prime256v1, SEC_OID_ANSIX962_EC_PRIME256V1,
+	"ANSI X9.62 elliptic curve prime256v1 (aka secp256r1, NIST P-256)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+
+    /* SECG named elliptic curves (prime field) */
+    OD( secgECsecp112r1, SEC_OID_SECG_EC_SECP112R1,
+	"SECG elliptic curve secp112r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp112r2, SEC_OID_SECG_EC_SECP112R2,
+	"SECG elliptic curve secp112r2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp128r1, SEC_OID_SECG_EC_SECP128R1,
+	"SECG elliptic curve secp128r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp128r2, SEC_OID_SECG_EC_SECP128R2,
+	"SECG elliptic curve secp128r2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp160k1, SEC_OID_SECG_EC_SECP160K1,
+	"SECG elliptic curve secp160k1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp160r1, SEC_OID_SECG_EC_SECP160R1,
+	"SECG elliptic curve secp160r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp160r2, SEC_OID_SECG_EC_SECP160R2,
+	"SECG elliptic curve secp160r2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp192k1, SEC_OID_SECG_EC_SECP192K1,
+	"SECG elliptic curve secp192k1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp224k1, SEC_OID_SECG_EC_SECP224K1,
+	"SECG elliptic curve secp224k1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp224r1, SEC_OID_SECG_EC_SECP224R1,
+	"SECG elliptic curve secp224r1 (aka NIST P-224)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp256k1, SEC_OID_SECG_EC_SECP256K1,
+	"SECG elliptic curve secp256k1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp384r1, SEC_OID_SECG_EC_SECP384R1,
+	"SECG elliptic curve secp384r1 (aka NIST P-384)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsecp521r1, SEC_OID_SECG_EC_SECP521R1,
+	"SECG elliptic curve secp521r1 (aka NIST P-521)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+
+    /* ANSI X9.62 named elliptic curves (characteristic two field) */
+    OD( ansiX962c2pnb163v1, SEC_OID_ANSIX962_EC_C2PNB163V1,
+	"ANSI X9.62 elliptic curve c2pnb163v1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2pnb163v2, SEC_OID_ANSIX962_EC_C2PNB163V2,
+	"ANSI X9.62 elliptic curve c2pnb163v2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2pnb163v3, SEC_OID_ANSIX962_EC_C2PNB163V3,
+	"ANSI X9.62 elliptic curve c2pnb163v3", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2pnb176v1, SEC_OID_ANSIX962_EC_C2PNB176V1,
+	"ANSI X9.62 elliptic curve c2pnb176v1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb191v1, SEC_OID_ANSIX962_EC_C2TNB191V1,
+	"ANSI X9.62 elliptic curve c2tnb191v1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb191v2, SEC_OID_ANSIX962_EC_C2TNB191V2,
+	"ANSI X9.62 elliptic curve c2tnb191v2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb191v3, SEC_OID_ANSIX962_EC_C2TNB191V3,
+	"ANSI X9.62 elliptic curve c2tnb191v3", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2onb191v4, SEC_OID_ANSIX962_EC_C2ONB191V4,
+	"ANSI X9.62 elliptic curve c2onb191v4", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2onb191v5, SEC_OID_ANSIX962_EC_C2ONB191V5,
+	"ANSI X9.62 elliptic curve c2onb191v5", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2pnb208w1, SEC_OID_ANSIX962_EC_C2PNB208W1,
+	"ANSI X9.62 elliptic curve c2pnb208w1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb239v1, SEC_OID_ANSIX962_EC_C2TNB239V1,
+	"ANSI X9.62 elliptic curve c2tnb239v1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb239v2, SEC_OID_ANSIX962_EC_C2TNB239V2,
+	"ANSI X9.62 elliptic curve c2tnb239v2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb239v3, SEC_OID_ANSIX962_EC_C2TNB239V3,
+	"ANSI X9.62 elliptic curve c2tnb239v3", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2onb239v4, SEC_OID_ANSIX962_EC_C2ONB239V4,
+	"ANSI X9.62 elliptic curve c2onb239v4", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2onb239v5, SEC_OID_ANSIX962_EC_C2ONB239V5,
+	"ANSI X9.62 elliptic curve c2onb239v5", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2pnb272w1, SEC_OID_ANSIX962_EC_C2PNB272W1,
+	"ANSI X9.62 elliptic curve c2pnb272w1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2pnb304w1, SEC_OID_ANSIX962_EC_C2PNB304W1,
+	"ANSI X9.62 elliptic curve c2pnb304w1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb359v1, SEC_OID_ANSIX962_EC_C2TNB359V1,
+	"ANSI X9.62 elliptic curve c2tnb359v1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2pnb368w1, SEC_OID_ANSIX962_EC_C2PNB368W1,
+	"ANSI X9.62 elliptic curve c2pnb368w1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansiX962c2tnb431r1, SEC_OID_ANSIX962_EC_C2TNB431R1,
+	"ANSI X9.62 elliptic curve c2tnb431r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+
+    /* SECG named elliptic curves (characterisitic two field) */
+    OD( secgECsect113r1, SEC_OID_SECG_EC_SECT113R1,
+	"SECG elliptic curve sect113r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect113r2, SEC_OID_SECG_EC_SECT113R2,
+	"SECG elliptic curve sect113r2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect131r1, SEC_OID_SECG_EC_SECT131R1,
+	"SECG elliptic curve sect131r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect131r2, SEC_OID_SECG_EC_SECT131R2,
+	"SECG elliptic curve sect131r2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect163k1, SEC_OID_SECG_EC_SECT163K1,
+	"SECG elliptic curve sect163k1 (aka NIST K-163)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect163r1, SEC_OID_SECG_EC_SECT163R1,
+	"SECG elliptic curve sect163r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect163r2, SEC_OID_SECG_EC_SECT163R2,
+	"SECG elliptic curve sect163r2 (aka NIST B-163)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect193r1, SEC_OID_SECG_EC_SECT193R1,
+	"SECG elliptic curve sect193r1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect193r2, SEC_OID_SECG_EC_SECT193R2,
+	"SECG elliptic curve sect193r2", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect233k1, SEC_OID_SECG_EC_SECT233K1,
+	"SECG elliptic curve sect233k1 (aka NIST K-233)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect233r1, SEC_OID_SECG_EC_SECT233R1,
+	"SECG elliptic curve sect233r1 (aka NIST B-233)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect239k1, SEC_OID_SECG_EC_SECT239K1,
+	"SECG elliptic curve sect239k1", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect283k1, SEC_OID_SECG_EC_SECT283K1,
+	"SECG elliptic curve sect283k1 (aka NIST K-283)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect283r1, SEC_OID_SECG_EC_SECT283R1,
+	"SECG elliptic curve sect283r1 (aka NIST B-283)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect409k1, SEC_OID_SECG_EC_SECT409K1,
+	"SECG elliptic curve sect409k1 (aka NIST K-409)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect409r1, SEC_OID_SECG_EC_SECT409R1,
+	"SECG elliptic curve sect409r1 (aka NIST B-409)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect571k1, SEC_OID_SECG_EC_SECT571K1,
+	"SECG elliptic curve sect571k1 (aka NIST K-571)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( secgECsect571r1, SEC_OID_SECG_EC_SECT571R1,
+	"SECG elliptic curve sect571r1 (aka NIST B-571)", 
+	CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+
+    OD( netscapeAOLScreenname, SEC_OID_NETSCAPE_AOLSCREENNAME,
+	"AOL Screenname", CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+
+    OD( x520SurName, SEC_OID_AVA_SURNAME,
+    	"X520 Title",         CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520SerialNumber, SEC_OID_AVA_SERIAL_NUMBER,
+        "X520 Serial Number", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520StreetAddress, SEC_OID_AVA_STREET_ADDRESS,
+        "X520 Street Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520Title, SEC_OID_AVA_TITLE, 
+    	"X520 Title",         CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520PostalAddress, SEC_OID_AVA_POSTAL_ADDRESS,
+    	"X520 Postal Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520PostalCode, SEC_OID_AVA_POSTAL_CODE,
+    	"X520 Postal Code",   CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520PostOfficeBox, SEC_OID_AVA_POST_OFFICE_BOX,
+    	"X520 Post Office Box", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520GivenName, SEC_OID_AVA_GIVEN_NAME,
+    	"X520 Given Name",    CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520Initials, SEC_OID_AVA_INITIALS,
+    	"X520 Initials",      CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520GenerationQualifier, SEC_OID_AVA_GENERATION_QUALIFIER,
+    	"X520 Generation Qualifier", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520HouseIdentifier, SEC_OID_AVA_HOUSE_IDENTIFIER,
+    	"X520 House Identifier", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( x520Pseudonym, SEC_OID_AVA_PSEUDONYM,
+    	"X520 Pseudonym",     CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* More OIDs */
+    OD( pkixCAIssuers, SEC_OID_PKIX_CA_ISSUERS,
+        "PKIX CA issuers access method", 
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs9ExtensionRequest, SEC_OID_PKCS9_EXTENSION_REQUEST,
+    	"PKCS #9 Extension Request",
+        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* more ECC Signature Oids */
+    OD( ansix962SignatureRecommended,
+	SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST,
+	"X9.62 ECDSA signature with recommended digest", CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansix962SignatureSpecified,
+	SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST,
+	"X9.62 ECDSA signature with specified digest", CKM_ECDSA,
+	INVALID_CERT_EXTENSION ),
+    OD( ansix962SignaturewithSHA224Digest,
+	SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE,
+	"X9.62 ECDSA signature with SHA224", CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansix962SignaturewithSHA256Digest,
+	SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE,
+	"X9.62 ECDSA signature with SHA256", CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansix962SignaturewithSHA384Digest,
+	SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE,
+	"X9.62 ECDSA signature with SHA384", CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( ansix962SignaturewithSHA512Digest,
+	SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE,
+	"X9.62 ECDSA signature with SHA512", CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+
+    /* More id-ce and id-pe OIDs from RFC 3280 */
+    OD( x509HoldInstructionCode,      SEC_OID_X509_HOLD_INSTRUCTION_CODE,
+        "CRL Hold Instruction Code",  CKM_INVALID_MECHANISM,
+	UNSUPPORTED_CERT_EXTENSION ),
+    OD( x509DeltaCRLIndicator,        SEC_OID_X509_DELTA_CRL_INDICATOR,
+        "Delta CRL Indicator",        CKM_INVALID_MECHANISM,
+	FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509IssuingDistributionPoint, SEC_OID_X509_ISSUING_DISTRIBUTION_POINT,
+        "Issuing Distribution Point", CKM_INVALID_MECHANISM,
+	FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509CertIssuer,               SEC_OID_X509_CERT_ISSUER,
+        "Certificate Issuer Extension",CKM_INVALID_MECHANISM,
+	FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509FreshestCRL,              SEC_OID_X509_FRESHEST_CRL,
+        "Freshest CRL",               CKM_INVALID_MECHANISM,
+	UNSUPPORTED_CERT_EXTENSION ),
+    OD( x509InhibitAnyPolicy,         SEC_OID_X509_INHIBIT_ANY_POLICY,
+        "Inhibit Any Policy",         CKM_INVALID_MECHANISM,
+	FAKE_SUPPORTED_CERT_EXTENSION ),
+    OD( x509SubjectInfoAccess,        SEC_OID_X509_SUBJECT_INFO_ACCESS,
+        "Subject Info Access",        CKM_INVALID_MECHANISM,
+	UNSUPPORTED_CERT_EXTENSION ),
+
+    /* Camellia algorithm OIDs */
+    OD( camellia128_CBC, SEC_OID_CAMELLIA_128_CBC,
+	"CAMELLIA-128-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+    OD( camellia192_CBC, SEC_OID_CAMELLIA_192_CBC,
+	"CAMELLIA-192-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+    OD( camellia256_CBC, SEC_OID_CAMELLIA_256_CBC,
+	"CAMELLIA-256-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+
+    /* PKCS 5 v2 OIDS */
+    OD( pkcs5Pbkdf2, SEC_OID_PKCS5_PBKDF2,
+	"PKCS #5 Password Based Key Dervive Function v2 ", 
+	CKM_PKCS5_PBKD2, INVALID_CERT_EXTENSION ),
+    OD( pkcs5Pbes2, SEC_OID_PKCS5_PBES2,
+	"PKCS #5 Password Based Encryption v2 ", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( pkcs5Pbmac1, SEC_OID_PKCS5_PBMAC1,
+	"PKCS #5 Password Based Authentication v1 ", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    OD( hmac_sha1, SEC_OID_HMAC_SHA1, "HMAC SHA-1", 
+	CKM_SHA_1_HMAC, INVALID_CERT_EXTENSION ),
+    OD( hmac_sha224, SEC_OID_HMAC_SHA224, "HMAC SHA-224", 
+	CKM_SHA224_HMAC, INVALID_CERT_EXTENSION ),
+    OD( hmac_sha256, SEC_OID_HMAC_SHA256, "HMAC SHA-256", 
+	CKM_SHA256_HMAC, INVALID_CERT_EXTENSION ),
+    OD( hmac_sha384, SEC_OID_HMAC_SHA384, "HMAC SHA-384", 
+	CKM_SHA384_HMAC, INVALID_CERT_EXTENSION ),
+    OD( hmac_sha512, SEC_OID_HMAC_SHA512, "HMAC SHA-512", 
+	CKM_SHA512_HMAC, INVALID_CERT_EXTENSION ),
+
+    /* SIA extension OIDs */
+    OD( x509SIATimeStamping,          SEC_OID_PKIX_TIMESTAMPING,
+        "SIA Time Stamping",          CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+    OD( x509SIACaRepository,          SEC_OID_PKIX_CA_REPOSITORY,
+        "SIA CA Repository",          CKM_INVALID_MECHANISM,
+	INVALID_CERT_EXTENSION ),
+
+    OD( isoSHA1WithRSASignature, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE,
+	"ISO SHA-1 with RSA Signature", 
+	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+    /* SEED algorithm OIDs */
+    OD( seed_CBC, SEC_OID_SEED_CBC,
+	"SEED-CBC", CKM_SEED_CBC, INVALID_CERT_EXTENSION),
+
+    OD( x509CertificatePoliciesAnyPolicy, SEC_OID_X509_ANY_POLICY,
+ 	"Certificate Policies AnyPolicy",
+        CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+};
+
+/* PRIVATE EXTENDED SECOID Table
+ * This table is private. Its structure is opaque to the outside.
+ * It is indexed by the same SECOidTag as the oids table above.
+ * Every member of this struct must have accessor functions (set, get)
+ * and those functions must operate by value, not by reference.
+ * The addresses of the contents of this table must not be exposed 
+ * by the accessor functions.
+ */
+typedef struct privXOidStr {
+    PRUint32	notPolicyFlags; /* ones complement of policy flags */
+} privXOid;
+
+static privXOid xOids[SEC_OID_TOTAL];
+
+/*
+ * now the dynamic table. The dynamic table gets build at init time.
+ * and conceivably gets modified if the user loads new crypto modules.
+ * All this static data, and the allocated data to which it points,
+ * is protected by a global reader/writer lock.  
+ * The c language guarantees that global and static data that is not 
+ * explicitly initialized will be initialized with zeros.  If we 
+ * initialize it with zeros, the data goes into the initialized data
+ * secment, and increases the size of the library.  By leaving it 
+ * uninitialized, it is allocated in BSS, and does NOT increase the 
+ * library size. 
+ */
+
+typedef struct dynXOidStr {
+    SECOidData  data;
+    privXOid    priv;
+} dynXOid;
+
+static NSSRWLock   * dynOidLock;
+static PLArenaPool * dynOidPool;
+static PLHashTable * dynOidHash;
+static dynXOid    ** dynOidTable;	/* not in the pool */
+static int           dynOidEntriesAllocated;
+static int           dynOidEntriesUsed;
+
+/* Creates NSSRWLock and dynOidPool at initialization time.
+*/
+static SECStatus
+secoid_InitDynOidData(void)
+{
+    SECStatus   rv = SECSuccess;
+
+    dynOidLock = NSSRWLock_New(1, "dynamic OID data");
+    if (!dynOidLock) {
+    	return SECFailure; /* Error code should already be set. */
+    }
+    dynOidPool = PORT_NewArena(2048);
+    if (!dynOidPool) {
+        rv = SECFailure /* Error code should already be set. */;
+    }
+    return rv;
+}
+
+/* Add oidData to hash table.  Caller holds write lock dynOidLock. */
+static SECStatus
+secoid_HashDynamicOiddata(const SECOidData * oid)
+{
+    PLHashEntry *entry;
+
+    if (!dynOidHash) {
+        dynOidHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+			PL_CompareValues, NULL, NULL);
+	if ( !dynOidHash ) {
+	    return SECFailure;
+	}
+    }
+
+    entry = PL_HashTableAdd( dynOidHash, &oid->oid, (void *)oid );
+    return entry ? SECSuccess : SECFailure;
+}
+
+
+/*
+ * Lookup a Dynamic OID. Dynamic OID's still change slowly, so it's
+ * cheaper to rehash the table when it changes than it is to do the loop
+ * each time. 
+ */
+static SECOidData *
+secoid_FindDynamic(const SECItem *key) 
+{
+    SECOidData *ret = NULL;
+
+    if (dynOidHash) {
+	NSSRWLock_LockRead(dynOidLock);
+	if (dynOidHash) { /* must check it again with lock held. */
+	    ret = (SECOidData *)PL_HashTableLookup(dynOidHash, key);
+	}
+	NSSRWLock_UnlockRead(dynOidLock);
+    }
+    if (ret == NULL) {
+	PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+    }
+    return ret;
+}
+
+static dynXOid *
+secoid_FindDynamicByTag(SECOidTag tagnum)
+{
+    dynXOid *dxo = NULL;
+    int tagNumDiff;
+
+    if (tagnum < SEC_OID_TOTAL) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return NULL;
+    }
+    tagNumDiff = tagnum - SEC_OID_TOTAL;
+
+    if (dynOidTable) {
+	NSSRWLock_LockRead(dynOidLock);
+	if (dynOidTable != NULL && /* must check it again with lock held. */
+	    tagNumDiff < dynOidEntriesUsed) {
+	    dxo = dynOidTable[tagNumDiff];
+	}
+	NSSRWLock_UnlockRead(dynOidLock);
+    }
+    if (dxo == NULL) {
+	PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+    }
+    return dxo;
+}
+
+/*
+ * This routine is thread safe now.
+ */
+SECOidTag
+SECOID_AddEntry(const SECOidData * src)
+{
+    SECOidData * dst;
+    dynXOid    **table;
+    SECOidTag    ret         = SEC_OID_UNKNOWN;
+    SECStatus    rv;
+    int          tableEntries;
+    int          used;
+
+    if (!src || !src->oid.data || !src->oid.len || \
+        !src->desc || !strlen(src->desc)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return ret;
+    }
+    if (src->supportedExtension != INVALID_CERT_EXTENSION     &&
+    	src->supportedExtension != UNSUPPORTED_CERT_EXTENSION &&
+    	src->supportedExtension != SUPPORTED_CERT_EXTENSION     ) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return ret;
+    }
+
+    if (!dynOidPool || !dynOidLock) {
+	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+    	return ret;
+    }
+
+    NSSRWLock_LockWrite(dynOidLock);
+
+    /* We've just acquired the write lock, and now we call FindOIDTag
+    ** which will acquire and release the read lock.  NSSRWLock has been
+    ** designed to allow this very case without deadlock.  This approach 
+    ** makes the test for the presence of the OID, and the subsequent 
+    ** addition of the OID to the table a single atomic write operation.
+    */
+    ret = SECOID_FindOIDTag(&src->oid);
+    if (ret != SEC_OID_UNKNOWN) {
+    	/* we could return an error here, but I chose not to do that.
+	** This way, if we add an OID to the shared library's built in
+	** list of OIDs in some future release, and that OID is the same
+	** as some OID that a program has been adding, the program will
+	** not suddenly stop working.
+	*/
+	goto done;
+    }
+
+    table        = dynOidTable;
+    tableEntries = dynOidEntriesAllocated;
+    used         = dynOidEntriesUsed;
+
+    if (used + 1 > tableEntries) {
+	dynXOid   ** newTable;
+	int          newTableEntries = tableEntries + 16;
+
+	newTable = (dynXOid **)PORT_Realloc(table, 
+				       newTableEntries * sizeof(dynXOid *));
+	if (newTable == NULL) {
+	    goto done;
+	}
+	dynOidTable            = table        = newTable;
+	dynOidEntriesAllocated = tableEntries = newTableEntries;
+    }
+
+    /* copy oid structure */
+    dst = (SECOidData *)PORT_ArenaZNew(dynOidPool, dynXOid);
+    if (!dst) {
+    	goto done;
+    }
+    rv  = SECITEM_CopyItem(dynOidPool, &dst->oid, &src->oid);
+    if (rv != SECSuccess) {
+	goto done;
+    }
+    dst->desc = PORT_ArenaStrdup(dynOidPool, src->desc);
+    if (!dst->desc) {
+	goto done;
+    }
+    dst->offset             = (SECOidTag)(used + SEC_OID_TOTAL);
+    dst->mechanism          = src->mechanism;
+    dst->supportedExtension = src->supportedExtension;
+
+    rv = secoid_HashDynamicOiddata(dst);
+    if (rv == SECSuccess) {
+	table[used++] = (dynXOid *)dst;
+	dynOidEntriesUsed = used;
+	ret = dst->offset;
+    }
+done:
+    NSSRWLock_UnlockWrite(dynOidLock);
+    return ret;
+}
+
+
+/* normal static table processing */
+static PLHashTable *oidhash     = NULL;
+static PLHashTable *oidmechhash = NULL;
+
+static PLHashNumber
+secoid_HashNumber(const void *key)
+{
+    return (PLHashNumber) key;
+}
+
+static void
+handleHashAlgSupport(char * envVal)
+{
+    char * myVal = PORT_Strdup(envVal);  /* Get a copy we can alter */
+    char * arg   = myVal;
+
+    while (arg && *arg) {
+	char *   nextArg = PL_strpbrk(arg, ";");
+	PRUint32 notEnable;
+
+	if (nextArg) {
+	    while (*nextArg == ';') {
+		*nextArg++ = '\0';
+	    }
+	}
+	notEnable = (*arg == '-') ? NSS_USE_ALG_IN_CERT_SIGNATURE : 0;
+	if ((*arg == '+' || *arg == '-') && *++arg) { 
+	    int i;
+
+	    for (i = 1; i < SEC_OID_TOTAL; i++) {
+	        if (oids[i].desc && strstr(arg, oids[i].desc)) {
+		     xOids[i].notPolicyFlags = notEnable |
+		    (xOids[i].notPolicyFlags & ~NSS_USE_ALG_IN_CERT_SIGNATURE);
+		}
+	    }
+	}
+	arg = nextArg;
+    }
+    PORT_Free(myVal);  /* can handle NULL argument OK */
+}
+
+SECStatus
+SECOID_Init(void)
+{
+    PLHashEntry *entry;
+    const SECOidData *oid;
+    int i;
+    char * envVal;
+
+    if (oidhash) {
+	return SECSuccess; /* already initialized */
+    }
+
+    if (!PR_GetEnv("NSS_ALLOW_WEAK_SIGNATURE_ALG")) {
+	/* initialize any policy flags that are disabled by default */
+	xOids[SEC_OID_MD2                           ].notPolicyFlags = ~0;
+	xOids[SEC_OID_MD4                           ].notPolicyFlags = ~0;
+	xOids[SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION ].notPolicyFlags = ~0;
+	xOids[SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION ].notPolicyFlags = ~0;
+	xOids[SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC].notPolicyFlags = ~0;
+    }
+
+    envVal = PR_GetEnv("NSS_HASH_ALG_SUPPORT");
+    if (envVal)
+    	handleHashAlgSupport(envVal);
+
+    if (secoid_InitDynOidData() != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        PORT_Assert(0); /* this function should never fail */
+    	return SECFailure;
+    }
+    
+    oidhash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+			PL_CompareValues, NULL, NULL);
+    oidmechhash = PL_NewHashTable(0, secoid_HashNumber, PL_CompareValues,
+			PL_CompareValues, NULL, NULL);
+
+    if ( !oidhash || !oidmechhash) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ 	PORT_Assert(0); /*This function should never fail. */
+	return(SECFailure);
+    }
+
+    for ( i = 0; i < SEC_OID_TOTAL; i++ ) {
+	oid = &oids[i];
+
+	PORT_Assert ( oid->offset == i );
+
+	entry = PL_HashTableAdd( oidhash, &oid->oid, (void *)oid );
+	if ( entry == NULL ) {
+	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            PORT_Assert(0); /*This function should never fail. */
+	    return(SECFailure);
+	}
+
+	if ( oid->mechanism != CKM_INVALID_MECHANISM ) {
+	    entry = PL_HashTableAdd( oidmechhash, 
+					(void *)oid->mechanism, (void *)oid );
+	    if ( entry == NULL ) {
+	        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+                PORT_Assert(0); /* This function should never fail. */
+		return(SECFailure);
+	    }
+	}
+    }
+
+    PORT_Assert (i == SEC_OID_TOTAL);
+
+    return(SECSuccess);
+}
+
+SECOidData *
+SECOID_FindOIDByMechanism(unsigned long mechanism)
+{
+    SECOidData *ret;
+
+    PR_ASSERT(oidhash != NULL);
+
+    ret = PL_HashTableLookupConst ( oidmechhash, (void *)mechanism);
+    if ( ret == NULL ) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+    }
+
+    return (ret);
+}
+
+SECOidData *
+SECOID_FindOID(const SECItem *oid)
+{
+    SECOidData *ret;
+
+    PR_ASSERT(oidhash != NULL);
+    
+    ret = PL_HashTableLookupConst ( oidhash, oid );
+    if ( ret == NULL ) {
+	ret  = secoid_FindDynamic(oid);
+	if (ret == NULL) {
+	    PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+	}
+    }
+
+    return(ret);
+}
+
+SECOidTag
+SECOID_FindOIDTag(const SECItem *oid)
+{
+    SECOidData *oiddata;
+
+    oiddata = SECOID_FindOID (oid);
+    if (oiddata == NULL)
+	return SEC_OID_UNKNOWN;
+
+    return oiddata->offset;
+}
+
+/* This really should return const. */
+SECOidData *
+SECOID_FindOIDByTag(SECOidTag tagnum)
+{
+    if (tagnum >= SEC_OID_TOTAL) {
+	return (SECOidData *)secoid_FindDynamicByTag(tagnum);
+    }
+
+    PORT_Assert((unsigned int)tagnum < SEC_OID_TOTAL);
+    return (SECOidData *)(&oids[tagnum]);
+}
+
+PRBool SECOID_KnownCertExtenOID (SECItem *extenOid)
+{
+    SECOidData * oidData;
+
+    oidData = SECOID_FindOID (extenOid);
+    if (oidData == (SECOidData *)NULL)
+	return (PR_FALSE);
+    return ((oidData->supportedExtension == SUPPORTED_CERT_EXTENSION) ?
+            PR_TRUE : PR_FALSE);
+}
+
+
+const char *
+SECOID_FindOIDTagDescription(SECOidTag tagnum)
+{
+  const SECOidData *oidData = SECOID_FindOIDByTag(tagnum);
+  return oidData ? oidData->desc : 0;
+}
+
+/* --------- opaque extended OID table accessor functions ---------------*/
+/*
+ * Any of these functions may return SECSuccess or SECFailure with the error 
+ * code set to SEC_ERROR_UNKNOWN_OBJECT_TYPE if the SECOidTag is out of range.
+ */
+
+static privXOid *
+secoid_FindXOidByTag(SECOidTag tagnum)
+{
+    if (tagnum >= SEC_OID_TOTAL) {
+	dynXOid *dxo = secoid_FindDynamicByTag(tagnum);
+	return (dxo ? &dxo->priv : NULL);
+    }
+
+    PORT_Assert((unsigned int)tagnum < SEC_OID_TOTAL);
+    return &xOids[tagnum];
+}
+
+/* The Get function outputs the 32-bit value associated with the SECOidTag.
+ * Flags bits are the NSS_USE_ALG_ #defines in "secoidt.h".
+ * Default value for any algorithm is 0xffffffff (enabled for all purposes).
+ * No value is output if function returns SECFailure.
+ */
+SECStatus 
+NSS_GetAlgorithmPolicy(SECOidTag tag, PRUint32 *pValue)
+{
+    privXOid * pxo = secoid_FindXOidByTag(tag);
+    if (!pxo)
+    	return SECFailure;
+    if (!pValue) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    *pValue = ~(pxo->notPolicyFlags);
+    return SECSuccess;
+}
+
+/* The Set function modifies the stored value according to the following
+ * algorithm:
+ *   policy[tag] = (policy[tag] & ~clearBits) | setBits;
+ */
+SECStatus
+NSS_SetAlgorithmPolicy(SECOidTag tag, PRUint32 setBits, PRUint32 clearBits)
+{
+    privXOid * pxo = secoid_FindXOidByTag(tag);
+    PRUint32   policyFlags;
+    if (!pxo)
+    	return SECFailure;
+    /* The stored policy flags are the ones complement of the flags as 
+     * seen by the user.  This is not atomic, but these changes should 
+     * be done rarely, e.g. at initialization time. 
+     */
+    policyFlags = ~(pxo->notPolicyFlags);
+    policyFlags = (policyFlags & ~clearBits) | setBits;
+    pxo->notPolicyFlags = ~policyFlags;
+    return SECSuccess;
+}
+
+/* --------- END OF opaque extended OID table accessor functions ---------*/
+
+/* for now, this is only used in a single place, so it can remain static */
+static PRBool parentForkedAfterC_Initialize;
+
+#define SKIP_AFTER_FORK(x) if (!parentForkedAfterC_Initialize) x
+
+/*
+ * free up the oid tables.
+ */
+SECStatus
+SECOID_Shutdown(void)
+{
+    if (oidhash) {
+	PL_HashTableDestroy(oidhash);
+	oidhash = NULL;
+    }
+    if (oidmechhash) {
+	PL_HashTableDestroy(oidmechhash);
+	oidmechhash = NULL;
+    }
+    /* Have to handle the case where the lock was created, but
+    ** the pool wasn't. 
+    ** I'm not going to attempt to create the lock, just to protect
+    ** the destruction of data that probably isn't initialized anyway.
+    */
+    if (dynOidLock) {
+	SKIP_AFTER_FORK(NSSRWLock_LockWrite(dynOidLock));
+	if (dynOidHash) {
+	    PL_HashTableDestroy(dynOidHash);
+	    dynOidHash = NULL;
+	}
+	if (dynOidPool) {
+	    PORT_FreeArena(dynOidPool, PR_FALSE);
+	    dynOidPool = NULL;
+	}
+	if (dynOidTable) {
+	    PORT_Free(dynOidTable);
+	    dynOidTable = NULL;
+	}
+	dynOidEntriesAllocated = 0;
+	dynOidEntriesUsed = 0;
+
+	SKIP_AFTER_FORK(NSSRWLock_UnlockWrite(dynOidLock));
+	SKIP_AFTER_FORK(NSSRWLock_Destroy(dynOidLock));
+	dynOidLock = NULL;
+    } else {
+    	/* Since dynOidLock doesn't exist, then all the data it protects
+	** should be uninitialized.  We'll check that (in DEBUG builds),
+	** and then make sure it is so, in case NSS is reinitialized.
+	*/
+	PORT_Assert(!dynOidHash && !dynOidPool && !dynOidTable && \
+	            !dynOidEntriesAllocated && !dynOidEntriesUsed);
+	dynOidHash = NULL;
+	dynOidPool = NULL;
+	dynOidTable = NULL;
+	dynOidEntriesAllocated = 0;
+	dynOidEntriesUsed = 0;
+    }
+    memset(xOids, 0, sizeof xOids);
+    return SECSuccess;
+}
+
+void UTIL_SetForkState(PRBool forked)
+{
+    parentForkedAfterC_Initialize = forked;
+}
+
+
diff --git a/mozilla/security/nss/lib/util/secoid.h b/mozilla/security/nss/lib/util/secoid.h
new file mode 100644
index 0000000..089e957
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secoid.h
@@ -0,0 +1,175 @@
+/* ***** 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 ***** */
+
+#ifndef _SECOID_H_
+#define _SECOID_H_
+
+#include "utilrename.h"
+
+/*
+ * secoid.h - public data structures and prototypes for ASN.1 OID functions
+ *
+ * $Id: secoid.h,v 1.14 2009/11/11 23:24:33 alexei.volkov.bugs%sun.com Exp $
+ */
+
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secasn1t.h"
+
+SEC_BEGIN_PROTOS
+
+extern const SEC_ASN1Template SECOID_AlgorithmIDTemplate[];
+
+/* This functions simply returns the address of the above-declared template. */
+SEC_ASN1_CHOOSER_DECLARE(SECOID_AlgorithmIDTemplate)
+
+/*
+ * OID handling routines
+ */
+extern SECOidData *SECOID_FindOID( const SECItem *oid);
+extern SECOidTag SECOID_FindOIDTag(const SECItem *oid);
+extern SECOidData *SECOID_FindOIDByTag(SECOidTag tagnum);
+extern SECOidData *SECOID_FindOIDByMechanism(unsigned long mechanism);
+
+/****************************************/
+/*
+** Algorithm id handling operations
+*/
+
+/*
+** Fill in an algorithm-ID object given a tag and some parameters.
+** 	"aid" where the DER encoded algorithm info is stored (memory
+**	   is allocated)
+**	"tag" the tag number defining the algorithm 
+**	"params" if not NULL, the parameters to go with the algorithm
+*/
+extern SECStatus SECOID_SetAlgorithmID(PLArenaPool *arena, SECAlgorithmID *aid,
+				   SECOidTag tag, SECItem *params);
+
+/*
+** 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 SECOID_DestroyAlgorithmID(dest, PR_FALSE)
+** to do that).
+*/
+extern SECStatus SECOID_CopyAlgorithmID(PLArenaPool *arena, SECAlgorithmID *dest,
+				    SECAlgorithmID *src);
+
+/*
+** Get the tag number for the given algorithm-id object.
+*/
+extern SECOidTag SECOID_GetAlgorithmTag(SECAlgorithmID *aid);
+
+/*
+** Destroy an algorithm-id object.
+**	"aid" the certificate-request to destroy
+**	"freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void SECOID_DestroyAlgorithmID(SECAlgorithmID *aid, PRBool freeit);
+
+/*
+** Compare two algorithm-id objects, returning the difference between
+** them.
+*/
+extern SECComparison SECOID_CompareAlgorithmID(SECAlgorithmID *a,
+					   SECAlgorithmID *b);
+
+extern PRBool SECOID_KnownCertExtenOID (SECItem *extenOid);
+
+/* Given a tag number, return a string describing it.
+ */
+extern const char *SECOID_FindOIDTagDescription(SECOidTag tagnum);
+
+/* Add a dynamic SECOidData to the dynamic OID table.
+** Routine copies the src entry, and returns the new SECOidTag.
+** Returns SEC_OID_INVALID if failed to add for some reason.
+*/
+extern SECOidTag SECOID_AddEntry(const SECOidData * src);
+
+/*
+ * initialize the oid data structures.
+ */
+extern SECStatus SECOID_Init(void);
+
+/*
+ * free up the oid data structures.
+ */
+extern SECStatus SECOID_Shutdown(void);
+
+/* if to->data is not NULL, and to->len is large enough to hold the result,
+ * then the resultant OID will be copyed into to->data, and to->len will be
+ * changed to show the actual OID length.
+ * Otherwise, memory for the OID will be allocated (from the caller's 
+ * PLArenaPool, if pool is non-NULL) and to->data will receive the address
+ * of the allocated data, and to->len will receive the OID length.
+ * The original value of to->data is not freed when a new buffer is allocated.
+ * 
+ * The input string may begin with "OID." and this still be ignored.
+ * The length of the input string is given in len.  If len == 0, then 
+ * len will be computed as strlen(from), meaning it must be NUL terminated.
+ * It is an error if from == NULL, or if *from == '\0'.
+ */
+extern SECStatus SEC_StringToOID(PLArenaPool *pool, SECItem *to, 
+                                 const char *from, PRUint32 len);
+
+extern void UTIL_SetForkState(PRBool forked);
+
+/*
+ * Accessor functions for new opaque extended SECOID table.
+ * Any of these functions may return SECSuccess or SECFailure with the error 
+ * code set to SEC_ERROR_UNKNOWN_OBJECT_TYPE if the SECOidTag is out of range.
+ */
+
+/* The Get function outputs the 32-bit value associated with the SECOidTag.
+ * Flags bits are the NSS_USE_ALG_ #defines in "secoidt.h".
+ * Default value for any algorithm is 0xffffffff (enabled for all purposes).
+ * No value is output if function returns SECFailure.
+ */
+extern SECStatus NSS_GetAlgorithmPolicy(SECOidTag tag, PRUint32 *pValue);
+
+/* The Set function modifies the stored value according to the following
+ * algorithm:
+ *   policy[tag] = (policy[tag] & ~clearBits) | setBits;
+ */
+extern SECStatus
+NSS_SetAlgorithmPolicy(SECOidTag tag, PRUint32 setBits, PRUint32 clearBits);
+
+
+SEC_END_PROTOS
+
+#endif /* _SECOID_H_ */
diff --git a/mozilla/security/nss/lib/util/secoidt.h b/mozilla/security/nss/lib/util/secoidt.h
new file mode 100644
index 0000000..2858218
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secoidt.h
@@ -0,0 +1,494 @@
+/* ***** 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):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+
+#ifndef _SECOIDT_H_
+#define _SECOIDT_H_
+
+#include "utilrename.h"
+
+/*
+ * secoidt.h - public data structures for ASN.1 OID functions
+ *
+ * $Id: secoidt.h,v 1.30 2009/04/14 02:04:08 alexei.volkov.bugs%sun.com Exp $
+ */
+
+#include "secitem.h"
+
+typedef struct SECOidDataStr SECOidData;
+typedef struct SECAlgorithmIDStr SECAlgorithmID;
+
+/*
+** An X.500 algorithm identifier
+*/
+struct SECAlgorithmIDStr {
+    SECItem algorithm;
+    SECItem parameters;
+};
+
+/*
+ * Misc object IDs - these numbers are for convenient handling.
+ * They are mapped into real object IDs
+ *
+ * NOTE: the order of these entries must mach the array "oids" of SECOidData
+ * in util/secoid.c.
+ */
+typedef enum {
+    SEC_OID_UNKNOWN = 0,
+    SEC_OID_MD2 = 1,
+    SEC_OID_MD4 = 2,
+    SEC_OID_MD5 = 3,
+    SEC_OID_SHA1 = 4,
+    SEC_OID_RC2_CBC = 5,
+    SEC_OID_RC4 = 6,
+    SEC_OID_DES_EDE3_CBC = 7,
+    SEC_OID_RC5_CBC_PAD = 8,
+    SEC_OID_DES_ECB = 9,
+    SEC_OID_DES_CBC = 10,
+    SEC_OID_DES_OFB = 11,
+    SEC_OID_DES_CFB = 12,
+    SEC_OID_DES_MAC = 13,
+    SEC_OID_DES_EDE = 14,
+    SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE = 15,
+    SEC_OID_PKCS1_RSA_ENCRYPTION = 16,
+    SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION = 17,
+    SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION = 18,
+    SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION = 19,
+    SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION = 20,
+    SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC = 21,
+    SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC = 22,
+    SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC = 23,
+    SEC_OID_PKCS7 = 24,
+    SEC_OID_PKCS7_DATA = 25,
+    SEC_OID_PKCS7_SIGNED_DATA = 26,
+    SEC_OID_PKCS7_ENVELOPED_DATA = 27,
+    SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA = 28,
+    SEC_OID_PKCS7_DIGESTED_DATA = 29,
+    SEC_OID_PKCS7_ENCRYPTED_DATA = 30,
+    SEC_OID_PKCS9_EMAIL_ADDRESS = 31,
+    SEC_OID_PKCS9_UNSTRUCTURED_NAME = 32,
+    SEC_OID_PKCS9_CONTENT_TYPE = 33,
+    SEC_OID_PKCS9_MESSAGE_DIGEST = 34,
+    SEC_OID_PKCS9_SIGNING_TIME = 35,
+    SEC_OID_PKCS9_COUNTER_SIGNATURE = 36,
+    SEC_OID_PKCS9_CHALLENGE_PASSWORD = 37,
+    SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS = 38,
+    SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES = 39,
+    SEC_OID_PKCS9_SMIME_CAPABILITIES = 40,
+    SEC_OID_AVA_COMMON_NAME = 41,
+    SEC_OID_AVA_COUNTRY_NAME = 42,
+    SEC_OID_AVA_LOCALITY = 43,
+    SEC_OID_AVA_STATE_OR_PROVINCE = 44,
+    SEC_OID_AVA_ORGANIZATION_NAME = 45,
+    SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME = 46,
+    SEC_OID_AVA_DN_QUALIFIER = 47,
+    SEC_OID_AVA_DC = 48,
+
+    SEC_OID_NS_TYPE_GIF = 49,
+    SEC_OID_NS_TYPE_JPEG = 50,
+    SEC_OID_NS_TYPE_URL = 51,
+    SEC_OID_NS_TYPE_HTML = 52,
+    SEC_OID_NS_TYPE_CERT_SEQUENCE = 53,
+    SEC_OID_MISSI_KEA_DSS_OLD = 54,
+    SEC_OID_MISSI_DSS_OLD = 55,
+    SEC_OID_MISSI_KEA_DSS = 56,
+    SEC_OID_MISSI_DSS = 57,
+    SEC_OID_MISSI_KEA = 58,
+    SEC_OID_MISSI_ALT_KEA = 59,
+
+    /* Netscape private certificate extensions */
+    SEC_OID_NS_CERT_EXT_NETSCAPE_OK = 60,
+    SEC_OID_NS_CERT_EXT_ISSUER_LOGO = 61,
+    SEC_OID_NS_CERT_EXT_SUBJECT_LOGO = 62,
+    SEC_OID_NS_CERT_EXT_CERT_TYPE = 63,
+    SEC_OID_NS_CERT_EXT_BASE_URL = 64,
+    SEC_OID_NS_CERT_EXT_REVOCATION_URL = 65,
+    SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL = 66,
+    SEC_OID_NS_CERT_EXT_CA_CRL_URL = 67,
+    SEC_OID_NS_CERT_EXT_CA_CERT_URL = 68,
+    SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL = 69,
+    SEC_OID_NS_CERT_EXT_CA_POLICY_URL = 70,
+    SEC_OID_NS_CERT_EXT_HOMEPAGE_URL = 71,
+    SEC_OID_NS_CERT_EXT_ENTITY_LOGO = 72,
+    SEC_OID_NS_CERT_EXT_USER_PICTURE = 73,
+    SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME = 74,
+    SEC_OID_NS_CERT_EXT_COMMENT = 75,
+    SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL = 76,
+    SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME = 77,
+    SEC_OID_NS_KEY_USAGE_GOVT_APPROVED = 78,
+
+    /* x.509 v3 Extensions */
+    SEC_OID_X509_SUBJECT_DIRECTORY_ATTR = 79,
+    SEC_OID_X509_SUBJECT_KEY_ID = 80,
+    SEC_OID_X509_KEY_USAGE = 81,
+    SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD = 82,
+    SEC_OID_X509_SUBJECT_ALT_NAME = 83,
+    SEC_OID_X509_ISSUER_ALT_NAME = 84,
+    SEC_OID_X509_BASIC_CONSTRAINTS = 85,
+    SEC_OID_X509_NAME_CONSTRAINTS = 86,
+    SEC_OID_X509_CRL_DIST_POINTS = 87,
+    SEC_OID_X509_CERTIFICATE_POLICIES = 88,
+    SEC_OID_X509_POLICY_MAPPINGS = 89,
+    SEC_OID_X509_POLICY_CONSTRAINTS = 90,
+    SEC_OID_X509_AUTH_KEY_ID = 91,
+    SEC_OID_X509_EXT_KEY_USAGE = 92,
+    SEC_OID_X509_AUTH_INFO_ACCESS = 93,
+
+    SEC_OID_X509_CRL_NUMBER = 94,
+    SEC_OID_X509_REASON_CODE = 95,
+    SEC_OID_X509_INVALID_DATE = 96,
+    /* End of x.509 v3 Extensions */    
+
+    SEC_OID_X500_RSA_ENCRYPTION = 97,
+
+    /* alg 1485 additions */
+    SEC_OID_RFC1274_UID = 98,
+    SEC_OID_RFC1274_MAIL = 99,
+
+    /* PKCS 12 additions */
+    SEC_OID_PKCS12 = 100,
+    SEC_OID_PKCS12_MODE_IDS = 101,
+    SEC_OID_PKCS12_ESPVK_IDS = 102,
+    SEC_OID_PKCS12_BAG_IDS = 103,
+    SEC_OID_PKCS12_CERT_BAG_IDS = 104,
+    SEC_OID_PKCS12_OIDS = 105,
+    SEC_OID_PKCS12_PBE_IDS = 106,
+    SEC_OID_PKCS12_SIGNATURE_IDS = 107,
+    SEC_OID_PKCS12_ENVELOPING_IDS = 108,
+   /* SEC_OID_PKCS12_OFFLINE_TRANSPORT_MODE,
+    SEC_OID_PKCS12_ONLINE_TRANSPORT_MODE, */
+    SEC_OID_PKCS12_PKCS8_KEY_SHROUDING = 109,
+    SEC_OID_PKCS12_KEY_BAG_ID = 110,
+    SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID = 111,
+    SEC_OID_PKCS12_SECRET_BAG_ID = 112,
+    SEC_OID_PKCS12_X509_CERT_CRL_BAG = 113,
+    SEC_OID_PKCS12_SDSI_CERT_BAG = 114,
+    SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4 = 115,
+    SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4 = 116,
+    SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC = 117,
+    SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 118,
+    SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 119,
+    SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4 = 120,
+    SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4 = 121,
+    SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES = 122,
+    SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST = 123,
+    /* end of PKCS 12 additions */
+
+    /* DSA signatures */
+    SEC_OID_ANSIX9_DSA_SIGNATURE = 124,
+    SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST = 125,
+    SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST = 126,
+
+    /* Verisign OIDs */
+    SEC_OID_VERISIGN_USER_NOTICES = 127,
+
+    /* PKIX OIDs */
+    SEC_OID_PKIX_CPS_POINTER_QUALIFIER = 128,
+    SEC_OID_PKIX_USER_NOTICE_QUALIFIER = 129,
+    SEC_OID_PKIX_OCSP = 130,
+    SEC_OID_PKIX_OCSP_BASIC_RESPONSE = 131,
+    SEC_OID_PKIX_OCSP_NONCE = 132,
+    SEC_OID_PKIX_OCSP_CRL = 133,
+    SEC_OID_PKIX_OCSP_RESPONSE = 134,
+    SEC_OID_PKIX_OCSP_NO_CHECK = 135,
+    SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF = 136,
+    SEC_OID_PKIX_OCSP_SERVICE_LOCATOR = 137,
+    SEC_OID_PKIX_REGCTRL_REGTOKEN = 138,
+    SEC_OID_PKIX_REGCTRL_AUTHENTICATOR = 139,
+    SEC_OID_PKIX_REGCTRL_PKIPUBINFO = 140,
+    SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS = 141,
+    SEC_OID_PKIX_REGCTRL_OLD_CERT_ID = 142,
+    SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY = 143,
+    SEC_OID_PKIX_REGINFO_UTF8_PAIRS = 144,
+    SEC_OID_PKIX_REGINFO_CERT_REQUEST = 145,
+    SEC_OID_EXT_KEY_USAGE_SERVER_AUTH = 146,
+    SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH = 147,
+    SEC_OID_EXT_KEY_USAGE_CODE_SIGN = 148,
+    SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT = 149,
+    SEC_OID_EXT_KEY_USAGE_TIME_STAMP = 150,
+    SEC_OID_OCSP_RESPONDER = 151,
+
+    /* Netscape Algorithm OIDs */
+    SEC_OID_NETSCAPE_SMIME_KEA = 152,
+
+    /* Skipjack OID -- ### mwelch temporary */
+    SEC_OID_FORTEZZA_SKIPJACK = 153,
+
+    /* PKCS 12 V2 oids */
+    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4 = 154,
+    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4 = 155,
+    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC = 156,
+    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC = 157,
+    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 158,
+    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 159,
+    SEC_OID_PKCS12_SAFE_CONTENTS_ID = 160,
+    SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID = 161,
+
+    SEC_OID_PKCS12_V1_KEY_BAG_ID = 162,
+    SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID = 163,
+    SEC_OID_PKCS12_V1_CERT_BAG_ID = 164,
+    SEC_OID_PKCS12_V1_CRL_BAG_ID = 165,
+    SEC_OID_PKCS12_V1_SECRET_BAG_ID = 166,
+    SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID = 167,
+    SEC_OID_PKCS9_X509_CERT = 168,
+    SEC_OID_PKCS9_SDSI_CERT = 169,
+    SEC_OID_PKCS9_X509_CRL = 170,
+    SEC_OID_PKCS9_FRIENDLY_NAME = 171,
+    SEC_OID_PKCS9_LOCAL_KEY_ID = 172,
+    SEC_OID_BOGUS_KEY_USAGE = 173,
+
+    /*Diffe Helman OIDS */
+    SEC_OID_X942_DIFFIE_HELMAN_KEY = 174,
+
+    /* Netscape other name types */
+    SEC_OID_NETSCAPE_NICKNAME = 175,
+
+    /* Cert Server OIDS */
+    SEC_OID_NETSCAPE_RECOVERY_REQUEST = 176,
+
+    /* New PSM certificate management OIDs */
+    SEC_OID_CERT_RENEWAL_LOCATOR = 177,
+    SEC_OID_NS_CERT_EXT_SCOPE_OF_USE = 178,
+    
+    /* CMS (RFC2630) OIDs */
+    SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN = 179,
+    SEC_OID_CMS_3DES_KEY_WRAP = 180,
+    SEC_OID_CMS_RC2_KEY_WRAP = 181,
+
+    /* SMIME attributes */
+    SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE = 182,
+
+    /* AES OIDs */
+    SEC_OID_AES_128_ECB 	= 183,
+    SEC_OID_AES_128_CBC 	= 184,
+    SEC_OID_AES_192_ECB 	= 185,
+    SEC_OID_AES_192_CBC 	= 186,
+    SEC_OID_AES_256_ECB 	= 187,
+    SEC_OID_AES_256_CBC 	= 188,
+
+    SEC_OID_SDN702_DSA_SIGNATURE = 189,
+
+    SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE = 190,
+
+    SEC_OID_SHA256              = 191,
+    SEC_OID_SHA384              = 192,
+    SEC_OID_SHA512              = 193,
+
+    SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION = 194,
+    SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION = 195,
+    SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION = 196,
+
+    SEC_OID_AES_128_KEY_WRAP	= 197,
+    SEC_OID_AES_192_KEY_WRAP	= 198,
+    SEC_OID_AES_256_KEY_WRAP	= 199,
+
+    /* Elliptic Curve Cryptography (ECC) OIDs */
+    SEC_OID_ANSIX962_EC_PUBLIC_KEY  = 200,
+    SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE = 201,
+
+#define SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST \
+	SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE
+
+    /* ANSI X9.62 named elliptic curves (prime field) */
+    SEC_OID_ANSIX962_EC_PRIME192V1  = 202,
+    SEC_OID_ANSIX962_EC_PRIME192V2  = 203,
+    SEC_OID_ANSIX962_EC_PRIME192V3  = 204,
+    SEC_OID_ANSIX962_EC_PRIME239V1  = 205,
+    SEC_OID_ANSIX962_EC_PRIME239V2  = 206,
+    SEC_OID_ANSIX962_EC_PRIME239V3  = 207,
+    SEC_OID_ANSIX962_EC_PRIME256V1  = 208,
+
+    /* SECG named elliptic curves (prime field) */
+    SEC_OID_SECG_EC_SECP112R1       = 209,
+    SEC_OID_SECG_EC_SECP112R2       = 210,
+    SEC_OID_SECG_EC_SECP128R1       = 211,
+    SEC_OID_SECG_EC_SECP128R2       = 212,
+    SEC_OID_SECG_EC_SECP160K1       = 213,
+    SEC_OID_SECG_EC_SECP160R1       = 214, 
+    SEC_OID_SECG_EC_SECP160R2       = 215,
+    SEC_OID_SECG_EC_SECP192K1       = 216,
+    /* SEC_OID_SECG_EC_SECP192R1 is SEC_OID_ANSIX962_EC_PRIME192V1 */
+    SEC_OID_SECG_EC_SECP224K1       = 217,
+    SEC_OID_SECG_EC_SECP224R1       = 218,
+    SEC_OID_SECG_EC_SECP256K1       = 219,
+    /* SEC_OID_SECG_EC_SECP256R1 is SEC_OID_ANSIX962_EC_PRIME256V1 */
+    SEC_OID_SECG_EC_SECP384R1       = 220,
+    SEC_OID_SECG_EC_SECP521R1       = 221,
+
+    /* ANSI X9.62 named elliptic curves (characteristic two field) */
+    SEC_OID_ANSIX962_EC_C2PNB163V1  = 222,
+    SEC_OID_ANSIX962_EC_C2PNB163V2  = 223,
+    SEC_OID_ANSIX962_EC_C2PNB163V3  = 224,
+    SEC_OID_ANSIX962_EC_C2PNB176V1  = 225,
+    SEC_OID_ANSIX962_EC_C2TNB191V1  = 226,
+    SEC_OID_ANSIX962_EC_C2TNB191V2  = 227,
+    SEC_OID_ANSIX962_EC_C2TNB191V3  = 228,
+    SEC_OID_ANSIX962_EC_C2ONB191V4  = 229,
+    SEC_OID_ANSIX962_EC_C2ONB191V5  = 230,
+    SEC_OID_ANSIX962_EC_C2PNB208W1  = 231,
+    SEC_OID_ANSIX962_EC_C2TNB239V1  = 232,
+    SEC_OID_ANSIX962_EC_C2TNB239V2  = 233,
+    SEC_OID_ANSIX962_EC_C2TNB239V3  = 234,
+    SEC_OID_ANSIX962_EC_C2ONB239V4  = 235,
+    SEC_OID_ANSIX962_EC_C2ONB239V5  = 236,
+    SEC_OID_ANSIX962_EC_C2PNB272W1  = 237,
+    SEC_OID_ANSIX962_EC_C2PNB304W1  = 238,
+    SEC_OID_ANSIX962_EC_C2TNB359V1  = 239,
+    SEC_OID_ANSIX962_EC_C2PNB368W1  = 240,
+    SEC_OID_ANSIX962_EC_C2TNB431R1  = 241,
+
+    /* SECG named elliptic curves (characteristic two field) */
+    SEC_OID_SECG_EC_SECT113R1       = 242,
+    SEC_OID_SECG_EC_SECT113R2       = 243,
+    SEC_OID_SECG_EC_SECT131R1       = 244,
+    SEC_OID_SECG_EC_SECT131R2       = 245,
+    SEC_OID_SECG_EC_SECT163K1       = 246,
+    SEC_OID_SECG_EC_SECT163R1       = 247,
+    SEC_OID_SECG_EC_SECT163R2       = 248,
+    SEC_OID_SECG_EC_SECT193R1       = 249,
+    SEC_OID_SECG_EC_SECT193R2       = 250,
+    SEC_OID_SECG_EC_SECT233K1       = 251,
+    SEC_OID_SECG_EC_SECT233R1       = 252,
+    SEC_OID_SECG_EC_SECT239K1       = 253,
+    SEC_OID_SECG_EC_SECT283K1       = 254,
+    SEC_OID_SECG_EC_SECT283R1       = 255,
+    SEC_OID_SECG_EC_SECT409K1       = 256,
+    SEC_OID_SECG_EC_SECT409R1       = 257,
+    SEC_OID_SECG_EC_SECT571K1       = 258,
+    SEC_OID_SECG_EC_SECT571R1       = 259,
+
+    SEC_OID_NETSCAPE_AOLSCREENNAME  = 260,
+
+    SEC_OID_AVA_SURNAME              = 261,
+    SEC_OID_AVA_SERIAL_NUMBER        = 262,
+    SEC_OID_AVA_STREET_ADDRESS       = 263,
+    SEC_OID_AVA_TITLE                = 264,
+    SEC_OID_AVA_POSTAL_ADDRESS       = 265,
+    SEC_OID_AVA_POSTAL_CODE          = 266,
+    SEC_OID_AVA_POST_OFFICE_BOX      = 267,
+    SEC_OID_AVA_GIVEN_NAME           = 268,
+    SEC_OID_AVA_INITIALS             = 269,
+    SEC_OID_AVA_GENERATION_QUALIFIER = 270,
+    SEC_OID_AVA_HOUSE_IDENTIFIER     = 271,
+    SEC_OID_AVA_PSEUDONYM            = 272,
+
+    /* More OIDs */
+    SEC_OID_PKIX_CA_ISSUERS          = 273,
+    SEC_OID_PKCS9_EXTENSION_REQUEST  = 274,
+
+    /* new EC Signature oids */
+    SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST = 275,
+    SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST = 276,
+    SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE = 277,
+    SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE = 278,
+    SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE = 279,
+    SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE = 280,
+
+    /* More id-ce and id-pe OIDs from RFC 3280 */
+    SEC_OID_X509_HOLD_INSTRUCTION_CODE      = 281,
+    SEC_OID_X509_DELTA_CRL_INDICATOR        = 282,
+    SEC_OID_X509_ISSUING_DISTRIBUTION_POINT = 283,
+    SEC_OID_X509_CERT_ISSUER                = 284,
+    SEC_OID_X509_FRESHEST_CRL               = 285,
+    SEC_OID_X509_INHIBIT_ANY_POLICY         = 286,
+    SEC_OID_X509_SUBJECT_INFO_ACCESS        = 287,
+
+    /* Camellia OIDs (RFC3657)*/
+    SEC_OID_CAMELLIA_128_CBC                = 288,
+    SEC_OID_CAMELLIA_192_CBC                = 289,
+    SEC_OID_CAMELLIA_256_CBC                = 290,
+
+    /* PKCS 5 V2 OIDS */
+    SEC_OID_PKCS5_PBKDF2                    = 291,
+    SEC_OID_PKCS5_PBES2                     = 292,
+    SEC_OID_PKCS5_PBMAC1                    = 293,
+    SEC_OID_HMAC_SHA1                       = 294,
+    SEC_OID_HMAC_SHA224                     = 295,
+    SEC_OID_HMAC_SHA256                     = 296,
+    SEC_OID_HMAC_SHA384                     = 297,
+    SEC_OID_HMAC_SHA512                     = 298,
+
+    SEC_OID_PKIX_TIMESTAMPING               = 299,
+    SEC_OID_PKIX_CA_REPOSITORY              = 300,
+
+    SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE     = 301,
+
+    SEC_OID_SEED_CBC			    = 302,
+
+    SEC_OID_X509_ANY_POLICY                 = 303,
+
+    SEC_OID_TOTAL
+} SECOidTag;
+
+#define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1
+#define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1
+#define SEC_OID_PKCS12_KEY_USAGE  SEC_OID_X509_KEY_USAGE
+
+/* fake OID for DSS sign/verify */
+#define SEC_OID_SHA SEC_OID_MISS_DSS
+
+typedef enum {
+    INVALID_CERT_EXTENSION = 0,
+    UNSUPPORTED_CERT_EXTENSION = 1,
+    SUPPORTED_CERT_EXTENSION = 2
+} SECSupportExtenTag;
+
+struct SECOidDataStr {
+    SECItem            oid;
+    SECOidTag          offset;
+    const char *       desc;
+    unsigned long      mechanism;
+    SECSupportExtenTag supportedExtension;	
+    				/* only used for x.509 v3 extensions, so
+				   that we can print the names of those
+				   extensions that we don't even support */
+};
+
+/* New Opaque extended OID table API.  
+ * These are algorithm policy Flags, used with functions
+ * NSS_SetAlgorithmPolicy & NSS_GetAlgorithmPolicy.
+ */
+#define NSS_USE_ALG_IN_CERT_SIGNATURE  0x00000001  /* CRLs and OCSP, too */
+#define NSS_USE_ALG_IN_CMS_SIGNATURE   0x00000002  /* used in S/MIME */
+#define NSS_USE_ALG_RESERVED           0xfffffffc  /* may be used in future */
+
+/* Code MUST NOT SET or CLEAR reserved bits, and must NOT depend on them
+ * being all zeros or having any other known value.  The reserved bits
+ * must be ignored.
+ */
+
+
+#endif /* _SECOIDT_H_ */
diff --git a/mozilla/security/nss/lib/util/secport.c b/mozilla/security/nss/lib/util/secport.c
new file mode 100644
index 0000000..3d30c62
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secport.c
@@ -0,0 +1,721 @@
+/* ***** 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 ***** */
+
+/*
+ * secport.c - portability interfaces for security libraries
+ *
+ * This file abstracts out libc functionality that libsec depends on
+ * 
+ * NOTE - These are not public interfaces
+ *
+ * $Id: secport.c,v 1.26 2009/12/24 03:37:46 nelson%bolyard.com Exp $
+ */
+
+#include "seccomon.h"
+#include "prmem.h"
+#include "prerror.h"
+#include "plarena.h"
+#include "secerr.h"
+#include "prmon.h"
+#include "nssilock.h"
+#include "secport.h"
+#include "prenv.h"
+
+#ifdef DEBUG
+#define THREADMARK
+#endif /* DEBUG */
+
+#ifdef THREADMARK
+#include "prthread.h"
+#endif /* THREADMARK */
+
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+#include <stdlib.h>
+#else
+#include "wtypes.h"
+#endif
+
+#define SET_ERROR_CODE	/* place holder for code to set PR error code. */
+
+#ifdef THREADMARK
+typedef struct threadmark_mark_str {
+  struct threadmark_mark_str *next;
+  void *mark;
+} threadmark_mark;
+
+#endif /* THREADMARK */
+
+/* The value of this magic must change each time PORTArenaPool changes. */
+#define ARENAPOOL_MAGIC 0xB8AC9BDF 
+
+typedef struct PORTArenaPool_str {
+  PLArenaPool arena;
+  PRUint32    magic;
+  PRLock *    lock;
+#ifdef THREADMARK
+  PRThread *marking_thread;
+  threadmark_mark *first_mark;
+#endif
+} PORTArenaPool;
+
+
+/* count of allocation failures. */
+unsigned long port_allocFailures;
+
+/* locations for registering Unicode conversion functions.  
+ * XXX is this the appropriate location?  or should they be
+ *     moved to client/server specific locations?
+ */
+PORTCharConversionFunc ucs4Utf8ConvertFunc;
+PORTCharConversionFunc ucs2Utf8ConvertFunc;
+PORTCharConversionWSwapFunc  ucs2AsciiConvertFunc;
+
+void *
+PORT_Alloc(size_t bytes)
+{
+    void *rv;
+
+    /* Always allocate a non-zero amount of bytes */
+    rv = (void *)PR_Malloc(bytes ? bytes : 1);
+    if (!rv) {
+	++port_allocFailures;
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+    return rv;
+}
+
+void *
+PORT_Realloc(void *oldptr, size_t bytes)
+{
+    void *rv;
+
+    rv = (void *)PR_Realloc(oldptr, bytes);
+    if (!rv) {
+	++port_allocFailures;
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+    return rv;
+}
+
+void *
+PORT_ZAlloc(size_t bytes)
+{
+    void *rv;
+
+    /* Always allocate a non-zero amount of bytes */
+    rv = (void *)PR_Calloc(1, bytes ? bytes : 1);
+    if (!rv) {
+	++port_allocFailures;
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+    return rv;
+}
+
+void
+PORT_Free(void *ptr)
+{
+    if (ptr) {
+	PR_Free(ptr);
+    }
+}
+
+void
+PORT_ZFree(void *ptr, size_t len)
+{
+    if (ptr) {
+	memset(ptr, 0, len);
+	PR_Free(ptr);
+    }
+}
+
+char *
+PORT_Strdup(const char *str)
+{
+    size_t len = PORT_Strlen(str)+1;
+    char *newstr;
+
+    newstr = (char *)PORT_Alloc(len);
+    if (newstr) {
+        PORT_Memcpy(newstr, str, len);
+    }
+    return newstr;
+}
+
+void
+PORT_SetError(int value)
+{	
+#ifdef DEBUG_jp96085
+    PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
+#endif
+    PR_SetError(value, 0);
+    return;
+}
+
+int
+PORT_GetError(void)
+{
+    return(PR_GetError());
+}
+
+/********************* Arena code follows *****************************
+ * ArenaPools are like heaps.  The memory in them consists of large blocks,
+ * called arenas, which are allocated from the/a system heap.  Inside an
+ * ArenaPool, the arenas are organized as if they were in a stack.  Newly
+ * allocated arenas are "pushed" on that stack.  When you attempt to
+ * allocate memory from an ArenaPool, the code first looks to see if there
+ * is enough unused space in the top arena on the stack to satisfy your
+ * request, and if so, your request is satisfied from that arena.
+ * Otherwise, a new arena is allocated (or taken from NSPR's list of freed
+ * arenas) and pushed on to the stack.  The new arena is always big enough
+ * to satisfy the request, and is also at least a minimum size that is
+ * established at the time that the ArenaPool is created.
+ *
+ * The ArenaMark function returns the address of a marker in the arena at
+ * the top of the arena stack.  It is the address of the place in the arena
+ * on the top of the arena stack from which the next block of memory will
+ * be allocated.  Each ArenaPool has its own separate stack, and hence
+ * marks are only relevant to the ArenaPool from which they are gotten.
+ * Marks may be nested.  That is, a thread can get a mark, and then get
+ * another mark.
+ *
+ * It is intended that all the marks in an ArenaPool may only be owned by a
+ * single thread.  In DEBUG builds, this is enforced.  In non-DEBUG builds,
+ * it is not.  In DEBUG builds, when a thread gets a mark from an
+ * ArenaPool, no other thread may acquire a mark in that ArenaPool while
+ * that mark exists, that is, until that mark is unmarked or released.
+ * Therefore, it is important that every mark be unmarked or released when
+ * the creating thread has no further need for exclusive ownership of the
+ * right to manage the ArenaPool.
+ *
+ * The ArenaUnmark function discards the ArenaMark at the address given,
+ * and all marks nested inside that mark (that is, acquired from that same
+ * ArenaPool while that mark existed).   It is an error for a thread other
+ * than the mark's creator to try to unmark it.  When a thread has unmarked
+ * all its marks from an ArenaPool, then another thread is able to set
+ * marks in that ArenaPool.  ArenaUnmark does not deallocate (or "pop") any
+ * memory allocated from the ArenaPool since the mark was created.
+ *
+ * ArenaRelease "pops" the stack back to the mark, deallocating all the
+ * memory allocated from the arenas in the ArenaPool since that mark was
+ * created, and removing any arenas from the ArenaPool that have no
+ * remaining active allocations when that is done.  It implicitly releases
+ * any marks nested inside the mark being explicitly released.  It is the
+ * only operation, other than destroying the arenapool, that potentially
+ * reduces the number of arenas on the stack.  Otherwise, the stack grows
+ * until the arenapool is destroyed, at which point all the arenas are
+ * freed or returned to a "free arena list", depending on their sizes.
+ */
+PLArenaPool *
+PORT_NewArena(unsigned long chunksize)
+{
+    PORTArenaPool *pool;
+    
+    pool = PORT_ZNew(PORTArenaPool);
+    if (!pool) {
+	return NULL;
+    }
+    pool->magic = ARENAPOOL_MAGIC;
+    pool->lock = PZ_NewLock(nssILockArena);
+    if (!pool->lock) {
+	++port_allocFailures;
+	PORT_Free(pool);
+	return NULL;
+    }
+    PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
+    return(&pool->arena);
+}
+
+#define MAX_SIZE 0x7fffffffUL
+
+void *
+PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
+{
+    void *p = NULL;
+
+    PORTArenaPool *pool = (PORTArenaPool *)arena;
+
+    if (size <= 0) {
+	size = 1;
+    }
+
+    if (size > MAX_SIZE) {
+	/* you lose. */
+    } else 
+    /* Is it one of ours?  Assume so and check the magic */
+    if (ARENAPOOL_MAGIC == pool->magic ) {
+	PZ_Lock(pool->lock);
+#ifdef THREADMARK
+        /* Most likely one of ours.  Is there a thread id? */
+	if (pool->marking_thread  &&
+	    pool->marking_thread != PR_GetCurrentThread() ) {
+	    /* Another thread holds a mark in this arena */
+	    PZ_Unlock(pool->lock);
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    PORT_Assert(0);
+	    return NULL;
+	} /* tid != null */
+#endif /* THREADMARK */
+	PL_ARENA_ALLOCATE(p, arena, size);
+	PZ_Unlock(pool->lock);
+    } else {
+	PL_ARENA_ALLOCATE(p, arena, size);
+    }
+
+    if (!p) {
+	++port_allocFailures;
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+    }
+
+    return(p);
+}
+
+void *
+PORT_ArenaZAlloc(PLArenaPool *arena, size_t size)
+{
+    void *p;
+
+    if (size <= 0)
+        size = 1;
+
+    p = PORT_ArenaAlloc(arena, size);
+
+    if (p) {
+	PORT_Memset(p, 0, size);
+    }
+
+    return(p);
+}
+
+/*
+ * If zero is true, zeroize the arena memory before freeing it.
+ */
+void
+PORT_FreeArena(PLArenaPool *arena, PRBool zero)
+{
+    PORTArenaPool *pool = (PORTArenaPool *)arena;
+    PRLock *       lock = (PRLock *)0;
+    size_t         len  = sizeof *arena;
+    static PRBool  checkedEnv = PR_FALSE;
+    static PRBool  doFreeArenaPool = PR_FALSE;
+
+    if (!pool)
+    	return;
+    if (ARENAPOOL_MAGIC == pool->magic ) {
+	len  = sizeof *pool;
+	lock = pool->lock;
+	PZ_Lock(lock);
+    }
+    if (!checkedEnv) {
+	/* no need for thread protection here */
+	const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
+	if (!ev) doFreeArenaPool = PR_TRUE;
+	checkedEnv = PR_TRUE;
+    }
+    if (zero) {
+	PLArena *a;
+	for (a = arena->first.next; a; a = a->next) {
+	    PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+	    memset((void *)a->base, 0, a->avail - a->base);
+	}
+    }
+    if (doFreeArenaPool) {
+	PL_FreeArenaPool(arena);
+    } else {
+	PL_FinishArenaPool(arena);
+    }
+    PORT_ZFree(arena, len);
+    if (lock) {
+	PZ_Unlock(lock);
+	PZ_DestroyLock(lock);
+    }
+}
+
+void *
+PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
+{
+    PORTArenaPool *pool = (PORTArenaPool *)arena;
+    PORT_Assert(newsize >= oldsize);
+    
+    if (ARENAPOOL_MAGIC == pool->magic ) {
+	PZ_Lock(pool->lock);
+	/* Do we do a THREADMARK check here? */
+	PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
+	PZ_Unlock(pool->lock);
+    } else {
+	PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
+    }
+    
+    return(ptr);
+}
+
+void *
+PORT_ArenaMark(PLArenaPool *arena)
+{
+    void * result;
+
+    PORTArenaPool *pool = (PORTArenaPool *)arena;
+    if (ARENAPOOL_MAGIC == pool->magic ) {
+	PZ_Lock(pool->lock);
+#ifdef THREADMARK
+	{
+	  threadmark_mark *tm, **pw;
+	  PRThread * currentThread = PR_GetCurrentThread();
+
+	    if (! pool->marking_thread ) {
+		/* First mark */
+		pool->marking_thread = currentThread;
+	    } else if (currentThread != pool->marking_thread ) {
+		PZ_Unlock(pool->lock);
+		PORT_SetError(SEC_ERROR_NO_MEMORY);
+		PORT_Assert(0);
+		return NULL;
+	    }
+
+	    result = PL_ARENA_MARK(arena);
+	    PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark));
+	    if (!tm) {
+		PZ_Unlock(pool->lock);
+		PORT_SetError(SEC_ERROR_NO_MEMORY);
+		return NULL;
+	    }
+
+	    tm->mark = result;
+	    tm->next = (threadmark_mark *)NULL;
+
+	    pw = &pool->first_mark;
+	    while( *pw ) {
+		 pw = &(*pw)->next;
+	    }
+
+	    *pw = tm;
+	}
+#else /* THREADMARK */
+	result = PL_ARENA_MARK(arena);
+#endif /* THREADMARK */
+	PZ_Unlock(pool->lock);
+    } else {
+	/* a "pure" NSPR arena */
+	result = PL_ARENA_MARK(arena);
+    }
+    return result;
+}
+
+static void
+port_ArenaZeroAfterMark(PLArenaPool *arena, void *mark)
+{
+    PLArena *a = arena->current;
+    if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
+	/* fast path: mark falls in the current arena */
+	memset(mark, 0, a->avail - (PRUword)mark);
+    } else {
+	/* slow path: need to find the arena that mark falls in */
+	for (a = arena->first.next; a; a = a->next) {
+	    PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+	    if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
+		memset(mark, 0, a->avail - (PRUword)mark);
+		a = a->next;
+		break;
+	    }
+	}
+	for (; a; a = a->next) {
+	    PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+	    memset((void *)a->base, 0, a->avail - a->base);
+	}
+    }
+}
+
+static void
+port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero)
+{
+    PORTArenaPool *pool = (PORTArenaPool *)arena;
+    if (ARENAPOOL_MAGIC == pool->magic ) {
+	PZ_Lock(pool->lock);
+#ifdef THREADMARK
+	{
+	    threadmark_mark **pw, *tm;
+
+	    if (PR_GetCurrentThread() != pool->marking_thread ) {
+		PZ_Unlock(pool->lock);
+		PORT_SetError(SEC_ERROR_NO_MEMORY);
+		PORT_Assert(0);
+		return /* no error indication available */ ;
+	    }
+
+	    pw = &pool->first_mark;
+	    while( *pw && (mark != (*pw)->mark) ) {
+		pw = &(*pw)->next;
+	    }
+
+	    if (! *pw ) {
+		/* bad mark */
+		PZ_Unlock(pool->lock);
+		PORT_SetError(SEC_ERROR_NO_MEMORY);
+		PORT_Assert(0);
+		return /* no error indication available */ ;
+	    }
+
+	    tm = *pw;
+	    *pw = (threadmark_mark *)NULL;
+
+	    if (zero) {
+		port_ArenaZeroAfterMark(arena, mark);
+	    }
+	    PL_ARENA_RELEASE(arena, mark);
+
+	    if (! pool->first_mark ) {
+		pool->marking_thread = (PRThread *)NULL;
+	    }
+	}
+#else /* THREADMARK */
+	if (zero) {
+	    port_ArenaZeroAfterMark(arena, mark);
+	}
+	PL_ARENA_RELEASE(arena, mark);
+#endif /* THREADMARK */
+	PZ_Unlock(pool->lock);
+    } else {
+	if (zero) {
+	    port_ArenaZeroAfterMark(arena, mark);
+	}
+	PL_ARENA_RELEASE(arena, mark);
+    }
+}
+
+void
+PORT_ArenaRelease(PLArenaPool *arena, void *mark)
+{
+    port_ArenaRelease(arena, mark, PR_FALSE);
+}
+
+/*
+ * Zeroize the arena memory before releasing it.
+ */
+void
+PORT_ArenaZRelease(PLArenaPool *arena, void *mark)
+{
+    port_ArenaRelease(arena, mark, PR_TRUE);
+}
+
+void
+PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
+{
+#ifdef THREADMARK
+    PORTArenaPool *pool = (PORTArenaPool *)arena;
+    if (ARENAPOOL_MAGIC == pool->magic ) {
+	threadmark_mark **pw, *tm;
+
+	PZ_Lock(pool->lock);
+
+	if (PR_GetCurrentThread() != pool->marking_thread ) {
+	    PZ_Unlock(pool->lock);
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    PORT_Assert(0);
+	    return /* no error indication available */ ;
+	}
+
+	pw = &pool->first_mark;
+	while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) {
+	    pw = &(*pw)->next;
+	}
+
+	if ((threadmark_mark *)NULL == *pw ) {
+	    /* bad mark */
+	    PZ_Unlock(pool->lock);
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    PORT_Assert(0);
+	    return /* no error indication available */ ;
+	}
+
+	tm = *pw;
+	*pw = (threadmark_mark *)NULL;
+
+	if (! pool->first_mark ) {
+	    pool->marking_thread = (PRThread *)NULL;
+	}
+
+	PZ_Unlock(pool->lock);
+    }
+#endif /* THREADMARK */
+}
+
+char *
+PORT_ArenaStrdup(PLArenaPool *arena, const char *str) {
+    int len = PORT_Strlen(str)+1;
+    char *newstr;
+
+    newstr = (char*)PORT_ArenaAlloc(arena,len);
+    if (newstr) {
+        PORT_Memcpy(newstr,str,len);
+    }
+    return newstr;
+}
+
+/********************** end of arena functions ***********************/
+
+/****************** unicode conversion functions ***********************/
+/*
+ * NOTE: These conversion functions all assume that the multibyte
+ * characters are going to be in NETWORK BYTE ORDER, not host byte
+ * order.  This is because the only time we deal with UCS-2 and UCS-4
+ * are when the data was received from or is going to be sent out
+ * over the wire (in, e.g. certificates).
+ */
+
+void
+PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{ 
+    ucs4Utf8ConvertFunc = convFunc;
+}
+
+void
+PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc)
+{ 
+    ucs2AsciiConvertFunc = convFunc;
+}
+
+void
+PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{ 
+    ucs2Utf8ConvertFunc = convFunc;
+}
+
+PRBool 
+PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+			 unsigned int inBufLen, unsigned char *outBuf,
+			 unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+    if(!ucs4Utf8ConvertFunc) {
+      return sec_port_ucs4_utf8_conversion_function(toUnicode,
+        inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
+    }
+
+    return (*ucs4Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 
+				  maxOutBufLen, outBufLen);
+}
+
+PRBool 
+PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+			 unsigned int inBufLen, unsigned char *outBuf,
+			 unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+    if(!ucs2Utf8ConvertFunc) {
+      return sec_port_ucs2_utf8_conversion_function(toUnicode,
+        inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
+    }
+
+    return (*ucs2Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 
+				  maxOutBufLen, outBufLen);
+}
+
+PRBool 
+PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
+			 unsigned int inBufLen, unsigned char *outBuf,
+			 unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+    return sec_port_iso88591_utf8_conversion_function(inBuf, inBufLen,
+      outBuf, maxOutBufLen, outBufLen);
+}
+
+PRBool 
+PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
+			  unsigned int inBufLen, unsigned char *outBuf,
+			  unsigned int maxOutBufLen, unsigned int *outBufLen,
+			  PRBool swapBytes)
+{
+    if(!ucs2AsciiConvertFunc) {
+	return PR_FALSE;
+    }
+
+    return (*ucs2AsciiConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 
+				  maxOutBufLen, outBufLen, swapBytes);
+}
+
+
+/* Portable putenv.  Creates/replaces an environment variable of the form
+ *  envVarName=envValue
+ */
+int
+NSS_PutEnv(const char * envVarName, const char * envValue)
+{
+#ifdef _WIN32_WCE
+    return SECFailure;
+#else
+    SECStatus result = SECSuccess;
+    char *    encoded;
+    int       putEnvFailed;
+#ifdef _WIN32
+    PRBool      setOK;
+
+    setOK = SetEnvironmentVariable(envVarName, envValue);
+    if (!setOK) {
+        SET_ERROR_CODE
+        return SECFailure;
+    }
+#endif
+
+    encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue));
+    strcpy(encoded, envVarName);
+    strcat(encoded, "=");
+    strcat(encoded, envValue);
+
+    putEnvFailed = putenv(encoded); /* adopt. */
+    if (putEnvFailed) {
+        SET_ERROR_CODE
+        result = SECFailure;
+        PORT_Free(encoded);
+    }
+    return result;
+#endif
+}
+
+/*
+ * Perform a constant-time compare of two memory regions. The return value is
+ * 0 if the memory regions are equal and non-zero otherwise.
+ */
+int
+NSS_SecureMemcmp(const void *ia, const void *ib, size_t n)
+{
+    const unsigned char *a = (const unsigned char*) ia;
+    const unsigned char *b = (const unsigned char*) ib;
+    size_t i;
+    unsigned char r = 0;
+
+    for (i = 0; i < n; ++i) {
+        r |= *a++ ^ *b++;
+    }
+
+    return r;
+}
diff --git a/mozilla/security/nss/lib/util/secport.h b/mozilla/security/nss/lib/util/secport.h
new file mode 100644
index 0000000..9ad6204
--- /dev/null
+++ b/mozilla/security/nss/lib/util/secport.h
@@ -0,0 +1,285 @@
+/* ***** 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 ***** */
+
+/*
+ * secport.h - portability interfaces for security libraries
+ *
+ * $Id: secport.h,v 1.23 2009/10/30 09:44:47 nelson%bolyard.com Exp $
+ */
+
+#ifndef _SECPORT_H_
+#define _SECPORT_H_
+
+#include "utilrename.h"
+#include "prlink.h"
+
+/*
+ * define XP_WIN, XP_BEOS, or XP_UNIX, in case they are not defined
+ * by anyone else
+ */
+#ifdef _WINDOWS
+# ifndef XP_WIN
+# define XP_WIN
+# endif
+#if defined(_WIN32) || defined(WIN32)
+# ifndef XP_WIN32
+# define XP_WIN32
+# endif
+#endif
+#endif
+
+#ifdef __BEOS__
+# ifndef XP_BEOS
+# define XP_BEOS
+# endif
+#endif
+
+#ifdef unix
+# ifndef XP_UNIX
+# define XP_UNIX
+# endif
+#endif
+
+#if defined(_WIN32_WCE)
+#include <windef.h>
+#include <types.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+#if defined(_WIN32_WCE)
+#include <stdlib.h>	/* WinCE puts some stddef symbols here. */
+#else
+#include <stddef.h>
+#endif
+#include <stdlib.h>
+#include "prtypes.h"
+#include "prlog.h"	/* for PR_ASSERT */
+#include "plarena.h"
+#include "plstr.h"
+
+/*
+ * HACK for NSS 2.8 to allow Admin to compile without source changes.
+ */
+#ifndef SEC_BEGIN_PROTOS
+#include "seccomon.h"
+#endif
+
+SEC_BEGIN_PROTOS
+
+extern void *PORT_Alloc(size_t len);
+extern void *PORT_Realloc(void *old, size_t len);
+extern void *PORT_AllocBlock(size_t len);
+extern void *PORT_ReallocBlock(void *old, size_t len);
+extern void PORT_FreeBlock(void *ptr);
+extern void *PORT_ZAlloc(size_t len);
+extern void PORT_Free(void *ptr);
+extern void PORT_ZFree(void *ptr, size_t len);
+extern char *PORT_Strdup(const char *s);
+extern time_t PORT_Time(void);
+extern void PORT_SetError(int value);
+extern int PORT_GetError(void);
+
+extern PLArenaPool *PORT_NewArena(unsigned long chunksize);
+extern void *PORT_ArenaAlloc(PLArenaPool *arena, size_t size);
+extern void *PORT_ArenaZAlloc(PLArenaPool *arena, size_t size);
+extern void PORT_FreeArena(PLArenaPool *arena, PRBool zero);
+extern void *PORT_ArenaGrow(PLArenaPool *arena, void *ptr,
+			    size_t oldsize, size_t newsize);
+extern void *PORT_ArenaMark(PLArenaPool *arena);
+extern void PORT_ArenaRelease(PLArenaPool *arena, void *mark);
+extern void PORT_ArenaZRelease(PLArenaPool *arena, void *mark);
+extern void PORT_ArenaUnmark(PLArenaPool *arena, void *mark);
+extern char *PORT_ArenaStrdup(PLArenaPool *arena, const char *str);
+
+SEC_END_PROTOS
+
+#define PORT_Assert PR_ASSERT
+#define PORT_ZNew(type) (type*)PORT_ZAlloc(sizeof(type))
+#define PORT_New(type) (type*)PORT_Alloc(sizeof(type))
+#define PORT_ArenaNew(poolp, type)	\
+		(type*) PORT_ArenaAlloc(poolp, sizeof(type))
+#define PORT_ArenaZNew(poolp, type)	\
+		(type*) PORT_ArenaZAlloc(poolp, sizeof(type))
+#define PORT_NewArray(type, num)	\
+		(type*) PORT_Alloc (sizeof(type)*(num))
+#define PORT_ZNewArray(type, num)	\
+		(type*) PORT_ZAlloc (sizeof(type)*(num))
+#define PORT_ArenaNewArray(poolp, type, num)	\
+		(type*) PORT_ArenaAlloc (poolp, sizeof(type)*(num))
+#define PORT_ArenaZNewArray(poolp, type, num)	\
+		(type*) PORT_ArenaZAlloc (poolp, sizeof(type)*(num))
+
+/* Please, keep these defines sorted alphabetically.  Thanks! */
+
+#define PORT_Atoi(buff)	(int)strtol(buff, NULL, 10)
+
+#define PORT_Memcmp 	memcmp
+#define PORT_Memcpy 	memcpy
+#ifndef SUNOS4
+#define PORT_Memmove 	memmove
+#else /*SUNOS4*/
+#define PORT_Memmove(s,ct,n)    bcopy ((ct), (s), (n))
+#endif/*SUNOS4*/
+#define PORT_Memset 	memset
+
+#define PORT_Strcasecmp PL_strcasecmp
+#define PORT_Strcat 	strcat
+#define PORT_Strchr 	strchr
+#define PORT_Strrchr    strrchr
+#define PORT_Strcmp 	strcmp
+#define PORT_Strcpy 	strcpy
+#define PORT_Strlen(s) 	strlen(s)
+#define PORT_Strncasecmp PL_strncasecmp
+#define PORT_Strncat 	strncat
+#define PORT_Strncmp 	strncmp
+#define PORT_Strncpy 	strncpy
+#define PORT_Strpbrk    strpbrk
+#define PORT_Strstr 	strstr
+#define PORT_Strtok 	strtok
+
+#define PORT_Tolower 	tolower
+
+typedef PRBool (PR_CALLBACK * PORTCharConversionWSwapFunc) (PRBool toUnicode,
+			unsigned char *inBuf, unsigned int inBufLen,
+			unsigned char *outBuf, unsigned int maxOutBufLen,
+			unsigned int *outBufLen, PRBool swapBytes);
+
+typedef PRBool (PR_CALLBACK * PORTCharConversionFunc) (PRBool toUnicode,
+			unsigned char *inBuf, unsigned int inBufLen,
+			unsigned char *outBuf, unsigned int maxOutBufLen,
+			unsigned int *outBufLen);
+
+SEC_BEGIN_PROTOS
+
+void PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc);
+void PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc);
+PRBool PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+			unsigned int inBufLen, unsigned char *outBuf,
+			unsigned int maxOutBufLen, unsigned int *outBufLen);
+PRBool PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
+			unsigned int inBufLen, unsigned char *outBuf,
+			unsigned int maxOutBufLen, unsigned int *outBufLen,
+			PRBool swapBytes);
+void PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc);
+PRBool PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+			unsigned int inBufLen, unsigned char *outBuf,
+			unsigned int maxOutBufLen, unsigned int *outBufLen);
+
+/* One-way conversion from ISO-8859-1 to UTF-8 */
+PRBool PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
+			unsigned int inBufLen, unsigned char *outBuf,
+			unsigned int maxOutBufLen, unsigned int *outBufLen);
+
+extern PRBool
+sec_port_ucs4_utf8_conversion_function
+(
+  PRBool toUnicode,
+  unsigned char *inBuf,
+  unsigned int inBufLen,
+  unsigned char *outBuf,
+  unsigned int maxOutBufLen,
+  unsigned int *outBufLen
+);
+
+extern PRBool
+sec_port_ucs2_utf8_conversion_function
+(
+  PRBool toUnicode,
+  unsigned char *inBuf,
+  unsigned int inBufLen,
+  unsigned char *outBuf,
+  unsigned int maxOutBufLen,
+  unsigned int *outBufLen
+);
+
+/* One-way conversion from ISO-8859-1 to UTF-8 */
+extern PRBool
+sec_port_iso88591_utf8_conversion_function
+(
+  const unsigned char *inBuf,
+  unsigned int inBufLen,
+  unsigned char *outBuf,
+  unsigned int maxOutBufLen,
+  unsigned int *outBufLen
+);
+
+extern int NSS_PutEnv(const char * envVarName, const char * envValue);
+
+extern int NSS_SecureMemcmp(const void *a, const void *b, size_t n);
+
+#if 0  /* STATIC LIBRARIES */
+/*
+ * Load a shared library called "newShLibName" in the same directory as
+ * a shared library that is already loaded, called existingShLibName.
+ * A pointer to a static function in that shared library,
+ * staticShLibFunc, is required.
+ *
+ * existingShLibName:
+ *   The file name of the shared library that shall be used as the 
+ *   "reference library". The loader will attempt to load the requested
+ *   library from the same directory as the reference library.
+ *
+ * staticShLibFunc:
+ *   Pointer to a static function in the "reference library".
+ *
+ * newShLibName:
+ *   The simple file name of the new shared library to be loaded.
+ *
+ * We use PR_GetLibraryFilePathname to get the pathname of the loaded 
+ * shared lib that contains this function, and then do a
+ * PR_LoadLibraryWithFlags with an absolute pathname for the shared
+ * library to be loaded.
+ *
+ * On Windows, the "alternate search path" strategy is employed, if available.
+ * On Unix, if existingShLibName is a symbolic link, and no link exists for the
+ * new library, the original link will be resolved, and the new library loaded
+ * from the resolved location.
+ *
+ * If the new shared library is not found in the same location as the reference
+ * library, it will then be loaded from the normal system library path.
+ */
+PRLibrary *
+PORT_LoadLibraryFromOrigin(const char* existingShLibName,
+                 PRFuncPtr staticShLibFunc,
+                 const char *newShLibName);
+#endif  /* STATIC LIBRARIES */
+
+SEC_END_PROTOS
+
+#endif /* _SECPORT_H_ */
diff --git a/mozilla/security/nss/lib/util/sectime.c b/mozilla/security/nss/lib/util/sectime.c
new file mode 100644
index 0000000..cf4c526
--- /dev/null
+++ b/mozilla/security/nss/lib/util/sectime.c
@@ -0,0 +1,194 @@
+/* ***** 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 "prlong.h"
+#include "prtime.h"
+#include "secder.h"
+#include "secitem.h"
+#include "secerr.h"
+
+static const PRTime January1st2050  = LL_INIT(0x0008f81e, 0x1b098000);
+
+static char *DecodeUTCTime2FormattedAscii (SECItem *utcTimeDER, char *format);
+static char *DecodeGeneralizedTime2FormattedAscii (SECItem *generalizedTimeDER, char *format);
+
+/* convert DER utc time to ascii time string */
+char *
+DER_UTCTimeToAscii(SECItem *utcTime)
+{
+    return (DecodeUTCTime2FormattedAscii (utcTime, "%a %b %d %H:%M:%S %Y"));
+}
+
+/* convert DER utc time to ascii time string, only include day, not time */
+char *
+DER_UTCDayToAscii(SECItem *utctime)
+{
+    return (DecodeUTCTime2FormattedAscii (utctime, "%a %b %d, %Y"));
+}
+
+/* convert DER generalized time to ascii time string, only include day,
+   not time */
+char *
+DER_GeneralizedDayToAscii(SECItem *gentime)
+{
+    return (DecodeGeneralizedTime2FormattedAscii (gentime, "%a %b %d, %Y"));
+}
+
+/* convert DER generalized or UTC time to ascii time string, only include
+   day, not time */
+char *
+DER_TimeChoiceDayToAscii(SECItem *timechoice)
+{
+    switch (timechoice->type) {
+
+    case siUTCTime:
+        return DER_UTCDayToAscii(timechoice);
+
+    case siGeneralizedTime:
+        return DER_GeneralizedDayToAscii(timechoice);
+
+    default:
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+}
+
+char *
+CERT_UTCTime2FormattedAscii (int64 utcTime, char *format)
+{
+    PRExplodedTime printableTime; 
+    char *timeString;
+   
+    /* Converse time to local time and decompose it into components */
+    PR_ExplodeTime(utcTime, PR_LocalTimeParameters, &printableTime);
+    
+    timeString = (char *)PORT_Alloc(256);
+
+    if ( timeString ) {
+        if ( ! PR_FormatTime( timeString, 256, format, &printableTime )) {
+            PORT_Free(timeString);
+            timeString = NULL;
+        }
+    }
+    
+    return (timeString);
+}
+
+char *CERT_GenTime2FormattedAscii (int64 genTime, char *format)
+{
+    PRExplodedTime printableTime; 
+    char *timeString;
+   
+    /* Decompose time into components */
+    PR_ExplodeTime(genTime, PR_GMTParameters, &printableTime);
+    
+    timeString = (char *)PORT_Alloc(256);
+
+    if ( timeString ) {
+        if ( ! PR_FormatTime( timeString, 256, format, &printableTime )) {
+            PORT_Free(timeString);
+            timeString = NULL;
+            PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+        }
+    }
+    
+    return (timeString);
+}
+
+
+/* convert DER utc time to ascii time string, The format of the time string
+   depends on the input "format"
+ */
+static char *
+DecodeUTCTime2FormattedAscii (SECItem *utcTimeDER,  char *format)
+{
+    int64 utcTime;
+    int rv;
+   
+    rv = DER_UTCTimeToTime(&utcTime, utcTimeDER);
+    if (rv) {
+        return(NULL);
+    }
+    return (CERT_UTCTime2FormattedAscii (utcTime, format));
+}
+
+/* convert DER utc time to ascii time string, The format of the time string
+   depends on the input "format"
+ */
+static char *
+DecodeGeneralizedTime2FormattedAscii (SECItem *generalizedTimeDER,  char *format)
+{
+    PRTime generalizedTime;
+    int rv;
+   
+    rv = DER_GeneralizedTimeToTime(&generalizedTime, generalizedTimeDER);
+    if (rv) {
+        return(NULL);
+    }
+    return (CERT_GeneralizedTime2FormattedAscii (generalizedTime, format));
+}
+
+/* decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME 
+   or a SEC_ASN1_UTC_TIME */
+
+SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input)
+{
+    switch (input->type) {
+        case siGeneralizedTime:
+            return DER_GeneralizedTimeToTime(output, input);
+
+        case siUTCTime:
+            return DER_UTCTimeToTime(output, input);
+
+        default:
+            PORT_SetError(SEC_ERROR_INVALID_ARGS);
+            PORT_Assert(0);
+            return SECFailure;
+    }
+}
+
+/* encode a PRTime to an ASN.1 DER SECItem containing either a
+   SEC_ASN1_GENERALIZED_TIME or a SEC_ASN1_UTC_TIME */
+
+SECStatus DER_EncodeTimeChoice(PRArenaPool* arena, SECItem* output, PRTime input)
+{
+    if (LL_CMP(input, >, January1st2050)) {
+        return DER_TimeToGeneralizedTimeArena(arena, output, input);
+    } else {
+        return DER_TimeToUTCTimeArena(arena, output, input);
+    }
+}
diff --git a/mozilla/security/nss/lib/util/templates.c b/mozilla/security/nss/lib/util/templates.c
new file mode 100644
index 0000000..a8dd9f7
--- /dev/null
+++ b/mozilla/security/nss/lib/util/templates.c
@@ -0,0 +1,168 @@
+/* ***** 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 Network Security Services libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 ***** */
+
+/*
+ * Templates that are compiled and exported from both libnss3 and libnssutil3.
+ * They have to be, because they were previously exported from libnss3, and
+ * there is no way to create data forwarder symbols on Unix.
+ *
+ * Please do not add to this file. New shared templates should be exported
+ * from libnssutil3 only.
+ *
+ */
+
+#include "utilrename.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "secoid.h"
+#include "secdig.h"
+
+const SEC_ASN1Template SECOID_AlgorithmIDTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SECAlgorithmID) },
+    { SEC_ASN1_OBJECT_ID,
+	  offsetof(SECAlgorithmID,algorithm), },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+	  offsetof(SECAlgorithmID,parameters), },
+    { 0, }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SECOID_AlgorithmIDTemplate)
+
+const SEC_ASN1Template SEC_AnyTemplate[] = {
+    { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_AnyTemplate)
+
+const SEC_ASN1Template SEC_BMPStringTemplate[] = {
+    { SEC_ASN1_BMP_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BMPStringTemplate)
+
+const SEC_ASN1Template SEC_BitStringTemplate[] = {
+    { SEC_ASN1_BIT_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BitStringTemplate)
+
+const SEC_ASN1Template SEC_BooleanTemplate[] = {
+    { SEC_ASN1_BOOLEAN, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BooleanTemplate)
+
+const SEC_ASN1Template SEC_GeneralizedTimeTemplate[] = {
+    { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_GeneralizedTimeTemplate)
+
+const SEC_ASN1Template SEC_IA5StringTemplate[] = {
+    { SEC_ASN1_IA5_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_IA5StringTemplate)
+
+const SEC_ASN1Template SEC_IntegerTemplate[] = {
+    { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_IntegerTemplate)
+
+const SEC_ASN1Template SEC_NullTemplate[] = {
+    { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_NullTemplate)
+
+const SEC_ASN1Template SEC_ObjectIDTemplate[] = {
+    { SEC_ASN1_OBJECT_ID, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_ObjectIDTemplate)
+
+const SEC_ASN1Template SEC_OctetStringTemplate[] = {
+    { SEC_ASN1_OCTET_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_OctetStringTemplate)
+
+const SEC_ASN1Template SEC_PointerToAnyTemplate[] = {
+    { SEC_ASN1_POINTER, 0, SEC_AnyTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToAnyTemplate)
+
+const SEC_ASN1Template SEC_PointerToOctetStringTemplate[] = {
+    { SEC_ASN1_POINTER | SEC_ASN1_MAY_STREAM, 0, SEC_OctetStringTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToOctetStringTemplate)
+
+const SEC_ASN1Template SEC_SetOfAnyTemplate[] = {
+    { SEC_ASN1_SET_OF, 0, SEC_AnyTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SetOfAnyTemplate)
+
+const SEC_ASN1Template SEC_UTCTimeTemplate[] = {
+    { SEC_ASN1_UTC_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UTCTimeTemplate)
+
+const SEC_ASN1Template SEC_UTF8StringTemplate[] = {
+    { SEC_ASN1_UTF8_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UTF8StringTemplate)
+
+/* XXX See comment below about SGN_DecodeDigestInfo -- keep this static! */
+/* XXX Changed from static -- need to change name? */
+const SEC_ASN1Template sgn_DigestInfoTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+	  0, NULL, sizeof(SGNDigestInfo) },
+    { SEC_ASN1_INLINE,
+	  offsetof(SGNDigestInfo,digestAlgorithm),
+	  SECOID_AlgorithmIDTemplate },
+    { SEC_ASN1_OCTET_STRING,
+	  offsetof(SGNDigestInfo,digest) },
+    { 0 }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(sgn_DigestInfoTemplate)
diff --git a/mozilla/security/nss/lib/util/utf8.c b/mozilla/security/nss/lib/util/utf8.c
new file mode 100644
index 0000000..7b26f48
--- /dev/null
+++ b/mozilla/security/nss/lib/util/utf8.c
@@ -0,0 +1,1833 @@
+/* ***** 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):
+ *   John Gardiner Myers <jgmyers@speakeasy.net>
+ *
+ * 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 ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile: utf8.c,v $ $Revision: 1.13 $ $Date: 2008/10/05 20:59:26 $";
+#endif /* DEBUG */
+
+#include "seccomon.h"
+#include "secport.h"
+
+#ifdef TEST_UTF8
+#include <assert.h>
+#undef PORT_Assert
+#define PORT_Assert assert
+#endif
+
+/*
+ * From RFC 2044:
+ *
+ * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+ * 0000 0000-0000 007F   0xxxxxxx
+ * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+ * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
+ * 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
+ */  
+
+/*
+ * From http://www.imc.org/draft-hoffman-utf16
+ *
+ * For U on [0x00010000,0x0010FFFF]:  Let U' = U - 0x00010000
+ *
+ * U' = yyyyyyyyyyxxxxxxxxxx
+ * W1 = 110110yyyyyyyyyy
+ * W2 = 110111xxxxxxxxxx
+ */
+
+/*
+ * This code is assuming NETWORK BYTE ORDER for the 16- and 32-bit
+ * character values.  If you wish to use this code for working with
+ * host byte order values, define the following:
+ *
+ * #if IS_BIG_ENDIAN
+ * #define L_0 0
+ * #define L_1 1
+ * #define L_2 2
+ * #define L_3 3
+ * #define H_0 0
+ * #define H_1 1
+ * #else / * not everyone has elif * /
+ * #if IS_LITTLE_ENDIAN
+ * #define L_0 3
+ * #define L_1 2
+ * #define L_2 1
+ * #define L_3 0
+ * #define H_0 1
+ * #define H_1 0
+ * #else
+ * #error "PDP and NUXI support deferred"
+ * #endif / * IS_LITTLE_ENDIAN * /
+ * #endif / * IS_BIG_ENDIAN * /
+ */
+
+#define L_0 0
+#define L_1 1
+#define L_2 2
+#define L_3 3
+#define H_0 0
+#define H_1 1
+
+#define BAD_UTF8 ((PRUint32)-1)
+
+/*
+ * Parse a single UTF-8 character per the spec. in section 3.9 (D36)
+ * of Unicode 4.0.0.
+ *
+ * Parameters:
+ * index - Points to the byte offset in inBuf of character to read.  On success,
+ *         updated to the offset of the following character.
+ * inBuf - Input buffer, UTF-8 encoded
+ * inbufLen - Length of input buffer, in bytes.
+ *
+ * Returns:
+ * Success - The UCS4 encoded character
+ * Failure - BAD_UTF8
+ */
+static PRUint32
+sec_port_read_utf8(unsigned int *index, unsigned char *inBuf, unsigned int inBufLen)
+{
+  PRUint32 result;
+  unsigned int i = *index;
+  int bytes_left;
+  PRUint32 min_value;
+
+  PORT_Assert(i < inBufLen);
+
+  if ( (inBuf[i] & 0x80) == 0x00 ) {
+    result = inBuf[i++];
+    bytes_left = 0;
+    min_value = 0;
+  } else if ( (inBuf[i] & 0xE0) == 0xC0 ) {
+    result = inBuf[i++] & 0x1F;
+    bytes_left = 1;
+    min_value = 0x80;
+  } else if ( (inBuf[i] & 0xF0) == 0xE0) {
+    result = inBuf[i++] & 0x0F;
+    bytes_left = 2;
+    min_value = 0x800;
+  } else if ( (inBuf[i] & 0xF8) == 0xF0) {
+    result = inBuf[i++] & 0x07;
+    bytes_left = 3;
+    min_value = 0x10000;
+  } else {
+    return BAD_UTF8;
+  }
+
+  while (bytes_left--) {
+    if (i >= inBufLen || (inBuf[i] & 0xC0) != 0x80) return BAD_UTF8;
+    result = (result << 6) | (inBuf[i++] & 0x3F);
+  }
+
+  /* Check for overlong sequences, surrogates, and outside unicode range */
+  if (result < min_value || (result & 0xFFFFF800) == 0xD800 || result > 0x10FFFF) {
+    return BAD_UTF8;
+  }
+
+  *index = i;
+  return result;
+}
+
+PRBool
+sec_port_ucs4_utf8_conversion_function
+(
+  PRBool toUnicode,
+  unsigned char *inBuf,
+  unsigned int inBufLen,
+  unsigned char *outBuf,
+  unsigned int maxOutBufLen,
+  unsigned int *outBufLen
+)
+{
+  PORT_Assert((unsigned int *)NULL != outBufLen);
+
+  if( toUnicode ) {
+    unsigned int i, len = 0;
+
+    for( i = 0; i < inBufLen; ) {
+      if( (inBuf[i] & 0x80) == 0x00 ) i += 1;
+      else if( (inBuf[i] & 0xE0) == 0xC0 ) i += 2;
+      else if( (inBuf[i] & 0xF0) == 0xE0 ) i += 3;
+      else if( (inBuf[i] & 0xF8) == 0xF0 ) i += 4;
+      else return PR_FALSE;
+
+      len += 4;
+    }
+
+    if( len > maxOutBufLen ) {
+      *outBufLen = len;
+      return PR_FALSE;
+    }
+
+    len = 0;
+
+    for( i = 0; i < inBufLen; ) {
+      PRUint32 ucs4 = sec_port_read_utf8(&i, inBuf, inBufLen);
+
+      if (ucs4 == BAD_UTF8) return PR_FALSE;
+           
+      outBuf[len+L_0] = 0x00;
+      outBuf[len+L_1] = (unsigned char)(ucs4 >> 16);
+      outBuf[len+L_2] = (unsigned char)(ucs4 >> 8);
+      outBuf[len+L_3] = (unsigned char)ucs4;
+
+      len += 4;
+    }
+
+    *outBufLen = len;
+    return PR_TRUE;
+  } else {
+    unsigned int i, len = 0;
+    PORT_Assert((inBufLen % 4) == 0);
+    if ((inBufLen % 4) != 0) {
+      *outBufLen = 0;
+      return PR_FALSE;
+    }
+
+    for( i = 0; i < inBufLen; i += 4 ) {
+      if( (inBuf[i+L_0] > 0x00) || (inBuf[i+L_1] > 0x10) ) {
+	*outBufLen = 0;
+	return PR_FALSE;
+      } else if( inBuf[i+L_1] >= 0x01 ) len += 4;
+      else if( inBuf[i+L_2] >= 0x08 ) len += 3;
+      else if( (inBuf[i+L_2] > 0x00) || (inBuf[i+L_3] >= 0x80) ) len += 2;
+      else len += 1;
+    }
+
+    if( len > maxOutBufLen ) {
+      *outBufLen = len;
+      return PR_FALSE;
+    }
+
+    len = 0;
+
+    for( i = 0; i < inBufLen; i += 4 ) {
+      if( inBuf[i+L_1] >= 0x01 ) {
+        /* 0001 0000-001F FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+        /* 00000000 000abcde fghijklm nopqrstu ->
+           11110abc 10defghi 10jklmno 10pqrstu */
+
+        outBuf[len+0] = 0xF0 | ((inBuf[i+L_1] & 0x1C) >> 2);
+        outBuf[len+1] = 0x80 | ((inBuf[i+L_1] & 0x03) << 4)
+                             | ((inBuf[i+L_2] & 0xF0) >> 4);
+        outBuf[len+2] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2)
+                             | ((inBuf[i+L_3] & 0xC0) >> 6);
+        outBuf[len+3] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+        len += 4;
+      } else if( inBuf[i+L_2] >= 0x08 ) {
+        /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
+        /* 00000000 00000000 abcdefgh ijklmnop ->
+           1110abcd 10efghij 10klmnop */
+
+        outBuf[len+0] = 0xE0 | ((inBuf[i+L_2] & 0xF0) >> 4);
+        outBuf[len+1] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2)
+                             | ((inBuf[i+L_3] & 0xC0) >> 6);
+        outBuf[len+2] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+        len += 3;
+      } else if( (inBuf[i+L_2] > 0x00) || (inBuf[i+L_3] >= 0x80) ) {
+        /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */
+        /* 00000000 00000000 00000abc defghijk ->
+           110abcde 10fghijk */
+
+        outBuf[len+0] = 0xC0 | ((inBuf[i+L_2] & 0x07) << 2)
+                             | ((inBuf[i+L_3] & 0xC0) >> 6);
+        outBuf[len+1] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+        len += 2;
+      } else {
+        /* 0000 0000-0000 007F -> 0xxxxxx */
+        /* 00000000 00000000 00000000 0abcdefg ->
+           0abcdefg */
+
+        outBuf[len+0] = (inBuf[i+L_3] & 0x7F);
+
+        len += 1;
+      }
+    }
+                            
+    *outBufLen = len;
+    return PR_TRUE;
+  }
+}
+
+PRBool
+sec_port_ucs2_utf8_conversion_function
+(
+  PRBool toUnicode,
+  unsigned char *inBuf,
+  unsigned int inBufLen,
+  unsigned char *outBuf,
+  unsigned int maxOutBufLen,
+  unsigned int *outBufLen
+)
+{
+  PORT_Assert((unsigned int *)NULL != outBufLen);
+
+  if( toUnicode ) {
+    unsigned int i, len = 0;
+
+    for( i = 0; i < inBufLen; ) {
+      if( (inBuf[i] & 0x80) == 0x00 ) {
+        i += 1;
+        len += 2;
+      } else if( (inBuf[i] & 0xE0) == 0xC0 ) {
+        i += 2;
+        len += 2;
+      } else if( (inBuf[i] & 0xF0) == 0xE0 ) {
+        i += 3;
+        len += 2;
+      } else if( (inBuf[i] & 0xF8) == 0xF0 ) { 
+        i += 4;
+        len += 4;
+      } else return PR_FALSE;
+    }
+
+    if( len > maxOutBufLen ) {
+      *outBufLen = len;
+      return PR_FALSE;
+    }
+
+    len = 0;
+
+    for( i = 0; i < inBufLen; ) {
+      PRUint32 ucs4 = sec_port_read_utf8(&i, inBuf, inBufLen);
+
+      if (ucs4 == BAD_UTF8) return PR_FALSE;
+
+      if( ucs4 < 0x10000) {
+        outBuf[len+H_0] = (unsigned char)(ucs4 >> 8);
+        outBuf[len+H_1] = (unsigned char)ucs4;
+        len += 2;
+      } else {
+	ucs4 -= 0x10000;
+        outBuf[len+0+H_0] = (unsigned char)(0xD8 | ((ucs4 >> 18) & 0x3));
+        outBuf[len+0+H_1] = (unsigned char)(ucs4 >> 10);
+        outBuf[len+2+H_0] = (unsigned char)(0xDC | ((ucs4 >> 8) & 0x3));
+        outBuf[len+2+H_1] = (unsigned char)ucs4;
+	len += 4;
+      }
+    }
+
+    *outBufLen = len;
+    return PR_TRUE;
+  } else {
+    unsigned int i, len = 0;
+    PORT_Assert((inBufLen % 2) == 0);
+    if ((inBufLen % 2) != 0) {
+      *outBufLen = 0;
+      return PR_FALSE;
+    }
+
+    for( i = 0; i < inBufLen; i += 2 ) {
+      if( (inBuf[i+H_0] == 0x00) && ((inBuf[i+H_0] & 0x80) == 0x00) ) len += 1;
+      else if( inBuf[i+H_0] < 0x08 ) len += 2;
+      else if( ((inBuf[i+0+H_0] & 0xDC) == 0xD8) ) {
+        if( ((inBuf[i+2+H_0] & 0xDC) == 0xDC) && ((inBufLen - i) > 2) ) {
+          i += 2;
+          len += 4;
+        } else {
+          return PR_FALSE;
+        }
+      }
+      else len += 3;
+    }
+
+    if( len > maxOutBufLen ) {
+      *outBufLen = len;
+      return PR_FALSE;
+    }
+
+    len = 0;
+
+    for( i = 0; i < inBufLen; i += 2 ) {
+      if( (inBuf[i+H_0] == 0x00) && ((inBuf[i+H_1] & 0x80) == 0x00) ) {
+        /* 0000-007F -> 0xxxxxx */
+        /* 00000000 0abcdefg -> 0abcdefg */
+
+        outBuf[len] = inBuf[i+H_1] & 0x7F;
+
+        len += 1;
+      } else if( inBuf[i+H_0] < 0x08 ) {
+        /* 0080-07FF -> 110xxxxx 10xxxxxx */
+        /* 00000abc defghijk -> 110abcde 10fghijk */
+
+        outBuf[len+0] = 0xC0 | ((inBuf[i+H_0] & 0x07) << 2) 
+                             | ((inBuf[i+H_1] & 0xC0) >> 6);
+        outBuf[len+1] = 0x80 | ((inBuf[i+H_1] & 0x3F) >> 0);
+
+        len += 2;
+      } else if( (inBuf[i+H_0] & 0xDC) == 0xD8 ) {
+        int abcde, BCDE;
+
+        PORT_Assert(((inBuf[i+2+H_0] & 0xDC) == 0xDC) && ((inBufLen - i) > 2));
+
+        /* D800-DBFF DC00-DFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+        /* 110110BC DEfghijk 110111lm nopqrstu ->
+           { Let abcde = BCDE + 1 }
+           11110abc 10defghi 10jklmno 10pqrstu */
+
+        BCDE = ((inBuf[i+H_0] & 0x03) << 2) | ((inBuf[i+H_1] & 0xC0) >> 6);
+        abcde = BCDE + 1;
+
+        outBuf[len+0] = 0xF0 | ((abcde & 0x1C) >> 2);
+        outBuf[len+1] = 0x80 | ((abcde & 0x03) << 4) 
+                             | ((inBuf[i+0+H_1] & 0x3C) >> 2);
+        outBuf[len+2] = 0x80 | ((inBuf[i+0+H_1] & 0x03) << 4)
+                             | ((inBuf[i+2+H_0] & 0x03) << 2)
+                             | ((inBuf[i+2+H_1] & 0xC0) >> 6);
+        outBuf[len+3] = 0x80 | ((inBuf[i+2+H_1] & 0x3F) >> 0);
+
+        i += 2;
+        len += 4;
+      } else {
+        /* 0800-FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
+        /* abcdefgh ijklmnop -> 1110abcd 10efghij 10klmnop */
+
+        outBuf[len+0] = 0xE0 | ((inBuf[i+H_0] & 0xF0) >> 4);
+        outBuf[len+1] = 0x80 | ((inBuf[i+H_0] & 0x0F) << 2) 
+                             | ((inBuf[i+H_1] & 0xC0) >> 6);
+        outBuf[len+2] = 0x80 | ((inBuf[i+H_1] & 0x3F) >> 0);
+
+        len += 3;
+      }
+    }
+
+    *outBufLen = len;
+    return PR_TRUE;
+  }
+}
+
+PRBool
+sec_port_iso88591_utf8_conversion_function
+(
+  const unsigned char *inBuf,
+  unsigned int inBufLen,
+  unsigned char *outBuf,
+  unsigned int maxOutBufLen,
+  unsigned int *outBufLen
+)
+{
+  unsigned int i, len = 0;
+
+  PORT_Assert((unsigned int *)NULL != outBufLen);
+
+  for( i = 0; i < inBufLen; i++) {
+    if( (inBuf[i] & 0x80) == 0x00 ) len += 1;
+    else len += 2;
+  }
+
+  if( len > maxOutBufLen ) {
+    *outBufLen = len;
+    return PR_FALSE;
+  }
+
+  len = 0;
+
+  for( i = 0; i < inBufLen; i++) {
+    if( (inBuf[i] & 0x80) == 0x00 ) {
+      /* 00-7F -> 0xxxxxxx */
+      /* 0abcdefg -> 0abcdefg */
+
+      outBuf[len] = inBuf[i];
+      len += 1;
+    } else {
+      /* 80-FF <- 110xxxxx 10xxxxxx */
+      /* 00000000 abcdefgh -> 110000ab 10cdefgh */
+
+      outBuf[len+0] = 0xC0 | ((inBuf[i] & 0xC0) >> 6);
+      outBuf[len+1] = 0x80 | ((inBuf[i] & 0x3F) >> 0);
+
+      len += 2;
+    }
+  }
+
+  *outBufLen = len;
+  return PR_TRUE;
+}
+
+#ifdef TEST_UTF8
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h> /* for htonl and htons */
+
+/*
+ * UCS-4 vectors
+ */
+
+struct ucs4 {
+  PRUint32 c;
+  char *utf8;
+};
+
+/*
+ * UCS-2 vectors
+ */
+
+struct ucs2 {
+  PRUint16 c;
+  char *utf8;
+};
+
+/*
+ * UTF-16 vectors
+ */
+
+struct utf16 {
+  PRUint32 c;
+  PRUint16 w[2];
+};
+
+
+/*
+ * UCS-4 vectors
+ */
+
+struct ucs4 ucs4[] = {
+  { 0x00000001, "\x01" },
+  { 0x00000002, "\x02" },
+  { 0x00000003, "\x03" },
+  { 0x00000004, "\x04" },
+  { 0x00000007, "\x07" },
+  { 0x00000008, "\x08" },
+  { 0x0000000F, "\x0F" },
+  { 0x00000010, "\x10" },
+  { 0x0000001F, "\x1F" },
+  { 0x00000020, "\x20" },
+  { 0x0000003F, "\x3F" },
+  { 0x00000040, "\x40" },
+  { 0x0000007F, "\x7F" },
+          
+  { 0x00000080, "\xC2\x80" },
+  { 0x00000081, "\xC2\x81" },
+  { 0x00000082, "\xC2\x82" },
+  { 0x00000084, "\xC2\x84" },
+  { 0x00000088, "\xC2\x88" },
+  { 0x00000090, "\xC2\x90" },
+  { 0x000000A0, "\xC2\xA0" },
+  { 0x000000C0, "\xC3\x80" },
+  { 0x000000FF, "\xC3\xBF" },
+  { 0x00000100, "\xC4\x80" },
+  { 0x00000101, "\xC4\x81" },
+  { 0x00000102, "\xC4\x82" },
+  { 0x00000104, "\xC4\x84" },
+  { 0x00000108, "\xC4\x88" },
+  { 0x00000110, "\xC4\x90" },
+  { 0x00000120, "\xC4\xA0" },
+  { 0x00000140, "\xC5\x80" },
+  { 0x00000180, "\xC6\x80" },
+  { 0x000001FF, "\xC7\xBF" },
+  { 0x00000200, "\xC8\x80" },
+  { 0x00000201, "\xC8\x81" },
+  { 0x00000202, "\xC8\x82" },
+  { 0x00000204, "\xC8\x84" },
+  { 0x00000208, "\xC8\x88" },
+  { 0x00000210, "\xC8\x90" },
+  { 0x00000220, "\xC8\xA0" },
+  { 0x00000240, "\xC9\x80" },
+  { 0x00000280, "\xCA\x80" },
+  { 0x00000300, "\xCC\x80" },
+  { 0x000003FF, "\xCF\xBF" },
+  { 0x00000400, "\xD0\x80" },
+  { 0x00000401, "\xD0\x81" },
+  { 0x00000402, "\xD0\x82" },
+  { 0x00000404, "\xD0\x84" },
+  { 0x00000408, "\xD0\x88" },
+  { 0x00000410, "\xD0\x90" },
+  { 0x00000420, "\xD0\xA0" },
+  { 0x00000440, "\xD1\x80" },
+  { 0x00000480, "\xD2\x80" },
+  { 0x00000500, "\xD4\x80" },
+  { 0x00000600, "\xD8\x80" },
+  { 0x000007FF, "\xDF\xBF" },
+          
+  { 0x00000800, "\xE0\xA0\x80" },
+  { 0x00000801, "\xE0\xA0\x81" },
+  { 0x00000802, "\xE0\xA0\x82" },
+  { 0x00000804, "\xE0\xA0\x84" },
+  { 0x00000808, "\xE0\xA0\x88" },
+  { 0x00000810, "\xE0\xA0\x90" },
+  { 0x00000820, "\xE0\xA0\xA0" },
+  { 0x00000840, "\xE0\xA1\x80" },
+  { 0x00000880, "\xE0\xA2\x80" },
+  { 0x00000900, "\xE0\xA4\x80" },
+  { 0x00000A00, "\xE0\xA8\x80" },
+  { 0x00000C00, "\xE0\xB0\x80" },
+  { 0x00000FFF, "\xE0\xBF\xBF" },
+  { 0x00001000, "\xE1\x80\x80" },
+  { 0x00001001, "\xE1\x80\x81" },
+  { 0x00001002, "\xE1\x80\x82" },
+  { 0x00001004, "\xE1\x80\x84" },
+  { 0x00001008, "\xE1\x80\x88" },
+  { 0x00001010, "\xE1\x80\x90" },
+  { 0x00001020, "\xE1\x80\xA0" },
+  { 0x00001040, "\xE1\x81\x80" },
+  { 0x00001080, "\xE1\x82\x80" },
+  { 0x00001100, "\xE1\x84\x80" },
+  { 0x00001200, "\xE1\x88\x80" },
+  { 0x00001400, "\xE1\x90\x80" },
+  { 0x00001800, "\xE1\xA0\x80" },
+  { 0x00001FFF, "\xE1\xBF\xBF" },
+  { 0x00002000, "\xE2\x80\x80" },
+  { 0x00002001, "\xE2\x80\x81" },
+  { 0x00002002, "\xE2\x80\x82" },
+  { 0x00002004, "\xE2\x80\x84" },
+  { 0x00002008, "\xE2\x80\x88" },
+  { 0x00002010, "\xE2\x80\x90" },
+  { 0x00002020, "\xE2\x80\xA0" },
+  { 0x00002040, "\xE2\x81\x80" },
+  { 0x00002080, "\xE2\x82\x80" },
+  { 0x00002100, "\xE2\x84\x80" },
+  { 0x00002200, "\xE2\x88\x80" },
+  { 0x00002400, "\xE2\x90\x80" },
+  { 0x00002800, "\xE2\xA0\x80" },
+  { 0x00003000, "\xE3\x80\x80" },
+  { 0x00003FFF, "\xE3\xBF\xBF" },
+  { 0x00004000, "\xE4\x80\x80" },
+  { 0x00004001, "\xE4\x80\x81" },
+  { 0x00004002, "\xE4\x80\x82" },
+  { 0x00004004, "\xE4\x80\x84" },
+  { 0x00004008, "\xE4\x80\x88" },
+  { 0x00004010, "\xE4\x80\x90" },
+  { 0x00004020, "\xE4\x80\xA0" },
+  { 0x00004040, "\xE4\x81\x80" },
+  { 0x00004080, "\xE4\x82\x80" },
+  { 0x00004100, "\xE4\x84\x80" },
+  { 0x00004200, "\xE4\x88\x80" },
+  { 0x00004400, "\xE4\x90\x80" },
+  { 0x00004800, "\xE4\xA0\x80" },
+  { 0x00005000, "\xE5\x80\x80" },
+  { 0x00006000, "\xE6\x80\x80" },
+  { 0x00007FFF, "\xE7\xBF\xBF" },
+  { 0x00008000, "\xE8\x80\x80" },
+  { 0x00008001, "\xE8\x80\x81" },
+  { 0x00008002, "\xE8\x80\x82" },
+  { 0x00008004, "\xE8\x80\x84" },
+  { 0x00008008, "\xE8\x80\x88" },
+  { 0x00008010, "\xE8\x80\x90" },
+  { 0x00008020, "\xE8\x80\xA0" },
+  { 0x00008040, "\xE8\x81\x80" },
+  { 0x00008080, "\xE8\x82\x80" },
+  { 0x00008100, "\xE8\x84\x80" },
+  { 0x00008200, "\xE8\x88\x80" },
+  { 0x00008400, "\xE8\x90\x80" },
+  { 0x00008800, "\xE8\xA0\x80" },
+  { 0x00009000, "\xE9\x80\x80" },
+  { 0x0000A000, "\xEA\x80\x80" },
+  { 0x0000C000, "\xEC\x80\x80" },
+  { 0x0000FFFF, "\xEF\xBF\xBF" },
+          
+  { 0x00010000, "\xF0\x90\x80\x80" },
+  { 0x00010001, "\xF0\x90\x80\x81" },
+  { 0x00010002, "\xF0\x90\x80\x82" },
+  { 0x00010004, "\xF0\x90\x80\x84" },
+  { 0x00010008, "\xF0\x90\x80\x88" },
+  { 0x00010010, "\xF0\x90\x80\x90" },
+  { 0x00010020, "\xF0\x90\x80\xA0" },
+  { 0x00010040, "\xF0\x90\x81\x80" },
+  { 0x00010080, "\xF0\x90\x82\x80" },
+  { 0x00010100, "\xF0\x90\x84\x80" },
+  { 0x00010200, "\xF0\x90\x88\x80" },
+  { 0x00010400, "\xF0\x90\x90\x80" },
+  { 0x00010800, "\xF0\x90\xA0\x80" },
+  { 0x00011000, "\xF0\x91\x80\x80" },
+  { 0x00012000, "\xF0\x92\x80\x80" },
+  { 0x00014000, "\xF0\x94\x80\x80" },
+  { 0x00018000, "\xF0\x98\x80\x80" },
+  { 0x0001FFFF, "\xF0\x9F\xBF\xBF" },
+  { 0x00020000, "\xF0\xA0\x80\x80" },
+  { 0x00020001, "\xF0\xA0\x80\x81" },
+  { 0x00020002, "\xF0\xA0\x80\x82" },
+  { 0x00020004, "\xF0\xA0\x80\x84" },
+  { 0x00020008, "\xF0\xA0\x80\x88" },
+  { 0x00020010, "\xF0\xA0\x80\x90" },
+  { 0x00020020, "\xF0\xA0\x80\xA0" },
+  { 0x00020040, "\xF0\xA0\x81\x80" },
+  { 0x00020080, "\xF0\xA0\x82\x80" },
+  { 0x00020100, "\xF0\xA0\x84\x80" },
+  { 0x00020200, "\xF0\xA0\x88\x80" },
+  { 0x00020400, "\xF0\xA0\x90\x80" },
+  { 0x00020800, "\xF0\xA0\xA0\x80" },
+  { 0x00021000, "\xF0\xA1\x80\x80" },
+  { 0x00022000, "\xF0\xA2\x80\x80" },
+  { 0x00024000, "\xF0\xA4\x80\x80" },
+  { 0x00028000, "\xF0\xA8\x80\x80" },
+  { 0x00030000, "\xF0\xB0\x80\x80" },
+  { 0x0003FFFF, "\xF0\xBF\xBF\xBF" },
+  { 0x00040000, "\xF1\x80\x80\x80" },
+  { 0x00040001, "\xF1\x80\x80\x81" },
+  { 0x00040002, "\xF1\x80\x80\x82" },
+  { 0x00040004, "\xF1\x80\x80\x84" },
+  { 0x00040008, "\xF1\x80\x80\x88" },
+  { 0x00040010, "\xF1\x80\x80\x90" },
+  { 0x00040020, "\xF1\x80\x80\xA0" },
+  { 0x00040040, "\xF1\x80\x81\x80" },
+  { 0x00040080, "\xF1\x80\x82\x80" },
+  { 0x00040100, "\xF1\x80\x84\x80" },
+  { 0x00040200, "\xF1\x80\x88\x80" },
+  { 0x00040400, "\xF1\x80\x90\x80" },
+  { 0x00040800, "\xF1\x80\xA0\x80" },
+  { 0x00041000, "\xF1\x81\x80\x80" },
+  { 0x00042000, "\xF1\x82\x80\x80" },
+  { 0x00044000, "\xF1\x84\x80\x80" },
+  { 0x00048000, "\xF1\x88\x80\x80" },
+  { 0x00050000, "\xF1\x90\x80\x80" },
+  { 0x00060000, "\xF1\xA0\x80\x80" },
+  { 0x0007FFFF, "\xF1\xBF\xBF\xBF" },
+  { 0x00080000, "\xF2\x80\x80\x80" },
+  { 0x00080001, "\xF2\x80\x80\x81" },
+  { 0x00080002, "\xF2\x80\x80\x82" },
+  { 0x00080004, "\xF2\x80\x80\x84" },
+  { 0x00080008, "\xF2\x80\x80\x88" },
+  { 0x00080010, "\xF2\x80\x80\x90" },
+  { 0x00080020, "\xF2\x80\x80\xA0" },
+  { 0x00080040, "\xF2\x80\x81\x80" },
+  { 0x00080080, "\xF2\x80\x82\x80" },
+  { 0x00080100, "\xF2\x80\x84\x80" },
+  { 0x00080200, "\xF2\x80\x88\x80" },
+  { 0x00080400, "\xF2\x80\x90\x80" },
+  { 0x00080800, "\xF2\x80\xA0\x80" },
+  { 0x00081000, "\xF2\x81\x80\x80" },
+  { 0x00082000, "\xF2\x82\x80\x80" },
+  { 0x00084000, "\xF2\x84\x80\x80" },
+  { 0x00088000, "\xF2\x88\x80\x80" },
+  { 0x00090000, "\xF2\x90\x80\x80" },
+  { 0x000A0000, "\xF2\xA0\x80\x80" },
+  { 0x000C0000, "\xF3\x80\x80\x80" },
+  { 0x000FFFFF, "\xF3\xBF\xBF\xBF" },
+  { 0x00100000, "\xF4\x80\x80\x80" },
+  { 0x00100001, "\xF4\x80\x80\x81" },
+  { 0x00100002, "\xF4\x80\x80\x82" },
+  { 0x00100004, "\xF4\x80\x80\x84" },
+  { 0x00100008, "\xF4\x80\x80\x88" },
+  { 0x00100010, "\xF4\x80\x80\x90" },
+  { 0x00100020, "\xF4\x80\x80\xA0" },
+  { 0x00100040, "\xF4\x80\x81\x80" },
+  { 0x00100080, "\xF4\x80\x82\x80" },
+  { 0x00100100, "\xF4\x80\x84\x80" },
+  { 0x00100200, "\xF4\x80\x88\x80" },
+  { 0x00100400, "\xF4\x80\x90\x80" },
+  { 0x00100800, "\xF4\x80\xA0\x80" },
+  { 0x00101000, "\xF4\x81\x80\x80" },
+  { 0x00102000, "\xF4\x82\x80\x80" },
+  { 0x00104000, "\xF4\x84\x80\x80" },
+  { 0x00108000, "\xF4\x88\x80\x80" },
+  { 0x0010FFFF, "\xF4\x8F\xBF\xBF" },
+};
+
+/*
+ * UCS-2 vectors
+ */
+
+struct ucs2 ucs2[] = {
+  { 0x0001, "\x01" },
+  { 0x0002, "\x02" },
+  { 0x0003, "\x03" },
+  { 0x0004, "\x04" },
+  { 0x0007, "\x07" },
+  { 0x0008, "\x08" },
+  { 0x000F, "\x0F" },
+  { 0x0010, "\x10" },
+  { 0x001F, "\x1F" },
+  { 0x0020, "\x20" },
+  { 0x003F, "\x3F" },
+  { 0x0040, "\x40" },
+  { 0x007F, "\x7F" },
+          
+  { 0x0080, "\xC2\x80" },
+  { 0x0081, "\xC2\x81" },
+  { 0x0082, "\xC2\x82" },
+  { 0x0084, "\xC2\x84" },
+  { 0x0088, "\xC2\x88" },
+  { 0x0090, "\xC2\x90" },
+  { 0x00A0, "\xC2\xA0" },
+  { 0x00C0, "\xC3\x80" },
+  { 0x00FF, "\xC3\xBF" },
+  { 0x0100, "\xC4\x80" },
+  { 0x0101, "\xC4\x81" },
+  { 0x0102, "\xC4\x82" },
+  { 0x0104, "\xC4\x84" },
+  { 0x0108, "\xC4\x88" },
+  { 0x0110, "\xC4\x90" },
+  { 0x0120, "\xC4\xA0" },
+  { 0x0140, "\xC5\x80" },
+  { 0x0180, "\xC6\x80" },
+  { 0x01FF, "\xC7\xBF" },
+  { 0x0200, "\xC8\x80" },
+  { 0x0201, "\xC8\x81" },
+  { 0x0202, "\xC8\x82" },
+  { 0x0204, "\xC8\x84" },
+  { 0x0208, "\xC8\x88" },
+  { 0x0210, "\xC8\x90" },
+  { 0x0220, "\xC8\xA0" },
+  { 0x0240, "\xC9\x80" },
+  { 0x0280, "\xCA\x80" },
+  { 0x0300, "\xCC\x80" },
+  { 0x03FF, "\xCF\xBF" },
+  { 0x0400, "\xD0\x80" },
+  { 0x0401, "\xD0\x81" },
+  { 0x0402, "\xD0\x82" },
+  { 0x0404, "\xD0\x84" },
+  { 0x0408, "\xD0\x88" },
+  { 0x0410, "\xD0\x90" },
+  { 0x0420, "\xD0\xA0" },
+  { 0x0440, "\xD1\x80" },
+  { 0x0480, "\xD2\x80" },
+  { 0x0500, "\xD4\x80" },
+  { 0x0600, "\xD8\x80" },
+  { 0x07FF, "\xDF\xBF" },
+          
+  { 0x0800, "\xE0\xA0\x80" },
+  { 0x0801, "\xE0\xA0\x81" },
+  { 0x0802, "\xE0\xA0\x82" },
+  { 0x0804, "\xE0\xA0\x84" },
+  { 0x0808, "\xE0\xA0\x88" },
+  { 0x0810, "\xE0\xA0\x90" },
+  { 0x0820, "\xE0\xA0\xA0" },
+  { 0x0840, "\xE0\xA1\x80" },
+  { 0x0880, "\xE0\xA2\x80" },
+  { 0x0900, "\xE0\xA4\x80" },
+  { 0x0A00, "\xE0\xA8\x80" },
+  { 0x0C00, "\xE0\xB0\x80" },
+  { 0x0FFF, "\xE0\xBF\xBF" },
+  { 0x1000, "\xE1\x80\x80" },
+  { 0x1001, "\xE1\x80\x81" },
+  { 0x1002, "\xE1\x80\x82" },
+  { 0x1004, "\xE1\x80\x84" },
+  { 0x1008, "\xE1\x80\x88" },
+  { 0x1010, "\xE1\x80\x90" },
+  { 0x1020, "\xE1\x80\xA0" },
+  { 0x1040, "\xE1\x81\x80" },
+  { 0x1080, "\xE1\x82\x80" },
+  { 0x1100, "\xE1\x84\x80" },
+  { 0x1200, "\xE1\x88\x80" },
+  { 0x1400, "\xE1\x90\x80" },
+  { 0x1800, "\xE1\xA0\x80" },
+  { 0x1FFF, "\xE1\xBF\xBF" },
+  { 0x2000, "\xE2\x80\x80" },
+  { 0x2001, "\xE2\x80\x81" },
+  { 0x2002, "\xE2\x80\x82" },
+  { 0x2004, "\xE2\x80\x84" },
+  { 0x2008, "\xE2\x80\x88" },
+  { 0x2010, "\xE2\x80\x90" },
+  { 0x2020, "\xE2\x80\xA0" },
+  { 0x2040, "\xE2\x81\x80" },
+  { 0x2080, "\xE2\x82\x80" },
+  { 0x2100, "\xE2\x84\x80" },
+  { 0x2200, "\xE2\x88\x80" },
+  { 0x2400, "\xE2\x90\x80" },
+  { 0x2800, "\xE2\xA0\x80" },
+  { 0x3000, "\xE3\x80\x80" },
+  { 0x3FFF, "\xE3\xBF\xBF" },
+  { 0x4000, "\xE4\x80\x80" },
+  { 0x4001, "\xE4\x80\x81" },
+  { 0x4002, "\xE4\x80\x82" },
+  { 0x4004, "\xE4\x80\x84" },
+  { 0x4008, "\xE4\x80\x88" },
+  { 0x4010, "\xE4\x80\x90" },
+  { 0x4020, "\xE4\x80\xA0" },
+  { 0x4040, "\xE4\x81\x80" },
+  { 0x4080, "\xE4\x82\x80" },
+  { 0x4100, "\xE4\x84\x80" },
+  { 0x4200, "\xE4\x88\x80" },
+  { 0x4400, "\xE4\x90\x80" },
+  { 0x4800, "\xE4\xA0\x80" },
+  { 0x5000, "\xE5\x80\x80" },
+  { 0x6000, "\xE6\x80\x80" },
+  { 0x7FFF, "\xE7\xBF\xBF" },
+  { 0x8000, "\xE8\x80\x80" },
+  { 0x8001, "\xE8\x80\x81" },
+  { 0x8002, "\xE8\x80\x82" },
+  { 0x8004, "\xE8\x80\x84" },
+  { 0x8008, "\xE8\x80\x88" },
+  { 0x8010, "\xE8\x80\x90" },
+  { 0x8020, "\xE8\x80\xA0" },
+  { 0x8040, "\xE8\x81\x80" },
+  { 0x8080, "\xE8\x82\x80" },
+  { 0x8100, "\xE8\x84\x80" },
+  { 0x8200, "\xE8\x88\x80" },
+  { 0x8400, "\xE8\x90\x80" },
+  { 0x8800, "\xE8\xA0\x80" },
+  { 0x9000, "\xE9\x80\x80" },
+  { 0xA000, "\xEA\x80\x80" },
+  { 0xC000, "\xEC\x80\x80" },
+  { 0xFFFF, "\xEF\xBF\xBF" }
+
+};
+
+/*
+ * UTF-16 vectors
+ */
+
+struct utf16 utf16[] = {
+  { 0x00010000, { 0xD800, 0xDC00 } },
+  { 0x00010001, { 0xD800, 0xDC01 } },
+  { 0x00010002, { 0xD800, 0xDC02 } },
+  { 0x00010003, { 0xD800, 0xDC03 } },
+  { 0x00010004, { 0xD800, 0xDC04 } },
+  { 0x00010007, { 0xD800, 0xDC07 } },
+  { 0x00010008, { 0xD800, 0xDC08 } },
+  { 0x0001000F, { 0xD800, 0xDC0F } },
+  { 0x00010010, { 0xD800, 0xDC10 } },
+  { 0x0001001F, { 0xD800, 0xDC1F } },
+  { 0x00010020, { 0xD800, 0xDC20 } },
+  { 0x0001003F, { 0xD800, 0xDC3F } },
+  { 0x00010040, { 0xD800, 0xDC40 } },
+  { 0x0001007F, { 0xD800, 0xDC7F } },
+  { 0x00010080, { 0xD800, 0xDC80 } },
+  { 0x00010081, { 0xD800, 0xDC81 } },
+  { 0x00010082, { 0xD800, 0xDC82 } },
+  { 0x00010084, { 0xD800, 0xDC84 } },
+  { 0x00010088, { 0xD800, 0xDC88 } },
+  { 0x00010090, { 0xD800, 0xDC90 } },
+  { 0x000100A0, { 0xD800, 0xDCA0 } },
+  { 0x000100C0, { 0xD800, 0xDCC0 } },
+  { 0x000100FF, { 0xD800, 0xDCFF } },
+  { 0x00010100, { 0xD800, 0xDD00 } },
+  { 0x00010101, { 0xD800, 0xDD01 } },
+  { 0x00010102, { 0xD800, 0xDD02 } },
+  { 0x00010104, { 0xD800, 0xDD04 } },
+  { 0x00010108, { 0xD800, 0xDD08 } },
+  { 0x00010110, { 0xD800, 0xDD10 } },
+  { 0x00010120, { 0xD800, 0xDD20 } },
+  { 0x00010140, { 0xD800, 0xDD40 } },
+  { 0x00010180, { 0xD800, 0xDD80 } },
+  { 0x000101FF, { 0xD800, 0xDDFF } },
+  { 0x00010200, { 0xD800, 0xDE00 } },
+  { 0x00010201, { 0xD800, 0xDE01 } },
+  { 0x00010202, { 0xD800, 0xDE02 } },
+  { 0x00010204, { 0xD800, 0xDE04 } },
+  { 0x00010208, { 0xD800, 0xDE08 } },
+  { 0x00010210, { 0xD800, 0xDE10 } },
+  { 0x00010220, { 0xD800, 0xDE20 } },
+  { 0x00010240, { 0xD800, 0xDE40 } },
+  { 0x00010280, { 0xD800, 0xDE80 } },
+  { 0x00010300, { 0xD800, 0xDF00 } },
+  { 0x000103FF, { 0xD800, 0xDFFF } },
+  { 0x00010400, { 0xD801, 0xDC00 } },
+  { 0x00010401, { 0xD801, 0xDC01 } },
+  { 0x00010402, { 0xD801, 0xDC02 } },
+  { 0x00010404, { 0xD801, 0xDC04 } },
+  { 0x00010408, { 0xD801, 0xDC08 } },
+  { 0x00010410, { 0xD801, 0xDC10 } },
+  { 0x00010420, { 0xD801, 0xDC20 } },
+  { 0x00010440, { 0xD801, 0xDC40 } },
+  { 0x00010480, { 0xD801, 0xDC80 } },
+  { 0x00010500, { 0xD801, 0xDD00 } },
+  { 0x00010600, { 0xD801, 0xDE00 } },
+  { 0x000107FF, { 0xD801, 0xDFFF } },
+  { 0x00010800, { 0xD802, 0xDC00 } },
+  { 0x00010801, { 0xD802, 0xDC01 } },
+  { 0x00010802, { 0xD802, 0xDC02 } },
+  { 0x00010804, { 0xD802, 0xDC04 } },
+  { 0x00010808, { 0xD802, 0xDC08 } },
+  { 0x00010810, { 0xD802, 0xDC10 } },
+  { 0x00010820, { 0xD802, 0xDC20 } },
+  { 0x00010840, { 0xD802, 0xDC40 } },
+  { 0x00010880, { 0xD802, 0xDC80 } },
+  { 0x00010900, { 0xD802, 0xDD00 } },
+  { 0x00010A00, { 0xD802, 0xDE00 } },
+  { 0x00010C00, { 0xD803, 0xDC00 } },
+  { 0x00010FFF, { 0xD803, 0xDFFF } },
+  { 0x00011000, { 0xD804, 0xDC00 } },
+  { 0x00011001, { 0xD804, 0xDC01 } },
+  { 0x00011002, { 0xD804, 0xDC02 } },
+  { 0x00011004, { 0xD804, 0xDC04 } },
+  { 0x00011008, { 0xD804, 0xDC08 } },
+  { 0x00011010, { 0xD804, 0xDC10 } },
+  { 0x00011020, { 0xD804, 0xDC20 } },
+  { 0x00011040, { 0xD804, 0xDC40 } },
+  { 0x00011080, { 0xD804, 0xDC80 } },
+  { 0x00011100, { 0xD804, 0xDD00 } },
+  { 0x00011200, { 0xD804, 0xDE00 } },
+  { 0x00011400, { 0xD805, 0xDC00 } },
+  { 0x00011800, { 0xD806, 0xDC00 } },
+  { 0x00011FFF, { 0xD807, 0xDFFF } },
+  { 0x00012000, { 0xD808, 0xDC00 } },
+  { 0x00012001, { 0xD808, 0xDC01 } },
+  { 0x00012002, { 0xD808, 0xDC02 } },
+  { 0x00012004, { 0xD808, 0xDC04 } },
+  { 0x00012008, { 0xD808, 0xDC08 } },
+  { 0x00012010, { 0xD808, 0xDC10 } },
+  { 0x00012020, { 0xD808, 0xDC20 } },
+  { 0x00012040, { 0xD808, 0xDC40 } },
+  { 0x00012080, { 0xD808, 0xDC80 } },
+  { 0x00012100, { 0xD808, 0xDD00 } },
+  { 0x00012200, { 0xD808, 0xDE00 } },
+  { 0x00012400, { 0xD809, 0xDC00 } },
+  { 0x00012800, { 0xD80A, 0xDC00 } },
+  { 0x00013000, { 0xD80C, 0xDC00 } },
+  { 0x00013FFF, { 0xD80F, 0xDFFF } },
+  { 0x00014000, { 0xD810, 0xDC00 } },
+  { 0x00014001, { 0xD810, 0xDC01 } },
+  { 0x00014002, { 0xD810, 0xDC02 } },
+  { 0x00014004, { 0xD810, 0xDC04 } },
+  { 0x00014008, { 0xD810, 0xDC08 } },
+  { 0x00014010, { 0xD810, 0xDC10 } },
+  { 0x00014020, { 0xD810, 0xDC20 } },
+  { 0x00014040, { 0xD810, 0xDC40 } },
+  { 0x00014080, { 0xD810, 0xDC80 } },
+  { 0x00014100, { 0xD810, 0xDD00 } },
+  { 0x00014200, { 0xD810, 0xDE00 } },
+  { 0x00014400, { 0xD811, 0xDC00 } },
+  { 0x00014800, { 0xD812, 0xDC00 } },
+  { 0x00015000, { 0xD814, 0xDC00 } },
+  { 0x00016000, { 0xD818, 0xDC00 } },
+  { 0x00017FFF, { 0xD81F, 0xDFFF } },
+  { 0x00018000, { 0xD820, 0xDC00 } },
+  { 0x00018001, { 0xD820, 0xDC01 } },
+  { 0x00018002, { 0xD820, 0xDC02 } },
+  { 0x00018004, { 0xD820, 0xDC04 } },
+  { 0x00018008, { 0xD820, 0xDC08 } },
+  { 0x00018010, { 0xD820, 0xDC10 } },
+  { 0x00018020, { 0xD820, 0xDC20 } },
+  { 0x00018040, { 0xD820, 0xDC40 } },
+  { 0x00018080, { 0xD820, 0xDC80 } },
+  { 0x00018100, { 0xD820, 0xDD00 } },
+  { 0x00018200, { 0xD820, 0xDE00 } },
+  { 0x00018400, { 0xD821, 0xDC00 } },
+  { 0x00018800, { 0xD822, 0xDC00 } },
+  { 0x00019000, { 0xD824, 0xDC00 } },
+  { 0x0001A000, { 0xD828, 0xDC00 } },
+  { 0x0001C000, { 0xD830, 0xDC00 } },
+  { 0x0001FFFF, { 0xD83F, 0xDFFF } },
+  { 0x00020000, { 0xD840, 0xDC00 } },
+  { 0x00020001, { 0xD840, 0xDC01 } },
+  { 0x00020002, { 0xD840, 0xDC02 } },
+  { 0x00020004, { 0xD840, 0xDC04 } },
+  { 0x00020008, { 0xD840, 0xDC08 } },
+  { 0x00020010, { 0xD840, 0xDC10 } },
+  { 0x00020020, { 0xD840, 0xDC20 } },
+  { 0x00020040, { 0xD840, 0xDC40 } },
+  { 0x00020080, { 0xD840, 0xDC80 } },
+  { 0x00020100, { 0xD840, 0xDD00 } },
+  { 0x00020200, { 0xD840, 0xDE00 } },
+  { 0x00020400, { 0xD841, 0xDC00 } },
+  { 0x00020800, { 0xD842, 0xDC00 } },
+  { 0x00021000, { 0xD844, 0xDC00 } },
+  { 0x00022000, { 0xD848, 0xDC00 } },
+  { 0x00024000, { 0xD850, 0xDC00 } },
+  { 0x00028000, { 0xD860, 0xDC00 } },
+  { 0x0002FFFF, { 0xD87F, 0xDFFF } },
+  { 0x00030000, { 0xD880, 0xDC00 } },
+  { 0x00030001, { 0xD880, 0xDC01 } },
+  { 0x00030002, { 0xD880, 0xDC02 } },
+  { 0x00030004, { 0xD880, 0xDC04 } },
+  { 0x00030008, { 0xD880, 0xDC08 } },
+  { 0x00030010, { 0xD880, 0xDC10 } },
+  { 0x00030020, { 0xD880, 0xDC20 } },
+  { 0x00030040, { 0xD880, 0xDC40 } },
+  { 0x00030080, { 0xD880, 0xDC80 } },
+  { 0x00030100, { 0xD880, 0xDD00 } },
+  { 0x00030200, { 0xD880, 0xDE00 } },
+  { 0x00030400, { 0xD881, 0xDC00 } },
+  { 0x00030800, { 0xD882, 0xDC00 } },
+  { 0x00031000, { 0xD884, 0xDC00 } },
+  { 0x00032000, { 0xD888, 0xDC00 } },
+  { 0x00034000, { 0xD890, 0xDC00 } },
+  { 0x00038000, { 0xD8A0, 0xDC00 } },
+  { 0x0003FFFF, { 0xD8BF, 0xDFFF } },
+  { 0x00040000, { 0xD8C0, 0xDC00 } },
+  { 0x00040001, { 0xD8C0, 0xDC01 } },
+  { 0x00040002, { 0xD8C0, 0xDC02 } },
+  { 0x00040004, { 0xD8C0, 0xDC04 } },
+  { 0x00040008, { 0xD8C0, 0xDC08 } },
+  { 0x00040010, { 0xD8C0, 0xDC10 } },
+  { 0x00040020, { 0xD8C0, 0xDC20 } },
+  { 0x00040040, { 0xD8C0, 0xDC40 } },
+  { 0x00040080, { 0xD8C0, 0xDC80 } },
+  { 0x00040100, { 0xD8C0, 0xDD00 } },
+  { 0x00040200, { 0xD8C0, 0xDE00 } },
+  { 0x00040400, { 0xD8C1, 0xDC00 } },
+  { 0x00040800, { 0xD8C2, 0xDC00 } },
+  { 0x00041000, { 0xD8C4, 0xDC00 } },
+  { 0x00042000, { 0xD8C8, 0xDC00 } },
+  { 0x00044000, { 0xD8D0, 0xDC00 } },
+  { 0x00048000, { 0xD8E0, 0xDC00 } },
+  { 0x0004FFFF, { 0xD8FF, 0xDFFF } },
+  { 0x00050000, { 0xD900, 0xDC00 } },
+  { 0x00050001, { 0xD900, 0xDC01 } },
+  { 0x00050002, { 0xD900, 0xDC02 } },
+  { 0x00050004, { 0xD900, 0xDC04 } },
+  { 0x00050008, { 0xD900, 0xDC08 } },
+  { 0x00050010, { 0xD900, 0xDC10 } },
+  { 0x00050020, { 0xD900, 0xDC20 } },
+  { 0x00050040, { 0xD900, 0xDC40 } },
+  { 0x00050080, { 0xD900, 0xDC80 } },
+  { 0x00050100, { 0xD900, 0xDD00 } },
+  { 0x00050200, { 0xD900, 0xDE00 } },
+  { 0x00050400, { 0xD901, 0xDC00 } },
+  { 0x00050800, { 0xD902, 0xDC00 } },
+  { 0x00051000, { 0xD904, 0xDC00 } },
+  { 0x00052000, { 0xD908, 0xDC00 } },
+  { 0x00054000, { 0xD910, 0xDC00 } },
+  { 0x00058000, { 0xD920, 0xDC00 } },
+  { 0x00060000, { 0xD940, 0xDC00 } },
+  { 0x00070000, { 0xD980, 0xDC00 } },
+  { 0x0007FFFF, { 0xD9BF, 0xDFFF } },
+  { 0x00080000, { 0xD9C0, 0xDC00 } },
+  { 0x00080001, { 0xD9C0, 0xDC01 } },
+  { 0x00080002, { 0xD9C0, 0xDC02 } },
+  { 0x00080004, { 0xD9C0, 0xDC04 } },
+  { 0x00080008, { 0xD9C0, 0xDC08 } },
+  { 0x00080010, { 0xD9C0, 0xDC10 } },
+  { 0x00080020, { 0xD9C0, 0xDC20 } },
+  { 0x00080040, { 0xD9C0, 0xDC40 } },
+  { 0x00080080, { 0xD9C0, 0xDC80 } },
+  { 0x00080100, { 0xD9C0, 0xDD00 } },
+  { 0x00080200, { 0xD9C0, 0xDE00 } },
+  { 0x00080400, { 0xD9C1, 0xDC00 } },
+  { 0x00080800, { 0xD9C2, 0xDC00 } },
+  { 0x00081000, { 0xD9C4, 0xDC00 } },
+  { 0x00082000, { 0xD9C8, 0xDC00 } },
+  { 0x00084000, { 0xD9D0, 0xDC00 } },
+  { 0x00088000, { 0xD9E0, 0xDC00 } },
+  { 0x0008FFFF, { 0xD9FF, 0xDFFF } },
+  { 0x00090000, { 0xDA00, 0xDC00 } },
+  { 0x00090001, { 0xDA00, 0xDC01 } },
+  { 0x00090002, { 0xDA00, 0xDC02 } },
+  { 0x00090004, { 0xDA00, 0xDC04 } },
+  { 0x00090008, { 0xDA00, 0xDC08 } },
+  { 0x00090010, { 0xDA00, 0xDC10 } },
+  { 0x00090020, { 0xDA00, 0xDC20 } },
+  { 0x00090040, { 0xDA00, 0xDC40 } },
+  { 0x00090080, { 0xDA00, 0xDC80 } },
+  { 0x00090100, { 0xDA00, 0xDD00 } },
+  { 0x00090200, { 0xDA00, 0xDE00 } },
+  { 0x00090400, { 0xDA01, 0xDC00 } },
+  { 0x00090800, { 0xDA02, 0xDC00 } },
+  { 0x00091000, { 0xDA04, 0xDC00 } },
+  { 0x00092000, { 0xDA08, 0xDC00 } },
+  { 0x00094000, { 0xDA10, 0xDC00 } },
+  { 0x00098000, { 0xDA20, 0xDC00 } },
+  { 0x000A0000, { 0xDA40, 0xDC00 } },
+  { 0x000B0000, { 0xDA80, 0xDC00 } },
+  { 0x000C0000, { 0xDAC0, 0xDC00 } },
+  { 0x000D0000, { 0xDB00, 0xDC00 } },
+  { 0x000FFFFF, { 0xDBBF, 0xDFFF } },
+  { 0x0010FFFF, { 0xDBFF, 0xDFFF } }
+
+};
+
+/* illegal utf8 sequences */
+char *utf8_bad[] = {
+  "\xC0\x80",
+  "\xC1\xBF",
+  "\xE0\x80\x80",
+  "\xE0\x9F\xBF",
+  "\xF0\x80\x80\x80",
+  "\xF0\x8F\xBF\xBF",
+  "\xF4\x90\x80\x80",
+  "\xF7\xBF\xBF\xBF",
+  "\xF8\x80\x80\x80\x80",
+  "\xF8\x88\x80\x80\x80",
+  "\xF8\x92\x80\x80\x80",
+  "\xF8\x9F\xBF\xBF\xBF",
+  "\xF8\xA0\x80\x80\x80",
+  "\xF8\xA8\x80\x80\x80",
+  "\xF8\xB0\x80\x80\x80",
+  "\xF8\xBF\xBF\xBF\xBF",
+  "\xF9\x80\x80\x80\x88",
+  "\xF9\x84\x80\x80\x80",
+  "\xF9\xBF\xBF\xBF\xBF",
+  "\xFA\x80\x80\x80\x80",
+  "\xFA\x90\x80\x80\x80",
+  "\xFB\xBF\xBF\xBF\xBF",
+  "\xFC\x84\x80\x80\x80\x81",
+  "\xFC\x85\x80\x80\x80\x80",
+  "\xFC\x86\x80\x80\x80\x80",
+  "\xFC\x87\xBF\xBF\xBF\xBF",
+  "\xFC\x88\xA0\x80\x80\x80",
+  "\xFC\x89\x80\x80\x80\x80",
+  "\xFC\x8A\x80\x80\x80\x80",
+  "\xFC\x90\x80\x80\x80\x82",
+  "\xFD\x80\x80\x80\x80\x80",
+  "\xFD\xBF\xBF\xBF\xBF\xBF",
+  "\x80",
+  "\xC3",
+  "\xC3\xC3\x80",
+  "\xED\xA0\x80",
+  "\xED\xBF\x80",
+  "\xED\xBF\xBF",
+  "\xED\xA0\x80\xE0\xBF\xBF",
+};
+
+static void
+dump_utf8
+(
+  char *word,
+  unsigned char *utf8,
+  char *end
+)
+{
+  fprintf(stdout, "%s ", word);
+  for( ; *utf8; utf8++ ) {
+    fprintf(stdout, "%02.2x ", (unsigned int)*utf8);
+  }
+  fprintf(stdout, "%s", end);
+}
+
+static PRBool
+test_ucs4_chars
+(
+  void
+)
+{
+  PRBool rv = PR_TRUE;
+  int i;
+
+  for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+    struct ucs4 *e = &ucs4[i];
+    PRBool result;
+    unsigned char utf8[8];
+    unsigned int len = 0;
+    PRUint32 back = 0;
+
+    (void)memset(utf8, 0, sizeof(utf8));
+    
+    result = sec_port_ucs4_utf8_conversion_function(PR_FALSE, 
+      (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+    if( !result ) {
+      fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8\n", e->c);
+      rv = PR_FALSE;
+      continue;
+    }
+
+    if( (len >= sizeof(utf8)) ||
+        (strlen(e->utf8) != len) ||
+        (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+      fprintf(stdout, "Wrong conversion of UCS-4 0x%08.8x to UTF-8: ", e->c);
+      dump_utf8("expected", e->utf8, ", ");
+      dump_utf8("received", utf8, "\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+    result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+      utf8, len, (unsigned char *)&back, sizeof(back), &len);
+
+    if( !result ) {
+      dump_utf8("Failed to convert UTF-8", utf8, "to UCS-4\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+    if( (sizeof(back) != len) || (e->c != back) ) {
+      dump_utf8("Wrong conversion of UTF-8", utf8, " to UCS-4:");
+      fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back);
+      rv = PR_FALSE;
+      continue;
+    }
+  }
+
+  return rv;
+}
+
+static PRBool
+test_ucs2_chars
+(
+  void
+)
+{
+  PRBool rv = PR_TRUE;
+  int i;
+
+  for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+    struct ucs2 *e = &ucs2[i];
+    PRBool result;
+    unsigned char utf8[8];
+    unsigned int len = 0;
+    PRUint16 back = 0;
+
+    (void)memset(utf8, 0, sizeof(utf8));
+    
+    result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+      (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+    if( !result ) {
+      fprintf(stdout, "Failed to convert UCS-2 0x%04.4x to UTF-8\n", e->c);
+      rv = PR_FALSE;
+      continue;
+    }
+
+    if( (len >= sizeof(utf8)) ||
+        (strlen(e->utf8) != len) ||
+        (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+      fprintf(stdout, "Wrong conversion of UCS-2 0x%04.4x to UTF-8: ", e->c);
+      dump_utf8("expected", e->utf8, ", ");
+      dump_utf8("received", utf8, "\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+    result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+      utf8, len, (unsigned char *)&back, sizeof(back), &len);
+
+    if( !result ) {
+      dump_utf8("Failed to convert UTF-8", utf8, "to UCS-2\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+    if( (sizeof(back) != len) || (e->c != back) ) {
+      dump_utf8("Wrong conversion of UTF-8", utf8, "to UCS-2:");
+      fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back);
+      rv = PR_FALSE;
+      continue;
+    }
+  }
+
+  return rv;
+}
+
+static PRBool
+test_utf16_chars
+(
+  void
+)
+{
+  PRBool rv = PR_TRUE;
+  int i;
+
+  for( i = 0; i < sizeof(utf16)/sizeof(utf16[0]); i++ ) {
+    struct utf16 *e = &utf16[i];
+    PRBool result;
+    unsigned char utf8[8];
+    unsigned int len = 0;
+    PRUint32 back32 = 0;
+    PRUint16 back[2];
+
+    (void)memset(utf8, 0, sizeof(utf8));
+    
+    result = sec_port_ucs2_utf8_conversion_function(PR_FALSE, 
+      (unsigned char *)&e->w[0], sizeof(e->w), utf8, sizeof(utf8), &len);
+
+    if( !result ) {
+      fprintf(stdout, "Failed to convert UTF-16 0x%04.4x 0x%04.4x to UTF-8\n", 
+              e->w[0], e->w[1]);
+      rv = PR_FALSE;
+      continue;
+    }
+
+    result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+      utf8, len, (unsigned char *)&back32, sizeof(back32), &len);
+
+    if( 4 != len ) {
+      fprintf(stdout, "Failed to convert UTF-16 0x%04.4x 0x%04.4x to UTF-8: "
+              "unexpected len %d\n", e->w[0], e->w[1], len);
+      rv = PR_FALSE;
+      continue;
+    }
+
+    utf8[len] = '\0'; /* null-terminate for printing */
+
+    if( !result ) {
+      dump_utf8("Failed to convert UTF-8", utf8, "to UCS-4 (utf-16 test)\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+    if( (sizeof(back32) != len) || (e->c != back32) ) {
+      fprintf(stdout, "Wrong conversion of UTF-16 0x%04.4x 0x%04.4x ", 
+              e->w[0], e->w[1]);
+      dump_utf8("to UTF-8", utf8, "and then to UCS-4: ");
+      if( sizeof(back32) != len ) {
+        fprintf(stdout, "len is %d\n", len);
+      } else {
+        fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back32);
+      }
+      rv = PR_FALSE;
+      continue;
+    }
+
+    (void)memset(utf8, 0, sizeof(utf8));
+    back[0] = back[1] = 0;
+
+    result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+      (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+    if( !result ) {
+      fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8 (utf-16 test)\n",
+              e->c);
+      rv = PR_FALSE;
+      continue;
+    }
+
+    result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+      utf8, len, (unsigned char *)&back[0], sizeof(back), &len);
+
+    if( 4 != len ) {
+      fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8: "
+              "unexpected len %d\n", e->c, len);
+      rv = PR_FALSE;
+      continue;
+    }
+
+    utf8[len] = '\0'; /* null-terminate for printing */
+
+    if( !result ) {
+      dump_utf8("Failed to convert UTF-8", utf8, "to UTF-16\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+    if( (sizeof(back) != len) || (e->w[0] != back[0]) || (e->w[1] != back[1]) ) {
+      fprintf(stdout, "Wrong conversion of UCS-4 0x%08.8x to UTF-8", e->c);
+      dump_utf8("", utf8, "and then to UTF-16:");
+      if( sizeof(back) != len ) {
+        fprintf(stdout, "len is %d\n", len);
+      } else {
+        fprintf(stdout, "expected 0x%04.4x 0x%04.4x, received 0x%04.4x 0x%04.4xx\n",
+                e->w[0], e->w[1], back[0], back[1]);
+      }
+      rv = PR_FALSE;
+      continue;
+    }
+  }
+
+  return rv;
+}
+
+static PRBool
+test_utf8_bad_chars
+(
+  void
+)
+{
+  PRBool rv = PR_TRUE;
+  int i;
+
+  for( i = 0; i < sizeof(utf8_bad)/sizeof(utf8_bad[0]); i++ ) {
+    PRBool result;
+    unsigned char destbuf[30];
+    unsigned int len = 0;
+
+    result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+      (unsigned char *)utf8_bad[i], strlen(utf8_bad[i]), destbuf, sizeof(destbuf), &len);
+
+    if( result ) {
+      dump_utf8("Failed to detect bad UTF-8 string converting to UCS2: ", utf8_bad[i], "\n");
+      rv = PR_FALSE;
+      continue;
+    }
+    result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+      (unsigned char *)utf8_bad[i], strlen(utf8_bad[i]), destbuf, sizeof(destbuf), &len);
+
+    if( result ) {
+      dump_utf8("Failed to detect bad UTF-8 string converting to UCS4: ", utf8_bad[i], "\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+  }
+
+  return rv;
+}
+
+static PRBool
+test_iso88591_chars
+(
+  void
+)
+{
+  PRBool rv = PR_TRUE;
+  int i;
+
+  for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+    struct ucs2 *e = &ucs2[i];
+    PRBool result;
+    unsigned char iso88591;
+    unsigned char utf8[3];
+    unsigned int len = 0;
+
+    if (ntohs(e->c) > 0xFF) continue;
+
+    (void)memset(utf8, 0, sizeof(utf8));
+    iso88591 = ntohs(e->c);
+    
+    result = sec_port_iso88591_utf8_conversion_function(&iso88591,
+      1, utf8, sizeof(utf8), &len);
+
+    if( !result ) {
+      fprintf(stdout, "Failed to convert ISO-8859-1 0x%02.2x to UTF-8\n", iso88591);
+      rv = PR_FALSE;
+      continue;
+    }
+
+    if( (len >= sizeof(utf8)) ||
+        (strlen(e->utf8) != len) ||
+        (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+      fprintf(stdout, "Wrong conversion of ISO-8859-1 0x%02.2x to UTF-8: ", iso88591);
+      dump_utf8("expected", e->utf8, ", ");
+      dump_utf8("received", utf8, "\n");
+      rv = PR_FALSE;
+      continue;
+    }
+
+  }
+
+  return rv;
+}
+
+static PRBool
+test_zeroes
+(
+  void
+)
+{
+  PRBool rv = PR_TRUE;
+  PRBool result;
+  PRUint32 lzero = 0;
+  PRUint16 szero = 0;
+  unsigned char utf8[8];
+  unsigned int len = 0;
+  PRUint32 lback = 1;
+  PRUint16 sback = 1;
+
+  (void)memset(utf8, 1, sizeof(utf8));
+
+  result = sec_port_ucs4_utf8_conversion_function(PR_FALSE, 
+    (unsigned char *)&lzero, sizeof(lzero), utf8, sizeof(utf8), &len);
+
+  if( !result ) {
+    fprintf(stdout, "Failed to convert UCS-4 0x00000000 to UTF-8\n");
+    rv = PR_FALSE;
+  } else if( 1 != len ) {
+    fprintf(stdout, "Wrong conversion of UCS-4 0x00000000: len = %d\n", len);
+    rv = PR_FALSE;
+  } else if( '\0' != *utf8 ) {
+    fprintf(stdout, "Wrong conversion of UCS-4 0x00000000: expected 00 ,"
+            "received %02.2x\n", (unsigned int)*utf8);
+    rv = PR_FALSE;
+  }
+
+  result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+    "", 1, (unsigned char *)&lback, sizeof(lback), &len);
+
+  if( !result ) {
+    fprintf(stdout, "Failed to convert UTF-8 00 to UCS-4\n");
+    rv = PR_FALSE;
+  } else if( 4 != len ) {
+    fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-4: len = %d\n", len);
+    rv = PR_FALSE;
+  } else if( 0 != lback ) {
+    fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-4: "
+            "expected 0x00000000, received 0x%08.8x\n", lback);
+    rv = PR_FALSE;
+  }
+
+  (void)memset(utf8, 1, sizeof(utf8));
+
+  result = sec_port_ucs2_utf8_conversion_function(PR_FALSE, 
+    (unsigned char *)&szero, sizeof(szero), utf8, sizeof(utf8), &len);
+
+  if( !result ) {
+    fprintf(stdout, "Failed to convert UCS-2 0x0000 to UTF-8\n");
+    rv = PR_FALSE;
+  } else if( 1 != len ) {
+    fprintf(stdout, "Wrong conversion of UCS-2 0x0000: len = %d\n", len);
+    rv = PR_FALSE;
+  } else if( '\0' != *utf8 ) {
+    fprintf(stdout, "Wrong conversion of UCS-2 0x0000: expected 00 ,"
+            "received %02.2x\n", (unsigned int)*utf8);
+    rv = PR_FALSE;
+  }
+
+  result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+    "", 1, (unsigned char *)&sback, sizeof(sback), &len);
+
+  if( !result ) {
+    fprintf(stdout, "Failed to convert UTF-8 00 to UCS-2\n");
+    rv = PR_FALSE;
+  } else if( 2 != len ) {
+    fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-2: len = %d\n", len);
+    rv = PR_FALSE;
+  } else if( 0 != sback ) {
+    fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-2: "
+            "expected 0x0000, received 0x%04.4x\n", sback);
+    rv = PR_FALSE;
+  }
+
+  return rv;
+}
+
+static PRBool
+test_multichars
+(
+  void
+)
+{
+  int i;
+  unsigned int len, lenout;
+  PRUint32 *ucs4s;
+  char *ucs4_utf8;
+  PRUint16 *ucs2s;
+  char *ucs2_utf8;
+  void *tmp;
+  PRBool result;
+
+  ucs4s = (PRUint32 *)calloc(sizeof(ucs4)/sizeof(ucs4[0]), sizeof(PRUint32));
+  ucs2s = (PRUint16 *)calloc(sizeof(ucs2)/sizeof(ucs2[0]), sizeof(PRUint16));
+
+  if( ((PRUint32 *)NULL == ucs4s) || ((PRUint16 *)NULL == ucs2s) ) {
+    fprintf(stderr, "out of memory\n");
+    exit(1);
+  }
+
+  len = 0;
+  for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+    ucs4s[i] = ucs4[i].c;
+    len += strlen(ucs4[i].utf8);
+  }
+
+  ucs4_utf8 = (char *)malloc(len);
+
+  len = 0;
+  for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+    ucs2s[i] = ucs2[i].c;
+    len += strlen(ucs2[i].utf8);
+  }
+
+  ucs2_utf8 = (char *)malloc(len);
+
+  if( ((char *)NULL == ucs4_utf8) || ((char *)NULL == ucs2_utf8) ) {
+    fprintf(stderr, "out of memory\n");
+    exit(1);
+  }
+
+  *ucs4_utf8 = '\0';
+  for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+    strcat(ucs4_utf8, ucs4[i].utf8);
+  }
+
+  *ucs2_utf8 = '\0';
+  for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+    strcat(ucs2_utf8, ucs2[i].utf8);
+  }
+
+  /* UTF-8 -> UCS-4 */
+  len = sizeof(ucs4)/sizeof(ucs4[0]) * sizeof(PRUint32);
+  tmp = calloc(len, 1);
+  if( (void *)NULL == tmp ) {
+    fprintf(stderr, "out of memory\n");
+    exit(1);
+  }
+
+  result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+    ucs4_utf8, strlen(ucs4_utf8), tmp, len, &lenout);
+  if( !result ) {
+    fprintf(stdout, "Failed to convert much UTF-8 to UCS-4\n");
+    goto done;
+  }
+
+  if( lenout != len ) {
+    fprintf(stdout, "Unexpected length converting much UTF-8 to UCS-4\n");
+    goto loser;
+  }
+
+  if( 0 != memcmp(ucs4s, tmp, len) ) {
+    fprintf(stdout, "Wrong conversion of much UTF-8 to UCS-4\n");
+    goto loser;
+  }
+
+  free(tmp); tmp = (void *)NULL;
+
+  /* UCS-4 -> UTF-8 */
+  len = strlen(ucs4_utf8);
+  tmp = calloc(len, 1);
+  if( (void *)NULL == tmp ) {
+    fprintf(stderr, "out of memory\n");
+    exit(1);
+  }
+
+  result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+    (unsigned char *)ucs4s, sizeof(ucs4)/sizeof(ucs4[0]) * sizeof(PRUint32), 
+    tmp, len, &lenout);
+  if( !result ) {
+    fprintf(stdout, "Failed to convert much UCS-4 to UTF-8\n");
+    goto done;
+  }
+
+  if( lenout != len ) {
+    fprintf(stdout, "Unexpected length converting much UCS-4 to UTF-8\n");
+    goto loser;
+  }
+
+  if( 0 != strncmp(ucs4_utf8, tmp, len) ) {
+    fprintf(stdout, "Wrong conversion of much UCS-4 to UTF-8\n");
+    goto loser;
+  }
+
+  free(tmp); tmp = (void *)NULL;
+
+  /* UTF-8 -> UCS-2 */
+  len = sizeof(ucs2)/sizeof(ucs2[0]) * sizeof(PRUint16);
+  tmp = calloc(len, 1);
+  if( (void *)NULL == tmp ) {
+    fprintf(stderr, "out of memory\n");
+    exit(1);
+  }
+
+  result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+    ucs2_utf8, strlen(ucs2_utf8), tmp, len, &lenout);
+  if( !result ) {
+    fprintf(stdout, "Failed to convert much UTF-8 to UCS-2\n");
+    goto done;
+  }
+
+  if( lenout != len ) {
+    fprintf(stdout, "Unexpected length converting much UTF-8 to UCS-2\n");
+    goto loser;
+  }
+
+  if( 0 != memcmp(ucs2s, tmp, len) ) {
+    fprintf(stdout, "Wrong conversion of much UTF-8 to UCS-2\n");
+    goto loser;
+  }
+
+  free(tmp); tmp = (void *)NULL;
+
+  /* UCS-2 -> UTF-8 */
+  len = strlen(ucs2_utf8);
+  tmp = calloc(len, 1);
+  if( (void *)NULL == tmp ) {
+    fprintf(stderr, "out of memory\n");
+    exit(1);
+  }
+
+  result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+    (unsigned char *)ucs2s, sizeof(ucs2)/sizeof(ucs2[0]) * sizeof(PRUint16), 
+    tmp, len, &lenout);
+  if( !result ) {
+    fprintf(stdout, "Failed to convert much UCS-2 to UTF-8\n");
+    goto done;
+  }
+
+  if( lenout != len ) {
+    fprintf(stdout, "Unexpected length converting much UCS-2 to UTF-8\n");
+    goto loser;
+  }
+
+  if( 0 != strncmp(ucs2_utf8, tmp, len) ) {
+    fprintf(stdout, "Wrong conversion of much UCS-2 to UTF-8\n");
+    goto loser;
+  }
+
+  /* implement UTF16 */
+
+  result = PR_TRUE;
+  goto done;
+
+ loser:
+  result = PR_FALSE;
+ done:
+  free(ucs4s);
+  free(ucs4_utf8);
+  free(ucs2s);
+  free(ucs2_utf8);
+  if( (void *)NULL != tmp ) free(tmp);
+  return result;
+}
+
+void
+byte_order
+(
+  void
+)
+{
+  /*
+   * The implementation (now) expects the 16- and 32-bit characters
+   * to be in network byte order, not host byte order.  Therefore I
+   * have to byteswap all those test vectors above.  hton[ls] may be
+   * functions, so I have to do this dynamically.  If you want to 
+   * use this code to do host byte order conversions, just remove
+   * the call in main() to this function.
+   */
+
+  int i;
+
+  for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+    struct ucs4 *e = &ucs4[i];
+    e->c = htonl(e->c);
+  }
+
+  for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+    struct ucs2 *e = &ucs2[i];
+    e->c = htons(e->c);
+  }
+
+  for( i = 0; i < sizeof(utf16)/sizeof(utf16[0]); i++ ) {
+    struct utf16 *e = &utf16[i];
+    e->c = htonl(e->c);
+    e->w[0] = htons(e->w[0]);
+    e->w[1] = htons(e->w[1]);
+  }
+
+  return;
+}
+
+int
+main
+(
+  int argc,
+  char *argv[]
+)
+{
+  byte_order();
+
+  if( test_ucs4_chars() &&
+      test_ucs2_chars() &&
+      test_utf16_chars() &&
+      test_utf8_bad_chars() &&
+      test_iso88591_chars() &&
+      test_zeroes() &&
+      test_multichars() &&
+      PR_TRUE ) {
+    fprintf(stderr, "PASS\n");
+    return 1;
+  } else {
+    fprintf(stderr, "FAIL\n");
+    return 0;
+  }
+}
+
+#endif /* TEST_UTF8 */
diff --git a/mozilla/security/nss/lib/util/utilrename.h b/mozilla/security/nss/lib/util/utilrename.h
new file mode 100644
index 0000000..ee5ae67
--- /dev/null
+++ b/mozilla/security/nss/lib/util/utilrename.h
@@ -0,0 +1,194 @@
+/* ***** 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 Network Security Services libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * 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 ***** */
+
+/*
+ * utilrename.h - rename symbols moved from libnss3 to libnssutil3
+ *
+ */
+
+#ifndef _LIBUTIL_H_
+#define _LIBUTIL_H_ _LIBUTIL_H__Util
+
+#ifdef USE_UTIL_DIRECTLY
+
+/* functions moved from libnss3 */
+#define ATOB_AsciiToData ATOB_AsciiToData_Util
+#define ATOB_ConvertAsciiToItem ATOB_ConvertAsciiToItem_Util
+#define BTOA_ConvertItemToAscii BTOA_ConvertItemToAscii_Util
+#define BTOA_DataToAscii BTOA_DataToAscii_Util
+#define CERT_GenTime2FormattedAscii CERT_GenTime2FormattedAscii_Util
+#define DER_AsciiToTime DER_AsciiToTime_Util
+#define DER_DecodeTimeChoice DER_DecodeTimeChoice_Util
+#define DER_Encode DER_Encode_Util
+#define DER_EncodeTimeChoice DER_EncodeTimeChoice_Util
+#define DER_GeneralizedDayToAscii DER_GeneralizedDayToAscii_Util
+#define DER_GeneralizedTimeToTime DER_GeneralizedTimeToTime_Util
+#define DER_GetInteger DER_GetInteger_Util
+#define DER_Lengths DER_Lengths_Util
+#define DER_TimeChoiceDayToAscii DER_TimeChoiceDayToAscii_Util
+#define DER_TimeToGeneralizedTime DER_TimeToGeneralizedTime_Util
+#define DER_TimeToGeneralizedTimeArena DER_TimeToGeneralizedTimeArena_Util
+#define DER_TimeToUTCTime DER_TimeToUTCTime_Util
+#define DER_UTCDayToAscii DER_UTCDayToAscii_Util
+#define DER_UTCTimeToAscii DER_UTCTimeToAscii_Util
+#define DER_UTCTimeToTime DER_UTCTimeToTime_Util
+#define NSS_PutEnv NSS_PutEnv_Util
+#define NSSBase64_DecodeBuffer NSSBase64_DecodeBuffer_Util
+#define NSSBase64_EncodeItem NSSBase64_EncodeItem_Util
+#define NSSBase64Decoder_Create NSSBase64Decoder_Create_Util
+#define NSSBase64Decoder_Destroy NSSBase64Decoder_Destroy_Util
+#define NSSBase64Decoder_Update NSSBase64Decoder_Update_Util
+#define NSSBase64Encoder_Create NSSBase64Encoder_Create_Util
+#define NSSBase64Encoder_Destroy NSSBase64Encoder_Destroy_Util
+#define NSSBase64Encoder_Update NSSBase64Encoder_Update_Util
+#define NSSRWLock_Destroy NSSRWLock_Destroy_Util
+#define NSSRWLock_HaveWriteLock NSSRWLock_HaveWriteLock_Util
+#define NSSRWLock_LockRead NSSRWLock_LockRead_Util
+#define NSSRWLock_LockWrite NSSRWLock_LockWrite_Util
+#define NSSRWLock_New NSSRWLock_New_Util
+#define NSSRWLock_UnlockRead NSSRWLock_UnlockRead_Util
+#define NSSRWLock_UnlockWrite NSSRWLock_UnlockWrite_Util
+#define PORT_Alloc PORT_Alloc_Util
+#define PORT_ArenaAlloc PORT_ArenaAlloc_Util
+#define PORT_ArenaGrow PORT_ArenaGrow_Util
+#define PORT_ArenaMark PORT_ArenaMark_Util
+#define PORT_ArenaRelease PORT_ArenaRelease_Util
+#define PORT_ArenaStrdup PORT_ArenaStrdup_Util
+#define PORT_ArenaUnmark PORT_ArenaUnmark_Util
+#define PORT_ArenaZAlloc PORT_ArenaZAlloc_Util
+#define PORT_Free PORT_Free_Util
+#define PORT_FreeArena PORT_FreeArena_Util
+#define PORT_GetError PORT_GetError_Util
+#define PORT_NewArena PORT_NewArena_Util
+#define PORT_Realloc PORT_Realloc_Util
+#define PORT_SetError PORT_SetError_Util
+#define PORT_SetUCS2_ASCIIConversionFunction PORT_SetUCS2_ASCIIConversionFunction_Util
+#define PORT_SetUCS2_UTF8ConversionFunction PORT_SetUCS2_UTF8ConversionFunction_Util
+#define PORT_SetUCS4_UTF8ConversionFunction PORT_SetUCS4_UTF8ConversionFunction_Util
+#define PORT_Strdup PORT_Strdup_Util
+#define PORT_UCS2_ASCIIConversion PORT_UCS2_ASCIIConversion_Util
+#define PORT_UCS2_UTF8Conversion PORT_UCS2_UTF8Conversion_Util
+#define PORT_ZAlloc PORT_ZAlloc_Util
+#define PORT_ZFree PORT_ZFree_Util
+#define SEC_ASN1Decode SEC_ASN1Decode_Util
+#define SEC_ASN1DecodeInteger SEC_ASN1DecodeInteger_Util
+#define SEC_ASN1DecodeItem SEC_ASN1DecodeItem_Util
+#define SEC_ASN1DecoderAbort SEC_ASN1DecoderAbort_Util
+#define SEC_ASN1DecoderClearFilterProc SEC_ASN1DecoderClearFilterProc_Util
+#define SEC_ASN1DecoderClearNotifyProc SEC_ASN1DecoderClearNotifyProc_Util
+#define SEC_ASN1DecoderFinish SEC_ASN1DecoderFinish_Util
+#define SEC_ASN1DecoderSetFilterProc SEC_ASN1DecoderSetFilterProc_Util
+#define SEC_ASN1DecoderSetNotifyProc SEC_ASN1DecoderSetNotifyProc_Util
+#define SEC_ASN1DecoderStart SEC_ASN1DecoderStart_Util
+#define SEC_ASN1DecoderUpdate SEC_ASN1DecoderUpdate_Util
+#define SEC_ASN1Encode SEC_ASN1Encode_Util
+#define SEC_ASN1EncodeInteger SEC_ASN1EncodeInteger_Util
+#define SEC_ASN1EncodeItem SEC_ASN1EncodeItem_Util
+#define SEC_ASN1EncoderAbort SEC_ASN1EncoderAbort_Util
+#define SEC_ASN1EncoderClearNotifyProc SEC_ASN1EncoderClearNotifyProc_Util
+#define SEC_ASN1EncoderClearStreaming SEC_ASN1EncoderClearStreaming_Util
+#define SEC_ASN1EncoderClearTakeFromBuf SEC_ASN1EncoderClearTakeFromBuf_Util
+#define SEC_ASN1EncoderFinish SEC_ASN1EncoderFinish_Util
+#define SEC_ASN1EncoderSetNotifyProc SEC_ASN1EncoderSetNotifyProc_Util
+#define SEC_ASN1EncoderSetStreaming SEC_ASN1EncoderSetStreaming_Util
+#define SEC_ASN1EncoderSetTakeFromBuf SEC_ASN1EncoderSetTakeFromBuf_Util
+#define SEC_ASN1EncoderStart SEC_ASN1EncoderStart_Util
+#define SEC_ASN1EncoderUpdate SEC_ASN1EncoderUpdate_Util
+#define SEC_ASN1EncodeUnsignedInteger SEC_ASN1EncodeUnsignedInteger_Util
+#define SEC_ASN1LengthLength SEC_ASN1LengthLength_Util
+#define SEC_QuickDERDecodeItem SEC_QuickDERDecodeItem_Util
+#define SECITEM_AllocItem SECITEM_AllocItem_Util
+#define SECITEM_ArenaDupItem SECITEM_ArenaDupItem_Util
+#define SECITEM_CompareItem SECITEM_CompareItem_Util
+#define SECITEM_CopyItem SECITEM_CopyItem_Util
+#define SECITEM_DupItem SECITEM_DupItem_Util
+#define SECITEM_FreeItem SECITEM_FreeItem_Util
+#define SECITEM_ItemsAreEqual SECITEM_ItemsAreEqual_Util
+#define SECITEM_ZfreeItem SECITEM_ZfreeItem_Util
+#define SECOID_AddEntry SECOID_AddEntry_Util
+#define SECOID_CompareAlgorithmID SECOID_CompareAlgorithmID_Util
+#define SECOID_CopyAlgorithmID SECOID_CopyAlgorithmID_Util
+#define SECOID_DestroyAlgorithmID SECOID_DestroyAlgorithmID_Util
+#define SECOID_FindOID SECOID_FindOID_Util
+#define SECOID_FindOIDByTag SECOID_FindOIDByTag_Util
+#define SECOID_FindOIDTag SECOID_FindOIDTag_Util
+#define SECOID_FindOIDTagDescription SECOID_FindOIDTagDescription_Util
+#define SECOID_GetAlgorithmTag SECOID_GetAlgorithmTag_Util
+#define SECOID_SetAlgorithmID SECOID_SetAlgorithmID_Util
+#define SGN_CompareDigestInfo SGN_CompareDigestInfo_Util
+#define SGN_CopyDigestInfo SGN_CopyDigestInfo_Util
+#define SGN_CreateDigestInfo SGN_CreateDigestInfo_Util
+#define SGN_DestroyDigestInfo SGN_DestroyDigestInfo_Util
+
+/* templates moved from libnss3 */
+#define NSS_Get_SEC_AnyTemplate NSS_Get_SEC_AnyTemplate_Util
+#define NSS_Get_SEC_BitStringTemplate NSS_Get_SEC_BitStringTemplate_Util
+#define NSS_Get_SEC_BMPStringTemplate NSS_Get_SEC_BMPStringTemplate_Util
+#define NSS_Get_SEC_BooleanTemplate NSS_Get_SEC_BooleanTemplate_Util
+#define NSS_Get_SEC_GeneralizedTimeTemplate NSS_Get_SEC_GeneralizedTimeTemplate_Util
+#define NSS_Get_SEC_IA5StringTemplate NSS_Get_SEC_IA5StringTemplate_Util
+#define NSS_Get_SEC_IntegerTemplate NSS_Get_SEC_IntegerTemplate_Util
+#define NSS_Get_SEC_NullTemplate NSS_Get_SEC_NullTemplate_Util
+#define NSS_Get_SEC_ObjectIDTemplate NSS_Get_SEC_ObjectIDTemplate_Util
+#define NSS_Get_SEC_OctetStringTemplate NSS_Get_SEC_OctetStringTemplate_Util
+#define NSS_Get_SEC_PointerToAnyTemplate NSS_Get_SEC_PointerToAnyTemplate_Util
+#define NSS_Get_SEC_PointerToOctetStringTemplate NSS_Get_SEC_PointerToOctetStringTemplate_Util
+#define NSS_Get_SEC_SetOfAnyTemplate NSS_Get_SEC_SetOfAnyTemplate_Util
+#define NSS_Get_SEC_UTCTimeTemplate NSS_Get_SEC_UTCTimeTemplate_Util
+#define NSS_Get_SEC_UTF8StringTemplate NSS_Get_SEC_UTF8StringTemplate_Util
+#define NSS_Get_SECOID_AlgorithmIDTemplate NSS_Get_SECOID_AlgorithmIDTemplate_Util
+#define NSS_Get_sgn_DigestInfoTemplate NSS_Get_sgn_DigestInfoTemplate_Util
+#define SEC_AnyTemplate SEC_AnyTemplate_Util
+#define SEC_BitStringTemplate SEC_BitStringTemplate_Util
+#define SEC_BMPStringTemplate SEC_BMPStringTemplate_Util
+#define SEC_BooleanTemplate SEC_BooleanTemplate_Util
+#define SEC_GeneralizedTimeTemplate SEC_GeneralizedTimeTemplate_Util
+#define SEC_IA5StringTemplate SEC_IA5StringTemplate_Util
+#define SEC_IntegerTemplate SEC_IntegerTemplate_Util
+#define SEC_NullTemplate SEC_NullTemplate_Util
+#define SEC_ObjectIDTemplate SEC_ObjectIDTemplate_Util
+#define SEC_OctetStringTemplate SEC_OctetStringTemplate_Util
+#define SEC_PointerToAnyTemplate SEC_PointerToAnyTemplate_Util
+#define SEC_PointerToOctetStringTemplate SEC_PointerToOctetStringTemplate_Util
+#define SEC_SetOfAnyTemplate SEC_SetOfAnyTemplate_Util
+#define SEC_UTCTimeTemplate SEC_UTCTimeTemplate_Util
+#define SEC_UTF8StringTemplate SEC_UTF8StringTemplate_Util
+#define SECOID_AlgorithmIDTemplate SECOID_AlgorithmIDTemplate_Util
+#define sgn_DigestInfoTemplate sgn_DigestInfoTemplate_Util
+
+#endif /* USE_UTIL_DIRECTLY */
+
+#endif /* _LIBUTIL_H_ */
diff --git a/nss.gyp b/nss.gyp
new file mode 100644
index 0000000..3ed50ef
--- /dev/null
+++ b/nss.gyp
@@ -0,0 +1,676 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'configurations': {
+      'Debug': {
+        'defines': [
+          'DEBUG',
+          '_DEBUG',
+        ],
+      },
+      'Release': {
+        'defines': [
+          'NDEBUG',
+        ],
+      },
+    },
+    'conditions': [
+      ['OS=="win"', {
+        'configurations': {
+          'Common_Base': {
+            'msvs_configuration_attributes': {
+              # Do not compile NSPR and NSS with /D _UNICODE /D UNICODE.
+              'CharacterSet': '0'
+            }
+          }
+        },
+        'defines!': [
+          'WIN32_LEAN_AND_MEAN',
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'nspr',
+      'type': '<(library)',
+      'sources': [
+        'mozilla/nsprpub/lib/ds/plarena.c',
+        'mozilla/nsprpub/lib/ds/plarena.h',
+        'mozilla/nsprpub/lib/ds/plarenas.h',
+        'mozilla/nsprpub/lib/ds/plhash.c',
+        'mozilla/nsprpub/lib/ds/plhash.h',
+        'mozilla/nsprpub/lib/libc/include/plbase64.h',
+        'mozilla/nsprpub/lib/libc/include/plerror.h',
+        'mozilla/nsprpub/lib/libc/include/plgetopt.h',
+        'mozilla/nsprpub/lib/libc/include/plstr.h',
+        'mozilla/nsprpub/lib/libc/src/base64.c',
+        'mozilla/nsprpub/lib/libc/src/plerror.c',
+        'mozilla/nsprpub/lib/libc/src/plgetopt.c',
+        'mozilla/nsprpub/lib/libc/src/strcase.c',
+        'mozilla/nsprpub/lib/libc/src/strcat.c',
+        'mozilla/nsprpub/lib/libc/src/strchr.c',
+        'mozilla/nsprpub/lib/libc/src/strcmp.c',
+        'mozilla/nsprpub/lib/libc/src/strcpy.c',
+        'mozilla/nsprpub/lib/libc/src/strdup.c',
+        'mozilla/nsprpub/lib/libc/src/strlen.c',
+        'mozilla/nsprpub/lib/libc/src/strpbrk.c',
+        'mozilla/nsprpub/lib/libc/src/strstr.c',
+        'mozilla/nsprpub/lib/libc/src/strtok.c',
+        'mozilla/nsprpub/pr/include/md/prosdep.h',
+        'mozilla/nsprpub/pr/include/md/_darwin.cfg',
+        'mozilla/nsprpub/pr/include/md/_darwin.h',
+        'mozilla/nsprpub/pr/include/md/_pcos.h',
+        'mozilla/nsprpub/pr/include/md/_pth.h',
+        'mozilla/nsprpub/pr/include/md/_unixos.h',
+        'mozilla/nsprpub/pr/include/md/_unix_errors.h',
+        'mozilla/nsprpub/pr/include/md/_win32_errors.h',
+        'mozilla/nsprpub/pr/include/md/_win95.cfg',
+        'mozilla/nsprpub/pr/include/md/_win95.h',
+        'mozilla/nsprpub/pr/include/nspr.h',
+        'mozilla/nsprpub/pr/include/obsolete/pralarm.h',
+        'mozilla/nsprpub/pr/include/obsolete/probslet.h',
+        'mozilla/nsprpub/pr/include/obsolete/protypes.h',
+        'mozilla/nsprpub/pr/include/obsolete/prsem.h',
+        'mozilla/nsprpub/pr/include/pratom.h',
+        'mozilla/nsprpub/pr/include/prbit.h',
+        'mozilla/nsprpub/pr/include/prclist.h',
+        'mozilla/nsprpub/pr/include/prcmon.h',
+        'mozilla/nsprpub/pr/include/prcountr.h',
+        'mozilla/nsprpub/pr/include/prcpucfg.h',
+        'mozilla/nsprpub/pr/include/prcvar.h',
+        'mozilla/nsprpub/pr/include/prdtoa.h',
+        'mozilla/nsprpub/pr/include/prenv.h',
+        'mozilla/nsprpub/pr/include/prerr.h',
+        'mozilla/nsprpub/pr/include/prerror.h',
+        'mozilla/nsprpub/pr/include/prinet.h',
+        'mozilla/nsprpub/pr/include/prinit.h',
+        'mozilla/nsprpub/pr/include/prinrval.h',
+        'mozilla/nsprpub/pr/include/prio.h',
+        'mozilla/nsprpub/pr/include/pripcsem.h',
+        'mozilla/nsprpub/pr/include/private/pprio.h',
+        'mozilla/nsprpub/pr/include/private/pprmwait.h',
+        'mozilla/nsprpub/pr/include/private/pprthred.h',
+        'mozilla/nsprpub/pr/include/private/primpl.h',
+        'mozilla/nsprpub/pr/include/private/prpriv.h',
+        'mozilla/nsprpub/pr/include/prlink.h',
+        'mozilla/nsprpub/pr/include/prlock.h',
+        'mozilla/nsprpub/pr/include/prlog.h',
+        'mozilla/nsprpub/pr/include/prlong.h',
+        'mozilla/nsprpub/pr/include/prmem.h',
+        'mozilla/nsprpub/pr/include/prmon.h',
+        'mozilla/nsprpub/pr/include/prmwait.h',
+        'mozilla/nsprpub/pr/include/prnetdb.h',
+        'mozilla/nsprpub/pr/include/prolock.h',
+        'mozilla/nsprpub/pr/include/prpdce.h',
+        'mozilla/nsprpub/pr/include/prprf.h',
+        'mozilla/nsprpub/pr/include/prproces.h',
+        'mozilla/nsprpub/pr/include/prrng.h',
+        'mozilla/nsprpub/pr/include/prrwlock.h',
+        'mozilla/nsprpub/pr/include/prshm.h',
+        'mozilla/nsprpub/pr/include/prshma.h',
+        'mozilla/nsprpub/pr/include/prsystem.h',
+        'mozilla/nsprpub/pr/include/prthread.h',
+        'mozilla/nsprpub/pr/include/prtime.h',
+        'mozilla/nsprpub/pr/include/prtpool.h',
+        'mozilla/nsprpub/pr/include/prtrace.h',
+        'mozilla/nsprpub/pr/include/prtypes.h',
+        'mozilla/nsprpub/pr/include/prvrsion.h',
+        'mozilla/nsprpub/pr/include/prwin16.h',
+        'mozilla/nsprpub/pr/src/io/prdir.c',
+        'mozilla/nsprpub/pr/src/io/prfdcach.c',
+        'mozilla/nsprpub/pr/src/io/prfile.c',
+        'mozilla/nsprpub/pr/src/io/prio.c',
+        'mozilla/nsprpub/pr/src/io/priometh.c',
+        'mozilla/nsprpub/pr/src/io/pripv6.c',
+        'mozilla/nsprpub/pr/src/io/prlayer.c',
+        'mozilla/nsprpub/pr/src/io/prlog.c',
+        'mozilla/nsprpub/pr/src/io/prmapopt.c',
+        'mozilla/nsprpub/pr/src/io/prmmap.c',
+        'mozilla/nsprpub/pr/src/io/prmwait.c',
+        'mozilla/nsprpub/pr/src/io/prpolevt.c',
+        'mozilla/nsprpub/pr/src/io/prprf.c',
+        'mozilla/nsprpub/pr/src/io/prscanf.c',
+        'mozilla/nsprpub/pr/src/io/prsocket.c',
+        'mozilla/nsprpub/pr/src/io/prstdio.c',
+        'mozilla/nsprpub/pr/src/linking/prlink.c',
+        'mozilla/nsprpub/pr/src/malloc/prmalloc.c',
+        'mozilla/nsprpub/pr/src/malloc/prmem.c',
+        'mozilla/nsprpub/pr/src/md/prosdep.c',
+        'mozilla/nsprpub/pr/src/md/unix/darwin.c',
+        'mozilla/nsprpub/pr/src/md/unix/os_Darwin.s',
+        'mozilla/nsprpub/pr/src/md/unix/os_Darwin_ppc.s',
+        'mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86.s',
+        'mozilla/nsprpub/pr/src/md/unix/os_Darwin_x86_64.s',
+        'mozilla/nsprpub/pr/src/md/unix/unix.c',
+        'mozilla/nsprpub/pr/src/md/unix/unix_errors.c',
+        'mozilla/nsprpub/pr/src/md/unix/uxpoll.c',
+        'mozilla/nsprpub/pr/src/md/unix/uxproces.c',
+        'mozilla/nsprpub/pr/src/md/unix/uxrng.c',
+        'mozilla/nsprpub/pr/src/md/unix/uxshm.c',
+        'mozilla/nsprpub/pr/src/md/unix/uxwrap.c',
+        'mozilla/nsprpub/pr/src/md/windows/ntgc.c',
+        'mozilla/nsprpub/pr/src/md/windows/ntinrval.c',
+        'mozilla/nsprpub/pr/src/md/windows/ntmisc.c',
+        'mozilla/nsprpub/pr/src/md/windows/ntsec.c',
+        'mozilla/nsprpub/pr/src/md/windows/ntsem.c',
+        'mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c',
+        'mozilla/nsprpub/pr/src/md/windows/w32poll.c',
+        'mozilla/nsprpub/pr/src/md/windows/w32rng.c',
+        'mozilla/nsprpub/pr/src/md/windows/w32shm.c',
+        'mozilla/nsprpub/pr/src/md/windows/w95cv.c',
+        'mozilla/nsprpub/pr/src/md/windows/w95dllmain.c',
+        'mozilla/nsprpub/pr/src/md/windows/w95io.c',
+        'mozilla/nsprpub/pr/src/md/windows/w95sock.c',
+        'mozilla/nsprpub/pr/src/md/windows/w95thred.c',
+        'mozilla/nsprpub/pr/src/md/windows/win32_errors.c',
+        'mozilla/nsprpub/pr/src/memory/prseg.c',
+        'mozilla/nsprpub/pr/src/memory/prshm.c',
+        'mozilla/nsprpub/pr/src/memory/prshma.c',
+        'mozilla/nsprpub/pr/src/misc/pralarm.c',
+        'mozilla/nsprpub/pr/src/misc/pratom.c',
+        'mozilla/nsprpub/pr/src/misc/praton.c',
+        'mozilla/nsprpub/pr/src/misc/prcountr.c',
+        'mozilla/nsprpub/pr/src/misc/prdtoa.c',
+        'mozilla/nsprpub/pr/src/misc/prenv.c',
+        'mozilla/nsprpub/pr/src/misc/prerr.c',
+        'mozilla/nsprpub/pr/src/misc/prerror.c',
+        'mozilla/nsprpub/pr/src/misc/prerrortable.c',
+        'mozilla/nsprpub/pr/src/misc/prinit.c',
+        'mozilla/nsprpub/pr/src/misc/prinrval.c',
+        'mozilla/nsprpub/pr/src/misc/pripc.c',
+        'mozilla/nsprpub/pr/src/misc/pripcsem.c',
+        'mozilla/nsprpub/pr/src/misc/prlog2.c',
+        'mozilla/nsprpub/pr/src/misc/prlong.c',
+        'mozilla/nsprpub/pr/src/misc/prnetdb.c',
+        'mozilla/nsprpub/pr/src/misc/prolock.c',
+        'mozilla/nsprpub/pr/src/misc/prrng.c',
+        'mozilla/nsprpub/pr/src/misc/prsystem.c',
+        'mozilla/nsprpub/pr/src/misc/prthinfo.c',
+        'mozilla/nsprpub/pr/src/misc/prtime.c',
+        'mozilla/nsprpub/pr/src/misc/prtpool.c',
+        'mozilla/nsprpub/pr/src/misc/prtrace.c',
+        'mozilla/nsprpub/pr/src/pthreads/ptio.c',
+        'mozilla/nsprpub/pr/src/pthreads/ptmisc.c',
+        'mozilla/nsprpub/pr/src/pthreads/ptsynch.c',
+        'mozilla/nsprpub/pr/src/pthreads/ptthread.c',
+        'mozilla/nsprpub/pr/src/threads/combined/prucpu.c',
+        'mozilla/nsprpub/pr/src/threads/combined/prucv.c',
+        'mozilla/nsprpub/pr/src/threads/combined/prulock.c',
+        'mozilla/nsprpub/pr/src/threads/combined/prustack.c',
+        'mozilla/nsprpub/pr/src/threads/combined/pruthr.c',
+        'mozilla/nsprpub/pr/src/threads/prcmon.c',
+        'mozilla/nsprpub/pr/src/threads/prcthr.c',
+        'mozilla/nsprpub/pr/src/threads/prdump.c',
+        'mozilla/nsprpub/pr/src/threads/prmon.c',
+        'mozilla/nsprpub/pr/src/threads/prrwlock.c',
+        'mozilla/nsprpub/pr/src/threads/prsem.c',
+        'mozilla/nsprpub/pr/src/threads/prtpd.c',
+      ],
+      'defines': [
+        'FORCE_PR_LOG',
+      ],
+      'include_dirs': [
+        'mozilla/nsprpub/pr/include',
+        'mozilla/nsprpub/pr/include/private',
+        'mozilla/nsprpub/lib/ds',
+        'mozilla/nsprpub/lib/libc/include',
+      ],
+      'direct_dependent_settings': {
+        'defines': [
+          'NO_NSPR_10_SUPPORT',
+        ],
+        'include_dirs': [
+          'mozilla/nsprpub/pr/include',
+          'mozilla/nsprpub/lib/ds',
+          'mozilla/nsprpub/lib/libc/include',
+        ],
+      },
+      'conditions': [
+        ['OS=="win"', {
+          'defines': [
+            'XP_PC',
+            'WIN32',
+            'WIN95',
+            '_PR_GLOBAL_THREADS_ONLY',
+          ],
+          'sources/': [
+            ['exclude', '^mozilla/nsprpub/pr/src/md/unix/'],
+            ['exclude', '^mozilla/nsprpub/pr/src/pthreads/'],
+          ],
+          'conditions': [
+            ['target_arch=="ia32"', {
+              'defines': [
+                '_X86_',
+              ],
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'nss',
+      'type': '<(library)',
+      'sources': [
+        'mozilla/security/nss/lib/base/arena.c',
+        'mozilla/security/nss/lib/base/base.h',
+        'mozilla/security/nss/lib/base/baset.h',
+        'mozilla/security/nss/lib/base/error.c',
+        'mozilla/security/nss/lib/base/errorval.c',
+        'mozilla/security/nss/lib/base/hash.c',
+        'mozilla/security/nss/lib/base/hashops.c',
+        'mozilla/security/nss/lib/base/item.c',
+        'mozilla/security/nss/lib/base/libc.c',
+        'mozilla/security/nss/lib/base/list.c',
+        'mozilla/security/nss/lib/base/nssbase.h',
+        'mozilla/security/nss/lib/base/nssbaset.h',
+        'mozilla/security/nss/lib/base/nssutf8.c',
+        'mozilla/security/nss/lib/base/tracker.c',
+        'mozilla/security/nss/lib/certdb/alg1485.c',
+        'mozilla/security/nss/lib/certdb/cert.h',
+        'mozilla/security/nss/lib/certdb/certdb.c',
+        'mozilla/security/nss/lib/certdb/certdb.h',
+        'mozilla/security/nss/lib/certdb/certi.h',
+        'mozilla/security/nss/lib/certdb/certt.h',
+        'mozilla/security/nss/lib/certdb/certv3.c',
+        'mozilla/security/nss/lib/certdb/certxutl.c',
+        'mozilla/security/nss/lib/certdb/certxutl.h',
+        'mozilla/security/nss/lib/certdb/crl.c',
+        'mozilla/security/nss/lib/certdb/genname.c',
+        'mozilla/security/nss/lib/certdb/genname.h',
+        'mozilla/security/nss/lib/certdb/polcyxtn.c',
+        'mozilla/security/nss/lib/certdb/secname.c',
+        'mozilla/security/nss/lib/certdb/stanpcertdb.c',
+        'mozilla/security/nss/lib/certdb/xauthkid.c',
+        'mozilla/security/nss/lib/certdb/xbsconst.c',
+        'mozilla/security/nss/lib/certdb/xconst.c',
+        'mozilla/security/nss/lib/certdb/xconst.h',
+        'mozilla/security/nss/lib/certhigh/certhigh.c',
+        'mozilla/security/nss/lib/certhigh/certhtml.c',
+        'mozilla/security/nss/lib/certhigh/certreq.c',
+        'mozilla/security/nss/lib/certhigh/certvfy.c',
+        'mozilla/security/nss/lib/certhigh/crlv2.c',
+        'mozilla/security/nss/lib/certhigh/ocsp.c',
+        'mozilla/security/nss/lib/certhigh/ocsp.h',
+        'mozilla/security/nss/lib/certhigh/ocspi.h',
+        'mozilla/security/nss/lib/certhigh/ocspt.h',
+        'mozilla/security/nss/lib/certhigh/ocspti.h',
+        'mozilla/security/nss/lib/certhigh/xcrldist.c',
+        'mozilla/security/nss/lib/cryptohi/cryptohi.h',
+        'mozilla/security/nss/lib/cryptohi/cryptoht.h',
+        'mozilla/security/nss/lib/cryptohi/dsautil.c',
+        'mozilla/security/nss/lib/cryptohi/key.h',
+        'mozilla/security/nss/lib/cryptohi/keyhi.h',
+        'mozilla/security/nss/lib/cryptohi/keyi.h',
+        'mozilla/security/nss/lib/cryptohi/keyt.h',
+        'mozilla/security/nss/lib/cryptohi/keythi.h',
+        'mozilla/security/nss/lib/cryptohi/sechash.c',
+        'mozilla/security/nss/lib/cryptohi/seckey.c',
+        'mozilla/security/nss/lib/cryptohi/secsign.c',
+        'mozilla/security/nss/lib/cryptohi/secvfy.c',
+        'mozilla/security/nss/lib/dev/ckhelper.c',
+        'mozilla/security/nss/lib/dev/ckhelper.h',
+        'mozilla/security/nss/lib/dev/dev.h',
+        'mozilla/security/nss/lib/dev/devm.h',
+        'mozilla/security/nss/lib/dev/devslot.c',
+        'mozilla/security/nss/lib/dev/devt.h',
+        'mozilla/security/nss/lib/dev/devtm.h',
+        'mozilla/security/nss/lib/dev/devtoken.c',
+        'mozilla/security/nss/lib/dev/devutil.c',
+        'mozilla/security/nss/lib/dev/nssdev.h',
+        'mozilla/security/nss/lib/dev/nssdevt.h',
+        'mozilla/security/nss/lib/freebl/aeskeywrap.c',
+        'mozilla/security/nss/lib/freebl/alg2268.c',
+        'mozilla/security/nss/lib/freebl/alghmac.c',
+        'mozilla/security/nss/lib/freebl/alghmac.h',
+        'mozilla/security/nss/lib/freebl/arcfive.c',
+        'mozilla/security/nss/lib/freebl/arcfour.c',
+        'mozilla/security/nss/lib/freebl/blapi.h',
+        'mozilla/security/nss/lib/freebl/blapii.h',
+        'mozilla/security/nss/lib/freebl/blapit.h',
+        'mozilla/security/nss/lib/freebl/camellia.c',
+        'mozilla/security/nss/lib/freebl/camellia.h',
+        'mozilla/security/nss/lib/freebl/des.c',
+        'mozilla/security/nss/lib/freebl/des.h',
+        'mozilla/security/nss/lib/freebl/desblapi.c',
+        'mozilla/security/nss/lib/freebl/dh.c',
+        'mozilla/security/nss/lib/freebl/drbg.c',
+        'mozilla/security/nss/lib/freebl/dsa.c',
+        'mozilla/security/nss/lib/freebl/ec.c',
+        'mozilla/security/nss/lib/freebl/ec.h',
+        'mozilla/security/nss/lib/freebl/ecl/ec2.h',
+        'mozilla/security/nss/lib/freebl/ecl/ecl-curve.h',
+        'mozilla/security/nss/lib/freebl/ecl/ecl-exp.h',
+        'mozilla/security/nss/lib/freebl/ecl/ecl-priv.h',
+        'mozilla/security/nss/lib/freebl/ecl/ecl.c',
+        'mozilla/security/nss/lib/freebl/ecl/ecl.h',
+        'mozilla/security/nss/lib/freebl/ecl/ecl_curve.c',
+        'mozilla/security/nss/lib/freebl/ecl/ecl_gf.c',
+        'mozilla/security/nss/lib/freebl/ecl/ecl_mult.c',
+        'mozilla/security/nss/lib/freebl/ecl/ecp.h',
+        'mozilla/security/nss/lib/freebl/ecl/ecp_aff.c',
+        'mozilla/security/nss/lib/freebl/ecl/ecp_jac.c',
+        'mozilla/security/nss/lib/freebl/ecl/ecp_jm.c',
+        'mozilla/security/nss/lib/freebl/ecl/ecp_mont.c',
+        'mozilla/security/nss/lib/freebl/ecl/ec_naf.c',
+        'mozilla/security/nss/lib/freebl/hasht.h',
+        'mozilla/security/nss/lib/freebl/md2.c',
+        'mozilla/security/nss/lib/freebl/md5.c',
+        'mozilla/security/nss/lib/freebl/mpi/logtab.h',
+        'mozilla/security/nss/lib/freebl/mpi/mpcpucache.c',
+        'mozilla/security/nss/lib/freebl/mpi/mpi-config.h',
+        'mozilla/security/nss/lib/freebl/mpi/mpi-priv.h',
+        'mozilla/security/nss/lib/freebl/mpi/mpi.c',
+        'mozilla/security/nss/lib/freebl/mpi/mpi.h',
+        'mozilla/security/nss/lib/freebl/mpi/mpi_amd64.c',
+        'mozilla/security/nss/lib/freebl/mpi/mpi_x86_asm.c',
+        'mozilla/security/nss/lib/freebl/mpi/mplogic.c',
+        'mozilla/security/nss/lib/freebl/mpi/mplogic.h',
+        'mozilla/security/nss/lib/freebl/mpi/mpmontg.c',
+        'mozilla/security/nss/lib/freebl/mpi/mpprime.c',
+        'mozilla/security/nss/lib/freebl/mpi/mpprime.h',
+        'mozilla/security/nss/lib/freebl/mpi/mp_gf2m-priv.h',
+        'mozilla/security/nss/lib/freebl/mpi/mp_gf2m.c',
+        'mozilla/security/nss/lib/freebl/mpi/mp_gf2m.h',
+        'mozilla/security/nss/lib/freebl/mpi/primes.c',
+        'mozilla/security/nss/lib/freebl/pqg.c',
+        'mozilla/security/nss/lib/freebl/rawhash.c',
+        'mozilla/security/nss/lib/freebl/rijndael.c',
+        'mozilla/security/nss/lib/freebl/rijndael.h',
+        'mozilla/security/nss/lib/freebl/rijndael32.tab',
+        'mozilla/security/nss/lib/freebl/rsa.c',
+        'mozilla/security/nss/lib/freebl/sechash.h',
+        'mozilla/security/nss/lib/freebl/secmpi.h',
+        'mozilla/security/nss/lib/freebl/secrng.h',
+        'mozilla/security/nss/lib/freebl/seed.c',
+        'mozilla/security/nss/lib/freebl/seed.h',
+        'mozilla/security/nss/lib/freebl/sha256.h',
+        'mozilla/security/nss/lib/freebl/sha512.c',
+        'mozilla/security/nss/lib/freebl/sha_fast.c',
+        'mozilla/security/nss/lib/freebl/sha_fast.h',
+        'mozilla/security/nss/lib/freebl/shsign.h',
+        'mozilla/security/nss/lib/freebl/shvfy.c',
+        'mozilla/security/nss/lib/freebl/sysrand.c',
+        'mozilla/security/nss/lib/freebl/tlsprfalg.c',
+        'mozilla/security/nss/lib/freebl/unix_rand.c',
+        'mozilla/security/nss/lib/freebl/win_rand.c',
+        'mozilla/security/nss/lib/nss/nss.h',
+        'mozilla/security/nss/lib/nss/nssinit.c',
+        'mozilla/security/nss/lib/nss/nssrenam.h',
+        'mozilla/security/nss/lib/nss/nssver.c',
+        'mozilla/security/nss/lib/nss/utilwrap.c',
+        'mozilla/security/nss/lib/pk11wrap/debug_module.c',
+        'mozilla/security/nss/lib/pk11wrap/dev3hack.c',
+        'mozilla/security/nss/lib/pk11wrap/dev3hack.h',
+        'mozilla/security/nss/lib/pk11wrap/pk11akey.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11auth.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11cert.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11cxt.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11err.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11func.h',
+        'mozilla/security/nss/lib/pk11wrap/pk11kea.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11list.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11load.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11mech.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11merge.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11nobj.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11obj.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11pars.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11pbe.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11pk12.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11pqg.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11pqg.h',
+        'mozilla/security/nss/lib/pk11wrap/pk11priv.h',
+        'mozilla/security/nss/lib/pk11wrap/pk11pub.h',
+        'mozilla/security/nss/lib/pk11wrap/pk11sdr.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11sdr.h',
+        'mozilla/security/nss/lib/pk11wrap/pk11skey.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11slot.c',
+        'mozilla/security/nss/lib/pk11wrap/pk11util.c',
+        'mozilla/security/nss/lib/pk11wrap/secmod.h',
+        'mozilla/security/nss/lib/pk11wrap/secmodi.h',
+        'mozilla/security/nss/lib/pk11wrap/secmodti.h',
+        'mozilla/security/nss/lib/pk11wrap/secpkcs5.h',
+        'mozilla/security/nss/lib/pkcs7/certread.c',
+        'mozilla/security/nss/lib/pkcs7/p7common.c',
+        'mozilla/security/nss/lib/pkcs7/p7create.c',
+        'mozilla/security/nss/lib/pkcs7/p7decode.c',
+        'mozilla/security/nss/lib/pkcs7/p7encode.c',
+        'mozilla/security/nss/lib/pkcs7/p7local.c',
+        'mozilla/security/nss/lib/pkcs7/p7local.h',
+        'mozilla/security/nss/lib/pkcs7/pkcs7t.h',
+        'mozilla/security/nss/lib/pkcs7/secmime.c',
+        'mozilla/security/nss/lib/pkcs7/secmime.h',
+        'mozilla/security/nss/lib/pkcs7/secpkcs7.h',
+        'mozilla/security/nss/lib/pki/asymmkey.c',
+        'mozilla/security/nss/lib/pki/certdecode.c',
+        'mozilla/security/nss/lib/pki/certificate.c',
+        'mozilla/security/nss/lib/pki/cryptocontext.c',
+        'mozilla/security/nss/lib/pki/nsspki.h',
+        'mozilla/security/nss/lib/pki/nsspkit.h',
+        'mozilla/security/nss/lib/pki/pki.h',
+        'mozilla/security/nss/lib/pki/pki3hack.c',
+        'mozilla/security/nss/lib/pki/pki3hack.h',
+        'mozilla/security/nss/lib/pki/pkibase.c',
+        'mozilla/security/nss/lib/pki/pkim.h',
+        'mozilla/security/nss/lib/pki/pkistore.c',
+        'mozilla/security/nss/lib/pki/pkistore.h',
+        'mozilla/security/nss/lib/pki/pkit.h',
+        'mozilla/security/nss/lib/pki/pkitm.h',
+        'mozilla/security/nss/lib/pki/symmkey.c',
+        'mozilla/security/nss/lib/pki/tdcache.c',
+        'mozilla/security/nss/lib/pki/trustdomain.c',
+        'mozilla/security/nss/lib/pki1/nsspki1.h',
+        'mozilla/security/nss/lib/pki1/nsspki1t.h',
+        'mozilla/security/nss/lib/pki1/oiddata.h',
+        'mozilla/security/nss/lib/pki1/pki1.h',
+        'mozilla/security/nss/lib/pki1/pki1t.h',
+        'mozilla/security/nss/lib/smime/cms.h',
+        'mozilla/security/nss/lib/smime/cmslocal.h',
+        'mozilla/security/nss/lib/smime/cmsreclist.h',
+        'mozilla/security/nss/lib/smime/cmst.h',
+        'mozilla/security/nss/lib/smime/smime.h',
+        'mozilla/security/nss/lib/softoken/ecdecode.c',
+        'mozilla/security/nss/lib/softoken/fipsaudt.c',
+        'mozilla/security/nss/lib/softoken/fipstest.c',
+        'mozilla/security/nss/lib/softoken/fipstokn.c',
+        'mozilla/security/nss/lib/softoken/lgglue.c',
+        'mozilla/security/nss/lib/softoken/lgglue.h',
+        'mozilla/security/nss/lib/softoken/lowkey.c',
+        'mozilla/security/nss/lib/softoken/lowkeyi.h',
+        'mozilla/security/nss/lib/softoken/lowkeyti.h',
+        'mozilla/security/nss/lib/softoken/lowpbe.c',
+        'mozilla/security/nss/lib/softoken/lowpbe.h',
+        'mozilla/security/nss/lib/softoken/padbuf.c',
+        'mozilla/security/nss/lib/softoken/pk11init.h',
+        'mozilla/security/nss/lib/softoken/pk11pars.h',
+        'mozilla/security/nss/lib/softoken/pkcs11.c',
+        'mozilla/security/nss/lib/softoken/pkcs11c.c',
+        'mozilla/security/nss/lib/softoken/pkcs11i.h',
+        'mozilla/security/nss/lib/softoken/pkcs11ni.h',
+        'mozilla/security/nss/lib/softoken/pkcs11u.c',
+        'mozilla/security/nss/lib/softoken/rsawrapr.c',
+        'mozilla/security/nss/lib/softoken/sdb.c',
+        'mozilla/security/nss/lib/softoken/sdb.h',
+        'mozilla/security/nss/lib/softoken/secmodt.h',
+        'mozilla/security/nss/lib/softoken/sftkdb.c',
+        'mozilla/security/nss/lib/softoken/sftkdb.h',
+        'mozilla/security/nss/lib/softoken/sftkdbt.h',
+        'mozilla/security/nss/lib/softoken/sftkdbti.h',
+        'mozilla/security/nss/lib/softoken/sftkmod.c',
+        'mozilla/security/nss/lib/softoken/sftkpars.c',
+        'mozilla/security/nss/lib/softoken/sftkpars.h',
+        'mozilla/security/nss/lib/softoken/sftkpwd.c',
+        'mozilla/security/nss/lib/softoken/softkver.c',
+        'mozilla/security/nss/lib/softoken/softkver.h',
+        'mozilla/security/nss/lib/softoken/softoken.h',
+        'mozilla/security/nss/lib/softoken/softoknt.h',
+        'mozilla/security/nss/lib/softoken/tlsprf.c',
+        'mozilla/security/nss/lib/ssl/sslerr.h',
+        'mozilla/security/nss/lib/util/base64.h',
+        'mozilla/security/nss/lib/util/ciferfam.h',
+        'mozilla/security/nss/lib/util/derdec.c',
+        'mozilla/security/nss/lib/util/derenc.c',
+        'mozilla/security/nss/lib/util/dersubr.c',
+        'mozilla/security/nss/lib/util/dertime.c',
+        'mozilla/security/nss/lib/util/nssb64.h',
+        'mozilla/security/nss/lib/util/nssb64d.c',
+        'mozilla/security/nss/lib/util/nssb64e.c',
+        'mozilla/security/nss/lib/util/nssb64t.h',
+        'mozilla/security/nss/lib/util/nssilckt.h',
+        'mozilla/security/nss/lib/util/nssilock.c',
+        'mozilla/security/nss/lib/util/nssilock.h',
+        'mozilla/security/nss/lib/util/nsslocks.h',
+        'mozilla/security/nss/lib/util/nssrwlk.c',
+        'mozilla/security/nss/lib/util/nssrwlk.h',
+        'mozilla/security/nss/lib/util/nssrwlkt.h',
+        'mozilla/security/nss/lib/util/nssutil.h',
+        'mozilla/security/nss/lib/util/oidstring.c',
+        'mozilla/security/nss/lib/util/pkcs11.h',
+        'mozilla/security/nss/lib/util/pkcs11f.h',
+        'mozilla/security/nss/lib/util/pkcs11n.h',
+        'mozilla/security/nss/lib/util/pkcs11p.h',
+        'mozilla/security/nss/lib/util/pkcs11t.h',
+        'mozilla/security/nss/lib/util/pkcs11u.h',
+        'mozilla/security/nss/lib/util/portreg.c',
+        'mozilla/security/nss/lib/util/portreg.h',
+        'mozilla/security/nss/lib/util/quickder.c',
+        'mozilla/security/nss/lib/util/secalgid.c',
+        'mozilla/security/nss/lib/util/secasn1.h',
+        'mozilla/security/nss/lib/util/secasn1d.c',
+        'mozilla/security/nss/lib/util/secasn1e.c',
+        'mozilla/security/nss/lib/util/secasn1t.h',
+        'mozilla/security/nss/lib/util/secasn1u.c',
+        'mozilla/security/nss/lib/util/seccomon.h',
+        'mozilla/security/nss/lib/util/secder.h',
+        'mozilla/security/nss/lib/util/secdert.h',
+        'mozilla/security/nss/lib/util/secdig.c',
+        'mozilla/security/nss/lib/util/secdig.h',
+        'mozilla/security/nss/lib/util/secdigt.h',
+        'mozilla/security/nss/lib/util/secerr.h',
+        'mozilla/security/nss/lib/util/secinit.c',
+        'mozilla/security/nss/lib/util/secitem.c',
+        'mozilla/security/nss/lib/util/secitem.h',
+        'mozilla/security/nss/lib/util/secload.c',
+        'mozilla/security/nss/lib/util/secoid.c',
+        'mozilla/security/nss/lib/util/secoid.h',
+        'mozilla/security/nss/lib/util/secoidt.h',
+        'mozilla/security/nss/lib/util/secport.c',
+        'mozilla/security/nss/lib/util/secport.h',
+        'mozilla/security/nss/lib/util/sectime.c',
+        'mozilla/security/nss/lib/util/templates.c',
+        'mozilla/security/nss/lib/util/utf8.c',
+        'mozilla/security/nss/lib/util/utilrename.h',
+      ],
+      'sources!': [
+        # primes.c is included by mpprime.c.
+        'mozilla/security/nss/lib/freebl/mpi/primes.c',
+        # unix_rand.c and win_rand.c are included by sysrand.c.
+        'mozilla/security/nss/lib/freebl/unix_rand.c',
+        'mozilla/security/nss/lib/freebl/win_rand.c',
+        # debug_module.c is included by pk11load.c.
+        'mozilla/security/nss/lib/pk11wrap/debug_module.c',
+      ],
+      'defines': [
+        'NSS_ENABLE_ECC',
+        'USE_UTIL_DIRECTLY',
+        'MP_API_COMPATIBLE',
+        'RIJNDAEL_INCLUDE_TABLES',
+        'NSS_USE_STATIC_LIBS',
+        'SHLIB_VERSION=\"3\"',
+        'SOFTOKEN_SHLIB_VERSION=\"3\"',
+      ],
+      'defines!': [
+        # Regrettably, NSS can't be compiled with NO_NSPR_10_SUPPORT yet.
+        'NO_NSPR_10_SUPPORT',
+      ],
+      'include_dirs': [
+        'mozilla/security/nss/lib/base',
+        'mozilla/security/nss/lib/certdb',
+        'mozilla/security/nss/lib/certhigh',
+        'mozilla/security/nss/lib/cryptohi',
+        'mozilla/security/nss/lib/dev',
+        'mozilla/security/nss/lib/freebl',
+        'mozilla/security/nss/lib/freebl/ecl',
+        'mozilla/security/nss/lib/freebl/mpi',
+        'mozilla/security/nss/lib/nss',
+        'mozilla/security/nss/lib/pk11wrap',
+        'mozilla/security/nss/lib/pkcs7',
+        'mozilla/security/nss/lib/pki',
+        'mozilla/security/nss/lib/pki1',
+        'mozilla/security/nss/lib/smime',
+        'mozilla/security/nss/lib/softoken',
+        'mozilla/security/nss/lib/ssl',
+        'mozilla/security/nss/lib/util',
+      ],
+      'dependencies': [
+        'nspr',
+        '../sqlite/sqlite.gyp:sqlite',
+      ],
+      'direct_dependent_settings': {
+        'defines': [
+          'NO_NSPR_10_SUPPORT',
+          'NSS_USE_STATIC_LIBS',
+          'USE_UTIL_DIRECTLY',
+        ],
+        'include_dirs': [
+          'mozilla/nsprpub/pr/include',
+          'mozilla/nsprpub/lib/ds',
+          'mozilla/nsprpub/lib/libc/include',
+          'mozilla/security/nss/lib/base',
+          'mozilla/security/nss/lib/certdb',
+          'mozilla/security/nss/lib/certhigh',
+          'mozilla/security/nss/lib/cryptohi',
+          'mozilla/security/nss/lib/dev',
+          'mozilla/security/nss/lib/freebl',
+          'mozilla/security/nss/lib/freebl/ecl',
+          'mozilla/security/nss/lib/nss',
+          'mozilla/security/nss/lib/pk11wrap',
+          'mozilla/security/nss/lib/pkcs7',
+          'mozilla/security/nss/lib/pki',
+          'mozilla/security/nss/lib/pki1',
+          'mozilla/security/nss/lib/smime',
+          'mozilla/security/nss/lib/softoken',
+          'mozilla/security/nss/lib/util',
+        ],
+      },
+      'conditions': [
+        ['target_arch=="ia32"', {
+          'defines': [
+            'NSS_X86_OR_X64',
+            'NSS_X86',
+          ],
+          'sources/': [
+            ['exclude', 'amd64'],
+          ],
+        }],
+        ['OS=="win"', {
+          'defines': [
+            'XP_PC',
+            'WIN32',
+            '_WINDOWS',
+            'WIN95',
+            'SHLIB_SUFFIX=\"dll\"',
+            'SHLIB_PREFIX=\"\"',
+            'SOFTOKEN_LIB_NAME=\"softokn3.dll\"',
+          ],
+          'conditions': [
+            ['target_arch=="ia32"', {
+              'defines': [
+                '_X86_',
+                'MP_ASSEMBLY_MULTIPLY',
+                'MP_ASSEMBLY_SQUARE',
+                'MP_ASSEMBLY_DIV_2DX1D',
+                'MP_USE_UINT_DIGIT',
+                'MP_NO_MP_WORD',
+              ],
+            }],
+          ],
+        }],
+      ],
+    },
+  ],
+}
diff --git a/patches/nspr-static.patch b/patches/nspr-static.patch
new file mode 100644
index 0000000..06dc86c
--- /dev/null
+++ b/patches/nspr-static.patch
@@ -0,0 +1,202 @@
+Index: mozilla/nsprpub/pr/include/prtypes.h
+===================================================================
+RCS file: /cvsroot/mozilla/nsprpub/pr/include/prtypes.h,v
+retrieving revision 3.41
+diff -p -u -8 -r3.41 prtypes.h
+--- mozilla/nsprpub/pr/include/prtypes.h	6 May 2009 05:40:35 -0000	3.41
++++ mozilla/nsprpub/pr/include/prtypes.h	15 Jan 2010 01:23:40 -0000
+@@ -75,17 +75,33 @@
+ ** Example:
+ **   in dowhim.h
+ **     PR_EXTERN( void ) DoWhatIMean( void );
+ **   in dowhim.c
+ **     PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; }
+ **
+ **
+ ***********************************************************************/
+-#if defined(WIN32)
++#if 1  /* STATIC LIBRARIES */
++
++#define PR_EXPORT(__type) extern __type
++#define PR_EXPORT_DATA(__type) extern __type
++#define PR_IMPORT(__type) extern __type
++#define PR_IMPORT_DATA(__type) extern __type
++
++#define PR_EXTERN(__type) extern __type
++#define PR_IMPLEMENT(__type) __type
++#define PR_EXTERN_DATA(__type) extern __type
++#define PR_IMPLEMENT_DATA(__type) __type
++
++#define PR_CALLBACK
++#define PR_CALLBACK_DECL
++#define PR_STATIC_CALLBACK(__x) static __x
++
++#elif defined(WIN32)
+ 
+ #define PR_EXPORT(__type) extern __declspec(dllexport) __type
+ #define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+ #define PR_IMPORT(__type) __declspec(dllimport) __type
+ #define PR_IMPORT_DATA(__type) __declspec(dllimport) __type
+ 
+ #define PR_EXTERN(__type) extern __declspec(dllexport) __type
+ #define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+Index: mozilla/nsprpub/pr/src/md/windows/w95dllmain.c
+===================================================================
+RCS file: /cvsroot/mozilla/nsprpub/pr/src/md/windows/w95dllmain.c,v
+retrieving revision 3.8
+diff -p -u -8 -r3.8 w95dllmain.c
+--- mozilla/nsprpub/pr/src/md/windows/w95dllmain.c	25 Apr 2004 15:01:00 -0000	3.8
++++ mozilla/nsprpub/pr/src/md/windows/w95dllmain.c	15 Jan 2010 01:23:40 -0000
+@@ -30,16 +30,18 @@
+  * 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 ***** */
+ 
++#if 0  /* STATIC LIBRARIES.  See the end of w95thred.c. */
++
+ /*
+  * The DLL entry point (DllMain) for NSPR.
+  *
+  * This is used to detach threads that were automatically attached by
+  * nspr.
+  */
+ 
+ #include <windows.h>
+@@ -64,8 +66,10 @@ PRThread *me;
+                     _PRI_DetachThread();
+             }
+             break;
+         case DLL_PROCESS_DETACH:
+             break;
+     }
+     return TRUE;
+ }
++
++#endif
+Index: mozilla/nsprpub/pr/src/md/windows/w95thred.c
+===================================================================
+RCS file: /cvsroot/mozilla/nsprpub/pr/src/md/windows/w95thred.c,v
+retrieving revision 3.18
+diff -p -u -8 -r3.18 w95thred.c
+--- mozilla/nsprpub/pr/src/md/windows/w95thred.c	4 Feb 2009 23:44:01 -0000	3.18
++++ mozilla/nsprpub/pr/src/md/windows/w95thred.c	15 Jan 2010 01:23:40 -0000
+@@ -309,8 +309,115 @@ PRThread *thread;
+ 
+    	if (NULL == thread) {
+ 		thread = _PRI_AttachThread(
+             PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
+ 	}
+ 	PR_ASSERT(thread != NULL);
+ 	return thread;
+ }
++
++// The following code is from Chromium src/base/thread_local_storage_win.cc,
++// r11329.
++
++// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
++//
++// Redistribution and use in source and binary forms, with or without
++// modification, are permitted provided that the following conditions are
++// met:
++//
++//    * Redistributions of source code must retain the above copyright
++// notice, this list of conditions and the following disclaimer.
++//    * Redistributions in binary form must reproduce the above
++// copyright notice, this list of conditions and the following disclaimer
++// in the documentation and/or other materials provided with the
++// distribution.
++//    * Neither the name of Google Inc. nor the names of its
++// contributors may be used to endorse or promote products derived from
++// this software without specific prior written permission.
++//
++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++// Thread Termination Callbacks.
++// Windows doesn't support a per-thread destructor with its
++// TLS primitives.  So, we build it manually by inserting a
++// function to be called on each thread's exit.
++// This magic is from http://www.codeproject.com/threads/tls.asp
++// and it works for VC++ 7.0 and later.
++
++#ifdef _WIN64
++
++// This makes the linker create the TLS directory if it's not already
++// there.  (e.g. if __declspec(thread) is not used).
++#pragma comment(linker, "/INCLUDE:_tls_used")
++
++#else  // _WIN64
++
++// This makes the linker create the TLS directory if it's not already
++// there.  (e.g. if __declspec(thread) is not used).
++#pragma comment(linker, "/INCLUDE:__tls_used")
++
++#endif  // _WIN64
++
++// Static callback function to call with each thread termination.
++static void NTAPI PR_OnThreadExit(PVOID module, DWORD reason, PVOID reserved)
++{
++PRThread *me;
++
++    switch (reason) {
++        case DLL_PROCESS_ATTACH:
++            break;
++        case DLL_THREAD_ATTACH:
++            break;
++        case DLL_THREAD_DETACH:
++            if (_pr_initialized) {
++                me = _MD_GET_ATTACHED_THREAD();
++                if ((me != NULL) && (me->flags & _PR_ATTACHED))
++                    _PRI_DetachThread();
++            }
++            break;
++        case DLL_PROCESS_DETACH:
++            break;
++    }
++}
++
++// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
++// called automatically by the OS loader code (not the CRT) when the module is
++// loaded and on thread creation. They are NOT called if the module has been
++// loaded by a LoadLibrary() call. It must have implicitly been loaded at
++// process startup.
++// By implicitly loaded, I mean that it is directly referenced by the main EXE
++// or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
++// implicitly loaded.
++//
++// See VC\crt\src\tlssup.c for reference.
++#ifdef _WIN64
++
++// .CRT section is merged with .rdata on x64 so it must be constant data.
++#pragma const_seg(".CRT$XLB")
++// When defining a const variable, it must have external linkage to be sure the
++// linker doesn't discard it. If this value is discarded, the PR_OnThreadExit
++// function will never be called.
++extern const PIMAGE_TLS_CALLBACK p_thread_callback;
++const PIMAGE_TLS_CALLBACK p_thread_callback = PR_OnThreadExit;
++
++// Reset the default section.
++#pragma const_seg()
++
++#else  // _WIN64
++
++#pragma data_seg(".CRT$XLB")
++PIMAGE_TLS_CALLBACK p_thread_callback = PR_OnThreadExit;
++
++// Reset the default section.
++#pragma data_seg()
++
++#endif  // _WIN64
diff --git a/patches/nspr-warnings.patch b/patches/nspr-warnings.patch
new file mode 100644
index 0000000..c819304
--- /dev/null
+++ b/patches/nspr-warnings.patch
@@ -0,0 +1,89 @@
+Index: mozilla/nsprpub/pr/include/prlog.h
+===================================================================
+RCS file: /cvsroot/mozilla/nsprpub/pr/include/prlog.h,v
+retrieving revision 3.16
+diff -p -u -8 -r3.16 prlog.h
+--- mozilla/nsprpub/pr/include/prlog.h	22 Feb 2009 19:56:13 -0000	3.16
++++ mozilla/nsprpub/pr/include/prlog.h	15 Jan 2010 01:33:24 -0000
+@@ -184,16 +184,18 @@ NSPR_API(void) PR_SetLogBuffering(PRIntn
+ */
+ NSPR_API(void) PR_LogPrint(const char *fmt, ...);
+ 
+ /*
+ ** Flush the log to its file.
+ */
+ NSPR_API(void) PR_LogFlush(void);
+ 
++NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln);
++
+ #if defined(DEBUG) || defined(FORCE_PR_LOG)
+ #define PR_LOGGING 1
+ 
+ #define PR_LOG_TEST(_module,_level) \
+     ((_module)->level >= (_level))
+ 
+ /*
+ ** Log something.
+@@ -228,17 +230,16 @@ NSPR_API(void) PR_LogFlush(void);
+ #define PR_LOG_END(module,level,args)
+ #define PR_LOG_DEFINE(_name)    NULL
+ #endif /* PR_LOGGING */
+ 
+ #endif /* NO_NSPR_10_SUPPORT */
+ 
+ #if defined(DEBUG) || defined(FORCE_PR_ASSERT)
+ 
+-NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln);
+ #define PR_ASSERT(_expr) \
+     ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__))
+ 
+ #define PR_NOT_REACHED(_reasonStr) \
+     PR_Assert(_reasonStr,__FILE__,__LINE__)
+ 
+ #else
+ 
+Index: mozilla/nsprpub/pr/src/md/windows/w95sock.c
+===================================================================
+RCS file: /cvsroot/mozilla/nsprpub/pr/src/md/windows/w95sock.c,v
+retrieving revision 3.16
+diff -p -u -8 -r3.16 w95sock.c
+--- mozilla/nsprpub/pr/src/md/windows/w95sock.c	4 Feb 2009 23:44:01 -0000	3.16
++++ mozilla/nsprpub/pr/src/md/windows/w95sock.c	15 Jan 2010 01:33:24 -0000
+@@ -67,17 +67,17 @@ static PRInt32 socket_io_wait(
+ 
+ typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID {
+     WsaBehaviorAll = 0,
+     WsaBehaviorReceiveBuffering,
+     WsaBehaviorAutoTuning
+ } WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID;
+ 
+ /* from sdkddkver.h */
+-#define NTDDI_LONGHORN                      0x06000000
++#define NTDDI_WIN6              0x06000000  /* Windows Vista */
+ 
+ /* from winsock2.h */
+ #define WSAEVENT                HANDLE
+ 
+ #define WSAOVERLAPPED           OVERLAPPED
+ typedef struct _OVERLAPPED *    LPWSAOVERLAPPED;
+ 
+ typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(
+@@ -170,17 +170,17 @@ _PR_MD_SOCKET(int af, int type, int flag
+     if ((af == AF_INET || af == AF_INET6) && 
+         type == SOCK_STREAM && socketSetCompatMode)
+     {
+         WSA_COMPATIBILITY_MODE mode;
+         char dummy[4];
+         int ret_dummy;
+ 
+         mode.BehaviorId = WsaBehaviorAutoTuning;
+-        mode.TargetOsVersion = NTDDI_LONGHORN;
++        mode.TargetOsVersion = NTDDI_WIN6;
+         if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE,  
+                          (char *)&mode, sizeof(mode),
+                          dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR)
+         {
+             int err = WSAGetLastError();
+             PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err));
+ 
+             /* SIO_SET_COMPATIBILITY_MODE may not be supported.
diff --git a/patches/nss-dertime.patch b/patches/nss-dertime.patch
new file mode 100644
index 0000000..8df9063
--- /dev/null
+++ b/patches/nss-dertime.patch
@@ -0,0 +1,83 @@
+Index: mozilla/security/nss/lib/util/dertime.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/util/dertime.c,v
+retrieving revision 1.13
+diff -u -p -u -8 -r1.13 dertime.c
+--- mozilla/security/nss/lib/util/dertime.c	29 Dec 2009 02:57:28 -0000	1.13
++++ mozilla/security/nss/lib/util/dertime.c	21 Jan 2010 22:34:30 -0000
+@@ -108,17 +108,17 @@ DER_TimeToUTCTimeArena(PRArenaPool* aren
+ SECStatus
+ DER_TimeToUTCTime(SECItem *dst, int64 gmttime)
+ {
+     return DER_TimeToUTCTimeArena(NULL, dst, gmttime);
+ }
+ 
+ static SECStatus /* forward */
+ der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
+-                     char **endptr);
++                     const char **endptr);
+ 
+ #define GEN_STRING 2 /* TimeString is a GeneralizedTime */
+ #define UTC_STRING 0 /* TimeString is a UTCTime         */
+ 
+ /* The caller of DER_AsciiToItem MUST ENSURE that either
+ ** a) "string" points to a null-terminated ASCII string, or
+ ** b) "string" points to a buffer containing a valid UTCTime, 
+ **     whether null terminated or not, or
+@@ -136,17 +136,17 @@ SECStatus
+ DER_UTCTimeToTime(int64 *dst, const SECItem *time)
+ {
+     /* Minimum valid UTCTime is yymmddhhmmZ       which is 11 bytes. 
+     ** Maximum valid UTCTime is yymmddhhmmss+0000 which is 17 bytes.
+     ** 20 should be large enough for all valid encoded times. 
+     */
+     unsigned int i;
+     char localBuf[20];
+-    char *end = NULL;
++    const char *end = NULL;
+     SECStatus rv;
+ 
+     if (!time || !time->data || time->len < 11 || time->len > 17) {
+ 	PORT_SetError(SEC_ERROR_INVALID_TIME);
+ 	return SECFailure;
+     }
+ 
+     for (i = 0; i < time->len; i++) {
+@@ -230,17 +230,17 @@ SECStatus
+ DER_GeneralizedTimeToTime(int64 *dst, const SECItem *time)
+ {
+     /* Minimum valid GeneralizedTime is ccyymmddhhmmZ       which is 13 bytes.
+     ** Maximum valid GeneralizedTime is ccyymmddhhmmss+0000 which is 19 bytes.
+     ** 20 should be large enough for all valid encoded times. 
+     */
+     unsigned int i;
+     char localBuf[20];
+-    char *end = NULL;
++    const char *end = NULL;
+     SECStatus rv;
+ 
+     if (!time || !time->data || time->len < 13 || time->len > 19) {
+ 	PORT_SetError(SEC_ERROR_INVALID_TIME);
+ 	return SECFailure;
+     }
+ 
+     for (i = 0; i < time->len; i++) {
+@@ -257,17 +257,17 @@ DER_GeneralizedTimeToTime(int64 *dst, co
+ 	PORT_SetError(SEC_ERROR_INVALID_TIME);
+ 	return SECFailure;
+     }
+     return rv;
+ }
+ 
+ static SECStatus
+ der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
+-                     char **endptr)
++                     const char **endptr)
+ {
+     PRExplodedTime genTime;
+     long hourOff = 0, minOff = 0;
+     uint16 century;
+     char signum;
+ 
+     if (string == NULL || dst == NULL) {
+ 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
diff --git a/patches/nss-nssinit.patch b/patches/nss-nssinit.patch
new file mode 100644
index 0000000..4e0f103
--- /dev/null
+++ b/patches/nss-nssinit.patch
@@ -0,0 +1,26 @@
+Index: mozilla/security/nss/lib/nss/nssinit.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/nss/nssinit.c,v
+retrieving revision 1.104
+diff -u -p -u -8 -r1.104 nssinit.c
+--- mozilla/security/nss/lib/nss/nssinit.c	9 Jan 2010 01:01:32 -0000	1.104
++++ mozilla/security/nss/lib/nss/nssinit.c	21 Jan 2010 23:02:17 -0000
+@@ -41,18 +41,16 @@
+ #include <ctype.h>
+ #include <string.h>
+ #include "seccomon.h"
+ #include "prinit.h"
+ #include "prprf.h"
+ #include "prmem.h"
+ #include "cert.h"
+ #include "key.h"
+-#include "ssl.h"
+-#include "sslproto.h"
+ #include "secmod.h"
+ #include "secoid.h"
+ #include "nss.h"
+ #include "pk11func.h"
+ #include "secerr.h"
+ #include "nssbase.h"
+ #include "pkixt.h"
+ #include "pkix.h"
diff --git a/patches/nss-secport.patch b/patches/nss-secport.patch
new file mode 100644
index 0000000..fb8a267
--- /dev/null
+++ b/patches/nss-secport.patch
@@ -0,0 +1,73 @@
+Index: mozilla/security/nss/lib/util/secport.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/util/secport.c,v
+retrieving revision 1.26
+diff -u -p -u -8 -r1.26 secport.c
+--- mozilla/security/nss/lib/util/secport.c	24 Dec 2009 03:37:46 -0000	1.26
++++ mozilla/security/nss/lib/util/secport.c	21 Jan 2010 22:47:00 -0000
+@@ -47,17 +47,16 @@
+ #include "seccomon.h"
+ #include "prmem.h"
+ #include "prerror.h"
+ #include "plarena.h"
+ #include "secerr.h"
+ #include "prmon.h"
+ #include "nssilock.h"
+ #include "secport.h"
+-#include "prvrsion.h"
+ #include "prenv.h"
+ 
+ #ifdef DEBUG
+ #define THREADMARK
+ #endif /* DEBUG */
+ 
+ #ifdef THREADMARK
+ #include "prthread.h"
+@@ -324,42 +323,31 @@ PORT_ArenaZAlloc(PLArenaPool *arena, siz
+  * If zero is true, zeroize the arena memory before freeing it.
+  */
+ void
+ PORT_FreeArena(PLArenaPool *arena, PRBool zero)
+ {
+     PORTArenaPool *pool = (PORTArenaPool *)arena;
+     PRLock *       lock = (PRLock *)0;
+     size_t         len  = sizeof *arena;
+-    extern const PRVersionDescription * libVersionPoint(void);
+-    static const PRVersionDescription * pvd;
++    static PRBool  checkedEnv = PR_FALSE;
+     static PRBool  doFreeArenaPool = PR_FALSE;
+ 
+     if (!pool)
+     	return;
+     if (ARENAPOOL_MAGIC == pool->magic ) {
+ 	len  = sizeof *pool;
+ 	lock = pool->lock;
+ 	PZ_Lock(lock);
+     }
+-    if (!pvd) {
+-	/* Each of NSPR's DLLs has a function libVersionPoint().
+-	** We could do a lot of extra work to be sure we're calling the
+-	** one in the DLL that holds PR_FreeArenaPool, but instead we
+-	** rely on the fact that ALL NSPR DLLs in the same directory
+-	** must be from the same release, and we call which ever one we get. 
+-	*/
++    if (!checkedEnv) {
+ 	/* no need for thread protection here */
+-	pvd = libVersionPoint();
+-	if ((pvd->vMajor > 4) || 
+-	    (pvd->vMajor == 4 && pvd->vMinor > 1) ||
+-	    (pvd->vMajor == 4 && pvd->vMinor == 1 && pvd->vPatch >= 1)) {
+-	    const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
+-	    if (!ev) doFreeArenaPool = PR_TRUE;
+-	}
++	const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
++	if (!ev) doFreeArenaPool = PR_TRUE;
++	checkedEnv = PR_TRUE;
+     }
+     if (zero) {
+ 	PLArena *a;
+ 	for (a = arena->first.next; a; a = a->next) {
+ 	    PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ 	    memset((void *)a->base, 0, a->avail - a->base);
+ 	}
+     }
diff --git a/patches/nss-static.patch b/patches/nss-static.patch
new file mode 100644
index 0000000..2b33832
--- /dev/null
+++ b/patches/nss-static.patch
@@ -0,0 +1,651 @@
+Index: mozilla/security/nss/lib/certhigh/certvfy.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/certhigh/certvfy.c,v
+retrieving revision 1.69
+diff -p -u -8 -r1.69 certvfy.c
+--- mozilla/security/nss/lib/certhigh/certvfy.c	13 Mar 2009 02:59:04 -0000	1.69
++++ mozilla/security/nss/lib/certhigh/certvfy.c	9 Jan 2010 03:02:21 -0000
+@@ -40,27 +40,71 @@
+ #include "secoid.h"
+ #include "sslerr.h"
+ #include "genname.h"
+ #include "keyhi.h"
+ #include "cert.h"
+ #include "certdb.h"
+ #include "certi.h"
+ #include "cryptohi.h"
++#define NO_LIBPKIX
++#ifndef NO_LIBPKIX
+ #include "pkix.h"
+ /*#include "pkix_sample_modules.h" */
+ #include "pkix_pl_cert.h"
++#endif  /* NO_LIBPKIX */
+ 
+ 
+ #include "nsspki.h"
+ #include "pkitm.h"
+ #include "pkim.h"
+ #include "pki3hack.h"
+ #include "base.h"
+ 
++#ifdef NO_LIBPKIX
++SECStatus
++cert_VerifyCertChainPkix(
++    CERTCertificate *cert,
++    PRBool           checkSig,
++    SECCertUsage     requiredUsage,
++    PRTime           time,
++    void            *wincx,
++    CERTVerifyLog   *log,
++    PRBool          *pSigerror,
++    PRBool          *pRevoked)
++{
++    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
++    return SECFailure;
++}
++
++SECStatus
++CERT_SetUsePKIXForValidation(PRBool enable)
++{
++    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
++    return SECFailure;
++}
++
++PRBool
++CERT_GetUsePKIXForValidation()
++{
++    return PR_FALSE;
++}
++
++SECStatus CERT_PKIXVerifyCert(
++    CERTCertificate *cert,
++    SECCertificateUsage usages,
++    CERTValInParam *paramsIn,
++    CERTValOutParam *paramsOut,
++    void *wincx)
++{
++    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
++    return SECFailure;
++}
++#endif  /* NO_LIBPKIX */
++
+ /*
+  * Check the validity times of a certificate
+  */
+ SECStatus
+ CERT_CertTimesValid(CERTCertificate *c)
+ {
+     SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE);
+     return (valid == secCertTimeValid) ? SECSuccess : SECFailure;
+Index: mozilla/security/nss/lib/freebl/blapii.h
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/freebl/blapii.h,v
+retrieving revision 1.1
+diff -p -u -8 -r1.1 blapii.h
+--- mozilla/security/nss/lib/freebl/blapii.h	3 Feb 2009 05:34:40 -0000	1.1
++++ mozilla/security/nss/lib/freebl/blapii.h	9 Jan 2010 03:02:21 -0000
+@@ -39,19 +39,19 @@
+ #define _BLAPII_H_
+ 
+ #include "blapit.h"
+ 
+ SEC_BEGIN_PROTOS
+ 
+ #if defined(XP_UNIX) && !defined(NO_CHECK_FORK)
+ 
+-extern PRBool parentForkedAfterC_Initialize;
++extern PRBool bl_parentForkedAfterC_Initialize;
+ 
+-#define SKIP_AFTER_FORK(x) if (!parentForkedAfterC_Initialize) x
++#define SKIP_AFTER_FORK(x) if (!bl_parentForkedAfterC_Initialize) x
+ 
+ #else
+ 
+ #define SKIP_AFTER_FORK(x) x
+ 
+ #endif
+ 
+ SEC_END_PROTOS
+Index: mozilla/security/nss/lib/freebl/rsa.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/freebl/rsa.c,v
+retrieving revision 1.39
+diff -p -u -8 -r1.39 rsa.c
+--- mozilla/security/nss/lib/freebl/rsa.c	3 Feb 2009 05:34:41 -0000	1.39
++++ mozilla/security/nss/lib/freebl/rsa.c	9 Jan 2010 03:02:22 -0000
+@@ -967,18 +967,25 @@ void RSA_Cleanup(void)
+  * free_bl may have allocated along the way. Currently only RSA does this,
+  * so I've put it here for now.
+  */
+ void BL_Cleanup(void)
+ {
+     RSA_Cleanup();
+ }
+ 
+-PRBool parentForkedAfterC_Initialize;
++#if 1  /* STATIC LIBRARIES */
++void
++BL_Unload(void)
++{
++}
++#endif
++
++PRBool bl_parentForkedAfterC_Initialize;
+ 
+ /*
+  * Set fork flag so it can be tested in SKIP_AFTER_FORK on relevant platforms.
+  */
+ void BL_SetForkState(PRBool forked)
+ {
+-    parentForkedAfterC_Initialize = forked;
++    bl_parentForkedAfterC_Initialize = forked;
+ }
+ 
+Index: mozilla/security/nss/lib/freebl/shvfy.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/freebl/shvfy.c,v
+retrieving revision 1.11
+diff -p -u -8 -r1.11 shvfy.c
+--- mozilla/security/nss/lib/freebl/shvfy.c	18 Nov 2008 19:48:24 -0000	1.11
++++ mozilla/security/nss/lib/freebl/shvfy.c	9 Jan 2010 03:02:22 -0000
+@@ -97,19 +97,29 @@ readItem(PRFileDesc *fd, SECItem *item)
+ 	PORT_Free(item->data);
+ 	item->data = NULL;
+ 	item->len = 0;
+ 	return SECFailure;
+     }
+     return SECSuccess;
+ }
+ 
++/*
++ * Define PSEUDO_FIPS if you can't do FIPS software integrity test (e.g.,
++ * if you're using NSS as static libraries), but want to confirm to the
++ * rest of the FIPS requirements.
++ */
++#define PSEUDO_FIPS
++
+ PRBool
+ BLAPI_SHVerify(const char *name, PRFuncPtr addr)
+ {
++#ifdef PSEUDO_FIPS
++    return PR_TRUE;  /* a lie, hence *pseudo* FIPS */
++#else
+     /* find our shared library name */
+     char *shName = PR_GetLibraryFilePathname(name, addr);
+     char *checkName = NULL;
+     PRFileDesc *checkFD = NULL;
+     PRFileDesc *shFD = NULL;
+     SHA1Context *hashcx = NULL;
+     SECItem signature = { 0, NULL, 0 };
+     SECItem hash;
+@@ -282,19 +292,23 @@ loser:
+     if (key.params.base.data != NULL) {
+ 	PORT_Free(key.params.base.data);
+     }
+     if (key.publicValue.data != NULL) {
+ 	PORT_Free(key.publicValue.data);
+     }
+ 
+     return result;
++#endif  /* PSEUDO_FIPS */
+ }
+ 
+ PRBool
+ BLAPI_VerifySelf(const char *name)
+ {
+-    /* to separate shlib to verify if name is NULL */
+     if (name == NULL) {
++	/*
++	 * If name is NULL, freebl is statically linked into softoken.
++	 * softoken will call BLAPI_SHVerify next to verify itself.
++	 */
+ 	return PR_TRUE;
+     }
+     return BLAPI_SHVerify(name, (PRFuncPtr) decodeInt);
+ }
+Index: mozilla/security/nss/lib/nss/nssinit.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/nss/nssinit.c,v
+retrieving revision 1.103
+diff -p -u -8 -r1.103 nssinit.c
+--- mozilla/security/nss/lib/nss/nssinit.c	29 Oct 2009 21:33:10 -0000	1.103
++++ mozilla/security/nss/lib/nss/nssinit.c	9 Jan 2010 03:02:22 -0000
+@@ -49,19 +49,22 @@
+ #include "ssl.h"
+ #include "sslproto.h"
+ #include "secmod.h"
+ #include "secoid.h"
+ #include "nss.h"
+ #include "pk11func.h"
+ #include "secerr.h"
+ #include "nssbase.h"
++#define NO_LIBPKIX
++#ifndef NO_LIBPKIX
+ #include "pkixt.h"
+ #include "pkix.h"
+ #include "pkix_tools.h"
++#endif  /* NO_LIBPKIX */
+ 
+ #include "pki3hack.h"
+ #include "certi.h"
+ #include "secmodi.h"
+ #include "ocspti.h"
+ #include "ocspi.h"
+ 
+ /*
+@@ -532,18 +535,20 @@ nss_Init(const char *configdir, const ch
+ 		 NSSInitParameters *initParams,
+ 		 PRBool readOnly, PRBool noCertDB, 
+ 		 PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
+ 		 PRBool optimizeSpace, PRBool noSingleThreadedModules,
+ 		 PRBool allowAlreadyInitializedModules,
+ 		 PRBool dontFinalizeModules)
+ {
+     SECStatus rv = SECFailure;
++#ifndef NO_LIBPKIX
+     PKIX_UInt32 actualMinorVersion = 0;
+     PKIX_Error *pkixError = NULL;
++#endif
+     PRBool isReallyInitted;
+     char *configStrings = NULL;
+     char *configName = NULL;
+     PRBool passwordRequired = PR_FALSE;
+ 
+     /* if we are trying to init with a traditional NSS_Init call, maintain
+      * the traditional idempotent behavior. */
+     if (!initContextPtr && nssIsInitted) {
+@@ -662,28 +667,30 @@ nss_Init(const char *configdir, const ch
+ 		    nss_FindExternalRoot(dbpath, secmodName);
+ 		}
+ 	    }
+ 	}
+ 
+ 	pk11sdr_Init();
+ 	cert_CreateSubjectKeyIDHashTable();
+ 
++#ifndef NO_LIBPKIX
+ 	pkixError = PKIX_Initialize
+ 	    (PKIX_FALSE, PKIX_MAJOR_VERSION, PKIX_MINOR_VERSION,
+ 	    PKIX_MINOR_VERSION, &actualMinorVersion, &plContext);
+ 
+ 	if (pkixError != NULL) {
+ 	    goto loser;
+ 	} else {
+             char *ev = getenv("NSS_ENABLE_PKIX_VERIFY");
+             if (ev && ev[0]) {
+                 CERT_SetUsePKIXForValidation(PR_TRUE);
+             }
+         }
++#endif  /* NO_LIBPKIX */
+ 
+ 
+     }
+ 
+     /*
+      * Now mark the appropriate init state. If initContextPtr was passed
+      * in, then return the new context pointer and add it to the
+      * nssInitContextList. Otherwise set the global nss_isInitted flag
+@@ -1026,17 +1033,19 @@ nss_Shutdown(void)
+ 
+     rv = nss_ShutdownShutdownList();
+     if (rv != SECSuccess) {
+ 	shutdownRV = SECFailure;
+     }
+     cert_DestroyLocks();
+     ShutdownCRLCache();
+     OCSP_ShutdownGlobal();
++#ifndef NO_LIBPKIX
+     PKIX_Shutdown(plContext);
++#endif
+     SECOID_Shutdown();
+     status = STAN_Shutdown();
+     cert_DestroySubjectKeyIDHashTable();
+     pk11_SetInternalKeySlot(NULL);
+     rv = SECMOD_Shutdown();
+     if (rv != SECSuccess) {
+ 	shutdownRV = SECFailure;
+     }
+Index: mozilla/security/nss/lib/pk11wrap/pk11load.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/pk11load.c,v
+retrieving revision 1.28
+diff -p -u -8 -r1.28 pk11load.c
+--- mozilla/security/nss/lib/pk11wrap/pk11load.c	30 Oct 2009 09:44:45 -0000	1.28
++++ mozilla/security/nss/lib/pk11wrap/pk11load.c	9 Jan 2010 03:02:22 -0000
+@@ -344,46 +344,54 @@ SECMOD_SetRootCerts(PK11SlotInfo *slot, 
+ 	   mod->slotInfo = psi_list;
+ 	   mod->slotInfoCount++;
+ 	   
+ 	}
+ 	psi->hasRootCerts = 1;
+     }
+ }
+ 
++#if 1  /* STATIC LIBRARIES */
++extern CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
++extern CK_RV FC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
++extern char **NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args);
++#else
+ static const char* my_shlib_name =
+     SHLIB_PREFIX"nss"SHLIB_VERSION"."SHLIB_SUFFIX;
+ static const char* softoken_shlib_name =
+     SHLIB_PREFIX"softokn"SOFTOKEN_SHLIB_VERSION"."SHLIB_SUFFIX;
+ static const PRCallOnceType pristineCallOnce;
+ static PRCallOnceType loadSoftokenOnce;
+ static PRLibrary* softokenLib;
+ static PRInt32 softokenLoadCount;
++#endif  /* STATIC LIBRARIES */
+ 
+ #include "prio.h"
+ #include "prprf.h"
+ #include <stdio.h>
+ #include "prsystem.h"
+ 
++#if 0  /* STATIC LIBRARIES */
+ /* This function must be run only once. */
+ /*  determine if hybrid platform, then actually load the DSO. */
+ static PRStatus
+ softoken_LoadDSO( void ) 
+ {
+   PRLibrary *  handle;
+ 
+   handle = PORT_LoadLibraryFromOrigin(my_shlib_name,
+                                       (PRFuncPtr) &softoken_LoadDSO,
+                                       softoken_shlib_name);
+   if (handle) {
+     softokenLib = handle;
+     return PR_SUCCESS;
+   }
+   return PR_FAILURE;
+ }
++#endif  /* STATIC LIBRARIES */
+ 
+ /*
+  * load a new module into our address space and initialize it.
+  */
+ SECStatus
+ secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule) {
+     PRLibrary *library = NULL;
+     CK_C_GetFunctionList entry = NULL;
+@@ -393,16 +401,26 @@ secmod_LoadPKCS11Module(SECMODModule *mo
+     SECStatus rv;
+     PRBool alreadyLoaded = PR_FALSE;
+     char *disableUnload = NULL;
+ 
+     if (mod->loaded) return SECSuccess;
+ 
+     /* intenal modules get loaded from their internal list */
+     if (mod->internal && (mod->dllName == NULL)) {
++#if 1  /* STATIC LIBRARIES */
++    if (mod->isFIPS) {
++        entry = FC_GetFunctionList;
++    } else {
++        entry = NSC_GetFunctionList;
++    }
++    if (mod->isModuleDB) {
++        mod->moduleDBFunc = NSC_ModuleDBFunc;
++    }
++#else
+     /*
+      * Loads softoken as a dynamic library,
+      * even though the rest of NSS assumes this as the "internal" module.
+      */
+     if (!softokenLib && 
+         PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO))
+         return SECFailure;
+ 
+@@ -418,16 +436,17 @@ secmod_LoadPKCS11Module(SECMODModule *mo
+ 
+     if (!entry)
+         return SECFailure;
+ 
+     if (mod->isModuleDB) {
+         mod->moduleDBFunc = (CK_C_GetFunctionList) 
+                     PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc");
+     }
++#endif
+ 
+     if (mod->moduleDBOnly) {
+         mod->loaded = PR_TRUE;
+         return SECSuccess;
+     }
+     } else {
+ 	/* Not internal, load the DLL and look up C_GetFunctionList */
+ 	if (mod->dllName == NULL) {
+@@ -587,27 +606,29 @@ SECMOD_UnloadModule(SECMODModule *mod) {
+     }
+     mod->moduleID = 0;
+     mod->loaded = PR_FALSE;
+     
+     /* do we want the semantics to allow unloading the internal library?
+      * if not, we should change this to SECFailure and move it above the
+      * mod->loaded = PR_FALSE; */
+     if (mod->internal) {
++#if 0  /* STATIC LIBRARIES */
+         if (0 == PR_AtomicDecrement(&softokenLoadCount)) {
+           if (softokenLib) {
+               disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
+               if (!disableUnload) {
+                   PRStatus status = PR_UnloadLibrary(softokenLib);
+                   PORT_Assert(PR_SUCCESS == status);
+               }
+               softokenLib = NULL;
+           }
+           loadSoftokenOnce = pristineCallOnce;
+         }
++#endif
+ 	return SECSuccess;
+     }
+ 
+     library = (PRLibrary *)mod->library;
+     /* paranoia */
+     if (library == NULL) {
+ 	return SECFailure;
+     }
+Index: mozilla/security/nss/lib/softoken/lgglue.c
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/softoken/lgglue.c,v
+retrieving revision 1.13
+diff -p -u -8 -r1.13 lgglue.c
+--- mozilla/security/nss/lib/softoken/lgglue.c	16 Apr 2009 18:19:26 -0000	1.13
++++ mozilla/security/nss/lib/softoken/lgglue.c	9 Jan 2010 03:02:23 -0000
+@@ -50,16 +50,17 @@
+ 
+ static LGOpenFunc legacy_glue_open = NULL;
+ static LGReadSecmodFunc legacy_glue_readSecmod = NULL;
+ static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL;
+ static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL;
+ static LGAddSecmodFunc legacy_glue_addSecmod = NULL;
+ static LGShutdownFunc legacy_glue_shutdown = NULL;
+ 
++#if 0  /* STATIC LIBRARIES */
+ /*
+  * The following 3 functions duplicate the work done by bl_LoadLibrary.
+  * We should make bl_LoadLibrary a global and replace the call to
+  * sftkdb_LoadLibrary(const char *libname) with it.
+  */
+ #ifdef XP_UNIX
+ #include <unistd.h>
+ #define LG_MAX_LINKS 20
+@@ -187,16 +188,17 @@ done:
+ 	PRLibSpec libSpec;
+ 	libSpec.type = PR_LibSpec_Pathname;
+ 	libSpec.value.pathname = libname;
+ 	lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
+     }
+ 
+     return lib;
+ }
++#endif  /* STATIC LIBRARIES */
+ 
+ /*
+  * stub files for legacy db's to be able to encrypt and decrypt
+  * various keys and attributes.
+  */
+ static SECStatus
+ sftkdb_encrypt_stub(PRArenaPool *arena, SDB *sdb, SECItem *plainText,
+ 		    SECItem **cipherText)
+@@ -299,16 +301,33 @@ sftkdbLoad_Legacy(PRBool isFIPS)
+ 		 * get cleared in shutdown */
+ 		return SECFailure;
+ 	    }
+     	    legacy_glue_libCheckSucceeded = PR_TRUE;
+ 	} 
+ 	return SECSuccess;
+     }
+ 
++#undef TRY_TO_USE_NSSDBM
++#if 1  /* STATIC LIBRARIES */
++#ifdef TRY_TO_USE_NSSDBM
++    lib = (PRLibrary *) 0x8;
++
++    legacy_glue_open = legacy_Open;
++    legacy_glue_readSecmod = legacy_ReadSecmodDB;
++    legacy_glue_releaseSecmod = legacy_ReleaseSecmodDBData;
++    legacy_glue_deleteSecmod = legacy_DeleteSecmodDB;
++    legacy_glue_addSecmod = legacy_AddSecmodDB;
++    legacy_glue_shutdown = legacy_Shutdown;
++    setCryptFunction = legacy_SetCryptFunctions;
++#else
++    fprintf(stderr, "NSSDBM omitted!\n");
++    return SECFailure;
++#endif
++#else
+     lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME);
+     if (lib == NULL) {
+ 	return SECFailure;
+     }
+     
+     legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open");
+     legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib,
+ 						 "legacy_ReadSecmodDB");
+@@ -324,21 +343,24 @@ sftkdbLoad_Legacy(PRBool isFIPS)
+ 						"legacy_SetCryptFunctions");
+ 
+     if (!legacy_glue_open || !legacy_glue_readSecmod || 
+ 	    !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || 
+ 	    !legacy_glue_addSecmod || !setCryptFunction) {
+ 	PR_UnloadLibrary(lib);
+ 	return SECFailure;
+     }
++#endif  /* STATIC LIBRARIES */
+ 
+     /* verify the loaded library if we are in FIPS mode */
+     if (isFIPS) {
+ 	if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
++#if 0  /* STATIC LIBRARIES */
+ 	    PR_UnloadLibrary(lib);
++#endif
+ 	    return SECFailure;
+ 	}
+     	legacy_glue_libCheckSucceeded = PR_TRUE;
+     } 
+ 
+     setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub);
+     legacy_glue_lib = lib;
+     return SECSuccess;
+@@ -445,20 +467,22 @@ sftkdbCall_Shutdown(void)
+ 	return CKR_OK;
+     }
+     if (legacy_glue_shutdown) {
+ #ifdef NO_FORK_CHECK
+ 	PRBool parentForkedAfterC_Initialize = PR_FALSE;
+ #endif
+ 	crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize);
+     }
++#if 0  /* STATIC LIBRARIES */
+     disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
+     if (!disableUnload) {
+         PR_UnloadLibrary(legacy_glue_lib);
+     }
++#endif
+     legacy_glue_lib = NULL;
+     legacy_glue_open = NULL;
+     legacy_glue_readSecmod = NULL;
+     legacy_glue_releaseSecmod = NULL;
+     legacy_glue_deleteSecmod = NULL;
+     legacy_glue_addSecmod = NULL;
+     legacy_glue_libCheckFailed    = PR_FALSE;
+     legacy_glue_libCheckSucceeded = PR_FALSE;
+Index: mozilla/security/nss/lib/softoken/lgglue.h
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/softoken/lgglue.h,v
+retrieving revision 1.4
+diff -p -u -8 -r1.4 lgglue.h
+--- mozilla/security/nss/lib/softoken/lgglue.h	16 Apr 2009 18:19:26 -0000	1.4
++++ mozilla/security/nss/lib/softoken/lgglue.h	9 Jan 2010 03:02:23 -0000
+@@ -65,16 +65,35 @@ typedef SECStatus (*LGDeleteSecmodFunc)(
+ 			const char *dbname, char *params, PRBool rw);
+ typedef SECStatus (*LGAddSecmodFunc)(const char *appName, 
+ 			const char *filename, 
+ 			const char *dbname, char *params, PRBool rw);
+ typedef SECStatus (*LGShutdownFunc)(PRBool forked);
+ typedef void (*LGSetForkStateFunc)(PRBool);
+ typedef void (*LGSetCryptFunc)(LGEncryptFunc, LGDecryptFunc);
+ 
++extern CK_RV legacy_Open(const char *dir, const char *certPrefix, 
++		const char *keyPrefix, 
++		int certVersion, int keyVersion, int flags, 
++		SDB **certDB, SDB **keyDB);
++extern char ** legacy_ReadSecmodDB(const char *appName, 
++			const char *filename, 
++			const char *dbname, char *params, PRBool rw);
++extern SECStatus legacy_ReleaseSecmodDBData(const char *appName,
++			const char *filename, 
++			const char *dbname, char **params, PRBool rw);
++extern SECStatus legacy_DeleteSecmodDB(const char *appName,
++			const char *filename, 
++			const char *dbname, char *params, PRBool rw);
++extern SECStatus legacy_AddSecmodDB(const char *appName, 
++			const char *filename, 
++			const char *dbname, char *params, PRBool rw);
++extern SECStatus legacy_Shutdown(PRBool forked);
++extern void legacy_SetCryptFunctions(LGEncryptFunc, LGDecryptFunc);
++
+ /*
+  * Softoken Glue Functions
+  */
+ CK_RV sftkdbCall_open(const char *dir, const char *certPrefix, 
+ 		const char *keyPrefix, 
+ 		int certVersion, int keyVersion, int flags, PRBool isFIPS,
+ 		SDB **certDB, SDB **keyDB);
+ char ** sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, 
+Index: mozilla/security/nss/lib/util/secport.h
+===================================================================
+RCS file: /cvsroot/mozilla/security/nss/lib/util/secport.h,v
+retrieving revision 1.23
+diff -p -u -8 -r1.23 secport.h
+--- mozilla/security/nss/lib/util/secport.h	30 Oct 2009 09:44:47 -0000	1.23
++++ mozilla/security/nss/lib/util/secport.h	9 Jan 2010 03:02:23 -0000
+@@ -238,16 +238,17 @@ sec_port_iso88591_utf8_conversion_functi
+   unsigned int maxOutBufLen,
+   unsigned int *outBufLen
+ );
+ 
+ extern int NSS_PutEnv(const char * envVarName, const char * envValue);
+ 
+ extern int NSS_SecureMemcmp(const void *a, const void *b, size_t n);
+ 
++#if 0  /* STATIC LIBRARIES */
+ /*
+  * Load a shared library called "newShLibName" in the same directory as
+  * a shared library that is already loaded, called existingShLibName.
+  * A pointer to a static function in that shared library,
+  * staticShLibFunc, is required.
+  *
+  * existingShLibName:
+  *   The file name of the shared library that shall be used as the 
+@@ -272,12 +273,13 @@ extern int NSS_SecureMemcmp(const void *
+  *
+  * If the new shared library is not found in the same location as the reference
+  * library, it will then be loaded from the normal system library path.
+  */
+ PRLibrary *
+ PORT_LoadLibraryFromOrigin(const char* existingShLibName,
+                  PRFuncPtr staticShLibFunc,
+                  const char *newShLibName);
++#endif  /* STATIC LIBRARIES */
+ 
+ SEC_END_PROTOS
+ 
+ #endif /* _SECPORT_H_ */
diff --git a/patches/prcpucfg.h b/patches/prcpucfg.h
new file mode 100644
index 0000000..dbd0203
--- /dev/null
+++ b/patches/prcpucfg.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-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 ***** */
+
+#if defined(_WIN32)
+#include "md/_win95.cfg"
+#elif defined(__APPLE__)
+#include "md/_darwin.cfg"
+#else
+#error Add a case for your platform
+#endif
diff --git a/scripts/nspr-checkout.sh b/scripts/nspr-checkout.sh
new file mode 100755
index 0000000..12331b1
--- /dev/null
+++ b/scripts/nspr-checkout.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This shell script checks out the NSPR source tree from CVS and prepares
+# it for Chromium.
+
+# Make the script exit as soon as something fails.
+set -e
+
+rm -rf mozilla/nsprpub
+cvs -q -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot export \
+    -D 2010-01-19 NSPR
+
+rm -r mozilla/nsprpub/admin
+rm -r mozilla/nsprpub/build
+rm -r mozilla/nsprpub/config
+rm -r mozilla/nsprpub/lib/msgc
+rm -r mozilla/nsprpub/lib/prstreams
+rm -r mozilla/nsprpub/lib/tests
+rm -r mozilla/nsprpub/pkg
+rm -r mozilla/nsprpub/pr/src/cplus
+rm -r mozilla/nsprpub/pr/tests
+rm -r mozilla/nsprpub/tools
+
+# Remove unneeded platform-specific directories.
+rm -r mozilla/nsprpub/pr/src/bthreads
+rm -r mozilla/nsprpub/pr/src/md/beos
+rm -r mozilla/nsprpub/pr/src/md/os2
+
+find mozilla/nsprpub -name .cvsignore -print | xargs rm
+find mozilla/nsprpub -name README -print | xargs rm
+
+# Remove the build system.
+rm mozilla/nsprpub/configure
+rm mozilla/nsprpub/configure.in
+find mozilla/nsprpub -name Makefile.in -print | xargs rm
+find mozilla/nsprpub -name MANIFEST -print | xargs rm
+find mozilla/nsprpub -name "*.mk" -print | xargs rm
+
+# Remove files for building shared libraries/DLLs.
+find mozilla/nsprpub -name "*.def" -print | xargs rm
+find mozilla/nsprpub -name "*.rc" -print | xargs rm
+find mozilla/nsprpub -name prvrsion.c -print | xargs rm
+find mozilla/nsprpub -name plvrsion.c -print | xargs rm
+
+# Remove unneeded platform-specific files in mozilla/nsprpub/pr/include/md.
+rm mozilla/nsprpub/pr/include/md/sunos4.h
+find mozilla/nsprpub/pr/include/md -name "_*" ! -name "_darwin.*" \
+    ! -name "_win95.*" ! -name _pth.h ! -name _pcos.h ! -name _unixos.h \
+    ! -name _unix_errors.h ! -name _win32_errors.h -print \
+    | xargs rm
+
+# Remove files for unneeded Unix flavors.
+find mozilla/nsprpub/pr/src/md/unix -type f ! -name "ux*.c" ! -name unix.c \
+    ! -name unix_errors.c ! -name darwin.c ! -name "os_Darwin*.s" -print \
+    | xargs rm
+
+# Remove files for the WINNT build configuration.
+rm mozilla/nsprpub/pr/src/md/windows/ntdllmn.c
+rm mozilla/nsprpub/pr/src/md/windows/ntio.c
+rm mozilla/nsprpub/pr/src/md/windows/ntthread.c
+
+# Remove obsolete files or files we don't need.
+rm mozilla/nsprpub/lib/libc/include/plresolv.h
+rm mozilla/nsprpub/pr/include/gencfg.c
+rm mozilla/nsprpub/pr/src/memory/prgcleak.c
+rm mozilla/nsprpub/pr/src/misc/compile-et.pl
+rm mozilla/nsprpub/pr/src/misc/dtoa.c
+rm mozilla/nsprpub/pr/src/misc/prerr.et
+rm mozilla/nsprpub/pr/src/misc/prerr.properties
diff --git a/scripts/nss-checkout.sh b/scripts/nss-checkout.sh
new file mode 100755
index 0000000..f92a436
--- /dev/null
+++ b/scripts/nss-checkout.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This shell script checks out the NSS source tree from CVS and prepares
+# it for Chromium.
+
+# Make the script exit as soon as something fails.
+set -e
+
+rm -rf mozilla/security/nss/lib
+cvs -q -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot export \
+    -D 2010-01-19 mozilla/security/nss/lib
+
+# Rename one of the utf8.c files to avoid name conflict.
+mv mozilla/security/nss/lib/base/utf8.c mozilla/security/nss/lib/base/nssutf8.c
+
+rm -r mozilla/security/nss/lib/ckfw
+rm -r mozilla/security/nss/lib/crmf
+rm -r mozilla/security/nss/lib/freebl/ecl/tests
+rm -r mozilla/security/nss/lib/freebl/mpi/doc
+rm -r mozilla/security/nss/lib/freebl/mpi/tests
+rm -r mozilla/security/nss/lib/freebl/mpi/utils
+rm -r mozilla/security/nss/lib/jar
+rm -r mozilla/security/nss/lib/libpkix
+rm -r mozilla/security/nss/lib/pkcs12
+rm -r mozilla/security/nss/lib/pki/doc
+rm -r mozilla/security/nss/lib/softoken/legacydb
+rm -r mozilla/security/nss/lib/sqlite
+rm -r mozilla/security/nss/lib/sysinit
+rm -r mozilla/security/nss/lib/zlib
+
+find mozilla/security/nss/lib -name .cvsignore -print | xargs rm
+find mozilla/security/nss/lib -name README -print | xargs rm
+
+# Remove the build system.
+find mozilla/security/nss/lib -name Makefile -print | xargs rm
+find mozilla/security/nss/lib -name manifest.mn -print | xargs rm
+find mozilla/security/nss/lib -name "*.mk" -print | xargs rm
+
+# Remove files for building shared libraries/DLLs.
+find mozilla/security/nss/lib -name "*.def" -print | xargs rm
+find mozilla/security/nss/lib -name "*.rc" -print | xargs rm
+
+# Remove obsolete files or files we don't need.
+rm mozilla/security/nss/lib/util/secplcy.c
+rm mozilla/security/nss/lib/util/secplcy.h
+rm mozilla/security/nss/lib/certhigh/certvfypkix.c
+rm mozilla/security/nss/lib/certhigh/certvfypkixprint.c
+rm mozilla/security/nss/lib/pki1/*.c
+rm mozilla/security/nss/lib/pki1/oidgen.perl
+rm mozilla/security/nss/lib/pki1/oids.txt
+rm mozilla/security/nss/lib/smime/*.c
+
+find mozilla/security/nss/lib/ssl -type f ! -name sslerr.h | xargs rm
+
+find mozilla/security/nss/lib/freebl -type f \
+    ! -name aeskeywrap.c ! -name alg2268.c ! -name alghmac.c \
+    ! -name alghmac.h ! -name arcfive.c ! -name arcfour.c \
+    ! -name blapi.h ! -name blapii.h ! -name blapit.h \
+    ! -name camellia.c ! -name camellia.h ! -name des.c \
+    ! -name des.h ! -name desblapi.c ! -name dh.c \
+    ! -name drbg.c ! -name dsa.c ! -name ec.c \
+    ! -name ec.h ! -name ec2.h ! -name ecl-curve.h \
+    ! -name ecl-exp.h ! -name ecl-priv.h ! -name ecl.c \
+    ! -name ecl.c ! -name ecl.h ! -name ecl_curve.c \
+    ! -name ecl_gf.c ! -name ecl_mult.c ! -name ecp.h \
+    ! -name ecp_aff.c ! -name ecp_jac.c ! -name ecp_jm.c \
+    ! -name ecp_mont.c ! -name ec_naf.c ! -name hasht.h \
+    ! -name md2.c ! -name md5.c ! -name logtab.h \
+    ! -name mpcpucache.c \
+    ! -name mpi-config.h \
+    ! -name mpi-priv.h ! -name mpi.c ! -name mpi.h \
+    ! -name mpi_amd64.c ! -name mpi_x86_asm.c ! -name mplogic.c \
+    ! -name mplogic.h ! -name mpmontg.c ! -name mpprime.c \
+    ! -name mpprime.h \
+    ! -name mp_gf2m-priv.h ! -name mp_gf2m.c ! -name mp_gf2m.h \
+    ! -name primes.c ! -name pqg.c ! -name rawhash.c \
+    ! -name rijndael.c ! -name rijndael.h ! -name rijndael32.tab \
+    ! -name rsa.c ! -name sechash.h ! -name secmpi.h \
+    ! -name secrng.h ! -name seed.c ! -name seed.h \
+    ! -name sha256.h ! -name sha512.c ! -name sha_fast.c \
+    ! -name sha_fast.h ! -name shsign.h ! -name shvfy.c \
+    ! -name sysrand.c ! -name tlsprfalg.c ! -name unix_rand.c \
+    ! -name win_rand.c \
+    | xargs rm